From: David Masover Date: 2009-09-18T03:06:29+09:00 Subject: Re: Mucking about with dynamically adding methods to objects On Thursday 17 September 2009 10:28:25 am Paul Smith wrote: > I think I have a lot more reading to do before > > irb(main):014:2> (class << obj;self;end).instance_eval do > irb(main):015:3* define_method :talk do > > makes any kind of sense. Break it down into pieces. You already know how to do: def obj.talk ... end Or, to define a class method: Class Foo def self.bar ... end end Foo.bar The next step is to realize that this is equivalent to: class << obj def talk ... end end It might not be immediately obvious, but just take my word for it: that is equivalent to 'def obj.talk'. But it looks like a class definition -- and it sort of is. It's the metaclass -- you can think of it as a class that only that object belongs to, which inherits from the object's real, official class. Now, think about this example: class Foo def self.bar You might've already done it this way: def Foo.bar So what is self inside a class? Easy, it's the class itself. So, what's self inside "class << object"? It's the metaclass I just described. So, if you do this: meta_class = class << object self end you extract the metaclass. (The last statement in a class definition is the return value of the class definition.) Once you understand that much, instance_eval may make sense. In fact, you could do this: class Object def metaclass class << self; self; end end end Now you can do object.metaclass.instance_eval. This is so incredibly common that it could be shortened, too: class Object def meta_eval &block metaclass.instance_eval &block end end I use this a lot -- even when "class << obj" would work just as well. And I'm blatantly stealing this from _why -- he distributed it as a gem called 'metaid'. His Rubyforge account seems to work, and the gem seems to be alive, so I think it's safe -- especially since it's so fundamental and obvious (17 lines of code) that it's not hard to replace if you have to. So, do this instead: gem install metaid require 'metaid' def talkify(obj, str) obj.meta_eval do define_method :talk do str end end end I might shorten it like this, if it fits well: require 'metaid' def talkify obj, str obj.metaclass.send :define_method, :talk do str end end It's probably covered somewhere in that book, but even once it is, I still suggest metaid.