1

当然,要实现我在标题中的要求,可以编写如下代码:

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方法?我有什么更好的选择?

编辑:我正在解决的现实世界问题与我的图书馆 SY有关,它提供了物理单位方法。物理单位方法,例如1.metre, 1.m, 1.s, 1.lb, 1.K, 往往是容易发生冲突的简单符号。例如。ActiveSupport已经定义了时间方法#hour, #minute, #secondon Numeric。SY 还通过提供对单元方法的反应的 mixin来定义方法#houralias #h#minutealias #min#secondalias #son 。但是使用的人已经定义了, ,因此不会加入。他们仍然可以通过,访问方法Numeric#method_missingActiveSupport#hour#minute#second#method_missingSY#h#min,#s缩写,但这不是重点。关键是,当 mixin 在包含它的模块中发现可能的冲突时,应该警告人们。这可以通过在Module#included钩子中编码碰撞检查来简单地实现。但问题是用户也可以动态定义单位,比如:

PINT = Unit.of Volume, amount: 568.26.cm³
QUART = Unit.of Volume, amount: 2.pint

但是可以想象用户已经#quart定义了方法Numeric,在做其他事情,比如计算接收器的四分之一,或者返回相对于接收器的第四个音程等。所以当 ze 调用QUART = Unit#of...构造函数时,我想问 mixinSY::ExpressibleInUnits报告它在哪里混入,并在看到碰撞后发出警告Numeric。我只是想让我的用户免于意外,我想知道什么是最有道德的(使用Avdi的商标词)。

4

1 回答 1

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
于 2013-05-21T21:41:49.750 回答