Add proper handling of vocabulary terms at various places
- in the coerce and value functions of the RDF.Term protocol for atoms - allow them as XSD.AnyURI values - RDF.Literal.coerce produces XSD.AnyURI literals from them - allow them in equal_value comparisons with RDF.IRIs and XSD.AnyURIs
This commit is contained in:
parent
76b6f69613
commit
47a19c0a67
8 changed files with 87 additions and 5 deletions
|
@ -238,6 +238,16 @@ defmodule RDF.IRI do
|
||||||
def equal_value?(%__MODULE__{value: left}, %URI{} = right),
|
def equal_value?(%__MODULE__{value: left}, %URI{} = right),
|
||||||
do: left == URI.to_string(right)
|
do: left == URI.to_string(right)
|
||||||
|
|
||||||
|
def equal_value?(left, %__MODULE__{} = right) when maybe_ns_term(left),
|
||||||
|
do: equal_value?(right, left)
|
||||||
|
|
||||||
|
def equal_value?(%__MODULE__{} = left, right) when maybe_ns_term(right) do
|
||||||
|
case Namespace.resolve_term(right) do
|
||||||
|
{:ok, iri} -> equal_value?(left, iri)
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def equal_value?(_, _),
|
def equal_value?(_, _),
|
||||||
do: nil
|
do: nil
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ defmodule RDF.Literal do
|
||||||
alias RDF.{IRI, LangString}
|
alias RDF.{IRI, LangString}
|
||||||
alias RDF.Literal.{Generic, Datatype}
|
alias RDF.Literal.{Generic, Datatype}
|
||||||
|
|
||||||
|
import RDF.Guards
|
||||||
|
|
||||||
@type t :: %__MODULE__{:literal => Datatype.literal()}
|
@type t :: %__MODULE__{:literal => Datatype.literal()}
|
||||||
|
|
||||||
@rdf_lang_string RDF.Utils.Bootstrapping.rdf_iri("langString")
|
@rdf_lang_string RDF.Utils.Bootstrapping.rdf_iri("langString")
|
||||||
|
@ -103,6 +105,13 @@ defmodule RDF.Literal do
|
||||||
def coerce(%NaiveDateTime{} = value), do: RDF.XSD.DateTime.new(value)
|
def coerce(%NaiveDateTime{} = value), do: RDF.XSD.DateTime.new(value)
|
||||||
def coerce(%URI{} = value), do: RDF.XSD.AnyURI.new(value)
|
def coerce(%URI{} = value), do: RDF.XSD.AnyURI.new(value)
|
||||||
|
|
||||||
|
def coerce(value) when maybe_ns_term(value) do
|
||||||
|
case RDF.Namespace.resolve_term(value) do
|
||||||
|
{:ok, iri} -> iri |> IRI.parse() |> coerce()
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Although the following catch-all-clause for all structs could handle the builtin datatypes
|
# Although the following catch-all-clause for all structs could handle the builtin datatypes
|
||||||
# we're generating dedicated clauses for them here, as they are approx. 15% faster
|
# we're generating dedicated clauses for them here, as they are approx. 15% faster
|
||||||
Enum.each(Datatype.Registry.builtin_datatypes(), fn datatype ->
|
Enum.each(Datatype.Registry.builtin_datatypes(), fn datatype ->
|
||||||
|
|
|
@ -134,11 +134,18 @@ defimpl RDF.Term, for: Atom do
|
||||||
|
|
||||||
def coerce(true), do: RDF.XSD.true
|
def coerce(true), do: RDF.XSD.true
|
||||||
def coerce(false), do: RDF.XSD.false
|
def coerce(false), do: RDF.XSD.false
|
||||||
def coerce(_), do: nil
|
def coerce(nil), do: nil
|
||||||
|
def coerce(term) do
|
||||||
|
case RDF.Namespace.resolve_term(term) do
|
||||||
|
{:ok, iri} -> iri
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def value(true), do: true
|
def value(true), do: true
|
||||||
def value(false), do: false
|
def value(false), do: false
|
||||||
def value(_), do: nil
|
def value(nil), do: nil
|
||||||
|
def value(term), do: RDF.Term.value(coerce(term))
|
||||||
|
|
||||||
def term?(_), do: false
|
def term?(_), do: false
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,6 +9,8 @@ defmodule RDF.XSD.AnyURI do
|
||||||
|
|
||||||
alias RDF.IRI
|
alias RDF.IRI
|
||||||
|
|
||||||
|
import RDF.Guards
|
||||||
|
|
||||||
use RDF.XSD.Datatype.Primitive,
|
use RDF.XSD.Datatype.Primitive,
|
||||||
name: "anyURI",
|
name: "anyURI",
|
||||||
id: RDF.Utils.Bootstrapping.xsd_iri("anyURI")
|
id: RDF.Utils.Bootstrapping.xsd_iri("anyURI")
|
||||||
|
@ -20,6 +22,14 @@ defmodule RDF.XSD.AnyURI do
|
||||||
@impl RDF.XSD.Datatype
|
@impl RDF.XSD.Datatype
|
||||||
@spec elixir_mapping(any, Keyword.t()) :: value
|
@spec elixir_mapping(any, Keyword.t()) :: value
|
||||||
def elixir_mapping(%URI{} = uri, _), do: uri
|
def elixir_mapping(%URI{} = uri, _), do: uri
|
||||||
|
|
||||||
|
def elixir_mapping(value, _) when maybe_ns_term(value) do
|
||||||
|
case RDF.Namespace.resolve_term(value) do
|
||||||
|
{:ok, iri} -> IRI.parse(iri)
|
||||||
|
_ -> @invalid_value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def elixir_mapping(_, _), do: @invalid_value
|
def elixir_mapping(_, _), do: @invalid_value
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
|
@ -35,5 +45,15 @@ defmodule RDF.XSD.AnyURI do
|
||||||
def do_equal_value?(%__MODULE__{} = any_uri, %IRI{value: iri}),
|
def do_equal_value?(%__MODULE__{} = any_uri, %IRI{value: iri}),
|
||||||
do: lexical(any_uri) == iri
|
do: lexical(any_uri) == iri
|
||||||
|
|
||||||
|
def do_equal_value?(left, %__MODULE__{} = right) when maybe_ns_term(left),
|
||||||
|
do: equal_value?(right, left)
|
||||||
|
|
||||||
|
def do_equal_value?(%__MODULE__{} = left, right) when maybe_ns_term(right) do
|
||||||
|
case RDF.Namespace.resolve_term(right) do
|
||||||
|
{:ok, iri} -> equal_value?(left, iri)
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def do_equal_value?(literal1, literal2), do: super(literal1, literal2)
|
def do_equal_value?(literal1, literal2), do: super(literal1, literal2)
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,10 +18,14 @@ defmodule RDF.EqualityTest do
|
||||||
@equal_iris_by_coercion [
|
@equal_iris_by_coercion [
|
||||||
{RDF.iri("http://example.com/"), URI.parse("http://example.com/")},
|
{RDF.iri("http://example.com/"), URI.parse("http://example.com/")},
|
||||||
{XSD.anyURI("http://example.com/"), URI.parse("http://example.com/")},
|
{XSD.anyURI("http://example.com/"), URI.parse("http://example.com/")},
|
||||||
|
{RDF.iri("http://example.com/Foo"), EX.Foo},
|
||||||
|
{XSD.anyURI("http://example.com/Foo"), EX.Foo},
|
||||||
]
|
]
|
||||||
@unequal_iris_by_coercion [
|
@unequal_iris_by_coercion [
|
||||||
{RDF.iri("http://example.com/foo"), URI.parse("http://example.com/bar")},
|
{RDF.iri("http://example.com/foo"), URI.parse("http://example.com/bar")},
|
||||||
{XSD.anyURI("http://example.com/foo"), URI.parse("http://example.com/bar")},
|
{XSD.anyURI("http://example.com/foo"), URI.parse("http://example.com/bar")},
|
||||||
|
{RDF.iri("http://example.com/Bar"), EX.Foo},
|
||||||
|
{XSD.anyURI("http://example.com/Bar"), EX.Foo},
|
||||||
]
|
]
|
||||||
@incomparable_iris [
|
@incomparable_iris [
|
||||||
{RDF.iri("http://example.com/"), XSD.string("http://example.com/")},
|
{RDF.iri("http://example.com/"), XSD.string("http://example.com/")},
|
||||||
|
|
|
@ -168,6 +168,15 @@ defmodule RDF.LiteralTest do
|
||||||
XSD.any_uri("http://example.com")
|
XSD.any_uri("http://example.com")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "with a resolvable vocabulary namespace term atom" do
|
||||||
|
assert Literal.coerce(EX.Foo) == EX.Foo |> RDF.iri() |> IRI.parse() |> XSD.any_uri()
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with a non-resolvable atom" do
|
||||||
|
refute Literal.coerce(Foo)
|
||||||
|
refute Literal.coerce(:foo)
|
||||||
|
end
|
||||||
|
|
||||||
test "with RDF.Literals" do
|
test "with RDF.Literals" do
|
||||||
assert XSD.integer(42) |> Literal.coerce() == XSD.integer(42)
|
assert XSD.integer(42) |> Literal.coerce() == XSD.integer(42)
|
||||||
end
|
end
|
||||||
|
@ -177,7 +186,8 @@ defmodule RDF.LiteralTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "with inconvertible values" do
|
test "with inconvertible values" do
|
||||||
assert self() |> Literal.coerce() == nil
|
refute Literal.coerce(nil)
|
||||||
|
refute Literal.coerce(self())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,16 @@ defmodule RDF.TermTest do
|
||||||
assert RDF.Term.coerce(~L"foo") == ~L"foo"
|
assert RDF.Term.coerce(~L"foo") == ~L"foo"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "with a resolvable vocabulary namespace term atom" do
|
||||||
|
assert RDF.Term.coerce(EX.Foo) == RDF.iri(EX.Foo)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with a non-resolvable atom" do
|
||||||
|
refute RDF.Term.coerce(nil)
|
||||||
|
refute RDF.Term.coerce(Foo)
|
||||||
|
refute RDF.Term.coerce(:foo)
|
||||||
|
end
|
||||||
|
|
||||||
test "with boolean" do
|
test "with boolean" do
|
||||||
assert RDF.Term.coerce(true) == XSD.true
|
assert RDF.Term.coerce(true) == XSD.true
|
||||||
assert RDF.Term.coerce(false) == XSD.false
|
assert RDF.Term.coerce(false) == XSD.false
|
||||||
|
@ -83,6 +93,16 @@ defmodule RDF.TermTest do
|
||||||
assert XSD.integer("foo") |> RDF.Term.value() == "foo"
|
assert XSD.integer("foo") |> RDF.Term.value() == "foo"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "with a resolvable vocabulary namespace term atom" do
|
||||||
|
assert RDF.Term.value(EX.Foo) == EX.Foo |> RDF.iri() |> to_string()
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with a non-resolvable atom" do
|
||||||
|
refute RDF.Term.value(nil)
|
||||||
|
refute RDF.Term.value(Foo)
|
||||||
|
refute RDF.Term.value(:foo)
|
||||||
|
end
|
||||||
|
|
||||||
test "with boolean" do
|
test "with boolean" do
|
||||||
assert RDF.Term.value(true) == true
|
assert RDF.Term.value(true) == true
|
||||||
assert RDF.Term.value(false) == false
|
assert RDF.Term.value(false) == false
|
||||||
|
|
|
@ -8,9 +8,11 @@ defmodule RDF.XSD.AnyURITest do
|
||||||
"http://example.com/foo" =>
|
"http://example.com/foo" =>
|
||||||
{URI.parse("http://example.com/foo"), nil, "http://example.com/foo"},
|
{URI.parse("http://example.com/foo"), nil, "http://example.com/foo"},
|
||||||
URI.parse("http://example.com/foo") =>
|
URI.parse("http://example.com/foo") =>
|
||||||
{URI.parse("http://example.com/foo"), nil, "http://example.com/foo"}
|
{URI.parse("http://example.com/foo"), nil, "http://example.com/foo"},
|
||||||
|
RDF.List =>
|
||||||
|
{URI.parse("http://www.w3.org/1999/02/22-rdf-syntax-ns#List"), nil, "http://www.w3.org/1999/02/22-rdf-syntax-ns#List"},
|
||||||
},
|
},
|
||||||
invalid: [42, 3.14, true, false]
|
invalid: [42, 3.14, Foo, :foo, true, false]
|
||||||
|
|
||||||
|
|
||||||
describe "cast/1" do
|
describe "cast/1" do
|
||||||
|
|
Loading…
Reference in a new issue