Reputation: 6322
Say I have a class like:
class Person
module Health
GOOD = 10
SICK = 4
DEAD = 0
end
end
I can reference such Health codes like: Person::Health::GOOD
. I'd like to dynamically generate a hash that maps from number values back to constant names:
{ 10 => "GOOD",
4 => "SICK",
0 => "DEAD" }
To do this dynamically, I've come up with:
Person::Health.constants.inject({}) do |hsh, const|
hsh.merge!( eval("Person::Health::#{const}") => const.to_s )
end
This works, but I wonder if there's a better/safer way to go about it. It's in a Rails app, and while it's nowhere near any user input, eval
still makes me nervous. Is there a better solution?
Upvotes: 1
Views: 276
Reputation: 3055
You can use constants
and const_get
for this purpose.
ph = Person::Health # Shorthand
Hash[ph.constants(false).map { |c| [ph.const_get(c), c.to_s ] }]
# {10=>:GOOD, 4=>:SICK, 0=>:DEAD}
I added false
to .constants
to prevent including any inherited constants from included Modules. For example, without false
the following scenario would also include a 5 => "X"
mapping:
module A
X = 5
end
class Person
module Health
include A
# ...
end
end
Hash[ph.constants.map { |c| [ph.const_get(c), c.to_s ] }]
# {10=>"GOOD", 4=>"SICK", 0=>"DEAD", 5=>"X"}
Upvotes: 4