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
|
||||
- a facility for the mapping of URIs of a vocabulary to Elixir modules and
|
||||
functions: `RDF.Vocabulary.Namespace`
|
||||
- a facility for the automatic generation of resource identifiers: `RDF.Resource.Generator`
|
||||
- modules for the construction of statements
|
||||
- `RDF.Triple`
|
||||
- `RDF.Quad`
|
||||
|
|
|
@ -2,6 +2,10 @@ defmodule RDF.BlankNode do
|
|||
@moduledoc """
|
||||
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>
|
||||
and <https://www.w3.org/TR/rdf11-concepts/#section-blank-nodes>
|
||||
"""
|
||||
|
@ -14,10 +18,10 @@ defmodule RDF.BlankNode do
|
|||
defstruct [:value]
|
||||
|
||||
use RDF.Resource.Generator
|
||||
alias RDF.Resource.Generator.ConfigError
|
||||
alias RDF.Resource.Generator
|
||||
|
||||
@doc """
|
||||
Creates a `RDF.BlankNode`.
|
||||
Creates a random `RDF.BlankNode`.
|
||||
"""
|
||||
@spec new :: t
|
||||
def new, do: new(:erlang.unique_integer([:positive]))
|
||||
|
@ -47,20 +51,6 @@ defmodule RDF.BlankNode do
|
|||
"""
|
||||
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 """
|
||||
Tests for value equality of blank nodes.
|
||||
|
||||
|
@ -75,6 +65,20 @@ defmodule RDF.BlankNode do
|
|||
def equal_value?(_, _),
|
||||
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
|
||||
def to_string(bnode), do: "_:#{bnode.value}"
|
||||
end
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
defmodule RDF.BlankNode.Generator do
|
||||
@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
|
||||
|
@ -11,7 +16,15 @@ defmodule RDF.BlankNode.Generator do
|
|||
@doc """
|
||||
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
|
||||
start_link({[algorithm: algorithm], []})
|
||||
|
@ -31,7 +44,7 @@ defmodule RDF.BlankNode.Generator do
|
|||
@doc """
|
||||
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
|
||||
start({[algorithm: algorithm], []})
|
||||
|
|
|
@ -1,10 +1,61 @@
|
|||
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
|
||||
|
||||
@doc """
|
||||
Generates a random resource identifier based on the given `config`.
|
||||
"""
|
||||
@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()
|
||||
|
||||
@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
|
||||
|
||||
defmacro __using__(_opts) do
|
||||
|
@ -18,11 +69,23 @@ defmodule RDF.Resource.Generator do
|
|||
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
|
||||
{generator, config} = config(:random_based, config)
|
||||
generator.generate(config)
|
||||
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
|
||||
{generator, config} = config(:value_based, config)
|
||||
generator.generate(config, value)
|
||||
|
|
|
@ -4,6 +4,54 @@
|
|||
|
||||
if Code.ensure_loaded?(UUID) 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
|
||||
|
||||
alias RDF.IRI
|
||||
|
|
Loading…
Reference in a new issue