Add function signatures
This commit is contained in:
parent
62fc1a753b
commit
8345e101d3
22 changed files with 363 additions and 60 deletions
|
@ -7,7 +7,7 @@ defmodule RDF.BlankNode do
|
|||
"""
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
id: binary
|
||||
id: String.t
|
||||
}
|
||||
|
||||
@enforce_keys [:id]
|
||||
|
@ -16,6 +16,7 @@ defmodule RDF.BlankNode do
|
|||
@doc """
|
||||
Creates a `RDF.BlankNode` with an arbitrary internal id.
|
||||
"""
|
||||
@spec new :: t
|
||||
def new,
|
||||
do: new(make_ref())
|
||||
|
||||
|
@ -27,6 +28,7 @@ defmodule RDF.BlankNode do
|
|||
iex> RDF.bnode(:foo)
|
||||
%RDF.BlankNode{id: "foo"}
|
||||
"""
|
||||
@spec new(reference | String.t | atom | integer) :: t
|
||||
def new(id)
|
||||
|
||||
def new(id) when is_binary(id),
|
||||
|
@ -44,6 +46,7 @@ defmodule RDF.BlankNode do
|
|||
|
||||
Returns `nil` when the given arguments are not comparable as blank nodes.
|
||||
"""
|
||||
@spec equal_value?(t, t) :: boolean | nil
|
||||
def equal_value?(left, right)
|
||||
|
||||
def equal_value?(%RDF.BlankNode{id: left}, %RDF.BlankNode{id: right}),
|
||||
|
|
|
@ -8,7 +8,7 @@ defmodule RDF.BlankNode.Generator.Algorithm do
|
|||
@doc """
|
||||
Returns the initial state of the algorithm.
|
||||
"""
|
||||
@callback init(opts :: map | Keyword.t()) :: map
|
||||
@callback init(opts :: map | keyword) :: map
|
||||
|
||||
@doc """
|
||||
Generates a blank node.
|
||||
|
|
|
@ -15,24 +15,28 @@ defmodule RDF.Dataset do
|
|||
|
||||
@behaviour Access
|
||||
|
||||
alias RDF.{Graph, Description}
|
||||
alias RDF.{Description, Graph, IRI, Statement}
|
||||
import RDF.Statement
|
||||
|
||||
@type graphs_key :: RDF.IRI.t | nil
|
||||
@type graphs_key :: IRI.t | nil
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
name: RDF.IRI.t | nil,
|
||||
graphs: %{graphs_key => RDF.Graph.t}
|
||||
name: IRI.t | nil,
|
||||
graphs: %{graphs_key => Graph.t}
|
||||
}
|
||||
|
||||
@type t_param :: Graph.t_param | t
|
||||
|
||||
@type update_graph_fun :: (Graph.t -> {Graph.t, t_param} | :pop)
|
||||
|
||||
defstruct name: nil, graphs: %{}
|
||||
|
||||
|
||||
@doc """
|
||||
Creates an empty unnamed `RDF.Dataset`.
|
||||
"""
|
||||
def new,
|
||||
do: %RDF.Dataset{}
|
||||
@spec new :: t
|
||||
def new, do: %RDF.Dataset{}
|
||||
|
||||
@doc """
|
||||
Creates an `RDF.Dataset`.
|
||||
|
@ -49,6 +53,7 @@ defmodule RDF.Dataset do
|
|||
RDF.Graph.new(name: EX.GraphName)
|
||||
|
||||
"""
|
||||
@spec new(t_param | [t_param] | keyword) :: t
|
||||
def new(data_or_options)
|
||||
|
||||
def new(data_or_options)
|
||||
|
@ -78,6 +83,7 @@ defmodule RDF.Dataset do
|
|||
- `name`: the name of the dataset to be created
|
||||
|
||||
"""
|
||||
@spec new(t_param | [t_param], keyword) :: t
|
||||
def new(data, options)
|
||||
|
||||
def new(%RDF.Dataset{} = graph, options) do
|
||||
|
@ -98,6 +104,7 @@ defmodule RDF.Dataset do
|
|||
destination graph to which the statements are added, ignoring the graph context
|
||||
of given quads or the name of given graphs.
|
||||
"""
|
||||
@spec add(t, t_param | [t_param], boolean | nil) :: t
|
||||
def add(dataset, statements, graph_context \\ false)
|
||||
|
||||
def add(dataset, statements, graph_context) when is_list(statements) do
|
||||
|
@ -179,6 +186,7 @@ defmodule RDF.Dataset do
|
|||
...> RDF.Dataset.put([{EX.S1, EX.P2, EX.O3}, {EX.S2, EX.P2, EX.O3}])
|
||||
RDF.Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S1, EX.P2, EX.O3}, {EX.S2, EX.P2, EX.O3}])
|
||||
"""
|
||||
@spec put(t, t_param | [t_param], Statement.coercible_graph_name | boolean | nil) :: t
|
||||
def put(dataset, statements, graph_context \\ false)
|
||||
|
||||
def put(%RDF.Dataset{} = dataset, {subject, predicate, objects}, false),
|
||||
|
@ -299,6 +307,7 @@ defmodule RDF.Dataset do
|
|||
are deleted. If you want to delete only datasets with matching names, you can
|
||||
use `RDF.Data.delete/2`.
|
||||
"""
|
||||
@spec delete(t, t_param | [t_param], Statement.coercible_graph_name | boolean | nil) :: t
|
||||
def delete(dataset, statements, graph_context \\ false)
|
||||
|
||||
def delete(%RDF.Dataset{} = dataset, statements, graph_context) when is_list(statements) do
|
||||
|
@ -362,6 +371,7 @@ defmodule RDF.Dataset do
|
|||
@doc """
|
||||
Deletes the given graph.
|
||||
"""
|
||||
@spec delete_graph(t, Statement.graph_name | [Statement.graph_name] | nil) :: t
|
||||
def delete_graph(graph, graph_names)
|
||||
|
||||
def delete_graph(%RDF.Dataset{} = dataset, graph_names) when is_list(graph_names) do
|
||||
|
@ -379,6 +389,7 @@ defmodule RDF.Dataset do
|
|||
@doc """
|
||||
Deletes the default graph.
|
||||
"""
|
||||
@spec delete_default_graph(t) :: t
|
||||
def delete_default_graph(%RDF.Dataset{} = graph),
|
||||
do: delete_graph(graph, nil)
|
||||
|
||||
|
@ -399,6 +410,7 @@ defmodule RDF.Dataset do
|
|||
:error
|
||||
"""
|
||||
@impl Access
|
||||
@spec fetch(t, Statement.graph_name | nil) :: {:ok, Graph.t} | :error
|
||||
def fetch(%RDF.Dataset{graphs: graphs}, graph_name) do
|
||||
Access.fetch(graphs, coerce_graph_name(graph_name))
|
||||
end
|
||||
|
@ -421,6 +433,7 @@ defmodule RDF.Dataset do
|
|||
iex> RDF.Dataset.get(dataset, EX.Foo, :bar)
|
||||
:bar
|
||||
"""
|
||||
@spec get(t, Statement.graph_name | nil, Graph.t | nil) :: Graph.t | nil
|
||||
def get(%RDF.Dataset{} = dataset, graph_name, default \\ nil) do
|
||||
case fetch(dataset, graph_name) do
|
||||
{:ok, value} -> value
|
||||
|
@ -431,12 +444,14 @@ defmodule RDF.Dataset do
|
|||
@doc """
|
||||
The graph with given name.
|
||||
"""
|
||||
@spec graph(t, Statement.graph_name | nil) :: Graph.t
|
||||
def graph(%RDF.Dataset{graphs: graphs}, graph_name),
|
||||
do: Map.get(graphs, coerce_graph_name(graph_name))
|
||||
|
||||
@doc """
|
||||
The default graph of a `RDF.Dataset`.
|
||||
"""
|
||||
@spec default_graph(t) :: Graph.t
|
||||
def default_graph(%RDF.Dataset{graphs: graphs}),
|
||||
do: Map.get(graphs, nil, Graph.new)
|
||||
|
||||
|
@ -444,6 +459,7 @@ defmodule RDF.Dataset do
|
|||
@doc """
|
||||
The set of all graphs.
|
||||
"""
|
||||
@spec graphs(t) :: [Graph.t]
|
||||
def graphs(%RDF.Dataset{graphs: graphs}), do: Map.values(graphs)
|
||||
|
||||
|
||||
|
@ -470,6 +486,7 @@ defmodule RDF.Dataset do
|
|||
{RDF.Graph.new({EX.S, EX.P, EX.O}, name: EX.Graph), RDF.Dataset.new({EX.S, EX.P, EX.NEW, EX.Graph})}
|
||||
"""
|
||||
@impl Access
|
||||
@spec get_and_update(t, Statement.graph_name | nil, update_graph_fun) :: {Graph.t, t_param}
|
||||
def get_and_update(%RDF.Dataset{} = dataset, graph_name, fun) do
|
||||
with graph_context = coerce_graph_name(graph_name) do
|
||||
case fun.(get(dataset, graph_context)) do
|
||||
|
@ -487,6 +504,7 @@ defmodule RDF.Dataset do
|
|||
@doc """
|
||||
Pops an arbitrary statement from a `RDF.Dataset`.
|
||||
"""
|
||||
@spec pop(t) :: {Statement.t | nil, t}
|
||||
def pop(dataset)
|
||||
|
||||
def pop(%RDF.Dataset{graphs: graphs} = dataset)
|
||||
|
@ -520,6 +538,7 @@ defmodule RDF.Dataset do
|
|||
{nil, dataset}
|
||||
"""
|
||||
@impl Access
|
||||
@spec pop(t, Statement.coercible_graph_name) :: {Statement.t | nil, t}
|
||||
def pop(%RDF.Dataset{name: name, graphs: graphs} = dataset, graph_name) do
|
||||
case Access.pop(graphs, coerce_graph_name(graph_name)) do
|
||||
{nil, _} ->
|
||||
|
@ -543,6 +562,7 @@ defmodule RDF.Dataset do
|
|||
...> RDF.Dataset.statement_count
|
||||
3
|
||||
"""
|
||||
@spec statement_count(t) :: non_neg_integer
|
||||
def statement_count(%RDF.Dataset{graphs: graphs}) do
|
||||
Enum.reduce graphs, 0, fn ({_, graph}, count) ->
|
||||
count + Graph.triple_count(graph)
|
||||
|
@ -641,6 +661,7 @@ defmodule RDF.Dataset do
|
|||
{RDF.iri(EX.S1), RDF.iri(EX.p2), RDF.iri(EX.O3)},
|
||||
{RDF.iri(EX.S2), RDF.iri(EX.p2), RDF.iri(EX.O2)}]
|
||||
"""
|
||||
@spec statements(t) :: [Statement.t]
|
||||
def statements(%RDF.Dataset{graphs: graphs}) do
|
||||
Enum.reduce graphs, [], fn ({_, graph}, all_statements) ->
|
||||
statements = Graph.triples(graph)
|
||||
|
@ -665,6 +686,7 @@ defmodule RDF.Dataset do
|
|||
...> RDF.Dataset.include?(dataset, {EX.S1, EX.p1, EX.O1, EX.Graph})
|
||||
true
|
||||
"""
|
||||
@spec include?(t, Statement.t, Statement.coercible_graph_name | nil) :: boolean
|
||||
def include?(dataset, statement, graph_context \\ nil)
|
||||
|
||||
def include?(%RDF.Dataset{graphs: graphs}, triple = {_, _, _}, graph_context) do
|
||||
|
@ -691,6 +713,7 @@ defmodule RDF.Dataset do
|
|||
iex> RDF.Dataset.new([{EX.S1, EX.p1, EX.O1}]) |> RDF.Dataset.describes?(EX.S2)
|
||||
false
|
||||
"""
|
||||
@spec describes?(t, Statement.t, Statement.coercible_graph_name | nil) :: boolean
|
||||
def describes?(%RDF.Dataset{graphs: graphs}, subject, graph_context \\ nil) do
|
||||
with graph_context = coerce_graph_name(graph_context) do
|
||||
if graph = graphs[graph_context] do
|
||||
|
@ -713,6 +736,7 @@ defmodule RDF.Dataset do
|
|||
...> RDF.Dataset.who_describes(dataset, EX.S1)
|
||||
[nil, RDF.iri(EX.Graph1)]
|
||||
"""
|
||||
@spec who_describes(t, Statement.coercible_subject) :: [Graph.t]
|
||||
def who_describes(%RDF.Dataset{graphs: graphs}, subject) do
|
||||
with subject = coerce_subject(subject) do
|
||||
graphs
|
||||
|
@ -775,6 +799,7 @@ defmodule RDF.Dataset do
|
|||
}
|
||||
|
||||
"""
|
||||
@spec values(t, Statement.term_mapping) :: map
|
||||
def values(dataset, mapping \\ &RDF.Statement.default_term_mapping/1)
|
||||
|
||||
def values(%RDF.Dataset{graphs: graphs}, mapping) do
|
||||
|
@ -790,6 +815,7 @@ defmodule RDF.Dataset do
|
|||
Two `RDF.Dataset`s are considered to be equal if they contain the same triples
|
||||
and have the same name.
|
||||
"""
|
||||
@spec equal?(t | any, t | any) :: boolean
|
||||
def equal?(dataset1, dataset2)
|
||||
|
||||
def equal?(%RDF.Dataset{} = dataset1, %RDF.Dataset{} = dataset2) do
|
||||
|
|
|
@ -6,23 +6,25 @@ defmodule RDF.Datatype do
|
|||
the validation, conversion and canonicalization of typed `RDF.Literal`s.
|
||||
"""
|
||||
|
||||
alias RDF.Literal
|
||||
alias RDF.{IRI, Literal}
|
||||
alias RDF.Datatype.NS.XSD
|
||||
|
||||
@type t :: module
|
||||
|
||||
@doc """
|
||||
The IRI of the datatype.
|
||||
"""
|
||||
@callback id :: RDF.IRI.t
|
||||
@callback id :: IRI.t
|
||||
|
||||
@doc """
|
||||
Produces the lexical form of a `RDF.Literal`.
|
||||
"""
|
||||
@callback lexical(literal :: RDF.Literal.t) :: any
|
||||
@callback lexical(Literal.t) :: any
|
||||
|
||||
@doc """
|
||||
Produces the lexical form of a value.
|
||||
"""
|
||||
@callback canonical_lexical(any) :: binary
|
||||
@callback canonical_lexical(any) :: String.t | nil
|
||||
|
||||
@doc """
|
||||
Produces the lexical form of an invalid value of a typed Literal.
|
||||
|
@ -30,12 +32,12 @@ defmodule RDF.Datatype do
|
|||
The default implementation of the `_using__` macro just returns `to_string`
|
||||
representation of the value.
|
||||
"""
|
||||
@callback invalid_lexical(any) :: binary
|
||||
@callback invalid_lexical(any) :: String.t | nil
|
||||
|
||||
@doc """
|
||||
Produces the canonical form of a `RDF.Literal`.
|
||||
"""
|
||||
@callback canonical(RDF.Literal.t) :: RDF.Literal.t
|
||||
@callback canonical(Literal.t) :: Literal.t | nil
|
||||
|
||||
@doc """
|
||||
Converts a value into a proper native value.
|
||||
|
@ -58,13 +60,13 @@ defmodule RDF.Datatype do
|
|||
If the given literal is invalid or can not be converted into this datatype
|
||||
`nil` is returned.
|
||||
"""
|
||||
@callback cast(RDF.Literal.t) :: RDF.Literal.t
|
||||
@callback cast(Literal.t) :: Literal.t | nil
|
||||
|
||||
|
||||
@doc """
|
||||
Determines if the value of a `RDF.Literal` is a member of lexical value space of its datatype.
|
||||
"""
|
||||
@callback valid?(literal :: RDF.Literal.t) :: boolean
|
||||
@callback valid?(literal :: Literal.t) :: boolean | nil
|
||||
|
||||
@doc """
|
||||
Checks if the value of two `RDF.Literal`s of this datatype are equal.
|
||||
|
@ -76,7 +78,7 @@ defmodule RDF.Datatype do
|
|||
The default implementation of the `_using__` macro compares the values of the
|
||||
`canonical/1` forms of the given literals of this datatype.
|
||||
"""
|
||||
@callback equal_value?(literal1 :: RDF.Literal.t, literal2 :: RDF.Literal.t) :: boolean | nil
|
||||
@callback equal_value?(literal1 :: Literal.t, literal2 :: Literal.t) :: boolean | nil
|
||||
|
||||
@doc """
|
||||
Compares two `RDF.Literal`s.
|
||||
|
@ -92,7 +94,7 @@ defmodule RDF.Datatype do
|
|||
The default implementation of the `_using__` macro compares the values of the
|
||||
`canonical/1` forms of the given literals of this datatype.
|
||||
"""
|
||||
@callback compare(literal1 :: RDF.Literal.t, literal2 :: RDF.Literal.t) :: :lt | :gt | :eq | :indeterminate | nil
|
||||
@callback compare(literal1 :: Literal.t, literal2 :: Literal.t) :: :lt | :gt | :eq | :indeterminate | nil
|
||||
|
||||
|
||||
@lang_string RDF.iri("http://www.w3.org/1999/02/22-rdf-syntax-ns#langString")
|
||||
|
@ -113,21 +115,25 @@ defmodule RDF.Datatype do
|
|||
@doc """
|
||||
The mapping of IRIs of datatypes to their `RDF.Datatype`.
|
||||
"""
|
||||
@spec mapping :: %{IRI.t => t}
|
||||
def mapping, do: @mapping
|
||||
|
||||
@doc """
|
||||
The IRIs of all datatypes with a `RDF.Datatype` defined.
|
||||
"""
|
||||
@spec ids :: [IRI.t]
|
||||
def ids, do: Map.keys(@mapping)
|
||||
|
||||
@doc """
|
||||
All defined `RDF.Datatype` modules.
|
||||
"""
|
||||
@spec modules :: [t]
|
||||
def modules, do: Map.values(@mapping)
|
||||
|
||||
@doc """
|
||||
Returns the `RDF.Datatype` for a directly datatype IRI or the datatype IRI of a `RDF.Literal`.
|
||||
"""
|
||||
@spec get(Literal.t | IRI.t) :: t
|
||||
def get(%Literal{datatype: id}), do: get(id)
|
||||
def get(id), do: @mapping[id]
|
||||
|
||||
|
|
|
@ -35,11 +35,13 @@ defmodule RDF.Numeric do
|
|||
@doc """
|
||||
The list of all numeric datatypes.
|
||||
"""
|
||||
@dialyzer {:nowarn_function, types: 0}
|
||||
def types(), do: MapSet.to_list(@types)
|
||||
|
||||
@doc """
|
||||
Returns if a given datatype is a numeric datatype.
|
||||
"""
|
||||
@dialyzer {:nowarn_function, type?: 1}
|
||||
def type?(type), do: MapSet.member?(@types, type)
|
||||
|
||||
@doc """
|
||||
|
|
|
@ -13,9 +13,17 @@ defmodule RDF.Description do
|
|||
@behaviour Access
|
||||
|
||||
import RDF.Statement
|
||||
alias RDF.{Statement, Triple}
|
||||
|
||||
@type predications :: %{Statement.predicate => %{Statement.object => nil}}
|
||||
|
||||
@type statements ::
|
||||
{Statement.coercible_predicate,
|
||||
Statement.coercible_object | [Statement.coercible_predicate]}
|
||||
| Statement.t
|
||||
| predications
|
||||
| t
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
subject: Statement.subject,
|
||||
predications: predications
|
||||
|
@ -30,21 +38,22 @@ defmodule RDF.Description do
|
|||
|
||||
When given a list of statements, the first one must contain a subject.
|
||||
"""
|
||||
@spec new(RDF.Statement.coercible_subject) :: RDF.Description.t
|
||||
@spec new(Statement.coercible_subject | statements | [statements]) :: t
|
||||
def new(subject)
|
||||
|
||||
def new({subject, predicate, object}),
|
||||
do: new(subject) |> add(predicate, object)
|
||||
def new([statement | more_statements]),
|
||||
do: new(statement) |> add(more_statements)
|
||||
def new(%RDF.Description{} = description),
|
||||
def new(%__MODULE__{} = description),
|
||||
do: description
|
||||
def new(subject),
|
||||
do: %RDF.Description{subject: coerce_subject(subject)}
|
||||
do: %__MODULE__{subject: coerce_subject(subject)}
|
||||
|
||||
@doc """
|
||||
Creates a new `RDF.Description` about the given subject with optional initial statements.
|
||||
"""
|
||||
@spec new(Statement.coercible_subject, statements | [statements]) :: t
|
||||
def new(subject, {predicate, objects}),
|
||||
do: new(subject) |> add(predicate, objects)
|
||||
def new(subject, statements) when is_list(statements),
|
||||
|
@ -57,8 +66,13 @@ defmodule RDF.Description do
|
|||
@doc """
|
||||
Creates a new `RDF.Description` about the given subject with optional initial statements.
|
||||
"""
|
||||
@spec new(
|
||||
Statement.coercible_subject | statements | [statements],
|
||||
Statement.coercible_predicate,
|
||||
Statement.coercible_object | [Statement.coercible_object]
|
||||
) :: t
|
||||
def new(%RDF.Description{} = description, predicate, objects),
|
||||
do: RDF.Description.add(description, predicate, objects)
|
||||
do: add(description, predicate, objects)
|
||||
def new(subject, predicate, objects),
|
||||
do: new(subject) |> add(predicate, objects)
|
||||
|
||||
|
@ -73,6 +87,11 @@ defmodule RDF.Description do
|
|||
iex> RDF.Description.add(RDF.Description.new({EX.S, EX.P, EX.O1}), EX.P, [EX.O2, EX.O3])
|
||||
RDF.Description.new([{EX.S, EX.P, EX.O1}, {EX.S, EX.P, EX.O2}, {EX.S, EX.P, EX.O3}])
|
||||
"""
|
||||
@spec add(
|
||||
t,
|
||||
Statement.coercible_predicate,
|
||||
Statement.coercible_object | [Statement.coercible_object]
|
||||
) :: t
|
||||
def add(description, predicate, objects)
|
||||
|
||||
def add(description, predicate, objects) when is_list(objects) do
|
||||
|
@ -101,6 +120,7 @@ defmodule RDF.Description do
|
|||
are added. As opposed to that `RDF.Data.merge/2` will produce a `RDF.Graph`
|
||||
containing both descriptions.
|
||||
"""
|
||||
@spec add(t, statements | [statements]) :: t
|
||||
def add(description, statements)
|
||||
|
||||
def add(description, {predicate, object}),
|
||||
|
@ -145,6 +165,11 @@ defmodule RDF.Description do
|
|||
iex> RDF.Description.put(RDF.Description.new({EX.S, EX.P1, EX.O1}), EX.P2, EX.O2)
|
||||
RDF.Description.new([{EX.S, EX.P1, EX.O1}, {EX.S, EX.P2, EX.O2}])
|
||||
"""
|
||||
@spec put(
|
||||
t,
|
||||
Statement.coercible_predicate,
|
||||
Statement.coercible_object | [Statement.coercible_object]
|
||||
) :: t
|
||||
def put(description, predicate, objects)
|
||||
|
||||
def put(%RDF.Description{subject: subject, predications: predications},
|
||||
|
@ -176,6 +201,7 @@ defmodule RDF.Description do
|
|||
...> RDF.Description.put(%{EX.P2 => [EX.O3, EX.O4]})
|
||||
RDF.Description.new([{EX.S, EX.P1, EX.O1}, {EX.S, EX.P2, EX.O3}, {EX.S, EX.P2, EX.O4}])
|
||||
"""
|
||||
@spec put(t, statements | [statements]) :: t
|
||||
def put(description, statements)
|
||||
|
||||
def put(%RDF.Description{} = description, {predicate, object}),
|
||||
|
@ -224,6 +250,11 @@ defmodule RDF.Description do
|
|||
@doc """
|
||||
Deletes statements from a `RDF.Description`.
|
||||
"""
|
||||
@spec delete(
|
||||
t,
|
||||
Statement.coercible_predicate,
|
||||
Statement.coercible_object | [Statement.coercible_object]
|
||||
) :: t
|
||||
def delete(description, predicate, objects)
|
||||
|
||||
def delete(description, predicate, objects) when is_list(objects) do
|
||||
|
@ -261,6 +292,7 @@ defmodule RDF.Description do
|
|||
are deleted. If you want to delete only a matching description subject, you can
|
||||
use `RDF.Data.delete/2`.
|
||||
"""
|
||||
@spec delete(t, statements | [statements]) :: t
|
||||
def delete(description, statements)
|
||||
|
||||
def delete(desc = %RDF.Description{}, {predicate, object}),
|
||||
|
@ -297,6 +329,7 @@ defmodule RDF.Description do
|
|||
@doc """
|
||||
Deletes all statements with the given properties.
|
||||
"""
|
||||
@spec delete_predicates(t, Statement.coercible_predicate | [Statement.coercible_predicate]) :: t
|
||||
def delete_predicates(description, properties)
|
||||
|
||||
def delete_predicates(%RDF.Description{} = description, properties) when is_list(properties) do
|
||||
|
@ -328,6 +361,7 @@ defmodule RDF.Description do
|
|||
:error
|
||||
"""
|
||||
@impl Access
|
||||
@spec fetch(t, Statement.coercible_predicate) :: {:ok, [Statement.object]} | :error
|
||||
def fetch(%RDF.Description{predications: predications}, predicate) do
|
||||
with {:ok, objects} <- Access.fetch(predications, coerce_predicate(predicate)) do
|
||||
{:ok, Map.keys(objects)}
|
||||
|
@ -348,6 +382,7 @@ defmodule RDF.Description do
|
|||
iex> RDF.Description.get(RDF.Description.new(EX.S), EX.foo, :bar)
|
||||
:bar
|
||||
"""
|
||||
@spec get(t, Statement.coercible_predicate, any) :: [Statement.object] | any
|
||||
def get(description = %RDF.Description{}, predicate, default \\ nil) do
|
||||
case fetch(description, predicate) do
|
||||
{:ok, value} -> value
|
||||
|
@ -367,6 +402,7 @@ defmodule RDF.Description do
|
|||
iex> RDF.Description.first(RDF.Description.new(EX.S), EX.foo)
|
||||
nil
|
||||
"""
|
||||
@spec first(t, Statement.coercible_predicate) :: Statement.object | nil
|
||||
def first(description = %RDF.Description{}, predicate) do
|
||||
description
|
||||
|> get(predicate, [])
|
||||
|
@ -395,6 +431,12 @@ defmodule RDF.Description do
|
|||
RDF.Description.new({EX.S, EX.p, EX.O})
|
||||
|
||||
"""
|
||||
@spec update(
|
||||
t,
|
||||
Statement.coercible_predicate,
|
||||
Statement.coercible_object | nil,
|
||||
([Statement.Object] -> [Statement.Object])
|
||||
) :: t
|
||||
def update(description = %RDF.Description{}, predicate, initial \\ nil, fun) do
|
||||
predicate = coerce_predicate(predicate)
|
||||
|
||||
|
@ -444,6 +486,11 @@ defmodule RDF.Description do
|
|||
{[RDF.iri(EX.O1)], RDF.Description.new({EX.S, EX.P2, EX.O2})}
|
||||
"""
|
||||
@impl Access
|
||||
@spec get_and_update(
|
||||
t,
|
||||
Statement.coercible_predicate,
|
||||
([Statement.Object] -> {[Statement.Object], t} | :pop)
|
||||
) :: {[Statement.Object], t}
|
||||
def get_and_update(description = %RDF.Description{}, predicate, fun) do
|
||||
with triple_predicate = coerce_predicate(predicate) do
|
||||
case fun.(get(description, triple_predicate)) do
|
||||
|
@ -458,6 +505,7 @@ defmodule RDF.Description do
|
|||
@doc """
|
||||
Pops an arbitrary triple from a `RDF.Description`.
|
||||
"""
|
||||
@spec pop(t) :: {Triple.t | [Statement.Object] | nil, t}
|
||||
def pop(description)
|
||||
|
||||
def pop(description = %RDF.Description{predications: predications})
|
||||
|
@ -511,6 +559,7 @@ defmodule RDF.Description do
|
|||
...> RDF.Description.predicates
|
||||
MapSet.new([EX.p1, EX.p2])
|
||||
"""
|
||||
@spec predicates(t) :: MapSet.t
|
||||
def predicates(%RDF.Description{predications: predications}),
|
||||
do: predications |> Map.keys |> MapSet.new
|
||||
|
||||
|
@ -530,12 +579,14 @@ defmodule RDF.Description do
|
|||
...> ]) |> RDF.Description.objects
|
||||
MapSet.new([RDF.iri(EX.O1), RDF.iri(EX.O2), RDF.bnode(:bnode)])
|
||||
"""
|
||||
@spec objects(t) :: MapSet.t
|
||||
def objects(%RDF.Description{} = description),
|
||||
do: objects(description, &RDF.resource?/1)
|
||||
|
||||
@doc """
|
||||
The set of all resources used in the objects within a `RDF.Description` satisfying the given filter criterion.
|
||||
"""
|
||||
@spec objects(t, (Statement.object -> boolean)) :: MapSet.t
|
||||
def objects(%RDF.Description{predications: predications}, filter_fn) do
|
||||
Enum.reduce predications, MapSet.new, fn ({_, objects}, acc) ->
|
||||
objects
|
||||
|
@ -560,6 +611,7 @@ defmodule RDF.Description do
|
|||
...> ]) |> RDF.Description.resources
|
||||
MapSet.new([RDF.iri(EX.O1), RDF.iri(EX.O2), RDF.bnode(:bnode), EX.p1, EX.p2, EX.p3])
|
||||
"""
|
||||
@spec resources(t) :: MapSet.t
|
||||
def resources(description) do
|
||||
description
|
||||
|> objects
|
||||
|
@ -569,6 +621,7 @@ defmodule RDF.Description do
|
|||
@doc """
|
||||
The list of all triples within a `RDF.Description`.
|
||||
"""
|
||||
@spec triples(t) :: keyword
|
||||
def triples(description = %RDF.Description{}), do: Enum.to_list(description)
|
||||
|
||||
defdelegate statements(description), to: RDF.Description, as: :triples
|
||||
|
@ -577,6 +630,7 @@ defmodule RDF.Description do
|
|||
@doc """
|
||||
Returns the number of statements of a `RDF.Description`.
|
||||
"""
|
||||
@spec count(t) :: non_neg_integer
|
||||
def count(%RDF.Description{predications: predications}) do
|
||||
Enum.reduce predications, 0,
|
||||
fn ({_, objects}, count) -> count + Enum.count(objects) end
|
||||
|
@ -586,6 +640,7 @@ defmodule RDF.Description do
|
|||
@doc """
|
||||
Checks if the given statement exists within a `RDF.Description`.
|
||||
"""
|
||||
@spec include?(t, statements) :: boolean
|
||||
def include?(description, statement)
|
||||
|
||||
def include?(%RDF.Description{predications: predications},
|
||||
|
@ -617,6 +672,7 @@ defmodule RDF.Description do
|
|||
iex> RDF.Description.new(EX.S1, EX.p1, EX.O1) |> RDF.Description.describes?(EX.S2)
|
||||
false
|
||||
"""
|
||||
@spec describes?(t, Statement.subject) :: boolean
|
||||
def describes?(%RDF.Description{subject: subject}, other_subject) do
|
||||
with other_subject = coerce_subject(other_subject) do
|
||||
subject == other_subject
|
||||
|
@ -656,6 +712,7 @@ defmodule RDF.Description do
|
|||
%{p: ["Foo"]}
|
||||
|
||||
"""
|
||||
@spec values(t, Statement.term_mapping) :: map
|
||||
def values(description, mapping \\ &RDF.Statement.default_term_mapping/1)
|
||||
|
||||
def values(%RDF.Description{predications: predications}, mapping) do
|
||||
|
@ -674,6 +731,7 @@ defmodule RDF.Description do
|
|||
|
||||
If `nil` is passed, the description is left untouched.
|
||||
"""
|
||||
@spec take(t, [Statement.coercible_predicate] | nil) :: t
|
||||
def take(description, predicates)
|
||||
|
||||
def take(%RDF.Description{} = description, nil), do: description
|
||||
|
@ -688,6 +746,7 @@ defmodule RDF.Description do
|
|||
|
||||
Two `RDF.Description`s are considered to be equal if they contain the same triples.
|
||||
"""
|
||||
@spec equal?(t, t) :: boolean
|
||||
def equal?(description1, description2)
|
||||
|
||||
def equal?(%RDF.Description{} = description1, %RDF.Description{} = description2) do
|
||||
|
|
|
@ -9,8 +9,8 @@ defmodule RDF.Diff do
|
|||
alias RDF.{Description, Graph}
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
additions: RDF.Graph.t,
|
||||
deletions: RDF.Graph.t
|
||||
additions: Graph.t,
|
||||
deletions: Graph.t
|
||||
}
|
||||
|
||||
defstruct [:additions, :deletions]
|
||||
|
@ -23,6 +23,7 @@ defmodule RDF.Diff do
|
|||
`additions` and `deletions` keywords. The statements for the additions and
|
||||
deletions can be provided in any form supported by the `RDF.Graph.new/1` function.
|
||||
"""
|
||||
@spec new(keyword) :: t
|
||||
def new(diff \\ []) do
|
||||
%__MODULE__{
|
||||
additions: Keyword.get(diff, :additions) |> coerce_graph(),
|
||||
|
@ -58,6 +59,8 @@ defmodule RDF.Diff do
|
|||
deletions: RDF.graph({EX.S1, EX.p1, EX.O1})
|
||||
}
|
||||
"""
|
||||
@dialyzer {:nowarn_function, diff: 2}
|
||||
@spec diff(Description.t | Graph.t, Description.t | Graph.t) :: t
|
||||
def diff(original_rdf_data, new_rdf_data)
|
||||
|
||||
def diff(%Description{} = description, description), do: new()
|
||||
|
@ -149,6 +152,7 @@ defmodule RDF.Diff do
|
|||
The diffs are merged by adding up the `additions` and `deletions` of both
|
||||
diffs respectively.
|
||||
"""
|
||||
@spec merge(t, t) :: t
|
||||
def merge(%__MODULE__{} = diff1, %__MODULE__{} = diff2) do
|
||||
new(
|
||||
additions: Graph.add(diff1.additions, diff2.additions),
|
||||
|
@ -161,6 +165,7 @@ defmodule RDF.Diff do
|
|||
|
||||
A `RDF.Diff` is empty, if its `additions` and `deletions` graphs are empty.
|
||||
"""
|
||||
@spec empty?(t) :: boolean
|
||||
def empty?(%__MODULE__{} = diff) do
|
||||
Enum.empty?(diff.additions) and Enum.empty?(diff.deletions)
|
||||
end
|
||||
|
@ -174,6 +179,7 @@ defmodule RDF.Diff do
|
|||
The result of an application is always a `RDF.Graph`, even if a `RDF.Description`
|
||||
is given and the additions from the diff are all about the subject of this description.
|
||||
"""
|
||||
@spec apply(t, Description.t | Graph.t) :: Graph.t
|
||||
def apply(diff, rdf_data)
|
||||
|
||||
def apply(%__MODULE__{} = diff, %Graph{} = graph) do
|
||||
|
|
|
@ -13,22 +13,31 @@ defmodule RDF.Graph do
|
|||
|
||||
@behaviour Access
|
||||
|
||||
alias RDF.Description
|
||||
import RDF.Statement
|
||||
alias RDF.{Description, IRI, PrefixMap, Statement}
|
||||
|
||||
@type graph_description :: %{IRI.t => Description.t}
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
name: RDF.IRI.t | nil,
|
||||
name: IRI.t | nil,
|
||||
descriptions: graph_description,
|
||||
prefixes: RDF.PrefixMap.t | nil,
|
||||
base_iri: RDF.IRI | nil
|
||||
prefixes: PrefixMap.t | nil,
|
||||
base_iri: IRI.t | nil
|
||||
}
|
||||
|
||||
@type t_param :: Statement.t | Description.t | t
|
||||
|
||||
@type update_description_fun :: (Description.t -> Description.t)
|
||||
|
||||
@type get_and_update_description_fun :: (Description.t -> {Description.t, t_param} | :pop)
|
||||
|
||||
defstruct name: nil, descriptions: %{}, prefixes: nil, base_iri: nil
|
||||
|
||||
|
||||
@doc """
|
||||
Creates an empty unnamed `RDF.Graph`.
|
||||
"""
|
||||
@spec new :: t
|
||||
def new, do: %RDF.Graph{}
|
||||
|
||||
@doc """
|
||||
|
@ -46,6 +55,7 @@ defmodule RDF.Graph do
|
|||
RDF.Graph.new(name: EX.GraphName)
|
||||
|
||||
"""
|
||||
@spec new(t_param | [t_param] | keyword) :: t
|
||||
def new(data_or_options)
|
||||
|
||||
def new(data_or_options)
|
||||
|
@ -88,6 +98,7 @@ defmodule RDF.Graph do
|
|||
RDF.Graph.new({EX.S, EX.p, EX.O}, name: EX.GraphName, base_iri: EX.base)
|
||||
|
||||
"""
|
||||
@spec new(t_param | [t_param], keyword) :: t
|
||||
def new(data, options)
|
||||
|
||||
def new(%RDF.Graph{} = graph, options) do
|
||||
|
@ -107,6 +118,12 @@ defmodule RDF.Graph do
|
|||
|
||||
See `new/2` for available arguments.
|
||||
"""
|
||||
@spec new(
|
||||
Statement.coercible_subject,
|
||||
Statement.coercible_predicate,
|
||||
Statement.coercible_object | [Statement.coercible_object],
|
||||
keyword
|
||||
) :: t
|
||||
def new(subject, predicate, objects, options \\ []),
|
||||
do: new([], options) |> add(subject, predicate, objects)
|
||||
|
||||
|
@ -118,6 +135,7 @@ defmodule RDF.Graph do
|
|||
another graph, as this function keeps graph name name, base IRI and default
|
||||
prefixes as they are and just removes the triples.
|
||||
"""
|
||||
@spec clear(t) :: t
|
||||
def clear(%RDF.Graph{} = graph) do
|
||||
%RDF.Graph{graph | descriptions: %{}}
|
||||
end
|
||||
|
@ -126,6 +144,12 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
Adds triples to a `RDF.Graph`.
|
||||
"""
|
||||
@spec add(
|
||||
t,
|
||||
Statement.coercible_subject,
|
||||
Statement.coercible_predicate,
|
||||
Statement.coercible_object | [Statement.coercible_object]
|
||||
) :: t
|
||||
def add(%RDF.Graph{} = graph, subject, predicate, objects),
|
||||
do: add(graph, {subject, predicate, objects})
|
||||
|
||||
|
@ -141,6 +165,7 @@ defmodule RDF.Graph do
|
|||
prefixes of this graph will be added. In case of conflicting prefix mappings
|
||||
the original prefix from `graph` will be kept.
|
||||
"""
|
||||
@spec add(t, t_param | [t_param]) :: t
|
||||
def add(graph, triples)
|
||||
|
||||
def add(%RDF.Graph{} = graph, {subject, _, _} = statement),
|
||||
|
@ -196,6 +221,7 @@ defmodule RDF.Graph do
|
|||
RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S1, EX.P2, EX.O3}, {EX.S2, EX.P2, EX.O3}])
|
||||
|
||||
"""
|
||||
@spec put(t, t_param | [t_param]) :: t
|
||||
def put(graph, statements)
|
||||
|
||||
def put(%RDF.Graph{} = graph, {subject, _, _} = statement),
|
||||
|
@ -233,6 +259,7 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
Add statements to a `RDF.Graph`, overwriting all statements with the same subject and predicate.
|
||||
"""
|
||||
@spec put(t, Statement.coercible_subject, Description.statements | [Description.statements]) :: t
|
||||
def put(graph, subject, predications)
|
||||
|
||||
def put(%RDF.Graph{descriptions: descriptions} = graph, subject, predications)
|
||||
|
@ -273,6 +300,12 @@ defmodule RDF.Graph do
|
|||
RDF.Graph.new([{EX.S, EX.P1, EX.O1}, {EX.S, EX.P2, EX.O2}])
|
||||
|
||||
"""
|
||||
@spec put(
|
||||
t,
|
||||
Statement.coercible_subject,
|
||||
Statement.coercible_predicate,
|
||||
Statement.coercible_object | [Statement.coercible_object]
|
||||
) :: t
|
||||
def put(%RDF.Graph{} = graph, subject, predicate, objects),
|
||||
do: put(graph, {subject, predicate, objects})
|
||||
|
||||
|
@ -280,6 +313,12 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
Deletes statements from a `RDF.Graph`.
|
||||
"""
|
||||
@spec delete(
|
||||
t,
|
||||
Statement.coercible_subject,
|
||||
Statement.coercible_predicate,
|
||||
Statement.coercible_object | [Statement.coercible_object]
|
||||
) :: t
|
||||
def delete(graph, subject, predicate, object),
|
||||
do: delete(graph, {subject, predicate, object})
|
||||
|
||||
|
@ -292,6 +331,7 @@ defmodule RDF.Graph do
|
|||
use `RDF.Data.delete/2`.
|
||||
|
||||
"""
|
||||
@spec delete(t, t_param | [t_param]) :: t
|
||||
def delete(graph, triples)
|
||||
|
||||
def delete(%RDF.Graph{} = graph, {subject, _, _} = triple),
|
||||
|
@ -337,6 +377,10 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
Deletes all statements with the given subjects.
|
||||
"""
|
||||
@spec delete_subjects(
|
||||
t,
|
||||
Statement.coercible_subject | [Statement.coercible_subject]
|
||||
) :: t
|
||||
def delete_subjects(graph, subjects)
|
||||
|
||||
def delete_subjects(%RDF.Graph{} = graph, subjects) when is_list(subjects) do
|
||||
|
@ -382,6 +426,12 @@ defmodule RDF.Graph do
|
|||
RDF.Graph.new([{EX.S, EX.p, EX.O}])
|
||||
|
||||
"""
|
||||
@spec update(
|
||||
t,
|
||||
Statement.coercible_subject,
|
||||
Description.statements | [Description.statements] | nil,
|
||||
update_description_fun
|
||||
) :: t
|
||||
def update(graph = %RDF.Graph{}, subject, initial \\ nil, fun) do
|
||||
subject = coerce_subject(subject)
|
||||
|
||||
|
@ -424,6 +474,7 @@ defmodule RDF.Graph do
|
|||
|
||||
"""
|
||||
@impl Access
|
||||
@spec fetch(t, Statement.coercible_subject) :: {:ok, Description.t} | :error
|
||||
def fetch(%RDF.Graph{descriptions: descriptions}, subject) do
|
||||
Access.fetch(descriptions, coerce_subject(subject))
|
||||
end
|
||||
|
@ -444,6 +495,7 @@ defmodule RDF.Graph do
|
|||
:bar
|
||||
|
||||
"""
|
||||
@spec get(t, Statement.coercible_subject, Description.t | nil) :: Description.t | nil
|
||||
def get(%RDF.Graph{} = graph, subject, default \\ nil) do
|
||||
case fetch(graph, subject) do
|
||||
{:ok, value} -> value
|
||||
|
@ -454,12 +506,14 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
The `RDF.Description` of the given subject.
|
||||
"""
|
||||
@spec description(t, Statement.coercible_subject) :: Description.t | nil
|
||||
def description(%RDF.Graph{descriptions: descriptions}, subject),
|
||||
do: Map.get(descriptions, coerce_subject(subject))
|
||||
|
||||
@doc """
|
||||
All `RDF.Description`s within a `RDF.Graph`.
|
||||
"""
|
||||
@spec descriptions(t) :: [Description.t]
|
||||
def descriptions(%RDF.Graph{descriptions: descriptions}),
|
||||
do: Map.values(descriptions)
|
||||
|
||||
|
@ -488,6 +542,8 @@ defmodule RDF.Graph do
|
|||
|
||||
"""
|
||||
@impl Access
|
||||
@spec get_and_update(t, Statement.coercible_subject, get_and_update_description_fun) ::
|
||||
{Description.t, t_param}
|
||||
def get_and_update(%RDF.Graph{} = graph, subject, fun) do
|
||||
with subject = coerce_subject(subject) do
|
||||
case fun.(get(graph, subject)) do
|
||||
|
@ -505,6 +561,7 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
Pops an arbitrary triple from a `RDF.Graph`.
|
||||
"""
|
||||
@spec pop(t) :: {Statement.t | nil, t}
|
||||
def pop(graph)
|
||||
|
||||
def pop(%RDF.Graph{descriptions: descriptions} = graph)
|
||||
|
@ -536,6 +593,7 @@ defmodule RDF.Graph do
|
|||
|
||||
"""
|
||||
@impl Access
|
||||
@spec pop(t, Statement.coercible_subject) :: {Description.t | nil, t}
|
||||
def pop(%RDF.Graph{descriptions: descriptions} = graph, subject) do
|
||||
case Access.pop(descriptions, coerce_subject(subject)) do
|
||||
{nil, _} ->
|
||||
|
@ -559,6 +617,7 @@ defmodule RDF.Graph do
|
|||
2
|
||||
|
||||
"""
|
||||
@spec subject_count(t) :: non_neg_integer
|
||||
def subject_count(%RDF.Graph{descriptions: descriptions}),
|
||||
do: Enum.count(descriptions)
|
||||
|
||||
|
@ -575,6 +634,7 @@ defmodule RDF.Graph do
|
|||
3
|
||||
|
||||
"""
|
||||
@spec triple_count(t) :: non_neg_integer
|
||||
def triple_count(%RDF.Graph{descriptions: descriptions}) do
|
||||
Enum.reduce descriptions, 0, fn ({_subject, description}, count) ->
|
||||
count + Description.count(description)
|
||||
|
@ -676,7 +736,8 @@ defmodule RDF.Graph do
|
|||
{RDF.iri(EX.S1), RDF.iri(EX.p2), RDF.iri(EX.O3)},
|
||||
{RDF.iri(EX.S2), RDF.iri(EX.p2), RDF.iri(EX.O2)}]
|
||||
"""
|
||||
def triples(graph = %RDF.Graph{}), do: Enum.to_list(graph)
|
||||
@spec triples(t) :: [Statement.t]
|
||||
def triples(%RDF.Graph{} = graph), do: Enum.to_list(graph)
|
||||
|
||||
defdelegate statements(graph), to: RDF.Graph, as: :triples
|
||||
|
||||
|
@ -684,6 +745,7 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
Checks if the given statement exists within a `RDF.Graph`.
|
||||
"""
|
||||
@spec include?(t, Statement.t) :: boolean
|
||||
def include?(%RDF.Graph{descriptions: descriptions},
|
||||
triple = {subject, _, _}) do
|
||||
with subject = coerce_subject(subject),
|
||||
|
@ -704,6 +766,7 @@ defmodule RDF.Graph do
|
|||
iex> RDF.Graph.new([{EX.S1, EX.p1, EX.O1}]) |> RDF.Graph.describes?(EX.S2)
|
||||
false
|
||||
"""
|
||||
@spec describes?(t, Statement.coercible_subject) :: boolean
|
||||
def describes?(%RDF.Graph{descriptions: descriptions}, subject) do
|
||||
with subject = coerce_subject(subject) do
|
||||
Map.has_key?(descriptions, subject)
|
||||
|
@ -753,6 +816,7 @@ defmodule RDF.Graph do
|
|||
}
|
||||
|
||||
"""
|
||||
@spec values(t, Statement.term_mapping) :: map
|
||||
def values(graph, mapping \\ &RDF.Statement.default_term_mapping/1)
|
||||
|
||||
def values(%RDF.Graph{descriptions: descriptions}, mapping) do
|
||||
|
@ -770,6 +834,7 @@ defmodule RDF.Graph do
|
|||
|
||||
If `nil` is passed as the `subjects`, the subjects will not be limited.
|
||||
"""
|
||||
@spec take(t, [Statement.coercible_subject] | nil, [Statement.coercible_predicate] | nil) :: t
|
||||
def take(graph, subjects, properties \\ nil)
|
||||
|
||||
def take(%RDF.Graph{} = graph, nil, nil), do: graph
|
||||
|
@ -795,6 +860,7 @@ defmodule RDF.Graph do
|
|||
Two `RDF.Graph`s are considered to be equal if they contain the same triples
|
||||
and have the same name. The prefixes of the graph are irrelevant for equality.
|
||||
"""
|
||||
@spec equal?(t | any, t | any) :: boolean
|
||||
def equal?(graph1, graph2)
|
||||
|
||||
def equal?(%RDF.Graph{} = graph1, %RDF.Graph{} = graph2) do
|
||||
|
@ -814,6 +880,11 @@ defmodule RDF.Graph do
|
|||
the new one. This behaviour can be customized by providing a `conflict_resolver`
|
||||
function. See `RDF.PrefixMap.merge/3` for more on that.
|
||||
"""
|
||||
@spec add_prefixes(
|
||||
t,
|
||||
PrefixMap.t | map | keyword | nil,
|
||||
PrefixMap.conflict_resolver | nil
|
||||
) :: t
|
||||
def add_prefixes(graph, prefixes, conflict_resolver \\ nil)
|
||||
|
||||
def add_prefixes(%RDF.Graph{} = graph, nil, _), do: graph
|
||||
|
@ -838,6 +909,7 @@ defmodule RDF.Graph do
|
|||
The `prefixes` can be a single prefix or a list of prefixes.
|
||||
Prefixes not in prefixes of the graph are simply ignored.
|
||||
"""
|
||||
@spec delete_prefixes(t, PrefixMap.t) :: t
|
||||
def delete_prefixes(graph, prefixes)
|
||||
|
||||
def delete_prefixes(%RDF.Graph{prefixes: nil} = graph, _), do: graph
|
||||
|
@ -849,6 +921,7 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
Clears all prefixes of the given `graph`.
|
||||
"""
|
||||
@spec clear_prefixes(t) :: t
|
||||
def clear_prefixes(%RDF.Graph{} = graph) do
|
||||
%RDF.Graph{graph | prefixes: nil}
|
||||
end
|
||||
|
@ -858,6 +931,7 @@ defmodule RDF.Graph do
|
|||
|
||||
The `base_iri` can be given as anything accepted by `RDF.IRI.coerce_base/1`.
|
||||
"""
|
||||
@spec set_base_iri(t, IRI.t | nil) :: t
|
||||
def set_base_iri(graph, base_iri)
|
||||
|
||||
def set_base_iri(%RDF.Graph{} = graph, nil) do
|
||||
|
@ -871,6 +945,7 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
Clears the base IRI of the given `graph`.
|
||||
"""
|
||||
@spec clear_base_iri(t) :: t
|
||||
def clear_base_iri(%RDF.Graph{} = graph) do
|
||||
%RDF.Graph{graph | base_iri: nil}
|
||||
end
|
||||
|
@ -878,6 +953,7 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
Clears the base IRI and all prefixes of the given `graph`.
|
||||
"""
|
||||
@spec clear_metadata(t) :: t
|
||||
def clear_metadata(%RDF.Graph{} = graph) do
|
||||
graph
|
||||
|> clear_base_iri()
|
||||
|
|
|
@ -16,12 +16,14 @@ defmodule RDF.IRI do
|
|||
see <https://tools.ietf.org/html/rfc3987>
|
||||
"""
|
||||
|
||||
alias RDF.Namespace
|
||||
alias RDF.{Datatype, Namespace}
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
value: binary
|
||||
value: String.t
|
||||
}
|
||||
|
||||
@type t_param :: String.t | Datatype.t | URI.t | t
|
||||
|
||||
@enforce_keys [:value]
|
||||
defstruct [:value]
|
||||
|
||||
|
@ -45,6 +47,7 @@ defmodule RDF.IRI do
|
|||
@doc """
|
||||
Creates a `RDF.IRI`.
|
||||
"""
|
||||
@spec new(t_param) :: t
|
||||
def new(iri)
|
||||
def new(iri) when is_binary(iri), do: %RDF.IRI{value: iri}
|
||||
def new(qname) when is_atom(qname) and qname not in [nil, true, false],
|
||||
|
@ -59,6 +62,7 @@ defmodule RDF.IRI do
|
|||
|
||||
see `valid?/1`
|
||||
"""
|
||||
@spec new!(t_param) :: 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],
|
||||
|
@ -73,6 +77,7 @@ defmodule RDF.IRI do
|
|||
As opposed to `new/1` this also accepts bare `RDF.Vocabulary.Namespace` modules
|
||||
and uses the base IRI from their definition.
|
||||
"""
|
||||
@spec coerce_base(t_param) :: t
|
||||
def coerce_base(base_iri)
|
||||
|
||||
def coerce_base(module) when is_atom(module) do
|
||||
|
@ -98,6 +103,7 @@ defmodule RDF.IRI do
|
|||
iex> RDF.IRI.valid!("not an iri")
|
||||
** (RDF.IRI.InvalidError) Invalid IRI: "not an iri"
|
||||
"""
|
||||
@spec valid!(t_param) :: t_param
|
||||
def valid!(iri) do
|
||||
if not valid?(iri), do: raise RDF.IRI.InvalidError, "Invalid IRI: #{inspect iri}"
|
||||
iri
|
||||
|
@ -116,6 +122,7 @@ defmodule RDF.IRI do
|
|||
iex> RDF.IRI.valid?("not an iri")
|
||||
false
|
||||
"""
|
||||
@spec valid?(t_param) :: boolean
|
||||
def valid?(iri), do: absolute?(iri) # TODO: Provide a more elaborate validation
|
||||
|
||||
|
||||
|
@ -125,6 +132,7 @@ defmodule RDF.IRI do
|
|||
An absolute IRI is defined in [RFC3987](http://www.ietf.org/rfc/rfc3987.txt)
|
||||
containing a scheme along with a path and optional query and fragment segments.
|
||||
"""
|
||||
@spec absolute?(any) :: boolean
|
||||
def absolute?(iri)
|
||||
|
||||
def absolute?(value) when is_binary(value), do: not is_nil(scheme(value))
|
||||
|
@ -151,6 +159,7 @@ defmodule RDF.IRI do
|
|||
|
||||
If the given is not an absolute IRI `nil` is returned.
|
||||
"""
|
||||
@spec absolute(t_param, t_param) :: t | nil
|
||||
def absolute(iri, base) do
|
||||
cond do
|
||||
absolute?(iri) -> new(iri)
|
||||
|
@ -166,6 +175,7 @@ defmodule RDF.IRI do
|
|||
This function merges two IRIs as per
|
||||
[RFC 3986, section 5.2](https://tools.ietf.org/html/rfc3986#section-5.2).
|
||||
"""
|
||||
@spec merge(t_param, t_param) :: t
|
||||
def merge(base, rel) do
|
||||
base
|
||||
|> parse()
|
||||
|
@ -186,6 +196,7 @@ defmodule RDF.IRI do
|
|||
iex> RDF.IRI.scheme("not an iri")
|
||||
nil
|
||||
"""
|
||||
@spec scheme(t_param) :: String.t | nil
|
||||
def scheme(iri)
|
||||
def scheme(%RDF.IRI{value: value}), do: scheme(value)
|
||||
def scheme(%URI{scheme: scheme}), do: scheme
|
||||
|
@ -200,6 +211,7 @@ defmodule RDF.IRI do
|
|||
@doc """
|
||||
Parses an IRI into its components and returns them as an `URI` struct.
|
||||
"""
|
||||
@spec parse(t_param) :: 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],
|
||||
|
@ -215,6 +227,7 @@ defmodule RDF.IRI do
|
|||
|
||||
see <https://www.w3.org/TR/rdf-concepts/#section-Graph-URIref>
|
||||
"""
|
||||
@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}),
|
||||
|
@ -247,6 +260,7 @@ defmodule RDF.IRI do
|
|||
"http://example.com/#Foo"
|
||||
|
||||
"""
|
||||
@spec to_string(t | Datatype.t) :: String.t
|
||||
def to_string(iri)
|
||||
|
||||
def to_string(%RDF.IRI{value: value}),
|
||||
|
|
|
@ -7,11 +7,11 @@ defmodule RDF.List do
|
|||
- <https://www.w3.org/TR/rdf11-mt/#rdf-collections>
|
||||
"""
|
||||
|
||||
alias RDF.{Graph, Description, IRI, BlankNode}
|
||||
alias RDF.{BlankNode, Description, Graph, IRI}
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
head: RDF.IRI.t,
|
||||
graph: RDF.Graph.t
|
||||
head: IRI.t,
|
||||
graph: Graph.t
|
||||
}
|
||||
|
||||
@enforce_keys [:head]
|
||||
|
@ -31,6 +31,7 @@ defmodule RDF.List do
|
|||
- does not contain cycles, i.e. `rdf:rest` statements don't refer to
|
||||
preceding list nodes
|
||||
"""
|
||||
@spec new(IRI.t_param, Graph.t) :: t
|
||||
def new(head, graph)
|
||||
|
||||
def new(head, graph) when is_atom(head) and head not in ~w[true false nil]a,
|
||||
|
@ -70,6 +71,7 @@ defmodule RDF.List do
|
|||
the head node of the empty list is always `RDF.nil`.
|
||||
|
||||
"""
|
||||
@spec from(Enumerable.t, keyword) :: t
|
||||
def from(list, opts \\ []) do
|
||||
with head = Keyword.get(opts, :head, RDF.bnode),
|
||||
graph = Keyword.get(opts, :graph, RDF.graph),
|
||||
|
@ -118,6 +120,7 @@ defmodule RDF.List do
|
|||
|
||||
Nested lists are converted recursively.
|
||||
"""
|
||||
@spec values(t) :: Enumerable.t
|
||||
def values(%RDF.List{graph: graph} = list) do
|
||||
Enum.map list, fn node_description ->
|
||||
value = Description.first(node_description, RDF.first)
|
||||
|
@ -135,6 +138,7 @@ defmodule RDF.List do
|
|||
@doc """
|
||||
The RDF nodes constituting a `RDF.List` as an Elixir list.
|
||||
"""
|
||||
@spec nodes(t) :: [BlankNode.t]
|
||||
def nodes(%RDF.List{} = list) do
|
||||
Enum.map list, fn node_description -> node_description.subject end
|
||||
end
|
||||
|
@ -143,16 +147,18 @@ defmodule RDF.List do
|
|||
@doc """
|
||||
Checks if a list is the empty list.
|
||||
"""
|
||||
@spec empty?(t) :: boolean
|
||||
def empty?(%RDF.List{head: @rdf_nil}), do: true
|
||||
def empty?(_), do: false
|
||||
def empty?(%RDF.List{}), do: false
|
||||
|
||||
|
||||
@doc """
|
||||
Checks if the given list consists of list nodes which are all blank nodes.
|
||||
"""
|
||||
@spec valid?(t) :: boolean
|
||||
def valid?(%RDF.List{head: @rdf_nil}), do: true
|
||||
|
||||
def valid?(list) do
|
||||
def valid?(%RDF.List{} = list) do
|
||||
Enum.all? list, fn node_description ->
|
||||
RDF.bnode?(node_description.subject)
|
||||
end
|
||||
|
@ -168,6 +174,7 @@ defmodule RDF.List do
|
|||
Note: This function doesn't indicate if the list is valid.
|
||||
See `new/2` and `valid?/2` for validations.
|
||||
"""
|
||||
@spec node?(any, Graph.t) :: boolean
|
||||
def node?(list_node, graph)
|
||||
|
||||
def node?(@rdf_nil, _),
|
||||
|
|
|
@ -4,23 +4,26 @@ defmodule RDF.Literal do
|
|||
"""
|
||||
|
||||
alias RDF.Datatype.NS.XSD
|
||||
alias RDF.IRI
|
||||
|
||||
@type literal_value ::
|
||||
binary
|
||||
| boolean
|
||||
boolean
|
||||
| integer
|
||||
| float
|
||||
| String.t
|
||||
| Decimal.t
|
||||
| Date.t
|
||||
| Time.t
|
||||
| DateTime.t
|
||||
| NaiveDateTime.t
|
||||
| {Date.t, String.t}
|
||||
| :nan
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
value: literal_value,
|
||||
datatype: RDF.IRI.t,
|
||||
uncanonical_lexical: binary | nil,
|
||||
language: binary | nil
|
||||
datatype: IRI.t,
|
||||
uncanonical_lexical: String.t | nil,
|
||||
language: String.t | nil
|
||||
}
|
||||
|
||||
defstruct [:value, :datatype, :uncanonical_lexical, :language]
|
||||
|
@ -56,6 +59,7 @@ defmodule RDF.Literal do
|
|||
%RDF.Literal{value: 42, datatype: XSD.integer}
|
||||
|
||||
"""
|
||||
@spec new(literal_value | t) :: t
|
||||
def new(value)
|
||||
|
||||
def new(%RDF.Literal{} = literal), do: literal
|
||||
|
@ -79,6 +83,7 @@ defmodule RDF.Literal do
|
|||
@doc """
|
||||
Creates a new `RDF.Literal` with the given datatype or language tag.
|
||||
"""
|
||||
@spec new(literal_value | t, map | keyword) :: t
|
||||
def new(value, opts)
|
||||
|
||||
def new(value, opts) when is_list(opts),
|
||||
|
@ -134,6 +139,7 @@ defmodule RDF.Literal do
|
|||
** (RDF.Literal.InvalidError) invalid RDF.Literal: %RDF.Literal{value: "foo", datatype: ~I<http://www.w3.org/1999/02/22-rdf-syntax-ns#langString>, language: nil}
|
||||
|
||||
"""
|
||||
@spec new!(literal_value | t, map | keyword) :: t
|
||||
def new!(value, opts \\ %{}) do
|
||||
with %RDF.Literal{} = literal <- new(value, opts) do
|
||||
if valid?(literal) do
|
||||
|
@ -150,6 +156,7 @@ defmodule RDF.Literal do
|
|||
@doc """
|
||||
Returns the lexical representation of the given literal according to its datatype.
|
||||
"""
|
||||
@spec lexical(t) :: String.t
|
||||
def lexical(%RDF.Literal{value: value, uncanonical_lexical: nil, datatype: id} = literal) do
|
||||
case RDF.Datatype.get(id) do
|
||||
nil -> to_string(value)
|
||||
|
@ -162,6 +169,7 @@ defmodule RDF.Literal do
|
|||
@doc """
|
||||
Returns the given literal in its canonical lexical representation.
|
||||
"""
|
||||
@spec canonical(t) :: t
|
||||
def canonical(%RDF.Literal{uncanonical_lexical: nil} = literal), do: literal
|
||||
def canonical(%RDF.Literal{datatype: id} = literal) do
|
||||
case RDF.Datatype.get(id) do
|
||||
|
@ -174,13 +182,15 @@ defmodule RDF.Literal do
|
|||
@doc """
|
||||
Returns if the given literal is in its canonical lexical representation.
|
||||
"""
|
||||
@spec canonical?(t) :: boolean
|
||||
def canonical?(%RDF.Literal{uncanonical_lexical: nil}), do: true
|
||||
def canonical?(_), do: false
|
||||
def canonical?(%RDF.Literal{} = _), do: false
|
||||
|
||||
|
||||
@doc """
|
||||
Returns if the value of the given literal is a valid according to its datatype.
|
||||
"""
|
||||
@spec valid?(t) :: boolean
|
||||
def valid?(%RDF.Literal{datatype: id} = literal) do
|
||||
case RDF.Datatype.get(id) do
|
||||
nil -> true
|
||||
|
@ -196,8 +206,9 @@ defmodule RDF.Literal do
|
|||
|
||||
see <http://www.w3.org/TR/sparql11-query/#simple_literal>
|
||||
"""
|
||||
@spec simple?(t) :: boolean
|
||||
def simple?(%RDF.Literal{datatype: @xsd_string}), do: true
|
||||
def simple?(_), do: false
|
||||
def simple?(%RDF.Literal{} = _), do: false
|
||||
|
||||
|
||||
@doc """
|
||||
|
@ -205,8 +216,9 @@ defmodule RDF.Literal do
|
|||
|
||||
see <http://www.w3.org/TR/rdf-concepts/#dfn-plain-literal>
|
||||
"""
|
||||
@spec has_language?(t) :: boolean
|
||||
def has_language?(%RDF.Literal{datatype: @lang_string}), do: true
|
||||
def has_language?(_), do: false
|
||||
def has_language?(%RDF.Literal{} = _), do: false
|
||||
|
||||
|
||||
@doc """
|
||||
|
@ -216,6 +228,7 @@ defmodule RDF.Literal do
|
|||
|
||||
see <http://www.w3.org/TR/rdf-concepts/#dfn-typed-literal>
|
||||
"""
|
||||
@spec has_datatype?(t) :: boolean
|
||||
def has_datatype?(literal) do
|
||||
not plain?(literal) and not has_language?(literal)
|
||||
end
|
||||
|
@ -229,10 +242,12 @@ defmodule RDF.Literal do
|
|||
|
||||
see <http://www.w3.org/TR/rdf-concepts/#dfn-plain-literal>
|
||||
"""
|
||||
@spec plain?(t) :: boolean
|
||||
def plain?(%RDF.Literal{datatype: datatype})
|
||||
when datatype in @plain_types, do: true
|
||||
def plain?(_), do: false
|
||||
def plain?(%RDF.Literal{} = _), do: false
|
||||
|
||||
@spec typed?(t) :: boolean
|
||||
def typed?(literal), do: not plain?(literal)
|
||||
|
||||
|
||||
|
@ -245,6 +260,7 @@ defmodule RDF.Literal do
|
|||
|
||||
see <https://www.w3.org/TR/rdf-concepts/#section-Literal-Equality>
|
||||
"""
|
||||
@spec equal_value?(t | IRI.t | any, t | IRI.t | any) :: boolean | nil
|
||||
def equal_value?(left, right)
|
||||
|
||||
def equal_value?(%RDF.Literal{datatype: id1} = literal1, %RDF.Literal{datatype: id2} = literal2) do
|
||||
|
@ -282,6 +298,7 @@ defmodule RDF.Literal do
|
|||
Returns `nil` when the given arguments are not comparable datatypes.
|
||||
|
||||
"""
|
||||
@spec less_than?(t | any, t | any) :: boolean | nil
|
||||
def less_than?(literal1, literal2) do
|
||||
case compare(literal1, literal2) do
|
||||
:lt -> true
|
||||
|
@ -296,6 +313,7 @@ defmodule RDF.Literal do
|
|||
Returns `nil` when the given arguments are not comparable datatypes.
|
||||
|
||||
"""
|
||||
@spec greater_than?(t | any, t | any) :: boolean | nil
|
||||
def greater_than?(literal1, literal2) do
|
||||
case compare(literal1, literal2) do
|
||||
:gt -> true
|
||||
|
@ -316,6 +334,7 @@ defmodule RDF.Literal do
|
|||
Returns `nil` when the given arguments are not comparable datatypes.
|
||||
|
||||
"""
|
||||
@spec compare(t | any, t | any) :: :eq | :lt | :gt | nil
|
||||
def compare(left, right)
|
||||
|
||||
def compare(%RDF.Literal{datatype: id1} = literal1, %RDF.Literal{datatype: id2} = literal2) do
|
||||
|
@ -347,6 +366,7 @@ defmodule RDF.Literal do
|
|||
|
||||
see <https://www.w3.org/TR/xpath-functions/#func-matches>
|
||||
"""
|
||||
@spec matches?(t | String.t, t | String.t, t | String.t) :: boolean
|
||||
def matches?(value, pattern, flags \\ "") do
|
||||
string = to_string(value)
|
||||
case xpath_pattern(pattern, flags) do
|
||||
|
@ -361,12 +381,13 @@ defmodule RDF.Literal do
|
|||
|> String.downcase()
|
||||
|> String.contains?(String.downcase(pattern))
|
||||
|
||||
_ ->
|
||||
raise "Invalid XQuery regex pattern or flags"
|
||||
# _ ->
|
||||
# raise "Invalid XQuery regex pattern or flags"
|
||||
end
|
||||
end
|
||||
|
||||
@doc false
|
||||
@spec xpath_pattern(t | String.t, t | String.t) :: {:regex, Regex.t} | {:q | :qi, String.t}
|
||||
def xpath_pattern(pattern, flags)
|
||||
|
||||
def xpath_pattern(%RDF.Literal{datatype: @xsd_string} = pattern, flags),
|
||||
|
@ -395,6 +416,7 @@ defmodule RDF.Literal do
|
|||
end
|
||||
|
||||
@doc false
|
||||
@spec convert_utf_escaping(String.t) :: String.t
|
||||
def convert_utf_escaping(string) do
|
||||
require Integer
|
||||
|
||||
|
|
|
@ -7,10 +7,12 @@ defmodule RDF.Namespace do
|
|||
namespaces for JSON-LD contexts.
|
||||
"""
|
||||
|
||||
alias RDF.{Datatype, IRI}
|
||||
|
||||
@doc """
|
||||
Resolves a term to a `RDF.IRI`.
|
||||
"""
|
||||
@callback __resolve_term__(atom) :: RDF.IRI.t
|
||||
@callback __resolve_term__(atom) :: IRI.t
|
||||
|
||||
@doc """
|
||||
All terms of a `RDF.Namespace`.
|
||||
|
@ -25,9 +27,10 @@ defmodule RDF.Namespace do
|
|||
delegates to remaining part of the term to `__resolve_term__/1` of this
|
||||
determined namespace.
|
||||
"""
|
||||
@spec resolve_term(IRI.t | Datatype.t) :: IRI.t
|
||||
def resolve_term(expr)
|
||||
|
||||
def resolve_term(%RDF.IRI{} = iri), do: iri
|
||||
def resolve_term(%IRI{} = iri), do: iri
|
||||
|
||||
def resolve_term(namespaced_term) when is_atom(namespaced_term) do
|
||||
namespaced_term
|
||||
|
|
|
@ -7,8 +7,15 @@ defmodule RDF.PrefixMap do
|
|||
|
||||
alias RDF.IRI
|
||||
|
||||
@type prefix :: atom | String.t
|
||||
@type namespace :: atom | String.t | IRI.t
|
||||
|
||||
@type prefix_map :: %{prefix => namespace}
|
||||
|
||||
@type conflict_resolver :: (prefix, namespace, namespace -> namespace)
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
map: map
|
||||
map: prefix_map
|
||||
}
|
||||
|
||||
defstruct map: %{}
|
||||
|
@ -17,7 +24,8 @@ defmodule RDF.PrefixMap do
|
|||
@doc """
|
||||
Creates an empty `RDF.PrefixMap`.
|
||||
"""
|
||||
def new(), do: %__MODULE__{}
|
||||
@spec new :: t
|
||||
def new, do: %__MODULE__{}
|
||||
|
||||
@doc """
|
||||
Creates a new `RDF.PrefixMap`.
|
||||
|
@ -26,6 +34,7 @@ defmodule RDF.PrefixMap do
|
|||
The keys for the prefixes can be given as atoms or strings and will be normalized to atoms.
|
||||
The namespaces can be given as `RDF.IRI`s or strings and will be normalized to `RDF.IRI`s.
|
||||
"""
|
||||
@spec new(t | map | keyword) :: t
|
||||
def new(map)
|
||||
|
||||
def new(%__MODULE__{} = prefix_map), do: prefix_map
|
||||
|
@ -54,6 +63,7 @@ defmodule RDF.PrefixMap do
|
|||
Unless a mapping of the given prefix to a different namespace already exists,
|
||||
an ok tuple is returned, other an error tuple.
|
||||
"""
|
||||
@spec add(t, prefix, namespace) :: {:ok, t} | {:error, String.t}
|
||||
def add(prefix_map, prefix, namespace)
|
||||
|
||||
def add(%__MODULE__{map: map}, prefix, %IRI{} = namespace) when is_atom(prefix) do
|
||||
|
@ -73,6 +83,7 @@ defmodule RDF.PrefixMap do
|
|||
@doc """
|
||||
Adds a prefix mapping to the given `RDF.PrefixMap` and raises an exception in error cases.
|
||||
"""
|
||||
@spec add!(t, prefix, namespace) :: t
|
||||
def add!(prefix_map, prefix, namespace) do
|
||||
with {:ok, new_prefix_map} <- add(prefix_map, prefix, namespace) do
|
||||
new_prefix_map
|
||||
|
@ -94,6 +105,7 @@ defmodule RDF.PrefixMap do
|
|||
|
||||
See also `merge/3` which allows you to resolve conflicts with a function.
|
||||
"""
|
||||
@spec merge(t, t | map | keyword) :: {:ok, t} | {:error, [atom | String.t]}
|
||||
def merge(prefix_map1, prefix_map2)
|
||||
|
||||
def merge(%__MODULE__{map: map1}, %__MODULE__{map: map2}) do
|
||||
|
@ -133,6 +145,7 @@ defmodule RDF.PrefixMap do
|
|||
If everything could be merged, an `:ok` tuple is returned.
|
||||
|
||||
"""
|
||||
@spec merge(t, t | map | keyword, conflict_resolver | nil) :: {:ok, t} | {:error, [atom | String.t]}
|
||||
def merge(prefix_map1, prefix_map2, conflict_resolver)
|
||||
|
||||
def merge(%__MODULE__{map: map1}, %__MODULE__{map: map2}, conflict_resolver)
|
||||
|
@ -185,20 +198,22 @@ defmodule RDF.PrefixMap do
|
|||
|
||||
See `merge/2` and `merge/3` for more information on merging prefix maps.
|
||||
"""
|
||||
@spec merge!(t, t | map | keyword, conflict_resolver | nil) :: t
|
||||
def merge!(prefix_map1, prefix_map2, conflict_resolver \\ nil) do
|
||||
with {:ok, new_prefix_map} <- merge(prefix_map1, prefix_map2, conflict_resolver) do
|
||||
new_prefix_map
|
||||
else
|
||||
{:error, conflicts} ->
|
||||
raise "conflicting prefix mappings: #{
|
||||
conflicts |> Stream.map(&inspect/1) |> Enum.join(", ")
|
||||
}"
|
||||
conflicts = conflicts |> Stream.map(&inspect/1) |> Enum.join(", ")
|
||||
|
||||
raise "conflicting prefix mappings: #{conflicts}"
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a prefix mapping from the given `RDF.PrefixMap`.
|
||||
"""
|
||||
@spec delete(t, prefix) :: t
|
||||
def delete(prefix_map, prefix)
|
||||
|
||||
def delete(%__MODULE__{map: map}, prefix) when is_atom(prefix) do
|
||||
|
@ -214,6 +229,7 @@ defmodule RDF.PrefixMap do
|
|||
|
||||
If `prefixes` contains prefixes that are not in `prefix_map`, they're simply ignored.
|
||||
"""
|
||||
@spec drop(t, [prefix]) :: t
|
||||
def drop(prefix_map, prefixes)
|
||||
|
||||
def drop(%__MODULE__{map: map}, prefixes) do
|
||||
|
@ -234,6 +250,7 @@ defmodule RDF.PrefixMap do
|
|||
|
||||
Returns `nil`, when the given `prefix` is not present in `prefix_map`.
|
||||
"""
|
||||
@spec namespace(t, prefix) :: namespace | nil
|
||||
def namespace(prefix_map, prefix)
|
||||
|
||||
def namespace(%__MODULE__{map: map}, prefix) when is_atom(prefix) do
|
||||
|
@ -249,6 +266,7 @@ defmodule RDF.PrefixMap do
|
|||
|
||||
Returns `nil`, when the given `namespace` is not present in `prefix_map`.
|
||||
"""
|
||||
@spec prefix(t, namespace) :: prefix | nil
|
||||
def prefix(prefix_map, namespace)
|
||||
|
||||
def prefix(%__MODULE__{map: map}, %IRI{} = namespace) do
|
||||
|
@ -262,6 +280,7 @@ defmodule RDF.PrefixMap do
|
|||
@doc """
|
||||
Returns whether the given prefix exists in the given `RDF.PrefixMap`.
|
||||
"""
|
||||
@spec has_prefix?(t, prefix) :: boolean
|
||||
def has_prefix?(prefix_map, prefix)
|
||||
|
||||
def has_prefix?(%__MODULE__{map: map}, prefix) when is_atom(prefix) do
|
||||
|
@ -275,6 +294,7 @@ defmodule RDF.PrefixMap do
|
|||
@doc """
|
||||
Returns all prefixes from the given `RDF.PrefixMap`.
|
||||
"""
|
||||
@spec prefixes(t) :: [prefix]
|
||||
def prefixes(%__MODULE__{map: map}) do
|
||||
Map.keys(map)
|
||||
end
|
||||
|
@ -282,6 +302,7 @@ defmodule RDF.PrefixMap do
|
|||
@doc """
|
||||
Returns all namespaces from the given `RDF.PrefixMap`.
|
||||
"""
|
||||
@spec namespaces(t) :: [namespace]
|
||||
def namespaces(%__MODULE__{map: map}) do
|
||||
Map.values(map)
|
||||
end
|
||||
|
|
|
@ -6,10 +6,16 @@ defmodule RDF.Quad do
|
|||
RDF values for subject, predicate, object and a graph context.
|
||||
"""
|
||||
|
||||
alias RDF.Statement
|
||||
alias RDF.{Literal, Statement}
|
||||
|
||||
@type t :: {Statement.subject, Statement.predicate, Statement.object, Statement.graph_name}
|
||||
|
||||
@type coercible_t ::
|
||||
{Statement.coercible_subject, Statement.coercible_predicate,
|
||||
Statement.coercible_object, Statement.coercible_graph_name}
|
||||
|
||||
@type t_values :: {String.t, String.t, Literal.literal_value, String.t}
|
||||
|
||||
|
||||
@doc """
|
||||
Creates a `RDF.Quad` with proper RDF values.
|
||||
|
@ -25,6 +31,12 @@ defmodule RDF.Quad do
|
|||
iex> RDF.Quad.new(EX.S, EX.p, 42, EX.Graph)
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42), RDF.iri("http://example.com/Graph")}
|
||||
"""
|
||||
@spec new(
|
||||
Statement.coercible_subject,
|
||||
Statement.coercible_predicate,
|
||||
Statement.coercible_object,
|
||||
Statement.coercible_graph_name
|
||||
) :: t
|
||||
def new(subject, predicate, object, graph_context) do
|
||||
{
|
||||
Statement.coerce_subject(subject),
|
||||
|
@ -48,6 +60,7 @@ defmodule RDF.Quad do
|
|||
iex> RDF.Quad.new {EX.S, EX.p, 42, EX.Graph}
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42), RDF.iri("http://example.com/Graph")}
|
||||
"""
|
||||
@spec new(coercible_t) :: t
|
||||
def new({subject, predicate, object, graph_context}),
|
||||
do: new(subject, predicate, object, graph_context)
|
||||
|
||||
|
@ -81,6 +94,7 @@ defmodule RDF.Quad do
|
|||
{:S, :p, 42, ~I<http://example.com/Graph>}
|
||||
|
||||
"""
|
||||
@spec values(t | any, Statement.term_mapping) :: t_values | nil
|
||||
def values(quad, mapping \\ &Statement.default_term_mapping/1)
|
||||
|
||||
def values({subject, predicate, object, graph_context}, mapping) do
|
||||
|
@ -105,6 +119,7 @@ defmodule RDF.Quad do
|
|||
position only IRIs and blank nodes allowed, while on the predicate and graph
|
||||
context position only IRIs allowed. The object position can be any RDF term.
|
||||
"""
|
||||
@spec valid?(t | any) :: boolean
|
||||
def valid?(tuple)
|
||||
def valid?({_, _, _, _} = quad), do: Statement.valid?(quad)
|
||||
def valid?(_), do: false
|
||||
|
|
|
@ -11,7 +11,8 @@ defmodule RDF.Serialization.Encoder do
|
|||
It returns an `{:ok, string}` tuple, with `string` being the serialized
|
||||
`RDF.Graph` or `RDF.Dataset`, or `{:error, reason}` if an error occurs.
|
||||
"""
|
||||
@callback encode(RDF.Graph.t | RDF.Dataset.t, keyword) :: keyword(String.t)
|
||||
@callback encode(RDF.Graph.t | RDF.Dataset.t, keyword) ::
|
||||
{:ok, String.t} | {:error, any}
|
||||
|
||||
@doc """
|
||||
Encodes a `RDF.Graph` or `RDF.Dataset`.
|
||||
|
|
|
@ -175,6 +175,7 @@ defmodule RDF.Turtle.Encoder do
|
|||
|> Enum.join(" ;" <> newline_indent(nesting))
|
||||
end
|
||||
|
||||
@dialyzer {:nowarn_function, order_predications: 1}
|
||||
defp order_predications(predications) do
|
||||
sorted_predications =
|
||||
@predicate_order
|
||||
|
@ -223,6 +224,7 @@ defmodule RDF.Turtle.Encoder do
|
|||
end
|
||||
end
|
||||
|
||||
@dialyzer {:nowarn_function, list_subject_description: 1}
|
||||
defp list_subject_description(description) do
|
||||
with description = Description.delete_predicates(description, [RDF.first, RDF.rest]) do
|
||||
if Enum.count(description.predications) == 0 do
|
||||
|
|
|
@ -82,6 +82,7 @@ defmodule RDF.Turtle.Encoder.State do
|
|||
|
||||
@list_properties MapSet.new([RDF.first, RDF.rest])
|
||||
|
||||
@dialyzer {:nowarn_function, to_list?: 2}
|
||||
defp to_list?(%Description{} = description, 1) do
|
||||
Description.count(description) == 2 and
|
||||
Description.predicates(description) |> MapSet.equal?(@list_properties)
|
||||
|
|
|
@ -5,18 +5,23 @@ defmodule RDF.Statement do
|
|||
A RDF statement is either a `RDF.Triple` or a `RDF.Quad`.
|
||||
"""
|
||||
|
||||
alias RDF.{Triple, Quad, IRI, BlankNode, Literal}
|
||||
alias RDF.{BlankNode, IRI, Literal, Quad, Term, Triple}
|
||||
|
||||
@type subject :: IRI.t | BlankNode.t
|
||||
@type predicate :: IRI.t
|
||||
@type predicate :: IRI.t | BlankNode.t
|
||||
@type object :: IRI.t | BlankNode.t | Literal.t
|
||||
@type graph_name :: IRI.t | BlankNode.t
|
||||
|
||||
@type coercible_subject :: subject | atom | String.t
|
||||
@type coercible_predicate :: predicate | atom | String.t
|
||||
@type coercible_object :: object | atom | String.t # TODO: all basic Elixir types coercible to Literals
|
||||
@type coercible_object :: object | Literal.literal_value
|
||||
@type coercible_graph_name :: graph_name | atom | String.t
|
||||
|
||||
@type qualified_term :: {atom, Term.t | nil}
|
||||
@type term_mapping :: (qualified_term -> Literal.literal_value | nil)
|
||||
|
||||
@type t :: Triple.t | Quad.t
|
||||
|
||||
|
||||
@doc """
|
||||
Creates a `RDF.Statement` tuple with proper RDF values.
|
||||
|
@ -30,11 +35,14 @@ defmodule RDF.Statement do
|
|||
iex> RDF.Statement.coerce {"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"}
|
||||
{~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42), ~I<http://example.com/Graph>}
|
||||
"""
|
||||
@spec coerce(Triple.coercible_t) :: Triple.t
|
||||
@spec coerce(Quad.coercible_t) :: Quad.t
|
||||
def coerce(statement)
|
||||
def coerce({_, _, _} = triple), do: Triple.new(triple)
|
||||
def coerce({_, _, _, _} = quad), do: Quad.new(quad)
|
||||
|
||||
@doc false
|
||||
@spec coerce_subject(coercible_subject) :: subject
|
||||
def coerce_subject(iri)
|
||||
def coerce_subject(iri = %IRI{}), do: iri
|
||||
def coerce_subject(bnode = %BlankNode{}), do: bnode
|
||||
|
@ -43,6 +51,7 @@ defmodule RDF.Statement do
|
|||
def coerce_subject(arg), do: raise RDF.Triple.InvalidSubjectError, subject: arg
|
||||
|
||||
@doc false
|
||||
@spec coerce_predicate(coercible_predicate) :: predicate
|
||||
def coerce_predicate(iri)
|
||||
def coerce_predicate(iri = %IRI{}), do: iri
|
||||
# Note: Although, RDF does not allow blank nodes for properties, JSON-LD allows
|
||||
|
@ -53,6 +62,7 @@ defmodule RDF.Statement do
|
|||
def coerce_predicate(arg), do: raise RDF.Triple.InvalidPredicateError, predicate: arg
|
||||
|
||||
@doc false
|
||||
@spec coerce_object(coercible_object) :: object
|
||||
def coerce_object(iri)
|
||||
def coerce_object(iri = %IRI{}), do: iri
|
||||
def coerce_object(literal = %Literal{}), do: literal
|
||||
|
@ -62,6 +72,7 @@ defmodule RDF.Statement do
|
|||
def coerce_object(arg), do: Literal.new(arg)
|
||||
|
||||
@doc false
|
||||
@spec coerce_graph_name(coercible_graph_name) :: graph_name
|
||||
def coerce_graph_name(iri)
|
||||
def coerce_graph_name(nil), do: nil
|
||||
def coerce_graph_name(iri = %IRI{}), do: iri
|
||||
|
@ -105,12 +116,14 @@ defmodule RDF.Statement do
|
|||
{"S", :p, 42, ~I<http://example.com/Graph>}
|
||||
|
||||
"""
|
||||
@spec values(t | any, term_mapping) :: Triple.t_values | Quad.t_values | nil
|
||||
def values(statement, mapping \\ &default_term_mapping/1)
|
||||
def values({_, _, _} = triple, mapping), do: RDF.Triple.values(triple, mapping)
|
||||
def values({_, _, _, _} = quad, mapping), do: RDF.Quad.values(quad, mapping)
|
||||
def values(_, _), do: nil
|
||||
|
||||
@doc false
|
||||
@spec default_term_mapping(qualified_term) :: Literal.literal_value | nil
|
||||
def default_term_mapping(qualified_term)
|
||||
def default_term_mapping({:graph_name, nil}), do: nil
|
||||
def default_term_mapping({_, term}), do: RDF.Term.value(term)
|
||||
|
@ -123,6 +136,7 @@ defmodule RDF.Statement do
|
|||
position only IRIs and blank nodes allowed, while on the predicate and graph
|
||||
context position only IRIs allowed. The object position can be any RDF term.
|
||||
"""
|
||||
@spec valid?(Triple.t | Quad.t | any) :: boolean
|
||||
def valid?(tuple)
|
||||
|
||||
def valid?({subject, predicate, object}) do
|
||||
|
@ -136,18 +150,22 @@ defmodule RDF.Statement do
|
|||
|
||||
def valid?(_), do: false
|
||||
|
||||
@spec valid_subject?(subject | any) :: boolean
|
||||
def valid_subject?(%IRI{}), do: true
|
||||
def valid_subject?(%BlankNode{}), do: true
|
||||
def valid_subject?(_), do: false
|
||||
|
||||
@spec valid_predicate?(predicate | any) :: boolean
|
||||
def valid_predicate?(%IRI{}), do: true
|
||||
def valid_predicate?(_), do: false
|
||||
|
||||
@spec valid_object?(object | any) :: boolean
|
||||
def valid_object?(%IRI{}), do: true
|
||||
def valid_object?(%BlankNode{}), do: true
|
||||
def valid_object?(%Literal{}), do: true
|
||||
def valid_object?(_), do: false
|
||||
|
||||
@spec valid_graph_name?(graph_name | any) :: boolean
|
||||
def valid_graph_name?(%IRI{}), do: true
|
||||
def valid_graph_name?(_), do: false
|
||||
|
||||
|
|
|
@ -109,6 +109,8 @@ defimpl RDF.Term, for: RDF.BlankNode do
|
|||
end
|
||||
|
||||
defimpl RDF.Term, for: Reference do
|
||||
@dialyzer {:nowarn_function, equal_value?: 2}
|
||||
@dialyzer {:nowarn_function, coerce: 1}
|
||||
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)
|
||||
|
|
|
@ -6,10 +6,16 @@ defmodule RDF.Triple do
|
|||
RDF values for subject, predicate and object.
|
||||
"""
|
||||
|
||||
alias RDF.Statement
|
||||
alias RDF.{Literal, Statement}
|
||||
|
||||
@type t :: {Statement.subject, Statement.predicate, Statement.object}
|
||||
|
||||
@type coercible_t ::
|
||||
{Statement.coercible_subject, Statement.coercible_predicate,
|
||||
Statement.coercible_object}
|
||||
|
||||
@type t_values :: {String.t, String.t, Literal.literal_value}
|
||||
|
||||
|
||||
@doc """
|
||||
Creates a `RDF.Triple` with proper RDF values.
|
||||
|
@ -25,6 +31,11 @@ defmodule RDF.Triple do
|
|||
iex> RDF.Triple.new(EX.S, EX.p, 42)
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42)}
|
||||
"""
|
||||
@spec new(
|
||||
Statement.coercible_subject,
|
||||
Statement.coercible_predicate,
|
||||
Statement.coercible_object
|
||||
) :: t
|
||||
def new(subject, predicate, object) do
|
||||
{
|
||||
Statement.coerce_subject(subject),
|
||||
|
@ -47,6 +58,7 @@ defmodule RDF.Triple do
|
|||
iex> RDF.Triple.new {EX.S, EX.p, 42}
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42)}
|
||||
"""
|
||||
@spec new(coercible_t) :: t
|
||||
def new({subject, predicate, object}), do: new(subject, predicate, object)
|
||||
|
||||
|
||||
|
@ -75,6 +87,7 @@ defmodule RDF.Triple do
|
|||
{"S", "p", 42}
|
||||
|
||||
"""
|
||||
@spec values(t | any, Statement.term_mapping) :: t_values | nil
|
||||
def values(triple, mapping \\ &Statement.default_term_mapping/1)
|
||||
|
||||
def values({subject, predicate, object}, mapping) do
|
||||
|
@ -98,6 +111,7 @@ defmodule RDF.Triple do
|
|||
position only IRIs and blank nodes allowed, while on the predicate position
|
||||
only IRIs allowed. The object position can be any RDF term.
|
||||
"""
|
||||
@spec valid?(t | any) :: boolean
|
||||
def valid?(tuple)
|
||||
def valid?({_, _, _} = triple), do: Statement.valid?(triple)
|
||||
def valid?(_), do: false
|
||||
|
|
|
@ -53,6 +53,7 @@ defmodule RDF.Utils.ResourceClassifier do
|
|||
|> Enum.map(&RDF.iri/1)
|
||||
|> MapSet.new
|
||||
|
||||
@dialyzer {:nowarn_function, property_by_rdf_type?: 1}
|
||||
defp property_by_rdf_type?(nil), do: nil
|
||||
defp property_by_rdf_type?(types) do
|
||||
not (
|
||||
|
|
|
@ -9,6 +9,7 @@ defmodule RDF.Vocabulary.Namespace do
|
|||
the `RDF.NS` module.
|
||||
"""
|
||||
|
||||
alias RDF.Datatype
|
||||
alias RDF.Utils.ResourceClassifier
|
||||
|
||||
@vocabs_dir "priv/vocabs"
|
||||
|
@ -295,6 +296,7 @@ defmodule RDF.Vocabulary.Namespace do
|
|||
terms
|
||||
end
|
||||
|
||||
@dialyzer {:nowarn_function, valid_term?: 1}
|
||||
defp valid_term?(term) do
|
||||
not MapSet.member?(@invalid_terms, term)
|
||||
end
|
||||
|
@ -567,12 +569,14 @@ defmodule RDF.Vocabulary.Namespace do
|
|||
defp vocab_term?(_), do: false
|
||||
|
||||
@doc false
|
||||
@spec term_to_iri(String.t, String.t | atom) :: RDF.IRI.t
|
||||
def term_to_iri(base_iri, term) when is_atom(term),
|
||||
do: term_to_iri(base_iri, Atom.to_string(term))
|
||||
def term_to_iri(base_iri, term),
|
||||
do: RDF.iri(base_iri <> term)
|
||||
|
||||
@doc false
|
||||
@spec vocabulary_namespace?(Datatype.t) :: boolean
|
||||
def vocabulary_namespace?(name) do
|
||||
Code.ensure_compiled?(name) && function_exported?(name, :__base_iri__, 0)
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue