Yeonho
Yeonho

Reputation: 3623

How to get the name of the constant

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

Answers (4)

Cary Swoveland
Cary Swoveland

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

Jörg W Mittag
Jörg W Mittag

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

Alastair Brown
Alastair Brown

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

Pramod
Pramod

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

Related Questions