meta-ruby:如何动态调用作用域常量?

时间:2014-04-17 21:59:51

标签: ruby metaprogramming

说我有一个类:

class Person
  module Health
    GOOD = 10
    SICK = 4
    DEAD = 0
  end
end

我可以参考像Person::Health::GOOD这样的健康代码。我想动态生成一个从数值映射回常量名称的哈希:

{ 10 => "GOOD",
   4 => "SICK",
   0 => "DEAD" }

为了动态地做到这一点,我想出了:

Person::Health.constants.inject({}) do |hsh, const|
  hsh.merge!( eval("Person::Health::#{const}") => const.to_s )
end

这样可行,但我想知道是否有更好/更安全的方法。它位于Rails应用程序中,虽然它远不及任何用户输入,eval仍然让我感到紧张。有更好的解决方案吗?

1 个答案:

答案 0 :(得分:3)

您可以将constantsconst_get用于此目的。

ph = Person::Health # Shorthand
Hash[ph.constants(false).map { |c| [ph.const_get(c), c.to_s ] }]
# {10=>:GOOD, 4=>:SICK, 0=>:DEAD}

我将false添加到.constants以防止包含所包含模块中的任何继承常量。例如,如果没有false,则以下方案还将包含5 => "X"映射:

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"}