From 00a6103e56040f7d9b50739e69a222d61d0a3b85 Mon Sep 17 00:00:00 2001 From: Marcel Otto Date: Wed, 6 May 2020 16:48:31 +0200 Subject: [PATCH] Interop between RDF.IRI and XSD.AnyURI in terms of cast and equal_value? --- lib/rdf/iri.ex | 21 +++++++++++++-------- lib/rdf/literal/datatype.ex | 4 ++-- lib/rdf/xsd/datatypes/any_uri.ex | 17 +++++++++++++++++ test/unit/equality_test.exs | 17 +++++++++++------ test/unit/xsd/datatypes/any_uri_test.exs | 23 +++++++++++++++++++++++ 5 files changed, 66 insertions(+), 16 deletions(-) diff --git a/lib/rdf/iri.ex b/lib/rdf/iri.ex index 386567c..abeac01 100644 --- a/lib/rdf/iri.ex +++ b/lib/rdf/iri.ex @@ -49,11 +49,11 @@ defmodule RDF.IRI do """ @spec new(coercible) :: t def new(iri) - def new(iri) when is_binary(iri), do: %RDF.IRI{value: iri} + def new(iri) when is_binary(iri), do: %__MODULE__{value: iri} def new(qname) when is_atom(qname) and qname not in [nil, true, false], do: Namespace.resolve_term(qname) def new(%URI{} = uri), do: uri |> URI.to_string |> new - def new(%RDF.IRI{} = iri), do: iri + def new(%__MODULE__{} = iri), do: iri @doc """ Creates a `RDF.IRI`, but checks if the given IRI is valid. @@ -68,7 +68,7 @@ defmodule RDF.IRI do def new!(qname) when is_atom(qname) and qname not in [nil, true, false], do: new(qname) # since terms of a namespace are already validated def new!(%URI{} = uri), do: uri |> valid!() |> new() - def new!(%RDF.IRI{} = iri), do: valid!(iri) + def new!(%__MODULE__{} = iri), do: valid!(iri) @doc """ @@ -136,7 +136,7 @@ defmodule RDF.IRI do def absolute?(iri) def absolute?(value) when is_binary(value), do: not is_nil(scheme(value)) - def absolute?(%RDF.IRI{value: value}), do: absolute?(value) + def absolute?(%__MODULE__{value: value}), do: absolute?(value) def absolute?(%URI{scheme: nil}), do: false def absolute?(%URI{scheme: _}), do: true def absolute?(qname) when is_atom(qname) and qname not in [nil, true, false] do @@ -198,7 +198,7 @@ defmodule RDF.IRI do """ @spec scheme(coercible) :: String.t | nil def scheme(iri) - def scheme(%RDF.IRI{value: value}), do: scheme(value) + def scheme(%__MODULE__{value: value}), do: scheme(value) def scheme(%URI{scheme: scheme}), do: scheme def scheme(qname) when is_atom(qname), do: Namespace.resolve_term(qname) |> scheme() def scheme(iri) when is_binary(iri) do @@ -216,7 +216,7 @@ defmodule RDF.IRI do def parse(iri) when is_binary(iri), do: URI.parse(iri) def parse(qname) when is_atom(qname) and qname not in [nil, true, false], do: Namespace.resolve_term(qname) |> parse() - def parse(%RDF.IRI{value: value}), do: URI.parse(value) + def parse(%__MODULE__{value: value}), do: URI.parse(value) def parse(%URI{} = uri), do: uri @@ -230,9 +230,14 @@ defmodule RDF.IRI do @spec equal_value?(t | RDF.Literal.t, t | RDF.Literal.t) :: boolean | nil def equal_value?(left, right) - def equal_value?(%RDF.IRI{value: left}, %RDF.IRI{value: right}), + def equal_value?(%__MODULE__{value: left}, %__MODULE__{value: right}), do: left == right + def equal_value?(%__MODULE__{} = left, %RDF.Literal{} = right), + do: RDF.Literal.equal_value?(right, left) + + def equal_value?(%__MODULE__{value: left}, %URI{} = right), + do: left == URI.to_string(right) def equal_value?(_, _), do: nil @@ -256,7 +261,7 @@ defmodule RDF.IRI do @spec to_string(t | module) :: String.t def to_string(iri) - def to_string(%RDF.IRI{value: value}), + def to_string(%__MODULE__{value: value}), do: value def to_string(qname) when is_atom(qname), diff --git a/lib/rdf/literal/datatype.ex b/lib/rdf/literal/datatype.ex index c5aff85..da365e9 100644 --- a/lib/rdf/literal/datatype.ex +++ b/lib/rdf/literal/datatype.ex @@ -214,8 +214,8 @@ defmodule RDF.Literal.Datatype do def equal_value?(_, nil), do: nil def equal_value?(left, right) do cond do - not RDF.literal?(right) -> equal_value?(left, Literal.coerce(right)) - not RDF.literal?(left) -> equal_value?(Literal.coerce(left), right) + not RDF.literal?(right) and not RDF.term?(right) -> equal_value?(left, Literal.coerce(right)) + not RDF.literal?(left) and not RDF.term?(left) -> equal_value?(Literal.coerce(left), right) true -> do_equal_value?(left, right) end end diff --git a/lib/rdf/xsd/datatypes/any_uri.ex b/lib/rdf/xsd/datatypes/any_uri.ex index 3a64680..d1e15ff 100644 --- a/lib/rdf/xsd/datatypes/any_uri.ex +++ b/lib/rdf/xsd/datatypes/any_uri.ex @@ -7,6 +7,8 @@ defmodule RDF.XSD.AnyURI do @type valid_value :: URI.t() + alias RDF.IRI + use RDF.XSD.Datatype.Primitive, name: "anyURI", id: RDF.Utils.Bootstrapping.xsd_iri("anyURI") @@ -19,4 +21,19 @@ defmodule RDF.XSD.AnyURI do @spec elixir_mapping(any, Keyword.t()) :: value def elixir_mapping(%URI{} = uri, _), do: uri def elixir_mapping(_, _), do: @invalid_value + + @impl RDF.Literal.Datatype + def do_cast(%IRI{} = iri), do: new(iri.value) + def do_cast(value), do: super(value) + + @impl RDF.Literal.Datatype + def do_equal_value?(literal1, literal2) + + def do_equal_value?(%IRI{} = iri, %__MODULE__{} = any_uri), + do: do_equal_value?(any_uri, iri) + + def do_equal_value?(%__MODULE__{} = any_uri, %IRI{value: iri}), + do: lexical(any_uri) == iri + + def do_equal_value?(literal1, literal2), do: super(literal1, literal2) end diff --git a/test/unit/equality_test.exs b/test/unit/equality_test.exs index e3b1eb9..8b7c1f0 100644 --- a/test/unit/equality_test.exs +++ b/test/unit/equality_test.exs @@ -3,28 +3,33 @@ defmodule RDF.EqualityTest do alias RDF.XSD - describe "RDF.IRI" do + describe "RDF.IRI and XSD.AnyURI" do @term_equal_iris [ {RDF.iri("http://example.com/"), RDF.iri("http://example.com/")}, + {XSD.anyURI("http://example.com/"), XSD.anyURI("http://example.com/")}, ] @value_equal_iris [ {RDF.iri("http://example.com/"), XSD.anyURI("http://example.com/")}, - {XSD.anyURI("http://example.com/"), XSD.anyURI("http://example.com/")}, ] @unequal_iris [ {RDF.iri("http://example.com/foo"), RDF.iri("http://example.com/bar")}, {RDF.iri("http://example.com/foo"), XSD.anyURI("http://example.com/bar")}, ] - @equal_iris_by_coercion [] - @unequal_iris_by_coercion [] + @equal_iris_by_coercion [ + {RDF.iri("http://example.com/"), URI.parse("http://example.com/")}, + {XSD.anyURI("http://example.com/"), URI.parse("http://example.com/")}, + ] + @unequal_iris_by_coercion [ + {RDF.iri("http://example.com/foo"), URI.parse("http://example.com/bar")}, + {XSD.anyURI("http://example.com/foo"), URI.parse("http://example.com/bar")}, + ] @incomparable_iris [ {RDF.iri("http://example.com/"), XSD.string("http://example.com/")}, + {XSD.anyURI("http://example.com/"), XSD.string("http://example.com/")}, ] test "term equality", do: assert_term_equal(@term_equal_iris) - @tag skip: "TODO: finish value equality of XSD.AnyURI" test "value equality", do: assert_value_equal(@value_equal_iris) - @tag skip: "TODO: finish value equality of XSD.AnyURI" test "inequality", do: assert_unequal(@unequal_iris) test "coerced value equality", do: assert_coerced_equal(@equal_iris_by_coercion) test "coerced value inequality", do: assert_coerced_unequal(@unequal_iris_by_coercion) diff --git a/test/unit/xsd/datatypes/any_uri_test.exs b/test/unit/xsd/datatypes/any_uri_test.exs index 2500138..ad821c7 100644 --- a/test/unit/xsd/datatypes/any_uri_test.exs +++ b/test/unit/xsd/datatypes/any_uri_test.exs @@ -11,4 +11,27 @@ defmodule RDF.XSD.AnyURITest do {URI.parse("http://example.com/foo"), nil, "http://example.com/foo"} }, invalid: [42, 3.14, true, false] + + + describe "cast/1" do + test "casting an anyURI returns the input as it is" do + assert XSD.anyURI("http://example.com/") |> XSD.AnyURI.cast() == + XSD.anyURI("http://example.com/") + end + + test "casting an RDF.IRI" do + assert RDF.iri("http://example.com/") |> XSD.AnyURI.cast() == + XSD.anyURI("http://example.com/") + end + + test "with coercible value" do + assert URI.parse("http://example.com/") |> XSD.AnyURI.cast() == + XSD.anyURI("http://example.com/") + end + + test "with non-coercible value" do + assert XSD.string("http://example.com/") |> XSD.AnyURI.cast() == nil + assert XSD.AnyURI.cast(make_ref()) == nil + end + end end