What does a double colon do inside a module? [duplicate] - ruby

This question already has answers here:
What is Ruby's double-colon `::`?
(12 answers)
Closed 9 years ago.
I'm looking at the following code:
module Tag
def sync_taggings_counter
::Tag.find_each do |t|
# block here
end
end
end
and I'm confused by ::Tag inside the Tag module.
I know the double colon is used to name-space classes and modules within classes/modules. But I've never seen it used like the above. What does it mean exactly?

It's a scope modifier. Prefixing your constant (Tag) with a double colon ensures that you're looking in the root/global namespace instead of within your current module.
E.g.
module Foo
class Bar
def self.greet
"Hello from the Foo::Bar class"
end
end
class Baz
def self.scope_test
Bar.greet # Resolves to the Bar class within the Foo module.
::Bar.greet # Resolves to the global Bar class.
end
end
end
class Bar
def self.greet
"Hello from the Bar class"
end
end
The prepending is usually not neccessary as Ruby automatically looks in the global namespace, if it fails to find the referenced constant in the local module. So if no Bar existed in the Foo module, then Bar.greet and ::Bar.greet would do the exact same thing.

Related

Ruby Class namespacing with modules: Why do I get NameError with double colons but not module blocks?

I am working with a lot of pre-existing files, classes, and modules and trying to come up with better namespacing for the different components of the framework. I've been using modules as a way to namespace mainly because this seems like the standard convention (and being able to 'include' different parts of the framework could be useful).
The problem is that there was a ton of classes underneath the global namespace that should exist underneath a module. For example, let's say there is a class that was simply defined as:
class FirstClass
def meth
puts "HELLO"
end
end
But now I want to have this class within a module:
Using Double Colons:
module Foo; end
class Foo::FirstClass
def meth
puts 'HELLO'
end
end
Using Module Blocks:
module Foo
class FirstClass
def meth
puts 'HELLO'
end
end
Using double colons is a lot cleaner and also a lot easier to implement since I am changing many class definitions. Both of these ways work and I thought that they are both effectively the same thing, but evidently they are not. The double colon method seems to result in a different namespace within each class compared to the module block. For instance, with two classes underneath "Foo":
Using Module Blocks:
module Foo
class FirstClass
def meth
puts 'HELLO'
end
end
class SecondClass
def meth
FirstClass.new.meth
end
end
end
Foo::SecondClass.new.meth
Using Double Colons:
module Foo; end
class Foo::FirstClass
def meth
puts 'HELLO'
end
end
class Foo::SecondClass
def meth
FirstClass.new.meth
end
end
Foo::SecondClass.new.meth
The code works when using module blocks, but doesn't work with double colons. With the double colons, NameError is raised because it resolves FirstClass as Foo::SecondClass::FirstClass (instead of Foo::FirstClass), which doesn't exist.
This can easily be solved by including Foo in SecondClass, but how come this isn't done by default?
Note: I'm using Ruby 2.1.5, which I know is outdated, but I get the same results on repl.it with ruby 2.5.5p157: https://repl.it/#joep2/Colon-vs-Block-Namespacing
It may seem counter-intuitive, but constant lookup in Ruby is done using current lexical scope, i.e. the current lexical nesting level (location in the source code), not the semantic nesting level.
This can be tested by inspecting Module.nesting, which prints the current lexical scope:
class Foo::SecondClass
pp Module.nesting # -> [Foo::SecondClass]
end
module Foo
class SecondClass
pp Module.nesting # -> [Foo::SecondClass, Foo]
end
end
Since Ruby uses this nesting level for symbol lookup, it means in the situation where you try to look up FirstClass within nesting [Foo::SecondClass], Ruby will not find it.
However when you try to look it up within nesting [Foo::SecondClass, Foo], it will find FirstClass under Foo, just like you expect.
To get around this, you could do:
class Foo::SecondClass
def meth
Foo::FirstClass.new.meth
end
end
Which will now work as you expect, since you provided the necessary lookup hint for FirstClass, and told Ruby it is inside Foo.

Ruby scopes: Diference between MyClass.new and ::MyClass.new [duplicate]

This question already has answers here:
Ruby: what does :: prefix do?
(3 answers)
Closed 7 years ago.
I know that the double colon (::) is basically a namespace resolution operator. But in this particular case, I'm not sure in which scope I'm working. Does it mean that I want MyClass class from the ruby core? Sort of like ~ means home directory in bash..
Imagine the following code:
class A
def a
puts 'TOPMOST'
end
end
module B
class A
def a
puts 'NESTED'
end
end
def self.topmost
::A.new.a
end
def self.nested
A.new.a
end
end
B.topmost will print "TOPMOST", and B.nested will print "NESTED".
So, ::A means not “from ruby core”, but rather “from no module.”

ruby difference between class ClassName and class ::ClassName [duplicate]

This question already has answers here:
What is Ruby's double-colon `::`?
(12 answers)
Closed 8 years ago.
what's the difference between class ClassName and class ::ClassName in ruby?
class ClassName
end
vs
class ::ClassName
end
Your two examples would make difference if the classes were defined inside a ruby module, so:
module Foo
class ClassName
end
end
would define a new class inside the Foo module. This could be accessed like Foo::ClassName.
On the other hand, this:
module Foo
class ::ClassName
end
end
would define (or monkey-patch) the class ClassName in the root namespace.
::Class says 'look for Class in top level namespace'. The difference shows when in context of a module.
module A
def foo
X.new
end
end
A.foo # => A::X.new
module B
def foo
::X.new
end
end
B.foo # => X.new

Get a reference to the enclosing module in ruby

How do you get a reference to the enclosing module in ruby?
module Foo
##variable=1
def variable
##variable
end
class A
def somemethod
puts "variable=#{Foo.variable}" #<--this won't run, resolving Foo
# as the class instead of the module
end
end
class Foo
... # doesn't matter what's here
end
end
I ran into this question caused by naming confusion. While the names are easy enough to fix, I"m wondering what the "correct" way is to do this in ruby. If I try to run this it seems like ruby is trying to resolve Foo.variable as Foo::Foo.variable which of course fails. It seems like there should be a simple way in the language to refer to the outer module method.
You can get the outer module reference by adding the :: prefix to Foo:
::Foo.variable
In your example code:
module Foo
##variable=1
def variable
##variable
end
class A
def somemethod
puts "variable=#{::Foo.variable}"
end
end
class Foo
... # doesn't matter what's here
end
end

What is the difference between "include module" and "extend module" in Ruby? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
What is the difference between include and extend in Ruby?
Given:
module my_module
def foo
...
end
end
Question 1
What is the difference between:
class A
include my_module
end
and
class A
extend my_module
end
Question 2
Will foo be considered an instance method or a class method ?
In other words, is this equivalent to:
class A
def foo
...
end
end
or to:
class A
def self.foo
...
end
end
?
I wrote a blog posting about this a long time ago here.
When you're "including" a module, the module is included as if the methods were defined at the class that's including them, you could say that it's copying the methods to the including class.
When you're "extending" a module, you're saying "add the methods of this module to this specific instance". When you're inside a class definition and say "extend" the "instance" is the class object itself, but you could also do something like this (as in my blog post above):
module MyModule
def foo
puts "foo called"
end
end
class A
end
object = A.new
object.extend MyModule
object.foo #prints "foo called"
So, it's not exactly a class method, but a method to the "instance" which you called "extend". As you're doing it inside a class definition and the instance in there is the class itself, it "looks like" a class method.
1) include adds methods, constants, and variables on instances of class A; extend adds those things to the instance of the Class instance A (effectively defining class methods).
include my_module will allow this: A.new.foo
extend my_module will allow this: A.foo
More generally, include only makes sense on a Class or Module, while extend can be used to add methods to any Object.
2) In effect: when using include, foo is an instance method of A ... when using extend, foo is a class method.

Resources