views:

949

answers:

2

This is useful if you are trying to create class methods metaprogramatically:

def self.create_methods(method_name)
    # To create instance methods:
    define_method method_name do
      ...
    end

    # To create class methods that refer to the args on create_methods:
    ???
end

My answer to follow...

+1  A: 

Derived from: Jay and Why, who also provide ways to make this prettier.

self.create_class_method(method_name)
  (class << self; self; end).instance_eval do
    define_method method_name do
      ...
    end
  end
end


Update: from VR's contribution below; a more concise method (as long as you're only defining one method this way) that is still standalone:

self.create_class_method(method_name)
  (class << self; self; end).send(:define_method, method_name) do
    ...
  end
end

but note that using send() to access private methods like define_method() is not necessarily a good idea (my understanding is that it is going away in Ruby 1.9).

Chinasaur
Better (?) alternative may be to put things in a module and then have your create_class_method extend the module onto the class???See: http://blog.jayfields.com/2008/07/ruby-underuse-of-modules.html
Chinasaur
+5  A: 

I prefer using send to call define_method, and I also like to create a metaclass method to access the metaclass:

class Object
  def metaclass
    class << self
      self
    end
  end
end

class MyClass
  # Defines MyClass.my_method
  self.metaclass.send(:define_method, :my_method) do
    ...
  end
end
Vincent Robert
Thanks! Definitely there are ways to make this nicer for yourself. But if you are working on an open source plugin, for example, I think it's nicer not to clog up the namespace with `metaclass`, so it's nice to know the easy, standalone shorthand.
Chinasaur
I decided to go with my original answer. My understanding is that using send() to access private methods if going away in Ruby 1.9, so that didn't seem like a good thing to use. Plus if you are defining more than one method, instance_evaling a block is cleaner.
Chinasaur