当然,要实现我在标题中要求的内容,可以编写以下代码:
module Foo
class << self
def included receiver
my_herd << receiver
end
def my_herd; @my_herd ||= [] end
alias where_everywhere_am_I_included my_herd
end
end
Foo.where_everywhere_am_I_included #=> []
module Bar
include Foo
end
Foo.where_everywhere_am_I_included #=> [Bar]
# etc.
我可以想象更糟这样做的方法,比如搜索ObjectSpace
所有模块并grep他们的祖先。我想知道的是,还有更好的方法吗?我忘了某些东西,比如方法Module#included_in
。我错过了一些聪明的东西,例如。着名的#append_features
方法?我有更好的选择吗?
编辑:我正在解决的现实世界问题与提供物理单位方法的my library SY有关。物理单位方法,例如1.metre
,1.m
,1.s
,1.lb
,1.K
,往往是容易发生碰撞的简单符号。例如。 ActiveSupport
已经在#hour
上定义了时间方法#minute
,#second
,Numeric
。 SY还通过a #hour
在#h
上定义方法#minute
别名#min
,#second
别名#s
,Numeric
别名#method_missing
mixin提供ActiveSupport
对单位方法的反应。但是,使用#hour
的人已经定义了#minute
,#second
,#method_missing
,因此SY
将无法启动。他们仍然可以访问#h
} #min
,#s
,Module#included
缩写的方法,但除此之外。关键是,当mixin在包含它的模块中发现可能的冲突时,应该警告人们。这可以通过在PINT = Unit.of Volume, amount: 568.26.cm³
QUART = Unit.of Volume, amount: 2.pint
钩子中编码碰撞检查来简单地实现。但问题是用户还可以动态定义单位,例如:
#quart
但是可以想象用户已经在Numeric
上定义了QUART = Unit#of...
方法,做了其他事情,比如计算接收器的四分之一,或者相对于接收器等返回第四个音程因此,当ze调用Numeric
构造函数时,我想让mixin SY::ExpressibleInUnits
报告其中混合的地方,并在{{1}}中看到碰撞后发出警告。我只是想让我的用户免于意外,我想知道什么是最有道德的(用Avdi的商标词)来做这件事。
答案 0 :(得分:1)
使用method_added
可以在现实场景中提供警告。
module MethodAdded
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def method_added(method_name)
if method_name == :my_magic
puts 'So sorry you did not like my code, it will not bother you now'
end
end
end
end
class Something
include MethodAdded
def my_magic
'I can create this method without worries.'
end
end
以下是我在评论中提到的扩展ClassMethods的可能性不大的一个例子。
module ClassMethods
def self.extended(base)
puts 'I am going to do all sorts of evil stuff now'
end
end
module MethodAdded
def self.included(base)
base.extend(ClassMethods)
end
module ClaszMethods #Intentional typo to demonstrate "risk"
end
end