无法对 ruby​​ 哈希使用点语法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9356704/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 04:47:15  来源:igfitidea点击:

Unable to use dot syntax for ruby hash

rubysyntaxhash

提问by Kyle Decot

I'm using net/httpto pull in some json data from the Yahoo Placemaker API. After receiving the response I am performing JSON.parseon the response. This gives me a hash that looks like:

我正在使用net/http从 Yahoo Placemaker API 中提取一些 json 数据。收到响应后,我正在执行JSON.parse响应。这给了我一个看起来像的哈希:

{"processingTime"=>"0.001493", "version"=>"1.4.0.526 build 111113", "documentLength"=>"25", "document"=>{"administrativeScope"=>{"woeId"=>"2503863", "type"=>"Town", "name"=>"Tampa, FL, US", "centroid"=>{"latitude"=>"27.9465", "longitude"=>"-82.4593"}}, "geographicScope"=>{"woeId"=>"2503863", "type"=>"Town", "name"=>"Tampa, FL, US", "centroid"=>{"latitude"=>"27.9465", "longitude"=>"-82.4593"}}, "localScopes"=>{"localScope"=>{"woeId"=>"2503863", "type"=>"Town", "name"=>"Tampa, FL, US (Town)", "centroid"=>{"latitude"=>"27.9465", "longitude"=>"-82.4593"}, "southWest"=>{"latitude"=>"27.8132", "longitude"=>"-82.6489"}, "northEast"=>{"latitude"=>"28.1714", "longitude"=>"-82.2539"}, "ancestors"=>[{"ancestor"=>{"woeId"=>"12587831", "type"=>"County", "name"=>"Hillsborough"}}, {"ancestor"=>{"woeId"=>"2347568", "type"=>"State", "name"=>"Florida"}}, {"ancestor"=>{"woeId"=>"23424977", "type"=>"Country", "name"=>"United States"}}]}}, "extents"=>{"center"=>{"latitude"=>"27.9465", "longitude"=>"-82.4593"}, "southWest"=>{"latitude"=>"27.8132", "longitude"=>"-82.6489"}, "northEast"=>{"latitude"=>"28.1714", "longitude"=>"-82.2539"}}, "placeDetails"=>{"placeId"=>"1", "place"=>{"woeId"=>"2503863", "type"=>"Town", "name"=>"Tampa, FL, US", "centroid"=>{"latitude"=>"27.9465", "longitude"=>"-82.4593"}}, "placeReferenceIds"=>"1", "matchType"=>"0", "weight"=>"1", "confidence"=>"8"}, "referenceList"=>{"reference"=>{"woeIds"=>"2503863", "placeReferenceId"=>"1", "placeIds"=>"1", "start"=>"15", "end"=>"20", "isPlaintextMarker"=>"1", "text"=>"Tampa", "type"=>"plaintext", "xpath"=>""}}}}

I am able to access elements by doing things like jsonResponse['version']but I am not able to do jsonResponse.version. Why is this?

我可以通过做类似的事情来访问元素,jsonResponse['version']但我不能做jsonResponse.version。为什么是这样?

回答by steenslag

Hashdoes not have dot-syntax for it's keys. OpenStructdoes:

Hash它的键没有点语法。OpenStruct做:

require 'ostruct'
hash = {:name => 'John'}
os = OpenStruct.new(hash)
p os.name #=> "John"

NOTE: Does not work with nested hashes.

注意:不适用于嵌套哈希。

回答by whodabudda

OpenStruct will work well for a pure hash, but for hashes with embeded arrays or other hashes, the dot syntax will choke. I came across this solution, which works well without loading in another gem: https://coderwall.com/p/74rajw/convert-a-complex-nested-hash-to-an-objectbasic steps are:

OpenStruct 适用于纯散列,但对于带有嵌入数组或其他散列的散列,点语法会阻塞。我遇到了这个解决方案,它在不加载另一个 gem 的情况下运行良好:https: //coderwall.com/p/74rajw/convert-a-complex-nested-hash-to-an-object基本步骤是:

data = YAML::load(File.open("your yaml file"))
json_data = data.to_json
mystr = JSON.parse(json_data,object_class: OpenStruct)

you can now access all objects in mystr using dot syntax.

您现在可以使用点语法访问 mystr 中的所有对象。

回答by steel

Ruby hashes don't work like this natively, but the HashDotgem would work for this.

Ruby 散列本身不是这样工作的,但HashDotgem 可以解决这个问题。

HashDot allows dot notation syntax use on hashes. It also works on json strings that have been re-parsed with JSON.parse.

HashDot 允许在散列上使用点符号语法。它也适用于使用 .json 重新解析的 json 字符串JSON.parse

require 'hash_dot'

hash = {b: {c: {d: 1}}}.to_dot
hash.b.c.d => 1

json_hash = JSON.parse(hash.to_json)
json_hash.b.c.d => 1

回答by d11wtq

That is a JavaScript feature, not a Ruby feature. In Ruby, to use a "dot syntax", the object would need to respond to those methods. Ruby hashes use the #[](key)method to access elements.

这是一个 JavaScript 特性,而不是一个 Ruby 特性。在 Ruby 中,要使用“点语法”,对象需要响应这些方法。Ruby 哈希使用该#[](key)方法访问元素。

回答by megas

Why not, you can do this via metaprogramming

为什么不,你可以通过元编程来做到这一点

module LookLikeJSON
  def method_missing(meth, *args, &block)
    if has_key?(meth.to_s)
      self[meth.to_s]
    else
      raise NoMethodError, 'undefined method #{meth} for #{self}' 
    end
  end
end

h = {"processingTime"=>"0.001493", "version"=>"1.4.0.526 build 111113", "documentLength"=>"25"}
h.extend(LookLikeJSON)
h.processingTime #=> "0.001493"

回答by Vinicius Brasil

If you don't want to install any gems, you can try to use the Ruby's native Structclass and some Ruby tricks, like the splat operator.

如果你不想安装任何 gems,你可以尝试使用 Ruby 的原生Struct类和一些 Ruby 技巧,比如splat operator

# regular hashes
customer = { name: "Maria", age: 21, country: "Brazil" }
customer.name
# => NoMethodError: undefined method `name' for {:name=>"Maria", :age=>21, :country=>"Brazil"}:Hash

# converting a hash to a struct
customer_on_steroids = Struct.new(*customer.keys).new(*customer.values)
customer_on_steroids.name
#=> "Maria"

Please note that this simple solution works only for single-level hashes. To make it dynamic and fully functional for any kind of Hash, you'll have to make it recursive to create substructs inside your struct.

请注意,这个简单的解决方案仅适用于单级哈希。为了使其对任何类型的Hash.

You can also store the Struct as if it was a class.

您还可以将 Struct 存储为一个类。

customer_1 = { name: "Maria", age: 21, country: "Brazil" }
customer_2 = { name: "Jo?o",  age: 32, country: "Brazil" }
customer_3 = { name: "José",  age: 43, country: "Brazil" }

Customer = Struct.new(*customer_1.keys)
customer_on_steroids_1 = Customer.new(*customer_1.values)
customer_on_steroids_2 = Customer.new(*customer_2.values) 
customer_on_steroids_3 = Customer.new(*customer_3.values)

Read more about Ruby Struct class.

阅读有关 Ruby Struct 类的更多信息。

回答by J?rg W Mittag

Because Hashdoesn't have a versionmethod.

因为Hash没有version办法。

回答by Eddie

If it's in Rspec stubs will work too.

如果它在 Rspec 中,存根也可以工作。

let(:item) { stub(current: 1, total: 1) }