列出包含模块的地方的最佳方式

时间:2013-05-21 18:35:07

标签: ruby module

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

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.metre1.m1.s1.lb1.K,往往是容易发生碰撞的简单符号。例如。 ActiveSupport已经在#hour上定义了时间方法#minute#secondNumeric。 SY还通过a #hour#h上定义方法#minute别名#min#second别名#sNumeric别名#method_missing mixin提供ActiveSupport对单位方法的反应。但是,使用#hour的人已经定义了#minute#second#method_missing,因此SY将无法启动。他们仍然可以访问#h } #min#sModule#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的商标词)来做这件事。

1 个答案:

答案 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