Как я могу объявить метод динамически с method_missing? - PullRequest
5 голосов
/ 10 ноября 2011

У меня есть программа ruby, и я хочу принять созданный пользователем метод и создать новый метод из этого имени. Я пробовал это:

def method_missing(meth,*args,&block)
  name = meth.to_s
  class << self
    define_method(name) do
      puts "hello " + name
    end
  end
end

И я получаю следующую ошибку:

`define_method': interning empty string (ArgumentError) in 'method_missing'

Есть идеи? Благодарю.

Edit:

У меня это работает по-другому, но мне все еще интересно, как это сделать таким образом. Вот мой код:

def method_missing(meth,*args,&block)
  Adder.class_eval do
    define_method(meth) do
      puts "hello " + meth
    end
  end
  send("#{meth}")
end

Ответы [ 2 ]

12 голосов
/ 10 ноября 2011

Переменная name недоступна внутри области определения класса (class << self).Это не выдает NameError, потому что вы переопределили method_missing.

Чтобы сделать то, что вы пытаетесь сделать, вам нужно сохранить область действия с name.Чтобы сделать это, вы должны использовать только блочные методы (например, class_eval) вместо прямого открытия класса, так что-то вроде этого:

def method_missing(meth,*args,&block)
  name = meth.to_s
  eigenclass = class << self; self; end
  eigenclass.class_eval do
    define_method(name) do
      puts "hello " + name
    end
  end
end

Но на самом деле символ в meth вполне достаточно - вам не нужно имя вообще.(Хотя вам все равно понадобится описанная выше техника в любом случае.) Кроме того, вы хотите немедленно запустить метод.Самый простой способ - отправить сообщение:

def method_missing(meth,*args,&block)
  eigenclass = class << self; self; end
  eigenclass.class_eval do
    define_method(meth) do
      puts "hello #{meth}"
    end
  end
  send(meth, *args, &block)
end
1 голос
/ 10 ноября 2011

Проблема в том, что class << self не действует как замыкание, что означает, что переменная name не будет доступна внутри определения метода.

С другой стороны, когда вы используетеclass_eval, вы передаете блок (Proc), который является закрытием, что означает, что все локальные переменные из текущей привязки будут доступны внутри тела блока.

...