Add @impl annotations

This commit is contained in:
Marcel Otto 2018-09-17 02:08:16 +02:00
parent dfb88ac65e
commit 9c6beeac13
23 changed files with 157 additions and 37 deletions

View file

@ -403,6 +403,7 @@ defmodule RDF.Dataset do
iex> RDF.Dataset.fetch(dataset, EX.Foo)
:error
"""
@impl Access
def fetch(%RDF.Dataset{graphs: graphs}, graph_name) do
Access.fetch(graphs, coerce_graph_name(graph_name))
end
@ -473,6 +474,7 @@ defmodule RDF.Dataset do
...> end)
{RDF.Graph.new(EX.Graph, {EX.S, EX.P, EX.O}), RDF.Dataset.new({EX.S, EX.P, EX.NEW, EX.Graph})}
"""
@impl Access
def get_and_update(%RDF.Dataset{} = dataset, graph_name, fun) do
with graph_context = coerce_graph_name(graph_name) do
case fun.(get(dataset, graph_context)) do
@ -522,6 +524,7 @@ defmodule RDF.Dataset do
iex> RDF.Dataset.pop(dataset, EX.Foo)
{nil, dataset}
"""
@impl Access
def pop(%RDF.Dataset{name: name, graphs: graphs} = dataset, graph_name) do
case Access.pop(graphs, coerce_graph_name(graph_name)) do
{nil, _} ->

View file

@ -125,6 +125,7 @@ defmodule RDF.Datatype do
alias RDF.Datatype.NS.XSD
@id unquote(id)
@impl unquote(__MODULE__)
def id, do: @id
@ -182,6 +183,9 @@ defmodule RDF.Datatype do
def convert(value, _), do: nil
@impl unquote(__MODULE__)
def lexical(literal)
def lexical(%RDF.Literal{value: value, uncanonical_lexical: nil}) do
canonical_lexical(value)
end
@ -191,21 +195,30 @@ defmodule RDF.Datatype do
end
@impl unquote(__MODULE__)
def canonical_lexical(value), do: to_string(value)
@impl unquote(__MODULE__)
def invalid_lexical(value), do: to_string(value)
@impl unquote(__MODULE__)
def canonical(literal)
def canonical(%Literal{value: nil} = literal), do: literal
def canonical(%Literal{uncanonical_lexical: nil} = literal), do: literal
def canonical(%Literal{} = literal) do
%Literal{literal | uncanonical_lexical: nil}
end
@impl unquote(__MODULE__)
def valid?(literal)
def valid?(%Literal{value: nil}), do: false
def valid?(%Literal{datatype: @id}), do: true
def valid?(_), do: false
@impl unquote(__MODULE__)
def equal_value?(literal1, literal2)
def equal_value?(%Literal{uncanonical_lexical: lexical1, datatype: @id, value: nil},
%Literal{uncanonical_lexical: lexical2, datatype: @id}) do
lexical1 == lexical2

View file

@ -8,6 +8,9 @@ defmodule RDF.Boolean do
import RDF.Literal.Guards
@impl RDF.Datatype
def convert(value, opts)
def convert(value, _) when is_boolean(value), do: value
def convert(value, opts) when is_binary(value) do
@ -27,6 +30,9 @@ defmodule RDF.Boolean do
def convert(value, opts), do: super(value, opts)
@impl RDF.Datatype
def cast(literal)
def cast(%RDF.Literal{datatype: datatype} = literal) do
cond do
not RDF.Literal.valid?(literal) ->

View file

@ -10,6 +10,9 @@ defmodule RDF.Date do
@grammar ~r/\A(-?\d{4}-\d{2}-\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z/
@impl RDF.Datatype
def convert(value, opts)
def convert(%Date{} = value, %{tz: "+00:00"} = opts) do
{convert(value, Map.delete(opts, :tz)), "Z"}
end
@ -47,6 +50,9 @@ defmodule RDF.Date do
end
@impl RDF.Datatype
def canonical_lexical(value)
def canonical_lexical(%Date{} = value) do
Date.to_iso8601(value)
end
@ -56,6 +62,9 @@ defmodule RDF.Date do
end
@impl RDF.Datatype
def cast(literal)
def cast(%RDF.Literal{datatype: datatype} = literal) do
cond do
not RDF.Literal.valid?(literal) ->

View file

@ -8,9 +8,8 @@ defmodule RDF.DateTime do
import RDF.Literal.Guards
def now() do
new(DateTime.utc_now())
end
@impl RDF.Datatype
def convert(value, opts)
# Special case for date and dateTime, for which 0 is not a valid year
def convert(%DateTime{year: 0} = value, opts), do: super(value, opts)
@ -52,6 +51,9 @@ defmodule RDF.DateTime do
def convert(value, opts), do: super(value, opts)
@impl RDF.Datatype
def canonical_lexical(value)
def canonical_lexical(%DateTime{} = value) do
DateTime.to_iso8601(value)
end
@ -61,6 +63,9 @@ defmodule RDF.DateTime do
end
@impl RDF.Datatype
def cast(literal)
def cast(%RDF.Literal{datatype: datatype} = literal) do
cond do
not RDF.Literal.valid?(literal) ->
@ -91,6 +96,19 @@ defmodule RDF.DateTime do
def cast(_), do: nil
@doc """
Builds a `RDF.DateTime` literal for current moment in time.
"""
def now() do
new(DateTime.utc_now())
end
@doc """
Extracts the timezone string from a `RDF.DateTime` literal.
"""
def tz(literal)
def tz(%Literal{value: %NaiveDateTime{}}), do: ""
def tz(date_time_literal) do
@ -101,6 +119,7 @@ defmodule RDF.DateTime do
end
end
@doc """
Converts a datetime literal to a canonical string, preserving the zone information.
"""

View file

@ -9,6 +9,9 @@ defmodule RDF.Decimal do
alias Elixir.Decimal, as: D
@impl RDF.Datatype
def convert(value, opts)
def convert(%D{coef: coef} = value, opts) when coef in ~w[qNaN sNaN inf]a,
do: super(value, opts)
@ -35,6 +38,9 @@ defmodule RDF.Decimal do
def convert(value, opts), do: super(value, opts)
@impl RDF.Datatype
def canonical_lexical(value)
def canonical_lexical(%D{sign: sign, coef: :qNaN}),
do: if sign == 1, do: "NaN", else: "-NaN"
@ -66,6 +72,8 @@ defmodule RDF.Decimal do
do: canonical_decimal(%{decimal | coef: Kernel.div(coef, 10), exp: exp + 1})
@impl RDF.Datatype
def cast(literal)
def cast(%RDF.Literal{datatype: datatype} = literal) do
cond do
@ -99,6 +107,7 @@ defmodule RDF.Decimal do
def cast(_), do: nil
@impl RDF.Datatype
def equal_value?(left, right), do: RDF.Numeric.equal_value?(left, right)
end

View file

@ -19,6 +19,8 @@ defmodule RDF.Double do
end
end
@impl RDF.Datatype
def convert(value, opts)
def convert(value, _) when is_float(value), do: value
@ -53,6 +55,9 @@ defmodule RDF.Double do
def convert(value, opts), do: super(value, opts)
@impl RDF.Datatype
def canonical_lexical(value)
def canonical_lexical(:nan), do: "NaN"
def canonical_lexical(:positive_infinity), do: "INF"
def canonical_lexical(:negative_infinity), do: "-INF"
@ -94,6 +99,8 @@ defmodule RDF.Double do
end
@impl RDF.Datatype
def cast(literal)
def cast(%RDF.Literal{datatype: datatype} = literal) do
cond do
@ -131,6 +138,7 @@ defmodule RDF.Double do
def cast(_), do: nil
@impl RDF.Datatype
def equal_value?(left, right), do: RDF.Numeric.equal_value?(left, right)
end

View file

@ -8,6 +8,9 @@ defmodule RDF.Integer do
import RDF.Literal.Guards
@impl RDF.Datatype
def convert(value, opts)
def convert(value, _) when is_integer(value), do: value
def convert(value, opts) when is_binary(value) do
@ -21,6 +24,9 @@ defmodule RDF.Integer do
def convert(value, opts), do: super(value, opts)
@impl RDF.Datatype
def cast(literal)
def cast(%RDF.Literal{datatype: datatype} = literal) do
cond do
not RDF.Literal.valid?(literal) ->
@ -61,6 +67,7 @@ defmodule RDF.Integer do
def cast(_), do: nil
@impl RDF.Datatype
def equal_value?(left, right), do: RDF.Numeric.equal_value?(left, right)
end

View file

@ -16,13 +16,22 @@ defmodule RDF.LangString do
end
@impl RDF.Datatype
def convert(value, _), do: to_string(value)
@impl RDF.Datatype
def valid?(literal)
def valid?(%Literal{language: nil}), do: false
def valid?(literal), do: super(literal)
@impl RDF.Datatype
def cast(_) do
nil
end
@doc """
Checks if a language tagged string literal or language tag matches a language range.
@ -53,9 +62,4 @@ defmodule RDF.LangString do
end
end
def cast(_) do
nil
end
end

View file

@ -28,9 +28,13 @@ defmodule RDF.String do
end
@impl RDF.Datatype
def convert(value, _), do: to_string(value)
@impl RDF.Datatype
def cast(literal)
def cast(%RDF.IRI{value: value}), do: new(value)
def cast(%RDF.Literal{datatype: datatype} = literal) do

View file

@ -11,6 +11,9 @@ defmodule RDF.Time do
@tz_grammar ~r/\A(?:([\+\-])(\d{2}):(\d{2}))\Z/
@impl RDF.Datatype
def convert(value, opts)
def convert(%Time{} = value, %{tz: tz} = opts) do
{convert(value, Map.delete(opts, :tz)), tz}
end
@ -62,6 +65,9 @@ defmodule RDF.Time do
end
@impl RDF.Datatype
def canonical_lexical(value)
def canonical_lexical(%Time{} = value) do
Time.to_iso8601(value)
end
@ -70,36 +76,9 @@ defmodule RDF.Time do
canonical_lexical(value) <> "Z"
end
def tz(time_literal) do
if valid?(time_literal) do
time_literal
|> lexical()
|> RDF.DateTimeUtils.tz()
end
end
@doc """
Converts a time literal to a canonical string, preserving the zone information.
"""
def canonical_lexical_with_zone(%Literal{datatype: datatype} = literal)
when is_xsd_time(datatype) do
case tz(literal) do
nil ->
nil
zone when zone in ["Z", "", "+00:00"] ->
canonical_lexical(literal.value)
zone ->
literal
|> lexical()
|> String.replace_trailing(zone, "")
|> Time.from_iso8601!()
|> canonical_lexical()
|> Kernel.<>(zone)
end
end
@impl RDF.Datatype
def cast(literal)
def cast(%RDF.Literal{datatype: datatype} = literal) do
cond do
@ -135,4 +114,39 @@ defmodule RDF.Time do
def cast(_), do: nil
@doc """
Extracts the timezone string from a `RDF.Time` literal.
"""
def tz(time_literal) do
if valid?(time_literal) do
time_literal
|> lexical()
|> RDF.DateTimeUtils.tz()
end
end
@doc """
Converts a time literal to a canonical string, preserving the zone information.
"""
def canonical_lexical_with_zone(%Literal{datatype: datatype} = literal)
when is_xsd_time(datatype) do
case tz(literal) do
nil ->
nil
zone when zone in ["Z", "", "+00:00"] ->
canonical_lexical(literal.value)
zone ->
literal
|> lexical()
|> String.replace_trailing(zone, "")
|> Time.from_iso8601!()
|> canonical_lexical()
|> Kernel.<>(zone)
end
end
end

View file

@ -321,6 +321,7 @@ defmodule RDF.Description do
iex> RDF.Description.fetch(RDF.Description.new(EX.S), EX.foo)
:error
"""
@impl Access
def fetch(%RDF.Description{predications: predications}, predicate) do
with {:ok, objects} <- Access.fetch(predications, coerce_predicate(predicate)) do
{:ok, Map.keys(objects)}
@ -391,6 +392,7 @@ defmodule RDF.Description do
...> RDF.Description.get_and_update(EX.P1, fn _ -> :pop end)
{[RDF.iri(EX.O1)], RDF.Description.new({EX.S, EX.P2, EX.O2})}
"""
@impl Access
def get_and_update(description = %RDF.Description{}, predicate, fun) do
with triple_predicate = coerce_predicate(predicate) do
case fun.(get(description, triple_predicate)) do
@ -435,6 +437,7 @@ defmodule RDF.Description do
iex> RDF.Description.pop(RDF.Description.new({EX.S, EX.P, EX.O}), EX.Missing)
{nil, RDF.Description.new({EX.S, EX.P, EX.O})}
"""
@impl Access
def pop(description = %RDF.Description{subject: subject, predications: predications}, predicate) do
case Access.pop(predications, coerce_predicate(predicate)) do
{nil, _} ->

View file

@ -319,6 +319,7 @@ defmodule RDF.Graph do
iex> RDF.Graph.fetch(RDF.Graph.new, EX.foo)
:error
"""
@impl Access
def fetch(%RDF.Graph{descriptions: descriptions}, subject) do
Access.fetch(descriptions, coerce_subject(subject))
end
@ -380,6 +381,7 @@ defmodule RDF.Graph do
...> end)
{RDF.Description.new(EX.S, EX.P, EX.O), RDF.Graph.new(EX.S, EX.P, EX.NEW)}
"""
@impl Access
def get_and_update(%RDF.Graph{} = graph, subject, fun) do
with subject = coerce_subject(subject) do
case fun.(get(graph, subject)) do
@ -426,6 +428,7 @@ defmodule RDF.Graph do
iex> RDF.Graph.pop(RDF.Graph.new({EX.S, EX.P, EX.O}), EX.Missing)
{nil, RDF.Graph.new({EX.S, EX.P, EX.O})}
"""
@impl Access
def pop(%RDF.Graph{name: name, descriptions: descriptions} = graph, subject) do
case Access.pop(descriptions, coerce_subject(subject)) do
{nil, _} ->

View file

@ -28,6 +28,7 @@ defmodule RDF.Serialization.Decoder do
quote bind_quoted: [], unquote: true do
@behaviour unquote(__MODULE__)
@impl unquote(__MODULE__)
def decode!(content, opts \\ []) do
case decode(content, opts) do
{:ok, data} -> data

View file

@ -30,6 +30,7 @@ defmodule RDF.Serialization.Encoder do
import RDF.Literal.Guards
@impl unquote(__MODULE__)
def encode!(data, opts \\ []) do
case encode(data, opts) do
{:ok, data} -> data

View file

@ -71,9 +71,13 @@ defmodule RDF.Serialization.Format do
@decoder __MODULE__.Decoder
@encoder __MODULE__.Encoder
@impl unquote(__MODULE__)
def decoder, do: @decoder
@impl unquote(__MODULE__)
def encoder, do: @encoder
@impl unquote(__MODULE__)
def options, do: %{}
defoverridable [decoder: 0, encoder: 0, options: 0]
@ -104,18 +108,22 @@ defmodule RDF.Serialization.Format do
quote do
if !Module.defines?(__MODULE__, {:id, 0}) &&
Module.get_attribute(__MODULE__, :id) do
@impl unquote(__MODULE__)
def id, do: @id
end
if !Module.defines?(__MODULE__, {:name, 0}) &&
Module.get_attribute(__MODULE__, :name) do
@impl unquote(__MODULE__)
def name, do: @name
end
if !Module.defines?(__MODULE__, {:extension, 0}) &&
Module.get_attribute(__MODULE__, :extension) do
@impl unquote(__MODULE__)
def extension, do: @extension
end
if !Module.defines?(__MODULE__, {:media_type, 0}) &&
Module.get_attribute(__MODULE__, :media_type) do
@impl unquote(__MODULE__)
def media_type, do: @media_type
end
end

View file

@ -3,6 +3,7 @@ defmodule RDF.NQuads.Decoder do
use RDF.Serialization.Decoder
@impl RDF.Serialization.Decoder
def decode(content, _opts \\ []) do
with {:ok, tokens, _} <- tokenize(content),
{:ok, ast} <- parse(tokens) do

View file

@ -3,6 +3,7 @@ defmodule RDF.NQuads.Encoder do
use RDF.Serialization.Encoder
@impl RDF.Serialization.Encoder
def encode(data, _opts \\ []) do
result =
data

View file

@ -3,6 +3,7 @@ defmodule RDF.NTriples.Decoder do
use RDF.Serialization.Decoder
@impl RDF.Serialization.Decoder
def decode(content, _opts \\ []) do
with {:ok, tokens, _} <- tokenize(content),
{:ok, ast} <- parse(tokens) do

View file

@ -6,6 +6,7 @@ defmodule RDF.NTriples.Encoder do
alias RDF.{IRI, Literal, BlankNode}
@impl RDF.Serialization.Encoder
def encode(data, _opts \\ []) do
result =
data

View file

@ -22,6 +22,7 @@ defmodule RDF.Turtle.Decoder do
end
end
@impl RDF.Serialization.Decoder
def decode(content, opts \\ %{})
def decode(content, opts) when is_list(opts),

View file

@ -26,6 +26,7 @@ defmodule RDF.Turtle.Encoder do
@ordered_properties MapSet.new(@predicate_order)
@impl RDF.Serialization.Encoder
def encode(data, opts \\ []) do
with base = Keyword.get(opts, :base) |> init_base(),
prefixes = Keyword.get(opts, :prefixes, %{}) |> init_prefixes(),

View file

@ -66,6 +66,7 @@ defmodule RDF.Vocabulary.Namespace do
def __strict__, do: @strict
@terms unquote(Macro.escape(terms))
@impl Elixir.RDF.Namespace
def __terms__, do: @terms |> Map.keys
@ignored_terms unquote(Macro.escape(ignored_terms))
@ -84,6 +85,7 @@ defmodule RDF.Vocabulary.Namespace do
define_vocab_terms unquote(lowercased_terms), unquote(base_iri)
@impl Elixir.RDF.Namespace
def __resolve_term__(term) do
case @terms[term] do
nil ->