Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/67.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.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 on rails Ruby方法\u添加了不包含模块的回调触发器_Ruby On Rails_Ruby_Callback - Fatal编程技术网

Ruby on rails Ruby方法\u添加了不包含模块的回调触发器

Ruby on rails Ruby方法\u添加了不包含模块的回调触发器,ruby-on-rails,ruby,callback,Ruby On Rails,Ruby,Callback,我想写一个小的“Deprecate It”库,并经常使用“method_added”回调。 但是现在我注意到,当包含一个模块时,这个回调不会被触发 是否有任何回调或变通方法,以便在包含somewhing时通知类“Foobar” 要演示的小演示: # Including Moduls won't trigger method_added callback module InvisibleMethod def invisible "You won't get a callback fr

我想写一个小的“Deprecate It”库,并经常使用“method_added”回调。 但是现在我注意到,当包含一个模块时,这个回调不会被触发

是否有任何回调或变通方法,以便在包含somewhing时通知类“Foobar”

要演示的小演示:

# Including Moduls won't trigger method_added callback

module InvisibleMethod
  def invisible
    "You won't get a callback from me"
  end
end

class Foobar
  def self.method_added(m)
    puts "InstanceMethod: '#{m}' added to '#{self}'"
  end

  def visible
    "You will get a callback from me"
  end

  include InvisibleMethod
end

[:invisible, :visible, :wont_exist].each do |meth|
  puts "#{meth}: #{Foobar.public_method_defined? meth}"
end
这就是结果:

InstanceMethod: 'visible' added to 'Foobar'
invisible: true
visible: true
wont_exist: false
其他信息:

我真的需要使用一个类似钩子的方法


ActiveModel正在运行时通过匿名模块向类添加公共\u实例\u方法。

正如其中一条评论所建议的,您可以使用其他钩子来获得所需的行为。例如,尝试在代码开头添加以下内容:

class Module
  def included(klass)
    if klass.respond_to?(:method_added)
      self.instance_methods.each do |method|
        klass.method_added(method)
      end
    end
  end
end
每当一个模块包含在一个类中时,该模块的所有实例方法都将被通知给该类,只要它定义了添加的方法
method\u
。通过使用上面的更改运行代码,我得到以下结果:

InstanceMethod: 'visible' added to 'Foobar'
InstanceMethod: 'invisible' added to 'Foobar'
invisible: true
visible: true
wont_exist: false

我认为这是您想要的行为。

问题在于,包含模块不会向类中添加方法,它只会更改方法调用链。该链定义了将在哪些类/模块中搜索方法,而该方法不是为所讨论的类定义的。当您包含一个模块时,会发生的事情是在该链中添加一个条目

这与在超类中添加方法完全相同-这不会调用
method\u added
,因为它没有在超类中定义。如果一个子类可以改变一个超类的行为,那将是非常奇怪的

您可以通过手动调用为包含的模块添加的方法,通过为您的类重新定义
include
,来解决这个问题:

class Foobar
  def self.include(included_module)
    included_module.instance_methods.each{|m| self.method_added(m)}
    super
  end
end

而且它比在
模块
中重新定义
包含的
方法要安全得多-更改仅限于您自己定义的类

我认为,
弃用
不是很大,因为我需要一个库。它在
datamapper
中是这样实现的。关于
method\u添加的
hook;由于已将方法添加到
模块
中,而不是
,因此它可以正常工作。只有您才能获得预期的结果,包括猴子修补
钩子

# got from https://github.com/datamapper/dm-core/blob/master/lib/dm-core/support/deprecate.rb
module Deprecate
  def deprecate(old_method, new_method)
    class_eval <<-RUBY, __FILE__, __LINE__ + 1
      def #{old_method}(*args, &block)
        warn "\#{self.class}##{old_method} is deprecated, use \#{self.class}##{new_method} instead (\#{caller.first})"
        send(#{new_method.inspect}, *args, &block)
      end
    RUBY
  end
end # module Deprecate

class MyClass
  extend Deprecate

  def old_method
    p "I am old"
  end
  deprecate :old_method, :new_method

  def new_method
    p "I am new"
  end
end

m = MyClass.new
m.old_method

# MyClass#old_method is deprecated, use MyClass#new_method instead (pinger.rb:27:in `<main>')
# "I am new"
#从https://github.com/datamapper/dm-core/blob/master/lib/dm-core/support/deprecate.rb
模块弃用
def弃用(旧方法、新方法)

不幸的是,我不认为有一个好的答案,但这可以为你指出一些有用的黑客的方向。。哦,如果有人在覆盖
included(klass)
时没有调用
super
,那就玩得开心吧。添加的方法默认是私有的,因此,如果你想做这个例子的相反操作,并在包含的模块内完成工作,你必须做:def self.included(base);base.send:method\u added,:method\u name;结束