我有一个包装类,它重新定义了包装类的方法。有没有办法可以从覆盖方法中访问包装器的状态?
class WidgetWrapper
attr_accessor :result_saved_by_widget
def initialize(widget)
@widget = widget
# we intercept the widget's usual "save" method so we can see
# what the widget tries to save
def @widget.save_result(result) # this override works fine ...
OUTER.result_saved_by_widget = result # .. but I need something like this inside it!
end
end
def call
widget.calculate # this will call "save_result" at some stage
end
end
# How it gets used
wrapper = Wrapper.new(Widget.new)
wrapper.call
puts wrapper.result_saved_by_widget
答案 0 :(得分:2)
根据你的例子,我会extend
带有模块的对象:
module WidgetExtension
attr_accessor :results_saved_by_widget
def save_result(result)
@results_saved_by_widget = result
super
end
end
w = Widget.new
w.extend(WidgetExtension)
w.calculate
w.results_saved_by_widget #=> stored value
答案 1 :(得分:1)
使用一个非常愚蠢的黑客来解决这个问题 - 事先使用instance_variable_set注入包装器对象。
class WidgetWrapper
attr_accessor :result_saved_by_widget
def initialize(widget)
@widget = widget
@widget.instance_variable_set :@wrapper, self
# we intercept the widget's usual "save" method so we can see
# what the widget tries to save
def @widget.save_result(result) # this override works fine ...
@wrapper.result_saved_by_widget = result # ... and this works too :)
end
end
def call
widget.calculate # this will call "save_result" at some stage
end
end
# How it gets used
wrapper = Wrapper.new(Widget.new)
wrapper.call
puts wrapper.result_saved_by_widget
答案 2 :(得分:1)
实际上,并不难。几点:
save_result
。否则,它不是一个包装器。你需要使用闭包来捕捉当前的词汇上下文(意思是,记住我们在WidgetWrapper
中的内容)
class Widget
def calculate
save_result(3)
end
def save_result(arg)
puts "original save_result: #{arg}"
end
end
class WidgetWrapper
attr_accessor :result_saved_by_widget, :widget
def initialize(widget)
@widget = widget
wrapper = self # `self` can/will unpredictably change.
@widget.define_singleton_method :save_result do |result|
wrapper.result_saved_by_widget = result
super(result)
end
end
def call
widget.calculate
end
end
# How it gets used
wrapper = WidgetWrapper.new(Widget.new)
wrapper.call
puts 'intercepted value'
puts wrapper.result_saved_by_widget
# >> original save_result: 3
# >> intercepted value
# >> 3
答案 3 :(得分:1)
我不太了解你的问题,但我认为过去做的事情非常相似,也许以下几行可以帮到你:
documents_to_wrap.each do |doc|
doc.define_singleton_method(:method){override_code}
tmp = doc.instance_variable_get(:@instance_var).
doc.instance_variable_set(:@other_instance_var, tmp.do_something)
end