Add RDF.Guards.maybe_ns_term/1

This commit is contained in:
Marcel Otto 2020-05-06 18:04:19 +02:00
parent 00a6103e56
commit 24051c6153
8 changed files with 66 additions and 32 deletions

View file

@ -1,4 +1,5 @@
import RDF.Sigils
import RDF.Guards
alias RDF.NS
alias RDF.NS.{RDFS, OWL, SKOS}

View file

@ -41,6 +41,7 @@ defmodule RDF do
alias RDF.{IRI, Namespace, Literal, BlankNode, Triple, Quad,
Description, Graph, Dataset, PrefixMap}
import RDF.Guards
import RDF.Utils.Bootstrapping
defdelegate default_base_iri(), to: RDF.IRI, as: :default_base
@ -146,8 +147,8 @@ defmodule RDF do
def resource?(value)
def resource?(%IRI{}), do: true
def resource?(%BlankNode{}), do: true
def resource?(atom) when is_atom(atom) and atom not in ~w[true false nil]a do
resource?(Namespace.resolve_term(atom))
def resource?(qname) when maybe_ns_term(qname) do
resource?(Namespace.resolve_term(qname))
rescue
RDF.Namespace.UndefinedTermError -> false
end

4
lib/rdf/guards.ex Normal file
View file

@ -0,0 +1,4 @@
defmodule RDF.Guards do
defguard maybe_ns_term(term)
when is_atom(term) and term not in [nil, true, false]
end

View file

@ -17,6 +17,7 @@ defmodule RDF.IRI do
"""
alias RDF.Namespace
import RDF.Guards
@type t :: %__MODULE__{
value: String.t
@ -49,11 +50,10 @@ defmodule RDF.IRI do
"""
@spec new(coercible) :: t
def new(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(%__MODULE__{} = iri), do: iri
def new(iri) when is_binary(iri), do: %__MODULE__{value: iri}
def new(qname) when maybe_ns_term(qname), do: Namespace.resolve_term(qname)
def new(%URI{} = uri), do: uri |> URI.to_string |> new
def new(%__MODULE__{} = iri), do: iri
@doc """
Creates a `RDF.IRI`, but checks if the given IRI is valid.
@ -64,11 +64,10 @@ defmodule RDF.IRI do
"""
@spec new!(coercible) :: t
def new!(iri)
def new!(iri) when is_binary(iri), do: iri |> valid!() |> new()
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!(%__MODULE__{} = iri), do: valid!(iri)
def new!(iri) when is_binary(iri), do: iri |> valid!() |> new()
def new!(qname) when maybe_ns_term(qname), do: new(qname) # since terms of a namespace are already validated
def new!(%URI{} = uri), do: uri |> valid!() |> new()
def new!(%__MODULE__{} = iri), do: valid!(iri)
@doc """
@ -80,7 +79,7 @@ defmodule RDF.IRI do
@spec coerce_base(coercible) :: t
def coerce_base(base_iri)
def coerce_base(module) when is_atom(module) do
def coerce_base(module) when maybe_ns_term(module) do
if RDF.Vocabulary.Namespace.vocabulary_namespace?(module) do
apply(module, :__base_iri__, [])
|> new()
@ -139,7 +138,7 @@ defmodule RDF.IRI do
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
def absolute?(qname) when maybe_ns_term(qname) do
qname |> Namespace.resolve_term |> absolute?()
rescue
_ -> false
@ -198,9 +197,9 @@ defmodule RDF.IRI do
"""
@spec scheme(coercible) :: String.t | nil
def scheme(iri)
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(%__MODULE__{value: value}), do: scheme(value)
def scheme(%URI{scheme: scheme}), do: scheme
def scheme(qname) when maybe_ns_term(qname), do: Namespace.resolve_term(qname) |> scheme()
def scheme(iri) when is_binary(iri) do
with [_, scheme] <- Regex.run(@scheme_regex, iri) do
scheme
@ -213,11 +212,10 @@ defmodule RDF.IRI do
"""
@spec parse(coercible) :: URI.t
def parse(iri)
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(%__MODULE__{value: value}), do: URI.parse(value)
def parse(%URI{} = uri), do: uri
def parse(iri) when is_binary(iri), do: URI.parse(iri)
def parse(qname) when maybe_ns_term(qname), do: Namespace.resolve_term(qname) |> parse()
def parse(%__MODULE__{value: value}), do: URI.parse(value)
def parse(%URI{} = uri), do: uri
@doc """
@ -264,7 +262,7 @@ defmodule RDF.IRI do
def to_string(%__MODULE__{value: value}),
do: value
def to_string(qname) when is_atom(qname),
def to_string(qname) when maybe_ns_term(qname),
do: qname |> new() |> __MODULE__.to_string()
defimpl String.Chars do

View file

@ -9,6 +9,8 @@ defmodule RDF.List do
alias RDF.{BlankNode, Description, Graph, IRI}
import RDF.Guards
@type t :: %__MODULE__{
head: IRI.t,
graph: Graph.t
@ -34,7 +36,7 @@ defmodule RDF.List do
@spec new(IRI.coercible, Graph.t) :: t
def new(head, graph)
def new(head, graph) when is_atom(head) and head not in ~w[true false nil]a,
def new(head, graph) when maybe_ns_term(head),
do: new(RDF.iri(head), graph)
def new(head, graph) do
@ -85,7 +87,7 @@ defmodule RDF.List do
{RDF.nil, graph}
end
defp do_from(list, head, graph, opts) when is_atom(head) do
defp do_from(list, head, graph, opts) when maybe_ns_term(head) do
do_from(list, RDF.iri!(head), graph, opts)
end
@ -186,8 +188,7 @@ defmodule RDF.List do
def node?(%IRI{} = list_node, graph),
do: do_node?(list_node, graph)
def node?(list_node, graph)
when is_atom(list_node) and list_node not in ~w[true false nil]a,
def node?(list_node, graph) when maybe_ns_term(list_node),
do: do_node?(RDF.iri(list_node), graph)
def node?(_, _), do: false

View file

@ -9,6 +9,8 @@ defmodule RDF.Namespace do
alias RDF.IRI
import RDF.Guards
@doc """
Resolves a term to a `RDF.IRI`.
"""
@ -32,7 +34,7 @@ defmodule RDF.Namespace do
def resolve_term(%IRI{} = iri), do: iri
def resolve_term(namespaced_term) when is_atom(namespaced_term) do
def resolve_term(namespaced_term) when maybe_ns_term(namespaced_term) do
namespaced_term
|> to_string()
|> do_resolve_term()

View file

@ -6,6 +6,7 @@ defmodule RDF.Statement do
"""
alias RDF.{BlankNode, IRI, Literal, Quad, Term, Triple}
import RDF.Guards
@type subject :: IRI.t | BlankNode.t
@type predicate :: IRI.t | BlankNode.t
@ -47,7 +48,7 @@ defmodule RDF.Statement do
def coerce_subject(iri = %IRI{}), do: iri
def coerce_subject(bnode = %BlankNode{}), do: bnode
def coerce_subject("_:" <> identifier), do: RDF.bnode(identifier)
def coerce_subject(iri) when is_atom(iri) or is_binary(iri), do: RDF.iri!(iri)
def coerce_subject(iri) when maybe_ns_term(iri) or is_binary(iri), do: RDF.iri!(iri)
def coerce_subject(arg), do: raise RDF.Triple.InvalidSubjectError, subject: arg
@doc false
@ -58,7 +59,7 @@ defmodule RDF.Statement do
# them, by introducing the notion of "generalized RDF".
# TODO: Support an option `:strict_rdf` to explicitly disallow them or produce warnings or ...
def coerce_predicate(bnode = %BlankNode{}), do: bnode
def coerce_predicate(iri) when is_atom(iri) or is_binary(iri), do: RDF.iri!(iri)
def coerce_predicate(iri) when maybe_ns_term(iri) or is_binary(iri), do: RDF.iri!(iri)
def coerce_predicate(arg), do: raise RDF.Triple.InvalidPredicateError, predicate: arg
@doc false
@ -68,7 +69,7 @@ defmodule RDF.Statement do
def coerce_object(literal = %Literal{}), do: literal
def coerce_object(bnode = %BlankNode{}), do: bnode
def coerce_object(bool) when is_boolean(bool), do: Literal.new(bool)
def coerce_object(atom) when is_atom(atom), do: RDF.iri(atom)
def coerce_object(atom) when maybe_ns_term(atom), do: RDF.iri(atom)
def coerce_object(arg), do: Literal.new(arg)
@doc false
@ -78,7 +79,7 @@ defmodule RDF.Statement do
def coerce_graph_name(iri = %IRI{}), do: iri
def coerce_graph_name(bnode = %BlankNode{}), do: bnode
def coerce_graph_name("_:" <> identifier), do: RDF.bnode(identifier)
def coerce_graph_name(iri) when is_atom(iri) or is_binary(iri), do: RDF.iri!(iri)
def coerce_graph_name(iri) when maybe_ns_term(iri) or is_binary(iri), do: RDF.iri!(iri)
def coerce_graph_name(arg),
do: raise RDF.Quad.InvalidGraphContextError, graph_context: arg

26
test/unit/guards_test.exs Normal file
View file

@ -0,0 +1,26 @@
defmodule RDF.GuardsTest do
use RDF.Test.Case
doctest RDF.Guards
import RDF.Guards
describe "maybe_ns_term/1" do
def test_fun(term) when maybe_ns_term(term), do: true
def test_fun(_), do: false
test "with booleans" do
refute test_fun(true)
refute test_fun(false)
end
test "with nil" do
refute test_fun(nil)
end
test "any other atom" do
assert test_fun(:foo)
assert test_fun(Foo)
end
end
end