Add method to instantiated object
obj = SomeObject.new def obj.new_method "do some things" end puts obj.new_method > "do some things" This is working fine. However, I need to do the same inside an existing method:
def some_random_method def obj.new_method "do some things" end end It works fine, but the method inside the method looks pretty awful. The question is, is there an alternative way to add such a method?
It has been a long time since I asked about this. In ruby ββ1.9+, the best way to do this is using define_singleton_method , as follows:
obj = SomeObject.new obj.define_singleton_method(:new_method) do "do some things" end Use Mixin.
module AdditionalMethods def new_method "do some things" end end obj = SomeObject.new obj.extend(AdditionalMethods) puts obj.new_method > "do some things" Just interesting to note:
if you left:
def my_method def my_other_method; end end Then my_other_method will be actually defined in the object's my_other_method , not allowing the receiver my_method be an instance.
However, if you go (like you):
def my_method def self.my_other_method; end end Then my_other_method defined on the instance's own instance.
It is not directly related to your question, but, nevertheless, is interesting;)
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 additional methods to this object, you just need to implement the methods in the module, and you are done.
class Some end obj = Some.new class << obj def hello puts 'hello' end end obj.hello obj2 = Some.new obj2.hello # error class << obj syntax class << obj means that we open the class definition for the object. As you probably know, we can define Ruby class methods using the syntax as follows:
class Math class << self def cos(x) ... end def sin(x) ... end end end Then we can use the following methods:
Math.cos(1) In Ruby, all objects - even classes. self here is an object of the Math class (you can access this object using Math.class ). Thus, the class << self syntax of the class << self means that we open the class for the Math class object of the Math class object . Yes, that means the Math class has a class (Math.class.class).
There are several syntaxes for this, and they are all associated with the singleton class:
You can use
class <<idiom to open a singleton class definition:obj = Object.new class << obj def my_new_method ... end endOr you can use
define_singleton_methodfor obj:obj = Object.new obj.define_sigleton_method(:my_new_method) do ... endYou can also use
define_methodfrom the singleton class:obj = Object.new obj.singleton_class.define_method(:my_new_method) do ... endOr you can directly use
def:obj = Object.new def obj.my_new_method ... end
Pay attention to example 3, I think that the concept of a singleton class becomes more understandable for this. There is a difference between the two examples:
a = Object.new b = Object.new # -- defining a new method in the object "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 "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 due to the fact that each 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) 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"