Вы можете использовать TracePoint
API для отслеживания всех вызовов и возвращает метод и построить стек, чтобы увидеть ли метод, который вызывается уже в стеке. Таким образом, вы можете по крайней мере обнаружить рекурсии, а затем вы можете просто raise
исключение или exit
программы.
Что-то вроде:
stack = []
TracePoint.trace(:call, :return) do |trace|
p trace, stack
method = trace.method_id
case trace.event
when :call
if stack.include?(method)
$stderr.puts "RECURSION DETECTED: method `#{stack.last}` calls method `#{method}`."
exit!
end
stack.push(method)
when :return
stack.pop
end
end
def foo; bar end
def bar; baz end
def baz; qux end
def qux; bar end
foo
Обратите внимание, что я застрял в отладочный p
RINT там, так что вы можете наблюдать, как он работает:
#<TracePoint:call `foo'@./test.rb:20>
[]
#<TracePoint:call `bar'@./test.rb:21>
[:foo]
#<TracePoint:call `baz'@./test.rb:22>
[:foo, :bar]
#<TracePoint:call `qux'@./test.rb:23>
[:foo, :bar, :baz]
#<TracePoint:call `bar'@./test.rb:21>
[:foo, :bar, :baz, :qux]
RECURSION DETECTED: method `qux` calls method `bar`.
Что вы пытаетесь достичь? –
Можете ли вы уточнить? – sawa
Даже если бы оно существовало, это приложение нарушило бы почти 102% функциональности рубинового ядра. – mudasobwa