想象一下,您经常需要将一组来自超类的方法包装在一些静态代码或方面,但每个方法的结果/不同的行数很少,例如,将更新通知包装在数组方法周围以获得可观察的数组。
我的第一个想法是,我希望使用一个类级别的方法,例如:
class MyArray < Array
extend ObserverHelper # defines :wrap_method
wrap_notify(:[]=) do |index_or_range, *args|
[self[index_or_range], super(index_or_range, *args)]
# much nicer it would be to define
# removed = self[index_or_range]
# added = super(index_or_range, *args)
# but this makes it even more complicated (suggestions welcome!)
end
...
end
到现在为止还挺好。现在如何实现 :wrap_method?我最有希望的方法已经走到了这一步。由于超级而不起作用:
require 'observer'
module ObserverHelper
include Observable
def wrap_notify(meth, &block)
define_method meth,->(*args) {
removed, added = instance_exec(*args, &block)
changed
notify_observers(removed, added)
added
}
end
end
错误:
如果直接在数组子类上定义:超级在方法外调用
如果在模块中定义并包含到数组中:“不支持定义到多个类的单例方法的超级;这将在 1.9.3 或更高版本中修复”或“分段错误”,如果该方法具有正确的返回值)
我搜索了一段时间,但没有找到改变闭包绑定的可取解决方案,但是,也许我错过了一些东西,或者你可以不解决它?
Rails 通过评估字符串来做这些事情,还不确定我是否想这样。性能尚不重要,但会很重要。因此,我需要有关不同可能性和性能问题的反馈。
最后,我运行了两个更详细的解决方案。首先,传递实例,没有 super 也没有 self:
wrap_observer(:[]=) do |instance, index_or_range, *args|
[instance[index_or_range], instance.send(meth, index_or_range, *args)]
end
另一种使用 wrap_observer 作为 instance_method:
def []=(index_or_range, *args)
wrap_observer do
[self[index_or_range], super(index_or_range, *args)]
end
end
我认为这是可取的。
DSL 的解决方案可能是在没有包装器的情况下定义方法,然后迭代定义的方法添加它。
是否有更多方法可以使用我想要的 DSL 来解决这个高性能和可维护的问题?