In an attempt to better understand instance_eval and class_eval, I just read Khaled’s post on Ruby reflection. It helped, and I came up with a memory crutch I can use to remember when to use each of them:
Use ClassName.instance_eval to define class methods.
Use ClassName.class_eval to define instance methods.
That’s right. Not a typo. Here are some examples, shamelessly stolen from his post:
# Defining a class method with instance_eval
Fixnum.instance_eval { def ten; 10; end }
Fixnum.ten #=> 10
# Defining an instance method with class_eval
Fixnum.class_eval { def number; self; end }
7.number #=> 7
I Like Stuff that’s Backwards
Why is it the reverse of what you might expect? Because Fixnum.instance_eval treats Fixnum as an instance (an instance of the Class class), thus any new functions you define can be called on that instance. So it’s equivalent to this:
class Fixnum
def self.ten
10
end
end
Fixnum.ten #=> 10
Fixnum.class_eval treats Fixnum as a class and executes the code in the context of that class, thus any “def” statements are treated exactly as if they were in normal code without any reflection. It’s equivalent to this:
class Fixnum
def number
self
end
end
7.number #=> 7
There are still some things about Ruby reflection that mystify me but at least I think I’ve got this one nailed.
January 9, 2009 at 6:17 pm |
A very nice explanation
January 10, 2009 at 8:05 pm |
But what about module_eval? Oh god, won’t someone think of the modules!
January 12, 2009 at 4:12 pm |
The Pragmatic Programmers have a “Ruby Metaprogramming” screencast series ($$) that delves deeply into these and many more Ruby “mysteries”–I recommend them!
January 12, 2009 at 5:50 pm |
That’s the same way I think of it. It’s a real gotcha when you start doing these kinds of things though
August 12, 2009 at 10:54 am |
Thanx thanx wonderful explanation….. Short and clean
August 22, 2009 at 7:16 am |
Very beautifully explained. thanks. i was pretty confused before reading ur post
September 9, 2009 at 1:58 pm |
Well now then how do these things compare to define_method?