Add method to an instanced object

Ruby

Ruby Problem Overview


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?

Ruby Solutions


Solution 1 - Ruby

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

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

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)

Solution 4 - Ruby

Just an interesting point to note:

if you had instead gone:

def my_method
    def my_other_method; end
end

Then my_other_method would actually be defined on the CLASS of the object not withstanding that the receiver ofmy_method is an instance.

However if you go (as you did):

def my_method
    def self.my_other_method; end
end

Then my_other_method is defined on the eigenclass of the instance.

Not directly relevant to your question but kind of interesting nonetheless ;)

Solution 5 - Ruby

You can use modules.

module ObjSingletonMethods
  def new_method
    "do some things"
  end
end


obj.extend ObjSingletonMethods

puts obj.new_method # => do some things

Now if you need to add more methods to that object, you just need to implement the methods in the module and you are done.

Solution 6 - Ruby

class Some
end 

obj = Some.new

class << obj
  def hello 
    puts 'hello'
  end 
end 

obj.hello

obj2 = Some.new
obj2.hello # error

Syntax class << obj means that we are opening definition of the class for an object. As you probably know we can define Ruby class methods using syntax like this:

class Math

    class << self 
        
        def cos(x)
            ...
        end 

        def sin(x)
            ...
        end 
    end 
end 

Then we can use those methods like this:

Math.cos(1)

In Ruby, everything is an object - even classes. self here is an object of Math class itself (you can access that object with Math.class). So syntax class << self means we are opening class for Math class object. Yes, it means that Math class has class too (Math.class.class).

Solution 7 - Ruby

Use instance_eval:

obj = SomeObject.new

obj.instance_eval do
  def new_method
    puts 'do something new'
  end
end

obj.new_method 
> "do something new"

Solution 8 - Ruby

Another way to use a Mixin

obj = SomeObject.new
class << obj
  include AnotherModule
end

This includes all of the methods from AnotherModule into the current object.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionviseView Question on Stackoverflow
Solution 1 - RubyviseView Answer on Stackoverflow
Solution 2 - RubyRinziView Answer on Stackoverflow
Solution 3 - RubyDavid Rissato CruzView Answer on Stackoverflow
Solution 4 - RubyhorseyguyView Answer on Stackoverflow
Solution 5 - RubyChirantanView Answer on Stackoverflow
Solution 6 - RubykajamiteView Answer on Stackoverflow
Solution 7 - RubyEJAgView Answer on Stackoverflow
Solution 8 - RubyHippoManView Answer on Stackoverflow