在Ruby中使用匿名模块

在Ruby中使用匿名模块,ruby,module,anonymous,Ruby,Module,Anonymous,假设我制作一个模块,如下所示: m = Module.new do class C end end 三个问题: 除了对m的引用之外,我是否有办法访问C和m中的其他内容 我可以在创建匿名模块后为其命名吗(就像我键入“模块…”) 完成匿名模块后,如何删除它,使其定义的常量不再存在 三个答案: 是,使用ObjectSpace。此代码使c引用您的类c,而不引用m: c = nil ObjectSpace.each_object { |obj| c = obj if (Class

假设我制作一个模块,如下所示:

m = Module.new do
  class C
  end
end
三个问题:

  • 除了对
    m
    的引用之外,我是否有办法访问
    C
    m
    中的其他内容

  • 我可以在创建匿名模块后为其命名吗(就像我键入“模块…”)

  • 完成匿名模块后,如何删除它,使其定义的常量不再存在

三个答案:

  • 是,使用
    ObjectSpace
    。此代码使
    c
    引用您的类
    c
    ,而不引用
    m

    c = nil  
    ObjectSpace.each_object { |obj|  
      c = obj if (Class === obj and obj.name =~ /::C$/)  
    }
    
    当然,这取决于程序中没有其他名为
    C
    的类,但是您知道了

  • 是的,有点。如果您只是将它赋给一个常量,比如
    M=M
    ,那么
    M.name
    将返回
    “M”
    ,而不是
    nil
    ,并且像
    M::C
    这样的引用将起作用。实际上,当我这样做并在irb中键入
    M::C
    时,我得到了
    ::C
    ,但这可能是一个bug

  • 我认为,一旦没有对它的引用,即当没有
    m
    C
    的实例或子类型,并且
    m
    被设置为不同的值或超出范围时,应该对其进行垃圾收集。如果您将其指定给一个常量(如上所述),则还需要将其更改为另一个值(尽管更改常量通常是不明智的)

我用Ruby 1.9.3-p0尝试了Wdebaum的第二个答案,但没有成功。
M::C
返回
name错误:未初始化的常量M::C
M.constants
返回
[]

因此,您应该尝试建议的方法

您可以像往常一样使用
m::C

定义一个NamedModule 处理这个问题的一种方法是定义自己的模块类型,该模块可以用名称初始化

class NamedModule < Module
  attr_accessor :name

  def initialize(name, &block)
    super(&block)
    self.name = name
  end

  def to_s
    [self.class.name, name, object_id].join(':')
  end
end
定义为_
可以在
祖先中提供良好的输出:

Sailor.ancestors 
#=> [Sailor, NamedModule:Piracy:70169997844420, Object, Kernel, BasicObject]
更新-使用命名的gem 在我的同事和我对此进行了实验之后,他编写了一个小型的gem实现。查看命名的gem-and

piracy = NamedModule.new("Piracy") do
  def berate
    puts "Yer a #{adjectives.sample} #{nouns.sample}!"
  end

  private

  def adjectives
    %w[yella-bellied landlubbing]
  end

  def nouns
    %w[scallywag bilge-drinker]
  end
end

Sailor = Class.new
Sailor.send(:include, piracy)
Sailor.new.berate #=> "Yer a yella-bellied scallywag!"
Sailor.ancestors 
#=> [Sailor, NamedModule:Piracy:70169997844420, Object, Kernel, BasicObject]