Подтвердить что ты не робот

Добавить метод к инстанцированному объекту

obj = SomeObject.new

def obj.new_method
  "do some things"
end

puts obj.new_method
> "do some things"

Это работает нормально. Однако мне нужно сделать то же самое внутри существующего метода:

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

Работает нормально, но метод внутри метода выглядит довольно ужасно. Вопрос в том, есть ли альтернативный способ добавления такого метода?

4b9b3361

Ответ 1

Прошло много времени с тех пор, как я спросил об этом. В ruby ​​1.9+ лучший способ сделать это, используя define_singleton_method, следующим образом:

obj = SomeObject.new

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

Ответ 2

Используйте Mixin.

module AdditionalMethods
  def new_method
    "do some things"
  end
end

obj = SomeObject.new
obj.extend(AdditionalMethods)

puts obj.new_method
> "do some things"

Ответ 3

Просто интересно отметить:

если бы вы ушли:

def my_method
    def my_other_method; end
end

Тогда my_other_method будет фактически определен в КЛАССЕ объекта, не допуская, что приемник my_method является экземпляром.

Однако, если вы идете (как и вы):

def my_method
    def self.my_other_method; end
end

Затем my_other_method определяется на собственном экземпляре экземпляра.

Не имеет прямого отношения к вашему вопросу, но, тем не менее, интересен;)

Ответ 4

Вы можете использовать модули.

module ObjSingletonMethods
  def new_method
    "do some things"
  end
end


obj.extend ObjSingletonMethods

puts obj.new_method # => do some things

Теперь, если вам нужно добавить дополнительные методы к этому объекту, вам просто нужно реализовать методы в модуле, и вы закончили.

Ответ 5

class Some
end 

obj = Some.new

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

obj.hello

obj2 = Some.new
obj2.hello # error

class << obj синтаксиса class << obj означает, что мы открываем определение класса для объекта. Как вы, наверное, знаете, мы можем определить методы класса Ruby с помощью синтаксиса следующим образом:

class Math

    class << self 

        def cos(x)
            ...
        end 

        def sin(x)
            ...
        end 
    end 
end 

Затем мы можем использовать следующие методы:

Math.cos(1)

В Ruby все объекты - даже классы. self здесь является объектом самого Math class (вы можете получить доступ к этому объекту с помощью Math.class). Таким образом, class << self синтаксиса class << self означает, что мы открываем класс для Math class object класса Math class object. Да, это означает, что Math class имеет класс (Math.class.class).

Ответ 6

Для этого есть несколько синтаксисов, и все они связаны с классом singleton:

  1. Вы можете использовать class << idiom, чтобы открыть определение класса singleton:

    obj = Object.new
    class << obj
      def my_new_method
         ...
      end
    end
    
  2. Или вы можете использовать define_singleton_method для obj:

    obj = Object.new
    obj.define_sigleton_method(:my_new_method) do
         ...
    end
    
  3. Вы также можете использовать define_method из класса singleton:

    obj = Object.new
    obj.singleton_class.define_method(:my_new_method) do
         ...
    end
    
  4. Или вы можете напрямую использовать def:

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

Обратите внимание на пример 3, я думаю, что концепция одноэлементного класса становится более понятной для этого. Существует разница между этими двумя примерами:

    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

Это связано с тем, что каждый объект имеет свой собственный одноэлементный класс:

    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)

Ответ 7

Использовать instance_eval:

obj = SomeObject.new

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

obj.new_method 
> "do something new"