Add method to an instanced object

obj = SomeObject.new

def obj.new_method
  "do some things"
end

puts obj.new_method
> "do some things"

This works ok. However, I need to do same thing inside an existing method:

def some_random_method
  def obj.new_method
    "do some things"
  end
end

Works ok as well, but having a method inside a method looks pretty horrible. The question is, is there any alternate way of adding such a method?


Solution 1:

In ruby 1.9+, there's a better way of doing this using define_singleton_method, as follows:

obj = SomeObject.new

obj.define_singleton_method(:new_method) do
  "do some things"
end

Solution 2:

Use a Mixin.

module AdditionalMethods
  def new_method
    "do some things"
  end
end

obj = SomeObject.new
obj.extend(AdditionalMethods)

puts obj.new_method
> "do some things"

Solution 3:

There are several ways to achieve this, and they are all related to the singleton class:

  1. You can use class << idiom to open the singleton class definition:

     obj = Object.new
     class << obj
       def my_new_method
          ...
       end
     end
    
  2. Or you can use define_singleton_method on the obj:

     obj = Object.new
     obj.define_singleton_method(:my_new_method) do
          ...
     end
    
  3. You can also use define_method from the singleton class:

     obj = Object.new
     obj.singleton_class.define_method(:my_new_method) do
          ...
     end
    
  4. Or you can use def directly:

     obj = Object.new
     def obj.my_new_method
          ...
     end
    

Pay attention to example 3, I think the concept of a singleton class becomes clearer on that one. There is a difference between these two examples:

    a = Object.new
    b = Object.new
    
    # -- defining a new method in the object's "class" --
    a.class.define_method(:abc) do
      puts "hello abc"
    end
    
    a.abc # prints "hello abc"
    b.abc # also prints "hello abc"

    # -- defining a new method in the object's "singleton class" --
    a.singleton_class.define_method(:bcd) do
      puts "hello bcd"
    end
    
    a.bcd # prints "hello bcd"
    b.bcd # error undefined method

This is because every object has its own singleton class:

    a = Object.new
    b = Object.new

    p a.class # prints "Object"
    p a.singleton_class # prints "#<Class:#<Object:0x000055ebc0b84438>>"

    p b.class # also prints "Object"
    p b.singleton_class # prints "#<Class:#<Object:0x000055ebc0b84410>>" (a different reference address)