From 568190e32724d60ca456748b08f88c67263257bf Mon Sep 17 00:00:00 2001 From: Marcel Otto Date: Mon, 22 Apr 2019 11:17:16 +0200 Subject: [PATCH] Add digit_count and fraction_digit_count to RDF.Decimal --- CHANGELOG.md | 2 ++ lib/rdf/datatypes/decimal.ex | 34 ++++++++++++++++++++++++++++ lib/rdf/datatypes/integer.ex | 14 ++++++++++++ test/unit/datatypes/decimal_test.exs | 27 +++++++++++++++++++++- test/unit/datatypes/integer_test.exs | 8 +++++++ 5 files changed, 84 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65f97d5..64a4f48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ This project adheres to [Semantic Versioning](http://semver.org/) and ### Added - `RDF.Literal.matches?/3` for XQuery regex pattern matching +- `RDF.Decimal.digit_count/1` and `RDF.Decimal.fraction_digit_count/1` for + determining the number of digits of decimal literals [Compare v0.6.0...HEAD](https://github.com/marcelotto/rdf-ex/compare/v0.6.0...HEAD) diff --git a/lib/rdf/datatypes/decimal.ex b/lib/rdf/datatypes/decimal.ex index dcab7f9..fc52d4c 100644 --- a/lib/rdf/datatypes/decimal.ex +++ b/lib/rdf/datatypes/decimal.ex @@ -8,6 +8,7 @@ defmodule RDF.Decimal do alias Elixir.Decimal, as: D + @xsd_integer RDF.Datatype.NS.XSD.integer @impl RDF.Datatype def convert(value, opts) @@ -113,4 +114,37 @@ defmodule RDF.Decimal do @impl RDF.Datatype def compare(left, right), do: RDF.Numeric.compare(left, right) + @doc """ + The number of digits in the XML Schema canonical form of the literal value. + """ + def digit_count(%RDF.Literal{datatype: @id} = literal) do + if valid?(literal) do + literal + |> canonical() + |> lexical() + |> String.replace(".", "") + |> String.replace("-", "") + |> String.length() + end + end + + def digit_count(%RDF.Literal{datatype: @xsd_integer} = literal), + do: RDF.Integer.digit_count(literal) + + @doc """ + The number of digits to the right of the decimal point in the XML Schema canonical form of the literal value. + """ + def fraction_digit_count(%RDF.Literal{datatype: @id, value: value} = literal) do + if valid?(literal) do + [_, fraction] = + literal + |> canonical() + |> lexical() + |> String.split(".") + String.length(fraction) + end + end + + def fraction_digit_count(%RDF.Literal{datatype: @xsd_integer}), do: 0 + end diff --git a/lib/rdf/datatypes/integer.ex b/lib/rdf/datatypes/integer.ex index 15ab41c..fbaca0b 100644 --- a/lib/rdf/datatypes/integer.ex +++ b/lib/rdf/datatypes/integer.ex @@ -73,4 +73,18 @@ defmodule RDF.Integer do @impl RDF.Datatype def compare(left, right), do: RDF.Numeric.compare(left, right) + + @doc """ + The number of digits in the XML Schema canonical form of the literal value. + """ + def digit_count(%RDF.Literal{datatype: @id} = literal) do + if valid?(literal) do + literal + |> canonical() + |> lexical() + |> String.replace("-", "") + |> String.length() + end + end + end diff --git a/test/unit/datatypes/decimal_test.exs b/test/unit/datatypes/decimal_test.exs index d346c56..385001c 100644 --- a/test/unit/datatypes/decimal_test.exs +++ b/test/unit/datatypes/decimal_test.exs @@ -122,6 +122,32 @@ defmodule RDF.DecimalTest do end end + test "digit_count/1" do + assert RDF.Decimal.digit_count(RDF.decimal("1.2345")) == 5 + assert RDF.Decimal.digit_count(RDF.decimal("-1.2345")) == 5 + assert RDF.Decimal.digit_count(RDF.decimal("+1.2345")) == 5 + assert RDF.Decimal.digit_count(RDF.decimal("01.23450")) == 5 + assert RDF.Decimal.digit_count(RDF.decimal("01.23450")) == 5 + assert RDF.Decimal.digit_count(RDF.decimal("NAN")) == nil + + assert RDF.Decimal.digit_count(RDF.integer("2")) == 1 + assert RDF.Decimal.digit_count(RDF.integer("23")) == 2 + assert RDF.Decimal.digit_count(RDF.integer("023")) == 2 + end + + test "fraction_digit_count/1" do + assert RDF.Decimal.fraction_digit_count(RDF.decimal("1.2345")) == 4 + assert RDF.Decimal.fraction_digit_count(RDF.decimal("-1.2345")) == 4 + assert RDF.Decimal.fraction_digit_count(RDF.decimal("+1.2345")) == 4 + assert RDF.Decimal.fraction_digit_count(RDF.decimal("01.23450")) == 4 + assert RDF.Decimal.fraction_digit_count(RDF.decimal("0.023450")) == 5 + assert RDF.Decimal.fraction_digit_count(RDF.decimal("NAN")) == nil + + assert RDF.Decimal.fraction_digit_count(RDF.integer("2")) == 0 + assert RDF.Decimal.fraction_digit_count(RDF.integer("23")) == 0 + assert RDF.Decimal.fraction_digit_count(RDF.integer("023")) == 0 + end + defmacrop sigil_d(str, _opts) do quote do @@ -151,5 +177,4 @@ defmodule RDF.DecimalTest do assert Decimal.canonical_decimal(~d"1.2E3") == ~d"1200.0" assert Decimal.canonical_decimal(~d"-42E+3") == ~d"-42000.0" end - end diff --git a/test/unit/datatypes/integer_test.exs b/test/unit/datatypes/integer_test.exs index c20dde7..4745a82 100644 --- a/test/unit/datatypes/integer_test.exs +++ b/test/unit/datatypes/integer_test.exs @@ -76,6 +76,14 @@ defmodule RDF.IntegerTest do end end + test "digit_count/1" do + assert RDF.Integer.digit_count(RDF.integer("2")) == 1 + assert RDF.Integer.digit_count(RDF.integer("23")) == 2 + assert RDF.Integer.digit_count(RDF.integer("023")) == 2 + assert RDF.Integer.digit_count(RDF.integer("+023")) == 2 + assert RDF.Integer.digit_count(RDF.integer("-023")) == 2 + assert RDF.Integer.digit_count(RDF.integer("NaN")) == nil + end describe "equality" do test "two literals are equal when they have the same datatype and lexical form" do