Ove*_*ked 6 ruby metaprogramming
在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
Run Code Online (Sandbox Code Playgroud)
这打印
hello
world
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来使用Ruby现有的元编程库?基本上,我不确定callcc是否会继续存在.
谢谢.
这个简单的方法怎么样:
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
Run Code Online (Sandbox Code Playgroud)
会打印
hello
cruel is undefined in both inner and outer classes
world
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如果内部类没有定义所需的方法,则使用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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9517 次 |
| 最近记录: |