Serializing an object to JSON, XML, YAML?

2020-07-10 06:06发布

问题:

I asked a previous question about serialization and validation. Someone mentioned using the JSON gem which allows me to tell my object how to serialize with the to_json method, however Ruby seems to do LOTS of complicated things really easily, however on the flip side some really simple things seem to be quite complicated, Serialization being one of those things.

I want to find out if there is a way to have a clean object:

class CleanClass
    attr_accessor :variable1
    attr_accessor :variable2
    attr_accessor :variable3
end

cleanObject = CleanClass.new

Ideally, I don't want to dirty the model, I just want to pass it to something and tell it what the output type should be and let it work its magic.

An example would be something like:

jsonOutput = MagicSerializer::Json.Serialize(cleanObject)
xmlOutput = MagicSerializer::Xml.Serialize(cleanObject)
yamlOutput = MagicSerializer::Yaml.Serialize(cleanObject)

revertedJsonObject = MagicSerializer::Json.Unserialize(jsonOutput)
revertedXmlObject = MagicSerializer::Xml.Unserialize(xmlOutput)
revertedYamlObject = MagicSerializer::Yaml.Unserialize(yamlOutput)

I want to pass something an object, and get the strings outputted, then be able to convert it back.

I know ActiveModel has serialization functionality but I need to dirty my class to do this, and I don't want to change the model if possible. ActiveSupport seems to satisfy the JSON criteria as I can just call that and it will take an object and spit out the JSON, but I would like to support other types.

Any further information would be great!

回答1:

Ruby has built-in automagical serialization/deserialization to binary and yaml.

Yaml:

require 'yaml'
serialized = CleanClass.new.to_yaml
object = YAML.load(serialized)

Marshal:

serialized = Marshal.dump(CleanClass.new)
object = Marshal.load(serialized)


回答2:

Have your magic serialization method dirty the object for you; the emdirtering can happen on a per-object basis.

Or dirty at your class level.

Either way, your mainline code doesn't see it.



回答3:

For JSON and YAML it seems pretty easy, since they would only be wrappers for the to_yaml and to_json methods (or YAML.load and from_json respectively)

For JSON you would have to wrap own classes around core-Types (or other types which implement to_json) e.g. first implement a to_hash method which then can be transformed into json.

XML is much more complicated because of the hierarchy-aspect, you'd have to standardize it, but actually i don't understand from your explanation what is wrong with the basic to_... methods. This is actually the convention we use in Ruby. If you're concerned with pollution of models, you could put these methods in a module, and include the module in the class.

module Foo
  def to_serialized_type
   ...
  end
end
class CleanClass
  include Foo
end