matcher

Hex.pmHex DocsLicense: MIT

A simple expression matcher and evaluator for Erlang.

Evaluate tuple-based expressions for comparisons, boolean logic, and substring matching — with optional case-insensitive variants and pluggable value providers.

Installation

Add matcher_erl to your rebar.config dependencies:

{deps, [
    {matcher_erl, "~> 1.0"}
]}.

Or directly from GitHub:

{deps, [
    {matcher, {git, "https://github.com/ratopi/matcher.git", {tag, "1.1.0"}}}
]}.

Then run:

rebar3 compile

Quick Start

%% Simple equality
true = matcher:eval({&#39;=&#39;, <<"Albert">>, <<"Albert">>}).

%% Case-insensitive equality
true = matcher:eval({&#39;=~&#39;, <<"Albert">>, <<"albert">>}).

%% Boolean logic
true = matcher:eval({&#39;|&#39;, [
    {&#39;=&#39;, <<"A">>, <<"B">>},
    {&#39;=&#39;, <<"A">>, <<"A">>}
]}).

%% Substring matching
true = matcher:eval({&#39;?&#39;, <<"bert">>, <<"Albert">>}).

Expressions

Expressions are tuples in one of the following forms:

{Op, Arg}            %% Unary  (e.g. not)
{Op, Arg1, Arg2}     %% Binary (e.g. eq, lt, part_of)
{Op, [Arg, ...]}     %% N-ary  (e.g. and, or)

Expressions can be nested — any argument can be an expression again:

{&#39;&&#39;, [{&#39;=&#39;, <<"Albert">>, <<"Albert">>}, {&#39;!&#39;, {&#39;=&#39;, <<"A">>, <<"B">>}}]}

Providers

eval/2 and match/2 accept a Provider as the first argument. A provider is a fun/1 that resolves values that cannot be evaluated further.

Map as Provider

The most common use case — look up atom keys in a map:

Map = #{name => <<"Albert">>, age => 42}.

true  = matcher:eval(Map, {&#39;=&#39;, name, <<"Albert">>}).
true  = matcher:eval(Map, {&#39;>&#39;, age, 18}).
false = matcher:eval(Map, {&#39;=&#39;, name, <<"Bob">>}).

matcher:eval(Map, Expr) is shorthand for matcher:eval(map_provider(Map), Expr).

Custom Provider

You can use any fun/1:

Provider = fun
    (temperature) -> 23.5;
    (unit) -> <<"°C">>;
    (X) -> X
end.

true = matcher:eval(Provider, {&#39;>&#39;, temperature, 20}).

You can even implement custom operators in your provider by handling tuples like {my_op, A, B}.

eval vs match

Function Returns On unknown operator
eval/1, eval/2 Any value Returns unevaluated expression as-is
match/1, match/2true, false, or {error, ...}{error, {unevaluated_expression, Expr}}

Operators

Unary (one operand)

Short Long Description
!not Logical negation

N-ary (list of operands)

Short Long Description
&and Logical AND (short-circuit)
|or Logical OR (short-circuit)

Binary (two operands)

Short Long Case-insensitive Description
<lt<~ Less than
>gt>~ Greater than
>=, =>ge>=~, =>~ Greater than or equal
<=, =<le<=~, =<~ Less than or equal
=, ==eq=~ Equal
?part_of?~ First string is part of second

Case-insensitive operators can also be written in long form, e.g. {eq, case_insensitive}.

Types

The library exports the following types:

-type provider()   :: fun((term()) -> term()).
-type expression() :: {unary_op(), expression()}
                    | {binary_op(), term(), term()}
                    | {nary_op(), [expression()]}
                    | term().

See the module documentation for full type definitions.

Testing

rebar3 ct

License

MIT — see LICENSE for details.

I'd love to hear from you if you find this library useful. :-)

Links