假设我有一个
w_data
哈希
{"latitude"=>"40.695", "air_temperature"=>"-10", "longitude"=>"-96.854", "datetime"=>"2014-01-01 02:55:00"}
我想通过
w_data.latitude
而不是w_data["latitude"]
来访问它的价值
怎么做?
我要说不要使用OpenStruct,因为它每次创建新方法缓存时都会破坏方法缓存。
相反,考虑像 hashie-mash 这样的 gem,或者滚动你自己的 hash-like:
Hashie::Mash
:
hsh = Hashie::Mash.new("latitude"=>"40.695", "air_temperature"=>"-10", "longitude"=>"-96.854", "datetime"=>"2014-01-01 02:55:00")
hsh.latitude
=> "40.695"
定制解决方案:
class AccessorHash < Hash
def method_missing(method, *args)
s_method = method.to_s
if s_method.match(/=$/) && args.length == 1
self[s_method.chomp("=")] = args[0]
elsif args.empty? && key?(s_method)
self.fetch(s_method)
elsif args.empty? && key?(method)
self.fetch(method)
else
super
end
end
end
hsh = AccessorHash.new("latitude"=>"40.695", "air_temperature"=>"-10", "longitude"=>"-96.854", "datetime"=>"2014-01-01 02:55:00")
hsh.latitude # => "40.695"
hsh.air_temperature = "16"
hsh => # {"latitude"=>"40.695", "air_temperature"=>"16", "longitude"=>"-96.854", "datetime"=>"2014-01-01 02:55:00"}
如果你想要一个纯Ruby解决方案,只需破解Hash类并升级
method_missing
方法!
class Hash
def method_missing method_name, *args, &block
return self[method_name] if has_key?(method_name)
return self[$1.to_sym] = args[0] if method_name.to_s =~ /^(.*)=$/
super
end
end
现在,每个哈希都有这个能力。
hash = {:five => 5, :ten => 10}
hash[:five] #=> 5
hash.five #=> 5
hash.fifteen = 15
hash[:fifteen] #=> 15
hash.fifteen #=> 15
method_missing
在每个 Ruby 类中都可用,以捕获对(尚)不存在的方法的尝试调用。我已经把它变成了一篇博客文章(带有交互式 Codewars 套路):
将散列转换为 OpenStruct。这里:
require 'ostruct'
w_data = OpenStruct.new
hash = {"latitude"=>"40.695", "air_temperature"=>"-10", "longitude"=>"-96.854", "datetime"=>"2014-01-01 02:55:00"}
w_data.marshal_load(hash)
w_data.longitude
#=> "-96.854"
另一种更简单的方法:
require 'ostruct'
hash = {"latitude"=>"40.695", "air_temperature"=>"-10", "longitude"=>"-96.854", "datetime"=>"2014-01-01 02:55:00"}
w_data = OpenStruct.new(hash)
w_data.longitude
#=> "-96.854"
如果您正在使用 Ruby on Rails,您可以利用 ActiveSupport::OrderedOptions 模块将散列键作为属性访问。该模块扩展了常规哈希的功能,允许您使用点表示法访问其密钥。
此外,您可以使用 ActiveSupport::InheritableOptions 通过将现有哈希传递给它来创建新对象。所以你很高兴。
作为示例显示:
h = ActiveSupport::InheritableOptions.new({ girl: 'Mary', boy: 'John' })
h.girl # => 'Mary'
h.boy