Add update/2 functions to RDF.Literal and the datatypes

This commit is contained in:
Marcel Otto 2020-04-16 20:57:10 +02:00
parent 238c9310be
commit 060fac4675
6 changed files with 72 additions and 0 deletions

View file

@ -254,6 +254,10 @@ defmodule RDF.Literal do
def matches?(value, pattern, flags) when is_binary(value) and is_binary(pattern) and is_binary(flags),
do: XSD.Utils.Regex.matches?(value, pattern, flags)
def update(%__MODULE__{literal: %datatype{} = literal}, fun, opts \\ []) do
Datatype.Registry.rdf_datatype(datatype).update(literal, fun, opts)
end
defimpl String.Chars do
def to_string(literal) do
String.Chars.to_string(literal.literal)

View file

@ -85,4 +85,7 @@ defmodule RDF.Literal.Datatype do
them is invalid.
"""
@callback compare(Literal.t() | literal, Literal.t() | literal) :: comparison_result | :indeterminate | nil
@callback update(Literal.t() | literal, fun()) :: Literal.t
@callback update(Literal.t() | literal, fun(), keyword) :: Literal.t
end

View file

@ -107,6 +107,16 @@ defmodule RDF.Literal.Generic do
def compare(_, _), do: nil
@impl Datatype
def update(literal, fun, opts \\ [])
def update(%Literal{literal: literal}, fun, opts), do: update(literal, fun, opts)
def update(%__MODULE__{} = literal, fun, _opts) do
literal
|> value()
|> fun.()
|> new(datatype: literal.datatype)
end
defimpl String.Chars do
def to_string(literal) do
literal.value

View file

@ -112,6 +112,16 @@ defmodule RDF.LangString do
def compare(_, _), do: nil
@impl Datatype
def update(literal, fun, opts \\ [])
def update(%Literal{literal: literal}, fun, opts), do: update(literal, fun, opts)
def update(%__MODULE__{} = literal, fun, _opts) do
literal
|> value()
|> fun.()
|> new(language: literal.language)
end
@doc """
Checks if a language tagged string literal or language tag matches a language range.

View file

@ -97,6 +97,18 @@ defmodule RDF.Literal.XSD do
def compare(%unquote(xsd_datatype){} = left, right) do
unquote(xsd_datatype).compare(left, right)
end
@impl RDF.Literal.Datatype
def update(literal, fun, opts \\ [])
def update(%Literal{literal: literal}, fun, opts), do: update(literal, fun, opts)
def update(%unquote(xsd_datatype){} = literal, fun, opts) do
case Keyword.get(opts, :as) do
:lexical -> lexical(literal)
nil -> value(literal)
end
|> fun.()
|> new()
end
end
| datatype_specific_module_body(xsd_datatype)]
end

View file

@ -402,6 +402,39 @@ defmodule RDF.LiteralTest do
end
end
describe "update/2" do
test "it updates value and lexical form" do
assert RDF.string("foo")
|> Literal.update(fn s when is_binary(s) -> s <> "bar" end) ==
RDF.string("foobar")
assert RDF.integer(1) |> Literal.update(fn i when is_integer(i) -> i + 1 end) ==
RDF.integer(2)
assert RDF.byte(42) |> Literal.update(fn i when is_integer(i) -> i + 1 end) ==
RDF.byte(43)
assert RDF.integer(1)
|> Literal.update(fn i when is_integer(i) -> "0" <> to_string(i) end) ==
RDF.integer("01")
end
test "it does not change the datatype of generic literals" do
assert RDF.literal("foo", datatype: "http://example.com/dt")
|> Literal.update(fn s when is_binary(s) -> s <> "bar" end) ==
RDF.literal("foobar", datatype: "http://example.com/dt")
end
test "it does not change the language of language literals" do
assert RDF.langString("foo", language: "en")
|> Literal.update(fn s when is_binary(s) -> s <> "bar" end) ==
RDF.langString("foobar", language: "en")
end
test "with as: :lexical opt it passes the lexical form" do
assert RDF.integer(1)
|> Literal.update(fn i when is_binary(i) -> "0" <> i end, as: :lexical) ==
RDF.integer("01")
end
end
describe "String.Chars protocol implementation" do
test "with XSD.Datatype literal" do
assert Literal.new("foo") |> to_string() == "foo"