Skip to content

am-kantox/exvalibur

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

42 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Logo Exvalibur

CircleCI     generator for blazingly fast validators of maps based on sets of predefined rules

Installation

Simply add exvalibur to your list of dependencies in mix.exs:

def deps do
  [
    {:exvalibur, "~> 0.1"}
  ]
end

Usage

rules = [
  %{matches: %{currency_pair: "EURUSD"},
    conditions: %{rate: %{min: 1.0, max: 2.0}}}]
Exvalibur.validator!(rules, module_name: Exvalibur.Validator)
Exvalibur.Validator.valid?(%{currency_pair: "EURUSD", rate: 1.5})
#⇒ {:ok, %{currency_pair: "EURUSD", rate: 1.5}}
Exvalibur.Validator.valid?(%{currency_pair: "EURGBP", rate: 1.5})
#⇒ :error
Exvalibur.Validator.valid?(%{currency_pair: "EURUSD", rate: 0.5})
#⇒ :error

rules = [
  %{matches: %{currency_pair: "EURGBP"},
    conditions: %{rate: %{min: 1.0, max: 2.0}}}]
Exvalibur.validator!(rules, module_name: Exvalibur.Validator)
Exvalibur.Validator.valid?(%{currency_pair: "EURGBP", rate: 1.5})
#⇒ {:ok, %{currency_pair: "EURGBP", rate: 1.5}}
Exvalibur.Validator.valid?(%{currency_pair: "EURUSD", rate: 1.5})
#⇒ {:ok, %{currency_pair: "EURUSD", rate: 1.5}}

Sigils To Pattern Match Data

Starting with v0.4.0 we support ~q and ~Q sigils to use validator with pattern matching.

  import Exvalibur.Sigils

  starting_with = "bar"
  rules = [%{matches: %{foo: ~q[<<"#{starting_with}", _::binary>>]}}]

  Exvalibur.validator!(rules, module_name: TestValidator)

  assert TestValidator.valid?(%{foo: "bar"}) == {:ok, %{foo: "bar"}}
  assert TestValidator.valid?(%{foo: "zzz"}) == :error
  assert TestValidator.valid?(%{foo: 42}) == :error

Binary Conditions

Starting with v0.5.0 we support binary conditions for the declared guards.

  import Exvalibur.Sigils

  rules = [%{conditions: "num >= 0 and num <= 100"}]

  Exvalibur.validator!(rules, module_name: TestValidator)

  assert TestValidator.valid?(%{num: "bar"}) == :error
  assert TestValidator.valid?(%{num: 200}) == :error
  assert TestValidator.valid?(%{num: 42}) == {:ok, %{num: 42}}

Any match expression allowed in function head matching clause is allowed here.

  import Exvalibur.Sigils

  rules = [%{matches: %{foo: ~Q[%{} = _]}}]

  Exvalibur.validator!(rules, module_name: TestValidator)

  assert TestValidator.valid?(%{foo: %{bar: "baz"}}) == {:ok, %{foo: %{bar: "baz"}}}
  assert TestValidator.valid?(%{foo: 42}) == :error

Custom Guards

Starting with v0.6.0 we support arbitrary custom guards in rules. The variables used in these guards should be explicitly declared under the matches key in rules, in the form foo: ~Q[foo].

  import Exvalibur.Sigils

  rules = [%{
    matches: %{num: ~Q[num]},
    guards: ["num >= 0 and num <= 100"]
  }]

  Exvalibur.validator!(rules, module_name: TestValidator)

  assert TestValidator.valid?(%{num: "bar"}) == :error
  assert TestValidator.valid?(%{num: 200}) == :error
  assert TestValidator.valid?(%{num: 42}) == {:ok, %{num: 42}}

Module-based validators

defmodule Validator do
  use Exvalibur, rules: [
    %{
      matches: %{currency_pair: <<"EUR", _ :: binary>>},
      conditions: %{foo: %{min: 0, max: 100}},
      guards: %{num: num > 0 and num < 100}}]
end
Validator.valid?(%{currency_pair: "EURUSD", foo: 50, num: 50})
#⇒ {:ok, %{currency_pair: "EURUSD", foo: 50, num: 50}}

Validator.valid?(%{currency_pair: "USDEUR", foo: 50, num: 50})
#⇒ :error
Validator.valid?(%{currency_pair: "EURUSD", foo: -50, num: 50})
#⇒ :error
Validator.valid?(%{currency_pair: "EURUSD", foo: 50, num: -50})
#⇒ :error

Changelog

0.11.0

  • Descriptive errors

0.10.0

  • @behaviour Exvalibur.Validatable with overridable custom_validate/1

0.9.0

  • valid?/1 is deprecated in favor of validate/1; starting with v1.0 valid?/1 will return boolean value

0.8.0

  • module-based validators