Add ProtocolEx-based custom datatype registration
This commit is contained in:
parent
4fedb2cfc0
commit
faaebb2de2
33 changed files with 182 additions and 60 deletions
|
@ -209,10 +209,7 @@ defmodule RDF do
|
|||
defdelegate literal(value), to: Literal, as: :new
|
||||
defdelegate literal(value, opts), to: Literal, as: :new
|
||||
|
||||
def literal?(%Literal{}), do: true
|
||||
def literal?(%RDF.Literal.Generic{}), do: true
|
||||
def literal?(%datatype{}), do: Literal.Datatype.Registry.datatype?(datatype)
|
||||
def literal?(_), do: false
|
||||
defdelegate literal?(literal), to: Literal.Datatype.Registry
|
||||
|
||||
defdelegate triple(s, p, o), to: Triple, as: :new
|
||||
defdelegate triple(tuple), to: Triple, as: :new
|
||||
|
|
|
@ -92,12 +92,6 @@ defmodule RDF.Literal do
|
|||
|
||||
def coerce(%__MODULE__{} = literal), do: literal
|
||||
|
||||
Enum.each(Datatype.Registry.datatypes(), fn datatype ->
|
||||
def coerce(%unquote(datatype){} = literal) do
|
||||
%__MODULE__{literal: literal}
|
||||
end
|
||||
end)
|
||||
|
||||
def coerce(value) when is_binary(value), do: RDF.XSD.String.new(value)
|
||||
def coerce(value) when is_boolean(value), do: RDF.XSD.Boolean.new(value)
|
||||
def coerce(value) when is_integer(value), do: RDF.XSD.Integer.new(value)
|
||||
|
@ -108,7 +102,22 @@ defmodule RDF.Literal do
|
|||
def coerce(%DateTime{} = value), do: RDF.XSD.DateTime.new(value)
|
||||
def coerce(%NaiveDateTime{} = value), do: RDF.XSD.DateTime.new(value)
|
||||
def coerce(%URI{} = value), do: RDF.XSD.AnyURI.new(value)
|
||||
def coerce(_), do: nil
|
||||
|
||||
# Although the following catch-all-clause for all structs could handle the core datatypes
|
||||
# we're generating dedicated clauses for them here, as they are approx. 15% faster
|
||||
Enum.each(Datatype.Registry.core_datatypes(), fn datatype ->
|
||||
def coerce(%unquote(datatype){} = datatype_literal) do
|
||||
%__MODULE__{literal: datatype_literal}
|
||||
end
|
||||
end)
|
||||
|
||||
def coerce(%_datatype{} = datatype_literal) do
|
||||
if Datatype.Registry.literal?(datatype_literal) do
|
||||
%__MODULE__{literal: datatype_literal}
|
||||
end
|
||||
end
|
||||
|
||||
def coerce(_), do: nil
|
||||
|
||||
|
||||
@doc """
|
||||
|
|
|
@ -140,6 +140,17 @@ defmodule RDF.Literal.Datatype do
|
|||
defmacro __using__(opts) do
|
||||
name = Keyword.fetch!(opts, :name)
|
||||
id = Keyword.fetch!(opts, :id)
|
||||
do_register = Keyword.get(opts, :register, not is_nil(id))
|
||||
datatype = __CALLER__.module
|
||||
|
||||
# TODO: find an alternative to Code.eval_quoted - We want to support that id can be passed via a function call
|
||||
unquoted_id =
|
||||
if do_register do
|
||||
id
|
||||
|> Code.eval_quoted([], __ENV__)
|
||||
|> elem(0)
|
||||
|> to_string()
|
||||
end
|
||||
|
||||
quote do
|
||||
@behaviour unquote(__MODULE__)
|
||||
|
@ -258,6 +269,15 @@ defmodule RDF.Literal.Datatype do
|
|||
literal.__struct__.lexical(literal)
|
||||
end
|
||||
end
|
||||
|
||||
if unquote(do_register) do
|
||||
import ProtocolEx
|
||||
|
||||
defimpl_ex Registration, unquote(unquoted_id),
|
||||
for: RDF.Literal.Datatype.Registry.Registration do
|
||||
def datatype(id), do: unquote(datatype)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,33 +1,45 @@
|
|||
# TODO: This registry should be managed automatically/dynamically and be extendable, to allow user-defined datatypes ...
|
||||
defmodule RDF.Literal.Datatype.Registry do
|
||||
@moduledoc false
|
||||
|
||||
alias RDF.{Literal, IRI, XSD}
|
||||
alias RDF.Literal.Datatype.Registry.Registration
|
||||
|
||||
@datatypes [RDF.LangString | Enum.to_list(XSD.datatypes())]
|
||||
import RDF.Guards
|
||||
|
||||
@mapping Map.new(@datatypes, fn datatype -> {IRI.new(datatype.id), datatype} end)
|
||||
@core_datatypes [RDF.LangString | Enum.to_list(XSD.datatypes())]
|
||||
@mapping Map.new(@core_datatypes, fn datatype -> {IRI.new(datatype.id), datatype} end)
|
||||
|
||||
@doc """
|
||||
The mapping of IRIs of datatypes to their `RDF.Literal.Datatype`.
|
||||
The IRIs of all core `RDF.Literal.Datatype`s.
|
||||
"""
|
||||
@spec mapping :: %{IRI.t => Literal.Datatype.t}
|
||||
def mapping, do: @mapping
|
||||
@spec core_ids :: [IRI.t]
|
||||
def core_ids, do: Map.keys(@mapping)
|
||||
|
||||
@doc """
|
||||
The IRIs of all datatypes with a `RDF.Literal.Datatype` defined.
|
||||
All core `RDF.Literal.Datatype` modules.
|
||||
"""
|
||||
@spec ids :: [IRI.t]
|
||||
def ids, do: Map.keys(@mapping)
|
||||
@spec core_datatypes :: Enum.t
|
||||
def core_datatypes, do: @core_datatypes
|
||||
|
||||
@doc """
|
||||
All defined `RDF.Literal.Datatype` modules.
|
||||
Checks if the given module is core datatype.
|
||||
"""
|
||||
@spec datatypes :: Enum.t
|
||||
def datatypes, do: @datatypes
|
||||
@spec core_datatype?(module) :: boolean
|
||||
def core_datatype?(module), do: module in @core_datatypes
|
||||
|
||||
@doc """
|
||||
Checks if the given module is a core datatype or a registered custom datatype implementing the `RDF.Literal.Datatype` behaviour.
|
||||
"""
|
||||
@spec datatype?(module) :: boolean
|
||||
def datatype?(module), do: module in @datatypes
|
||||
def datatype?(module) do
|
||||
core_datatype?(module) or implements_datatype_behaviour?(module)
|
||||
end
|
||||
|
||||
@spec literal?(module) :: boolean
|
||||
def literal?(%Literal{}), do: true
|
||||
def literal?(%Literal.Generic{}), do: true
|
||||
def literal?(%datatype{}), do: datatype?(datatype)
|
||||
def literal?(_), do: false
|
||||
|
||||
@doc """
|
||||
Returns the `RDF.Literal.Datatype` for a directly datatype IRI or the datatype IRI of a `RDF.Literal`.
|
||||
|
@ -35,5 +47,19 @@ defmodule RDF.Literal.Datatype.Registry do
|
|||
@spec get(Literal.t | IRI.t | String.t) :: Literal.Datatype.t
|
||||
def get(%Literal{} = literal), do: Literal.datatype(literal)
|
||||
def get(id) when is_binary(id), do: id |> IRI.new() |> get()
|
||||
def get(id), do: @mapping[id]
|
||||
def get(id) when maybe_ns_term(id), do: id |> IRI.new() |> get()
|
||||
def get(id), do: @mapping[id] || get_custom_datatype(id)
|
||||
|
||||
defp get_custom_datatype(id) do
|
||||
id
|
||||
|> to_string()
|
||||
|> Registration.datatype()
|
||||
end
|
||||
|
||||
defp implements_datatype_behaviour?(module) do
|
||||
module.module_info[:attributes]
|
||||
|> Keyword.get_values(:behaviour)
|
||||
|> List.flatten()
|
||||
|> Enum.member?(RDF.Literal.Datatype)
|
||||
end
|
||||
end
|
||||
|
|
5
lib/rdf/literal/datatype/registry/protocol.ex
Normal file
5
lib/rdf/literal/datatype/registry/protocol.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
import ProtocolEx
|
||||
|
||||
defprotocol_ex RDF.Literal.Datatype.Registry.Registration do
|
||||
def datatype(id), do: nil
|
||||
end
|
|
@ -7,7 +7,8 @@ defmodule RDF.LangString do
|
|||
|
||||
use RDF.Literal.Datatype,
|
||||
name: "langString",
|
||||
id: RDF.Utils.Bootstrapping.rdf_iri("langString")
|
||||
id: RDF.Utils.Bootstrapping.rdf_iri("langString"),
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
alias RDF.Literal.Datatype
|
||||
alias RDF.Literal
|
||||
|
|
|
@ -11,7 +11,8 @@ defmodule RDF.XSD.AnyURI do
|
|||
|
||||
use RDF.XSD.Datatype.Primitive,
|
||||
name: "anyURI",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("anyURI")
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("anyURI"),
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
@impl RDF.XSD.Datatype
|
||||
@spec lexical_mapping(String.t(), Keyword.t()) :: valid_value
|
||||
|
|
|
@ -8,7 +8,8 @@ defmodule RDF.XSD.Boolean do
|
|||
|
||||
use RDF.XSD.Datatype.Primitive,
|
||||
name: "boolean",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("boolean")
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("boolean"),
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
@impl RDF.XSD.Datatype
|
||||
def lexical_mapping(lexical, _) do
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.Byte do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "byte",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("byte"),
|
||||
base: RDF.XSD.Short
|
||||
base: RDF.XSD.Short,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MinInclusive, -128
|
||||
def_facet_constraint RDF.XSD.Facets.MaxInclusive, 127
|
||||
|
|
|
@ -11,7 +11,8 @@ defmodule RDF.XSD.Date do
|
|||
|
||||
use RDF.XSD.Datatype.Primitive,
|
||||
name: "date",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("date")
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("date"),
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
|
||||
# TODO: Are GMT/UTC actually allowed? Maybe because it is supported by Elixir's Datetime ...
|
||||
|
|
|
@ -7,7 +7,8 @@ defmodule RDF.XSD.DateTime do
|
|||
|
||||
use RDF.XSD.Datatype.Primitive,
|
||||
name: "dateTime",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("dateTime")
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("dateTime"),
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
@impl RDF.XSD.Datatype
|
||||
def lexical_mapping(lexical, opts) do
|
||||
|
|
|
@ -7,7 +7,8 @@ defmodule RDF.XSD.Decimal do
|
|||
|
||||
use RDF.XSD.Datatype.Primitive,
|
||||
name: "decimal",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("decimal")
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("decimal"),
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
alias Elixir.Decimal, as: D
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ defmodule RDF.XSD.Double do
|
|||
|
||||
use RDF.XSD.Datatype.Primitive,
|
||||
name: "double",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("double")
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("double"),
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
@special_values ~W[positive_infinity negative_infinity nan]a
|
||||
|
||||
|
|
|
@ -9,5 +9,6 @@ defmodule RDF.XSD.Float do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "float",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("float"),
|
||||
base: RDF.XSD.Double
|
||||
base: RDF.XSD.Double,
|
||||
register: false # core datatypes don't need to be registered
|
||||
end
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.Int do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "int",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("int"),
|
||||
base: RDF.XSD.Long
|
||||
base: RDF.XSD.Long,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MinInclusive, -2_147_483_648
|
||||
def_facet_constraint RDF.XSD.Facets.MaxInclusive, 2_147_483_647
|
||||
|
|
|
@ -10,7 +10,8 @@ defmodule RDF.XSD.Integer do
|
|||
|
||||
use RDF.XSD.Datatype.Primitive,
|
||||
name: "integer",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("integer")
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("integer"),
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_applicable_facet RDF.XSD.Facets.MinInclusive
|
||||
def_applicable_facet RDF.XSD.Facets.MaxInclusive
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.Long do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "long",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("long"),
|
||||
base: RDF.XSD.Integer
|
||||
base: RDF.XSD.Integer,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MinInclusive, -9_223_372_036_854_775_808
|
||||
def_facet_constraint RDF.XSD.Facets.MaxInclusive, 9_223_372_036_854_775_807
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.NegativeInteger do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "negativeInteger",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("negativeInteger"),
|
||||
base: RDF.XSD.NonPositiveInteger
|
||||
base: RDF.XSD.NonPositiveInteger,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MaxInclusive, -1
|
||||
end
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.NonNegativeInteger do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "nonNegativeInteger",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("nonNegativeInteger"),
|
||||
base: RDF.XSD.Integer
|
||||
base: RDF.XSD.Integer,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MinInclusive, 0
|
||||
end
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.NonPositiveInteger do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "nonPositiveInteger",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("nonPositiveInteger"),
|
||||
base: RDF.XSD.Integer
|
||||
base: RDF.XSD.Integer,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MaxInclusive, 0
|
||||
end
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.PositiveInteger do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "positiveInteger",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("positiveInteger"),
|
||||
base: RDF.XSD.NonNegativeInteger
|
||||
base: RDF.XSD.NonNegativeInteger,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MinInclusive, 1
|
||||
end
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.Short do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "short",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("short"),
|
||||
base: RDF.XSD.Int
|
||||
base: RDF.XSD.Int,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MinInclusive, -32768
|
||||
def_facet_constraint RDF.XSD.Facets.MaxInclusive, 32767
|
||||
|
|
|
@ -7,7 +7,8 @@ defmodule RDF.XSD.String do
|
|||
|
||||
use RDF.XSD.Datatype.Primitive,
|
||||
name: "string",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("string")
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("string"),
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
@impl RDF.XSD.Datatype
|
||||
@spec lexical_mapping(String.t(), Keyword.t()) :: valid_value
|
||||
|
|
|
@ -7,7 +7,8 @@ defmodule RDF.XSD.Time do
|
|||
|
||||
use RDF.XSD.Datatype.Primitive,
|
||||
name: "time",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("time")
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("time"),
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
# TODO: Are GMT/UTC actually allowed? Maybe because it is supported by Elixir's Datetime ...
|
||||
@grammar ~r/\A(\d{2}:\d{2}:\d{2}(?:\.\d+)?)((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z/
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.UnsignedByte do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "unsignedByte",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("unsignedByte"),
|
||||
base: RDF.XSD.UnsignedShort
|
||||
base: RDF.XSD.UnsignedShort,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MinInclusive, 0
|
||||
def_facet_constraint RDF.XSD.Facets.MaxInclusive, 255
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.UnsignedInt do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "unsignedInt",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("unsignedInt"),
|
||||
base: RDF.XSD.UnsignedLong
|
||||
base: RDF.XSD.UnsignedLong,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MinInclusive, 0
|
||||
def_facet_constraint RDF.XSD.Facets.MaxInclusive, 4_294_967_295
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.UnsignedLong do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "unsignedLong",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("unsignedLong"),
|
||||
base: RDF.XSD.NonNegativeInteger
|
||||
base: RDF.XSD.NonNegativeInteger,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MinInclusive, 0
|
||||
def_facet_constraint RDF.XSD.Facets.MaxInclusive, 18_446_744_073_709_551_615
|
||||
|
|
|
@ -2,7 +2,8 @@ defmodule RDF.XSD.UnsignedShort do
|
|||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "unsignedShort",
|
||||
id: RDF.Utils.Bootstrapping.xsd_iri("unsignedShort"),
|
||||
base: RDF.XSD.UnsignedInt
|
||||
base: RDF.XSD.UnsignedInt,
|
||||
register: false # core datatypes don't need to be registered
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MinInclusive, 0
|
||||
def_facet_constraint RDF.XSD.Facets.MaxInclusive, 65535
|
||||
|
|
2
mix.exs
2
mix.exs
|
@ -14,6 +14,7 @@ defmodule RDF.Mixfile do
|
|||
start_permanent: Mix.env == :prod,
|
||||
deps: deps(),
|
||||
elixirc_paths: elixirc_paths(Mix.env()),
|
||||
compilers: Mix.compilers ++ [:protocol_ex],
|
||||
|
||||
# Dialyzer
|
||||
dialyzer: dialyzer(),
|
||||
|
@ -68,6 +69,7 @@ defmodule RDF.Mixfile do
|
|||
defp deps do
|
||||
[
|
||||
{:decimal, "~> 1.5"},
|
||||
{:protocol_ex, "~> 0.4"},
|
||||
|
||||
{:credo, "~> 1.3", only: [:dev, :test], runtime: false},
|
||||
{:dialyxir, "~> 1.0.0-rc.7", only: :dev, runtime: false},
|
||||
|
|
1
mix.lock
1
mix.lock
|
@ -20,6 +20,7 @@
|
|||
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
|
||||
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
|
||||
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
|
||||
"protocol_ex": {:hex, :protocol_ex, "0.4.3", "4acbe35da85109dc40315c1139bb7a65ebc7fc102d384cd8b3038384fbb9b282", [:mix], [], "hexpm", "6ca5ddb3505c9c86f17cd3f19838b34bf89966ae17078f79f81983b6a4391fe9"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"},
|
||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"},
|
||||
}
|
||||
|
|
10
test/support/test_datatypes.ex
Normal file
10
test/support/test_datatypes.ex
Normal file
|
@ -0,0 +1,10 @@
|
|||
defmodule RDF.TestDatatypes do
|
||||
defmodule Age do
|
||||
use RDF.XSD.Datatype.Restriction,
|
||||
name: "age",
|
||||
id: "http://example.com/Age",
|
||||
base: RDF.XSD.PositiveInteger
|
||||
|
||||
def_facet_constraint RDF.XSD.Facets.MaxInclusive, 150
|
||||
end
|
||||
end
|
|
@ -1,6 +1,7 @@
|
|||
defmodule RDF.Literal.Datatype.RegistryTest do
|
||||
use ExUnit.Case
|
||||
use RDF.Test.Case
|
||||
|
||||
alias RDF.TestDatatypes.Age
|
||||
alias RDF.Literal.Datatype
|
||||
alias RDF.NS
|
||||
|
||||
|
@ -36,20 +37,40 @@ defmodule RDF.Literal.Datatype.RegistryTest do
|
|||
|
||||
|
||||
describe "get/1" do
|
||||
test "IRIs of supported datatypes from the XSD namespace" do
|
||||
Enum.each(@supported_xsd_datatypes, fn xsd_datatype_iri ->
|
||||
assert xsd_datatype = Datatype.Registry.get(xsd_datatype_iri)
|
||||
assert xsd_datatype == Datatype.Registry.get(to_string(xsd_datatype_iri))
|
||||
assert RDF.iri(xsd_datatype.id) == xsd_datatype_iri
|
||||
|
||||
test "core datatypes" do
|
||||
Enum.each(Datatype.Registry.core_datatypes(), fn datatype ->
|
||||
assert datatype == Datatype.Registry.get(datatype.id)
|
||||
assert datatype == Datatype.Registry.get(to_string(datatype.id))
|
||||
end)
|
||||
end
|
||||
|
||||
test "IRIs of unsupported datatypes from the XSD namespace" do
|
||||
test "supported datatypes from the XSD namespace" do
|
||||
Enum.each(@supported_xsd_datatypes, fn xsd_datatype_iri ->
|
||||
assert xsd_datatype = Datatype.Registry.get(xsd_datatype_iri)
|
||||
assert xsd_datatype.id == xsd_datatype_iri
|
||||
end)
|
||||
end
|
||||
|
||||
test "unsupported datatypes from the XSD namespace" do
|
||||
Enum.each(@unsupported_xsd_datatypes, fn xsd_datatype_iri ->
|
||||
refute Datatype.Registry.get(xsd_datatype_iri)
|
||||
refute Datatype.Registry.get(to_string(xsd_datatype_iri))
|
||||
end)
|
||||
end
|
||||
|
||||
test "with IRI of custom datatype" do
|
||||
assert Age == Datatype.Registry.get(Age.id)
|
||||
end
|
||||
|
||||
test "with namespace terms" do
|
||||
assert Age == Datatype.Registry.get(EX.Age)
|
||||
end
|
||||
end
|
||||
|
||||
test "core datatypes are handled differently and should not be registered (for performance reasons)" do
|
||||
Enum.each(Datatype.Registry.core_datatypes(), fn datatype ->
|
||||
refute Datatype.Registry.Registration.datatype(datatype.id)
|
||||
refute Datatype.Registry.Registration.datatype(to_string(datatype.id))
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
defmodule RDF.LiteralTest do
|
||||
use ExUnit.Case
|
||||
use RDF.Test.Case
|
||||
|
||||
import RDF.Sigils
|
||||
import RDF.TestLiterals
|
||||
|
||||
alias RDF.{Literal, XSD, LangString}
|
||||
|
@ -31,13 +30,18 @@ defmodule RDF.LiteralTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "with typed literals" do
|
||||
Enum.each Datatype.Registry.datatypes(), fn datatype ->
|
||||
test "with core datatype literals" do
|
||||
Enum.each Datatype.Registry.core_datatypes(), fn datatype ->
|
||||
datatype_literal = datatype.new("foo").literal
|
||||
assert %Literal{literal: ^datatype_literal} = Literal.new(datatype_literal)
|
||||
end
|
||||
end
|
||||
|
||||
test "with custom datatype literals" do
|
||||
datatype_literal = RDF.TestDatatypes.Age.new(42).literal
|
||||
assert %Literal{literal: typed_literal} = Literal.new(datatype_literal)
|
||||
end
|
||||
|
||||
test "when options without datatype given" do
|
||||
assert Literal.new(true, []) == XSD.Boolean.new(true)
|
||||
assert Literal.new(42, []) == XSD.Integer.new(42)
|
||||
|
@ -80,6 +84,10 @@ defmodule RDF.LiteralTest do
|
|||
assert Literal.new("foo", datatype: NS.XSD.string) == XSD.String.new("foo")
|
||||
end
|
||||
|
||||
test "registered custom datatype" do
|
||||
assert Literal.new(42, datatype: EX.Age) == RDF.TestDatatypes.Age.new(42)
|
||||
end
|
||||
|
||||
test "unmapped/unknown datatype" do
|
||||
assert Literal.new("custom typed value", datatype: "http://example/dt") ==
|
||||
Generic.new("custom typed value", datatype: "http://example/dt")
|
||||
|
|
Loading…
Reference in a new issue