Add implementation of RDF.Datatype.cast/1 on RDF.String

This commit is contained in:
Marcel Otto 2018-09-11 03:12:58 +02:00
parent de25b5399b
commit 45866fe30b
3 changed files with 141 additions and 0 deletions

View file

@ -53,4 +53,8 @@ defmodule RDF.LangString do
end
end
def cast(_) do
raise "not supported"
end
end

View file

@ -5,6 +5,9 @@ defmodule RDF.String do
use RDF.Datatype, id: RDF.Datatype.NS.XSD.string
alias RDF.Datatype.NS.XSD
def new(value, opts) when is_list(opts),
do: new(value, Map.new(opts))
def new(value, %{language: language} = opts) when not is_nil(language),
@ -28,4 +31,64 @@ defmodule RDF.String do
def convert(value, _), do: to_string(value)
def cast(%RDF.IRI{value: value}), do: new(value)
def cast(%RDF.Literal{datatype: datatype} = literal) do
cond do
not RDF.Literal.valid?(literal) ->
nil
datatype == XSD.string ->
literal
datatype == XSD.decimal ->
try do
literal.value
|> Decimal.to_integer()
|> RDF.Integer.new()
|> cast()
rescue
_ ->
literal.value
|> RDF.Decimal.canonical_lexical()
|> new()
end
datatype in [XSD.double, XSD.float] ->
cond do
RDF.Numeric.negative_zero?(literal) ->
new("-0")
RDF.Numeric.zero?(literal) ->
new("0")
literal.value >= 0.000_001 and literal.value < 1000000 ->
literal.value
|> RDF.Decimal.new()
|> cast()
true ->
literal.value
|> RDF.Double.canonical_lexical()
|> new()
end
datatype == XSD.dateTime ->
literal
|> RDF.DateTime.canonical_lexical_with_zone()
|> new()
datatype == XSD.time ->
literal
|> RDF.Time.canonical_lexical_with_zone()
|> new()
true ->
literal
|> RDF.Literal.canonical()
|> RDF.Literal.lexical()
|> new()
end
end
end

View file

@ -42,4 +42,78 @@ defmodule RDF.StringTest do
end
describe "cast/1" do
test "casting a string returns the input as it is" do
assert RDF.string("foo") |> RDF.String.cast() == RDF.string("foo")
end
test "casting an integer" do
assert RDF.integer(0) |> RDF.String.cast() == RDF.string("0")
assert RDF.integer(1) |> RDF.String.cast() == RDF.string("1")
end
test "casting a boolean" do
assert RDF.false |> RDF.String.cast() == RDF.string("false")
assert RDF.true |> RDF.String.cast() == RDF.string("true")
end
test "casting a decimal" do
assert RDF.decimal(0) |> RDF.String.cast() == RDF.string("0")
assert RDF.decimal(1.0) |> RDF.String.cast() == RDF.string("1")
assert RDF.decimal(3.14) |> RDF.String.cast() == RDF.string("3.14")
end
test "casting a double" do
assert RDF.double(0) |> RDF.String.cast() == RDF.string("0")
assert RDF.double(0.0) |> RDF.String.cast() == RDF.string("0")
assert RDF.double("+0") |> RDF.String.cast() == RDF.string("0")
assert RDF.double("-0") |> RDF.String.cast() == RDF.string("-0")
assert RDF.double(0.1) |> RDF.String.cast() == RDF.string("0.1")
assert RDF.double(3.14) |> RDF.String.cast() == RDF.string("3.14")
assert RDF.double(0.000_001) |> RDF.String.cast() == RDF.string("0.000001")
assert RDF.double(123_456) |> RDF.String.cast() == RDF.string("123456")
assert RDF.double(1_234_567) |> RDF.String.cast() == RDF.string("1.234567E6")
assert RDF.double(0.0000001) |> RDF.String.cast() == RDF.string("1.0E-7")
assert RDF.double(1.0e-10) |> RDF.String.cast() == RDF.string("1.0E-10")
assert RDF.double("1.0e-10") |> RDF.String.cast() == RDF.string("1.0E-10")
assert RDF.double(1.26743223e15) |> RDF.String.cast() == RDF.string("1.26743223E15")
assert RDF.double(:nan) |> RDF.String.cast() == RDF.string("NaN")
assert RDF.double(:positive_infinity) |> RDF.String.cast() == RDF.string("INF")
assert RDF.double(:negative_infinity) |> RDF.String.cast() == RDF.string("-INF")
end
@tag skip: "TODO: RDF.Float datatype"
test "casting a float"
test "casting a datetime" do
assert RDF.date_time(~N[2010-01-01T12:34:56]) |> RDF.String.cast() == RDF.string("2010-01-01T12:34:56")
assert RDF.date_time("2010-01-01T00:00:00+00:00") |> RDF.String.cast() == RDF.string("2010-01-01T00:00:00Z")
assert RDF.date_time("2010-01-01T01:00:00+01:00") |> RDF.String.cast() == RDF.string("2010-01-01T01:00:00+01:00")
assert RDF.date_time("2010-01-01 01:00:00+01:00") |> RDF.String.cast() == RDF.string("2010-01-01T01:00:00+01:00")
end
test "casting a date" do
assert RDF.date(~D[2000-01-01]) |> RDF.String.cast() == RDF.string("2000-01-01")
assert RDF.date("2000-01-01") |> RDF.String.cast() == RDF.string("2000-01-01")
assert RDF.date("2000-01-01+00:00") |> RDF.String.cast() == RDF.string("2000-01-01Z")
assert RDF.date("2000-01-01+01:00") |> RDF.String.cast() == RDF.string("2000-01-01+01:00")
assert RDF.date("0001-01-01") |> RDF.String.cast() == RDF.string("0001-01-01")
assert RDF.date("-0001-01-01") |> RDF.String.cast() == RDF.string("-0001-01-01")
end
test "casting a time" do
assert RDF.time(~T[00:00:00]) |> RDF.String.cast() == RDF.string("00:00:00")
assert RDF.time("00:00:00") |> RDF.String.cast() == RDF.string("00:00:00")
assert RDF.time("00:00:00Z") |> RDF.String.cast() == RDF.string("00:00:00Z")
assert RDF.time("00:00:00+00:00") |> RDF.String.cast() == RDF.string("00:00:00Z")
assert RDF.time("00:00:00+01:00") |> RDF.String.cast() == RDF.string("00:00:00+01:00")
end
test "casting an IRI" do
assert RDF.iri("http://example.com") |> RDF.String.cast() == RDF.string("http://example.com")
end
end
end