Reputation: 3623
module Colors
Red = 0
Blue = 1
Green = 2
end
When I have the reference to the module Colors
, I can get the name of that module "Colors"
by Colors.name
.
Is it possible to get the string representation of the constant "Colors::Red"
when I have a reference to the constant Colors::Red
?
Upvotes: 3
Views: 4782
Reputation: 110675
Yes, provided only one constant has a value equal to the value of the given reference.
def ref_to_str(value)
k = Colors.constants.find { |k| Colors.const_get(k) == value }
k.nil? ? nil : "Colors::#{k}"
end
ref_to_str(0)
#=> "Colors::Red"
ref_to_str(1)
#=> "Colors::Blue"
ref_to_str(2)
#=> "Colors::Green"
ref_to_str(3)
#=> nil
Upvotes: 8
Reputation: 369428
'Colors'
is not the name of the constant Colors
, it is the name of the Module
that has been assigned to the constant Colors
. There is a fundamental difference between variables (and I include constants in this, together with local variables, instance variables, class variables, global variables, thread-local pseudo-globals, method-local pseudo-globals, and special variables) and objects, not the least of which is that objects are, well, objects (duh!) and variables are not objects! You cannot store them in variables, you cannot call methods on them, all you can do is assign them (at least some of them) and dereference them.
Since in an object-oriented language, method calling is pretty much all you can do, and you cannot call methods on variables because they aren't objects, there is no way that you can ask a variable questions such as "what is your name".
You can ask a Module
for its name, because the Module
class has a name
instance method that returns the Module
's name. Integer
doesn't have a name
method, so you cannot ask an Integer
for its name.
Note that the name of a Module
is somewhat "magical". It is nil
by default, but the first time you assign a Module
to a constant, the name will become some representation of the path to said constant (basically the name
of the enclosing module + ::
+ the name of the constant). However, if you assign the module to a different constant, even if you remove_const
the constant, the name will still stay the same.
Here's a nice little snippet of code that demonstrates that Module#name
really returns the name of the Module
, not the name of the variable used to refer to it:
m = Module.new
m.name
# => nil
A = m
m.name
# => 'A'
A = nil
Object.send(:remove_const, :A) # just to be *really* sure
A
# NameError: uninitialized constant A
m.name
# => 'A'
So, in short: no, there is no way you can get the name of a constant (or any variable) from the object referenced by that constant, even if just because the object can be referenced by more than one variable, and then what name would you return?
Upvotes: 1
Reputation: 1616
Try using constants
:
Colors.constants
so
Colors.constants[0].id2name
is Red
Colors.constants[1].id2name
is Blue
Colors.constants[2].id2name
is Green
Upvotes: 1
Reputation: 1416
No, It's not possible to get the string representation as Colors::Red
will refer to value of constant Red
defined in module Colors
.
Colors::Red => 0
However, You can get the list of constants for the module using Colors.constants
Colors.constants => [:Red, :Blue, :Green]
Upvotes: 1