Class: RightSupport::Data::Serializer
- Defined in:
- lib/right_support/data/serializer.rb
Overview
Utility class that implements true, lossless Ruby-to-JSON serialization. With a few small exceptions, this module can #dump any Ruby object in your VM, and later #load the exact same object from its serialized representation. It can also be used with encoding schemes other than JSON, e.g. msgpack.
This class works by transforming Ruby object graphs into an intermediate representation that consists solely of JSON-clean Ruby objects (String, Integer, …). This intermediate format is dubbed “JSONish”, and it can be transformed to JSON and back without losing data or creating ambiguity.
If you use the class-level (::load and ::dump) interface to this class, it always uses JSON serialization by default. If you construct an instance, you can control which encoding scheme to use, as well as which Hash key to use to mark a serialized object.
JSONish Object Representation
Most Ruby simple types (String, Integer, Float, true/false/nil) are represented by their corresponding JSON type. However, some JSONish values have special meaning:
* Strings beginning with a ':' represent a Ruby Symbol
* Strings in the ISO 8601 timestamp format represent a Ruby Time
To avoid ambiguity due to Ruby Strings that happen to look like a JSONish Time or Symbol, some Strings are “object-escaped,” meaning they are represented as a JSON object with _ruby_class:String.
Arbitrary Ruby objects are represented as a Hash that contains a special key ‘_ruby_class’. The other key/value pairs of the hash consist of the object’s instance variables. Any object whose state is solely contained in its instance variables is therefore eligible for serialization.
JSONish also has special-purpose logic for some Ruby built-ins, allowing them to be serialized even though their state is not contained in instance variables. The following are all serializable built-ins:
* Class
* Module
* String (see below).
Capabilities
The serializer can handle any Ruby object that uses instance variables to record state. It cleanly round-trips the following Ruby object types:
* Collections (Hash, Array)
* JSON-clean data (Numeric, String, true, false, nil)
* Symbol
* Time
* Class
* Module
Known Limitations
Cannot record the following kinds of state:
* Class variables of objects
* State that lives outside of instance variables, e.g. IO#fileno
Cannot cleanly round-trip the following:
* Objects that represent callable code: Proc, Lambda, etc.
* High-precision floating point numbers (due to truncation)
* Times with timezone other than UTC or precision greater than 1 sec
* Hash keys that are anything other than a String (depends on JSON parser)
* Hashes that contain a String key whose value is '_ruby_class'
Constant Summary collapse
- Encoder =
nil
- TIME_FORMAT =
Format string to use when sprintf’ing a JSONish Time
'%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2dZ'
- TIME_PATTERN =
Pattern to match Strings against for object-escaping
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/
- CLASS_ESCAPE_KEY =
Special key used as a pseudo-instance-variable for Class and Module
'name'
- STRING_ESCAPE_KEY =
Special key used as a pseudo-instance-variable for String
'value'
- DEFAULT_OPTIONS =
{ :marker => '_ruby_class', :encoder => Encoder }
Class Method Summary collapse
Instance Method Summary collapse
-
#dump(object) ⇒ String
JSON document representing the serialized object.
-
#initialize(options = {}) ⇒ Serializer
constructor
Instantiate a Serializer instance.
-
#load(data) ⇒ Object
Unserialized Ruby object.
Constructor Details
#initialize(options = {}) ⇒ Serializer
Instantiate a Serializer instance.
123 124 125 126 127 |
# File 'lib/right_support/data/serializer.rb', line 123 def initialize(={}) = DEFAULT_OPTIONS.merge() @marker = [:marker] @encoder = [:encoder] end |
Class Method Details
.dump(object) ⇒ Object
116 117 118 |
# File 'lib/right_support/data/serializer.rb', line 116 def self.dump(object) self.new.dump(object) end |
.load(data) ⇒ Object
112 113 114 |
# File 'lib/right_support/data/serializer.rb', line 112 def self.load(data) self.new.load(data) end |
Instance Method Details
#dump(object) ⇒ String
Returns JSON document representing the serialized object.
138 139 140 141 |
# File 'lib/right_support/data/serializer.rb', line 138 def dump(object) jsonish = object_to_jsonish(object) @encoder.dump(jsonish) end |
#load(data) ⇒ Object
Returns unserialized Ruby object.
131 132 133 134 |
# File 'lib/right_support/data/serializer.rb', line 131 def load(data) jsonish = @encoder.load(data) jsonish_to_object(jsonish) end |