How do I use define_method to create class methods?

51,272

Solution 1

I think in Ruby 1.9 you can do this:

class A
  define_singleton_method :loudly do |message|
    puts message.upcase
  end
end

A.loudly "my message"

# >> MY MESSAGE

Solution 2

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

Solution 3

This is the simplest way in Ruby 1.8+:

class A
  class << self
    def method_name
      ...
    end
  end
end

Solution 4

To be used in Rails if you want to define class methods dynamically from concern:

module Concerns::Testable
  extend ActiveSupport::Concern

  included do 
    singleton_class.instance_eval do
      define_method(:test) do
        puts 'test'
      end
    end
  end
end

Solution 5

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).

Share:
51,272

Related videos on Youtube

Chinasaur
Author by

Chinasaur

Updated on July 08, 2022

Comments

  • Chinasaur
    Chinasaur almost 2 years

    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...

  • Chinasaur
    Chinasaur about 15 years
    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
    Chinasaur almost 15 years
    Better (?) alternative may be to put things in a module and then have your create_class_method extend the module onto the class??? See: blog.jayfields.com/2008/07/ruby-underuse-of-modules.html
  • Amol Pujari
    Amol Pujari almost 12 years
    @Vincent Robert any link which would explain the magic of metaclass method?
  • Vincent Robert
    Vincent Robert almost 12 years
    class << self; self; end; simply reopens the class of self (class << self) and then returns that class (self) so actually returning the metaclass of self.
  • Pyro
    Pyro over 11 years
    also singleton_class.define_method
  • A Fader Darkly
    A Fader Darkly about 11 years
    I really like this one. Small, neat, reads well and it's portable. Of course, you could ask what I'm doing using ruby 1.8 in 2013...
  • Joshua Pinter
    Joshua Pinter over 4 years
    @Pyro Just to clarify, would you just go singleton_class.define_method :loudly do |message| etc.?