如何将散列键转换为方法名称?
这是我的哈希:
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_method
dynamic地在该模块(或类)上定义方法。 例如:
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
模块,其中major
, minor
和patch
方法分别返回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'
希望这会帮助别人。