The YAML::Serializable
module automatically generates methods for YAML serialization when included.
require "yaml" class Location include YAML::Serializable @[YAML::Field(key: "lat")] property latitude : Float64 @[YAML::Field(key: "lng")] property longitude : Float64 end class House include YAML::Serializable property address : String property location : Location? end house = House.from_yaml(%({"address": "Crystal Road 1234", "location": {"lat": 12.3, "lng": 34.5}})) house.address # => "Crystal Road 1234" house.location # => #<Location:0x10cd93d80 @latitude=12.3, @longitude=34.5> house.to_yaml # => "---\naddress: Crystal Road 1234\nlocation:\n lat: 12.3\n lng: 34.5\n" houses = Array(House).from_yaml("---\n- address: Crystal Road 1234\n location:\n lat: 12.3\n lng: 34.5\n") houses.size # => 1 houses.to_yaml # => "---\n- address: Crystal Road 1234\n location:\n lat: 12.3\n lng: 34.5\n"
Including YAML::Serializable
will create #to_yaml
and self.from_yaml
methods on the current class, and a constructor which takes a YAML::PullParser
. By default, these methods serialize into a yaml object containing the value of every instance variable, the keys being the instance variable name. Most primitives and collections supported as instance variable values (string, integer, array, hash, etc.), along with objects which define to_yaml and a constructor taking a YAML::PullParser
. Union types are also supported, including unions with nil. If multiple types in a union parse correctly, it is undefined which one will be chosen.
To change how individual instance variables are parsed and serialized, the annotation YAML::Field
can be placed on the instance variable. Annotating property, getter and setter macros is also allowed.
require "yaml" class A include YAML::Serializable @[YAML::Field(key: "my_key", emit_null: true)] getter a : Int32? end
YAML::Field
properties:
true
skip this field in seriazation and deserialization (by default false)from_yaml(YAML::PullParser)
and to_yaml(value, YAML::Builder)
as class methods. Examples of converters are Time::Format
and Time::EpochConverter
for Time
.true
, a @{{key}}_present
instance variable will be generated when the key was present (even if it has a null
value), false
by defaulttrue
, emits a null
value for nilable property (by default nulls are not emitted)Deserialization also respects default values of variables:
require "yaml" struct A include YAML::Serializable @a : Int32 @b : Float64 = 1.0 end A.from_yaml("---\na: 1\n") # => A(@a=1, @b=1.0)
YAML::Serializable::Strict
and YAML::Serializable::Unmapped
.If the YAML::Serializable::Strict
module is included, unknown properties in the YAML document will raise a parse exception. By default the unknown properties are silently ignored. If the YAML::Serializable::Unmapped
module is included, unknown properties in the YAML document will be stored in a Hash(String, YAML::Any)
. On serialization, any keys inside yaml_unmapped will be serialized appended to the current yaml object.
require "yaml" struct A include YAML::Serializable include YAML::Serializable::Unmapped @a : Int32 end a = A.from_yaml("---\na: 1\nb: 2\n") # => A(@yaml_unmapped={"b" => 2_i64}, @a=1) a.to_yaml # => "---\na: 1\nb: 2\n"
YAML::Serializable::Options
supported properties:
true
, emits a null
value for all nilable properties (by default nulls are not emitted)require "yaml" @[YAML::Serializable::Options(emit_nulls: true)] class A include YAML::Serializable @a : Int32? end
A very common YAML serialization strategy for handling different objects under a same hierarchy is to use a discriminator field. For example in GeoJSON each object has a "type" field, and the rest of the fields, and their meaning, depend on its value.
You can use YAML::Serializable.use_yaml_discriminator
for this use case.
Tells this class to decode YAML by using a field as a discriminator.
Tells this class to decode YAML by using a field as a discriminator.
For example:
require "yaml" abstract class Shape include YAML::Serializable use_yaml_discriminator "type", {point: Point, circle: Circle} property type : String end class Point < Shape property x : Int32 property y : Int32 end class Circle < Shape property x : Int32 property y : Int32 property radius : Int32 end Shape.from_yaml(%( type: point x: 1 y: 2 )) # => #<Point:0x10373ae20 @type="point", @x=1, @y=2> Shape.from_yaml(%( type: circle x: 1 y: 2 radius: 3 )) # => #<Circle:0x106a4cea0 @type="circle", @x=1, @y=2, @radius=3>
© 2012–2020 Manas Technology Solutions.
Licensed under the Apache License, Version 2.0.
https://crystal-lang.org/api/0.35.1/YAML/Serializable.html