目前,我正在执行类似以下内容的Runnable
课程' run
的{{1}}方法访问方法:
ExecutionContext
这个想法是class ExecutionContext
def message(text)
puts "ExecutionContext.message: #{text}"
end
def answer?
puts "ExecutionContext.answer called"
true
end
end
class Controller
def do_run(context)
@context = context
run
@context = nil
end
def method_missing(mth, *args)
@context.send(mth, *args)
end
end
class Runnable < Controller
def run
if answer?
message "Runnable's block executing!"
end
end
end
runnable = Runnable.new
context = ExecutionContext.new
runnable.do_run(context)
课程由&#34;最终用户&#34;谁想要访问从其他地方提供的Runnable
实例的功能(例如message
和answer?
方法)。实际上,ExecutionContext
类是所有&#34;最终用户&#34;我们关注并且它应该尽可能小而简单。
上面的代码按预期工作,Runnable
调用的所有方法都由Runnable.run
提供。
但是我想知道是否有更优雅的方法来实现同样的目的,我可以避免使用ExecutionContext
并定义临时method_missing
实例变量。
理想情况下,我想将代码修改为与此类似的代码(@context
保持不变):
ExecutionContext
是否有class Controller
def do_run(context, runnable)
runnable.extend_from_instance(context)
runnable.run
end
end
class Runnable
def run
if answer?
message "Runnable's block executing!"
end
end
end
runnable = Runnable.new
context = ExecutionContext.new
Controller.new.do_run(context, runnable)
这样的事情?
感谢大家对此进行调查。
由于我到目前为止已经提到了两个答案,我意识到我应该提到以下限制:不幸的是extend_from_instance
和Runnable
都不能变成ExecutionContext
s。它们需要module
es,因为它们的实例对于不同的情况会有不同的行为(两者都有自己的实例变量等)。
我真的需要执行class
方法,就像它是run
实例(代码中的ExecutionContext
)的一部分一样。
答案 0 :(得分:1)
是的,在这种情况下,您不想使用method_missing
。
我真的不明白你想要完成什么。也许define_block
不是正确的名字......?
但是,模块似乎具有您想要的功能。
module Messaging
def message(text)
puts "Provider.message: #{text}"
end
end
class Parent
include Messaging
...
编辑:我认为你想使用绑定。它允许您将当前范围(上下文)传递给另一个范围。
def print_local binding
puts 'local is ' + binding.eval('local')
end
def foo
local = 'value'
print_local binding
end
foo
=> local is value
在这种情况下,print_local想要打印foo的local
变量。但它无法访问它,因为local
仅存在于foo的范围(或上下文)中。
因此,您可以将foo的范围作为binding
传递。
请参阅binding。
答案 1 :(得分:0)
我认为B Seven说的是正确的。在类Module
和include
模块中创建共享功能最有意义。但是,如果您真的想要像extend_from_instance
这样的东西,您可以使用Ruby的Object#extend方法在类的实例中动态扩展模块(尽管我认为这样是一个坏主意)。使用您想要的代码:
module ExecutionContext
def message(text)
puts "ExecutionContext.message: #{text}"
end
def answer?
puts "ExecutionContext.answer called"
true
end
end
class Controller
def do_run(context_module, runnable)
runnable.extend(context_module)
runnable.run
end
end
class Runnable
def run
if answer?
message "Runnable's block executing!"
end
end
end
runnable = Runnable.new
Controller.new.do_run(ExecutionContext, runnable)
但是,这是一个坏主意,从长远来看可能会回来咬你。