在Ruby中,我想捕获在另一个对象中的对象上生成的NoMethodError,然后将一些值返回到引发异常的位置并继续执行。有没有现成的方法呢?
我想出的最好的是:
class Exception
attr_accessor :continuation
end
class Outer
def hello
puts "hello"
end
class Inner
def world
puts "world"
end
def method_missing(method, *args, &block)
x = callcc do |cc|
e = RuntimeError.exception(method)
e.continuation = cc
raise e
end
return x
end
end
def inner(&block)
inner = Inner.new
begin
inner.instance_eval(&block)
rescue => e
cc = e.continuation
cc.call(hello())
end
inner
end
end
o = Outer.new
o.inner do
hello
world
end
打印
hello
world
使用Ruby现有的元编程库数据库有没有更好的方法呢?基本上,我不确定callcc是否会继续存在。
感谢。
答案 0 :(得分:5)
这个简单的方法怎么样:
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
类未定义委托方法时控制情况。
<强>更新强> 您也可以使用光纤来解决问题:
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
答案 1 :(得分:2)
Ruby有一个名为throw
的关键字,可用于向上传播错误。我无法从你的帖子中确切地告诉你你想要这个块,但它是这样的:
class Outer
catch :NoMethodError do
#process the exception thrown from inner
end
class Inner
def some_method
##...some other processing
throw :NoMethodError if #....
#remaining statements
end
end
end
在throw语句和catch块执行后,some_method
中的其余语句应该执行
希望这有帮助