I'd like to convert the constant FOO::BAR
to the string "BAR"
.
This is the opposite of what constantize
does and is very similar to demodulize
, except I expect a string instead of the actual Module reference.
I was thinking I could make my own helper to do this, but I'm not able to get the "stringified" version of FOO::BAR
.
Ideally, I'd like to avoid any 3rd party gems.
Example:
class FOO
BAR = {}
end
# this works
FOO #=> FOO
FOO.name #=> "FOO"
# this doesn't
FOO::BAR #=> {}
FOO::BAR.name #=> NoMethodError: undefined method `name' for {}:Hash
You can't pass constants, you can only pass objects. If you pass FOO::BAR
to a method, you're not passing the constant, but the object that has been assigned to FOO::BAR
, i.e. the hash.
In order to retrieve the constant's name an object has been assigned-to from the object itself, the object has to store the name somehow.
Modules do store the constant name they have been assigned-to (Ruby sets the name when a module is assigned to a constant for the first time). And because FOO
is a module (classes are modules), you can call FOO.name
and it returns "FOO"
. But that only works because the object "knows" its name.
From the built-in objects, only Module
(and therefore Class
) has a name
method that works this way.
You could add a name
method to the hash instance FOO::BAR
is referring to, although this is probably not what you want:
def (FOO::BAR).name
'FOO::BAR'
end
FOO::BAR.name #=> "FOO::BAR"
Another way is to pass both, the constant (the object actually) and its module to a method:
def find_const(mod, obj)
mod.constants.find { |c| mod.const_get(c).equal?(obj) }
end
find_const(FOO, FOO::BAR) #=> :BAR
The method traverses the module's constants and returns the (first) constant that refers to the passed object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With