diff --git a/spec/std/json/any_spec.cr b/spec/std/json/any_spec.cr index ec033b62c62e..b93cd9f29a31 100644 --- a/spec/std/json/any_spec.cr +++ b/spec/std/json/any_spec.cr @@ -26,11 +26,8 @@ describe JSON::Any do it "gets float" do JSON.parse("123.45").as_f.should eq(123.45) - JSON.parse("123.45").as_f32.should eq(123.45_f32) JSON.parse("123.45").as_f?.should eq(123.45) - JSON.parse("123.45").as_f32?.should eq(123.45_f32) JSON.parse("true").as_f?.should be_nil - JSON.parse("true").as_f32?.should be_nil end it "gets string" do diff --git a/src/any.cr b/src/any.cr new file mode 100644 index 000000000000..af924a30150b --- /dev/null +++ b/src/any.cr @@ -0,0 +1,160 @@ +abstract struct Any + # Assumes the underlying value is an `Array` or `Hash` and returns its size. + # Raises if the underlying value is not an `Array` or `Hash`. + def size : Int + case object = @raw + when Array + object.size + when Hash + object.size + else + raise "Expected Array or Hash for #size, not #{object.class}" + end + end + + # Checks that the underlying value is `Bool`, and returns its value. + # Raises otherwise. + def as_bool : Bool + @raw.as(Bool) + end + + # Checks that the underlying value is `Bool`, and returns its value. + # Returns `nil` otherwise. + def as_bool? : Bool? + @raw.as?(Bool) + end + + # Checks that the underlying value is `Float64`, and returns its value. + # Raises otherwise. + def as_f : Float64 + @raw.as(Float64) + end + + # Checks that the underlying value is `Float64`, and returns its value. + # Returns `nil` otherwise. + def as_f? : Float64? + @raw.as?(Float64) + end + + # Checks that the underlying value is `Nil`, and returns `nil`. + # Raises otherwise. + def as_nil : Nil + @raw.as(Nil) + end + + # Checks that the underlying value is `String`, and returns its value. + # Raises otherwise. + def as_s : String + @raw.as(String) + end + + # Checks that the underlying value is `String`, and returns its value. + # Returns `nil` otherwise. + def as_s? : String? + @raw.as?(String) + end + + # Checks that the underlying value is `Int64`, and returns its value as `Int32`. + # Raises otherwise. + def as_i : Int32 + as_i64.to_i + end + + # Checks that the underlying value is `Int64`, and returns its value as `Int32`. + # Returns `nil` otherwise. + def as_i? : Int32? + as_i64?.try &.to_i + end + + # Checks that the underlying value is `Int64`, and returns its value. + # Raises otherwise. + def as_i64 : Int64 + @raw.as(Int64) + end + + # Checks that the underlying value is `Int64`, and returns its value. + # Returns `nil` otherwise. + def as_i64? : Int64? + @raw.as?(Int64) + end + + # Checks that the underlying value is `Bytes`, and returns its value. + # Raises otherwise. + def as_bytes : Bytes + @raw.as(Bytes) + end + + # Checks that the underlying value is `Bytes`, and returns its value. + # Returns `nil` otherwise. + def as_bytes? : Bytes? + @raw.as?(Bytes) + end + + # :nodoc: + def inspect(io) + @raw.inspect(io) + end + + # :nodoc: + def to_s(io) + @raw.to_s(io) + end + + # :nodoc: + def pretty_print(pp) + @raw.pretty_print(pp) + end + + # Returns `true` if both `self` and *other*'s raw object are equal. + def ==(other : Any) + raw == other.raw + end + + # Returns `true` if the raw object is equal to *other*. + def ==(other) + raw == other + end + + # See `Object#hash(hasher)` + def_hash raw +end + +macro any_classes(type) + class Object + def ===(other : {{type.id}}::Any) + self === other.raw + end + end + + struct Value + def ==(other : {{type.id}}::Any) + self == other.raw + end + end + + class Reference + def ==(other : {{type.id}}::Any) + self == other.raw + end + end + + class Array + def ==(other : {{type.id}}::Any) + self == other.raw + end + end + + class Hash + def ==(other : {{type.id}}::Any) + self == other.raw + end + end + + class Regex + def ===(other : {{type.id}}::Any) + value = self === other.raw + $~ = $~ + value + end + end +end diff --git a/src/json/any.cr b/src/json/any.cr index 5048b6351acc..86b24e835d5c 100644 --- a/src/json/any.cr +++ b/src/json/any.cr @@ -1,3 +1,5 @@ +require "../any" + # `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. # @@ -13,7 +15,7 @@ # a type check against the raw underlying value. This means that invoking `#as_s` # when the underlying value is not a String will raise: the value won't automatically # be converted (parsed) to a `String`. -struct JSON::Any +struct JSON::Any < ::Any # All possible JSON types. alias Type = Nil | Bool | Int64 | Float64 | String | Array(Any) | Hash(String, Any) @@ -54,19 +56,6 @@ struct JSON::Any def initialize(@raw : Type) end - # Assumes the underlying value is an `Array` or `Hash` and returns its size. - # Raises if the underlying value is not an `Array` or `Hash`. - def size : Int - case object = @raw - when Array - object.size - when Hash - object.size - else - raise "Expected Array or Hash for #size, not #{object.class}" - end - end - # Assumes the underlying value is an `Array` and returns the element # at the given index. # Raises if the underlying value is not an `Array`. @@ -115,84 +104,6 @@ struct JSON::Any end end - # Checks that the underlying value is `Nil`, and returns `nil`. - # Raises otherwise. - def as_nil : Nil - @raw.as(Nil) - end - - # Checks that the underlying value is `Bool`, and returns its value. - # Raises otherwise. - def as_bool : Bool - @raw.as(Bool) - end - - # Checks that the underlying value is `Bool`, and returns its value. - # Returns `nil` otherwise. - def as_bool? : Bool? - as_bool if @raw.is_a?(Bool) - end - - # Checks that the underlying value is `Int`, and returns its value as an `Int32`. - # Raises otherwise. - def as_i : Int32 - @raw.as(Int).to_i - end - - # Checks that the underlying value is `Int`, and returns its value as an `Int32`. - # Returns `nil` otherwise. - def as_i? : Int32? - as_i if @raw.is_a?(Int) - end - - # Checks that the underlying value is `Int`, and returns its value as an `Int64`. - # Raises otherwise. - def as_i64 : Int64 - @raw.as(Int).to_i64 - end - - # Checks that the underlying value is `Int`, and returns its value as an `Int64`. - # Returns `nil` otherwise. - def as_i64? : Int64? - as_i64 if @raw.is_a?(Int64) - end - - # Checks that the underlying value is `Float`, and returns its value as an `Float64`. - # Raises otherwise. - def as_f : Float64 - @raw.as(Float).to_f - end - - # Checks that the underlying value is `Float`, and returns its value as an `Float64`. - # Returns `nil` otherwise. - def as_f? : Float64? - as_f if @raw.is_a?(Float64) - end - - # Checks that the underlying value is `Float`, and returns its value as an `Float32`. - # Raises otherwise. - def as_f32 : Float32 - @raw.as(Float).to_f32 - end - - # Checks that the underlying value is `Float`, and returns its value as an `Float32`. - # Returns `nil` otherwise. - def as_f32? : Float32? - as_f32 if (@raw.is_a?(Float32) || @raw.is_a?(Float64)) - end - - # Checks that the underlying value is `String`, and returns its value. - # Raises otherwise. - def as_s : String - @raw.as(String) - end - - # Checks that the underlying value is `String`, and returns its value. - # Returns `nil` otherwise. - def as_s? : String? - as_s if @raw.is_a?(String) - end - # Checks that the underlying value is `Array`, and returns its value. # Raises otherwise. def as_a : Array(Any) @@ -202,7 +113,7 @@ struct JSON::Any # Checks that the underlying value is `Array`, and returns its value. # Returns `nil` otherwise. def as_a? : Array(Any)? - as_a if @raw.is_a?(Array) + @raw.as?(Array) end # Checks that the underlying value is `Hash`, and returns its value. @@ -214,87 +125,23 @@ struct JSON::Any # Checks that the underlying value is `Hash`, and returns its value. # Returns `nil` otherwise. def as_h? : Hash(String, Any)? - as_h if @raw.is_a?(Hash) - end - - # :nodoc: - def inspect(io) - @raw.inspect(io) + @raw.as?(Hash) end - # :nodoc: - def to_s(io) - @raw.to_s(io) - end - - # :nodoc: - def pretty_print(pp) - @raw.pretty_print(pp) - end - - # Returns `true` if both `self` and *other*'s raw object are equal. - def ==(other : JSON::Any) - raw == other.raw - end - - # Returns `true` if the raw object is equal to *other*. - def ==(other) - raw == other - end - - # See `Object#hash(hasher)` - def_hash raw - # :nodoc: def to_json(json : JSON::Builder) raw.to_json(json) end - # Returns a new JSON::Any instance with the `raw` value `dup`ed. + # Returns a new Any instance with the `raw` value `dup`ed. def dup Any.new(raw.dup) end - # Returns a new JSON::Any instance with the `raw` value `clone`ed. + # Returns a new Any instance with the `raw` value `clone`ed. def clone Any.new(raw.clone) end end -class Object - def ===(other : JSON::Any) - self === other.raw - 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 - $~ = $~ - value - end -end +any_classes "JSON" diff --git a/src/yaml.cr b/src/yaml.cr index f4d51d85cc45..86afc3dd85b6 100644 --- a/src/yaml.cr +++ b/src/yaml.cr @@ -1,8 +1,4 @@ -require "./yaml/*" -require "./yaml/schema/*" -require "./yaml/schema/core/*" -require "./yaml/nodes/*" - +require "./yaml/**" require "base64" # The YAML module provides serialization and deserialization of YAML diff --git a/src/yaml/any.cr b/src/yaml/any.cr index 97def02a7857..dd520bb2752b 100644 --- a/src/yaml/any.cr +++ b/src/yaml/any.cr @@ -1,3 +1,5 @@ +require "../any" + # `YAML::Any` is a convenient wrapper around all possible YAML core types # (`YAML::Any::Type`) and can be used for traversing dynamic or # unknown YAML structures. @@ -23,7 +25,7 @@ # a type check against the raw underlying value. This means that invoking `#as_s` # when the underlying value is not a `String` will raise: the value won't automatically # be converted (parsed) to a `String`. -struct YAML::Any +struct YAML::Any < ::Any # All valid YAML core schema types. alias Type = Nil | Bool | Int64 | Float64 | String | Time | Bytes | Array(Any) | Hash(Any, Any) | Set(Any) @@ -74,20 +76,6 @@ struct YAML::Any def initialize(@raw : Type) end - # Assumes the underlying value is an `Array` or `Hash` and returns its size. - # - # Raises if the underlying value is not an `Array` or `Hash`. - def size : Int - case object = @raw - when Array - object.size - when Hash - object.size - else - raise "Expected Array or Hash for #size, not #{object.class}" - end - end - # Assumes the underlying value is an `Array` or `Hash` # and returns the element at the given *index_or_key*. # @@ -126,60 +114,6 @@ struct YAML::Any end end - # Checks that the underlying value is `Nil`, and returns `nil`. - # Raises otherwise. - def as_nil : Nil - @raw.as(Nil) - end - - # Checks that the underlying value is `String`, and returns its value. - # Raises otherwise. - def as_s : String - @raw.as(String) - end - - # Checks that the underlying value is `String`, and returns its value. - # Returns `nil` otherwise. - def as_s? : String? - @raw.as?(String) - end - - # Checks that the underlying value is `Int64`, and returns its value. - # Raises otherwise. - def as_i64 : Int64 - @raw.as(Int64) - end - - # Checks that the underlying value is `Int64`, and returns its value. - # Returns `nil` otherwise. - def as_i64? : Int64? - @raw.as?(Int64) - end - - # Checks that the underlying value is `Int64`, and returns its value as `Int32`. - # Raises otherwise. - def as_i : Int32 - @raw.as(Int64).to_i - end - - # Checks that the underlying value is `Int64`, and returns its value as `Int32`. - # Returns `nil` otherwise. - def as_i? : Int32? - @raw.as?(Int64).try &.to_i - end - - # Checks that the underlying value is `Float64`, and returns its value. - # Raises otherwise. - def as_f : Float64 - @raw.as(Float64) - end - - # Checks that the underlying value is `Float64`, and returns its value. - # Returns `nil` otherwise. - def as_f? : Float64? - @raw.as?(Float64) - end - # Checks that the underlying value is `Time`, and returns its value. # Raises otherwise. def as_time : Time @@ -216,96 +150,20 @@ struct YAML::Any @raw.as?(Hash) end - # Checks that the underlying value is `Bytes`, and returns its value. - # Raises otherwise. - def as_bytes : Bytes - @raw.as(Bytes) - end - - # Checks that the underlying value is `Bytes`, and returns its value. - # Returns `nil` otherwise. - def as_bytes? : Bytes? - @raw.as?(Bytes) - end - - # :nodoc: - def inspect(io) - @raw.inspect(io) - end - - # :nodoc: - def to_s(io) - @raw.to_s(io) - end - - # :nodoc: - def pretty_print(pp) - @raw.pretty_print(pp) - end - - # Returns `true` if both `self` and *other*'s raw object are equal. - def ==(other : YAML::Any) - raw == other.raw - end - - # Returns `true` if the raw object is equal to *other*. - def ==(other) - raw == other - end - - # See `Object#hash(hasher)` - def_hash raw - # :nodoc: def to_yaml(io) raw.to_yaml(io) end - # Returns a new YAML::Any instance with the `raw` value `dup`ed. + # Returns a new Any instance with the `raw` value `dup`ed. def dup Any.new(raw.dup) end - # Returns a new YAML::Any instance with the `raw` value `clone`ed. + # Returns a new Any instance with the `raw` value `clone`ed. def clone Any.new(raw.clone) end end -class Object - def ===(other : YAML::Any) - self === other.raw - 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 - $~ = $~ - value - end -end +any_classes "YAML"