[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Passing a block with define_method

James Coglan

8/26/2008 2:30:00 PM

[Note: parts of this message were removed to make it a legal post.]

Hi list,

I've got a bit of a problem whereby I need to pass a block to a method
defined using define_method this works:

def some_method(*args, &block)
# ...
end

but this does not -- the interpreter complains about unexpected ampersands:

define_method(:some_method) do |*args, &block|
# ...
end

Is there any way to make this work? I'm doing something a little meta, so I
don't know the name of the method or the number of arguments, so it's all
got to be dynamic.



--
James Coglan

17 Answers

ara.t.howard

8/26/2008 2:42:00 PM

0


On Aug 26, 2008, at 8:30 AM, James Coglan wrote:

> Hi list,
>
> I've got a bit of a problem whereby I need to pass a block to a method
> defined using define_method this works:
>
> def some_method(*args, &block)
> # ...
> end
>
> but this does not -- the interpreter complains about unexpected
> ampersands:
>
> define_method(:some_method) do |*args, &block|
> # ...
> end
>
> Is there any way to make this work? I'm doing something a little
> meta, so I
> don't know the name of the method or the number of arguments, so
> it's all
> got to be dynamic.
>

module_eval a string.

a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




James Coglan

8/26/2008 3:03:00 PM

0

[Note: parts of this message were removed to make it a legal post.]

> module_eval a string.



I'm actually wrapping existing methods so I need to use define_method to
retain access to the old method. Here's my (broken) code so far:

module Continuations
def accepts_continuation(*args)
args.each do |method_name|
func = instance_method(method_name)
define_method(method_name) do |*params, &block|
value = func.bind(self).call(*params)
end
end
end
end

James Coglan

8/26/2008 3:11:00 PM

0

[Note: parts of this message were removed to make it a legal post.]

> I'm actually wrapping existing methods so I need to use define_method to
> retain access to the old method. Here's my (broken) code so far:
>
> module Continuations
> def accepts_continuation(*args)
> args.each do |method_name|
> func = instance_method(method_name)
> define_method(method_name) do |*params, &block|
> value = func.bind(self).call(*params)
> end
> end
> end
> end
>


To clarify, this formulation does not work:

module Continuations
def accepts_continuation(*args)
args.each do |method_name|
func = instance_method(method_name)
module_eval <<-EOS
def #{method_name}(*params, &block)
value = func.bind(self).call(params)
end
EOS
end
end
end

Emmanuel Oga

8/26/2008 3:13:00 PM

0

> I'm actually wrapping existing methods so I need to use define_method to
> retain access to the old method. Here's my (broken) code so far:

I think I saw this "trick" in one of Ara's posts :D

* Store the method somewhere so it is not GC by ruby
* Retrieve the method object from its object_id with ObjectSpace._id2ref
* use eval instead of define_method

> module Continuations
NOGC = []
> def accepts_continuation(*args)
> args.each do |method_name|
> func = instance_method(method_name)
NOGC << func # Stop garbage collection of the method.
func_object_id = func.object_id
> #define_method(method_name) do |*params, &block|
> # value = func.bind(self).call(*params)
> #end
eval(<<-CODE, __FILE__, __LINE__)
def #{ method_name }(*params, &block)
func = ObjectSpace._id2ref(#{ func_object_id })
func.bind(self).call(*params, &block)
end
CODE
> end
> end
> end
--
Posted via http://www.ruby-....

David A. Black

8/26/2008 3:13:00 PM

0

Hi --

On Wed, 27 Aug 2008, James Coglan wrote:

>> module_eval a string.
>
>
>
> I'm actually wrapping existing methods so I need to use define_method to
> retain access to the old method. Here's my (broken) code so far:
>
> module Continuations
> def accepts_continuation(*args)
> args.each do |method_name|
> func = instance_method(method_name)
> define_method(method_name) do |*params, &block|
> value = func.bind(self).call(*params)
> end
> end
> end
> end

In Ruby 1.9 you can do this:

>> func = ->(*a,&block) { block.call if block; puts a }
=> #<Proc:0x388bdc@(irb):1 (lambda)>
>> C = Class.new { define_method(:hi, &func) }
=> C
>> C.new.hi(10) { puts "In block" }
In block
10

The ->(){} thing lets you create a lambda with method-argument
semantics.


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL
See http://www.r... for details and updates!

Emmanuel Oga

8/26/2008 3:19:00 PM

0

> To clarify, this formulation does not work:
>
> module Continuations
> def accepts_continuation(*args)
> args.each do |method_name|
> func = instance_method(method_name)
> module_eval <<-EOS
> def #{method_name}(*params, &block)


> value = func.bind(self).call(params)

where does the "func" method come from here? because you are
using module_eval, this is just calling a method named "func" on the
target class (the class where you included the module). I don't think
this would do what you want, even if you do have a "func" method lying
around...


> end
> EOS
> end
> end
> end

--
Posted via http://www.ruby-....

David A. Black

8/26/2008 3:19:00 PM

0

Hi --

On Wed, 27 Aug 2008, David A. Black wrote:

> Hi --
>
> On Wed, 27 Aug 2008, James Coglan wrote:
>
>>> module_eval a string.
>>
>>
>>
>> I'm actually wrapping existing methods so I need to use define_method to
>> retain access to the old method. Here's my (broken) code so far:
>>
>> module Continuations
>> def accepts_continuation(*args)
>> args.each do |method_name|
>> func = instance_method(method_name)
>> define_method(method_name) do |*params, &block|
>> value = func.bind(self).call(*params)
>> end
>> end
>> end
>> end
>
> In Ruby 1.9 you can do this:
>
>>> func = ->(*a,&block) { block.call if block; puts a }
> => #<Proc:0x388bdc@(irb):1 (lambda)>
>>> C = Class.new { define_method(:hi, &func) }
> => C
>>> C.new.hi(10) { puts "In block" }
> In block
> 10
>
> The ->(){} thing lets you create a lambda with method-argument
> semantics.

Actually the fix is in: you can now (and I think permanently) do this
in 1.9 without the ->(){}.

>> class C; define_method(:hi) {|*a,&block| block.call if block; puts
>> a }; end
=> #<Proc:0x1d5754@(irb):1 (lambda)>
>> C.new.hi(10) { puts "In block" }
In block
10

I'd lost track of where this stood -- I'm very glad to see that it's
there in the block syntax (thanks to Eric Mahurin's patch, if I'm not
mistaken).


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL
See http://www.r... for details and updates!

ara.t.howard

8/26/2008 3:20:00 PM

0


On Aug 26, 2008, at 9:12 AM, Emmanuel Oga wrote:

> I think I saw this "trick" in one of Ara's posts :D
>
> * Store the method somewhere so it is not GC by ruby
> * Retrieve the method object from its object_id with
> ObjectSpace._id2ref
> * use eval instead of define_method

that's correct. you just need to store the data/block somewhere whcih
won't be GC'd and pull it back using the id

a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




James Coglan

8/26/2008 3:23:00 PM

0

[Note: parts of this message were removed to make it a legal post.]

Just did something similar to Emmanuel's suggestion, works a treat:

module Continuations
METHODS = {}

def accepts_continuation(*args)
args.each do |method_name|
func = instance_method(method_name)
id = func.object_id
METHODS[id] = func

module_eval <<-EOS
def #{method_name}(*params, &block)
value = Continuations::METHODS[#{id}].bind(self).call(*params)
block.call(value) if block
value
end
EOS
end
end
end

ara.t.howard

8/26/2008 3:23:00 PM

0


On Aug 26, 2008, at 9:03 AM, James Coglan wrote:

>> module_eval a string.
>
>
>
> I'm actually wrapping existing methods so I need to use
> define_method to
> retain access to the old method. Here's my (broken) code so far:
>
> module Continuations
> def accepts_continuation(*args)
> args.each do |method_name|
> func = instance_method(method_name)
> define_method(method_name) do |*params, &block|
> value = func.bind(self).call(*params)
> end
> end
> end
> end


off the top of my head (un-tested but similar will work)


module Continuations

Funcs = {}

def Continuations.funcs() Funcs end

def accepts_continuation *argv

argv.each do |arg|

arg = arg.to_s

Funcs[arg] = instance_method(arg)

module_eval <<-code
def #{ arg }(*a, &b)
Contiuations.funcs.bind(self).call(*a, &b
end
code
end
end
end



a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama