Clean up serialization API, code and documentation

This commit is contained in:
Marcel Otto 2020-11-03 13:01:47 +01:00
parent 0dc8e383ce
commit 3d28ec9085
12 changed files with 222 additions and 188 deletions

View file

@ -181,7 +181,7 @@ defmodule RDF.IRI do
Characters additionally allowed in IRI references are treated in the same way that unreserved
characters are treated in URI references, per [section 6.5 of RFC3987](http://tools.ietf.org/html/rfc3987#section-6.5)
If the given is not an absolute IRI `nil` is returned.
If the given `base` is not an absolute IRI `nil` is returned.
"""
@spec absolute(coercible, coercible) :: t | nil
def absolute(iri, base) do

View file

@ -1,7 +1,7 @@
defmodule RDF.Serialization.Decoder do
@moduledoc """
A behaviour for decoders of strings encoded in a specific `RDF.Serialization` format.
"""
@moduledoc !"""
A behaviour for decoders of strings encoded in a specific `RDF.Serialization` format.
"""
alias RDF.{Dataset, Graph}
@ -11,7 +11,7 @@ defmodule RDF.Serialization.Decoder do
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs.
"""
@callback decode(String.t(), keyword | map) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
@callback decode(String.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
@doc """
Decodes a serialized `RDF.Graph` or `RDF.Dataset` from the given string.
@ -21,14 +21,14 @@ defmodule RDF.Serialization.Decoder do
Note: The `__using__` macro automatically provides an overridable default
implementation based on the non-bang `decode` function.
"""
@callback decode!(String.t(), keyword | map) :: RDF.Graph.t() | RDF.Dataset.t()
@callback decode!(String.t(), keyword) :: RDF.Graph.t() | RDF.Dataset.t()
defmacro __using__(_) do
quote bind_quoted: [], unquote: true do
@behaviour unquote(__MODULE__)
@impl unquote(__MODULE__)
@spec decode!(String.t(), keyword | map) :: RDF.Graph.t() | RDF.Dataset.t()
@spec decode!(String.t(), keyword) :: RDF.Graph.t() | RDF.Dataset.t()
def decode!(content, opts \\ []) do
case decode(content, opts) do
{:ok, data} -> data
@ -36,7 +36,7 @@ defmodule RDF.Serialization.Decoder do
end
end
defoverridable decode!: 2
defoverridable unquote(__MODULE__)
end
end
end

View file

@ -1,29 +1,25 @@
defmodule RDF.Serialization.Encoder do
@moduledoc """
A behaviour for encoders of `RDF.Graph`s or `RDF.Dataset`s in a specific
`RDF.Serialization` format.
"""
alias RDF.{Dataset, Graph, Description}
@moduledoc !"""
A behaviour for encoders of RDF data structures in a specific `RDF.Serialization` format.
"""
@doc """
Encodes a `RDF.Graph` or `RDF.Dataset`.
Serializes a RDF data structure into a string.
It returns an `{:ok, string}` tuple, with `string` being the serialized
`RDF.Graph` or `RDF.Dataset`, or `{:error, reason}` if an error occurs.
It should return an `{:ok, string}` tuple, with `string` being the serialized
RDF data structure, or `{:error, reason}` if an error occurs.
"""
@callback encode(Description.t() | Graph.t() | Dataset.t(), keyword | map) ::
{:ok, String.t()} | {:error, any}
@callback encode(RDF.Data.t(), keyword) :: {:ok, String.t()} | {:error, any}
@doc """
Encodes a `RDF.Graph` or `RDF.Dataset`.
Serializes a RDF data structure into a string.
As opposed to `encode`, it raises an exception if an error occurs.
Note: The `__using__` macro automatically provides an overridable default
implementation based on the non-bang `encode` function.
"""
@callback encode!(Description.t() | Graph.t() | Dataset.t(), keyword | map) :: String.t()
@callback encode!(RDF.Data.t(), keyword) :: String.t()
defmacro __using__(_) do
quote bind_quoted: [], unquote: true do
@ -39,8 +35,7 @@ defmodule RDF.Serialization.Encoder do
end
end
defoverridable encode!: 1
defoverridable encode!: 2
defoverridable unquote(__MODULE__)
end
end
end

View file

@ -2,7 +2,7 @@ defmodule RDF.Serialization.Format do
@moduledoc """
A behaviour for RDF serialization formats.
A `RDF.Serialization` for a format can be implemented like this
A serialization format can be implemented like this
defmodule SomeFormat do
use RDF.Serialization.Format
@ -28,7 +28,8 @@ defmodule RDF.Serialization.Format do
`decoder/0` functions in your `RDF.Serialization.Format` module.
"""
alias RDF.{Dataset, Graph, Description}
alias RDF.{Dataset, Graph}
alias RDF.Serialization.{Reader, Writer}
@doc """
An IRI of the serialization format.
@ -73,41 +74,113 @@ defmodule RDF.Serialization.Format do
@impl unquote(__MODULE__)
def encoder, do: @encoder
defoverridable decoder: 0, encoder: 0
defoverridable unquote(__MODULE__)
@decoder_doc_ref """
See the [module documentation of the decoder](`#{@decoder}`) for the
available format-specific options, all of which can be used in this
function and will be passed them through to the decoder.
"""
@doc """
Reads and decodes a serialized graph or dataset from a string.
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs.
#{@decoder_doc_ref}
"""
@spec read_string(String.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
def read_string(content, opts \\ []),
do: RDF.Serialization.Reader.read_string(decoder(), content, opts)
def read_string(content, opts \\ []), do: Reader.read_string(decoder(), content, opts)
@doc """
Reads and decodes a serialized graph or dataset from a string.
As opposed to `read_string/2`, it raises an exception if an error occurs.
#{@decoder_doc_ref}
"""
@spec read_string!(String.t(), keyword) :: Graph.t() | Dataset.t()
def read_string!(content, opts \\ []),
do: RDF.Serialization.Reader.read_string!(decoder(), content, opts)
def read_string!(content, opts \\ []), do: Reader.read_string!(decoder(), content, opts)
@doc """
Reads and decodes a serialized graph or dataset from a file.
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs.
#{@decoder_doc_ref}
"""
@spec read_file(Path.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
def read_file(file, opts \\ []),
do: RDF.Serialization.Reader.read_file(decoder(), file, opts)
def read_file(file, opts \\ []), do: Reader.read_file(decoder(), file, opts)
@doc """
Reads and decodes a serialized graph or dataset from a file.
As opposed to `read_file/2`, it raises an exception if an error occurs.
#{@decoder_doc_ref}
"""
@spec read_file!(Path.t(), keyword) :: Graph.t() | Dataset.t()
def read_file!(file, opts \\ []),
do: RDF.Serialization.Reader.read_file!(decoder(), file, opts)
def read_file!(file, opts \\ []), do: Reader.read_file!(decoder(), file, opts)
@spec write_string(Description.t() | Graph.t() | Dataset.t(), keyword) ::
{:ok, String.t()} | {:error, any}
def write_string(data, opts \\ []),
do: RDF.Serialization.Writer.write_string(encoder(), data, opts)
@encoder_doc_ref """
See the [module documentation of the encoder](`#{@encoder}`) for the
available format-specific options, all of which can be used in this
function and will be passed them through to the encoder.
"""
@spec write_string!(Description.t() | Graph.t() | Dataset.t(), keyword) :: String.t()
def write_string!(data, opts \\ []),
do: RDF.Serialization.Writer.write_string!(encoder(), data, opts)
@doc """
Serializes a RDF data structure to a string.
@spec write_file(Description.t() | Graph.t() | Dataset.t(), Path.t(), keyword) ::
:ok | {:error, any}
def write_file(data, path, opts \\ []),
do: RDF.Serialization.Writer.write_file(encoder(), data, path, opts)
It returns an `{:ok, string}` tuple, with `string` being the serialized graph or
dataset, or `{:error, reason}` if an error occurs.
@spec write_file!(Description.t() | Graph.t() | Dataset.t(), Path.t(), keyword) :: :ok
def write_file!(data, path, opts \\ []),
do: RDF.Serialization.Writer.write_file!(encoder(), data, path, opts)
#{@encoder_doc_ref}
"""
@spec write_string(RDF.Data.t(), keyword) :: {:ok, String.t()} | {:error, any}
def write_string(data, opts \\ []), do: Writer.write_string(encoder(), data, opts)
@doc """
Serializes a RDF data structure to a string.
As opposed to `write_string/2`, it raises an exception if an error occurs.
#{@encoder_doc_ref}
"""
@spec write_string!(RDF.Data.t(), keyword) :: String.t()
def write_string!(data, opts \\ []), do: Writer.write_string!(encoder(), data, opts)
@doc """
Serializes a RDF data structure to a file.
It returns `:ok` if successful or `{:error, reason}` if an error occurs.
## Options
General serialization-independent options:
- `:force` - If not set to `true`, an error is raised when the given file
already exists (default: `false`)
- `:file_mode` - A list with the Elixir `File.open` modes to be used for writing
(default: `[:write, :exclusive]`)
#{@encoder_doc_ref}
"""
@spec write_file(RDF.Data.t(), Path.t(), keyword) :: :ok | {:error, any}
def write_file(data, path, opts \\ []), do: Writer.write_file(encoder(), data, path, opts)
@doc """
Serializes a RDF data structure to a file.
As opposed to `write_file/3`, it raises an exception if an error occurs.
See `write_file/3` for the available format-independent options.
#{@encoder_doc_ref}
"""
@spec write_file!(RDF.Data.t(), Path.t(), keyword) :: :ok
def write_file!(data, path, opts \\ []), do: Writer.write_file!(encoder(), data, path, opts)
@before_compile unquote(__MODULE__)
end

View file

@ -1,41 +1,24 @@
defmodule RDF.Serialization.Reader do
@moduledoc """
General functions for reading a `RDF.Graph` or `RDF.Dataset` from a serialization file or encoded-string.
@moduledoc !"""
General functions for reading a `RDF.Graph` or `RDF.Dataset` from a serialization file, stream or encoded-string.
You probably won't use these functions directly, but instead use the automatically
generated functions with same name on a `RDF.Serialization.Format`, which implicitly
use the proper `RDF.Serialization.Decoder` module.
"""
These functions are not intended for direct use, but instead via the automatically
generated functions with the same name on a `RDF.Serialization.Format`, which
implicitly use the proper `RDF.Serialization.Decoder` module.
"""
alias RDF.{Dataset, Graph}
@doc """
Reads and decodes a serialized graph or dataset from a string.
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs.
"""
@spec read_string(module, String.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
def read_string(decoder, content, opts \\ []) do
decoder.decode(content, opts)
end
@doc """
Reads and decodes a serialized graph or dataset from a string.
As opposed to `read_string`, it raises an exception if an error occurs.
"""
@spec read_string!(module, String.t(), keyword) :: Graph.t() | Dataset.t()
def read_string!(decoder, content, opts \\ []) do
decoder.decode!(content, opts)
end
@doc """
Reads and decodes a serialized graph or dataset from a file.
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs.
"""
@spec read_file(module, Path.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
def read_file(decoder, file, opts \\ []) do
case File.read(file) do
@ -44,15 +27,9 @@ defmodule RDF.Serialization.Reader do
end
end
@doc """
Reads and decodes a serialized graph or dataset from a file.
As opposed to `read_file`, it raises an exception if an error occurs.
"""
@spec read_file!(module, Path.t(), keyword) :: Graph.t() | Dataset.t()
def read_file!(decoder, file, opts \\ []) do
with content = File.read!(file) do
read_string!(decoder, content, opts)
end
content = File.read!(file)
read_string!(decoder, content, opts)
end
end

View file

@ -1,6 +1,15 @@
defmodule RDF.Serialization do
@moduledoc """
General functions for working with RDF serializations.
Functions for working with RDF serializations generically.
Besides some reflection functions regarding available serialization formats,
this module includes the full serialization reader and writer API from the
serialization format modules.
As opposed to calling the reader and writer functions statically on the
serialization format module, they can be used more dynamically on this module
either by providing the format by name or media type with the `:format` option
or in the case of the read and write function on files by relying on detection
of the format by file extension.
"""
alias RDF.{Dataset, Graph}
@ -22,7 +31,7 @@ defmodule RDF.Serialization do
## Examples
iex> RDF.Serialization.formats
[RDF.Turtle, JSON.LD, RDF.NTriples, RDF.NQuads]
#{inspect(@formats)}
"""
@spec formats :: [format]
@ -116,13 +125,16 @@ defmodule RDF.Serialization do
end
@doc """
Reads and decodes a serialized graph or dataset from a string.
The format must be specified with the `format` option and a format name or the
`media_type` option and the media type of the format.
Deserializes a graph or dataset from a string.
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs.
The format must be specified with the `format` option and a format name or the
`media_type` option and the media type of the format.
Please refer to the documentation of the decoder of a RDF serialization format
for format-specific options.
"""
@spec read_string(String.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
def read_string(content, opts) do
@ -132,12 +144,15 @@ defmodule RDF.Serialization do
end
@doc """
Reads and decodes a serialized graph or dataset from a string.
Deserializes a graph or dataset from a string.
The format must be specified with the `format` option and a format name or the
As opposed to `read_string/2`, it raises an exception if an error occurs.
The format must be specified with the `format` option and a format name or the
`media_type` option and the media type of the format.
As opposed to `read_string`, it raises an exception if an error occurs.
Please refer to the documentation of the decoder of a RDF serialization format
for format-specific options.
"""
@spec read_string!(String.t(), keyword) :: Graph.t() | Dataset.t()
def read_string!(content, opts) do
@ -149,14 +164,17 @@ defmodule RDF.Serialization do
end
@doc """
Reads and decodes a serialized graph or dataset from a file.
The format can be specified with the `format` option and a format name or the
`media_type` option and the media type of the format. If none of these are
given, the format gets inferred from the extension of the given file name.
Deserializes a graph or dataset from a file.
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs.
The format can be specified with the `format` option and a format name or the
`media_type` option and the media type of the format. If none of these are
given, the format gets inferred from the extension of the given file name.
Please refer to the documentation of the decoder of a RDF serialization format
for format-specific options.
"""
@spec read_file(Path.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
def read_file(file, opts \\ []) do
@ -166,13 +184,16 @@ defmodule RDF.Serialization do
end
@doc """
Reads and decodes a serialized graph or dataset from a file.
Deserializes a graph or dataset from a file.
As opposed to `read_file/2`, it raises an exception if an error occurs.
The format can be specified with the `format` option and a format name or the
`media_type` option and the media type of the format. If none of these are
given, the format gets inferred from the extension of the given file name.
As opposed to `read_file`, it raises an exception if an error occurs.
Please refer to the documentation of the decoder of a RDF serialization format
for format-specific options.
"""
@spec read_file!(Path.t(), keyword) :: Graph.t() | Dataset.t()
def read_file!(file, opts \\ []) do
@ -184,13 +205,16 @@ defmodule RDF.Serialization do
end
@doc """
Encodes and writes a graph or dataset to a string.
The format must be specified with the `format` option and a format name or the
`media_type` option and the media type of the format.
Serializes a RDF data structure to a string.
It returns an `{:ok, string}` tuple, with `string` being the serialized graph or
dataset, or `{:error, reason}` if an error occurs.
The format must be specified with the `format` option and a format name or the
`media_type` option and the media type of the format.
Please refer to the documentation of the encoder of a RDF serialization format
for format-specific options.
"""
@spec write_string(RDF.Data.t(), keyword) :: {:ok, String.t()} | {:error, any}
def write_string(data, opts) do
@ -200,12 +224,15 @@ defmodule RDF.Serialization do
end
@doc """
Encodes and writes a graph or dataset to a string.
Serializes a RDF data structure to a string.
The format must be specified with the `format` option and a format name or the
As opposed to `write_string/2`, it raises an exception if an error occurs.
The format must be specified with the `format` option and a format name or the
`media_type` option and the media type of the format.
As opposed to `write_string`, it raises an exception if an error occurs.
Please refer to the documentation of the encoder of a RDF serialization format
for format-specific options.
"""
@spec write_string!(RDF.Data.t(), keyword) :: String.t()
def write_string!(data, opts) do
@ -217,7 +244,11 @@ defmodule RDF.Serialization do
end
@doc """
Encodes and writes a graph or dataset to a file.
Serializes a RDF data structure to a file.
It returns `:ok` if successful or `{:error, reason}` if an error occurs.
## Options
The format can be specified with the `format` option and a format name or the
`media_type` option and the media type of the format. If none of these are
@ -228,9 +259,10 @@ defmodule RDF.Serialization do
- `:force` - If not set to `true`, an error is raised when the given file
already exists (default: `false`)
- `:file_mode` - A list with the Elixir `File.open` modes to be used for writing
(default: `[:utf8, :write]`)
(default: `[:write, :exclusive]`)
It returns `:ok` if successful or `{:error, reason}` if an error occurs.
Please refer to the documentation of the encoder of a RDF serialization format
for format-specific options.
"""
@spec write_file(RDF.Data.t(), Path.t(), keyword) :: :ok | {:error, any}
def write_file(data, path, opts \\ []) do
@ -240,15 +272,14 @@ defmodule RDF.Serialization do
end
@doc """
Encodes and writes a graph or dataset to a file.
Serializes a RDF data structure to a file.
The format can be specified with the `format` option and a format name or the
`media_type` option and the media type of the format. If none of these are
given, the format gets inferred from the extension of the given file name.
As opposed to `write_file/3`, it raises an exception if an error occurs.
See `write_file` for a list of other available options.
See `write_file/3` for the available format-independent options.
As opposed to `write_file`, it raises an exception if an error occurs.
Please refer to the documentation of the encoder of a RDF serialization format
for format-specific options.
"""
@spec write_file!(RDF.Data.t(), Path.t(), keyword) :: :ok
def write_file!(data, path, opts \\ []) do

View file

@ -1,75 +1,44 @@
defmodule RDF.Serialization.Writer do
@moduledoc """
General functions for writing the statements of a `RDF.Graph` or `RDF.Dataset` to a serialization file or string.
@moduledoc !"""
General functions for writing the statements of a RDF data structure to a file, string or stream.
You probably won't use these functions directly, but instead use the automatically
generated functions with same name on a `RDF.Serialization.Format`, which implicitly
use the proper `RDF.Serialization.Encoder` module.
"""
These functions are not intended for direct use, but instead via the automatically
generated functions with the same name on a `RDF.Serialization.Format`, which
implicitly use the proper `RDF.Serialization.Encoder` module.
"""
@doc """
Encodes and writes a graph or dataset to a string.
@default_file_mode ~w[write exclusive]a
It returns an `{:ok, string}` tuple, with `string` being the serialized graph or
dataset, or `{:error, reason}` if an error occurs.
"""
@spec write_string(module, RDF.Data.t(), keyword) ::
{:ok, String.t()} | {:error, any}
@spec write_string(module, RDF.Data.t(), keyword) :: {:ok, String.t()} | {:error, any}
def write_string(encoder, data, opts \\ []) do
encoder.encode(data, opts)
end
@doc """
Encodes and writes a graph or dataset to a string.
As opposed to `write_string`, it raises an exception if an error occurs.
"""
@spec write_string!(module, RDF.Data.t(), keyword) :: String.t()
def write_string!(encoder, data, opts \\ []) do
encoder.encode!(data, opts)
end
@doc """
Encodes and writes a graph or dataset to a file.
General available serialization-independent options:
- `:force` - If not set to `true`, an error is raised when the given file
already exists (default: `false`)
- `:file_mode` - A list with the Elixir `File.open` modes to be used for writing
(default: `[:write, :exclusive]`)
It returns `:ok` if successful or `{:error, reason}` if an error occurs.
"""
@spec write_file(module, RDF.Data.t(), Path.t(), keyword) ::
:ok | {:error, any}
@spec write_file(module, RDF.Data.t(), Path.t(), keyword) :: :ok | {:error, any}
def write_file(encoder, data, path, opts \\ []) do
with {:ok, encoded_string} <- write_string(encoder, data, opts) do
File.write(path, encoded_string, file_mode(encoder, opts))
end
end
@doc """
Encodes and writes a graph or dataset to a file.
See `write_file` for a list of available options.
As opposed to `write_file`, it raises an exception if an error occurs.
"""
@spec write_file!(module, RDF.Data.t(), Path.t(), keyword) :: :ok
def write_file!(encoder, data, path, opts \\ []) do
with encoded_string = write_string!(encoder, data, opts) do
File.write!(path, encoded_string, file_mode(encoder, opts))
end
encoded_string = write_string!(encoder, data, opts)
File.write!(path, encoded_string, file_mode(encoder, opts))
end
defp file_mode(_encoder, opts) do
with file_mode = Keyword.get(opts, :file_mode, ~w[write exclusive]a) do
if Keyword.get(opts, :force) do
List.delete(file_mode, :exclusive)
else
file_mode
end
file_mode = Keyword.get(opts, :file_mode, @default_file_mode)
if Keyword.get(opts, :force) do
List.delete(file_mode, :exclusive)
else
file_mode
end
end
end

View file

@ -5,10 +5,10 @@ defmodule RDF.NQuads.Decoder do
import RDF.Serialization.ParseHelper, only: [error_description: 1]
alias RDF.{Dataset, Graph}
alias RDF.Dataset
@impl RDF.Serialization.Decoder
@spec decode(String.t(), keyword | map) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
@spec decode(String.t(), keyword) :: {:ok, Dataset.t()} | {:error, any}
def decode(content, _opts \\ []) do
with {:ok, tokens, _} <- tokenize(content),
{:ok, ast} <- parse(tokens) do
@ -24,13 +24,11 @@ defmodule RDF.NQuads.Decoder do
end
end
defp tokenize(content), do: content |> to_charlist |> :ntriples_lexer.string()
defp tokenize(content), do: content |> to_charlist() |> :ntriples_lexer.string()
defp parse(tokens), do: tokens |> :nquads_parser.parse()
defp build_dataset(ast) do
Enum.reduce(ast, RDF.Dataset.new(), fn quad, dataset ->
RDF.Dataset.add(dataset, quad)
end)
Enum.reduce(ast, Dataset.new(), &Dataset.add(&2, &1))
end
end

View file

@ -3,14 +3,14 @@ defmodule RDF.NQuads.Encoder do
use RDF.Serialization.Encoder
alias RDF.{Dataset, Graph, Statement}
alias RDF.Statement
@impl RDF.Serialization.Encoder
@callback encode(Graph.t() | Dataset.t(), keyword | map) :: {:ok, String.t()} | {:error, any}
@callback encode(RDF.Data.t(), keyword) :: {:ok, String.t()} | {:error, any}
def encode(data, _opts \\ []) do
result =
data
|> Enum.reduce([], fn statement, result -> [statement(statement) | result] end)
|> Enum.reduce([], &[statement(&1) | &2])
|> Enum.reverse()
|> Enum.join("\n")

View file

@ -5,10 +5,10 @@ defmodule RDF.NTriples.Decoder do
import RDF.Serialization.ParseHelper, only: [error_description: 1]
alias RDF.{Dataset, Graph}
alias RDF.Graph
@impl RDF.Serialization.Decoder
@spec decode(String.t(), keyword | map) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
@spec decode(String.t(), keyword) :: {:ok, Graph.t()} | {:error, any}
def decode(content, _opts \\ []) do
with {:ok, tokens, _} <- tokenize(content),
{:ok, ast} <- parse(tokens) do
@ -24,13 +24,11 @@ defmodule RDF.NTriples.Decoder do
end
end
defp tokenize(content), do: content |> to_charlist |> :ntriples_lexer.string()
defp tokenize(content), do: content |> to_charlist() |> :ntriples_lexer.string()
defp parse(tokens), do: tokens |> :ntriples_parser.parse()
defp build_graph(ast) do
Enum.reduce(ast, RDF.Graph.new(), fn triple, graph ->
RDF.Graph.add(graph, triple)
end)
Enum.reduce(ast, Graph.new(), &Graph.add(&2, &1))
end
end

View file

@ -3,16 +3,14 @@ defmodule RDF.NTriples.Encoder do
use RDF.Serialization.Encoder
alias RDF.{BlankNode, Dataset, Graph, IRI, XSD, Literal, Statement, Triple, LangString}
alias RDF.{BlankNode, IRI, XSD, Literal, Statement, Triple, LangString}
@impl RDF.Serialization.Encoder
@callback encode(Graph.t() | Dataset.t(), keyword | map) :: {:ok, String.t()} | {:error, any}
@callback encode(RDF.Data.t(), keyword) :: {:ok, String.t()} | {:error, any}
def encode(data, _opts \\ []) do
result =
data
|> Enum.reduce([], fn statement, result ->
[statement(statement) | result]
end)
|> Enum.reduce([], &[statement(&1) | &2])
|> Enum.reverse()
|> Enum.join("\n")

View file

@ -5,7 +5,7 @@ defmodule RDF.Turtle.Decoder do
import RDF.Serialization.ParseHelper, only: [error_description: 1]
alias RDF.{Dataset, Graph, IRI}
alias RDF.{Graph, IRI}
defmodule State do
defstruct base_iri: nil, namespaces: %{}, bnode_counter: 0
@ -24,16 +24,11 @@ defmodule RDF.Turtle.Decoder do
end
@impl RDF.Serialization.Decoder
@spec decode(String.t(), keyword | map) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
def decode(content, opts \\ %{})
def decode(content, opts) when is_list(opts),
do: decode(content, Map.new(opts))
def decode(content, opts) do
@spec decode(String.t(), keyword) :: {:ok, Graph.t()} | {:error, any}
def decode(content, opts \\ []) do
with {:ok, tokens, _} <- tokenize(content),
{:ok, ast} <- parse(tokens),
base_iri = Map.get(opts, :base, Map.get(opts, :base_iri, RDF.default_base_iri())) do
base_iri = Keyword.get(opts, :base, Keyword.get(opts, :base_iri, RDF.default_base_iri())) do
build_graph(ast, base_iri && RDF.iri(base_iri))
else
{:error, {error_line, :turtle_lexer, error_descriptor}, _error_line_again} ->