我有一个哈希
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
答案 0 :(得分:81)
>> require 'ostruct'
=> []
>> foo = {'bar'=>'baz'}
=> {"bar"=>"baz"}
>> foo_obj = OpenStruct.new foo
=> #<OpenStruct bar="baz">
>> foo_obj.bar
=> "baz"
>>
答案 1 :(得分:35)
您要找的是OpenStruct。它是标准库的一部分。
答案 2 :(得分:22)
一个好的解决方案:
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”条件
答案 3 :(得分:6)
不是将所有内容复制到散列中,而是可以向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
。
答案 4 :(得分:4)
这有一些宝石。这是我最近的宝石,hash_dot,还有一些我在RubyGems上发布的类似名字的宝石,包括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提交改进或错误。