Skip to content

Commit

Permalink
YAML revamp
Browse files Browse the repository at this point in the history
- Add support for YAML core schema
- Add support for possibly other schemas via the abstract YAML::Parser class
- Add missing arguments to YAML::Builder (tag, anchor, scalar)
- Add support for parsing and generating recursive data structures
- Add support for merge (<<)
- Move LibYAML enums to the YAML namespace
  • Loading branch information
asterite authored and Martin Verzilli committed Oct 2, 2017
1 parent ab30165 commit 3335450
Show file tree
Hide file tree
Showing 27 changed files with 2,508 additions and 489 deletions.
74 changes: 72 additions & 2 deletions spec/std/yaml/any_spec.cr
Expand Up @@ -24,6 +24,67 @@ describe YAML::Any do
YAML.parse("foo: bar").as_h?.should eq({"foo" => "bar"})
YAML.parse("foo: bar")["foo"].as_h?.should be_nil
end

it "gets int64" do
value = YAML.parse("1").as_i64
value.should eq(1)
value.should be_a(Int64)

value = YAML.parse("1").as_i64?
value.should eq(1)
value.should be_a(Int64)

value = YAML.parse("true").as_i64?
value.should be_nil
end

it "gets int32" do
value = YAML.parse("1").as_i
value.should eq(1)
value.should be_a(Int32)

value = YAML.parse("1").as_i?
value.should eq(1)
value.should be_a(Int32)

value = YAML.parse("true").as_i?
value.should be_nil
end

it "gets float64" do
value = YAML.parse("1.2").as_f
value.should eq(1.2)
value.should be_a(Float64)

value = YAML.parse("1.2").as_f?
value.should eq(1.2)
value.should be_a(Float64)

value = YAML.parse("true").as_f?
value.should be_nil
end

it "gets time" do
value = YAML.parse("2010-01-02").as_time
value.should eq(Time.new(2010, 1, 2, kind: Time::Kind::Utc))

value = YAML.parse("2010-01-02").as_time?
value.should eq(Time.new(2010, 1, 2, kind: Time::Kind::Utc))

value = YAML.parse("hello").as_time?
value.should be_nil
end

it "gets bytes" do
value = YAML.parse("!!binary aGVsbG8=").as_bytes
value.should eq("hello".to_slice)

value = YAML.parse("!!binary aGVsbG8=").as_bytes?
value.should eq("hello".to_slice)

value = YAML.parse("1").as_bytes?
value.should be_nil
end
end

describe "#size" do
Expand All @@ -44,6 +105,10 @@ describe YAML::Any do
it "of hash" do
YAML.parse("foo: bar")["foo"].raw.should eq("bar")
end

it "of hash with integer keys" do
YAML.parse("1: bar")[1].raw.should eq("bar")
end
end

describe "#[]?" do
Expand All @@ -56,6 +121,11 @@ describe YAML::Any do
YAML.parse("foo: bar")["foo"]?.not_nil!.raw.should eq("bar")
YAML.parse("foo: bar")["fox"]?.should be_nil
end

it "of hash with integer keys" do
YAML.parse("1: bar")[1]?.not_nil!.raw.should eq("bar")
YAML.parse("1: bar")[2]?.should be_nil
end
end

describe "each" do
Expand Down Expand Up @@ -94,7 +164,7 @@ describe YAML::Any do
end

it "can compare with ===" do
("1" === YAML.parse("1")).should be_truthy
(1 === YAML.parse("1")).should be_truthy
end

it "exposes $~ when doing Regex#===" do
Expand All @@ -106,7 +176,7 @@ describe YAML::Any do
nums = YAML.parse("[1, 2, 3]")
nums.each_with_index do |x, i|
x.should be_a(YAML::Any)
x.raw.should eq((i + 1).to_s)
x.raw.should eq(i + 1)
end
end
end
81 changes: 81 additions & 0 deletions spec/std/yaml/builder_spec.cr
Expand Up @@ -15,6 +15,24 @@ describe YAML::Builder do
end
end

it "writes scalar with style" do
assert_built(%(--- "1"\n)) do
scalar(1, style: YAML::ScalarStyle::DOUBLE_QUOTED)
end
end

it "writes scalar with tag" do
assert_built(%(--- !foo 1\n...\n)) do
scalar(1, tag: "!foo")
end
end

it "writes scalar with anchor" do
assert_built(%(--- &foo 1\n...\n)) do
scalar(1, anchor: "foo")
end
end

it "writes sequence" do
assert_built("---\n- 1\n- 2\n- 3\n") do
sequence do
Expand All @@ -25,6 +43,36 @@ describe YAML::Builder do
end
end

it "writes sequence with tag" do
assert_built("--- !foo\n- 1\n- 2\n- 3\n") do
sequence(tag: "!foo") do
scalar(1)
scalar(2)
scalar(3)
end
end
end

it "writes sequence with anchor" do
assert_built("--- &foo\n- 1\n- 2\n- 3\n") do
sequence(anchor: "foo") do
scalar(1)
scalar(2)
scalar(3)
end
end
end

it "writes sequence with style" do
assert_built("--- [1, 2, 3]\n") do
sequence(style: YAML::SequenceStyle::FLOW) do
scalar(1)
scalar(2)
scalar(3)
end
end
end

it "writes mapping" do
assert_built("---\nfoo: 1\nbar: 2\n") do
mapping do
Expand All @@ -35,4 +83,37 @@ describe YAML::Builder do
end
end
end

it "writes mapping with tag" do
assert_built("--- !foo\nfoo: 1\nbar: 2\n") do
mapping(tag: "!foo") do
scalar("foo")
scalar(1)
scalar("bar")
scalar(2)
end
end
end

it "writes mapping with anchor" do
assert_built("--- &foo\nfoo: 1\nbar: 2\n") do
mapping(anchor: "foo") do
scalar("foo")
scalar(1)
scalar("bar")
scalar(2)
end
end
end

it "writes mapping with style" do
assert_built("--- {foo: 1, bar: 2}\n") do
mapping(style: YAML::MappingStyle::FLOW) do
scalar("foo")
scalar(1)
scalar("bar")
scalar(2)
end
end
end
end
138 changes: 134 additions & 4 deletions spec/std/yaml/mapping_spec.cr
Expand Up @@ -96,6 +96,34 @@ private class YAMLWithPresence
})
end

class YAMLRecursive
YAML.mapping({
name: String,
other: YAMLRecursive,
})
end

class YAMLRecursiveNilable
YAML.mapping({
name: String,
other: YAMLRecursiveNilable?,
})
end

class YAMLRecursiveArray
YAML.mapping({
name: String,
other: Array(YAMLRecursiveArray),
})
end

class YAMLRecursiveHash
YAML.mapping({
name: String,
other: Hash(String, YAMLRecursiveHash),
})
end

describe "YAML mapping" do
it "parses person" do
person = YAMLPerson.from_yaml("---\nname: John\nage: 30\n")
Expand Down Expand Up @@ -127,6 +155,35 @@ describe "YAML mapping" do
people[1].name.should eq("Doe")
end

it "parses array of people with merge" do
yaml = <<-YAML
- &1
name: foo
age: 1
-
<<: *1
age: 2
YAML

people = Array(YAMLPerson).from_yaml(yaml)
people[1].name.should eq("foo")
people[1].age.should eq(2)
end

it "parses array of people with merge, doesn't hang on infinite recursion" do
yaml = <<-YAML
- &1
name: foo
<<: *1
<<: [ *1, *1 ]
age: 1
YAML

people = Array(YAMLPerson).from_yaml(yaml)
people[0].name.should eq("foo")
people[0].age.should eq(1)
end

it "parses person with unknown attributes" do
person = YAMLPerson.from_yaml("---\nname: John\nunknown: [1, 2, 3]\nage: 30\n")
person.should be_a(YAMLPerson)
Expand Down Expand Up @@ -197,6 +254,68 @@ describe "YAML mapping" do
typeof(yaml.bar).should eq(Int8)
end

it "parses recursive" do
yaml = <<-YAML
--- &1
name: foo
other: *1
YAML

rec = YAMLRecursive.from_yaml(yaml)
rec.name.should eq("foo")
rec.other.should be(rec)
end

it "parses recursive nilable (1)" do
yaml = <<-YAML
--- &1
name: foo
other: *1
YAML

rec = YAMLRecursiveNilable.from_yaml(yaml)
rec.name.should eq("foo")
rec.other.should be(rec)
end

it "parses recursive nilable (2)" do
yaml = <<-YAML
--- &1
name: foo
YAML

rec = YAMLRecursiveNilable.from_yaml(yaml)
rec.name.should eq("foo")
rec.other.should be_nil
end

it "parses recursive array" do
yaml = <<-YAML
---
name: foo
other: &1
- name: bar
other: *1
YAML

rec = YAMLRecursiveArray.from_yaml(yaml)
rec.other[0].other.should be(rec.other)
end

it "parses recursive hash" do
yaml = <<-YAML
---
name: foo
other: &1
foo:
name: bar
other: *1
YAML

rec = YAMLRecursiveHash.from_yaml(yaml)
rec.other["foo"].other.should be(rec.other)
end

describe "parses YAML with defaults" do
it "mixed" do
json = YAMLWithDefaults.from_yaml(%({"a":1,"b":"bla"}))
Expand All @@ -214,11 +333,22 @@ describe "YAML mapping" do
json = YAMLWithDefaults.from_yaml(%({}))
json.a.should eq 11
json.b.should eq "Haha"
end

it "mixes with all defaults (#2873)" do
yaml = YAMLWithDefaults.from_yaml("")
yaml.a.should eq 11
yaml.b.should eq "Haha"
end

it "raises when not a mapping or empty scalar" do
expect_raises(YAML::ParseException) do
YAMLWithDefaults.from_yaml("1")
end

# There's no "null" in YAML? Maybe we should support this eventually
# json = YAMLWithDefaults.from_yaml(%({"a":null,"b":null}))
# json.a.should eq 11
# json.b.should eq "Haha"
expect_raises(YAML::ParseException) do
YAMLWithDefaults.from_yaml("[1]")
end
end

it "bool" do
Expand Down

0 comments on commit 3335450

Please sign in to comment.