如何使用JSON进行Ruby对象序列化

我有一个像这样的简单容器类的结构(在伪ruby中):

class A attr_reader :string_field1, :string_field2 ... end class B attr_reader: int_field3, :string_field4 ... end # C includes an instance of A and B class C attr_reader: :a_instance, :b_instance ... end 

是否有简单的方法在Ruby中将其/序列化为JSON? 或者我应该为每个类制作嵌套的序列化方法,如本例所示 ?

编辑:

在我的特定场景中,我想将一些JSON数据发送到运行Ruby的服务器,这将提取数据并采取相应的行动。

JSON的发送者不一定是Ruby进程,但可能是其他系统的后端。 (虽然在我的测试工具中是Ruby)。

因此,我不需要JSON采用某种“特定于Ruby”的格式,我只是假设如果它实际上是内置于Ruby的话会更容易。

使用Marshal,PStore或其他Ruby解决方案来处理非JSON对象

有人可能有理由怀疑为什么像Ruby这样的完全reflection的语言不会自动化JSON生成和任意类的解析。

但是,除非您坚持使用JSON类型,否则除了运行另一个Ruby之外,没有地方可以发送或接收JSON对象。 在这种情况下,我怀疑传统的智慧是“忘记JSON,使用像核心类Marshal一样的原生Ruby接口。

因此,如果您真的将这些对象发送到PHP或非Ruby的东西,那么您应该使用Array等直接创建支持JSON的Ruby数据结构,然后您将拥有JSON.generate将直接处理的内容。

如果你只是需要序列化,那么你应该使用MarshalPStore

更新:啊哈,好的,试试这个:

 module AutoJ def auto_j h = {} instance_variables.each do |e| o = instance_variable_get e.to_sym h[e[1..-1]] = (o.respond_to? :auto_j) ? o.auto_j : o; end h end def to_json *a auto_j.to_json *a end end 

如果你在每个类中都include AutoJ ,它应该是DTRT。 在您的示例中,这会导致

 {"a":{"string_field1":"aa","string_field2":"bb"},"b":{"int_field3":123,"string_field4":"dd"}} 

您可能希望更改auto_j方法以返回h.values而不是h ,在这种情况下,您将获得:

 [["aa","bb"],[123,"dd"]] 

我有同样的问题(主要是尝试创建任意复杂的JSON字符串)而不是解析它们。 在查看了一个非侵入性类,它将采用Ruby对象(包括嵌套数组)并将其编组为JSON字符串后,我终于编写了自己的简单序列化器。 此代码还会转义特殊字符以创建有效的JSON。

http://www.keepingmyhandin.com/Downhome/Sketchup/simplejsonserializerrubyimplementation

你所要做的就是:

 json = JSON.new; jsonString = json.marshal(obj); # Where obj is a Ruby object 

这是我对自定义类的to_json实现的方法。

使用self.included在模块中有一点魔力。 这是2006年关于模块同时具有实例和类方法的非常好的文章http://blog.jayfields.com/2006/12/ruby-instance-and-class-methods-from.html

该模块旨在包含在任何类中以提供to_jsonfunction。 它拦截attr_accessor方法而不是使用它自己的方法,以便对现有类进行最小的更改。

to_json实现基于这个答案

 module JSONable module ClassMethods attr_accessor :attributes def attr_accessor *attrs self.attributes = Array attrs super end end def self.included(base) base.extend(ClassMethods) end def as_json options = {} serialized = Hash.new self.class.attributes.each do |attribute| serialized[attribute] = self.public_send attribute end serialized end def to_json *a as_json.to_json *a end end class CustomClass include JSONable attr_accessor :b, :c def initialize b: nil, c: nil self.b, self.c = b, c end end a = CustomClass.new(b: "q", c: 23) puts JSON.pretty_generate a { "b": "q", "c": 23 }