diff --git a/spec/std/json/any_spec.cr b/spec/std/json/any_spec.cr index c4e840115e24..a4399870efbb 100644 --- a/spec/std/json/any_spec.cr +++ b/spec/std/json/any_spec.cr @@ -86,24 +86,6 @@ describe JSON::Any do end end - describe "each" do - it "of array" do - elems = [] of Int32 - JSON.parse("[1, 2, 3]").each do |any| - elems << any.as_i - end - elems.should eq([1, 2, 3]) - end - - it "of hash" do - elems = [] of String - JSON.parse(%({"foo": "bar"})).each do |key, value| - elems << key.to_s << value.to_s - end - elems.should eq(%w(foo bar)) - end - end - it "traverses big structure" do obj = JSON.parse(%({"foo": [1, {"bar": [2, 3]}]})) obj["foo"][1]["bar"][1].as_i.should eq(3) @@ -123,12 +105,4 @@ describe JSON::Any do (/o+/ === JSON.parse(%("foo"))).should be_truthy $~[0].should eq("oo") end - - it "is enumerable" do - nums = JSON.parse("[1, 2, 3]") - nums.each_with_index do |x, i| - x.should be_a(JSON::Any) - x.raw.should eq(i + 1) - end - end end diff --git a/spec/std/json/parser_spec.cr b/spec/std/json/parser_spec.cr index cd0b16b02918..96cfd52277a2 100644 --- a/spec/std/json/parser_spec.cr +++ b/spec/std/json/parser_spec.cr @@ -34,7 +34,7 @@ describe JSON::Parser do it_parses "[0]", [0] it_parses " [ 0 ] ", [0] - it_parses "{}", {} of String => JSON::Type + it_parses "{}", {} of String => JSON::Any it_parses %({"foo": 1}), {"foo" => 1} it_parses %({"foo": 1, "bar": 1.5}), {"foo" => 1, "bar" => 1.5} it_parses %({"fo\\no": 1}), {"fo\no" => 1} @@ -75,7 +75,7 @@ describe JSON::Parser do end it "returns raw" do - value = JSON.parse_raw("1") + value = JSON.parse("1").raw value.should eq(1) value.should be_a(Int64) end diff --git a/spec/std/json/pull_parser_spec.cr b/spec/std/json/pull_parser_spec.cr index f9e20a6dc2f0..74de1cea4f2a 100644 --- a/spec/std/json/pull_parser_spec.cr +++ b/spec/std/json/pull_parser_spec.cr @@ -46,7 +46,7 @@ class JSON::PullParser def assert(array : Array) assert_array do array.each do |x| - assert x + assert x.raw end end end @@ -54,8 +54,8 @@ class JSON::PullParser def assert(hash : Hash) assert_object do hash.each do |key, value| - assert(key.as(String)) do - assert value + assert(key) do + assert value.raw end end end diff --git a/spec/std/yaml/any_spec.cr b/spec/std/yaml/any_spec.cr index 78d307136038..deb7c8b2323c 100644 --- a/spec/std/yaml/any_spec.cr +++ b/spec/std/yaml/any_spec.cr @@ -128,24 +128,6 @@ describe YAML::Any do end end - describe "each" do - it "of array" do - elems = [] of String - YAML.parse("- foo\n- bar\n").each do |any| - elems << any.as_s - end - elems.should eq(%w(foo bar)) - end - - it "of hash" do - elems = [] of String - YAML.parse("foo: bar").each do |key, value| - elems << key.to_s << value.to_s - end - elems.should eq(%w(foo bar)) - end - end - it "traverses big structure" do obj = YAML.parse("--- \nfoo: \n bar: \n baz: \n - qux\n - fox") obj["foo"]["bar"]["baz"][1].as_s.should eq("fox") @@ -174,7 +156,7 @@ describe YAML::Any do it "is enumerable" do nums = YAML.parse("[1, 2, 3]") - nums.each_with_index do |x, i| + nums.as_a.each_with_index do |x, i| x.should be_a(YAML::Any) x.raw.should eq(i + 1) end diff --git a/spec/std/yaml/schema/core_spec.cr b/spec/std/yaml/schema/core_spec.cr index 0cb295c53650..017e91b15148 100644 --- a/spec/std/yaml/schema/core_spec.cr +++ b/spec/std/yaml/schema/core_spec.cr @@ -31,7 +31,7 @@ private def it_parses_scalar_from_pull(string, expected, file = __FILE__, line = end end -private def it_parses_scalar_from_pull(string, file = __FILE__, line = __LINE__, &block : YAML::Type ->) +private def it_parses_scalar_from_pull(string, file = __FILE__, line = __LINE__, &block : YAML::Any::Type ->) it "parses #{string.inspect}", file, line do pull = YAML::PullParser.new(%(value: #{string})) pull.read_stream_start @@ -39,7 +39,7 @@ private def it_parses_scalar_from_pull(string, file = __FILE__, line = __LINE__, pull.read_mapping_start pull.read_scalar # key - block.call(YAML::Schema::Core.parse_scalar(pull).as(YAML::Type)) + block.call(YAML::Schema::Core.parse_scalar(pull).as(YAML::Any::Type)) end end diff --git a/spec/std/yaml/yaml_spec.cr b/spec/std/yaml/yaml_spec.cr index af57d204395c..4eb6a345d9bd 100644 --- a/spec/std/yaml/yaml_spec.cr +++ b/spec/std/yaml/yaml_spec.cr @@ -7,12 +7,12 @@ describe "YAML" do it { YAML.parse("- foo\n- bar").should eq(["foo", "bar"]) } it { YAML.parse_all("---\nfoo\n---\nbar\n").should eq(["foo", "bar"]) } it { YAML.parse("foo: bar").should eq({"foo" => "bar"}) } - it { YAML.parse("--- []\n").should eq([] of YAML::Type) } + it { YAML.parse("--- []\n").should eq([] of YAML::Any) } it { YAML.parse("---\n...").should eq nil } it "parses recursive sequence" do doc = YAML.parse("--- &foo\n- *foo\n") - doc[0].raw.as(Array).should be(doc.raw.as(Array)) + doc[0].as_a.should be(doc.raw.as(Array)) end it "parses recursive mapping" do @@ -20,13 +20,13 @@ describe "YAML" do friends: - *1 )) - doc["friends"][0].raw.as(Hash).should be(doc.raw.as(Hash)) + doc["friends"][0].as_h.should be(doc.as_h) end it "parses alias to scalar" do doc = YAML.parse("---\n- &x foo\n- *x\n") doc.should eq(["foo", "foo"]) - doc[0].raw.as(String).should be(doc[1].raw.as(String)) + doc[0].as_s.should be(doc[1].as_s) end describe "merging with << key" do diff --git a/src/json.cr b/src/json.cr index d86ffdef96e1..dee3dbae8d61 100644 --- a/src/json.cr +++ b/src/json.cr @@ -75,16 +75,8 @@ module JSON end end - # All valid JSON types. - alias Type = Nil | Bool | Int64 | Float64 | String | Array(Type) | Hash(String, Type) - # Parses a JSON document as a `JSON::Any`. def self.parse(input : String | IO) : Any - Any.new parse_raw(input) - end - - # Parses a JSON document as a `JSON::Type`. - def self.parse_raw(input : String | IO) : Type Parser.new(input).parse end end diff --git a/src/json/any.cr b/src/json/any.cr index f326c72a52b8..8b6294a6f890 100644 --- a/src/json/any.cr +++ b/src/json/any.cr @@ -1,4 +1,4 @@ -# `JSON::Any` is a convenient wrapper around all possible JSON types (`JSON::Type`) +# `JSON::Any` is a convenient wrapper around all possible JSON types (`JSON::Any::Type`) # and can be used for traversing dynamic or unknown JSON structures. # # ``` @@ -14,7 +14,8 @@ # when the underlying value is not a String will raise: the value won't automatically # be converted (parsed) to a `String`. struct JSON::Any - include Enumerable(self) + # All possible JSON types. + alias Type = Nil | Bool | Int64 | Float64 | String | Array(Any) | Hash(String, Any) # Reads a `JSON::Any` value from the given pull parser. def self.new(pull : JSON::PullParser) @@ -30,15 +31,15 @@ struct JSON::Any when :string new pull.read_string when :begin_array - ary = [] of JSON::Type + ary = [] of JSON::Any pull.read_array do - ary << new(pull).raw + ary << new(pull) end new ary when :begin_object - hash = {} of String => JSON::Type + hash = {} of String => JSON::Any pull.read_object do |key| - hash[key] = new(pull).raw + hash[key] = new(pull) end new hash else @@ -46,11 +47,11 @@ struct JSON::Any end end - # Returns the raw underlying value, a `JSON::Type`. - getter raw : JSON::Type + # Returns the raw underlying value. + getter raw : Type - # Creates a `JSON::Any` that wraps the given `JSON::Type`. - def initialize(@raw : JSON::Type) + # Creates a `JSON::Any` that wraps the given value. + def initialize(@raw : Type) end # Assumes the underlying value is an `Array` or `Hash` and returns its size. @@ -72,7 +73,7 @@ struct JSON::Any def [](index : Int) : JSON::Any case object = @raw when Array - Any.new object[index] + object[index] else raise "Expected Array for #[](index : Int), not #{object.class}" end @@ -84,8 +85,7 @@ struct JSON::Any def []?(index : Int) : JSON::Any? case object = @raw when Array - value = object[index]? - value.nil? ? nil : Any.new(value) + object[index]? else raise "Expected Array for #[]?(index : Int), not #{object.class}" end @@ -97,7 +97,7 @@ struct JSON::Any def [](key : String) : JSON::Any case object = @raw when Hash - Any.new object[key] + object[key] else raise "Expected Hash for #[](key : String), not #{object.class}" end @@ -109,31 +109,12 @@ struct JSON::Any def []?(key : String) : JSON::Any? case object = @raw when Hash - value = object[key]? - value.nil? ? nil : Any.new(value) + object[key]? else raise "Expected Hash for #[]?(key : String), not #{object.class}" end end - # Assumes the underlying value is an `Array` or `Hash` and yields each - # of the elements or key/values, always as `JSON::Any`. - # Raises if the underlying value is not an `Array` or `Hash`. - def each - case object = @raw - when Array - object.each do |elem| - yield Any.new(elem), Any.new(nil) - end - when Hash - object.each do |key, value| - yield Any.new(key), Any.new(value) - end - else - raise "Expected Array or Hash for #each, not #{object.class}" - end - end - # Checks that the underlying value is `Nil`, and returns `nil`. # Raises otherwise. def as_nil : Nil @@ -214,26 +195,26 @@ struct JSON::Any # Checks that the underlying value is `Array`, and returns its value. # Raises otherwise. - def as_a : Array(Type) + def as_a : Array(Any) @raw.as(Array) end # Checks that the underlying value is `Array`, and returns its value. # Returns `nil` otherwise. - def as_a? : Array(Type)? - as_a if @raw.is_a?(Array(Type)) + def as_a? : Array(Any)? + as_a if @raw.is_a?(Array) end # Checks that the underlying value is `Hash`, and returns its value. # Raises otherwise. - def as_h : Hash(String, Type) + def as_h : Hash(String, Any) @raw.as(Hash) end # Checks that the underlying value is `Hash`, and returns its value. # Returns `nil` otherwise. - def as_h? : Hash(String, Type)? - as_h if @raw.is_a?(Hash(String, Type)) + def as_h? : Hash(String, Any)? + as_h if @raw.is_a?(Hash) end # :nodoc: @@ -276,6 +257,30 @@ class Object end end +struct Value + def ==(other : JSON::Any) + self == other.raw + end +end + +class Reference + def ==(other : JSON::Any) + self == other.raw + end +end + +class Array + def ==(other : JSON::Any) + self == other.raw + end +end + +class Hash + def ==(other : JSON::Any) + self == other.raw + end +end + class Regex def ===(other : JSON::Any) value = self === other.raw diff --git a/src/json/parser.cr b/src/json/parser.cr index 2872f9c5f644..115bccb7b42f 100644 --- a/src/json/parser.cr +++ b/src/json/parser.cr @@ -9,7 +9,7 @@ class JSON::Parser next_token end - def parse : Type + def parse : Any json = parse_value check :EOF json @@ -41,7 +41,7 @@ class JSON::Parser private def parse_array next_token - ary = [] of Type + ary = [] of Any nest do if token.type != :"]" @@ -63,13 +63,13 @@ class JSON::Parser next_token - ary + Any.new(ary) end private def parse_object next_token_expect_object_key - object = {} of String => Type + object = {} of String => Any nest do if token.type != :"}" @@ -101,7 +101,7 @@ class JSON::Parser next_token - object + Any.new(object) end private delegate token, to: @lexer @@ -110,7 +110,7 @@ class JSON::Parser private def value_and_next_token(value) next_token - value + Any.new(value) end private def check(token_type) diff --git a/src/yaml.cr b/src/yaml.cr index cbecdabefeb7..147ede01a1aa 100644 --- a/src/yaml.cr +++ b/src/yaml.cr @@ -83,9 +83,6 @@ module YAML end end - # All valid YAML core schema types. - alias Type = Nil | Bool | Int64 | Float64 | String | Time | Bytes | Array(Type) | Hash(Type, Type) | Set(Type) - # Deserializes a YAML document according to the core schema. # # ```yaml diff --git a/src/yaml/any.cr b/src/yaml/any.cr index 31b4d3626517..305af3e001d5 100644 --- a/src/yaml/any.cr +++ b/src/yaml/any.cr @@ -1,5 +1,5 @@ # `YAML::Any` is a convenient wrapper around all possible YAML core types -# (`YAML::Type`) and can be used for traversing dynamic or +# (`YAML::Any::Type`) and can be used for traversing dynamic or # unknown YAML structures. # # ``` @@ -24,41 +24,42 @@ # when the underlying value is not a `String` will raise: the value won't automatically # be converted (parsed) to a `String`. struct YAML::Any - include Enumerable(self) + # All valid YAML core schema types. + alias Type = Nil | Bool | Int64 | Float64 | String | Time | Bytes | Array(Any) | Hash(Any, Any) | Set(Any) def self.new(ctx : YAML::ParseContext, node : YAML::Nodes::Node) - anchors = {} of String => Type - new(convert(node, anchors)) + anchors = {} of String => Any + convert(node, anchors) end private def self.convert(node, anchors) case node when YAML::Nodes::Scalar - YAML::Schema::Core.parse_scalar(node.value) + new YAML::Schema::Core.parse_scalar(node.value) when YAML::Nodes::Sequence - ary = [] of Type + ary = [] of Any if anchor = node.anchor - anchors[anchor] = ary + anchors[anchor] = Any.new(ary) end node.each do |value| ary << convert(value, anchors) end - ary + new ary when YAML::Nodes::Mapping - hash = {} of Type => Type + hash = {} of Any => Any if anchor = node.anchor - anchors[anchor] = hash + anchors[anchor] = Any.new(hash) end node.each do |key, value| hash[convert(key, anchors)] = convert(value, anchors) end - hash + new hash when YAML::Nodes::Alias anchors[node.anchor] else @@ -66,11 +67,11 @@ struct YAML::Any end end - # Returns the raw underlying value, a `YAML::Type`. - getter raw : YAML::Type + # Returns the raw underlying value, a `Type`. + getter raw : Type - # Creates a `YAML::Any` that wraps the given `YAML::Type`. - def initialize(@raw : YAML::Type) + # Creates a `Any` that wraps the given `Type`. + def initialize(@raw : Type) end # Assumes the underlying value is an `Array` or `Hash` and returns its size. @@ -95,12 +96,12 @@ struct YAML::Any case object = @raw when Array if index_or_key.is_a?(Int) - Any.new object[index_or_key] + object[index_or_key] else raise "Expected int key for Array#[], not #{object.class}" end when Hash - Any.new object[index_or_key] + object[index_or_key] else raise "Expected Array or Hash, not #{object.class}" end @@ -114,33 +115,12 @@ struct YAML::Any case object = @raw when Array if index_or_key.is_a?(Int) - value = object[index_or_key]? - value ? Any.new(value) : nil + object[index_or_key]? else nil end when Hash - value = object[index_or_key]? - value ? Any.new(value) : nil - else - raise "Expected Array or Hash, not #{object.class}" - end - end - - # Assumes the underlying value is an `Array` or `Hash` and yields each - # of the elements or key/values, always as `YAML::Any`. - # - # Raises if the underlying value is not an `Array` or `Hash`. - def each - case object = @raw - when Array - object.each do |elem| - yield Any.new(elem), Any.new(nil) - end - when Hash - object.each do |key, value| - yield Any.new(key), Any.new(value) - end + object[index_or_key]? else raise "Expected Array or Hash, not #{object.class}" end @@ -214,25 +194,25 @@ struct YAML::Any # Checks that the underlying value is `Array`, and returns its value. # Raises otherwise. - def as_a : Array(Type) + def as_a : Array(Any) @raw.as(Array) end # Checks that the underlying value is `Array`, and returns its value. # Returns `nil` otherwise. - def as_a? : Array(Type)? + def as_a? : Array(Any)? @raw.as?(Array) end # Checks that the underlying value is `Hash`, and returns its value. # Raises otherwise. - def as_h : Hash(Type, Type) + def as_h : Hash(Any, Any) @raw.as(Hash) end # Checks that the underlying value is `Hash`, and returns its value. # Returns `nil` otherwise. - def as_h? : Hash(Type, Type)? + def as_h? : Hash(Any, Any)? @raw.as?(Hash) end @@ -288,6 +268,30 @@ class Object end end +struct Value + def ==(other : YAML::Any) + self == other.raw + end +end + +class Reference + def ==(other : YAML::Any) + self == other.raw + end +end + +class Array + def ==(other : YAML::Any) + self == other.raw + end +end + +class Hash + def ==(other : YAML::Any) + self == other.raw + end +end + class Regex def ===(other : YAML::Any) value = self === other.raw diff --git a/src/yaml/nodes/parser.cr b/src/yaml/nodes/parser.cr index 324e5a16c83c..31366cc8bb57 100644 --- a/src/yaml/nodes/parser.cr +++ b/src/yaml/nodes/parser.cr @@ -67,4 +67,20 @@ class YAML::Nodes::Parser < YAML::Parser def process_tag(tag, &block) end + + def add_to_documents(documents, document) + documents << document + end + + def add_to_document(document, node) + document << node + end + + def add_to_sequence(sequence, node) + sequence << node + end + + def add_to_mapping(mapping, key, value) + mapping[key] = value + end end diff --git a/src/yaml/parser.cr b/src/yaml/parser.cr index 7b30e64f1fdb..308b3fb0af34 100644 --- a/src/yaml/parser.cr +++ b/src/yaml/parser.cr @@ -16,6 +16,10 @@ abstract class YAML::Parser abstract def new_scalar abstract def put_anchor(anchor, value) abstract def get_anchor(anchor) + abstract def add_to_documents(documents, document) + abstract def add_to_document(document, node) + abstract def add_to_sequence(sequence, node) + abstract def add_to_mapping(mapping, key, value) def end_value(value) end @@ -23,10 +27,6 @@ abstract class YAML::Parser def process_tag(tag, &block) end - protected def cast_value(value) - value - end - protected def cast_document(document) document end @@ -41,7 +41,7 @@ abstract class YAML::Parser when .stream_end? return documents when .document_start? - documents << cast_value(parse_document) + add_to_documents(documents, parse_document) else unexpected_event end @@ -62,7 +62,7 @@ abstract class YAML::Parser unexpected_event end - cast_value(cast_document(document)) + cast_document(document) end private def parse_document @@ -73,7 +73,7 @@ abstract class YAML::Parser private def parse_document(document) @pull_parser.read_next - document << parse_node + add_to_document(document, parse_node) end_value(document) @pull_parser.read_document_end end @@ -116,7 +116,7 @@ abstract class YAML::Parser sequence = anchor new_sequence parse_sequence(sequence) do - sequence << parse_node + add_to_sequence(sequence, parse_node) end sequence @@ -138,7 +138,7 @@ abstract class YAML::Parser mapping = anchor new_mapping parse_mapping(mapping) do - mapping[parse_node] = parse_node + add_to_mapping(mapping, parse_node, parse_node) end mapping diff --git a/src/yaml/schema/core.cr b/src/yaml/schema/core.cr index 2719eb745283..3a702a750f70 100644 --- a/src/yaml/schema/core.cr +++ b/src/yaml/schema/core.cr @@ -19,7 +19,7 @@ module YAML::Schema::Core # parses it according to the core schema, taking the # scalar's style and tag into account, then advances # the pull parser. - def self.parse_scalar(pull_parser : YAML::PullParser) : Type + def self.parse_scalar(pull_parser : YAML::PullParser) : Nil | Bool | Int64 | Float64 | String | Time | Bytes string = pull_parser.value # Check for core schema tags @@ -36,7 +36,7 @@ module YAML::Schema::Core end # Parses a scalar value from the given *node*. - def self.parse_scalar(node : YAML::Nodes::Scalar) : Type + def self.parse_scalar(node : YAML::Nodes::Scalar) : Nil | Bool | Int64 | Float64 | String | Time | Bytes string = node.value # Check for core schema tags @@ -60,7 +60,7 @@ module YAML::Schema::Core # YAML::Schema::Core.parse_scalar("1.2") # => 1.2 # YAML::Schema::Core.parse_scalar("false") # => false # ``` - def self.parse_scalar(string : String) : Type + def self.parse_scalar(string : String) : Nil | Bool | Int64 | Float64 | String | Time | Bytes if parse_null?(string) return nil end diff --git a/src/yaml/schema/core/parser.cr b/src/yaml/schema/core/parser.cr index 6fbf01624947..ba8629bac067 100644 --- a/src/yaml/schema/core/parser.cr +++ b/src/yaml/schema/core/parser.cr @@ -1,6 +1,6 @@ # :nodoc: class YAML::Schema::Core::Parser < YAML::Parser - @anchors = {} of String => Type + @anchors = {} of String => Any def put_anchor(anchor, value) @anchors[anchor] = value @@ -17,56 +17,70 @@ class YAML::Schema::Core::Parser < YAML::Parser end def new_document - [] of Type + Any.new([] of Any) end def cast_document(document) - document.first? + document.as_a.first? || Any.new(nil) end def new_sequence - [] of Type + Any.new([] of Any) end def new_mapping - {} of Type => Type + Any.new({} of Any => Any) end def new_scalar - Core.parse_scalar(@pull_parser) + Any.new(Core.parse_scalar(@pull_parser)) end - def cast_value(value) - YAML::Any.new(value) + def add_to_documents(documents, document) + documents << document + end + + def add_to_document(document, node) + document.as_a << node + end + + def add_to_sequence(sequence, node) + sequence.as_a << node + end + + def add_to_mapping(mapping, key, value) + mapping.as_h[key] = value end protected def parse_mapping mapping = anchor new_mapping + raw_mapping = mapping.as_h parse_mapping(mapping) do tag = @pull_parser.tag key = parse_node + raw_key = key.raw location = @pull_parser.location value = parse_node - if key == "<<" && tag != "tag:yaml.org,2002:str" - case value + if raw_key == "<<" && tag != "tag:yaml.org,2002:str" + case raw = value.raw when Hash - mapping.merge!(value) + mapping.as_h.merge!(raw) when Array - if value.all? &.is_a?(Hash) - value.each do |elem| - mapping.merge!(elem.as(Hash)) + if raw.all? &.as_h? + raw.each do |elem| + raw_mapping.merge!(elem.as_h) end else - mapping[key] = value + raw_mapping[key] = value end else - mapping[key] = value + raw_mapping[key] = value end else - mapping[key] = value + raw_mapping[key] = value end end @@ -80,7 +94,7 @@ class YAML::Schema::Core::Parser < YAML::Parser Core.process_scalar_tag(@pull_parser, tag) do |value| @pull_parser.read_next - yield value + yield Any.new(value) end end @@ -103,25 +117,25 @@ class YAML::Schema::Core::Parser < YAML::Parser private def parse_pairs @pull_parser.expect_kind EventKind::SEQUENCE_START - pairs = [] of Type + pairs = [] of Any parse_sequence(pairs) do @pull_parser.expect_kind EventKind::MAPPING_START @pull_parser.read_next - pairs << {parse_node => parse_node} of Type => Type + pairs << Any.new({parse_node => parse_node} of Any => Any) @pull_parser.expect_kind EventKind::MAPPING_END @pull_parser.read_next end - pairs + Any.new(pairs) end private def parse_set @pull_parser.expect_kind EventKind::MAPPING_START - set = Set(Type).new + set = Set(Any).new parse_mapping(set) do set << parse_node @@ -129,6 +143,6 @@ class YAML::Schema::Core::Parser < YAML::Parser parse_node # discard value end - set + Any.new(set) end end diff --git a/src/yaml/schema/fail_safe.cr b/src/yaml/schema/fail_safe.cr index b8095014b590..4d531086a526 100644 --- a/src/yaml/schema/fail_safe.cr +++ b/src/yaml/schema/fail_safe.cr @@ -2,22 +2,19 @@ # fail-safe schema, as specified in http://www.yaml.org/spec/1.2/spec.html#id2802346, # where all scalar values are considered strings. module YAML::Schema::FailSafe - # All possible types according to the failsafe schema - alias Type = String | Hash(Type, Type) | Array(Type) | Nil - # Deserializes a YAML document. - def self.parse(data : String | IO) : Type + def self.parse(data : String | IO) : Any Parser.new data, &.parse end # Deserializes multiple YAML documents. - def self.parse_all(data : String | IO) : Type + def self.parse_all(data : String | IO) : Any Parser.new data, &.parse_all end # :nodoc: class Parser < YAML::Parser - @anchors = {} of String => Type + @anchors = {} of String => Any def put_anchor(anchor, value) @anchors[anchor] = value @@ -30,27 +27,43 @@ module YAML::Schema::FailSafe end def new_documents - [] of Type + [] of Any end def new_document - [] of Type + Any.new([] of Any) end def cast_document(doc) - doc.first? + doc.first? || Any.new(nil) end def new_sequence - [] of Type + Any.new([] of Any) end def new_mapping - {} of Type => Type + Any.new({} of Any => Any) end def new_scalar - @pull_parser.value + Any.new(@pull_parser.value) + end + + def add_to_documents(documents, document) + documents << document + end + + def add_to_document(document, node) + document.as_a << node + end + + def add_to_sequence(sequence, node) + sequence.as_a << node + end + + def add_to_mapping(mapping, key, value) + mapping.as_h[key] = value end end end