Current section

Files

Jump to
meeseeks lib meeseeks selector xpath expr helpers.ex
Raw

lib/meeseeks/selector/xpath/expr/helpers.ex

defmodule Meeseeks.Selector.XPath.Expr.Helpers do
@moduledoc false
alias Meeseeks.{Context, Document}
@nodes Context.nodes_key()
@other_nums [:NaN, :Infinity, :"-Infinity"]
# eq_fmt
def eq_fmt(x, y, document) when is_list(x) or is_list(y) do
nodes_fmt(x, y, document)
end
def eq_fmt(x, y, document) when is_boolean(x) or is_boolean(y) do
boolean(x, document)
end
def eq_fmt(x, y, document) when is_number(x) or is_number(y) do
number(x, document)
end
def eq_fmt(x, y, document) when x in @other_nums or y in @other_nums do
number(x, document)
end
def eq_fmt(x, _y, document) do
string(x, document)
end
# cmp_fmt
def cmp_fmt(x, y, document) when is_list(x) or is_list(y) do
nodes_fmt(x, y, document)
end
def cmp_fmt(x, _y, document) do
number(x, document)
end
# nodes_fmt
defp nodes_fmt(x, _y, _document) when is_number(x) do
x
end
defp nodes_fmt(x, _y, _document) when x in @other_nums do
x
end
defp nodes_fmt(x, _y, _document) when is_boolean(x) do
x
end
defp nodes_fmt(x, _y, _document) when is_binary(x) do
x
end
defp nodes_fmt(x, y, document) when is_list(x) and is_number(y) do
Enum.map(x, &(string(&1, document) |> number(document)))
end
defp nodes_fmt(x, y, document) when is_list(x) and y in @other_nums do
Enum.map(x, &(string(&1, document) |> number(document)))
end
defp nodes_fmt(x, y, document) when is_list(x) and is_boolean(y) do
boolean(x, document)
end
defp nodes_fmt(x, y, document) when is_list(x) and is_binary(y) do
Enum.map(x, &string(&1, document))
end
defp nodes_fmt(x, y, document) when is_list(x) and is_list(y) do
Enum.map(x, &string(&1, document))
end
# boolean
def boolean(false, _document), do: false
def boolean(true, _document), do: true
def boolean("", _document), do: false
def boolean([], _document), do: false
def boolean(:NaN, _document), do: false
def boolean(:Infinity, _document), do: true
def boolean(:"-Infinity", _document), do: true
def boolean(x, _document) when is_binary(x), do: true
def boolean(x, _document) when is_integer(x), do: x != 0
def boolean(x, _document) when is_float(x), do: x != 0.0
def boolean(x, _document) when is_list(x), do: nodes?(x)
def boolean(x, _document), do: raise ArgumentError, arg_error("boolean", x)
# number
def number(false, _document), do: 0
def number(true, _document), do: 1
def number("", _document), do: :NaN
def number([], _document), do: :NaN
def number(:NaN, _document), do: :NaN
def number(:Infinity, _document), do: :Infinity
def number(:"-Infinity", _document), do: :"-Infinity"
def number(x, _document) when is_number(x), do: x
def number(x, document) when is_list(x), do: string(x, document) |> number(document)
def number(x, _document) when is_binary(x) do
case Regex.run(~r/^\s*(\-?\d+(\.\d+)?)\s*$/, x) do
[_, s] -> String.to_integer(s)
[_, s, _] -> String.to_float(s)
_ -> :NaN
end
end
def number(x, _document), do: raise ArgumentError, arg_error("number", x)
# string
def string(false, _document), do: "false"
def string(true, _document), do: "true"
def string([], _document), do: ""
def string(0, _document), do: "0"
def string(0.0, _document), do: "0"
def string(:NaN, _document), do: "NaN"
def string(:Infinity, _document), do: "Infinity"
def string(:"-Infinity", _document), do: "-Infinity"
def string({_attr, value}, _document), do: value
def string(%Document.Doctype{}, _document), do: ""
def string(%Document.Comment{} = x, _document), do: x.content
def string(%Document.Data{} = x, _document), do: x.content
def string(%Document.Text{} = x, _document), do: x.content
def string(%Document.Element{} = x, document) do
children = Document.children(document, x.id)
child_nodes = Document.get_nodes(document, children)
child_nodes
|> Enum.map(&string(&1, document))
|> Enum.join("")
end
def string(x, _document) when is_binary(x), do: x
def string(x, _document) when is_integer(x), do: Integer.to_string(x)
def string(x, _document) when is_float(x), do: Float.to_string(x)
def string(x, document) when is_list(x) do
if nodes?(x) do
[node|_] = x
string(node, document)
else
raise ArgumentError, arg_error("string", x)
end
end
def string(x, _document), do: raise ArgumentError, arg_error("string", x)
# nodes?
def nodes?(xs) when is_list(xs), do: Enum.all?(xs, &node?/1)
def nodes?(_), do: false
# node?
def node?(%Document.Comment{}), do: true
def node?(%Document.Data{}), do: true
def node?(%Document.Doctype{}), do: true
def node?(%Document.Element{}), do: true
def node?(%Document.Text{}), do: true
# attribute
def node?({attr, val}) when is_binary(attr) and is_binary(val), do: true
# namespace
def node?(ns) when is_binary(ns), do: true
def node?(_), do: false
# position
def position(node, context) do
context
|> Map.fetch!(@nodes)
|> Enum.find_index(fn(n) -> node == n end)
|> plus_one()
end
# substring/2
def substring(_s, :NaN), do: ""
def substring(_s, :Infinity), do: ""
def substring(s, :"-Infinity"), do: s
def substring(s, n) when n <= 0, do: s
def substring(s, n) do
{_, sub} = String.split_at(s, n)
sub
end
# substring/3
def substring(_s, :NaN, _n2), do: ""
def substring(_s, _n1, :NaN), do: ""
def substring(_s, :Infinity, _n2), do: ""
def substring(s, :"-Infinity", :Infinity), do: s
def substring(s, :"-Infinity", n2), do: String.slice(s, 0, n2)
def substring(s, n1, n2) when n1 <= 0 do
case n2 do
:"-Infinity" -> ""
:Infinity -> String.slice(s, 0, String.length(s))
_ ->
len = n1 + n2
if len <= 0 do
""
else
String.slice(s, 0, len)
end
end
end
def substring(s, n1, n2) do
case n2 do
:"-Infinity" -> ""
:Infinity -> String.slice(s, n1, String.length(s))
_ ->
if n2 <= 0 do
""
else
String.slice(s, n1, n2)
end
end
end
# arithmetic
def add(:NaN, _), do: :NaN
def add(_, :NaN), do: :NaN
def add(:Infinity, _), do: :Infinity
def add(_, :Infinity), do: :Infinity
def add(:"-Infinity", _), do: :"-Infinity"
def add(_, :"-Infinity"), do: :"-Infinity"
def add(n1, n2), do: n1 + n2
def sub(:NaN, _), do: :NaN
def sub(_, :NaN), do: :NaN
def sub(:Infinity, _), do: :Infinity
def sub(_, :Infinity), do: :Infinity
def sub(:"-Infinity", _), do: :"-Infinity"
def sub(_, :"-Infinity"), do: :"-Infinity"
def sub(n1, n2), do: n1 - n2
def mult(:NaN, _), do: :NaN
def mult(_, :NaN), do: :NaN
def mult(:Infinity, _), do: :Infinity
def mult(_, :Infinity), do: :Infinity
def mult(:"-Infinity", _), do: :"-Infinity"
def mult(_, :"-Infinity"), do: :"-Infinity"
def mult(n1, n2), do: n1 * n2
def divd(:NaN, _), do: :NaN
def divd(_, :NaN), do: :NaN
def divd(:Infinity, _), do: :Infinity
def divd(_, :Infinity), do: :Infinity
def divd(:"-Infinity", _), do: :"-Infinity"
def divd(_, :"-Infinity"), do: :"-Infinity"
def divd(_, 0), do: :Infinity
def divd(n1, n2), do: div(n1, n2)
def mod(:NaN, _), do: :NaN
def mod(_, :NaN), do: :NaN
def mod(:Infinity, _), do: :Infinity
def mod(_, :Infinity), do: :Infinity
def mod(:"-Infinity", _), do: :"-Infinity"
def mod(_, :"-Infinity"), do: :"-Infinity"
def mod(_, 0), do: :Infinity
def mod(n1, n2), do: rem(n1, n2)
# numbers
def round_(:NaN), do: :NaN
def round_(:Infinity), do: :Infinity
def round_(:"-Infinity"), do: :"-Infinity"
def round_(n) when is_float(n), do: round(n)
def round_(n) when is_integer(n), do: n
def floor(:NaN), do: :NaN
def floor(:Infinity), do: :Infinity
def floor(:"-Infinity"), do: :"-Infinity"
def floor(n) when is_float(n), do: Float.floor(n)
def floor(n) when is_integer(n), do: n
def ceiling(:NaN), do: :NaN
def ceiling(:Infinity), do: :Infinity
def ceiling(:"-Infinity"), do: :"-Infinity"
def ceiling(n) when is_float(n), do: Float.ceil(n)
def ceiling(n) when is_integer(n), do: n
# compare
# =
def compare(:=, x, y), do: x == y
# !=
def compare(:!=, x, y), do: x != y
# <=
def compare(:<=, :NaN, :NaN), do: true
def compare(:<=, :NaN, _), do: true
def compare(:<=, _, :NaN), do: false
def compare(:<=, :Infinity, :Infinity), do: true
def compare(:<=, :Infinity, _), do: false
def compare(:<=, _, :Infinity), do: true
def compare(:<=, :"-Infinity", :"-Infinity"), do: true
def compare(:<=, :"-Infinity", _), do: true
def compare(:<=, _, :"-Infinity"), do: false
def compare(:<=, x, y), do: x <= y
# <
def compare(:<, :NaN, :NaN), do: false
def compare(:<, :NaN, _), do: true
def compare(:<, _, :NaN), do: false
def compare(:<, :Infinity, :Infinity), do: false
def compare(:<, :Infinity, _), do: false
def compare(:<, _, :Infinity), do: true
def compare(:<, :"-Infinity", :"-Infinity"), do: false
def compare(:<, :"-Infinity", _), do: true
def compare(:<, _, :"-Infinity"), do: false
def compare(:<, x, y), do: x < y
# >=
def compare(:>=, :NaN, :NaN), do: true
def compare(:>=, :NaN, _), do: false
def compare(:>=, _, :NaN), do: true
def compare(:>=, :Infinity, :Infinity), do: true
def compare(:>=, :Infinity, _), do: true
def compare(:>=, _, :Infinity), do: false
def compare(:>=, :"-Infinity", :"-Infinity"), do: true
def compare(:>=, :"-Infinity", _), do: false
def compare(:>=, _, :"-Infinity"), do: true
def compare(:>=, x, y), do: x >= y
# >
def compare(:>, :NaN, :NaN), do: false
def compare(:>, :NaN, _), do: false
def compare(:>, _, :NaN), do: true
def compare(:>, :Infinity, :Infinity), do: false
def compare(:>, :Infinity, _), do: true
def compare(:>, _, :Infinity), do: false
def compare(:>, :"-Infinity", :"-Infinity"), do: false
def compare(:>, :"-Infinity", _), do: false
def compare(:>, _, :"-Infinity"), do: true
def compare(:>, x, y), do: x > y
# negate
def negate(:NaN), do: :NaN
def negate(:Infinity), do: :"-Infinity"
def negate(:"-Infinity"), do: :Infinity
def negate(n), do: - n
# misc
defp arg_error(f, arg) do
"Meeseeks.Selector.XPath.Expr.Helpers.#{f}(#{inspect(arg)})"
end
defp plus_one(n), do: n + 1
end