Railstic

sharing experiences

Dynamically Defining Methods with define_method

| Comments

If you have been hacking ruby for a while you should have heard that “Everything is an object”. To understand this concept knowing what a singleton class is important. Yehuda Katz’s post is a good source for it.

My ruby version 1.9.2.

$ ruby -v
ruby 1.9.2p136 (2010-12-25 revision 30365) [i686-linux]

First I’m going to show you how to add methods to instances by using define_method.

class Message
[:hello, :goodbye].each do |method_name|
define_method method_name do |arg|
"#{method_name} #{arg}"
end
end
end
#irb
Message.instance_methods false #=> [:hello, :goodbye]
Message.new.hello 'emre' #=> "hello emre"
Message.new.goodbye 'emre' #=> "goodbye emre"

You can also write an instance method to create instance methods. send must be used because define_method is private.

class Message
def create_instance_methods *methods
methods.each do |method_name|
self.class.send :define_method, method_name do |arg|
"#{method_name} #{arg}"
end
end
end
end
#irb
Message.instance_methods false #=> [:create_instance_methods]
Message.new.create_instance_methods 'fork' #=> ["fork"]
Message.instance_methods false #=> [:create_instance_methods, :fork]
Message.new.fork 'emre' #=> "fork emre"

Write a singleton method to create instance methods.

class Message
def self.create_instance_methods *methods
methods.each do |method_name|
define_method method_name do |arg|
"#{method_name} #{arg}"
end
end
end
end
#irb
Message.singleton_methods #=> [:create_instance_methods]
Message.create_instance_methods 'follow' #=> ["follow"]
Message.instance_methods false #=> [:follow]
Message.new.follow 'emre' #=> "follow emre"

Now it is time to add singleton methods. When we call define_method, it creates an instance method. What we have to do is call define_method on class’ singleton class.

Getting singleton class of a class:

#ruby 1.9.2
class Message
end
#irb
Message.singleton_class #=> #<Class:Message>
#ruby 1.8.x
class Message
#define this method to get singleton class
def self.singleton_class
class << self
self
end
end
end
#irb
Message.singleton_class #=> #<Class:Message>

First defining singleton method to create singleton methods.

class Message
def self.create_singleton_methods *methods
methods.each do |method_name|
singleton_class.send :define_method, method_name do |arg|
"#{method_name} #{arg}"
end
end
end
end
#irb
Message.singleton_methods false #=> [:create_singleton_methods]
Message.create_singleton_methods 'like' #=> ["like"]
Message.singleton_methods false #=> [:create_singleton_methods, :like]
Message.like 'emre' #=> "like emre"

Then defining instance method to create singleton methods.

class Message
def create_singleton_methods *methods
methods.each do |method_name|
self.class.singleton_class.send :define_method, method_name do |arg|
"#{method_name} #{arg}"
end
end
end
end
#irb
Message.instance_methods false #=> [:create_singleton_methods]
Message.new.create_singleton_methods 'poke' #=> ["poke"]
Message.singleton_methods false #=> [:poke]
Message.poke 'emre' #=> "poke emre"

Comments