开发者

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?


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


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"


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)


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


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.


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"


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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜