Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6102cb8e5734
Choose a base ref
...
head repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: dc9f5265e6a3
Choose a head ref
  • 2 commits
  • 8 files changed
  • 1 contributor

Commits on Jul 11, 2016

  1. Added Class#nilable? and Union.nilable?

    Ary Borenszweig committed Jul 11, 2016
    Copy the full SHA
    7fd2b33 View commit details
  2. Fixed #2983: JSON.mapping doesn't work with nilable type when missi…

    …ng key
    Ary Borenszweig committed Jul 11, 2016
    Copy the full SHA
    dc9f526 View commit details
Showing with 66 additions and 5 deletions.
  1. +7 −0 spec/std/class_spec.cr
  2. +24 −0 spec/std/json/mapping_spec.cr
  3. +7 −0 spec/std/yaml/mapping_spec.cr
  4. +10 −0 src/class.cr
  5. +1 −1 src/json/mapping.cr
  6. +9 −0 src/union.cr
  7. +6 −2 src/yaml/from_yaml.cr
  8. +2 −2 src/yaml/mapping.cr
7 changes: 7 additions & 0 deletions spec/std/class_spec.cr
Original file line number Diff line number Diff line change
@@ -30,4 +30,11 @@ describe Class do
it "clones" do
Int32.clone.should eq(Int32)
end

it "#nilable" do
Int32.nilable?.should be_false
Nil.nilable?.should be_true
(Int32 | String).nilable?.should be_false
Int32?.nilable?.should be_true
end
end
24 changes: 24 additions & 0 deletions spec/std/json/mapping_spec.cr
Original file line number Diff line number Diff line change
@@ -140,6 +140,12 @@ class JSONWithNilableUnion
})
end

class JSONWithNilableUnion2
JSON.mapping({
value: Int32?,
})
end

describe "JSON mapping" do
it "parses person" do
person = JSONPerson.from_json(%({"name": "John", "age": 30}))
@@ -402,5 +408,23 @@ describe "JSON mapping" do
obj = JSONWithNilableUnion.from_json(%({"value": null}))
obj.value.should be_nil
obj.to_json.should eq(%({}))

obj = JSONWithNilableUnion.from_json(%({}))
obj.value.should be_nil
obj.to_json.should eq(%({}))
end

it "parses nilable union2" do
obj = JSONWithNilableUnion2.from_json(%({"value": 1}))
obj.value.should eq(1)
obj.to_json.should eq(%({"value":1}))

obj = JSONWithNilableUnion2.from_json(%({"value": null}))
obj.value.should be_nil
obj.to_json.should eq(%({}))

obj = JSONWithNilableUnion2.from_json(%({}))
obj.value.should be_nil
obj.to_json.should eq(%({}))
end
end
7 changes: 7 additions & 0 deletions spec/std/yaml/mapping_spec.cr
Original file line number Diff line number Diff line change
@@ -48,6 +48,7 @@ class YAMLWithDefaults
f: {type: Int32, nilable: true, default: 1},
g: {type: Int32, nilable: true, default: nil},
h: {type: Array(Int32), default: [1, 2, 3]},
i: String?,
})
end

@@ -214,6 +215,12 @@ describe "YAML mapping" do
json.e.should eq false
json = YAMLWithDefaults.from_yaml(%({"e":true}))
json.e.should eq true

json = YAMLWithDefaults.from_yaml(%({}))
json.i.should be_nil

json = YAMLWithDefaults.from_yaml(%({"i":"bla"}))
json.i.should eq("bla")
end

it "create new array every time" do
10 changes: 10 additions & 0 deletions src/class.cr
Original file line number Diff line number Diff line change
@@ -51,6 +51,16 @@ class Class
typeof(t, u)
end

# Returns `true` if this class is `Nil`.
#
# ```
# Int32.nilable? # => false
# Nil.nilable? # => true
# ```
def nilable?
self == ::Nil
end

def to_s(io)
io << name
end
2 changes: 1 addition & 1 deletion src/json/mapping.cr
Original file line number Diff line number Diff line change
@@ -120,7 +120,7 @@ module JSON

{% for key, value in properties %}
{% unless value[:nilable] || value[:default] != nil %}
if %var{key.id}.is_a?(Nil) && !%found{key.id}
if %var{key.id}.is_a?(Nil) && !%found{key.id} && !Union({{value[:type]}}).nilable?
raise JSON::ParseException.new("missing json attribute: {{(value[:key] || key).id}}", 0, 0)
end
{% end %}
9 changes: 9 additions & 0 deletions src/union.cr
Original file line number Diff line number Diff line change
@@ -17,4 +17,13 @@
# Union(Int32, Int32, Int32) # => Int32
# ```
struct Union
# Returns `true` if this union includes the `Nil` type.
#
# ```
# (Int32 | String).nilable? # => false
# (Int32 | Nil).nilable? # => true
# ```
def self.nilable?
{{ T.any? &.==(::Nil) }}
end
end
8 changes: 6 additions & 2 deletions src/yaml/from_yaml.cr
Original file line number Diff line number Diff line change
@@ -19,8 +19,12 @@ def Array.from_yaml(string : String)
end

def Nil.new(pull : YAML::PullParser)
pull.read_scalar
nil
value = pull.read_scalar
if value.empty?
nil
else
raise YAML::ParseException.new("expected nil, not #{value}", 0, 0)
end
end

def Bool.new(pull : YAML::PullParser)
4 changes: 2 additions & 2 deletions src/yaml/mapping.cr
Original file line number Diff line number Diff line change
@@ -121,7 +121,7 @@ module YAML

{% for key, value in properties %}
{% unless value[:nilable] || value[:default] != nil %}
if %var{key.id}.is_a?(Nil) && !%found{key.id}
if %var{key.id}.is_a?(Nil) && !%found{key.id} && !Union({{value[:type]}}).nilable?
raise YAML::ParseException.new("missing yaml attribute: {{(value[:key] || key).id}}", 0, 0)
end
{% end %}
@@ -137,7 +137,7 @@ module YAML
{% elsif value[:default] != nil %}
@{{key.id}} = %var{key.id}.is_a?(Nil) ? {{value[:default]}} : %var{key.id}
{% else %}
@{{key.id}} = %var{key.id}.not_nil!
@{{key.id}} = %var{key.id}.as({{value[:type]}})
{% end %}
{% end %}
end