Surpreendentemente, todas as 10 respostas aqui dizem a mesma coisa. O '::' é um operador de resolução de espaço para nome e sim, é verdade. Mas há um problema que você precisa entender sobre o operador de resolução do espaço para nome quando se trata do algoritmo de pesquisa constante . Como Matz delineia em seu livro 'The Ruby Programming Language', a pesquisa constante tem várias etapas. Primeiro, ele pesquisa uma constante no escopo lexical onde a constante é referenciada. Se não encontrar a constante no escopo lexical, ela procurará na hierarquia de herança . Devido a esse algoritmo de pesquisa constante, abaixo obtemos os resultados esperados:
module A
module B
PI = 3.14
module C
class E
PI = 3.15
end
class F < E
def get_pi
puts PI
end
end
end
end
end
f = A::B::C::F.new
f.get_pi
> 3.14
Enquanto F herda de E, o módulo B está dentro do escopo lexical de F. Consequentemente, as instâncias F se referem à PI constante definida no módulo B. Agora, se o módulo B não definiu PI, as instâncias F se referem ao PI constante definida na superclasse E.
Mas e se usássemos '::' em vez de aninhar módulos? Teríamos o mesmo resultado? Não!
Ao usar o operador de resolução de espaço para nome ao definir módulos aninhados, os módulos e as classes aninhadas não estão mais dentro do escopo lexical de seus módulos externos. Como você pode ver abaixo, o PI definido em A :: B não está no escopo lexical de A :: B :: C :: D e, portanto, obtemos constante não inicializada ao tentar fazer referência ao PI no método de instância get_pi:
module A
end
module A::B
PI = 3.14
end
module A::B::C
class D
def get_pi
puts PI
end
end
end
d = A::B::C::D.new
d.get_pi
NameError: uninitialized constant A::B::C::D::PI
Did you mean? A::B::PI