这些Ruby命名空间约定之间有什么区别?

时间:2011-10-19 12:40:16

标签: ruby

因此可以在Ruby中使用Module来提供除mixins之外的命名空间,如下所示:

module SomeNamespace
  class Animal

  end
end

animal = SomeNamespace::Animal.new

但我也看到了以下用法:

module SomeNamespace
end

class SomeNamespace::Animal

end

animal = SomeNamespace::Animal.new

我的问题是它们是如何不同的(如果它们是)并且哪个是更惯用的Ruby?

2 个答案:

答案 0 :(得分:40)

区别在于嵌套。

在下面的示例中,您可以看到使用类Foo的前一个方法可以无错误地获取外部作用域的常量变量BAR_A。

与此同时,Baz类会弹出未初始化的常数A :: B :: Baz :: BAR_A的错误。因为它没有隐含地引入A :: *,只有A :: B :: *显式。

module A
  BAR_A = 'Bar A!'
  module B
    BAR_B = 'Bar B!'
      class Foo
        p BAR_A
        p BAR_B
      end
  end
end

class A::B::Baz
  p BAR_A
  p BAR_B
end

这两种行为都有自己的位置。在我看来,社区中没有真正的共识,哪一个是真正的Ruby方式(tm)。我个人大多数时候都会使用前者。

答案 1 :(得分:6)

这两种方法之间的唯一区别是,如果先前未声明名称空间,则第二种方法将抛出uninitialized constant Object::SomeNamespace

在单个文件中声明时,我会选择第一个,因为您不必重复SomeNamespace

当使用多个文件时,我也使用第二个文件,以避免遇到以下问题:

# in a.rb
require 'b'

module SomeNamespace
  def self.animal
    Animal.new
  end
end

# in b.rb
class SomeNamespace::Animal

end

# irb
require 'a' # explodes with the uninitialized constant error

这个例子可能是人为的,但如果你的代码库有点大,很容易触发它。我通常使用明确的方式(你的第一个)来避免这种情况。

使用第二种形式时可能有用的一点是它会检测命名空间中的拼写错误。

似乎没有一种既定的方法来创建名称空间,例如,Devise混合了两种方法:first onesecond one