115 lines
3.8 KiB
Elixir
115 lines
3.8 KiB
Elixir
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
|
|
quote do
|
|
@behaviour RDF.Resource.Generator
|
|
|
|
@impl RDF.Resource.Generator
|
|
def generator_config(_, config), do: config
|
|
|
|
defoverridable generator_config: 2
|
|
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)
|
|
end
|
|
|
|
defp config(id_type, config) do
|
|
{random_config, config} = Keyword.pop(config, :random_based)
|
|
{value_based_config, config} = Keyword.pop(config, :value_based)
|
|
|
|
{generator, config} =
|
|
id_type
|
|
|> merge_config(config, random_config, value_based_config)
|
|
|> Keyword.pop!(:generator)
|
|
|
|
{generator, generator.generator_config(id_type, config)}
|
|
end
|
|
|
|
defp merge_config(:random_based, config, nil, _), do: config
|
|
|
|
defp merge_config(:random_based, config, random_config, _),
|
|
do: Keyword.merge(config, random_config)
|
|
|
|
defp merge_config(:value_based, config, _, nil), do: config
|
|
|
|
defp merge_config(:value_based, config, _, value_based_config),
|
|
do: Keyword.merge(config, value_based_config)
|
|
end
|