А как насчет этого простого подхода:
class Outer
def hello
puts "hello"
end
class Inner
def initialize outer
@outer = outer
end
def world
puts "world"
end
def method_missing(method, *args, &block)
@outer.send(method, *args, &block)
rescue NoMethodError # you can also add this
puts "#{method} is undefined in both inner and outer classes"
end
end
def inner(&block)
inner = Inner.new self
inner.instance_eval(&block)
inner
end
end
o = Outer.new
o.inner do
hello
cruel
world
end
Распечатает
hello
cruel is undefined in both inner and outer classes
world
В этом случае, если внутренний класс не определяет требуемый метод, он делегирует его внешнему классу, используя Object # send . Вы можете поймать NoMethodError
внутри method_missing
, чтобы контролировать ситуацию, когда класс Outer
не определяет делегированный метод.
UPDATE
Вы также можете использовать волокна для решения проблемы:
class Outer
def hello
puts "hello"
end
class Inner
def world
puts "world"
end
def method_missing(method, *args, &block)
Fiber.yield [method, args, block] # pass method args to outer
end
end
def inner(&block)
inner = Inner.new
f = Fiber.new { inner.instance_eval(&block) }
result = nil # result for first fiber call does not matter, it will be ignored
while (undef_method = f.resume result) # pass method execution result to inner
result = self.send(undef_method[0], *undef_method[1], &undef_method[2])
end
inner
end
end