Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby块-包装和自定义超类方法(使用define_方法和块)_Ruby_Binding_Closures - Fatal编程技术网

Ruby块-包装和自定义超类方法(使用define_方法和块)

Ruby块-包装和自定义超类方法(使用define_方法和块),ruby,binding,closures,Ruby,Binding,Closures,想象一下,您经常需要在一些静态代码或APECT中包装来自一个超类的一组方法,但每个方法的结果/不同行数很少,例如,围绕数组方法包装更新通知以获得一个可观察的数组 我的第一个想法是,我希望使用一个类级方法,如下所示: class MyArray < Array extend ObserverHelper # defines :wrap_method wrap_notify(:[]=) do |index_or_range, *args| [self[index_or_ran

想象一下,您经常需要在一些静态代码或APECT中包装来自一个超类的一组方法,但每个方法的结果/不同行数很少,例如,围绕数组方法包装更新通知以获得一个可观察的数组

我的第一个想法是,我希望使用一个类级方法,如下所示:

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
错误:

  • 如果直接在数组子类上定义: 在方法外部调用super

  • 如果在模块中定义并包含在阵列中: “不支持定义为多个类的单例超级方法;这将在1.9.3或更高版本中修复”或“分段错误”(如果该方法具有正确的返回值)

我搜索了一段时间,但没有找到一个合适的解决方案来更改闭包的绑定,但是,也许我遗漏了什么,或者您可以不用它来解决它

Rails通过对字符串求值来实现这些功能,但还不确定我是否愿意采用这种方式。性能还不重要,但将非常重要。因此,我需要关于不同可能性和性能问题的反馈

最后,我又运行了两个详细的解决方案。首先,通过实例,没有超级,没有自我:

  wrap_observer(:[]=) do |instance, index_or_range, *args|
    [instance[index_or_range], instance.send(meth, index_or_range, *args)]
  end
另一个使用wrap_observer作为实例_方法:

  def []=(index_or_range, *args)
    wrap_observer do
      [self[index_or_range], super(index_or_range, *args)]
    end
  end
我认为这更可取

DSL的一个解决方案可能是在不使用包装器的情况下定义方法,然后通过添加包装器的已定义方法进行迭代


有没有更多的方法可以解决这个性能问题,并且可以使用我想要的DSL进行维护?

重新绑定块的唯一方法是使用它定义一个方法,该方法还允许使用super。因此,您需要定义两种方法——可以使用模块来实现:

模块observer助手
def wrap_notify(meth,options={},&block)
覆盖=模块。新do
定义方法(方法和块)
结束
通知程序=Module.new do
定义|方法方法|*参数|
删除,添加=超级(*args)
选项| |={}
改变
通知观察员(删除、添加)
之后
结束
结束
包括覆盖
包含通知程序
结束
结束

此外,我想回答我自己的问题,因为这种方法基本上不起作用。方法更加多样化(例如,如前所述,[]=适用于数字和范围,但其他方法不适用),我找到了一个通用解决方案:

      define_method(meth) do |*args, &block|
        old_state = Array.new(self)
        r = super(*args,&block)
        new_state = Array.new(self)
        old_state.delete_if{|e| (i = new_state.index(e)) && new_state.delete_at(i)}
        unless new_state.empty? and old_state.empty?
          changed
          notify_observers(old_state, new_state, meth)
        end
        r
      end

因此,我可以在一个循环中重写所有方法,无需进行黑客攻击。基本上,我使用它作为回退和测试参考,而我在其他方面实现了更专门的方法

有趣的方法,确实,它使超级再次工作,非常感谢!
      define_method(meth) do |*args, &block|
        old_state = Array.new(self)
        r = super(*args,&block)
        new_state = Array.new(self)
        old_state.delete_if{|e| (i = new_state.index(e)) && new_state.delete_at(i)}
        unless new_state.empty? and old_state.empty?
          changed
          notify_observers(old_state, new_state, meth)
        end
        r
      end