define_method and blocks

  • Thread starter Florian G. Pflug
  • Start date
F

Florian G. Pflug

Hi

I'm trying to add a method that receives a block as an argument via
define_method - but none of the following versions work.

Version1: (gives a syntax error - &block doesn't seem to be allowed in block arguments)
define_method:)meth1) do |*args, &block|
block.call
end

Version2: (gives "No block given, altough I called methd2 with a block)
define_method:)meth2) do |*args|
Proc::new.call
end

Version3: ("No block given" - the same as before)
define_method:)meth3) do |*args|
yield
end

Is it possible to define methods that accept blocks as parameters using
define_method()?

greetings, Florian Pflug
 
D

Dan Doel

I thought Matz was contemplating &block parameters for blocks for the future,
but I can't find the post by searching ruby-talk.

Currently what you want is not possible, but it may be in the future.

- Dan
 
V

Vincent ISAMBART

I'm trying to add a method that receives a block as an argument via
define_method - but none of the following versions work.

As it seems you can't do it with define_methods, you could try using
eval. It is slower, but it should work. Try something like this :
eval %{
class MyClass
def meth1(*args, &block)
block.call
end
end
}

eval is the most powerful statement in the script languages...

PS : I have not tested it, because I have no ruby interpreter to test
this on. But the idea should work :eek:)

Vincent Isambart
 
F

Florian Gross

Florian said:
Hi
Moin!

I'm trying to add a method that receives a block as an argument via
define_method - but none of the following versions work.

You can try something like this:

obj = Object.new

sklass = class << obj
def meth1(*args, &block)
_meth1(args, block)
end

self
end

some_variable = "bar"

sklass.send:)define_method, :_meth1) do |args, block|
block.call(some_variable, *args)
end

obj.meth1("foo") { |var, str| p [str, var] } # outputs ["foo", "bar"]

As you see this way you still get the closure behavior of define_method.
(You can access variables from the scope where you defined the method
from within the method.)

It's all a bit complex, but this is the only way to do this right now.

Maybe it would be better to define a convenience method for this:

class Class
def define_block_method(name, &block)
internal_name = :"_#{name}"

module_eval %{
def #{name}(*args, &block)
#{internal_name}(args, block)
end
}

define_method(internal_name, &block)
return block
end
end

It's used like this:

Fixnum.define_block_method:)new_times) do |args, block|
(1 .. self).each { |i| block.call(i) }
self
end

5.new_times { puts "foo" } # outputs 3 "foo"s
greetings, Florian Pflug

Regards,
Florian Gross
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,112
Latest member
VinayKumar Nevatia
Top