view release on metacpan or search on metacpan
Check if there is a chain definition whose name is $chain_nameo
inflate_chains
$da->inflate_chains;
Make sure all input chain definitions are inflated, i.e. turned into
"Data::Annotation::Chain" objects. This makes sure the definitions
parse correctly.
overlay_cloak
my $overlay = $da->overlay_cloak($data, %opts);
Shorthand to the constructor for "Data::Annotation::Overlay", passing
$data as the under option and then the rest of %opts:
BUGS AND LIMITATIONS
Minimul perl version 5.24.
Report bugs through Codeberg (patches welcome) at
https://codeberg.org/polettix/Data-Annotation.
lib/Data/Annotation.pm view on Meta::CPAN
return defined($name) && exists($self->chains->{$name});
}
sub chains_list ($self) { sort { $a cmp $b } keys($self->chains->%*) }
sub inflate_chains ($self) {
$self->_chain_for($_) for $self->chains_list;
return $self;
}
sub overlay_cloak ($self, $data, %opts) {
return Data::Annotation::Overlay->new(under => $data, %opts);
}
sub evaluate ($self, $chain, $data) {
$chain = $self->default_chain unless $self->has_chain_for($chain);
# cloak the input $data with an Overlay, unless it's already an
# overlay in which case it's used directly
$data = $self->overlay_cloak($data,
value_if_missing => '',
value_if_undef => '',
) unless blessed($data) && $data->isa('Data::Annotation::Overlay');
my @call_sequence;
my $wrapped = sub ($name) {
my @stack;
push @stack, { name => $name, state => {} }
if $self->has_chain_for($name);
lib/Data/Annotation.pod view on Meta::CPAN
Check if there is a chain definition whose name is C<< $chain_name >>o
=head3 B<< inflate_chains >>
$da->inflate_chains;
Make sure all input chain definitions are I<inflated>, i.e. turned into
L</Data::Annotation::Chain> objects. This makes sure the definitions
parse correctly.
=head3 B<< overlay_cloak >>
my $overlay = $da->overlay_cloak($data, %opts);
Shorthand to the constructor for L</Data::Annotation::Overlay>, passing
C<$data> as the C<under> option and then the rest of C<%opts>:
=head1 BUGS AND LIMITATIONS
Minimul perl version 5.24.
Report bugs through Codeberg (patches welcome) at
L<https://codeberg.org/polettix/Data-Annotation>.
lib/Data/Annotation/Chain.pm view on Meta::CPAN
use Scalar::Util qw< blessed >;
use Data::Annotation::Rule;
use namespace::clean;
has description => (is => 'ro', default => '');
has default_retval => (is => 'ro', init_arg => 'default', predicate => 1);
has parse_context => (is => 'ro', default => sub { return {} },
init_arg => 'condition-parse-context');
has rules => (is => 'ro', default => sub { [] });
sub evaluate ($self, $state, $overlay) {
my $rules = $self->rules;
my $ri = \($state->{idx} //= 0);
while ($$ri <= $rules->$#*) {
$rules->[$$ri] = Data::Annotation::Rule->new(
'condition-parse-context' => $self->parse_context,
$rules->[$$ri]->%*,
) unless blessed($rules->[$$ri]);
my $rule = $rules->[$$ri++];
if (defined(my $outcome = $rule->evaluate($overlay))) {
my $name = $rule->has_name ? $rule->name : "#@{[ $$ri - 1 ]}";
return ($outcome, $name);
}
}
return $self->has_default_retval ? ($self->default_retval, undef) : ();
}
1;
lib/Data/Annotation/Chain.pod view on Meta::CPAN
=head3 B<< rules >>
my $aref = $chain->rules;
Get the list of rules configured for the chain. Thi
=head2 Methods
=head2 B<< evaluate >>
my $result = $chain->evaluate($state, $overlay);
Evaluate the annotation for data wrapped in some C<$overlay>, leveraging
state in C<$state>.
=head1 ANYTHING ELSE (INCLUDING AUTHOR, COPYRIGHT AND LICENSE)
See documentation for L<Data::Annotation>.
=cut
lib/Data/Annotation/Expression.pm view on Meta::CPAN
$definition = $normalizer->($parse_ctx, $definition)
if defined($normalizer);
my $type = $definition->{type};
my $parser = __PACKAGE__->can("generate_function_$type")
or die "no parser for function type '$type'\n";
return $parser->($parse_ctx, $definition);
}
sub generate_function_data ($parse_ctx, $definition) {
return sub ($overlay) { return $definition->{value} };
}
sub generate_function_context ($parse_ctx, $definition) {
my $path = $definition->{path} // '';
my ($entry, @crumbs) = crumble($path)->@*;
# the runtime context is a Data::Annotation::Overlay instance. For
# 'run' we plug directly into it, otherwise we use its access options
# for other data, but without the overlay/caching
return sub ($overlay) { $overlay->get(\@crumbs) } if $entry eq 'run';
my $other = { definition => $definition, parse => $parse_ctx };
return sub ($overlay) {
return $overlay->get_external([$entry, @crumbs], $other);
};
}
sub generate_function_sub ($parse_ctx, $definition) {
my ($name, $package) = $definition->@{qw< name package >};
my $function = resolve_function($parse_ctx, $name, $package);
my @args = map { generate_function($parse_ctx, $_) }
($definition->{args} // [])->@*;
return sub ($overlay) { $function->(map { $_->($overlay) } @args) };
}
sub resolve_function ($parse_ctx, $name, $package) {
die "undefined sub name\n" unless defined($name);
die "empty sub name\n" unless length($name);
my $suffix = $package //= '';
my $is_absolute = $suffix =~ s{\A /}{}mxs;
my $relative_prefixes = $parse_ctx->{'locator-relative-prefixes'};
my @prefixes = $is_absolute ? ('') : (($relative_prefixes // [])->@*);
lib/Data/Annotation/Overlay.pm view on Meta::CPAN
has value_if_undef => (is => 'ro', predicate => 1);
has cache_existing => (is => 'ro', default => 1);
sub delete ($self, $path) { $self->set($path, MISSING) }
sub get ($self, $path) {
ouch 400, 'cannot get an undefined path' unless defined($path);
my $crumbs = crumble($path);
my $kpath = kpath($crumbs);
# retrieve item, first look in the overlay, then go down
my $retval;
my $over = $self->over;
my $under = $self->under;
my $under_class = blessed($under);
if (exists($over->{$kpath})) {
$retval = $over->{$kpath};
}
elsif (blessed($under) && $under->isa(__PACKAGE__)) {
$retval = $under->get($path); # get from previous layer in stack
}
lib/Data/Annotation/Overlay.pod view on Meta::CPAN
=head1 NAME
Data::Annotation::Overlay
=head1 SYNOPSIS
use Data::Annotation::Overlay;
my %data = (...);
my $overlay = Data::Annotation::Overlay->new(under => \%data);
=head1 DESCRIPTION
Wrapper around a data structure, useful to record "changes" to the data
structure without making actual modifications to it. Loosely inspired by
the I<overalay> file systems.
=head1 INTERFACE
=head2 Constructor
my $rule = Data::Annotation::Overlay->(%opts);
Make a new instance for an overlay. Accepted options are all
L</Accessors>.
Input parameter C<under> is the only required key, representing the data
structure that the overlay wraps around.
All I<paths> used in this module must be compatible with
L</Data::Annotation::Traverse::crumble> and will be normalized with
L</Data::Annotation::Traverse::kpath>.
=head2 Accessors
=head3 B<< cache_existing >>
All values retrieved with L</get> will be cached for quicker access
later on. Set by default. Disable if there are intermediate function
calls that need to be executed at every access.
=head3 B<< method_over_key >>
Prefer the method call over key access when there is an intermediate
blessed object while traversing.
=head3 B<< over >>
Reference to the I<overlay> data structure (a hash reference).
=head3 B<< strict_blessed >>
Only consider method calls on blessed objects while traversing. False by
default.
=head3 B<< traverse_methods >>
Consider using methods when traversing an object. True by default.
lib/Data/Annotation/Overlay.pod view on Meta::CPAN
my $value = $ov->get_external($path, $data);
Shorthand to apply the same traversing algorithm (with the same options)
in traversing C<$data> with C<$path>. In particular, it also uses
L</return_value_for> to cope with missing/undefined elements.
=head3 B<< merged >>
my $thin_ov = $stacked_ov->merged;
Generate a new overlay from a stack of multiple wrapped overlays. The
L</under> of this new overlay is the same as the one for the bottom
overlay of the whole stack, as well as traversal options; L</over> is
generated anew and independent of what's in the stacked overlay;
L</value_if_missing> and L</value_if_undef> are taken from the top
overlay, and L<cache_existing> is taken from any layer.
All in all, it aims at being a close representation of the behaviour as
seen from the top layer of the C<$stacked_ov>.
=head3 B<< return_value_for >>
my $value = $ov->return_value_for($retval);
Adapt the return value according to the configuration.
lib/Data/Annotation/Rule.pm view on Meta::CPAN
has condition => (is => 'ro', default => 1);
has _condition => (is => 'lazy');
sub _build__condition ($self) {
my $condition = $self->condition;
return evaluator_factory($condition, $self->parse_context // {})
if ref($condition) eq 'HASH';
return sub { $condition };
}
sub evaluate ($self, $overlay) {
return unless $self->_condition->($overlay);
if ($self->has_record) {
my $record = $self->record;
if (exists($record->{delete})) {
for my $skey ($record->{delete}->@*) {
my $key = $skey =~ s{\A \.?}{}rmxs;
$overlay->delete($key);
}
}
if (exists($record->{set})) {
my $set = $record->{set};
for my $skey (keys($set->%*)) {
my $key = $skey =~ s{\A \.?}{}rmxs;
$overlay->set($key, $set->{$skey});
}
}
}
return $self->retval if $self->has_retval;
return;
}
1;
lib/Data/Annotation/Rule.pod view on Meta::CPAN
my $ctx = $rule->parse_context;
Whatever was passed as argument C<condition-parse-context>, which can
help set the stage for condition parsing. This should not be generally
needed, but still. See L<Data::Annotation::Expression> for more details.
=head3 B<< record >>
my $defs = $rule->record;
A data structure to drive changes in the C<$overlay> passed to
L</evaluate> in case the condition applies. This allows recording some
data that can be later used by other chains/rules during following
evaluations.
Accepts a hash reference with the following keys:
=over
=item *
C<delete>: an array reference of I<paths> suitable for
L</Data::Annotation::Traverse::traverse_plain>, these paths will be
marked as deleted in the overlay.
=item *
C<set>: a hash reference of I<paths>/values to be set in the overlay.
=back
All paths are supposed to be relative to an initial key C<run>, which is
mapped onto the C<$overlay> in L</execute>.
As an example, let's consider the following chains definitions:
# ...
EHLO:
default: reject
rules:
- condition:
and:
- eq: [ '.peer_ip', '=127.0.0.1' ]
lib/Data/Annotation/Rule.pod view on Meta::CPAN
The result (annotation) value returned by L</evaluate> when the
condition of the rule applies.
Initialized by key C<return> in the constructor.
=head2 Methods
=head3 B<< evaluate >>
my $result = $rule->evaluate($overlay);
Evaluate the annotation for data wrapped in some C<$overlay>.
=head1 ANYTHING ELSE (INCLUDING AUTHOR, COPYRIGHT AND LICENSE)
See documentation for Data::Annotation.
=cut
lib/Data/Annotation/Util.pm view on Meta::CPAN
package Data::Annotation::Util;
use v5.24;
use experimental qw< signatures >;
use Data::Annotation::Overlay;
use Exporter qw< import >;
our @EXPORT_OK = qw< o overlay >;
sub o { Data::Annotation::Overlay->new(under => @_) }
*{overlay} = \&o;
1;
lib/Data/Annotation/Util.pod view on Meta::CPAN
=encoding utf8
=head1 NAME
Data::Annotation::Util
=head1 SYNOPSIS
use Data::Annotation::Util qw< o overlay >;
my $ov = o(\%data); # same as overlay(\%data);
=head1 DESCRIPTION
Utility functions.
=head1 INTERFACE
=head2 C<< o >>
Same as L</overlay>.
=head2 C<< overlay >>
my $o = overlay(\%data_structure);
Instantiate a L<Data::Annotation::Overlay> taking the provided
C<%data_structure> for the underlay. It's also possible to pass additional
parameters that will be passed on to the constructor.
=head1 ANYTHING ELSE (INCLUDING AUTHOR, COPYRIGHT AND LICENSE)
See documentation for L<Data::Annotation>.
=cut