自/至JSON API客体红宝石哈希 [英] Objectify Ruby Hashes from/to JSON API

查看:164
本文介绍了自/至JSON API客体红宝石哈希的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚发布了红宝石的宝石通过HTTP API使用一些JSON:

https://github.com/solyaris/blomming_api

我的纳伊夫红宝石code只是转换通过API端点(json_data)回到红宝石哈希(hash_data)复/嵌套JSON数据结构,在一个平面一到一transaltion(JSON红宝石哈希,反之亦然)。 TAT的罚款,但...

我想一个编程接口更高级。
也许instatiating一个端点一类资源,但我感到困惑的一个聪明的实现。

让我用一种抽象的code解释。

让说,我有通过API获得一个复杂/嵌套JSON,
通常哈希的数组,递归嵌套这里下面(例如想象):

  json_data ='[{
    通勤:{
        分钟:0,
        startTime时:周三05月06日22点14分12秒EDT 2014年
        地点:
            {
                纬度:40.4220061
                经度:40.4220061
            },
            {
                纬度:40.4989909
                经度:40.48989805
            },
            {
                纬度:40.4111169
                经度:40.42222869
            }
        ]
    }
},
{
    通勤:{
        分钟:2,
        startTime时:周三5月28日20点14分十二秒EDT 2014年
        地点:
            {
                纬度:43.4220063
                经度:43.4220063
            }
        ]
    }
}]

目前我做什么,当我收到了类似的JSON形成API仅仅是:

 #从JSON散列
hash_data = JSON.load json_data#和分配值:
COORDS = hash_data.first [通勤] [位置。最后
COORDS [经度] =40.00#是40.4111169
COORDS [纬度] =41.00#是40.42222869

这是确定的,但与awfull /混淆语法。
相反,我可能会喜欢这样的:

 #创建哈希对象资源
RES = Resource.create(hash_data)#...一些处理#分配一个嵌套变量:经度,对象纬度:RES
COORDS = res.first.commute.locations.last
coords.longitude =40.00#是40.4111169
coords.latitude =41.00#是40.42222869#...一些处理#转换修改的对象:水库成散列再次:
modified_hash = res.save#和可能至少我会恢复到以JSON:
modified_json = modified_hash传入json.dump

我看了intresting的帖子:
http://pullmonkey.com/ 2008/01/06 /转换-A-红宝石散列成 - 一类对象/
http://www.gooder$c$c.com/wp/convert-your-hash-keys-to-object-properties-in-ruby/

和复制克里威尔逊'code,我在这里勾勒下执行:

 类资源  高清self.create(散)
    新(散)
  结束  高清初始化(散)
    hash.to_obj
  结束  高清保存
    #或to_hash()
    # 去做!帮帮我! (见下文)
  结束结束
类::哈希
  #添加密钥散列
  高清to_obj
    self.each做| K,V |      v.to_obj如果v.kind_of?哈希
      v.to_obj如果v.kind_of?排列      K = k.gsub。(/ \\ | \\ S | - | \\ / | \\'/'_')downcase.to_sym      ##创建和初始化实例变量此键/值对
      self.instance_variable_set(@#[KP},第五章)      ##创建一个返回实例变量的吸
      self.class.send(:define_method,K,PROC {self.instance_variable_get(@#[KP})})      ##创建设置实例变量二传手
      self.class.send(:define_method,#[KP} ={PROC | V | self.instance_variable_set(@#[KP},V)})
    结束
    自回归
  结束
结束类::阵列
  高清to_obj
    self.map {| V | v.to_obj}
  结束
结束
#------------------------------------------------- -----------

顺便说一句,我研究了一下项目的ActiveResource(是的Rails的一部分,如果我很好理解)。
战神可能是伟大的我的范围,但问题是ARES有充分的REST API的有点太严presumption ...
在我的情况服务器API不在战神所期望的方式完全REST风格...
总之,我会做了很多工作,以子/修改战神行为
而此刻我放弃的想法使用的ActiveResource

问题:


  1. 有人可以帮助我实现(我用递归方法真不好...... :-()?以上code中的save()方法

  2. 确实存在一定的宝石,上面绘制的hash_to_object()和object_to_hash()的翻译?


  3. 你想想一个任意散列未来弗罗马JSON通过HTTP API,它们自动客观化是什么?
    我的意思是:我看到了伟大的职业,我不需要客户端的静态线的数据结构,从而可以灵活地可能的服务器端的变化。
    但在另一方面,这样做自动客观化,存在的副作用可能的利弊,让安全问题......像恶意JSON注射(可能untrasted通信网...)


您如何看待这一切?任何建议,欢迎!
对不起,我长的帖子,我的Ruby语言的元编程azards: - )

乔治

更新2:我对问题3点仍然有兴趣阅读意见:
优点/缺点创建资源类每一个接收到JSON
优点/缺点创建静态(preemptive属性)/ automatich /动态嵌套对象

更新1:长回复西蒙娜:
谢谢,你是正确的醪有一个甜蜜的.to_hash()方法:

 要求'JSON'
需要'HASHIEjson_data ='{
    通勤:{
        分钟:0,
        startTime时:周三05月06日22点14分12秒EDT 2014年
        地点:
            {
                纬度:40.4220061
                经度:40.4220061
            },
            {
                纬度:40.4989909
                经度:40.48989805
            },
            {
                纬度:40.4111169
                经度:40.42222869
            }
        ]
    }
}哈希#trasforma
哈希= JSON.load json_data把散列RES = HASHIE :: Mash.new哈希#分配一个嵌套变量:经度,对象纬度:RES
COORDS = res.commute.locations.last
coords.longitude =40.00#是40.4111169
coords.latitude =41.00#是40.42222869放;把经度:#{} res.commute.locations.last.longitude
把纬度:#{} res.commute.locations.last.latitudemodified_hash = res.to_hash
放;把modified_hash


解决方案

此功能是由几个宝石提供。其中最知名的是 HASHIE ,特别是 HASHIE ::醪


  

醪是一个扩展的哈希,让可以从哈希建成并轻松扩展简单的伪对象的功能。它的设计基于REST的API库被用来提供JSON和XML解析哈希容易喜欢对象的访问。


还支持多级别的对象。

I just released a ruby gem to use some JSON over HTTP API:

https://github.com/solyaris/blomming_api

My naif ruby code just convert complex/nested JSON data structures returned by API endpoints (json_data) to ruby Hashes ( hash_data), in a flat one-to-one transaltion (JSON to ruby hash and viceversa). Tat's fine, but...

I would like a programming interface more "high level". Maybe instatiating a class Resource for every endpoint, but I'm confused about a smart implementation.

Let me explain with an abstract code.

Let say I have a complex/nested JSON received by an API, usually an Array of Hashes, recursively nested as here below (imagination example):

json_data = '[{
    "commute": {
        "minutes": 0,
        "startTime": "Wed May 06 22:14:12 EDT 2014",
        "locations": [
            {
                "latitude": "40.4220061",
                "longitude": "40.4220061"
            },
            {
                "latitude": "40.4989909",
                "longitude": "40.48989805"
            },            
            {
                "latitude": "40.4111169",
                "longitude": "40.42222869"
            }            
        ]
    }
},
{
    "commute": {
        "minutes": 2,
        "startTime": "Wed May 28 20:14:12 EDT 2014",
        "locations": [
            {
                "latitude": "43.4220063",
                "longitude": "43.4220063"
            }
        ]
    }
}]'

At the moment what I do, when I receive a similar JSON form an API is just:

# from JSON to hash 
hash_data = JSON.load json_data

# and to assign values:
coords = hash_data.first["commute"]["locations"].last
coords["longitude"] = "40.00" # was "40.4111169"
coords["latitude"] = "41.00" # was "40.42222869"

that's ok, but with awfull/confusing syntax. Instead, I probably would enjoy something like:

# create object Resource from hash
res = Resource.create( hash_data )

# ... some processing

# assign a "nested" variables: longitude, latitude of object: res
coords = res.first.commute.locations.last
coords.longitude = "40.00" # was "40.4111169"
coords.latitude = "41.00" # was "40.42222869"

# ... some processing

# convert modified object: res into an hash again:
modified_hash = res.save

# and probably at least I'll recover to to JSON:
modified_json = JSON.dump modified_hash

I read intresting posts: http://pullmonkey.com/2008/01/06/convert-a-ruby-hash-into-a-class-object/ http://www.goodercode.com/wp/convert-your-hash-keys-to-object-properties-in-ruby/

and copying Kerry Wilson' code, I sketched the implementation here below:

class Resource

  def self.create (hash)
    new ( hash)
  end

  def initialize ( hash)
    hash.to_obj
  end

  def save
    # or to_hash() 
    # todo! HELP! (see later)
  end

end


class ::Hash
  # add keys to hash
  def to_obj
    self.each do |k,v|

      v.to_obj if v.kind_of? Hash
      v.to_obj if v.kind_of? Array

      k=k.gsub(/\.|\s|-|\/|\'/, '_').downcase.to_sym

      ## create and initialize an instance variable for this key/value pair
      self.instance_variable_set("@#{k}", v)

      ## create the getter that returns the instance variable
      self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")})

      ## create the setter that sets the instance variable
      self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)})
    end
    return self
  end
end

class ::Array
  def to_obj
    self.map { |v| v.to_obj }
  end 
end
#------------------------------------------------------------

BTW, I studied a bit ActiveResource project (was part of Rails if I well understood). ARes could be great for my scope but the problem is ARes have a bit too "strict" presumption of full REST APIs... In my case server API are not completely RESTfull in the way ARes would expect... All in all I would do a lot of work to subclass / modify ARes behaviours and at the moment I discarded the idea to use ActiveResource

QUESTIONS:

  1. someone could help me to realize the save() method on the above code (I'm really bad with recursive methods... :-( ) ?
  2. Does exist some gem that to the above sketched hash_to_object() and object_to_hash() translation ?

  3. What do you think about that "automatic" objectifying of an "arbitrary" hash coming froma JSON over http APIs ? I mean: I see the great pro that I do not need to client-side static-wire data structures, allowing to be flexible to possible server side variations. But on the other hand, doing this automatic objectify, there is a possible cons of a side effect to allow security issues ... like malicious JSON injection (possible untrasted communication net ...)

What do you think about all this ? Any suggestion is welcome! Sorry for my long post and my ruby language metaprogramming azards :-)

giorgio

UPDATE 2: I'm still interested reading opinions about question point 3: Pros/Cons to create Resource class for every received JSON Pros/Cons to create static (preemptive attributes) / automatich/dynamic nested objects

UPDATE 1: long reply to Simone: thanks, you are right Mash have a sweet .to_hash() method:

require 'json'
require 'hashie'

json_data = '{
    "commute": {
        "minutes": 0,
        "startTime": "Wed May 06 22:14:12 EDT 2014",
        "locations": [
            {
                "latitude": "40.4220061",
                "longitude": "40.4220061"
            },
            {
                "latitude": "40.4989909",
                "longitude": "40.48989805"
            },            
            {
                "latitude": "40.4111169",
                "longitude": "40.42222869"
            }            
        ]
    }
}'

# trasforma in hash
hash = JSON.load json_data

puts hash

res = Hashie::Mash.new hash

# assign a "nested" variables: longitude, latitude of object: res
coords = res.commute.locations.last
coords.longitude = "40.00" # was "40.4111169"
coords.latitude = "41.00" # was "40.42222869"

puts; puts "longitude: #{res.commute.locations.last.longitude}"
puts "latitude: #{res.commute.locations.last.latitude}"

modified_hash = res.to_hash
puts; puts modified_hash

解决方案

This feature is provided by a few gem. One of the most known is Hashie, specifically the class Hashie::Mash.

Mash is an extended Hash that gives simple pseudo-object functionality that can be built from hashes and easily extended. It is designed to be used in RESTful API libraries to provide easy object-like access to JSON and XML parsed hashes.

Mash also supports multi-level objects.

这篇关于自/至JSON API客体红宝石哈希的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆