Ruby on rails Ruby方法\u添加了不包含模块的回调触发器
我想写一个小的“Deprecate It”库,并经常使用“method_added”回调。 但是现在我注意到,当包含一个模块时,这个回调不会被触发 是否有任何回调或变通方法,以便在包含somewhing时通知类“Foobar” 要演示的小演示: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
# 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;结束