5

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

m = Module.new do
  class C
  end
end

三个问题:

  • 除了参考之外m,有没有办法可以访问C里面的其他东西m

  • 我可以在创建匿名模块后为其命名(就像我输入“模块...”一样)吗?

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

4

3 回答 3

7

三个答案:

  • 是的,使用ObjectSpace. 此代码在不引用的情况下引用c您的类:Cm

    c = nil  
    ObjectSpace.each_object { |obj|  
      c = obj if (Class === obj and obj.name =~ /::C$/)  
    }
    

    当然,这取决于C程序中没有其他类命名,但你明白了。

  • 是的,有点。如果您只是将它分配给一个常量,例如M = m,那么m.name将返回"M"而不是nil,并且引用 likeM::C将起作用。实际上,当我这样做并输入M::Cirb 时,我得到#<Module:0x9ed509c>::C了 ,但也许这是一个错误。

  • 我认为一旦没有对它的引用,即当没有 or 的实例或子类型,并且设置为不同的值或超出范围时,它应该被m垃圾C收集m。如果您将其分配给上述点的常量,您也需要将其更改为不同的值(尽管更改常量通常是不明智的)。
于 2010-05-21T15:39:33.860 回答
1

定义一个 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

然后你可以这样做:

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!"

定义to_s给你很好的输出ancestors

Sailor.ancestors 
#=> [Sailor, NamedModule:Piracy:70169997844420, Object, Kernel, BasicObject]

更新 - 使用命名宝石

在我和我的同事对此进行了实验之后,他编写了一个小型 gem 实现。查看命名宝石 - RubygemsGithub

于 2013-04-04T14:12:03.167 回答
0

我在 Ruby 1.9.3-p0 中尝试了 wdebeaum 的第二个回答,但没有成功。 M::C返回NameError: uninitialized constant M::CM.constants返回[]

所以你应该尝试这里建议的方法

m = Module.new do
  class self::C
  end
end

您可以m::C照常使用。

于 2012-01-18T22:54:11.197 回答