What exactly does ::SomeModule do? I first expected that it was a method like any other, getting called in the context it was in, so I went into irb to confirm.
1.8.7 :001 > class A; class B; end; end
=> nil
1.8.7 :002 > A.send(:::, :B)
SyntaxError: compile error
(irb):2: syntax error, unexpected tSYMBEG, expecting tCONSTANT
A.send(:::, :B)
^
from (irb):2
Ruby naturally had no idea what I meant by :::, but I was trying to turn "::" into a symbol to send to my class A.
1.8.7 :003 > A.::(B)
SyntaxError: compile error
(irb):3: syntax error, unexpected tCOLON2
A.::(B)
^
from (irb):3
So it seems :: isn't a method as I expected. Let's see if it accesses the current scope. So if I call ::B inside A, it should access the class B.
1.8.7 :004 > A.class_eval do
1.8.7 :005 > puts ::B
1.8.7 :006?> end
NameError: uninitialized constant B
from (irb):5
from (irb):4:in `class_eval'
from (irb):4
Maybe I need to instance_eval? (Note: there was no reason behind this guess or why this should work)
1.8.7 :007 > A.instance_eval do
1.8.7 :008 > puts ::B
1.8.7 :009?> end
NameError: uninitialized constant B
from (irb):8
from (irb):7:in `instance_eval'
from (irb):7
Nope. executing ::B in the context of A doesn't find it in that context.
1.8.7 :010 > A.instance_eval do
1.8.7 :011 > puts A::B
1.8.7 :012?> end
A::B
=> nil
Now I thought, well maybe it works like '..' in bash, which is a pointer to the directory one level up. So I reopened A::B to add a bubbles class method, and added a top-level B class with the same .bubbles method.
1.8.7 :013 > class A
1.8.7 :014?> class B
1.8.7 :015?> def self.bubbles
1.8.7 :016?> puts 'bubbling away'
1.8.7 :017?> end
1.8.7 :018?> end
1.8.7 :019?> end
=> nil
1.8.7 :020 > class B
1.8.7 :021?> def self.bubbles
1.8.7 :022?> puts 'frat frat frat frat'
1.8.7 :023?> end
1.8.7 :024?> end
=> nil
1.8.7 :025 > A.class_eval do
1.8.7 :026 > ::B.bubbles
1.8.7 :027?> end
frat frat frat frat
=> nil
So I was right, It does go up one level! But It could also just be going all the way up to the top-level namespace (since in this instance, being 1 level deep, 1 level up and all the way up are the same.)
We need to go deeper!
1.8.7 :031 > class A; class C; class B; def self.bubbles; puts 'in too deep!';end;end;end;end
=> nil
1.8.7 :032 > A::C.class_eval do
1.8.7 :033 > ::B.bubbles
1.8.7 :034?> end
frat frat frat frat
=> nil
This executed B.bubbles on the top-level class B, showing that :: bumps you all the way up the top-level context.
so it looks like it is useful when you are buried deep inside of a namespace, and know what the direct namespace from the top level is. So if you are in A::C::B and want to reference A::B, you can say ::A::B and always know you have the right one. Or if you had C::A::B and A::B and were inside C, calling A::B would give you C::A::B when you really wanted A::B, so you can use ::A::B.
Yep! But also, for legacy reasons (scary music), it also calls class methods. So,
Process.pid
is the same and preferred toProcess::pid
.