Есть рубиновый файл DSL, который мне нужно разобрать. Это выглядит как
# file B.rb
class B < A
hello "John"
end
hello "Mary"
Он вызывает функцию hello()
со строковым параметром как внутри, так и вне класса B
.
Я пытаюсь require
файл B.rb
и решить недостающие методы:
# file A.rb
# define a class A for subclassing, before loading B.rb
class A
end
# Try to catch the missing methods
def method_missing(name, *args, &block)
puts "tried to handle unknown method %s" % name # name is a symbol
end
require("./B.rb")
После запуска этого кода method_missing
вызывает бесконечный цикл.
Как захватить и разрешить неопределенный метод как внутри, так и вне класса B
? Я хочу знать, как называются методы и параметры в файле DSL.
🤔 А знаете ли вы, что...
Ruby активно используется во множестве веб-сервисов и стартапов.
Я намекнул на этот подход в своем комментарии, но подумал, что было бы полезно разъяснить.
Итак, прежде всего нам нужно определить method_missing
для чего-то, мы не можем определить это на верхнем уровне, потому что мы получим это предупреждение
переопределение Object#method_missing может вызвать бесконечный цикл
Вместо этого мы определим его на class A
(на уровне класса).
# in a.rb
class A
def self.method_missing(name, *args, &block)
puts "tried to handle unknown method %s" % name # name is a symbol
end
end
Теперь мы можем использовать class_eval
для оценки b.rb
в рамках class A
следующим образом:
# also in a.rb
A.class_eval(File.read("./b.rb"))
Теперь вызов «верхнего уровня» hello "Mary"
фактически выполняется в области класса A
(где определение method_missing
активно). Кроме того, поскольку class B
наследуется от A
, он также имеет определение method_missing
на уровне класса, поэтому вызов hello "John"
также поразит его.
Итак, запустив скрипт, я вижу, что tried to handle unknown method hello
напечатано дважды, как и ожидалось.
Должен отметить, я не думаю, что это хорошая идея просто "игнорировать" ошибки таким образом... скорее всего, лучше остановить выполнение программы. Но, возможно, вы имеете в виду что-то, что требует этого, я не могу знать наверняка.
Эта строчка в твоем method_missing
,
puts "tried to handle unknown method %s" % name # name is a symbol
приводит к вызову to_ary
, который не определен, и снова вызывает method_missing
. Отсюда ваш бесконечный цикл.
def method_missing(name, *args, &block)
p name
puts "tried to handle unknown method %s" % name # name is a symbol
end
# =>
...
...
:to_ary
:to_ary
:to_ary
/System/Library/.../kernel_require.rb:55: stack level too deep (SystemStackError)
Исправление довольно простое, если вы хотите сделать это таким образом. Используйте интерполяцию строк.
puts "tried to handle unknown method #{name.to_s}"
# =>
Tried to handle unknown method hello
Tried to handle unknown method hello