class Foo
include Module.new { class_eval "def lab; puts 'm' end" }
def lab
super
puts 'c'
end
end
Foo.new.lab #=> m c
========================================================================
class Foo
include Module.new { instance_eval "def lab; puts 'm' end" }
def lab
super
puts 'c'
end
end
Notice here I changed class_eval to instance_eval
Foo.new.lab rescue nil#=> no super class method lab
Foo.lab #=> undefined method lab for Foo class
So it seems that including the module neither defined an instance method nor a class method.
Any explanation what's going on here?
This code was tested on ruby 1.8.7 on mac.
First, think of what include
does. it makes the instance methods of the module being included into instance methods on the including class. i.e. apart from the fact that your working example uses an anonymous module it is equivalent to:
module M1
def lab
puts 'm'
end
end
class Foo
include M1
def lab
super
puts 'c'
end
end
Next, think of what class_eval
does. It evaluates the given code in the context of the class or module. i.e. it's exactly like you reopened the module and typed the code passed to class_eval
. So MyModule = Module.new { class_eval "def lab; puts 'm' end" }
is equivalent to
module MyModule
def lab
puts 'm'
end
end
Hopefully this explains the case that works.
When you use instance_eval
you are evaluating the code within the context of the receiving object (in this case the instance of module) so MyMod2 = Module.new { instance_eval "def lab; puts 'm' end" }
is equivalent to
module MyMod2
def MyMod2.lab
puts 'm'
end
end
i.e. it creates a module method which you'd call via MyMod2.lab
and such methods are not added as instance methods by include
.
Please note: this answer borrows a bit of its explanation from an answer I wrote to a previous question asking about instance_eval vs. class_eval relating to an example from The Ruby Programming Language book. You might find that answer helpful too.
including a module just takes the instance methods - you are looking for extend. luckily to get the best of both worlds, you can simply do:
module Something
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def blah
puts "lol"
end
end
end
class Test
include Something
end
irb:
>> Test.blah
lol
=> nil
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With