Add documentation on RDF.Resource.Generators
This commit is contained in:
parent
78a3e25bd8
commit
7d97888971
5 changed files with 148 additions and 19 deletions
|
@ -12,6 +12,7 @@ defmodule RDF do
|
||||||
- the `RDF.Literal.Datatype` system
|
- the `RDF.Literal.Datatype` system
|
||||||
- a facility for the mapping of URIs of a vocabulary to Elixir modules and
|
- a facility for the mapping of URIs of a vocabulary to Elixir modules and
|
||||||
functions: `RDF.Vocabulary.Namespace`
|
functions: `RDF.Vocabulary.Namespace`
|
||||||
|
- a facility for the automatic generation of resource identifiers: `RDF.Resource.Generator`
|
||||||
- modules for the construction of statements
|
- modules for the construction of statements
|
||||||
- `RDF.Triple`
|
- `RDF.Triple`
|
||||||
- `RDF.Quad`
|
- `RDF.Quad`
|
||||||
|
|
|
@ -2,6 +2,10 @@ defmodule RDF.BlankNode do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
An RDF blank node (aka bnode) is a local node of a graph without an IRI.
|
An RDF blank node (aka bnode) is a local node of a graph without an IRI.
|
||||||
|
|
||||||
|
This module can also be used as `RDF.Resource.Generator` for the generation
|
||||||
|
of random identifiers, which is using the `new/0` function.
|
||||||
|
For the generation of value-based blank nodes, you can use `RDF.BlankNode.Generator`.
|
||||||
|
|
||||||
see <https://www.w3.org/TR/rdf11-primer/#section-blank-node>
|
see <https://www.w3.org/TR/rdf11-primer/#section-blank-node>
|
||||||
and <https://www.w3.org/TR/rdf11-concepts/#section-blank-nodes>
|
and <https://www.w3.org/TR/rdf11-concepts/#section-blank-nodes>
|
||||||
"""
|
"""
|
||||||
|
@ -14,10 +18,10 @@ defmodule RDF.BlankNode do
|
||||||
defstruct [:value]
|
defstruct [:value]
|
||||||
|
|
||||||
use RDF.Resource.Generator
|
use RDF.Resource.Generator
|
||||||
alias RDF.Resource.Generator.ConfigError
|
alias RDF.Resource.Generator
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Creates a `RDF.BlankNode`.
|
Creates a random `RDF.BlankNode`.
|
||||||
"""
|
"""
|
||||||
@spec new :: t
|
@spec new :: t
|
||||||
def new, do: new(:erlang.unique_integer([:positive]))
|
def new, do: new(:erlang.unique_integer([:positive]))
|
||||||
|
@ -47,20 +51,6 @@ defmodule RDF.BlankNode do
|
||||||
"""
|
"""
|
||||||
def value(%__MODULE__{} = bnode), do: bnode.value
|
def value(%__MODULE__{} = bnode), do: bnode.value
|
||||||
|
|
||||||
@impl RDF.Resource.Generator
|
|
||||||
def generate(_), do: new()
|
|
||||||
|
|
||||||
@impl RDF.Resource.Generator
|
|
||||||
def generate(_, _) do
|
|
||||||
raise(
|
|
||||||
ConfigError,
|
|
||||||
"""
|
|
||||||
Value-based resource generation is not supported by RDF.BlankNode.
|
|
||||||
Use RDF.BlankNode.Generator or another generator.
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Tests for value equality of blank nodes.
|
Tests for value equality of blank nodes.
|
||||||
|
|
||||||
|
@ -75,6 +65,20 @@ defmodule RDF.BlankNode do
|
||||||
def equal_value?(_, _),
|
def equal_value?(_, _),
|
||||||
do: nil
|
do: nil
|
||||||
|
|
||||||
|
@impl RDF.Resource.Generator
|
||||||
|
def generate(_), do: new()
|
||||||
|
|
||||||
|
@impl RDF.Resource.Generator
|
||||||
|
def generate(_, _) do
|
||||||
|
raise(
|
||||||
|
Generator.ConfigError,
|
||||||
|
"""
|
||||||
|
Value-based resource generation is not supported by RDF.BlankNode.
|
||||||
|
Use RDF.BlankNode.Generator or another generator.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
defimpl String.Chars do
|
defimpl String.Chars do
|
||||||
def to_string(bnode), do: "_:#{bnode.value}"
|
def to_string(bnode), do: "_:#{bnode.value}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
defmodule RDF.BlankNode.Generator do
|
defmodule RDF.BlankNode.Generator do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
A GenServer generates `RDF.BlankNode`s using a `RDF.BlankNode.Generator.Algorithm`.
|
A GenServer which generates `RDF.BlankNode`s using a `RDF.BlankNode.Generator.Algorithm`.
|
||||||
|
|
||||||
|
This module implements the `RDF.Resource.Generator` behaviour.
|
||||||
|
The only `RDF.Resource.Generator` configuration it requires is the process
|
||||||
|
identifier. The actual configuration of the behaviour of this generator
|
||||||
|
is done on the GenServer itself via `start_link/1` and `start/1`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
use GenServer
|
use GenServer
|
||||||
|
@ -11,7 +16,15 @@ defmodule RDF.BlankNode.Generator do
|
||||||
@doc """
|
@doc """
|
||||||
Starts a blank node generator linked to the current process.
|
Starts a blank node generator linked to the current process.
|
||||||
|
|
||||||
The state will be initialized according to the given `RDF.BlankNode.Generator.Algorithm`.
|
The `RDF.BlankNode.Generator.Algorithm` implementation is the only required
|
||||||
|
keyword option, which must be given with the `:algorithm` key or, if no other
|
||||||
|
options are required, can be given directly (instead of a keyword list).
|
||||||
|
The remaining options are used as the configuration for `init/1` of the
|
||||||
|
respective `RDF.BlankNode.Generator.Algorithm` implementation.
|
||||||
|
|
||||||
|
If you want to pass `GenServer.start_link/3` options, you'll can provide
|
||||||
|
two separate keyword lists as a tuple with the first being the `RDF.BlankNode.Generator`
|
||||||
|
configuration and the second the `GenServer.start_link/3` options.
|
||||||
"""
|
"""
|
||||||
def start_link(algorithm) when is_atom(algorithm) do
|
def start_link(algorithm) when is_atom(algorithm) do
|
||||||
start_link({[algorithm: algorithm], []})
|
start_link({[algorithm: algorithm], []})
|
||||||
|
@ -31,7 +44,7 @@ defmodule RDF.BlankNode.Generator do
|
||||||
@doc """
|
@doc """
|
||||||
Starts a blank node generator process without links (outside of a supervision tree).
|
Starts a blank node generator process without links (outside of a supervision tree).
|
||||||
|
|
||||||
The state will be initialized according to the given `RDF.BlankNode.Generator.Algorithm`.
|
The options are handled the same as `start_link/1`.
|
||||||
"""
|
"""
|
||||||
def start(algorithm) when is_atom(algorithm) do
|
def start(algorithm) when is_atom(algorithm) do
|
||||||
start({[algorithm: algorithm], []})
|
start({[algorithm: algorithm], []})
|
||||||
|
|
|
@ -1,10 +1,61 @@
|
||||||
defmodule RDF.Resource.Generator do
|
defmodule RDF.Resource.Generator do
|
||||||
|
@moduledoc """
|
||||||
|
A configurable and customizable way to generate resource identifiers.
|
||||||
|
|
||||||
|
The basis are different implementations of the behaviour defined in this
|
||||||
|
module for configurable resource identifier generation methods.
|
||||||
|
|
||||||
|
Generally two kinds of identifiers are differentiated:
|
||||||
|
|
||||||
|
1. parameter-less identifiers which are generally random
|
||||||
|
2. identifiers which are based on some value, where every attempt to create
|
||||||
|
an identifier for the same value, should produce the same identifier
|
||||||
|
|
||||||
|
Not all implementations must support both kind of identifiers.
|
||||||
|
|
||||||
|
The `RDF.Resource.Generator` module provides two `generate` functions for the
|
||||||
|
kindes of identifiers, `generate/1` for random-based and `generate/2` for
|
||||||
|
value-based identifiers.
|
||||||
|
The `config` keyword list they take must contain a `:generator` key, which
|
||||||
|
provides the module implementing the `RDF.Resource.Generator` behaviour.
|
||||||
|
All other keywords are specific to the generator implementation.
|
||||||
|
When the generator is configured differently for the different
|
||||||
|
identifier types, the identifier-type specific configuration can be put under
|
||||||
|
the keys `:random_based` and `:value_based` respectively.
|
||||||
|
The `RDF.Resource.Generator.generate` implementations will be called with the
|
||||||
|
general configuration options from the top-level merged with the identifier-type
|
||||||
|
specific configuration.
|
||||||
|
|
||||||
|
The `generate` functions however are usually not called directly.
|
||||||
|
See the [guide](https://rdf-elixir.dev/rdf-ex/resource-generators.html) on
|
||||||
|
how they are meant to be used.
|
||||||
|
|
||||||
|
The following `RDF.Resource.Generator` implementations are provided with RDF.ex:
|
||||||
|
|
||||||
|
- `RDF.BlankNode`
|
||||||
|
- `RDF.BlankNode.Generator`
|
||||||
|
- `RDF.IRI.UUID.Generator`
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
@type id_type :: :random_based | :value_based
|
@type id_type :: :random_based | :value_based
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Generates a random resource identifier based on the given `config`.
|
||||||
|
"""
|
||||||
@callback generate(config :: any) :: RDF.Resource.t()
|
@callback generate(config :: any) :: RDF.Resource.t()
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Generates a resource identifier based on the given `config` and `value`.
|
||||||
|
"""
|
||||||
@callback generate(config :: any, value :: binary) :: RDF.Resource.t()
|
@callback generate(config :: any, value :: binary) :: RDF.Resource.t()
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Allows to normalize the configuration.
|
||||||
|
|
||||||
|
This callback is optional. A default implementation is generated which
|
||||||
|
returns the configuration as-is.
|
||||||
|
"""
|
||||||
@callback generator_config(id_type, keyword) :: any
|
@callback generator_config(id_type, keyword) :: any
|
||||||
|
|
||||||
defmacro __using__(_opts) do
|
defmacro __using__(_opts) do
|
||||||
|
@ -18,11 +69,23 @@ defmodule RDF.Resource.Generator do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Generates a random resource identifier based on the given `config`.
|
||||||
|
|
||||||
|
See the [guide](https://rdf-elixir.dev/rdf-ex/resource-generators.html) on
|
||||||
|
how it is meant to be used.
|
||||||
|
"""
|
||||||
def generate(config) do
|
def generate(config) do
|
||||||
{generator, config} = config(:random_based, config)
|
{generator, config} = config(:random_based, config)
|
||||||
generator.generate(config)
|
generator.generate(config)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Generates a resource identifier based on the given `config` and `value`.
|
||||||
|
|
||||||
|
See the [guide](https://rdf-elixir.dev/rdf-ex/resource-generators.html) on
|
||||||
|
how it is meant to be used.
|
||||||
|
"""
|
||||||
def generate(config, value) do
|
def generate(config, value) do
|
||||||
{generator, config} = config(:value_based, config)
|
{generator, config} = config(:value_based, config)
|
||||||
generator.generate(config, value)
|
generator.generate(config, value)
|
||||||
|
|
|
@ -4,6 +4,54 @@
|
||||||
|
|
||||||
if Code.ensure_loaded?(UUID) do
|
if Code.ensure_loaded?(UUID) do
|
||||||
defmodule RDF.IRI.UUID.Generator do
|
defmodule RDF.IRI.UUID.Generator do
|
||||||
|
@moduledoc """
|
||||||
|
A `RDF.Resource.Generator` for various kinds of UUID-based IRI identifiers.
|
||||||
|
|
||||||
|
This generator is only available when you have defined the [elixir_uuid](https://hex.pm/packages/elixir_uuid)
|
||||||
|
package as dependency in the Mixfile of your application.
|
||||||
|
|
||||||
|
|
||||||
|
## Configuration options
|
||||||
|
|
||||||
|
- `:prefix`: The URI prefix to be prepended to the generated UUID.
|
||||||
|
It can be given also as `RDF.Vocabulary.Namespace` module.
|
||||||
|
If the `:uuid_format` is set explicitly to something other than `:urn`
|
||||||
|
(which is the default), this is a required parameter.
|
||||||
|
- `:uuid_version`: The UUID version to be used. Can be any of the
|
||||||
|
integers 1 and 4 for random-based identifiers (4 being the default) and
|
||||||
|
3 and 5 for value-based identifiers (5 being the default).
|
||||||
|
- `:uuid_format`: The format of the UUID to be generated. Can be any of the
|
||||||
|
following atoms:
|
||||||
|
- `:urn`: a standard UUID representation, prefixed with the UUID URN
|
||||||
|
(in this case the `:prefix` is not used) (the default when no `:prefix` given)
|
||||||
|
- `:default`: a standard UUID representation, appended to the `:prefix` value
|
||||||
|
(the default when a `:prefix` is given)
|
||||||
|
- `:hex`: a standard UUID without the `-` (dash) characters, appended to the
|
||||||
|
`:prefix` value
|
||||||
|
- `:uuid_namespace` (only with `:uuid_version` 3 and 5, where it is a required parameter)
|
||||||
|
|
||||||
|
When your generator configuration is just for a function producing one of
|
||||||
|
the two kinds of identifiers, you can use these options directly. Otherwise you
|
||||||
|
must provide the identifier-specific configuration under one of the keys
|
||||||
|
`:random_based` and `:value_based`.
|
||||||
|
|
||||||
|
|
||||||
|
## Example configuration
|
||||||
|
|
||||||
|
config :example, :id,
|
||||||
|
generator: RDF.IRI.UUID.Generator,
|
||||||
|
prefix: "http://example.com/",
|
||||||
|
uuid_format: :hex,
|
||||||
|
random_based: [
|
||||||
|
uuid_version: 1
|
||||||
|
],
|
||||||
|
value_based: [
|
||||||
|
uuid_version: 3,
|
||||||
|
uuid_namespace: UUID.uuid5(:url, "http://your.application.com/example")
|
||||||
|
]
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
use RDF.Resource.Generator
|
use RDF.Resource.Generator
|
||||||
|
|
||||||
alias RDF.IRI
|
alias RDF.IRI
|
||||||
|
|
Loading…
Reference in a new issue