我有一个哈希
foo = {'bar'=>'baz'}
我想打个电话 foo.bar #=> 'baz'
我的动机是将activerecord查询重写为原始sql查询(使用Model#find_by_sql).这将返回一个带有SELECT子句值作为键的哈希.但是,我现有的代码依赖于object.method点表示法.我想做最小的代码重写.谢谢.
编辑:看来Lua有这个功能:
point = { x = 10, y = 20 } -- Create new table print(point["x"]) -- Prints 10 print(point.x) -- Has exactly the same meaning as line above
Hooopo.. 81
>> require 'ostruct' => [] >> foo = {'bar'=>'baz'} => {"bar"=>"baz"} >> foo_obj = OpenStruct.new foo => #>> foo_obj.bar => "baz" >>
@Steen如果你谷歌"红宝石方法缓存",前几个点击将由查理萨默维尔和已故的詹姆斯戈利克解释它.在Ruby 2.1之前,实例化一个ostruct方法转储了*whole*方法缓存.在2.1+中,它为所有ostruct实例及其子类的实例转储方法高速缓存. (4认同)
不鼓励使用OpenStruct,因为每个实例化都会使Ruby方法缓存失效,从而减慢整个应用程序的速度. (3认同)
Avdi.. 35
您正在寻找的是OpenStruct.它是标准库的一部分.
>> require 'ostruct' => [] >> foo = {'bar'=>'baz'} => {"bar"=>"baz"} >> foo_obj = OpenStruct.new foo => #>> foo_obj.bar => "baz" >>
您正在寻找的是OpenStruct.它是标准库的一部分.
一个好的解决方案
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
注意:此实现只有一个已知错误:
x = { 'test' => 'aValue', :test => 'bar'} x.test # => 'aValue'
如果您更喜欢符号查找而不是字符串查找,那么交换两个"if"条件
而不是将所有内容复制到散列中,您只需向Hash添加一些行为即可进行查找.
如果添加此定义,则扩展Hash以将所有未知方法作为哈希查找处理:
class Hash def method_missing(n) self[n.to_s] end end
请记住,这意味着如果在哈希上调用错误的方法,您将永远不会看到错误 - 您将获得相应的哈希查找将返回的任何内容.
只需将方法放在特定的哈希值上,或者根据需要添加多个哈希值,就可以大大减少调试问题:
a={'foo'=>5, 'goo'=>6} def a.method_missing(n) self[n.to_s] end
另一个观察是,当method_missing
系统调用它时,它会给你一个Symbol
参数.我的代码将其转换为String
.如果你的散列键不是字符串此代码永远不会返回的价值观-如果你通过按键符号而不是字符串,可以替换n
为n.to_s
以上.
有一些宝石。我最近在RubyGems上发布我的宝石时,发现了我的宝石hash_dot和其他名称相似的宝石,包括dot_hash。
HashDot允许使用点表示法语法,同时仍可解决@avdi解决的NoMethodErrors问题。它比使用OpenStruct创建的对象更快,更可遍历。
require 'hash_dot' a = {b: {c: {d: 1}}}.to_dot a.b.c.d => 1 require 'open_struct' os = OpenStruct.new(a) os.b => {c: {d: 1}} os.b.c.d => NoMethodError
当调用非方法时,它也保持预期的行为。
a.non_method => NoMethodError
请随时向HashDot提交改进或错误。