lib/guards.ex

defmodule RulEx.Guards do
  @moduledoc "Provide helper guards for use with RulEx."

  @value_operands RulEx.Operands.value()
  @variable_operands RulEx.Operands.variable()
  @comparison_operands RulEx.Operands.comparison()
  @reserved_operands RulEx.Operands.reserved()

  @doc "Yield true if given expression is a valid `val` expression, false otherwise."
  defguard is_val(expr)
           when is_list(expr) and
                  length(expr) == 3 and
                  hd(expr) in @value_operands and
                  expr |> tl |> hd |> is_binary()

  @doc "Yield true if given expression is a valid `var` expression, false otherwise."
  defguard is_var(expr)
           when is_list(expr) and
                  length(expr) in [3, 4] and
                  hd(expr) in @variable_operands and
                  expr |> tl |> hd |> is_binary()

  @doc "Yield true if given expression is a valid `val` or `var` expression, false otherwise."
  defguard is_val_or_var(expr) when is_val(expr) or is_var(expr)

  @doc "Yield true if given operand is a valid comparison operand, false otherwise."
  defguard is_comparison_operand(op) when op in @comparison_operands

  @doc "Yield true if given expression is a valid comparison expression, false otherwise."
  defguard is_comparison(expr)
           when is_list(expr) and
                  length(expr) == 3 and
                  expr |> hd |> is_comparison_operand() and
                  expr |> tl |> hd |> is_val_or_var() and
                  expr |> tl |> tl |> hd |> is_val_or_var()

  @doc "Yield true if given operand is reserved by RulEx, false otherwise."
  defguard is_reserved_operand(op)
           when op in @reserved_operands

  @doc "Yield true if give operand is a reserved operand or a string standing for any custom operands, false otherwise."
  defguard is_valid_operand(op) when is_reserved_operand(op) or is_binary(op)

  @doc "Yield true if given Elixir values is truthy, i.e. not `nil` or `false`, false otherwise."
  defguard is_truthy(value) when value not in [false, nil]

  @doc "Yield true if given Elixir values is falsy, i.e. `nil` or `false`, false otherwise."
  defguard is_falsy(value) when not is_truthy(value)
end