NAME

Data::Filter::Abstract::Util - DSL for generating Perl filter expressions from data structures

SYNOPSIS

use Data::Filter::Abstract::Util qw(:all);

my $expr = simple_sub(foo => "bar");
# => '($_->{foo} eq "bar")'

my $code = eval "sub { $expr }";
$code->({ foo => "bar" }); # true

DESCRIPTION

This module implements a small domain-specific language (DSL) for describing boolean filters as Perl data structures. The DSL is compiled into Perl expressions (as strings) which operate on $_, assumed to be a hash reference.

The resulting expressions are intended to be embedded into sub { ... } blocks and evaluated.

The test suite defines the DSL behavior and serves as its authoritative specification.

GENERAL SEMANTICS

  • All generated expressions assume $_ is a hash reference.

  • Field access is performed as $_-{field}>.

  • Hashes represent logical AND.

  • Arrays represent logical OR, unless explicitly overridden by logical operators.

  • Generated expressions are syntactically valid Perl code suitable for eval.

BASIC FILTER FORMS

Scalar equality

simple_sub(foo => "bar")

Generates a string equality comparison:

($_->{foo} eq "bar")

If the value looks like a number, numeric comparison is used:

simple_sub(foo => 1)
# ($_->{foo} == 1)

Regular expressions

simple_sub(foo => qr/12/)
simple_sub(foo => qr/[a-z]/i)

Generates regex match expressions:

($_->{foo} =~ qr/12/)
($_->{foo} =~ qr/[a-z]/i)

Hash form (implicit AND)

simple_sub({ bar => 1, baz => "wq", boo => qr/12/ })

Equivalent to:

($_->{bar} == 1)
&& ($_->{baz} eq "wq")
&& ($_->{boo} =~ qr/12/)

simple_hash behaves identically.

ARRAY FORMS

Simple OR array

simple_sub(foo => [ 1, "wq", qr/12/ ])

Generates a logical OR over the values:

($_->{foo} == 1)
|| ($_->{foo} eq "wq")
|| ($_->{foo} =~ qr/12/)

Arrays of operator expressions

simple_array(foo => [ { '==', 2 }, { '>', 5 } ])

Generates:

($_->{foo} == 2) || ($_->{foo} > 5)

LOGICAL ARRAYS

Arrays may begin with a logical operator to control how elements are combined.

AND logic

simple_sub(foo => [ -and => { '==', 2 }, { '>=', 5 } ])

Generates:

($_->{foo} == 2) && ($_->{foo} >= 5)

OR logic

simple_sub(foo => [ -or => { '==', 2 }, { '>=', 5 } ])

Generates:

($_->{foo} == 2) || ($_->{foo} >= 5)

OPERATOR HASHES (FUNCTION HASHES)

A field value may be a hash mapping operators to values.

simple_sub(foo => { '>' => 12, '<' => 23 })

Generates:

($_->{foo} < 23) && ($_->{foo} > 12)

The order of operators is not significant.

Supported operators (as tested)

  • String operators

    eq ne lt le gt ge
  • Numeric operators

    == != < <= > >=
  • Regex operators

    =~ !~

OPERATORS WITH ARRAY VALUES

Equality with array

simple_sub(status => { eq => [ 'assigned', 'in-progress', 'pending' ] })

Generates an OR expression:

($_->{status} eq "assigned")
|| ($_->{status} eq "in-progress")
|| ($_->{status} eq "pending")

Equivalent logic may also be expressed via a logical array:

simple_sub(status => [
    -or =>
    { eq => 'assigned' },
    { eq => 'in-progress' },
    { eq => 'pending' },
])

Regex operators with arrays

simple_sub(foo => { '=~' => [ qr/12/, qr/23/i ] })

Generates:

($_->{foo} =~ qr/12/)
|| ($_->{foo} =~ qr/23/i)

Non-regex values are coerced to regexes:

simple_sub(foo => { '=~' => [ "12", qr/23/i ] })

UNDEF HANDLING

simple_sub(user => undef)

Generates:

(! defined $_->{user})

Operator hashes may also compare against undef, though some combinations are known to be problematic (see tests marked as failing).

FIELD-TO-FIELD COMPARISON (SCALAR REF)

If the value is a scalar reference, it is interpreted as another field name.

simple_sub(foo => \"bar")

Generates a dynamic comparison:

( (looks_like_number($_->{foo}))
    ? ($_->{foo} == $_->{bar})
    : ($_->{foo} eq $_->{bar})
)

This form may also appear inside logical arrays.

CODE REFERENCES

A code reference may be supplied as a filter.

simple_sub(sub { $_->{foo}->{bar} > 5 })

or

simple_sub(foo => sub { $_->{foo}->{bar} > 5 })

The code reference is deparsed and embedded verbatim:

(sub { use strict; $_->{'foo'}{'bar'} > 5; })

The field name is ignored when a code reference is supplied.

MIXED COMPLEX EXPRESSIONS

Arrays may contain mixed value types:

simple_sub(foo => [
    1,
    "wq",
    qr/12/,
    sub { shift()->{foo}->{bar} > 5 }
])

Generates a logical OR over all components.

SEE ALSO

Data::Filter::Abstract, SQL::Abstract