Add functions for the basic logical operations to RDF.Boolean
This commit is contained in:
parent
a8cc834616
commit
71dc3d5acc
3 changed files with 159 additions and 0 deletions
|
@ -13,6 +13,8 @@ This project adheres to [Semantic Versioning](http://semver.org/) and
|
|||
- top-level constant functions `RDF.true` and `RDF.false` for the two boolean
|
||||
RDF.Literal values
|
||||
- `RDF.Numeric` with a list of all numeric datatypes
|
||||
- the logical operators and the Effective Boolean Value (EBV) coercion algorithm
|
||||
from the XPath and SPARQL specs on `RDF.Boolean`
|
||||
|
||||
|
||||
[Compare v0.4.1...HEAD](https://github.com/marcelotto/rdf-ex/compare/v0.4.1...HEAD)
|
||||
|
|
|
@ -25,6 +25,126 @@ defmodule RDF.Boolean do
|
|||
def convert(value, opts), do: super(value, opts)
|
||||
|
||||
|
||||
@doc """
|
||||
Returns `RDF.true` if the effective boolean value of the given argument is `RDF.false`, or `RDF.false` if it is `RDF.true`.
|
||||
|
||||
Otherwise it returns `nil`.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> RDF.Boolean.fn_not(RDF.true)
|
||||
RDF.false
|
||||
iex> RDF.Boolean.fn_not(RDF.false)
|
||||
RDF.true
|
||||
|
||||
iex> RDF.Boolean.fn_not(true)
|
||||
RDF.false
|
||||
iex> RDF.Boolean.fn_not(false)
|
||||
RDF.true
|
||||
|
||||
iex> RDF.Boolean.fn_not(42)
|
||||
RDF.false
|
||||
iex> RDF.Boolean.fn_not("")
|
||||
RDF.true
|
||||
|
||||
iex> RDF.Boolean.fn_not(nil)
|
||||
nil
|
||||
|
||||
see <https://www.w3.org/TR/xpath-functions/#func-not>
|
||||
"""
|
||||
def fn_not(value) do
|
||||
case ebv(value) do
|
||||
%RDF.Literal{value: true} -> RDF.Boolean.Value.false
|
||||
%RDF.Literal{value: false} -> RDF.Boolean.Value.true
|
||||
nil -> nil
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the logical `AND` of the effective boolean value of the given arguments.
|
||||
|
||||
It returns `nil` if only one argument is `nil` and the other argument is
|
||||
`RDF.true` and `RDF.false` if the other argument is `RDF.false`.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> RDF.Boolean.logical_and(RDF.true, RDF.true)
|
||||
RDF.true
|
||||
iex> RDF.Boolean.logical_and(RDF.true, RDF.false)
|
||||
RDF.false
|
||||
|
||||
iex> RDF.Boolean.logical_and(RDF.true, nil)
|
||||
nil
|
||||
iex> RDF.Boolean.logical_and(nil, RDF.false)
|
||||
RDF.false
|
||||
iex> RDF.Boolean.logical_and(nil, nil)
|
||||
nil
|
||||
|
||||
see <https://www.w3.org/TR/sparql11-query/#func-logical-and>
|
||||
|
||||
"""
|
||||
def logical_and(left, right) do
|
||||
case ebv(left) do
|
||||
%RDF.Literal{value: false} ->
|
||||
RDF.false
|
||||
|
||||
%RDF.Literal{value: true} ->
|
||||
case ebv(right) do
|
||||
%RDF.Literal{value: true} -> RDF.true
|
||||
%RDF.Literal{value: false} -> RDF.false
|
||||
nil -> nil
|
||||
end
|
||||
|
||||
nil ->
|
||||
if match?(%RDF.Literal{value: false}, ebv(right)) do
|
||||
RDF.false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the logical `OR` of the effective boolean value of the given arguments.
|
||||
|
||||
It returns `nil` if only one argument is `nil` and the other argument is
|
||||
`RDF.false` and `RDF.true` if the other argument is `RDF.true`.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> RDF.Boolean.logical_or(RDF.true, RDF.false)
|
||||
RDF.true
|
||||
iex> RDF.Boolean.logical_or(RDF.false, RDF.false)
|
||||
RDF.false
|
||||
|
||||
iex> RDF.Boolean.logical_or(RDF.true, nil)
|
||||
RDF.true
|
||||
iex> RDF.Boolean.logical_or(nil, RDF.false)
|
||||
nil
|
||||
iex> RDF.Boolean.logical_or(nil, nil)
|
||||
nil
|
||||
|
||||
see <https://www.w3.org/TR/sparql11-query/#func-logical-or>
|
||||
|
||||
"""
|
||||
def logical_or(left, right) do
|
||||
case ebv(left) do
|
||||
%RDF.Literal{value: true} ->
|
||||
RDF.true
|
||||
|
||||
%RDF.Literal{value: false} ->
|
||||
case ebv(right) do
|
||||
%RDF.Literal{value: true} -> RDF.true
|
||||
%RDF.Literal{value: false} -> RDF.false
|
||||
nil -> nil
|
||||
end
|
||||
|
||||
nil ->
|
||||
if match?(%RDF.Literal{value: true}, ebv(right)) do
|
||||
RDF.true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@xsd_boolean RDF.Datatype.NS.XSD.boolean
|
||||
|
||||
@doc """
|
||||
|
@ -39,6 +159,7 @@ defmodule RDF.Boolean do
|
|||
see
|
||||
- <https://www.w3.org/TR/xpath-31/#id-ebv>
|
||||
- <https://www.w3.org/TR/sparql11-query/#ebv>
|
||||
|
||||
"""
|
||||
def ebv(value)
|
||||
|
||||
|
|
|
@ -134,4 +134,40 @@ defmodule RDF.BooleanTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "truth-table of logical_and" do
|
||||
[
|
||||
{RDF.true, RDF.true, RDF.true},
|
||||
{RDF.true, RDF.false, RDF.false},
|
||||
{RDF.false, RDF.true, RDF.false},
|
||||
{RDF.false, RDF.false, RDF.false},
|
||||
{RDF.true, nil, nil},
|
||||
{nil, RDF.true, nil},
|
||||
{RDF.false, nil, RDF.false},
|
||||
{nil, RDF.false, RDF.false},
|
||||
{nil, nil, nil},
|
||||
]
|
||||
|> Enum.each(fn {left, right, result} ->
|
||||
assert RDF.Boolean.logical_and(left, right) == result,
|
||||
"expected logical_and(#{inspect left}, #{inspect right}) to be #{inspect result}, but got #{inspect RDF.Boolean.logical_and(left, right)}"
|
||||
end)
|
||||
end
|
||||
|
||||
test "truth-table of logical_or" do
|
||||
[
|
||||
{RDF.true, RDF.true, RDF.true},
|
||||
{RDF.true, RDF.false, RDF.true},
|
||||
{RDF.false, RDF.true, RDF.true},
|
||||
{RDF.false, RDF.false, RDF.false},
|
||||
{RDF.true, nil, RDF.true},
|
||||
{nil, RDF.true, RDF.true},
|
||||
{RDF.false, nil, nil},
|
||||
{nil, RDF.false, nil},
|
||||
{nil, nil, nil},
|
||||
]
|
||||
|> Enum.each(fn {left, right, result} ->
|
||||
assert RDF.Boolean.logical_or(left, right) == result,
|
||||
"expected logical_or(#{inspect left}, #{inspect right}) to be #{inspect result}, but got #{inspect RDF.Boolean.logical_and(left, right)}"
|
||||
end)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue