如何将散列键转换为方法名称?

这是我的哈希:

tempData = {"a" => 100, "here" => 200, "c" => "hello"} 

我需要像下面这样访问散列键:

 tempData.a #100 tempData.here # 200 

你可以把你的散列打包在一个OpenStruct中 :

 require 'ostruct' tempData = {"a" => 100, "here" => 200, "c" => "hello"} os = OpenStruct.new tempData os.a #=> 100 os.here #=> 200 

如果你真的想要,也可以猴子修补Hash类,但我build议不要这样做:

 class Hash def method_missing(m, *args, &blk) fetch(m) { fetch(m.to_s) { super } } end end tempData = {"a" => 100, "here" => 200, "c" => "hello"} tempData.a #=> 100 

更新:在我的个人扩展库中,我添加了一个Hash#to_ostruct方法。 这将recursion地将散列转换为包含所有嵌套散列的OpenStruct

另外,如果它只是一个小脚本,那么扩展Hash本身可能会更方便

 class Hash def method_missing sym,* fetch(sym){fetch(sym.to_s){super}} end end 

method_missing是一个神奇的方法,只要你的代码试图调用一个不存在的方法,就会被调用。 Ruby将在运行时拦截失败的调用,并让您处理它,以便您的程序可以正常恢复。 上面的实现尝试使用方法名称作为符号来访问哈希,使用方法名称作为string,并且最终因Ruby的内置方法丢失错误而失败。

注意一个更复杂的脚本,添加此行为可能会破坏其他第三方gems,您可以使用模块并扩展每个实例

 module H def method_missing sym,* fetch(sym){fetch(sym.to_s){super}} end end the = { answer: 42 } the.extend(H) the.answer # => 42 

为了更方便,您甚至可以将模块传播到嵌套散列

 module H def method_missing sym,* r = fetch(sym){fetch(sym.to_s){super}} Hash === r ? r.extend(H) : r end end the = { answer: { is: 42 } } the.extend(H) the.answer.is # => 42 

如果散列位于模块内,则可以使用define_methoddynamic地在该模块(或类)上定义方法。 例如:

 module Version module_function HASH = { major: 1, minor: 2, patch: 3, } HASH.each do |name, value| define_method(name) do return value end end end 

这将定义一个Version模块,其中majorminorpatch方法分别返回1,2和3。

您可以按照以下方式扩展Hash类。

 class Hash # return nil whenever the key doesn't exist def method_missing(m, *opts) if self.has_key?(m.to_s) return self[m.to_s] elsif self.has_key?(m.to_sym) return self[m.to_sym] end return nil # comment out above line and replace with line below if you want to return an error # super end end 

还有另一种方法来做到这一点。

JSON.parse(tempData.to_json, object_class: OpenStruct)

这将给对象#<OpenStruct a=100, here=200, c="hello">

这样嵌套的hash也会被转换成OpenStruct Object

 tempData = {a: { b: { c: 3}}, foo: 200, msg: 'test msg'} obj = JSON.parse(tempData.to_json, object_class: OpenStruct) 

现在我们可以打电话了

 obj.abc # 3 obj.foo # 200 obj.msg # 'test msg' 

希望这会帮助别人。