无法使用ruby哈希的点语法

Kyl*_*cot 27 ruby syntax hash

我正在使用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"=>""}}}}
Run Code Online (Sandbox Code Playgroud)

我可以通过做某些事情来访问元素,jsonResponse['version']但我无法做到jsonResponse.version.为什么是这样?

ste*_*lag 64

Hash它的键没有点语法.OpenStruct作用:

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

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


小智 22

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)
Run Code Online (Sandbox Code Playgroud)

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

  • “由于 JSON 和 OpenStruct 都在 Ruby 标准库中,我们将没有第三方依赖项。” (3认同)

ste*_*eel 10

Ruby哈希本身不像这样工作,但HashDot gem可以用于此.

HashDot允许在哈希上使用点表示法语法.它也适用于已经重新解析的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
Run Code Online (Sandbox Code Playgroud)


d11*_*wtq 6

这是一个JavaScript功能,而不是Ruby功能.在Ruby中,要使用"点语法",对象需要响应这些方法.Ruby哈希使用该#[](key)方法来访问元素.


meg*_*gas 5

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

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"
Run Code Online (Sandbox Code Playgroud)

  • 对,但为什么要这么麻烦? (3认同)

Vin*_*sil 5

如果你不想安装任何 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"
Run Code Online (Sandbox Code Playgroud)

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

您还可以将 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)
Run Code Online (Sandbox Code Playgroud)

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