-
class_eval vs instance_eval
In Ruby you may have seen class_eval and instance_eval and thought to yourself “What is the difference?” They both accept a string or a block as an argument, but then they diverge:
instance_eval evaluates a string as Ruby code or a block in the context of the object’s singleton class. Effectively it changes the value of self, the implicit receiver, to be that of the object’s metaclass, singleton class, eigenclass, or whatever else you may know it as.
Methods on an object’s singleton class are defined on that object. If you call it on an instance of a class, the code evaluated by instance_eval will only apply to that instance.
instance_eval is not the only way to define singleton methods in Ruby. As usual in Ruby, there is a multitude of ways to skin a cat:
dude = "steve" # All these are equivalent class << dude def say_what_up "yo, my name is #{self}" end end def dude.say_what_up "yo, my name is #{self}" end dude.instance_eval do def say_what_up "yo, my name is #{self}" end endWhen you call it on an actual class, it has the effect of defining “class methods”. I put that in quotes because once you think of it in those terms it becomes clear that “class methods” do not actually exist, they are just singleton methods on another type of object, i.e. a class. Amazing!
class Foo def self.foo "foo" end end class Foo class << self def foo "foo" end end end def Foo.foo "foo" end class << Foo def foo "foo" end end Foo.instance_eval do def foo "foo" end endThese all do the same thing, i.e. define the “class method” Foo.foo that returns a string “foo”.
So I did say earlier that code evaluated by instance_eval will only apply to that object. That’s not strictly true, although semantically it is. If you call on an actual class, it will be visible to classes that subclass it when Ruby can’t find it on that object. Ruby then goes off on its merry way up the inheritance chain looking for it in ancestor classes.
Like so:
Foo = Class.new Foo.instance_eval do def foo "foo" end end Bar = Class.new Foo puts Bar.foo #=> fooclass_eval
class_eval switches the value of self to its receiver. This can only be called on a module or class and not an instantiation of those objects. A method defined in a string or block supplied to instance_eval has the effect of defining instance methods for that class or module. (Although a module cannot be instantiated, it can be mixed into a class, making the class respond to those instance methods. More on this at a later date.)
class Foo def to_s "foo" end end Foo.class_eval do def to_s "foo" end endclass_eval is also aliased as module_eval. I tend to use module_eval if the object that I’m manipulating is a module as opposed to a class. I think it makes my code more readable and is a good style to adopt.
You can’t use class_eval on an object instance. Try it, you’ll get a NoMethod error. This makes perfect sense!
That’s all I can think of for now
S
Sat27Mar