rdf-ex/lib/rdf.ex
Marcel Otto 5819eec0cf Re-integrate XSD.ex
It turned out that the costs of separating the XSD datatypes are too high
and probably not worth the effort, since with its limited scope
probably nobody would want to use XSD.ex outside of the RDF.ex context
anyway.
2020-05-05 23:58:44 +02:00

264 lines
8.6 KiB
Elixir

defmodule RDF do
@moduledoc """
The top-level module of RDF.ex.
RDF.ex consists of:
- modules for the nodes of an RDF graph
- `RDF.Term`
- `RDF.IRI`
- `RDF.BlankNode`
- `RDF.Literal`
- a facility for the mapping of URIs of a vocabulary to Elixir modules and
functions: `RDF.Vocabulary.Namespace`
- modules for the construction of statements
- `RDF.Triple`
- `RDF.Quad`
- `RDF.Statement`
- modules for collections of statements
- `RDF.Description`
- `RDF.Graph`
- `RDF.Dataset`
- `RDF.Data`
- `RDF.List`
- `RDF.Diff`
- functions for working with RDF serializations: `RDF.Serialization`
- behaviours for the definition of RDF serialization formats
- `RDF.Serialization.Format`
- `RDF.Serialization.Decoder`
- `RDF.Serialization.Encoder`
- and the implementation of various RDF serialization formats
- `RDF.NTriples`
- `RDF.NQuads`
- `RDF.Turtle`
This top-level module provides shortcut functions for the construction of the
basic elements and structures of RDF and some general helper functions.
For a general introduction you may refer to the guides on the [homepage](https://rdf-elixir.dev).
"""
alias RDF.{IRI, Namespace, Literal, BlankNode, Triple, Quad,
Description, Graph, Dataset, PrefixMap}
import RDF.Utils.Bootstrapping
defdelegate default_base_iri(), to: RDF.IRI, as: :default_base
@standard_prefixes PrefixMap.new(
xsd: xsd_iri_base(),
rdf: rdf_iri_base(),
rdfs: rdfs_iri_base()
)
@doc """
A fixed set prefixes that will always be part of the `default_prefixes/0`.
```elixir
#{inspect(@standard_prefixes, pretty: true)}
```
See `default_prefixes/0`, if you don't want these standard prefixes to be part
of the default prefixes.
"""
def standard_prefixes(), do: @standard_prefixes
@doc """
A user-defined `RDF.PrefixMap` of prefixes to IRI namespaces.
This prefix map will be used implicitly wherever a prefix map is expected, but
not provided. For example, when you don't pass a prefix map to the Turtle serializer,
this prefix map will be used.
By default the `standard_prefixes/0` are part of this prefix map, but you can
define additional default prefixes via the `default_prefixes` compile-time
configuration.
For example:
config :rdf,
default_prefixes: %{
ex: "http://example.com/"
}
If you don't want the `standard_prefixes/0` to be part of the default prefixes,
or you want to map the standard prefixes to different namespaces (strongly discouraged!),
you can set the `use_standard_prefixes` compile-time configuration flag to `false`.
config :rdf,
use_standard_prefixes: false
"""
@default_prefixes Application.get_env(:rdf, :default_prefixes, %{}) |> PrefixMap.new()
if Application.get_env(:rdf, :use_standard_prefixes, true) do
def default_prefixes() do
PrefixMap.merge!(@standard_prefixes, @default_prefixes)
end
else
def default_prefixes() do
@default_prefixes
end
end
@doc """
Returns the `default_prefixes/0` with additional prefix mappings.
The `prefix_mappings` can be given in any format accepted by `RDF.PrefixMap.new/1`.
"""
def default_prefixes(prefix_mappings) do
default_prefixes() |> PrefixMap.merge!(prefix_mappings)
end
defdelegate read_string(content, opts), to: RDF.Serialization
defdelegate read_string!(content, opts), to: RDF.Serialization
defdelegate read_file(filename, opts \\ []), to: RDF.Serialization
defdelegate read_file!(filename, opts \\ []), to: RDF.Serialization
defdelegate write_string(content, opts), to: RDF.Serialization
defdelegate write_string!(content, opts), to: RDF.Serialization
defdelegate write_file(content, filename, opts \\ []), to: RDF.Serialization
defdelegate write_file!(content, filename, opts \\ []), to: RDF.Serialization
@doc """
Checks if the given value is a RDF resource.
## Examples
Supposed `EX` is a `RDF.Vocabulary.Namespace` and `Foo` is not.
iex> RDF.resource?(RDF.iri("http://example.com/resource"))
true
iex> RDF.resource?(EX.resource)
true
iex> RDF.resource?(EX.Resource)
true
iex> RDF.resource?(Foo.Resource)
false
iex> RDF.resource?(RDF.bnode)
true
iex> RDF.resource?(RDF.XSD.integer(42))
false
iex> RDF.resource?(42)
false
"""
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))
rescue
RDF.Namespace.UndefinedTermError -> false
end
def resource?(_), do: false
@doc """
Checks if the given value is a RDF term.
## Examples
Supposed `EX` is a `RDF.Vocabulary.Namespace` and `Foo` is not.
iex> RDF.term?(RDF.iri("http://example.com/resource"))
true
iex> RDF.term?(EX.resource)
true
iex> RDF.term?(EX.Resource)
true
iex> RDF.term?(Foo.Resource)
false
iex> RDF.term?(RDF.bnode)
true
iex> RDF.term?(RDF.XSD.integer(42))
true
iex> RDF.term?(42)
false
"""
def term?(value)
def term?(%Literal{}), do: true
def term?(value), do: resource?(value)
defdelegate uri?(value), to: IRI, as: :valid?
defdelegate iri?(value), to: IRI, as: :valid?
defdelegate uri(value), to: IRI, as: :new
defdelegate iri(value), to: IRI, as: :new
defdelegate uri!(value), to: IRI, as: :new!
defdelegate iri!(value), to: IRI, as: :new!
@doc """
Checks if the given value is a blank node.
## Examples
iex> RDF.bnode?(RDF.bnode)
true
iex> RDF.bnode?(RDF.iri("http://example.com/resource"))
false
iex> RDF.bnode?(42)
false
"""
def bnode?(%BlankNode{}), do: true
def bnode?(_), do: false
defdelegate bnode(), to: BlankNode, as: :new
defdelegate bnode(id), to: BlankNode, as: :new
defdelegate literal(value), to: Literal, as: :new
defdelegate literal(value, opts), to: Literal, as: :new
def literal?(%Literal{}), do: true
def literal?(%RDF.Literal.Generic{}), do: true
def literal?(%datatype{}), do: Literal.Datatype.Registry.datatype?(datatype)
def literal?(_), do: false
defdelegate triple(s, p, o), to: Triple, as: :new
defdelegate triple(tuple), to: Triple, as: :new
defdelegate quad(s, p, o, g), to: Quad, as: :new
defdelegate quad(tuple), to: Quad, as: :new
defdelegate description(arg), to: Description, as: :new
defdelegate description(arg1, arg2), to: Description, as: :new
defdelegate description(arg1, arg2, arg3), to: Description, as: :new
defdelegate graph(), to: Graph, as: :new
defdelegate graph(arg), to: Graph, as: :new
defdelegate graph(arg1, arg2), to: Graph, as: :new
defdelegate graph(arg1, arg2, arg3), to: Graph, as: :new
defdelegate graph(arg1, arg2, arg3, arg4), to: Graph, as: :new
defdelegate dataset(), to: Dataset, as: :new
defdelegate dataset(arg), to: Dataset, as: :new
defdelegate dataset(arg1, arg2), to: Dataset, as: :new
defdelegate diff(arg1, arg2), to: RDF.Diff
defdelegate list?(resource, graph), to: RDF.List, as: :node?
defdelegate list?(description), to: RDF.List, as: :node?
def list(native_list), do: RDF.List.from(native_list)
def list(head, %Graph{} = graph), do: RDF.List.new(head, graph)
def list(native_list, opts), do: RDF.List.from(native_list, opts)
defdelegate prefix_map(prefixes), to: RDF.PrefixMap, as: :new
defdelegate langString(value, opts), to: RDF.LangString, as: :new
defdelegate lang_string(value, opts), to: RDF.LangString, as: :new
for term <- ~w[type subject predicate object first rest value]a do
defdelegate unquote(term)(), to: RDF.NS.RDF
defdelegate unquote(term)(s, o), to: RDF.NS.RDF
defdelegate unquote(term)(s, o1, o2), to: RDF.NS.RDF
defdelegate unquote(term)(s, o1, o2, o3), to: RDF.NS.RDF
defdelegate unquote(term)(s, o1, o2, o3, o4), to: RDF.NS.RDF
defdelegate unquote(term)(s, o1, o2, o3, o4, o5), to: RDF.NS.RDF
end
defdelegate langString(), to: RDF.NS.RDF
defdelegate lang_string(), to: RDF.NS.RDF, as: :langString
defdelegate unquote(nil)(), to: RDF.NS.RDF
defdelegate __base_iri__(), to: RDF.NS.RDF
end