У меня есть пара модулей, которые расширяют метод, отсутствующий:
module SaysHello
def respond_to?(method)
super.respond_to?(method) || !!(method.to_s =~ /^hello/)
end
def method_missing(method, *args, &block)
if (method.to_s =~ /^hello/)
puts "Hello, #{method}"
else
super.method_missing(method, *args, &block)
end
end
end
module SaysGoodbye
def respond_to?(method)
super.respond_to?(method) || !!(method.to_s =~ /^goodbye/)
end
def method_missing(method, *args, &block)
if (method.to_s =~ /^goodbye/)
puts "Goodbye, #{method}"
else
super.method_missing(method, *args, &block)
end
end
end
class ObjectA
include SaysHello
end
class ObjectB
include SaysGoodbye
end
Это все работает хорошо, например, ObjectA.new.hello_there
вывод "Hello, hello_there"
. Аналогично, ObjectB.new.goodbye_xxx
выводит "Goodbye, xxx"
. respond_to?
также работает, например, ObjectA.new.respond_to? :hello_there
возвращает true.
Однако, это не очень хорошо работает, если вы хотите использовать SaysHello
и SaysGoodbye
:
class ObjectC
include SaysHello
include SaysGoodbye
end
Хотя ObjectC.new.goodbye_aaa
работает правильно, ObjectC.new.hello_a
ведет себя странно:
> ObjectC.new.hello_aaa
Hello, hello_aaa
NoMethodError: private method `method_missing' called for nil:NilClass
from test.rb:22:in `method_missing' (line 22 was the super.method_missing line in the SaysGoodbye module)
Выводит правильно, затем выдает ошибку. Также respond_to?
не правильно, ObjectC.new.respond_to? :hello_a
возвращает false.
Наконец, добавив этот класс:
class ObjectD
include SaysHello
include SaysGoodbye
def respond_to?(method)
super.respond_to?(method) || !!(method.to_s =~ /^lol/)
end
def method_missing(method, *args, &block)
if (method.to_s =~ /^lol/)
puts "Haha, #{method}"
else
super.method_missing(method, *args, &block)
end
end
end
Также действует странно. ObjectD.new.lol_zzz
работает, однако ObjectD.new.hello_a and ObjectD.new.goodbye_t
оба выдают исключение имени после вывода правильной строки. respond_to?
также не работает для методов hello и goodbye.
Есть ли способ заставить все это работать правильно? Объяснение того, как method_missing
, Модули и super
взаимодействуют, также было бы очень полезно.
РЕДАКТИРОВАТЬ: coreyward решил проблему, если я использую super вместо super.<method-name>(args...)
во всех определяемых мной методах, программа работает правильно. Я не понимаю, почему это так, поэтому я задал еще один вопрос по этому поводу на Что делает super. в ruby?