Рубин: определение метода и деф


в качестве упражнения по программированию я написал фрагмент Ruby, который создает класс, создает два объекта из этого класса, monkeypatches один объект и полагается на method_missing для monkeypatch другой.

вот в чем дело. Это работает по назначению:

class Monkey

  def chatter
    puts "I am a chattering monkey!"
  end

  def method_missing(m)
    puts "No #{m}, so I'll make one..."
    def screech
      puts "This is the new screech."
    end
  end
end

m1 = Monkey.new
m2 = Monkey.new

m1.chatter
m2.chatter

def m1.screech
  puts "Aaaaaargh!"
end

m1.screech
m2.screech
m2.screech
m1.screech
m2.screech

Вы заметите, что у меня есть параметр для и method_missing. Я сделал это, потому что я надеялся использовать define_method для динамического создания отсутствующих методов с соответствующим именем. Однако не работает. На самом деле, даже с помощью define_method со статическим именем, например:

def method_missing(m)
  puts "No #{m}, so I'll make one..."
  define_method(:screech) do
    puts "This is the new screech."
  end
end

заканчивается следующим результатом:

ArgumentError: wrong number of arguments (2 for 1)

method method_missing   in untitled document at line 9
method method_missing   in untitled document at line 9
at top level    in untitled document at line 26
Program exited.

что делает сообщение об ошибке более странно, что у меня есть только один аргумент в пользу method_missing...

3 64

3 ответа:

define_method является (частным) методом объекта класс. Вы вызываете его из экземпляр. Не существует метода экземпляра с именем define_method, поэтому он возвращается в свой method_missing С :define_method (имя метода), и :screech (единственный аргумент, который вы передали define_method).

попробуйте вместо этого (чтобы определить новый метод для всех объектов обезьяна):

def method_missing(m)
    puts "No #{m}, so I'll make one..."
    self.class.send(:define_method, :screech) do
      puts "This is the new screech."
    end
end

или это (чтобы определить его только на объекте он называется при использовании объекта "eigenclass"):

def method_missing(m)
    puts "No #{m}, so I'll make one..."
    class << self
      define_method(:screech) do
        puts "This is the new screech."
      end
    end
end

self.класс.define_method (: screech)не работает, потому что define_method является частным методом вы можете сделать это

class << self
    public :define_method
end
def method_missing(m)
puts "No #{m}, so I'll make one..."
Monkey.define_method(:screech) do
  puts "This is the new screech."
end
def method_missing(m)
    self.class.class_exec do
       define_method(:screech) {puts "This is the new screech."}
    end 
end

метод screech будет доступен для всех объектов Monkey.