Skip to content

Commit

Permalink
Support to_yaml in YAML.mapping generated classes (#3559)
Browse files Browse the repository at this point in the history
* Support to_yaml in YAML.mapping generated classes

* Support converters
maxpowa authored and Ary Borenszweig committed Nov 19, 2016
1 parent 4e3eb11 commit d3bc110
Showing 3 changed files with 64 additions and 2 deletions.
30 changes: 30 additions & 0 deletions spec/std/yaml/mapping_spec.cr
Original file line number Diff line number Diff line change
@@ -68,6 +68,15 @@ private class YAMLWithSmallIntegers
})
end

private class YAMLWithNilableTime
YAML.mapping({
value: {type: Time, nilable: true, converter: Time::Format.new("%F")},
})

def initialize
end
end

private class YAMLWithTimeEpoch
YAML.mapping({
value: {type: Time, converter: Time::EpochConverter},
@@ -124,6 +133,17 @@ describe "YAML mapping" do
end
end

it "does to_yaml" do
person = YAMLPerson.from_yaml("---\nname: John\nage: 30\n")
person2 = YAMLPerson.from_yaml(person.to_yaml)
person2.should eq(person)
end

it "doesn't emit null when doing to_yaml" do
person = YAMLPerson.from_yaml("---\nname: John\n")
(person.to_yaml =~ /age/).should be_falsey
end

it "raises if non-nilable attribute is nil" do
expect_raises YAML::ParseException, "missing yaml attribute: name" do
YAMLPerson.from_yaml("---\nage: 30\n")
@@ -137,7 +157,10 @@ describe "YAML mapping" do

it "parses yaml with Time::Format converter" do
yaml = YAMLWithTime.from_yaml("---\nvalue: 2014-10-31 23:37:16\n")
yaml.value.should be_a(Time)
yaml.value.to_s.should eq("2014-10-31 23:37:16")
yaml.value.should eq(Time.new(2014, 10, 31, 23, 37, 16))
yaml.to_yaml.should eq("---\nvalue: 2014-10-31 23:37:16\n")
end

it "parses YAML with mapping key named 'key'" do
@@ -245,17 +268,24 @@ describe "YAML mapping" do
yaml.obj["foo"].as_s.should eq("bar")
end

it "outputs with converter when nilable" do
yaml = YAMLWithNilableTime.new
yaml.to_yaml.should eq("--- {}\n")
end

it "uses Time::EpochConverter" do
string = %({"value":1459859781})
yaml = YAMLWithTimeEpoch.from_yaml(string)
yaml.value.should be_a(Time)
yaml.value.should eq(Time.epoch(1459859781))
yaml.to_yaml.should eq("---\nvalue: 1459859781\n")
end

it "uses Time::EpochMillisConverter" do
string = %({"value":1459860483856})
yaml = YAMLWithTimeEpochMillis.from_yaml(string)
yaml.value.should be_a(Time)
yaml.value.should eq(Time.epoch_ms(1459860483856))
yaml.to_yaml.should eq("---\nvalue: 1459860483856\n")
end
end
20 changes: 20 additions & 0 deletions src/yaml/mapping.cr
Original file line number Diff line number Diff line change
@@ -146,6 +146,26 @@ module YAML
{% end %}
{% end %}
end

def to_yaml(%emitter : YAML::Emitter)
%emitter.mapping do
{% for key, value in properties %}
_{{key.id}} = @{{key.id}}

unless _{{key.id}}.is_a?(Nil)
# Key
{{value[:key] || key.id.stringify}}.to_yaml(%emitter)

# Value
{% if value[:converter] %}
{{ value[:converter] }}.to_yaml(_{{key.id}}, %emitter)
{% else %}
_{{key.id}}.to_yaml(%emitter)
{% end %}
end
{% end %}
end
end
end

# This is a convenience method to allow invoking `YAML.mapping`
16 changes: 14 additions & 2 deletions src/yaml/to_yaml.cr
Original file line number Diff line number Diff line change
@@ -104,8 +104,20 @@ struct Time
end
end

struct Time::Format
def to_yaml(value : Time, emitter : YAML::Emitter)
format(value).to_yaml(emitter)
end
end

module Time::EpochConverter
def self.to_yaml(value : Time, io : IO)
io << value.epoch
def self.to_yaml(value : Time, emitter : YAML::Emitter)
emitter << value.epoch
end
end

module Time::EpochMillisConverter
def self.to_yaml(value : Time, emitter : YAML::Emitter)
emitter << value.epoch_ms
end
end

0 comments on commit d3bc110

Please sign in to comment.