在Ruby中hash 到hash.key

我有一个哈希

foo = {'bar'=>'baz'} 

我想打电话给foo.bar #=> 'baz'

我的动机是将主动logging查询重写为原始sql查询(使用Model#find_by_sql)。 这将以SELECT子句值作为键返回一个散列。 但是,我现有的代码依赖于object.method点符号。 我想做最小的代码重写。 谢谢。

编辑:看来Lua有这个function:

 point = { x = 10, y = 20 } -- Create new table print(point["x"]) -- Prints 10 print(point.x) -- Has exactly the same meaning as line above 

 >> require 'ostruct' => [] >> foo = {'bar'=>'baz'} => {"bar"=>"baz"} >> foo_obj = OpenStruct.new foo => #<OpenStruct bar="baz"> >> foo_obj.bar => "baz" >> 

你在找什么叫做OpenStruct 。 这是标准库的一部分。

一个好的解决scheme

 class Hash def method_missing(method, *opts) m = method.to_s if self.has_key?(m) return self[m] elsif self.has_key?(m.to_sym) return self[m.to_sym] end super end end 

注意:这个实现只有一个已知的bug:

 x = { 'test' => 'aValue', :test => 'bar'} x.test # => 'aValue' 

如果您更喜欢符号查找而不是string查找,则交换两个“if”条件

而不是复制所有的东西哈希,你可以添加一些行为哈希来做查找。

如果你添加这个定义,你扩展哈希以处理所有未知的方法作为哈希查找:

 class Hash def method_missing(n) self[n.to_s] end end 

请记住,这意味着如果你在hash上调用了错误的方法,你将不会看到错误 – 你只要得到相应的hash查询就会返回。

只需将该方法放在特定的散列函数上,就可以大大减lessdebugging问题,或者根据需要进行多次散列:

 a={'foo'=>5, 'goo'=>6} def a.method_missing(n) self[n.to_s] end 

另一种观察是,当method_missing被系统调用时,它会给你一个Symbol参数。 我的代码转换成一个String 。 如果您的散列键不是string,这个代码将永远不会返回这些值 – 如果您使用符号而不是string键入,只需将nreplace为上面的n.to_s

这有几个gem。 有我最近的gem, hash_dot和其他一些我在RubyGems上发布的类似名字的gem,包括dot_hash 。

HashDot允许使用点符号语法,同时仍然解决有关由@avdi处理的NoMethodErrors问题。 它比使用OpenStruct创build的对象更快,更易于穿越。

 require 'hash_dot' a = {b: {c: {d: 1}}}.to_dot abcd => 1 require 'open_struct' os = OpenStruct.new(a) os.b => {c: {d: 1}} os.bcd => NoMethodError 

当非方法被调用时,它也保持预期的行为。

 a.non_method => NoMethodError 

请随时向HashDot提交改进或错误。