Limitations of passing a block to class_eval

One shortcoming of define_method is that it does not allow you to
specify a method body that expects a block. If you need to dynamically
create a method that accepts a block, you will need to use the def
statement within class_eval. Here’s a trivial example:

class Module
def acts_as_thing(name, &block)
self.class_eval {
define_method(name, &block)
}
end
end

class Thing
#using define_method does not allow us to specify a method body that
expects a block, because the block used in define method becomes the
method body itself, not a block passed to a method body.
acts_as_thing :animals do
puts “animal group”
end

def initialize(name)
@name = name
end
end

#To address the limitations of define_method, that is, to dynamically
create a method that accepts a block, we need to use the def statement
with class_eval.
Thing.class_eval {
def spell_out_name
yield @name
end
}

thing = Thing.new(“dog”)
thing.animals # => animal group
thing.spell_out_name {|name| puts “The name is #{name}.”} # => The
name is dog.

Here’s my question. I am reading a book called The Ruby P.ming
Language. It says the following:

“If the method you are creating is sufficiently dynamic, you may not
be able to pass a block to class_eval and will instead have to specify
the method definition as a string to be evaluated.”

I’m not sure what they are talking about here. What does it mean by
“sufficiently dynamic”? In my example above, I proved that a method
defined within the context of class_eval can accept a block.

On Fri, Oct 19, 2012 at 8:28 PM, John M. [email protected] wrote:

One shortcoming of define_method is that it does not allow you to
specify a method body that expects a block. If you need to dynamically
create a method that accepts a block, you will need to use the def
statement within class_eval. Here’s a trivial example:

Why are you using define_method inside of class eval again? That set
aside I hope you are not learning Ruby on 1.8.7 because that would
defeat the purpose of learning Ruby, since 1.8.7 is pretty much dead
and 1.9.3 is where you should start, since hopefully no company will
ever ask you to do Ruby on 1.8.7 that said, ruby does in-fact support
blocks in define_method see:

class MyClass
define_method(:my_method1) do |&block|
if !block
raise “No block given”
end

block.call

end
end

MyClass.new.my_method1 do
$stdout.puts “Hello World”
end

class MyClass
class_eval do
define_method(:my_method1) do |&block|
block.call
end
end
end

MyClass.new.my_method1 do
$stdout.puts “Hello World”
end

“If the method you are creating is sufficiently dynamic, you may not
be able to pass a block to class_eval and will instead have to specify
the method definition as a string to be evaluated.”

I’m not sure what they are talking about here. What does it mean by
“sufficiently dynamic”? In my example above, I proved that a method
defined within the context of class_eval can accept a block.

What they are talking about is complicated logic vs simple logic, when
you are aliasing a helper into sub-helpers (for example color(color)
gets meta-programmed in a loop to def black; color(“#000”) end) that
is simple logic, then you have complicated logic, which involves
morphing entire sets of meta-methods based on variables and using
those variables in the meta too. An example of that is
https://github.com/envygeeks/mongoid-find_by/blob/master/lib/mongoid/finders/find_by.rb#L21
that can morph dynamically into find_by_field1_and_field2(field1,
field2) or find_by_field1(field1) and (hopefully) any mixture of and
or find_all_by ± and you want and define the method for you. That
is the difference between just doing a simple block and doing a
string.

A good tip though, if you are /just/ learning Ruby, stay away from
meta-programming, because it’s the devil in disguise as a blessing,
what I mean is it’s all fun until somebody gets poked in the eye.
It’s really great but some people overkill it, rape it, hang it out to
dry, rape it again, and then throw it in the trash after murdering it
because it ends up so complicated that it’s just not worth managing
anymore. As a beginner meta-programmed tends to get abused, the same
thing happens with monkey-patching with beginners, it absolutely gets
abused and you wouldn’t believe how many people I see monkey patch
directly onto STDLib instead of doing at worst a class and then
including it, but whatever.