Skip to content

Commit

Permalink
Merge pull request #19 from JuliaObjects/setproperr
Browse files Browse the repository at this point in the history
Improve setproperties error message
  • Loading branch information
jw3126 authored Oct 3, 2019
2 parents 0efa52d + 9515d4a commit 23937e9
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 21 deletions.
43 changes: 24 additions & 19 deletions src/ConstructionBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,32 +39,37 @@ struct NamedTupleConstructor{names} end
end
end

function assert_hasfields(T, fnames)
for fname in fnames
if !(fname in fieldnames(T))
msg = "$T has no field $fname"
throw(ArgumentError(msg))
end
end
end

function setproperties(obj; kw...)
setproperties(obj, (;kw...))
end

@generated function setproperties(obj, patch::NamedTuple)
assert_hasfields(obj, fieldnames(patch))
args = map(fieldnames(obj)) do fn
if fn in fieldnames(patch)
:(patch.$fn)
else
:(obj.$fn)
if issubset(fieldnames(patch), fieldnames(obj))
args = map(fieldnames(obj)) do fn
if fn in fieldnames(patch)
:(patch.$fn)
else
:(obj.$fn)
end
end
return Expr(:block,
Expr(:meta, :inline),
Expr(:call,:(constructorof($obj)), args...)
)
else
:(setproperties_unknown_field_error(obj, patch))
end
Expr(:block,
Expr(:meta, :inline),
Expr(:call,:(constructorof($obj)), args...)
)
end

function setproperties_unknown_field_error(obj, patch)
O = typeof(obj)
P = typeof(patch)
msg = """
Failed to assign properties $(fieldnames(P)) to object with fields $(fieldnames(O)).
You may want to overload
ConstructionBase.setproperties(obj::$O, patch::NamedTuple)
"""
throw(ArgumentError(msg))
end


Expand Down
14 changes: 12 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,18 @@ end
@test setproperties(o, (a=2, b=3.0)) === AB(2,3.0)
@test setproperties(o, a=2, b=3.0) === AB(2,3.0)

@test_throws ArgumentError setproperties(o, (a=2, c=3.0))
@test_throws ArgumentError setproperties(o, a=2, c=3.0)
res = @test_throws ArgumentError setproperties(o, (a=2, this_field_does_not_exist=3.0))
msg = sprint(showerror, res.value)
@test occursin("this_field_does_not_exist", msg)
@test occursin("overload", msg)
@test occursin("ConstructionBase.setproperties", msg)

res = @test_throws ArgumentError setproperties(o, a=2, this_field_does_not_exist=3.0)
msg = sprint(showerror, res.value)
@test occursin("this_field_does_not_exist", msg)
@test occursin("overload", msg)
@test occursin("ConstructionBase.setproperties", msg)

@test setproperties(Empty(), NamedTuple()) === Empty()
@test setproperties(Empty()) === Empty()

Expand Down

0 comments on commit 23937e9

Please sign in to comment.