Redesign datatype reflection API
This commit is contained in:
parent
042ff1c1b8
commit
fa35b65d9f
23 changed files with 431 additions and 233 deletions
|
@ -207,11 +207,15 @@ defmodule RDF do
|
|||
defdelegate bnode(), to: BlankNode, as: :new
|
||||
defdelegate bnode(id), to: BlankNode, as: :new
|
||||
|
||||
@doc """
|
||||
Checks if the given value is a RDF literal.
|
||||
"""
|
||||
def literal?(%Literal{}), do: true
|
||||
def literal?(_), do: false
|
||||
|
||||
defdelegate literal(value), to: Literal, as: :new
|
||||
defdelegate literal(value, opts), to: Literal, as: :new
|
||||
|
||||
defdelegate literal?(literal), to: Literal.Datatype.Registry
|
||||
|
||||
defdelegate triple(s, p, o), to: Triple, as: :new
|
||||
defdelegate triple(tuple), to: Triple, as: :new
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
defmodule RDF.Guards do
|
||||
defguard maybe_ns_term(term)
|
||||
when is_atom(term) and term not in [nil, true, false]
|
||||
import RDF.Utils.Guards
|
||||
|
||||
defguard maybe_ns_term(term) when maybe_module(term)
|
||||
end
|
||||
|
|
|
@ -103,16 +103,16 @@ defmodule RDF.Literal do
|
|||
def coerce(%NaiveDateTime{} = value), do: RDF.XSD.DateTime.new(value)
|
||||
def coerce(%URI{} = value), do: RDF.XSD.AnyURI.new(value)
|
||||
|
||||
# Although the following catch-all-clause for all structs could handle the core datatypes
|
||||
# Although the following catch-all-clause for all structs could handle the builtin datatypes
|
||||
# we're generating dedicated clauses for them here, as they are approx. 15% faster
|
||||
Enum.each(Datatype.Registry.core_datatypes(), fn datatype ->
|
||||
Enum.each(Datatype.Registry.builtin_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
|
||||
def coerce(%datatype{} = datatype_literal) do
|
||||
if Datatype.Registry.datatype_struct?(datatype) do
|
||||
%__MODULE__{literal: datatype_literal}
|
||||
end
|
||||
end
|
||||
|
@ -148,6 +148,23 @@ defmodule RDF.Literal do
|
|||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns if the given value is a `RDF.Literal` or `RDF.Literal.Datatype` struct.
|
||||
|
||||
If you simply want to check for a `RDF.Literal` use pattern matching or `RDF.literal?/1`.
|
||||
This function is a bit slower than those and most of the time only needed when
|
||||
implementing `RDF.Literal.Datatype`s where you have to deal with the raw,
|
||||
i.e. unwrapped `RDF.Literal.Datatype` structs.
|
||||
"""
|
||||
defdelegate datatype?(value), to: RDF.Literal.Datatype.Registry, as: :datatype?
|
||||
|
||||
@doc """
|
||||
Returns if the literal uses the `RDF.Literal.Generic` datatype or on of the dedicated builtin or custom `RDF.Literal.Datatype`s.
|
||||
"""
|
||||
@spec generic?(t) :: boolean
|
||||
def generic?(%__MODULE__{literal: %RDF.Literal.Generic{}}), do: true
|
||||
def generic?(%__MODULE__{}), do: false
|
||||
|
||||
@doc """
|
||||
Returns if a literal is a language-tagged literal.
|
||||
|
||||
|
@ -178,7 +195,7 @@ defmodule RDF.Literal do
|
|||
"""
|
||||
@spec simple?(t) :: boolean
|
||||
def simple?(%__MODULE__{literal: %RDF.XSD.String{}}), do: true
|
||||
def simple?(%__MODULE__{} = _), do: false
|
||||
def simple?(%__MODULE__{}), do: false
|
||||
|
||||
|
||||
@doc """
|
||||
|
@ -192,11 +209,7 @@ defmodule RDF.Literal do
|
|||
@spec plain?(t) :: boolean
|
||||
def plain?(%__MODULE__{literal: %RDF.XSD.String{}}), do: true
|
||||
def plain?(%__MODULE__{literal: %LangString{}}), do: true
|
||||
def plain?(%__MODULE__{} = _), do: false
|
||||
|
||||
@spec typed?(t) :: boolean
|
||||
def typed?(literal), do: not plain?(literal)
|
||||
|
||||
def plain?(%__MODULE__{}), do: false
|
||||
|
||||
############################################################################
|
||||
# functions delegating to the RDF.Literal.Datatype of a RDF.Literal
|
||||
|
|
|
@ -34,6 +34,17 @@ defmodule RDF.Literal.Datatype do
|
|||
"""
|
||||
@callback do_cast(literal | any) :: Literal.t() | nil
|
||||
|
||||
@doc """
|
||||
Checks if the given `RDF.Literal` has the datatype for which the `RDF.Literal.Datatype` is implemented or is derived from it.
|
||||
|
||||
## Example
|
||||
|
||||
iex> RDF.XSD.byte(42) |> RDF.XSD.Integer.datatype?()
|
||||
true
|
||||
|
||||
"""
|
||||
@callback datatype?(Literal.t | t | literal) :: boolean
|
||||
|
||||
@doc """
|
||||
The datatype IRI of the given `RDF.Literal`.
|
||||
"""
|
||||
|
@ -139,6 +150,15 @@ defmodule RDF.Literal.Datatype do
|
|||
|
||||
defdelegate get(id), to: Literal.Datatype.Registry, as: :datatype
|
||||
|
||||
@doc !"""
|
||||
As opposed to RDF.Literal.valid?/1 this function operates on the datatype structs ...
|
||||
|
||||
It's meant for internal use only and doesn't perform checks if the struct
|
||||
passed is actually a `RDF.Literal.Datatype` struct.
|
||||
"""
|
||||
def valid?(%datatype{} = datatype_literal), do: datatype.valid?(datatype_literal)
|
||||
|
||||
|
||||
defmacro __using__(opts) do
|
||||
name = Keyword.fetch!(opts, :name)
|
||||
id = Keyword.fetch!(opts, :id)
|
||||
|
@ -157,6 +177,13 @@ defmodule RDF.Literal.Datatype do
|
|||
quote do
|
||||
@behaviour unquote(__MODULE__)
|
||||
|
||||
@doc !"""
|
||||
This function is just used to check if a module is a RDF.Literal.Datatype.
|
||||
|
||||
See `RDF.Literal.Datatype.Registry.is_rdf_literal_datatype?/1`.
|
||||
"""
|
||||
def __rdf_literal_datatype_indicator__, do: true
|
||||
|
||||
@name unquote(name)
|
||||
@impl unquote(__MODULE__)
|
||||
def name, do: @name
|
||||
|
@ -165,6 +192,16 @@ defmodule RDF.Literal.Datatype do
|
|||
@impl unquote(__MODULE__)
|
||||
def id, do: @id
|
||||
|
||||
# RDF.XSD.Datatypes offers another default implementation, but since it is
|
||||
# still in a macro implementation defoverridable doesn't work
|
||||
unless RDF.XSD.Datatype in @behaviour do
|
||||
@impl unquote(__MODULE__)
|
||||
def datatype?(%Literal{literal: literal}), do: datatype?(literal)
|
||||
def datatype?(%datatype{}), do: datatype?(datatype)
|
||||
def datatype?(__MODULE__), do: true
|
||||
def datatype?(_), do: false
|
||||
end
|
||||
|
||||
@impl unquote(__MODULE__)
|
||||
def datatype(%Literal{literal: literal}), do: datatype(literal)
|
||||
def datatype(%__MODULE__{}), do: @id
|
||||
|
@ -227,8 +264,8 @@ defmodule RDF.Literal.Datatype do
|
|||
def equal_value?(_, nil), do: nil
|
||||
def equal_value?(left, right) do
|
||||
cond do
|
||||
not RDF.literal?(right) and not RDF.term?(right) -> equal_value?(left, Literal.coerce(right))
|
||||
not RDF.literal?(left) and not RDF.term?(left) -> equal_value?(Literal.coerce(left), right)
|
||||
not Literal.datatype?(right) and not RDF.term?(right) -> equal_value?(left, Literal.coerce(right))
|
||||
not Literal.datatype?(left) and not RDF.term?(left) -> equal_value?(Literal.coerce(left), right)
|
||||
true -> do_equal_value?(left, right)
|
||||
end
|
||||
end
|
||||
|
@ -256,6 +293,9 @@ defmodule RDF.Literal.Datatype do
|
|||
|> new()
|
||||
end
|
||||
|
||||
# This is a private RDF.Literal constructor, which should be used to build
|
||||
# the RDF.Literals from the datatype literal structs instead of the
|
||||
# RDF.Literal/new/1, to bypass the unnecessary datatype checks.
|
||||
defp literal(datatype_literal), do: %Literal{literal: datatype_literal}
|
||||
|
||||
defoverridable datatype: 1,
|
||||
|
|
|
@ -5,34 +5,162 @@ defmodule RDF.Literal.Datatype.Registry do
|
|||
alias RDF.Literal.Datatype.Registry.Registration
|
||||
|
||||
import RDF.Guards
|
||||
import RDF.Utils.Guards
|
||||
|
||||
@core_datatypes [RDF.LangString | Enum.to_list(XSD.datatypes())]
|
||||
@primitive_numeric_datatypes [
|
||||
RDF.XSD.Integer,
|
||||
RDF.XSD.Decimal,
|
||||
RDF.XSD.Double
|
||||
]
|
||||
|
||||
@builtin_numeric_datatypes @primitive_numeric_datatypes ++ [
|
||||
RDF.XSD.Long,
|
||||
RDF.XSD.Int,
|
||||
RDF.XSD.Short,
|
||||
RDF.XSD.Byte,
|
||||
RDF.XSD.NonNegativeInteger,
|
||||
RDF.XSD.PositiveInteger,
|
||||
RDF.XSD.UnsignedLong,
|
||||
RDF.XSD.UnsignedInt,
|
||||
RDF.XSD.UnsignedShort,
|
||||
RDF.XSD.UnsignedByte,
|
||||
RDF.XSD.NonPositiveInteger,
|
||||
RDF.XSD.NegativeInteger,
|
||||
RDF.XSD.Float
|
||||
]
|
||||
|
||||
@builtin_xsd_datatypes [
|
||||
XSD.Boolean,
|
||||
XSD.String,
|
||||
XSD.Date,
|
||||
XSD.Time,
|
||||
XSD.DateTime,
|
||||
XSD.AnyURI
|
||||
] ++ @builtin_numeric_datatypes
|
||||
|
||||
@builtin_datatypes [RDF.LangString | @builtin_xsd_datatypes]
|
||||
|
||||
@doc """
|
||||
All core `RDF.Literal.Datatype` modules.
|
||||
Returns a list of all builtin `RDF.Literal.Datatype` modules.
|
||||
"""
|
||||
@spec core_datatypes :: Enum.t
|
||||
def core_datatypes, do: @core_datatypes
|
||||
@spec builtin_datatypes :: [RDF.Literal.Datatype.t]
|
||||
def builtin_datatypes, do: @builtin_datatypes
|
||||
|
||||
@doc """
|
||||
Checks if the given module is core datatype.
|
||||
"""
|
||||
@spec core_datatype?(module) :: boolean
|
||||
def core_datatype?(module), do: module in @core_datatypes
|
||||
Checks if the given module is a builtin datatype.
|
||||
|
||||
@doc """
|
||||
Checks if the given module is a core datatype or a registered custom datatype implementing the `RDF.Literal.Datatype` behaviour.
|
||||
Note: This doesn't include `RDF.Literal.Generic`.
|
||||
"""
|
||||
@spec datatype?(module) :: boolean
|
||||
def datatype?(module) do
|
||||
core_datatype?(module) or implements_behaviour?(module, Literal.Datatype)
|
||||
@spec builtin_datatype?(module) :: boolean
|
||||
def builtin_datatype?(module)
|
||||
|
||||
for datatype <- @builtin_datatypes do
|
||||
def builtin_datatype?(unquote(datatype)), do: true
|
||||
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
|
||||
def builtin_datatype?(_), do: false
|
||||
|
||||
@doc """
|
||||
Checks if the given module is a builtin datatype or a registered custom datatype implementing the `RDF.Literal.Datatype` behaviour.
|
||||
"""
|
||||
@spec datatype?(Literal.t | Literal.Datatype.literal | module) :: boolean
|
||||
def datatype?(value)
|
||||
|
||||
# We assume literals were created properly which means they have a proper RDF.Literal.Datatype
|
||||
def datatype?(%Literal{}), do: true
|
||||
def datatype?(value), do: datatype_struct?(value)
|
||||
|
||||
@doc false
|
||||
@spec datatype_struct?(Literal.Datatype.literal | module) :: boolean
|
||||
def datatype_struct?(value)
|
||||
|
||||
def datatype_struct?(%datatype{}), do: datatype_struct?(datatype)
|
||||
|
||||
def datatype_struct?(Literal.Generic), do: true
|
||||
|
||||
def datatype_struct?(module) when maybe_module(module) do
|
||||
builtin_datatype?(module) or is_rdf_literal_datatype?(module)
|
||||
end
|
||||
|
||||
def datatype_struct?(_), do: false
|
||||
|
||||
@doc """
|
||||
Returns a list of all builtin `RDF.XSD.Datatype` modules.
|
||||
"""
|
||||
@spec builtin_xsd_datatypes :: [RDF.Literal.Datatype.t]
|
||||
def builtin_xsd_datatypes, do: @builtin_xsd_datatypes
|
||||
|
||||
@doc false
|
||||
@spec builtin_xsd_datatype?(module) :: boolean
|
||||
def builtin_xsd_datatype?(module)
|
||||
|
||||
for datatype <- @builtin_xsd_datatypes do
|
||||
def builtin_xsd_datatype?(unquote(datatype)), do: true
|
||||
end
|
||||
|
||||
def builtin_xsd_datatype?(_), do: false
|
||||
|
||||
@doc """
|
||||
Checks if the given module is a builtin XSD datatype or a registered custom datatype implementing the `RDF.XSD.Datatype` behaviour.
|
||||
"""
|
||||
@spec xsd_datatype?(Literal.t | XSD.Datatype.literal | module) :: boolean
|
||||
def xsd_datatype?(value)
|
||||
def xsd_datatype?(%Literal{literal: datatype_struct}), do: xsd_datatype?(datatype_struct)
|
||||
def xsd_datatype?(value), do: xsd_datatype_struct?(value)
|
||||
|
||||
@doc false
|
||||
@spec xsd_datatype_struct?(RDF.Literal.t() | XSD.Datatype.literal | module) :: boolean
|
||||
def xsd_datatype_struct?(value)
|
||||
|
||||
def xsd_datatype_struct?(%datatype{}), do: xsd_datatype_struct?(datatype)
|
||||
|
||||
def xsd_datatype_struct?(module) when maybe_module(module) do
|
||||
builtin_xsd_datatype?(module) or is_xsd_datatype?(module)
|
||||
end
|
||||
|
||||
def xsd_datatype_struct?(_), do: false
|
||||
|
||||
@doc """
|
||||
Returns a list of all numeric datatype modules.
|
||||
"""
|
||||
@spec builtin_numeric_datatypes() :: [RDF.Literal.Datatype.t]
|
||||
def builtin_numeric_datatypes(), do: @builtin_numeric_datatypes
|
||||
|
||||
@doc """
|
||||
The set of all primitive numeric datatypes.
|
||||
"""
|
||||
@spec primitive_numeric_datatypes() :: [RDF.Literal.Datatype.t]
|
||||
def primitive_numeric_datatypes(), do: @primitive_numeric_datatypes
|
||||
|
||||
@doc false
|
||||
@spec builtin_numeric_datatype?(module) :: boolean
|
||||
def builtin_numeric_datatype?(module)
|
||||
|
||||
for datatype <- @builtin_numeric_datatypes do
|
||||
def builtin_numeric_datatype?(unquote(datatype)), do: true
|
||||
end
|
||||
|
||||
def builtin_numeric_datatype?(_), do: false
|
||||
|
||||
|
||||
@doc """
|
||||
Returns if a given literal or datatype has or is a numeric datatype.
|
||||
"""
|
||||
@spec numeric_datatype?(RDF.Literal.t() | RDF.XSD.Datatype.t() | any) :: boolean
|
||||
def numeric_datatype?(literal)
|
||||
def numeric_datatype?(%RDF.Literal{literal: literal}), do: numeric_datatype?(literal)
|
||||
def numeric_datatype?(%datatype{}), do: numeric_datatype?(datatype)
|
||||
|
||||
def numeric_datatype?(datatype) when maybe_module(datatype) do
|
||||
builtin_numeric_datatype?(datatype) or (
|
||||
xsd_datatype?(datatype) and
|
||||
Enum.any?(@primitive_numeric_datatypes, fn numeric_primitive ->
|
||||
datatype.derived_from?(numeric_primitive)
|
||||
end)
|
||||
)
|
||||
end
|
||||
|
||||
def numeric_datatype?(_), do: false
|
||||
|
||||
@doc """
|
||||
Returns the `RDF.Literal.Datatype` for a datatype IRI.
|
||||
|
@ -50,15 +178,31 @@ defmodule RDF.Literal.Datatype.Registry do
|
|||
def xsd_datatype(id) do
|
||||
datatype = datatype(id)
|
||||
|
||||
if datatype && implements_behaviour?(datatype, XSD.Datatype) do
|
||||
if datatype && is_xsd_datatype?(datatype) do
|
||||
datatype
|
||||
end
|
||||
end
|
||||
|
||||
defp implements_behaviour?(module, behaviour) do
|
||||
module.module_info[:attributes]
|
||||
|> Keyword.get_values(:behaviour)
|
||||
|> List.flatten()
|
||||
|> Enum.member?(behaviour)
|
||||
# TODO: Find a better/faster solution for checking datatype modules which includes unknown custom datatypes.
|
||||
# Although checking for the presence of a function via __info__(:functions) is
|
||||
# the fastest way to reflect a module type on average over the positive and negative
|
||||
# case (being roughly comparable to a map access), we would still have to rescue
|
||||
# from an UndefinedFunctionError since its raised by trying to access __info__
|
||||
# on plain (non-module) atoms, so we can do the check by rescueing in the first place.
|
||||
# Although the positive is actually faster than the __info__(:functions) check,
|
||||
# the negative is more than 7 times slower.
|
||||
# (Properly checking for the behaviour attribute with module_info[:attributes]
|
||||
# is more than 200 times slower.)
|
||||
|
||||
defp is_rdf_literal_datatype?(module) do
|
||||
module.__rdf_literal_datatype_indicator__()
|
||||
rescue
|
||||
UndefinedFunctionError -> false
|
||||
end
|
||||
|
||||
defp is_xsd_datatype?(module) do
|
||||
module.__xsd_datatype_indicator__()
|
||||
rescue
|
||||
UndefinedFunctionError -> false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,6 +9,8 @@ defmodule RDF.LangString do
|
|||
name: "langString",
|
||||
id: RDF.Utils.Bootstrapping.rdf_iri("langString")
|
||||
|
||||
import RDF.Utils.Guards
|
||||
|
||||
alias RDF.Literal.Datatype
|
||||
alias RDF.Literal
|
||||
|
||||
|
@ -21,7 +23,7 @@ defmodule RDF.LangString do
|
|||
@spec new(any, String.t | atom | keyword) :: Literal.t
|
||||
def new(value, language_or_opts \\ [])
|
||||
def new(value, language) when is_binary(language), do: new(value, language: language)
|
||||
def new(value, language) when is_atom(language), do: new(value, language: language)
|
||||
def new(value, language) when is_ordinary_atom(language), do: new(value, language: language)
|
||||
def new(value, opts) do
|
||||
%Literal{
|
||||
literal: %__MODULE__{
|
||||
|
@ -33,7 +35,7 @@ defmodule RDF.LangString do
|
|||
|
||||
defp normalize_language(nil), do: nil
|
||||
defp normalize_language(""), do: nil
|
||||
defp normalize_language(language) when is_atom(language), do: language |> to_string() |> normalize_language()
|
||||
defp normalize_language(language) when is_ordinary_atom(language), do: language |> to_string() |> normalize_language()
|
||||
defp normalize_language(language), do: String.downcase(language)
|
||||
|
||||
@impl RDF.Literal.Datatype
|
||||
|
|
6
lib/rdf/utils/guards.ex
Normal file
6
lib/rdf/utils/guards.ex
Normal file
|
@ -0,0 +1,6 @@
|
|||
defmodule RDF.Utils.Guards do
|
||||
defguard is_ordinary_atom(term)
|
||||
when is_atom(term) and term not in [nil, true, false]
|
||||
|
||||
defguard maybe_module(term) when is_ordinary_atom(term)
|
||||
end
|
|
@ -5,19 +5,9 @@ defmodule RDF.XSD do
|
|||
see <https://www.w3.org/TR/xmlschema-2/>
|
||||
"""
|
||||
|
||||
alias __MODULE__
|
||||
alias RDF.{IRI, Literal}
|
||||
import RDF.Utils.Guards
|
||||
|
||||
@datatypes [
|
||||
XSD.Boolean,
|
||||
XSD.String,
|
||||
XSD.Date,
|
||||
XSD.Time,
|
||||
XSD.DateTime,
|
||||
XSD.AnyURI
|
||||
]
|
||||
|> MapSet.new()
|
||||
|> MapSet.union(XSD.Numeric.datatypes())
|
||||
alias __MODULE__
|
||||
|
||||
@facets [
|
||||
XSD.Facets.MinInclusive,
|
||||
|
@ -32,39 +22,15 @@ defmodule RDF.XSD do
|
|||
|
||||
@facets_by_name Map.new(@facets, fn facet -> {facet.name(), facet} end)
|
||||
|
||||
def facet(name) when is_atom(name), do: @facets_by_name[to_string(name)]
|
||||
def facet(name) when is_ordinary_atom(name), do: @facets_by_name[to_string(name)]
|
||||
def facet(name), do: @facets_by_name[name]
|
||||
|
||||
@doc """
|
||||
The list of all XSD datatypes.
|
||||
Returns if the given value is a `RDF.XSD.Datatype` struct or `RDF.Literal` with a `RDF.XSD.Datatype`.
|
||||
"""
|
||||
@spec datatypes() :: Enum.t()
|
||||
def datatypes(), do: @datatypes
|
||||
defdelegate datatype?(value), to: RDF.Literal.Datatype.Registry, as: :xsd_datatype?
|
||||
|
||||
@datatypes_by_name Map.new(@datatypes, fn datatype -> {datatype.name(), datatype} end)
|
||||
@datatypes_by_iri Map.new(@datatypes, fn datatype -> {datatype.id(), datatype} end)
|
||||
|
||||
def datatype_by_name(name) when is_atom(name), do: @datatypes_by_name[to_string(name)]
|
||||
def datatype_by_name(name), do: @datatypes_by_name[name]
|
||||
def datatype_by_iri(iri) when is_binary(iri), do: @datatypes_by_iri[IRI.new(iri)]
|
||||
def datatype_by_iri(%IRI{} = iri), do: @datatypes_by_iri[iri]
|
||||
|
||||
@doc """
|
||||
Returns if a given datatype is a XSD datatype.
|
||||
"""
|
||||
def datatype?(datatype), do: datatype in @datatypes
|
||||
|
||||
@doc """
|
||||
Returns if a given argument is a `RDF.XSD.datatype` literal.
|
||||
"""
|
||||
def literal?(%Literal{literal: %datatype{}}), do: datatype?(datatype)
|
||||
def literal?(%datatype{}), do: datatype?(datatype)
|
||||
def literal?(_), do: false
|
||||
|
||||
@doc false
|
||||
def valid?(%datatype{} = datatype_literal), do: datatype.valid?(datatype_literal)
|
||||
|
||||
for datatype <- @datatypes do
|
||||
for datatype <- RDF.Literal.Datatype.Registry.builtin_xsd_datatypes() do
|
||||
defdelegate unquote(String.to_atom(datatype.name))(value), to: datatype, as: :new
|
||||
defdelegate unquote(String.to_atom(datatype.name))(value, opts), to: datatype, as: :new
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ defmodule RDF.XSD.Datatype do
|
|||
|
||||
@type comparison_result :: :lt | :gt | :eq
|
||||
|
||||
import RDF.Utils.Guards
|
||||
|
||||
@doc """
|
||||
Returns if the `RDF.XSD.Datatype` is a primitive datatype.
|
||||
|
@ -34,15 +35,13 @@ defmodule RDF.XSD.Datatype do
|
|||
@callback base_primitive :: t()
|
||||
|
||||
@doc """
|
||||
Checks if a `RDF.XSD.Datatype` is directly or indirectly derived from another `RDF.XSD.Datatype`.
|
||||
Checks if the `RDF.XSD.Datatype` is directly or indirectly derived from the given `RDF.XSD.Datatype`.
|
||||
|
||||
Note that this is just a basic datatype reflection function on the module level
|
||||
and does not work with `RDF.Literal`s. See `c:RDF.Literal.Datatype.datatype?/1` instead.
|
||||
"""
|
||||
@callback derived_from?(t()) :: boolean
|
||||
|
||||
@doc """
|
||||
Checks if the datatype of a given literal is derived from a `RDF.XSD.Datatype`.
|
||||
"""
|
||||
@callback derived?(RDF.XSD.Literal.t()) :: boolean
|
||||
|
||||
@doc """
|
||||
The set of applicable facets of a `RDF.XSD.Datatype`.
|
||||
"""
|
||||
|
@ -95,18 +94,21 @@ defmodule RDF.XSD.Datatype do
|
|||
uncanonical_lexical: RDF.XSD.Datatype.uncanonical_lexical()
|
||||
}
|
||||
|
||||
@impl unquote(__MODULE__)
|
||||
def derived_from?(datatype)
|
||||
@doc !"""
|
||||
This function is just used to check if a module is a RDF.XSD.Datatype.
|
||||
|
||||
def derived_from?(__MODULE__), do: true
|
||||
See `RDF.Literal.Datatype.Registry.is_xsd_datatype?/1`.
|
||||
"""
|
||||
def __xsd_datatype_indicator__, do: true
|
||||
|
||||
def derived_from?(datatype) do
|
||||
base = base()
|
||||
not is_nil(base) and base.derived_from?(datatype)
|
||||
@impl RDF.Literal.Datatype
|
||||
def datatype?(%RDF.Literal{literal: literal}), do: datatype?(literal)
|
||||
def datatype?(%datatype{}), do: datatype?(datatype)
|
||||
def datatype?(__MODULE__), do: true
|
||||
def datatype?(datatype) when maybe_module(datatype) do
|
||||
RDF.XSD.datatype?(datatype) and datatype.derived_from?(__MODULE__)
|
||||
end
|
||||
|
||||
@impl unquote(__MODULE__)
|
||||
def derived?(literal), do: RDF.XSD.Datatype.derived_from?(literal, __MODULE__)
|
||||
def datatype?(_), do: false
|
||||
|
||||
# Dialyzer causes a warning on all primitives since the facet_conform?/2 call
|
||||
# always returns true there, so the other branch is unnecessary. This could
|
||||
|
@ -252,14 +254,4 @@ defmodule RDF.XSD.Datatype do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
@spec base_primitive(t()) :: t()
|
||||
def base_primitive(%RDF.Literal{literal: literal}), do: base_primitive(literal)
|
||||
def base_primitive(%datatype{}), do: base_primitive(datatype)
|
||||
def base_primitive(datatype), do: datatype.base_primitive()
|
||||
|
||||
@spec derived_from?(t() | literal() | RDF.Literal.t(), t()) :: boolean
|
||||
def derived_from?(%RDF.Literal{literal: literal}, super_datatype), do: derived_from?(literal, super_datatype)
|
||||
def derived_from?(%datatype{}, super_datatype), do: derived_from?(datatype, super_datatype)
|
||||
def derived_from?(datatype, super_datatype) when is_atom(datatype), do: datatype.derived_from?(super_datatype)
|
||||
end
|
||||
|
|
|
@ -23,6 +23,9 @@ defmodule RDF.XSD.Datatype.Primitive do
|
|||
@impl RDF.XSD.Datatype
|
||||
def base_primitive, do: __MODULE__
|
||||
|
||||
@impl RDF.XSD.Datatype
|
||||
def derived_from?(_), do: false
|
||||
|
||||
@impl RDF.XSD.Datatype
|
||||
def init_valid_lexical(value, lexical, opts)
|
||||
def init_valid_lexical(_value, nil, _opts), do: nil
|
||||
|
@ -40,8 +43,8 @@ defmodule RDF.XSD.Datatype.Primitive do
|
|||
|
||||
@impl RDF.Literal.Datatype
|
||||
def do_cast(value) do
|
||||
if RDF.XSD.literal?(value) do
|
||||
if derived?(value) do
|
||||
if RDF.Literal.datatype?(value) do
|
||||
if datatype?(value) do
|
||||
build_valid(value.value, value.uncanonical_lexical, [])
|
||||
end
|
||||
else
|
||||
|
|
|
@ -20,6 +20,10 @@ defmodule RDF.XSD.Datatype.Restriction do
|
|||
@impl RDF.XSD.Datatype
|
||||
def base_primitive, do: @base.base_primitive()
|
||||
|
||||
@impl RDF.XSD.Datatype
|
||||
def derived_from?(@base), do: true
|
||||
def derived_from?(datatype), do: @base.derived_from?(datatype)
|
||||
|
||||
@impl RDF.XSD.Datatype
|
||||
def applicable_facets, do: @base.applicable_facets()
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ defmodule RDF.XSD.Boolean do
|
|||
end
|
||||
|
||||
def do_cast(literal_or_value) do
|
||||
if RDF.XSD.Numeric.literal?(literal_or_value) do
|
||||
if RDF.XSD.Numeric.datatype?(literal_or_value) do
|
||||
new(literal_or_value.value not in [0, 0.0, :nan])
|
||||
else
|
||||
super(literal_or_value)
|
||||
|
@ -82,7 +82,7 @@ defmodule RDF.XSD.Boolean do
|
|||
def ebv(%datatype{} = literal) do
|
||||
if RDF.XSD.Numeric.datatype?(datatype) do
|
||||
if datatype.valid?(literal) and
|
||||
not (literal.value == 0 or literal.value == :nan),
|
||||
not (datatype.value(literal) == 0 or datatype.value(literal) == :nan),
|
||||
do: RDF.XSD.Boolean.Value.true(),
|
||||
else: RDF.XSD.Boolean.Value.false()
|
||||
end
|
||||
|
|
|
@ -107,8 +107,8 @@ defmodule RDF.XSD.Decimal do
|
|||
|
||||
def digit_count(literal) do
|
||||
cond do
|
||||
RDF.XSD.Integer.derived?(literal) -> RDF.XSD.Integer.digit_count(literal)
|
||||
derived?(literal) -> do_digit_count(literal)
|
||||
RDF.XSD.Integer.datatype?(literal) -> RDF.XSD.Integer.digit_count(literal)
|
||||
datatype?(literal) -> do_digit_count(literal)
|
||||
true -> nil
|
||||
end
|
||||
end
|
||||
|
@ -132,8 +132,8 @@ defmodule RDF.XSD.Decimal do
|
|||
|
||||
def fraction_digit_count(literal) do
|
||||
cond do
|
||||
RDF.XSD.Integer.derived?(literal) -> 0
|
||||
derived?(literal) -> do_fraction_digit_count(literal)
|
||||
RDF.XSD.Integer.datatype?(literal) -> 0
|
||||
datatype?(literal) -> do_fraction_digit_count(literal)
|
||||
true -> nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -74,7 +74,7 @@ defmodule RDF.XSD.Integer do
|
|||
"""
|
||||
@spec digit_count(RDF.XSD.Literal.t()) :: non_neg_integer | nil
|
||||
def digit_count(%datatype{} = literal) do
|
||||
if derived?(literal) and datatype.valid?(literal) do
|
||||
if datatype?(literal) and datatype.valid?(literal) do
|
||||
literal
|
||||
|> datatype.canonical()
|
||||
|> datatype.lexical()
|
||||
|
|
|
@ -3,67 +3,13 @@ defmodule RDF.XSD.Numeric do
|
|||
Collection of functions for numeric literals.
|
||||
"""
|
||||
|
||||
@type t :: module
|
||||
|
||||
alias Elixir.Decimal, as: D
|
||||
|
||||
import Kernel, except: [abs: 1, floor: 1, ceil: 1]
|
||||
|
||||
@datatypes MapSet.new([
|
||||
RDF.XSD.Decimal,
|
||||
RDF.XSD.Integer,
|
||||
RDF.XSD.Long,
|
||||
RDF.XSD.Int,
|
||||
RDF.XSD.Short,
|
||||
RDF.XSD.Byte,
|
||||
RDF.XSD.NonNegativeInteger,
|
||||
RDF.XSD.PositiveInteger,
|
||||
RDF.XSD.UnsignedLong,
|
||||
RDF.XSD.UnsignedInt,
|
||||
RDF.XSD.UnsignedShort,
|
||||
RDF.XSD.UnsignedByte,
|
||||
RDF.XSD.NonPositiveInteger,
|
||||
RDF.XSD.NegativeInteger,
|
||||
RDF.XSD.Double,
|
||||
RDF.XSD.Float
|
||||
])
|
||||
|
||||
@type t ::
|
||||
RDF.XSD.Decimal.t()
|
||||
| RDF.XSD.Integer.t()
|
||||
| RDF.XSD.Long.t()
|
||||
| RDF.XSD.Int.t()
|
||||
| RDF.XSD.Short.t()
|
||||
| RDF.XSD.Byte.t()
|
||||
| RDF.XSD.NonNegativeInteger.t()
|
||||
| RDF.XSD.PositiveInteger.t()
|
||||
| RDF.XSD.UnsignedLong.t()
|
||||
| RDF.XSD.UnsignedInt.t()
|
||||
| RDF.XSD.UnsignedShort.t()
|
||||
| RDF.XSD.UnsignedByte.t()
|
||||
| RDF.XSD.NonPositiveInteger.t()
|
||||
| RDF.XSD.NegativeInteger.t()
|
||||
| RDF.XSD.Double.t()
|
||||
| RDF.XSD.Float.t()
|
||||
|
||||
@doc """
|
||||
The set of all numeric datatypes.
|
||||
"""
|
||||
@spec datatypes() :: Enum.t
|
||||
def datatypes(), do: @datatypes
|
||||
|
||||
@doc """
|
||||
Returns if a given datatype is a numeric datatype.
|
||||
"""
|
||||
@spec datatype?(RDF.XSD.Datatype.t() | any) :: boolean
|
||||
def datatype?(datatype), do: datatype in @datatypes
|
||||
|
||||
@doc """
|
||||
Returns if a given XSD literal has a numeric datatype.
|
||||
"""
|
||||
@spec literal?(RDF.Literal.t() | any) :: boolean
|
||||
def literal?(literal)
|
||||
def literal?(%RDF.Literal{literal: literal}), do: literal?(literal)
|
||||
def literal?(%datatype{}), do: datatype?(datatype)
|
||||
def literal?(_), do: false
|
||||
defdelegate datatype?(value), to: RDF.Literal.Datatype.Registry, as: :numeric_datatype?
|
||||
|
||||
@doc """
|
||||
Tests for numeric value equality of two numeric XSD datatyped literals.
|
||||
|
@ -346,8 +292,8 @@ defmodule RDF.XSD.Numeric do
|
|||
|
||||
def abs(value) do
|
||||
cond do
|
||||
literal?(value) ->
|
||||
if RDF.XSD.valid?(value) do
|
||||
datatype?(value) ->
|
||||
if RDF.Literal.Datatype.valid?(value) do
|
||||
%datatype{} = value
|
||||
|
||||
case value.value do
|
||||
|
@ -367,7 +313,7 @@ defmodule RDF.XSD.Numeric do
|
|||
end
|
||||
end
|
||||
|
||||
RDF.XSD.literal?(value) ->
|
||||
RDF.Literal.datatype?(value) ->
|
||||
nil
|
||||
|
||||
true ->
|
||||
|
@ -424,8 +370,8 @@ defmodule RDF.XSD.Numeric do
|
|||
|
||||
def round(value, precision) do
|
||||
cond do
|
||||
literal?(value) ->
|
||||
if RDF.XSD.valid?(value) do
|
||||
datatype?(value) ->
|
||||
if RDF.Literal.Datatype.valid?(value) do
|
||||
if precision < 0 do
|
||||
value.value
|
||||
|> new_decimal()
|
||||
|
@ -437,7 +383,7 @@ defmodule RDF.XSD.Numeric do
|
|||
end
|
||||
end
|
||||
|
||||
RDF.XSD.literal?(value) ->
|
||||
RDF.Literal.datatype?(value) ->
|
||||
nil
|
||||
|
||||
true ->
|
||||
|
@ -494,12 +440,12 @@ defmodule RDF.XSD.Numeric do
|
|||
|
||||
def ceil(value) do
|
||||
cond do
|
||||
literal?(value) ->
|
||||
if RDF.XSD.valid?(value) do
|
||||
datatype?(value) ->
|
||||
if RDF.Literal.Datatype.valid?(value) do
|
||||
literal(value)
|
||||
end
|
||||
|
||||
RDF.XSD.literal?(value) ->
|
||||
RDF.Literal.datatype?(value) ->
|
||||
nil
|
||||
|
||||
true ->
|
||||
|
@ -550,10 +496,10 @@ defmodule RDF.XSD.Numeric do
|
|||
|
||||
def floor(value) do
|
||||
cond do
|
||||
literal?(value) ->
|
||||
if RDF.XSD.valid?(value), do: literal(value)
|
||||
datatype?(value) ->
|
||||
if RDF.Literal.Datatype.valid?(value), do: literal(value)
|
||||
|
||||
RDF.XSD.literal?(value) ->
|
||||
RDF.Literal.datatype?(value) ->
|
||||
nil
|
||||
|
||||
true ->
|
||||
|
@ -578,8 +524,8 @@ defmodule RDF.XSD.Numeric do
|
|||
cond do
|
||||
is_nil(left) -> nil
|
||||
is_nil(right) -> nil
|
||||
not RDF.XSD.literal?(left) -> arithmetic_operation(op, RDF.Literal.coerce(left), right, fun)
|
||||
not RDF.XSD.literal?(right) -> arithmetic_operation(op, left, RDF.Literal.coerce(right), fun)
|
||||
not RDF.Literal.datatype?(left) -> arithmetic_operation(op, RDF.Literal.coerce(left), right, fun)
|
||||
not RDF.Literal.datatype?(right) -> arithmetic_operation(op, left, RDF.Literal.coerce(right), fun)
|
||||
true -> false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -65,7 +65,7 @@ defmodule RDF.XSD.String do
|
|||
end
|
||||
|
||||
def do_cast(%datatype{} = literal) do
|
||||
if RDF.XSD.datatype?(datatype) do
|
||||
if RDF.Literal.Datatype.Registry.xsd_datatype_struct?(datatype) do
|
||||
default_canonical_cast(literal, datatype)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,9 +33,14 @@ defmodule RDF.XSD.Datatype.Test.Case do
|
|||
@invalid unquote(invalid)
|
||||
|
||||
test "registration" do
|
||||
assert unquote(datatype) in XSD.datatypes()
|
||||
assert XSD.datatype_by_name(unquote(datatype_name)) == unquote(datatype)
|
||||
assert XSD.datatype_by_iri(unquote(datatype_iri)) == unquote(datatype)
|
||||
assert unquote(datatype) in RDF.Literal.Datatype.Registry.builtin_datatypes()
|
||||
assert unquote(datatype) in RDF.Literal.Datatype.Registry.builtin_xsd_datatypes()
|
||||
|
||||
assert unquote(datatype) |> RDF.Literal.Datatype.Registry.builtin_datatype?()
|
||||
assert unquote(datatype) |> RDF.Literal.Datatype.Registry.builtin_xsd_datatype?()
|
||||
|
||||
assert RDF.Literal.Datatype.get(unquote(datatype_iri)) == unquote(datatype)
|
||||
assert XSD.Datatype.get(unquote(datatype_iri)) == unquote(datatype)
|
||||
end
|
||||
|
||||
test "primitive/0" do
|
||||
|
@ -59,7 +64,7 @@ defmodule RDF.XSD.Datatype.Test.Case do
|
|||
end
|
||||
|
||||
test "derived_from?/1" do
|
||||
assert unquote(datatype).derived_from?(unquote(datatype)) == true
|
||||
assert unquote(datatype).derived_from?(unquote(datatype)) == false
|
||||
|
||||
unless unquote(primitive) do
|
||||
assert unquote(datatype).derived_from?(unquote(base)) == true
|
||||
|
@ -67,6 +72,26 @@ defmodule RDF.XSD.Datatype.Test.Case do
|
|||
end
|
||||
end
|
||||
|
||||
describe "datatype?/1" do
|
||||
test "with itself" do
|
||||
assert unquote(datatype).datatype?(unquote(datatype)) == true
|
||||
end
|
||||
|
||||
test "with non-RDF values" do
|
||||
assert unquote(datatype).datatype?(self()) == false
|
||||
assert unquote(datatype).datatype?(Elixir.Enum) == false
|
||||
assert unquote(datatype).datatype?(:foo) == false
|
||||
end
|
||||
|
||||
unless unquote(primitive) do
|
||||
test "on a base datatype" do
|
||||
# We're using apply here to suppress "nil.datatype?/1 is undefined" warnings caused by the primitives
|
||||
assert apply(unquote(base), :datatype?, [unquote(datatype)]) == true
|
||||
assert apply(unquote(base_primitive), :datatype?, [unquote(datatype)]) == true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "applicable_facets/0" do
|
||||
assert MapSet.new(unquote(datatype).applicable_facets()) ==
|
||||
MapSet.new(unquote(applicable_facets))
|
||||
|
@ -88,10 +113,36 @@ defmodule RDF.XSD.Datatype.Test.Case do
|
|||
assert unquote(datatype).id() == RDF.iri(unquote(datatype_iri))
|
||||
end
|
||||
|
||||
test "language/1" do
|
||||
Enum.each(@valid, fn {input, _} ->
|
||||
assert (unquote(datatype).new(input) |> unquote(datatype).language()) == nil
|
||||
end)
|
||||
describe "general datatype?/1" do
|
||||
test "on the exact same datatype" do
|
||||
assert (unquote(datatype).datatype?(unquote(datatype))) == true
|
||||
Enum.each(@valid, fn {input, _} ->
|
||||
literal = unquote(datatype).new(input)
|
||||
assert (unquote(datatype).datatype?(literal)) == true
|
||||
assert (unquote(datatype).datatype?(literal.literal)) == true
|
||||
end)
|
||||
end
|
||||
|
||||
unless unquote(primitive) do
|
||||
test "on the base datatype" do
|
||||
assert (unquote(base).datatype?(unquote(datatype))) == true
|
||||
Enum.each(@valid, fn {input, _} ->
|
||||
literal = unquote(datatype).new(input)
|
||||
assert (unquote(base).datatype?(literal)) == true
|
||||
assert (unquote(base).datatype?(literal.literal)) == true
|
||||
end)
|
||||
end
|
||||
|
||||
test "on the base primitive datatype" do
|
||||
assert (unquote(base_primitive).datatype?(unquote(datatype))) == true
|
||||
Enum.each(@valid, fn {input, _} ->
|
||||
literal = unquote(datatype).new(input)
|
||||
assert (unquote(base_primitive).datatype?(literal)) == true
|
||||
assert (unquote(base_primitive).datatype?(literal.literal)) == true
|
||||
end)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
test "datatype/1" do
|
||||
|
@ -100,6 +151,12 @@ defmodule RDF.XSD.Datatype.Test.Case do
|
|||
end)
|
||||
end
|
||||
|
||||
test "language/1" do
|
||||
Enum.each(@valid, fn {input, _} ->
|
||||
assert (unquote(datatype).new(input) |> unquote(datatype).language()) == nil
|
||||
end)
|
||||
end
|
||||
|
||||
describe "general new" do
|
||||
Enum.each(@valid, fn {input, {value, lexical, _}} ->
|
||||
expected = %RDF.Literal{
|
||||
|
|
|
@ -90,6 +90,15 @@ defmodule RDF.Literal.GenericTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "datatype?/1" do
|
||||
assert Generic.datatype?(Generic) == true
|
||||
Enum.each @valid, fn {input, {_, datatype}} ->
|
||||
literal = Generic.new(input, datatype: datatype)
|
||||
assert Generic.datatype?(literal) == true
|
||||
assert Generic.datatype?(literal.literal) == true
|
||||
end
|
||||
end
|
||||
|
||||
test "datatype/1" do
|
||||
Enum.each @valid, fn {input, {_, datatype}} ->
|
||||
assert (Generic.new(input, datatype: datatype) |> Generic.datatype()) == RDF.iri(datatype)
|
||||
|
|
|
@ -100,6 +100,15 @@ defmodule RDF.LangStringTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "datatype?/1" do
|
||||
assert LangString.datatype?(LangString) == true
|
||||
Enum.each @valid, fn {input, {_, language}} ->
|
||||
literal = LangString.new(input, language: language)
|
||||
assert LangString.datatype?(literal) == true
|
||||
assert LangString.datatype?(literal.literal) == true
|
||||
end
|
||||
end
|
||||
|
||||
test "datatype/1" do
|
||||
Enum.each @valid, fn {input, {_, language}} ->
|
||||
assert (LangString.new(input, language: language) |> LangString.datatype()) == RDF.iri(LangString.id())
|
||||
|
|
|
@ -4,6 +4,7 @@ defmodule RDF.Literal.Datatype.RegistryTest do
|
|||
alias RDF.TestDatatypes.Age
|
||||
alias RDF.Literal.Datatype
|
||||
alias RDF.NS
|
||||
alias RDF.TestDatatypes
|
||||
|
||||
@unsupported_xsd_datatypes ~w[
|
||||
ENTITIES
|
||||
|
@ -37,8 +38,8 @@ defmodule RDF.Literal.Datatype.RegistryTest do
|
|||
|
||||
|
||||
describe "datatype/1" do
|
||||
test "core datatypes" do
|
||||
Enum.each(Datatype.Registry.core_datatypes(), fn datatype ->
|
||||
test "builtin datatypes" do
|
||||
Enum.each(Datatype.Registry.builtin_datatypes(), fn datatype ->
|
||||
assert datatype == Datatype.Registry.datatype(datatype.id)
|
||||
assert datatype == Datatype.Registry.datatype(to_string(datatype.id))
|
||||
end)
|
||||
|
@ -67,21 +68,40 @@ defmodule RDF.Literal.Datatype.RegistryTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "xsd_datatype/1" do
|
||||
test "when a core XSD datatype with the given IRI exists" do
|
||||
assert XSD.String = Datatype.Registry.xsd_datatype(NS.XSD.string)
|
||||
end
|
||||
test "datatype?/1" do
|
||||
assert Datatype.Registry.datatype?(XSD.string("foo"))
|
||||
assert Datatype.Registry.datatype?(~L"foo"en)
|
||||
assert Datatype.Registry.datatype?(XSD.integer(42))
|
||||
assert Datatype.Registry.datatype?(XSD.byte(42))
|
||||
assert Datatype.Registry.datatype?(TestDatatypes.Age.new(42))
|
||||
assert Datatype.Registry.datatype?(RDF.literal("foo", datatype: "http://example.com"))
|
||||
refute Datatype.Registry.datatype?(~r/foo/)
|
||||
refute Datatype.Registry.datatype?(:foo)
|
||||
refute Datatype.Registry.datatype?(42)
|
||||
end
|
||||
|
||||
test "when a custom XSD datatype with the given IRI exists" do
|
||||
assert Age = Datatype.Registry.xsd_datatype(EX.Age)
|
||||
end
|
||||
test "xsd_datatype?/1" do
|
||||
assert Datatype.Registry.xsd_datatype?(XSD.string("foo"))
|
||||
assert Datatype.Registry.xsd_datatype?(XSD.integer(42))
|
||||
assert Datatype.Registry.xsd_datatype?(XSD.byte(42))
|
||||
assert Datatype.Registry.xsd_datatype?(TestDatatypes.Age.new(42))
|
||||
refute Datatype.Registry.xsd_datatype?(~L"foo"en)
|
||||
refute Datatype.Registry.xsd_datatype?(RDF.literal("foo", datatype: "http://example.com"))
|
||||
refute Datatype.Registry.xsd_datatype?(~r/foo/)
|
||||
refute Datatype.Registry.xsd_datatype?(:foo)
|
||||
refute Datatype.Registry.xsd_datatype?(42)
|
||||
end
|
||||
|
||||
test "when datatype with the given IRI exists, but it is not an XSD datatype" do
|
||||
refute Datatype.Registry.xsd_datatype(RDF.langString)
|
||||
end
|
||||
|
||||
test "when no datatype with the given IRI exists" do
|
||||
refute Datatype.Registry.xsd_datatype(EX.foo)
|
||||
end
|
||||
test "numeric_datatype?/1" do
|
||||
assert Datatype.Registry.numeric_datatype?(XSD.integer(42))
|
||||
assert Datatype.Registry.numeric_datatype?(XSD.byte(42))
|
||||
assert Datatype.Registry.numeric_datatype?(TestDatatypes.Age.new(42))
|
||||
refute Datatype.Registry.numeric_datatype?(XSD.string("foo"))
|
||||
refute Datatype.Registry.numeric_datatype?(~L"foo"en)
|
||||
refute Datatype.Registry.numeric_datatype?(RDF.literal("foo", datatype: "http://example.com"))
|
||||
refute Datatype.Registry.numeric_datatype?(~r/foo/)
|
||||
refute Datatype.Registry.numeric_datatype?(:foo)
|
||||
refute Datatype.Registry.numeric_datatype?(42)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,8 +30,8 @@ defmodule RDF.LiteralTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "with core datatype literals" do
|
||||
Enum.each Datatype.Registry.core_datatypes(), fn datatype ->
|
||||
test "with builtin datatype literals" do
|
||||
Enum.each Datatype.Registry.builtin_datatypes(), fn datatype ->
|
||||
datatype_literal = datatype.new("foo").literal
|
||||
assert %Literal{literal: ^datatype_literal} = Literal.new(datatype_literal)
|
||||
end
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
defmodule RDF.XSD.DatatypeTest do
|
||||
use ExUnit.Case
|
||||
|
||||
alias RDF.XSD
|
||||
|
||||
test "base_primitive/1" do
|
||||
assert XSD.integer(42) |> XSD.Datatype.base_primitive() == XSD.Integer
|
||||
assert XSD.non_negative_integer(42) |> XSD.Datatype.base_primitive() == XSD.Integer
|
||||
assert XSD.positive_integer(42) |> XSD.Datatype.base_primitive() == XSD.Integer
|
||||
end
|
||||
|
||||
test "derived_from?/2" do
|
||||
assert XSD.integer(42) |> XSD.Datatype.derived_from?(XSD.Integer)
|
||||
assert XSD.non_negative_integer(42) |> XSD.Datatype.derived_from?(XSD.Integer)
|
||||
assert XSD.positive_integer(42) |> XSD.Datatype.derived_from?(XSD.Integer)
|
||||
assert XSD.positive_integer(42) |> XSD.Datatype.derived_from?(XSD.NonNegativeInteger)
|
||||
end
|
||||
end
|
|
@ -3,8 +3,8 @@ defmodule RDF.XSDTest do
|
|||
|
||||
doctest RDF.XSD
|
||||
|
||||
test "Datatype constructor alias functions" do
|
||||
Enum.each(XSD.datatypes(), fn datatype ->
|
||||
test "builtin datatype constructor alias functions" do
|
||||
Enum.each(RDF.Literal.Datatype.Registry.builtin_xsd_datatypes(), fn datatype ->
|
||||
assert apply(XSD, String.to_atom(datatype.name), [1]) == datatype.new(1)
|
||||
assert apply(XSD, String.to_atom(Macro.underscore(datatype.name)), [1]) == datatype.new(1)
|
||||
end)
|
||||
|
|
Loading…
Reference in a new issue