From f4877bbc6534aa147ffe300c403af9a30d131fa1 Mon Sep 17 00:00:00 2001 From: Marcel Otto Date: Sun, 16 Sep 2018 22:21:53 +0200 Subject: [PATCH] Fix some issues with RDF.Term coercion in various contexts --- lib/rdf/datatype.ex | 2 +- lib/rdf/datatypes/numeric.ex | 32 ++++++++++++++++--------- lib/rdf/literal.ex | 2 +- lib/rdf/term.ex | 36 ++++++++++++++++++++++++++++ test/unit/datatypes/numeric_test.exs | 16 +++++++++++-- 5 files changed, 73 insertions(+), 15 deletions(-) diff --git a/lib/rdf/datatype.ex b/lib/rdf/datatype.ex index ec4a916..f3b844c 100644 --- a/lib/rdf/datatype.ex +++ b/lib/rdf/datatype.ex @@ -216,7 +216,7 @@ defmodule RDF.Datatype do end def equal_value?(%RDF.Literal{} = left, right) when not is_nil(right) do - unless RDF.term?(right) do + unless RDF.Term.term?(right) do equal_value?(left, RDF.Term.coerce(right)) end end diff --git a/lib/rdf/datatypes/numeric.ex b/lib/rdf/datatypes/numeric.ex index 8de8333..ac47205 100644 --- a/lib/rdf/datatypes/numeric.ex +++ b/lib/rdf/datatypes/numeric.ex @@ -79,7 +79,7 @@ defmodule RDF.Numeric do end def equal_value?(%RDF.Literal{} = left, right) when not is_nil(right) do - unless RDF.term?(right) do + unless RDF.Term.term?(right) do equal_value?(left, RDF.Term.coerce(right)) end end @@ -269,7 +269,7 @@ defmodule RDF.Numeric do end def abs(value) do - unless RDF.term?(value) do + if not is_nil(value) and not RDF.Term.term?(value) do value |> RDF.Term.coerce() |> abs() @@ -331,7 +331,7 @@ defmodule RDF.Numeric do end def round(value, precision) do - unless RDF.term?(value) do + if not is_nil(value) and not RDF.Term.term?(value) do value |> RDF.Term.coerce() |> round(precision) @@ -383,7 +383,7 @@ defmodule RDF.Numeric do end def ceil(value) do - unless RDF.term?(value) do + if not is_nil(value) and not RDF.Term.term?(value) do value |> RDF.Term.coerce() |> ceil() @@ -430,7 +430,7 @@ defmodule RDF.Numeric do end def floor(value) do - unless RDF.term?(value) do + if not is_nil(value) and not RDF.Term.term?(value) do value |> RDF.Term.coerce() |> floor() @@ -450,14 +450,24 @@ defmodule RDF.Numeric do end end - defp arithmetic_operation(op, %Literal{} = arg1, arg2, fun), - do: arithmetic_operation(op, arg1, RDF.Term.coerce(arg2), fun) + defp arithmetic_operation(op, %Literal{} = arg1, arg2, fun) do + if not is_nil(arg2) and not RDF.Term.term?(arg2) do + arithmetic_operation(op, arg1, RDF.Term.coerce(arg2), fun) + end + end - defp arithmetic_operation(op, arg1, %Literal{} = arg2, fun), - do: arithmetic_operation(op, RDF.Term.coerce(arg1), arg2, fun) + defp arithmetic_operation(op, arg1, %Literal{} = arg2, fun) do + if not is_nil(arg1) and not RDF.Term.term?(arg1) do + arithmetic_operation(op, RDF.Term.coerce(arg1), arg2, fun) + end + end - defp arithmetic_operation(op, arg1, arg2, fun), - do: arithmetic_operation(op, RDF.Term.coerce(arg1), RDF.Term.coerce(arg2), fun) + defp arithmetic_operation(op, arg1, arg2, fun) do + if not is_nil(arg1) and not RDF.Term.term?(arg1) and + not is_nil(arg2) and not RDF.Term.term?(arg2) do + arithmetic_operation(op, RDF.Term.coerce(arg1), RDF.Term.coerce(arg2), fun) + end + end defp type_conversion(%Literal{datatype: datatype} = arg1, diff --git a/lib/rdf/literal.ex b/lib/rdf/literal.ex index f5220bf..d6a92e0 100644 --- a/lib/rdf/literal.ex +++ b/lib/rdf/literal.ex @@ -251,7 +251,7 @@ defmodule RDF.Literal do do: RDF.IRI.equal_value?(left, right) def equal_value?(%RDF.Literal{} = left, right) when not is_nil(right) do - unless RDF.term?(right) do + unless RDF.Term.term?(right) do equal_value?(left, RDF.Term.coerce(right)) end end diff --git a/lib/rdf/term.ex b/lib/rdf/term.ex index 348b593..dbe63a3 100644 --- a/lib/rdf/term.ex +++ b/lib/rdf/term.ex @@ -15,6 +15,27 @@ defprotocol RDF.Term do @type t :: RDF.IRI.t | RDF.BlankNode.t | RDF.Literal.t + @doc """ + Checks if the given value is a RDF term. + + Note: As opposed to `RDF.term?` this function returns false on atoms and does + not try resolves those to IRIs. + + ## Examples + + iex> RDF.Term.term?(RDF.iri("http://example.com/resource")) + true + iex> RDF.Term.term?(EX.Resource) + false + iex> RDF.Term.term?(RDF.bnode) + true + iex> RDF.Term.term?(RDF.integer(42)) + true + iex> RDF.Term.term?(42) + false + """ + def term?(value) + @doc """ Tests for term equality. @@ -51,24 +72,28 @@ defimpl RDF.Term, for: RDF.IRI do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.IRI.equal_value?(term1, term2) def coerce(term), do: term + def term?(_), do: true end defimpl RDF.Term, for: RDF.BlankNode do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.BlankNode.equal_value?(term1, term2) def coerce(term), do: term + def term?(_), do: true end defimpl RDF.Term, for: Reference do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) def coerce(term), do: RDF.BlankNode.new(term) + def term?(_), do: false end defimpl RDF.Term, for: RDF.Literal do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Literal.equal_value?(term1, term2) def coerce(term), do: term + def term?(_), do: true end defimpl RDF.Term, for: Atom do @@ -80,58 +105,69 @@ defimpl RDF.Term, for: Atom do def coerce(true), do: RDF.true def coerce(false), do: RDF.false def coerce(_), do: nil + + def term?(_), do: false end defimpl RDF.Term, for: BitString do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) def coerce(term), do: RDF.String.new(term) + def term?(_), do: false end defimpl RDF.Term, for: Integer do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) def coerce(term), do: RDF.Integer.new(term) + def term?(_), do: false end defimpl RDF.Term, for: Float do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) def coerce(term), do: RDF.Double.new(term) + def term?(_), do: false end defimpl RDF.Term, for: Decimal do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) def coerce(term), do: RDF.Decimal.new(term) + def term?(_), do: false end defimpl RDF.Term, for: DateTime do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) def coerce(term), do: RDF.DateTime.new(term) + def term?(_), do: false end defimpl RDF.Term, for: NaiveDateTime do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) def coerce(term), do: RDF.DateTime.new(term) + def term?(_), do: false end defimpl RDF.Term, for: Date do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) def coerce(term), do: RDF.Date.new(term) + def term?(_), do: false end defimpl RDF.Term, for: Time do def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) def coerce(term), do: RDF.Time.new(term) + def term?(_), do: false end defimpl RDF.Term, for: Any do def equal?(term1, term2), do: term1 == term2 def equal_value?(_, _), do: nil def coerce(_), do: nil + def term?(_), do: false end diff --git a/test/unit/datatypes/numeric_test.exs b/test/unit/datatypes/numeric_test.exs index cd649d8..18c7aed 100644 --- a/test/unit/datatypes/numeric_test.exs +++ b/test/unit/datatypes/numeric_test.exs @@ -104,6 +104,10 @@ defmodule RDF.NumericTest do assert Numeric.add(3.14, 42) == RDF.double(45.14) assert RDF.decimal(3.14) |> Numeric.add(42) == RDF.decimal(45.14) assert Numeric.add(42, RDF.decimal(3.14)) == RDF.decimal(45.14) + assert Numeric.add(42, ~B"foo") == nil + assert Numeric.add(42, :foo) == nil + assert Numeric.add(:foo, 42) == nil + assert Numeric.add(:foo, :bar) == nil end end @@ -337,8 +341,11 @@ defmodule RDF.NumericTest do assert RDF.decimal(4) |> Numeric.divide(2) == RDF.decimal(2.0) assert Numeric.divide(4, RDF.decimal(2.0)) == RDF.decimal(2.0) assert Numeric.divide("foo", "bar") == nil - assert Numeric.divide(4, "bar") == nil - assert Numeric.divide("foo", 2) == nil + assert Numeric.divide(4, "bar") == nil + assert Numeric.divide("foo", 2) == nil + assert Numeric.divide(42, :bar) == nil + assert Numeric.divide(:foo, 42) == nil + assert Numeric.divide(:foo, :bar) == nil end end @@ -383,6 +390,7 @@ defmodule RDF.NumericTest do assert Numeric.abs(-3.14) == RDF.double(3.14) assert Numeric.abs(D.new(-3.14)) == RDF.decimal(3.14) assert Numeric.abs("foo") == nil + assert Numeric.abs(:foo) == nil end end @@ -419,6 +427,7 @@ defmodule RDF.NumericTest do assert Numeric.round(-3.14) == RDF.double(-3.0) assert Numeric.round(D.new(3.14)) == RDF.decimal("3") assert Numeric.round("foo") == nil + assert Numeric.round(:foo) == nil end end @@ -459,6 +468,7 @@ defmodule RDF.NumericTest do assert Numeric.round(-3.14, 1) == RDF.double(-3.1) assert Numeric.round(D.new(3.14), 1) == RDF.decimal("3.1") assert Numeric.round("foo", 1) == nil + assert Numeric.round(:foo, 1) == nil end end @@ -493,6 +503,7 @@ defmodule RDF.NumericTest do assert Numeric.ceil(-3.14) == RDF.double("-3") assert Numeric.ceil(D.new(3.14)) == RDF.decimal("4") assert Numeric.ceil("foo") == nil + assert Numeric.ceil(:foo) == nil end end @@ -527,6 +538,7 @@ defmodule RDF.NumericTest do assert Numeric.floor(-3.14) == RDF.double("-4") assert Numeric.floor(D.new(3.14)) == RDF.decimal("3") assert Numeric.floor("foo") == nil + assert Numeric.floor(:foo) == nil end end