Merge pull request #7 from rustra/fix_dialyzer_warnings

Fix the rest dialyzer warnings
This commit is contained in:
Marcel Otto 2020-03-11 00:11:53 +01:00 committed by GitHub
commit 625cec9d28
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 159 additions and 54 deletions

View file

@ -24,7 +24,7 @@ defmodule RDF.Datatype do
@doc """
Produces the lexical form of a value.
"""
@callback canonical_lexical(any) :: String.t | nil
@callback canonical_lexical(Literal.literal_value) :: String.t | nil
@doc """
Produces the lexical form of an invalid value of a typed Literal.
@ -51,7 +51,7 @@ defmodule RDF.Datatype do
of the lexical value space of an `xsd:boolean`, so the `RDF.Boolean`
implementation of this datatype calls `super`.
"""
@callback convert(any, keyword) :: any
@callback convert(any, map) :: any
@doc """
@ -60,13 +60,13 @@ defmodule RDF.Datatype do
If the given literal is invalid or can not be converted into this datatype
`nil` is returned.
"""
@callback cast(Literal.t) :: Literal.t | nil
@callback cast(Literal.t | any) :: Literal.t | nil
@doc """
Determines if the value of a `RDF.Literal` is a member of lexical value space of its datatype.
"""
@callback valid?(literal :: Literal.t) :: boolean | nil
@callback valid?(Literal.t) :: boolean | nil
@doc """
Checks if the value of two `RDF.Literal`s of this datatype are equal.
@ -78,7 +78,7 @@ defmodule RDF.Datatype do
The default implementation of the `_using__` macro compares the values of the
`canonical/1` forms of the given literals of this datatype.
"""
@callback equal_value?(literal1 :: Literal.t, literal2 :: Literal.t) :: boolean | nil
@callback equal_value?(Literal.t, Literal.t) :: boolean | nil
@doc """
Compares two `RDF.Literal`s.
@ -94,7 +94,7 @@ defmodule RDF.Datatype do
The default implementation of the `_using__` macro compares the values of the
`canonical/1` forms of the given literals of this datatype.
"""
@callback compare(literal1 :: Literal.t, literal2 :: Literal.t) :: :lt | :gt | :eq | :indeterminate | nil
@callback compare(Literal.t, Literal.t) :: :lt | :gt | :eq | :indeterminate | nil
@lang_string RDF.iri("http://www.w3.org/1999/02/22-rdf-syntax-ns#langString")
@ -122,7 +122,7 @@ defmodule RDF.Datatype do
The IRIs of all datatypes with a `RDF.Datatype` defined.
"""
@spec ids :: [IRI.t]
def ids, do: Map.keys(@mapping)
def ids, do: Map.keys(@mapping)
@doc """
All defined `RDF.Datatype` modules.
@ -151,6 +151,7 @@ defmodule RDF.Datatype do
def id, do: @id
@spec new(any, map | keyword) :: Literal.t
def new(value, opts \\ %{})
def new(value, opts) when is_list(opts),
@ -170,6 +171,8 @@ defmodule RDF.Datatype do
end
@dialyzer {:nowarn_function, build_literal_by_value: 2}
@spec build_literal_by_value(any, map) :: Literal.t
def build_literal_by_value(value, opts) do
case convert(value, opts) do
nil ->
@ -179,6 +182,7 @@ defmodule RDF.Datatype do
end
end
@dialyzer {:nowarn_function, build_literal_by_lexical: 2}
def build_literal_by_lexical(lexical, opts) do
case convert(lexical, opts) do
nil ->
@ -192,6 +196,7 @@ defmodule RDF.Datatype do
end
end
@spec build_literal(Literal.literal_value | nil, String.t | nil, map) :: Literal.t
def build_literal(value, lexical, %{canonicalize: true} = opts) do
build_literal(value, lexical, Map.delete(opts, :canonicalize))
|> canonical
@ -208,11 +213,11 @@ defmodule RDF.Datatype do
@impl unquote(__MODULE__)
def lexical(literal)
def lexical(%RDF.Literal{value: value, uncanonical_lexical: nil}) do
def lexical(%Literal{value: value, uncanonical_lexical: nil}) do
canonical_lexical(value)
end
def lexical(%RDF.Literal{uncanonical_lexical: lexical}) do
def lexical(%Literal{uncanonical_lexical: lexical}) do
lexical
end
@ -250,7 +255,7 @@ defmodule RDF.Datatype do
canonical(literal1).value == canonical(literal2).value
end
def equal_value?(%RDF.Literal{} = left, right) when not is_nil(right) do
def equal_value?(%Literal{} = left, right) when not is_nil(right) do
unless RDF.Term.term?(right) do
equal_value?(left, RDF.Term.coerce(right))
end
@ -259,9 +264,9 @@ defmodule RDF.Datatype do
def equal_value?(_, _), do: nil
def less_than?(literal1, literal2), do: RDF.Literal.less_than?(literal1, literal2)
def less_than?(literal1, literal2), do: Literal.less_than?(literal1, literal2)
def greater_than?(literal1, literal2), do: RDF.Literal.greater_than?(literal1, literal2)
def greater_than?(literal1, literal2), do: Literal.greater_than?(literal1, literal2)
@impl unquote(__MODULE__)

View file

@ -5,12 +5,14 @@ defmodule RDF.Boolean do
use RDF.Datatype, id: RDF.Datatype.NS.XSD.boolean
import RDF.Literal.Guards
import Literal.Guards
@type value :: boolean
@type input :: value | String.t | number
@impl RDF.Datatype
@spec convert(input | any, map) :: value | nil
def convert(value, opts)
def convert(value, _) when is_boolean(value), do: value
@ -35,9 +37,9 @@ defmodule RDF.Boolean do
@impl RDF.Datatype
def cast(literal)
def cast(%RDF.Literal{datatype: datatype} = literal) do
def cast(%Literal{datatype: datatype} = literal) do
cond do
not RDF.Literal.valid?(literal) ->
not Literal.valid?(literal) ->
nil
is_xsd_boolean(datatype) ->
@ -92,11 +94,12 @@ defmodule RDF.Boolean do
see <https://www.w3.org/TR/xpath-functions/#func-not>
"""
@spec fn_not(Literal.t | any) :: Literal.t | nil
def fn_not(value) do
case ebv(value) do
%RDF.Literal{value: true} -> RDF.Boolean.Value.false
%RDF.Literal{value: false} -> RDF.Boolean.Value.true
nil -> nil
%Literal{value: true} -> RDF.Boolean.Value.false
%Literal{value: false} -> RDF.Boolean.Value.true
nil -> nil
end
end
@ -123,20 +126,22 @@ defmodule RDF.Boolean do
see <https://www.w3.org/TR/sparql11-query/#func-logical-and>
"""
@spec logical_and(Literal.t | any, Literal.t | any) ::
Literal.t | nil
def logical_and(left, right) do
case ebv(left) do
%RDF.Literal{value: false} ->
%Literal{value: false} ->
RDF.false
%RDF.Literal{value: true} ->
%Literal{value: true} ->
case ebv(right) do
%RDF.Literal{value: true} -> RDF.true
%RDF.Literal{value: false} -> RDF.false
nil -> nil
%Literal{value: true} -> RDF.true
%Literal{value: false} -> RDF.false
nil -> nil
end
nil ->
if match?(%RDF.Literal{value: false}, ebv(right)) do
if match?(%Literal{value: false}, ebv(right)) do
RDF.false
end
end
@ -165,20 +170,22 @@ defmodule RDF.Boolean do
see <https://www.w3.org/TR/sparql11-query/#func-logical-or>
"""
@spec logical_or(Literal.t | any, Literal.t | any) ::
Literal.t | nil
def logical_or(left, right) do
case ebv(left) do
%RDF.Literal{value: true} ->
%Literal{value: true} ->
RDF.true
%RDF.Literal{value: false} ->
%Literal{value: false} ->
case ebv(right) do
%RDF.Literal{value: true} -> RDF.true
%RDF.Literal{value: false} -> RDF.false
%Literal{value: true} -> RDF.true
%Literal{value: false} -> RDF.false
nil -> nil
end
nil ->
if match?(%RDF.Literal{value: true}, ebv(right)) do
if match?(%Literal{value: true}, ebv(right)) do
RDF.true
end
end
@ -201,23 +208,24 @@ defmodule RDF.Boolean do
- <https://www.w3.org/TR/sparql11-query/#ebv>
"""
@spec ebv(Literal.t | any) :: Literal.t | nil
def ebv(value)
def ebv(true), do: RDF.Boolean.Value.true
def ebv(false), do: RDF.Boolean.Value.false
def ebv(%RDF.Literal{value: nil, datatype: @xsd_boolean}), do: RDF.Boolean.Value.false
def ebv(%RDF.Literal{datatype: @xsd_boolean} = literal), do: literal
def ebv(%Literal{value: nil, datatype: @xsd_boolean}), do: RDF.Boolean.Value.false
def ebv(%Literal{datatype: @xsd_boolean} = literal), do: literal
def ebv(%RDF.Literal{datatype: datatype} = literal) do
def ebv(%Literal{datatype: datatype} = literal) do
cond do
RDF.Numeric.type?(datatype) ->
if RDF.Literal.valid?(literal) and
if Literal.valid?(literal) and
not (literal.value == 0 or literal.value == :nan),
do: RDF.Boolean.Value.true,
else: RDF.Boolean.Value.false
RDF.Literal.plain?(literal) ->
Literal.plain?(literal) ->
if String.length(literal.value) == 0,
do: RDF.Boolean.Value.false,
else: RDF.Boolean.Value.true
@ -228,7 +236,7 @@ defmodule RDF.Boolean do
end
def ebv(value) when is_binary(value) or is_number(value) do
value |> RDF.Literal.new() |> ebv()
value |> Literal.new() |> ebv()
end
def ebv(_), do: nil
@ -236,6 +244,7 @@ defmodule RDF.Boolean do
@doc """
Alias for `ebv/1`.
"""
@spec effective(Literal.t | any) :: Literal.t | nil
def effective(value), do: ebv(value)
end

View file

@ -8,12 +8,14 @@ defmodule RDF.Date do
import RDF.Literal.Guards
@type value :: Date.t | {Date.t, String.t}
@type input :: value | String.t
@grammar ~r/\A(-?\d{4}-\d{2}-\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z/
@xsd_datetime RDF.Datatype.NS.XSD.dateTime
@impl RDF.Datatype
@spec convert(input | any, map) :: value | nil
def convert(value, opts)
def convert(%Date{} = value, %{tz: "+00:00"} = opts) do
@ -54,6 +56,7 @@ defmodule RDF.Date do
@impl RDF.Datatype
@spec canonical_lexical(value) :: String.t
def canonical_lexical(value)
def canonical_lexical(%Date{} = value) do

View file

@ -8,11 +8,13 @@ defmodule RDF.DateTime do
import RDF.Literal.Guards
@type value :: DateTime.t | NaiveDateTime.t
@type input :: value | String.t
@xsd_date RDF.Datatype.NS.XSD.date
@impl RDF.Datatype
@spec convert(input | any, map) :: value | nil
def convert(value, opts)
# Special case for date and dateTime, for which 0 is not a valid year
@ -65,6 +67,7 @@ defmodule RDF.DateTime do
@impl RDF.Datatype
@spec canonical_lexical(value) :: String.t
def canonical_lexical(value)
def canonical_lexical(%DateTime{} = value) do
@ -112,6 +115,7 @@ defmodule RDF.DateTime do
@doc """
Builds a `RDF.DateTime` literal for current moment in time.
"""
@spec now :: Literal.t
def now() do
new(DateTime.utc_now())
end
@ -120,6 +124,7 @@ defmodule RDF.DateTime do
@doc """
Extracts the timezone string from a `RDF.DateTime` literal.
"""
@spec tz(Literal.t) :: String.t | nil
def tz(literal)
def tz(%Literal{value: %NaiveDateTime{}}), do: ""
@ -136,6 +141,7 @@ defmodule RDF.DateTime do
@doc """
Converts a datetime literal to a canonical string, preserving the zone information.
"""
@spec canonical_lexical_with_zone(Literal.t) :: String.t | nil
def canonical_lexical_with_zone(%Literal{datatype: datatype} = literal)
when is_xsd_datetime(datatype) do
case tz(literal) do

View file

@ -1,6 +1,7 @@
defmodule RDF.DateTimeUtils do
@moduledoc false
@spec tz(String.t) :: String.t
def tz(string) do
case Regex.run(~r/([+-])(\d\d:\d\d)/, string) do
[_, sign, zone] ->

View file

@ -8,12 +8,14 @@ defmodule RDF.Decimal do
alias Elixir.Decimal, as: D
@type value :: Decimal.t | :nan
@type value :: Decimal.t
@type input :: value | number | String.t
@xsd_integer RDF.Datatype.NS.XSD.integer
@impl RDF.Datatype
@spec convert(input | any, map) :: value | nil
def convert(value, opts)
def convert(%D{coef: coef} = value, opts) when coef in ~w[qNaN sNaN inf]a,
@ -120,6 +122,7 @@ defmodule RDF.Decimal do
@doc """
The number of digits in the XML Schema canonical form of the literal value.
"""
@spec digit_count(Literal.t) :: non_neg_integer
def digit_count(%RDF.Literal{datatype: @id} = literal) do
if valid?(literal) do
literal
@ -137,6 +140,7 @@ defmodule RDF.Decimal do
@doc """
The number of digits to the right of the decimal point in the XML Schema canonical form of the literal value.
"""
@spec fraction_digit_count(Literal.t) :: non_neg_integer
def fraction_digit_count(%RDF.Literal{datatype: @id} = literal) do
if valid?(literal) do
[_, fraction] =

View file

@ -7,7 +7,8 @@ defmodule RDF.Double do
import RDF.Literal.Guards
@type value :: float
@type value :: float | :positive_infinity | :negative_infinity | :nan
@type input :: value | number | String.t
def build_literal_by_value(value, opts) do
@ -22,6 +23,7 @@ defmodule RDF.Double do
end
@impl RDF.Datatype
@spec convert(input | any, map) :: value | nil
def convert(value, opts)
def convert(value, _) when is_float(value), do: value
@ -57,6 +59,7 @@ defmodule RDF.Double do
@impl RDF.Datatype
@spec canonical_lexical(value) :: String.t
def canonical_lexical(value)
def canonical_lexical(:nan), do: "NaN"

View file

@ -8,9 +8,11 @@ defmodule RDF.Integer do
import RDF.Literal.Guards
@type value :: integer
@type input :: value | String.t
@impl RDF.Datatype
@spec convert(input | any, map) :: value | nil
def convert(value, opts)
def convert(value, _) when is_integer(value), do: value
@ -79,6 +81,7 @@ defmodule RDF.Integer do
@doc """
The number of digits in the XML Schema canonical form of the literal value.
"""
@spec digit_count(Literal.t) :: non_neg_integer
def digit_count(%RDF.Literal{datatype: @id} = literal) do
if valid?(literal) do
literal

View file

@ -5,6 +5,8 @@ defmodule RDF.LangString do
use RDF.Datatype, id: RDF.uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#langString")
@type value :: String.t
def build_literal(value, lexical, %{language: language} = opts)
when is_binary(language) and language != "" do
@ -17,6 +19,7 @@ defmodule RDF.LangString do
@impl RDF.Datatype
@spec convert(any, map) :: value
def convert(value, _), do: to_string(value)
@ -43,6 +46,7 @@ defmodule RDF.LangString do
see <https://www.w3.org/TR/sparql11-query/#func-langMatches>
"""
@spec match_language?(Literal.t | String.t, String.t) :: boolean
def match_language?(language_tag, language_range)
def match_language?(%Literal{language: nil}, _), do: false

View file

@ -11,6 +11,7 @@ defmodule RDF.Numeric do
import RDF.Literal.Guards
import Kernel, except: [abs: 1, floor: 1, ceil: 1]
@type value :: RDF.Decimal.value | RDF.Integer.value | RDF.Double.value
@types MapSet.new [
XSD.integer,
@ -47,6 +48,7 @@ defmodule RDF.Numeric do
@doc """
Returns if a given literal has a numeric datatype.
"""
@spec literal?(Literal.t | any) :: boolean
def literal?(%Literal{datatype: datatype}), do: type?(datatype)
def literal?(_), do: false
@ -138,6 +140,7 @@ defmodule RDF.Numeric do
def compare(_, _), do: nil
@dialyzer {:nowarn_function, compare_decimal_value: 2}
defp compare_decimal_value(%D{} = left, %D{} = right), do: D.cmp(left, right)
defp compare_decimal_value(%D{} = left, right), do: compare_decimal_value(left, new_decimal(right))
defp compare_decimal_value(left, %D{} = right), do: compare_decimal_value(new_decimal(left), right)

View file

@ -31,6 +31,7 @@ defmodule RDF.String do
@impl RDF.Datatype
@spec convert(any, map) :: value
def convert(value, _), do: to_string(value)

View file

@ -8,12 +8,14 @@ defmodule RDF.Time do
import RDF.Literal.Guards
@type value :: Time.t
@type input :: value | String.t
@grammar ~r/\A(\d{2}:\d{2}:\d{2}(?:\.\d+)?)((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z/
@tz_grammar ~r/\A(?:([\+\-])(\d{2}):(\d{2}))\Z/
@impl RDF.Datatype
@spec convert(input | any, map) :: value | nil
def convert(value, opts)
def convert(%Time{} = value, %{tz: tz} = opts) do
@ -120,6 +122,7 @@ defmodule RDF.Time do
@doc """
Extracts the timezone string from a `RDF.Time` literal.
"""
@spec tz(Literal.t) :: String.t | nil
def tz(time_literal) do
if valid?(time_literal) do
time_literal
@ -132,6 +135,7 @@ defmodule RDF.Time do
@doc """
Converts a time literal to a canonical string, preserving the zone information.
"""
@spec canonical_lexical_with_zone(Literal.t) :: String.t | nil
def canonical_lexical_with_zone(%Literal{datatype: datatype} = literal)
when is_xsd_time(datatype) do
case tz(literal) do

View file

@ -3,6 +3,7 @@ defmodule RDF.Serialization.Decoder do
A behaviour for decoders of strings encoded in a specific `RDF.Serialization` format.
"""
alias RDF.{Dataset, Graph}
@doc """
Decodes a serialized `RDF.Graph` or `RDF.Dataset` from the given string.
@ -10,8 +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) :: {:ok, RDF.Graph.t | RDF.Dataset.t} |
{:error, any}
@callback decode(String.t, keyword | map) :: {:ok, Graph.t | Dataset.t} | {:error, any}
@doc """
Decodes a serialized `RDF.Graph` or `RDF.Dataset` from the given string.
@ -21,7 +21,7 @@ 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) :: RDF.Graph.t | RDF.Dataset.t
@callback decode!(String.t, keyword | map) :: RDF.Graph.t | RDF.Dataset.t
defmacro __using__(_) do
@ -29,6 +29,7 @@ defmodule RDF.Serialization.Decoder do
@behaviour unquote(__MODULE__)
@impl unquote(__MODULE__)
@spec decode!(String.t, keyword | map) :: RDF.Graph.t | RDF.Dataset.t
def decode!(content, opts \\ []) do
case decode(content, opts) do
{:ok, data} -> data

View file

@ -4,6 +4,7 @@ defmodule RDF.Serialization.Encoder do
`RDF.Serialization` format.
"""
alias RDF.{Dataset, Graph}
@doc """
Encodes a `RDF.Graph` or `RDF.Dataset`.
@ -11,8 +12,7 @@ defmodule RDF.Serialization.Encoder do
It returns an `{:ok, string}` tuple, with `string` being the serialized
`RDF.Graph` or `RDF.Dataset`, or `{:error, reason}` if an error occurs.
"""
@callback encode(RDF.Graph.t | RDF.Dataset.t, keyword) ::
{:ok, String.t} | {:error, any}
@callback encode(Graph.t | Dataset.t, keyword | map) :: {:ok, String.t} | {:error, any}
@doc """
Encodes a `RDF.Graph` or `RDF.Dataset`.
@ -22,7 +22,7 @@ defmodule RDF.Serialization.Encoder do
Note: The `__using__` macro automatically provides an overridable default
implementation based on the non-bang `encode` function.
"""
@callback encode!(RDF.Graph.t | RDF.Dataset.t, keyword) :: String.t
@callback encode!(Graph.t | Dataset.t, keyword | map) :: String.t
defmacro __using__(_) do
@ -32,6 +32,8 @@ defmodule RDF.Serialization.Encoder do
import RDF.Literal.Guards
@impl unquote(__MODULE__)
@dialyzer {:nowarn_function, encode!: 2}
@spec encode!(Graph.t | Dataset.t, keyword) :: String.t
def encode!(data, opts \\ []) do
case encode(data, opts) do
{:ok, data} -> data

View file

@ -28,6 +28,8 @@ defmodule RDF.Serialization.Format do
`decoder/0` functions in your `RDF.Serialization.Format` module.
"""
alias RDF.{Dataset, Graph}
@doc """
An IRI of the serialization format.
"""
@ -41,12 +43,12 @@ defmodule RDF.Serialization.Format do
@doc """
The usual file extension for the serialization format.
"""
@callback extension :: binary
@callback extension :: String.t
@doc """
The MIME type of the serialization format.
"""
@callback media_type :: binary
@callback media_type :: String.t
@doc """
A map with the supported options of the `Encoder` and `Decoder` for the serialization format.
@ -82,21 +84,29 @@ defmodule RDF.Serialization.Format do
defoverridable [decoder: 0, encoder: 0, options: 0]
@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)
@spec read_string!(String.t, keyword) :: Graph.t | Dataset.t
def read_string!(content, opts \\ []),
do: RDF.Serialization.Reader.read_string!(decoder(), content, opts)
@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)
@spec read_file!(Path.t, keyword) :: Graph.t | Dataset.t
def read_file!(file, opts \\ []),
do: RDF.Serialization.Reader.read_file!(decoder(), file, opts)
@spec write_string(Graph.t | Dataset.t, keyword) :: {:ok, String.t} | {:error, any}
def write_string(data, opts \\ []),
do: RDF.Serialization.Writer.write_string(encoder(), data, opts)
@spec write_string!(Graph.t | Dataset.t, keyword) :: String.t
def write_string!(data, opts \\ []),
do: RDF.Serialization.Writer.write_string!(encoder(), data, opts)
@spec write_file(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)
@spec write_file!(Graph.t | Dataset.t, Path.t, keyword) :: :ok
def write_file!(data, path, opts \\ []),
do: RDF.Serialization.Writer.write_file!(encoder(), data, path, opts)

View file

@ -7,12 +7,15 @@ defmodule RDF.Serialization.Reader do
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
@ -22,6 +25,7 @@ defmodule RDF.Serialization.Reader do
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
@ -32,6 +36,7 @@ defmodule RDF.Serialization.Reader do
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
{:ok, content} -> read_string(decoder, content, opts)
@ -44,6 +49,7 @@ defmodule RDF.Serialization.Reader do
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)

View file

@ -3,6 +3,10 @@ defmodule RDF.Serialization do
General functions for working with RDF serializations.
"""
alias RDF.{Dataset, Graph}
@type format :: module
@formats [
RDF.Turtle,
JSON.LD,
@ -21,6 +25,7 @@ defmodule RDF.Serialization do
[RDF.Turtle, JSON.LD, RDF.NTriples, RDF.NQuads]
"""
@spec formats :: [format]
def formats, do: @formats
@doc """
@ -36,6 +41,7 @@ defmodule RDF.Serialization do
[RDF.Turtle, RDF.NTriples, RDF.NQuads]
"""
@spec available_formats :: [format]
def available_formats do
Enum.filter @formats, &Code.ensure_loaded?/1
end
@ -52,6 +58,7 @@ defmodule RDF.Serialization do
iex> RDF.Serialization.format(:jsonld)
nil # unless json_ld is defined as a dependency of the application
"""
@spec format(String.t | atom) :: format | nil
def format(name)
def format(name) when is_binary(name) do
@ -77,6 +84,7 @@ defmodule RDF.Serialization do
iex> RDF.Serialization.format_by_media_type("application/ld+json")
nil # unless json_ld is defined as a dependency of the application
"""
@spec format_by_media_type(String.t) :: format | nil
def format_by_media_type(media_type) do
format_where(fn format -> format.media_type == media_type end)
end
@ -93,6 +101,7 @@ defmodule RDF.Serialization do
iex> RDF.Serialization.format_by_extension("jsonld")
nil # unless json_ld is defined as a dependency of the application
"""
@spec format_by_extension(String.t) :: format | nil
def format_by_extension(extension)
def format_by_extension("." <> extension), do: format_by_extension(extension)
@ -117,6 +126,7 @@ defmodule RDF.Serialization do
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs.
"""
@spec read_string(String.t, keyword) :: {:ok, Graph.t | Dataset.t} | {:error, any}
def read_string(content, opts) do
with {:ok, format} <- string_format(opts) do
format.read_string(content, opts)
@ -131,6 +141,7 @@ defmodule RDF.Serialization do
As opposed to `read_string`, it raises an exception if an error occurs.
"""
@spec read_string!(String.t, keyword) :: Graph.t | Dataset.t
def read_string!(content, opts) do
with {:ok, format} <- string_format(opts) do
format.read_string!(content, opts)
@ -149,6 +160,7 @@ defmodule RDF.Serialization do
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs.
"""
@spec read_file(Path.t, keyword) :: {:ok, Graph.t | Dataset.t} | {:error, any}
def read_file(file, opts \\ []) do
with {:ok, format} <- file_format(file, opts) do
format.read_file(file, opts)
@ -164,6 +176,7 @@ defmodule RDF.Serialization do
As opposed to `read_file`, it raises an exception if an error occurs.
"""
@spec read_file!(Path.t, keyword) :: Graph.t | Dataset.t
def read_file!(file, opts \\ []) do
with {:ok, format} <- file_format(file, opts) do
format.read_file!(file, opts)
@ -181,6 +194,7 @@ defmodule RDF.Serialization do
It returns an `{:ok, string}` tuple, with `string` being the serialized graph or
dataset, or `{:error, reason}` if an error occurs.
"""
@spec write_string(Graph.t | Dataset.t, keyword) :: {:ok, String.t} | {:error, any}
def write_string(data, opts) do
with {:ok, format} <- string_format(opts) do
format.write_string(data, opts)
@ -195,6 +209,7 @@ defmodule RDF.Serialization do
As opposed to `write_string`, it raises an exception if an error occurs.
"""
@spec write_string!(Graph.t | Dataset.t, keyword) :: String.t
def write_string!(data, opts) do
with {:ok, format} <- string_format(opts) do
format.write_string!(data, opts)
@ -219,6 +234,7 @@ defmodule RDF.Serialization do
It returns `:ok` if successful or `{:error, reason}` if an error occurs.
"""
@spec write_file(Graph.t | Dataset.t, Path.t, keyword) :: :ok | {:error, any}
def write_file(data, path, opts \\ []) do
with {:ok, format} <- file_format(path, opts) do
format.write_file(data, path, opts)
@ -236,6 +252,7 @@ defmodule RDF.Serialization do
As opposed to `write_file`, it raises an exception if an error occurs.
"""
@spec write_file!(Graph.t | Dataset.t, Path.t, keyword) :: :ok
def write_file!(data, path, opts \\ []) do
with {:ok, format} <- file_format(path, opts) do
format.write_file!(data, path, opts)

View file

@ -7,6 +7,7 @@ defmodule RDF.Serialization.Writer do
use the proper `RDF.Serialization.Encoder` module.
"""
alias RDF.{Dataset, Graph}
@doc """
Encodes and writes a graph or dataset to a string.
@ -14,6 +15,7 @@ defmodule RDF.Serialization.Writer do
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, Graph.t | Dataset.t, keyword) :: {:ok, String.t} | {:error, any}
def write_string(encoder, data, opts \\ []) do
encoder.encode(data, opts)
end
@ -23,6 +25,7 @@ defmodule RDF.Serialization.Writer do
As opposed to `write_string`, it raises an exception if an error occurs.
"""
@spec write_string!(module, Graph.t | Dataset.t, keyword) :: String.t
def write_string!(encoder, data, opts \\ []) do
encoder.encode!(data, opts)
end
@ -39,6 +42,7 @@ defmodule RDF.Serialization.Writer do
It returns `:ok` if successful or `{:error, reason}` if an error occurs.
"""
@spec write_file(module, Graph.t | Dataset.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))
@ -52,6 +56,7 @@ defmodule RDF.Serialization.Writer do
As opposed to `write_file`, it raises an exception if an error occurs.
"""
@spec write_file!(module, Graph.t | Dataset.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))

View file

@ -5,7 +5,10 @@ defmodule RDF.NQuads.Decoder do
import RDF.Serialization.ParseHelper, only: [error_description: 1]
alias RDF.{Dataset, Graph}
@impl RDF.Serialization.Decoder
@spec decode(String.t, keyword | map) :: {:ok, Graph.t | Dataset.t} | {:error, any}
def decode(content, _opts \\ []) do
with {:ok, tokens, _} <- tokenize(content),
{:ok, ast} <- parse(tokens) do

View file

@ -3,26 +3,30 @@ defmodule RDF.NQuads.Encoder do
use RDF.Serialization.Encoder
alias RDF.{Dataset, Graph, Quad, Statement, Triple}
@impl RDF.Serialization.Encoder
@callback encode(Graph.t | Dataset.t, keyword | map) :: {:ok, String.t} | {:error, any}
def encode(data, _opts \\ []) do
result =
data
|> Enum.reduce([], fn (statement, result) ->
[statement(statement) | result]
end)
|> Enum.reduce([], fn (statement, result) -> [statement(statement) | result] end)
|> Enum.reverse
|> Enum.join("\n")
{:ok, (if result == "", do: result, else: result <> "\n")}
{:ok, (if result == "", do: result, else: "#{result}\n")}
end
@spec statement({Statement.subject, Statement.predicate, Statement.object, nil}) :: String.t
def statement({subject, predicate, object, nil}) do
statement({subject, predicate, object})
end
@spec statement(Quad.t) :: String.t
def statement({subject, predicate, object, graph}) do
"#{term(subject)} #{term(predicate)} #{term(object)} #{term(graph)} ."
end
@spec statement(Triple.t) :: String.t
def statement({subject, predicate, object}) do
"#{term(subject)} #{term(predicate)} #{term(object)} ."
end

View file

@ -5,7 +5,10 @@ defmodule RDF.NTriples.Decoder do
import RDF.Serialization.ParseHelper, only: [error_description: 1]
alias RDF.{Dataset, Graph}
@impl RDF.Serialization.Decoder
@spec decode(String.t, keyword | map) :: {:ok, Graph.t | Dataset.t} | {:error, any}
def decode(content, _opts \\ []) do
with {:ok, tokens, _} <- tokenize(content),
{:ok, ast} <- parse(tokens) do

View file

@ -3,10 +3,10 @@ defmodule RDF.NTriples.Encoder do
use RDF.Serialization.Encoder
alias RDF.{IRI, Literal, BlankNode}
alias RDF.{BlankNode, Dataset, Graph, IRI, Literal, Statement, Triple}
@impl RDF.Serialization.Encoder
@callback encode(Graph.t | Dataset.t, keyword | map) :: {:ok, String.t} | {:error, any}
def encode(data, _opts \\ []) do
result =
data
@ -18,10 +18,12 @@ defmodule RDF.NTriples.Encoder do
{:ok, (if result == "", do: result, else: result <> "\n")}
end
@spec statement(Triple.t) :: String.t
def statement({subject, predicate, object}) do
"#{term(subject)} #{term(predicate)} #{term(object)} ."
end
@spec term(Statement.subject | Statement.predicate | Statement.object) :: String.t
def term(%IRI{} = iri) do
"<#{to_string(iri)}>"
end

View file

@ -2,11 +2,11 @@ defmodule RDF.Turtle.Decoder do
@moduledoc false
use RDF.Serialization.Decoder
alias RDF.IRI
import RDF.Serialization.ParseHelper, only: [error_description: 1]
alias RDF.{Dataset, Graph, IRI}
defmodule State do
defstruct base_iri: nil, namespaces: %{}, bnode_counter: 0
@ -25,6 +25,7 @@ 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),

View file

@ -4,7 +4,7 @@ defmodule RDF.Turtle.Encoder do
use RDF.Serialization.Encoder
alias RDF.Turtle.Encoder.State
alias RDF.{IRI, Literal, BlankNode, Description}
alias RDF.{BlankNode, Dataset, Description, Graph, IRI, Literal}
@indentation_char " "
@indentation 4
@ -27,6 +27,7 @@ defmodule RDF.Turtle.Encoder do
@impl RDF.Serialization.Encoder
@callback encode(Graph.t | Dataset.t, keyword | map) :: {:ok, String.t} | {:error, any}
def encode(data, opts \\ []) do
with base = Keyword.get(opts, :base, Keyword.get(opts, :base_iri))
|> base_iri(data) |> init_base_iri(),

View file

@ -58,9 +58,11 @@ defmodule RDF.Vocabulary.Namespace do
end
@base_iri unquote(base_iri)
@spec __base_iri__ :: String.t
def __base_iri__, do: @base_iri
@strict unquote(strict)
@spec __strict__ :: boolean
def __strict__, do: @strict
@terms unquote(Macro.escape(terms))
@ -72,6 +74,7 @@ defmodule RDF.Vocabulary.Namespace do
@doc """
Returns all known IRIs of the vocabulary.
"""
@spec __iris__ :: [Elixir.RDF.IRI.t]
def __iris__ do
@terms
|> Enum.map(fn
@ -84,6 +87,7 @@ defmodule RDF.Vocabulary.Namespace do
define_vocab_terms unquote(lowercased_terms), unquote(base_iri)
@impl Elixir.RDF.Namespace
@dialyzer {:nowarn_function, __resolve_term__: 1}
def __resolve_term__(term) do
case @terms[term] do
nil ->