rdf-ex/lib/rdf/datatypes/double.ex
Marcel Otto 4105a3e59b core: RDF.DateTime datatype
- negative years not yet supported
2017-04-30 16:53:23 +02:00

82 lines
2.3 KiB
Elixir

defmodule RDF.Double do
use RDF.Datatype, id: RDF.Datatype.NS.XSD.double
def build_literal_by_value(value, opts) do
case convert(value, opts) do
float when is_float(float) ->
build_literal(float, decimal_form(float), opts)
nil ->
build_literal(nil, invalid_lexical(value), opts)
special_value when is_atom(special_value) ->
build_literal(special_value, nil, opts)
end
end
def convert(value, _) when is_float(value), do: value
def convert(value, _) when is_integer(value), do: value / 1
def convert(value, opts) when is_binary(value) do
case Float.parse(value) do
{float, ""} ->
float
{float, remainder} ->
# 1.E-8 is not a valid Elixir float literal and consequently not fully parsed with Float.parse
if Regex.match?(~r/^\.e?[\+\-]?\d+$/i, remainder) do
convert(to_string(float) <> String.trim_leading(remainder, "."), opts)
else
super(value, opts)
end
:error ->
case String.upcase(value) do
"INF" -> :positive_infinity
"+INF" -> :positive_infinity
"-INF" -> :negative_infinity
"NAN" -> :nan
_ -> super(value, opts)
end
end
end
def convert(value, _)
when value in ~W[positive_infinity negative_infinity nan]a,
do: value
def convert(value, opts), do: super(value, opts)
def canonical_lexical(value) do
case value do
:nan -> "NaN"
:positive_infinity -> "INF"
:negative_infinity -> "-INF"
float when is_float(float) -> exponential_form(float)
_ -> to_string(value)
end
end
def decimal_form(float) when is_float(float) do
to_string(float)
end
def exponential_form(float) when is_float(float) do
# Can't use simple %f transformation due to special requirements from
# N3 tests in representation
[i, f, e] =
:io_lib.format("~.15e", [float])
|> List.first
|> to_string
|> String.split(~r/[\.e]/)
f =
case String.replace(f, ~r/0*$/, "", global: false) do # remove any trailing zeroes
"" -> "0" # ...but there must be a digit to the right of the decimal point
f -> f
end
e = String.trim_leading(e, "+")
"#{i}.#{f}E#{e}"
end
end