mirror of
https://codeberg.org/scip/Data-Validate-Struct.git
synced 2025-12-16 20:21:02 +01:00
updated pod, added grammar sample
This commit is contained in:
186
README
186
README
@@ -268,61 +268,11 @@ SUBROUTINES/METHODS
|
||||
or more new types using a simple hash using the type() method.
|
||||
Values in this hash can be regexes or anonymous subs.
|
||||
|
||||
Example:
|
||||
|
||||
$v3->type(
|
||||
address => qr(^\w+\s\s*\d+$),
|
||||
|
||||
list => sub {
|
||||
my $list = shift;
|
||||
my @list = split /\s*,\s*/, $list;
|
||||
return scalar @list > 1;
|
||||
},
|
||||
);
|
||||
|
||||
In this example we add 2 new types, 'list' and 'address', which are
|
||||
really simple. 'address' is a regex which matches a word followed by
|
||||
an integer. 'list' is a subroutine which gets called during
|
||||
evaluation for each option which you define as type 'list'.
|
||||
|
||||
Such a subroutine must return a true value in order to produce a
|
||||
match. It receives the following arguments:
|
||||
|
||||
value to be evaluated
|
||||
unparsed arguments, if defined in the reference
|
||||
array of parsed arguments, tokenized by , and -
|
||||
|
||||
That way you may define a type which accepts an arbitrary number of
|
||||
arguments, which makes the type customizable. Sample:
|
||||
|
||||
# new validator
|
||||
$v4 = Data::Validate::Struct->new({ list => nwords(4) });
|
||||
|
||||
# define type 'nwords' with support for 1 argument
|
||||
$v4->type(
|
||||
nwords => sub {
|
||||
my($val, $ignore, $count) = @_;
|
||||
return (scalar(split /\s+/, $val) == $count) ? 1 : 0;
|
||||
},
|
||||
);
|
||||
|
||||
# validate
|
||||
$v4->validate({ list => 'these are four words' });
|
||||
|
||||
It is also possible to add validators globally so they are available
|
||||
during repeated calls to new, see add_validators.
|
||||
|
||||
A negative/reverse match is automatically added as well, see
|
||||
"NEGATIVE MATCHING".
|
||||
|
||||
Regexes will be executed exactly as given. No flags or ^ or $ will
|
||||
be used by the module. Eg. if you want to match the whole value from
|
||||
beginning to the end, add ^ and $, like you can see in our 'address'
|
||||
example above.
|
||||
|
||||
"type" does accept either a hash (%hash), a hash ref (%$hash) or a
|
||||
list of key/values ("key => value") as input.
|
||||
|
||||
For details see "CUSTOM VALIDATORS".
|
||||
|
||||
debug()
|
||||
Enables debug output which gets printed to STDERR.
|
||||
|
||||
@@ -345,7 +295,121 @@ EXPORTED FUNCTIONS
|
||||
add_validators( name => .. );
|
||||
my $v = Data::Validate::Struct->new(..);
|
||||
|
||||
Parameter to add_validators are the same as of the type method.
|
||||
Parameters to add_validators are the same as of the type method.
|
||||
|
||||
For details see "CUSTOM VALIDATORS".
|
||||
|
||||
CUSTOM VALIDATORS
|
||||
You can add your own validators, which maybe regular expressions or
|
||||
anonymous subs. Validators can be added using the type() method or
|
||||
globally using the add_validators() function.
|
||||
|
||||
CUSTOM REGEX VALIDATORS
|
||||
If you add a validator which is just a regular expressions, it will
|
||||
evaluated as is. This is the most simplest way to customize validation.
|
||||
|
||||
Sample:
|
||||
|
||||
use Data::Validate::Struct qw(add_validators);
|
||||
add_validators(address => qr(^\w+\s\s*\d+$));
|
||||
my $v = Data::Validate::Struct->new({place => 'address'});
|
||||
$v->validate({place => 'Livermore 19'});
|
||||
|
||||
Regexes will be executed exactly as given. No flags or ^ or $ will be
|
||||
used by the module. Eg. if you want to match the whole value from
|
||||
beginning to the end, add ^ and $, like you can see in our 'address'
|
||||
example above.
|
||||
|
||||
CUSTOM VALIDATOR FUNCTIONS
|
||||
If the validator is a coderef, it will be executed as a sub.
|
||||
|
||||
Example:
|
||||
|
||||
use Data::Validate::Struct qw(add_validators);
|
||||
add_validators(
|
||||
list => sub {
|
||||
my $list = shift;
|
||||
my @list = split /\s*,\s*/, $list;
|
||||
return scalar @list > 1;
|
||||
},
|
||||
);
|
||||
|
||||
In this example we add a new type 'list', which is really simple. 'list'
|
||||
is a subroutine which gets called during evaluation for each option
|
||||
which you define as type 'list'.
|
||||
|
||||
Such a subroutine must return a true value in order to produce a match.
|
||||
It receives the following arguments:
|
||||
|
||||
* value to be evaluated
|
||||
|
||||
* unparsed arguments, if defined in the reference
|
||||
|
||||
* array of parsed arguments, tokenized by , and -
|
||||
|
||||
That way you may define a type which accepts an arbitrary number of
|
||||
arguments, which makes the type customizable. Sample:
|
||||
|
||||
# new validator
|
||||
$v4 = Data::Validate::Struct->new({ list => nwords(4) });
|
||||
|
||||
# define type 'nwords' with support for 1 argument
|
||||
$v4->type(
|
||||
nwords => sub {
|
||||
my($val, $ignore, $count) = @_;
|
||||
return (scalar(split /\s+/, $val) == $count) ? 1 : 0;
|
||||
},
|
||||
);
|
||||
|
||||
# validate
|
||||
$v4->validate({ list => 'these are four words' });
|
||||
|
||||
CUSTOM VALIDATORS USING A GRAMMAR
|
||||
Sometimes you want to be more flexible, in such cases you may use a
|
||||
parser generator to validate input. This is no feature of
|
||||
Data::Validate::Struct, you will just write a custom code ref validator,
|
||||
which then uses the grammar.
|
||||
|
||||
Here's a complete example using Parse::RecDescent:
|
||||
|
||||
use Parse::RecDescent;
|
||||
use Data::Validate::Struct qw(add_validators);
|
||||
|
||||
my $grammar = q{
|
||||
line: expr(s)
|
||||
expr: number operator number
|
||||
number: int | float
|
||||
int: /\d+/
|
||||
float: /\d*\\.\d+/
|
||||
operator: '+' | '-' | '*' | '/'
|
||||
};
|
||||
|
||||
my $parse = Parse::RecDescent->new($grammar);
|
||||
|
||||
add_validators(calc => sub { defined $parse->line($_[0]) ? 1 : 0; });
|
||||
|
||||
my $val = Data::Validate::Struct->new({line => 'calc'});
|
||||
|
||||
if ($val->validate({line => "@ARGV"})) {
|
||||
my $r;
|
||||
eval "\$r = @ARGV";
|
||||
print "$r\n";
|
||||
}
|
||||
else {
|
||||
print "syntax error\n";
|
||||
}
|
||||
|
||||
Now you can use it as follows:
|
||||
|
||||
./mycalc 54 + 100 - .1
|
||||
153.9
|
||||
|
||||
./mycalc 8^2
|
||||
syntax error
|
||||
|
||||
NEGATED VALIDATOR
|
||||
A negative/reverse match is automatically added as well, see "NEGATIVE
|
||||
MATCHING".
|
||||
|
||||
EXAMPLES
|
||||
Take a look to t/run.t for lots of examples.
|
||||
@@ -397,24 +461,10 @@ DEPENDENCIES
|
||||
Data::Validate::Struct depends on the module Data::Validate,
|
||||
Data::Validate:IP, Regexp::Common, File::Spec and File::stat.
|
||||
|
||||
TODO
|
||||
* Perhaps add code validation too, for example we could have a type
|
||||
'perl' which tries to evaluate the given value. On the other side
|
||||
this may lead to security holes - so I might never do it.
|
||||
|
||||
* Plugin System
|
||||
|
||||
* Possibly add support for grammars. This might be much more powerful
|
||||
than regular expressions, say:
|
||||
|
||||
{ name => 'expr OP expr | expr' }
|
||||
|
||||
or something like this.
|
||||
|
||||
AUTHORS
|
||||
T. v.Dein <tlinden |AT| cpan.org>
|
||||
|
||||
Per Carlson <pelle |AT| hemmop.com>
|
||||
Per Carlson <pelle |AT| cpan.org>
|
||||
|
||||
Thanks to David Cantrell for his helpful hints.
|
||||
|
||||
|
||||
224
Struct.pm
224
Struct.pm
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Copyright (c) 2007-2014 T. v.Dein <tlinden |AT| cpan.org>.
|
||||
# All Rights Reserved. Std. disclaimer applies.
|
||||
# Artificial License, same as perl itself. Have fun.
|
||||
# Artistic License, same as perl itself. Have fun.
|
||||
#
|
||||
# namespace
|
||||
package Data::Validate::Struct;
|
||||
@@ -316,7 +316,7 @@ sub _tokenize {
|
||||
my @params = split /[\,\-]/, $args;
|
||||
return ($name, $args, @params);
|
||||
}
|
||||
print "nofunc <$type>\n";
|
||||
|
||||
# default, just return the name as it is
|
||||
return ($type);
|
||||
}
|
||||
@@ -650,67 +650,11 @@ You can enhance the validator by adding your own rules. Just
|
||||
add one or more new types using a simple hash using the B<type()>
|
||||
method. Values in this hash can be regexes or anonymous subs.
|
||||
|
||||
Example:
|
||||
|
||||
$v3->type(
|
||||
address => qr(^\w+\s\s*\d+$),
|
||||
|
||||
list => sub {
|
||||
my $list = shift;
|
||||
my @list = split /\s*,\s*/, $list;
|
||||
return scalar @list > 1;
|
||||
},
|
||||
);
|
||||
|
||||
In this example we add 2 new types, 'list' and 'address', which
|
||||
are really simple. 'address' is a regex which matches a word
|
||||
followed by an integer. 'list' is a subroutine which gets called
|
||||
during evaluation for each option which you define as type 'list'.
|
||||
|
||||
Such a subroutine must return a true value in order to produce a match.
|
||||
It receives the following arguments:
|
||||
|
||||
=over
|
||||
|
||||
=item value to be evaluated
|
||||
|
||||
=item unparsed arguments, if defined in the reference
|
||||
|
||||
=item array of parsed arguments, tokenized by , and -
|
||||
|
||||
=back
|
||||
|
||||
That way you may define a type which accepts an arbitrary number
|
||||
of arguments, which makes the type customizable. Sample:
|
||||
|
||||
# new validator
|
||||
$v4 = Data::Validate::Struct->new({ list => nwords(4) });
|
||||
|
||||
# define type 'nwords' with support for 1 argument
|
||||
$v4->type(
|
||||
nwords => sub {
|
||||
my($val, $ignore, $count) = @_;
|
||||
return (scalar(split /\s+/, $val) == $count) ? 1 : 0;
|
||||
},
|
||||
);
|
||||
|
||||
# validate
|
||||
$v4->validate({ list => 'these are four words' });
|
||||
|
||||
It is also possible to add validators globally so they are
|
||||
available during repeated calls to B<new>, see B<add_validators>.
|
||||
|
||||
A negative/reverse match is automatically added as well, see
|
||||
L</NEGATIVE MATCHING>.
|
||||
|
||||
Regexes will be executed exactly as given. No flags or ^ or $
|
||||
will be used by the module. Eg. if you want to match the whole
|
||||
value from beginning to the end, add ^ and $, like you can see
|
||||
in our 'address' example above.
|
||||
|
||||
C<type> does accept either a hash (C<%hash>), a hash ref (C<%$hash>) or a
|
||||
list of key/values (C<< key => value >>) as input.
|
||||
|
||||
For details see L<CUSTOM VALIDATORS>.
|
||||
|
||||
=item B<debug()>
|
||||
|
||||
Enables debug output which gets printed to STDERR.
|
||||
@@ -740,9 +684,140 @@ but globally for each instance of Data::Validate::Struct.
|
||||
add_validators( name => .. );
|
||||
my $v = Data::Validate::Struct->new(..);
|
||||
|
||||
Parameter to B<add_validators> are the same as of the
|
||||
Parameters to B<add_validators> are the same as of the
|
||||
B<type> method.
|
||||
|
||||
For details see L<CUSTOM VALIDATORS>.
|
||||
|
||||
=head1 CUSTOM VALIDATORS
|
||||
|
||||
You can add your own validators, which maybe regular expressions
|
||||
or anonymous subs. Validators can be added using the B<type()>
|
||||
method or globally using the B<add_validators()> function.
|
||||
|
||||
=head2 CUSTOM REGEX VALIDATORS
|
||||
|
||||
If you add a validator which is just a regular expressions,
|
||||
it will evaluated as is. This is the most simplest way to
|
||||
customize validation.
|
||||
|
||||
Sample:
|
||||
|
||||
use Data::Validate::Struct qw(add_validators);
|
||||
add_validators(address => qr(^\w+\s\s*\d+$));
|
||||
my $v = Data::Validate::Struct->new({place => 'address'});
|
||||
$v->validate({place => 'Livermore 19'});
|
||||
|
||||
Regexes will be executed exactly as given. No flags or ^ or $
|
||||
will be used by the module. Eg. if you want to match the whole
|
||||
value from beginning to the end, add ^ and $, like you can see
|
||||
in our 'address' example above.
|
||||
|
||||
=head2 CUSTOM VALIDATOR FUNCTIONS
|
||||
|
||||
If the validator is a coderef, it will be executed as a sub.
|
||||
|
||||
Example:
|
||||
|
||||
use Data::Validate::Struct qw(add_validators);
|
||||
add_validators(
|
||||
list => sub {
|
||||
my $list = shift;
|
||||
my @list = split /\s*,\s*/, $list;
|
||||
return scalar @list > 1;
|
||||
},
|
||||
);
|
||||
|
||||
In this example we add a new type 'list', which
|
||||
is really simple. 'list' is a subroutine which gets called
|
||||
during evaluation for each option which you define as type 'list'.
|
||||
|
||||
Such a subroutine must return a true value in order to produce a match.
|
||||
It receives the following arguments:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
|
||||
value to be evaluated
|
||||
|
||||
=item *
|
||||
|
||||
unparsed arguments, if defined in the reference
|
||||
|
||||
=item *
|
||||
|
||||
array of parsed arguments, tokenized by , and -
|
||||
|
||||
=back
|
||||
|
||||
That way you may define a type which accepts an arbitrary number
|
||||
of arguments, which makes the type customizable. Sample:
|
||||
|
||||
# new validator
|
||||
$v4 = Data::Validate::Struct->new({ list => nwords(4) });
|
||||
|
||||
# define type 'nwords' with support for 1 argument
|
||||
$v4->type(
|
||||
nwords => sub {
|
||||
my($val, $ignore, $count) = @_;
|
||||
return (scalar(split /\s+/, $val) == $count) ? 1 : 0;
|
||||
},
|
||||
);
|
||||
|
||||
# validate
|
||||
$v4->validate({ list => 'these are four words' });
|
||||
|
||||
|
||||
=head2 CUSTOM VALIDATORS USING A GRAMMAR
|
||||
|
||||
Sometimes you want to be more flexible, in such cases you may
|
||||
use a parser generator to validate input. This is no feature
|
||||
of Data::Validate::Struct, you will just write a custom code
|
||||
ref validator, which then uses the grammar.
|
||||
|
||||
Here's a complete example using L<Parse::RecDescent>:
|
||||
|
||||
use Parse::RecDescent;
|
||||
use Data::Validate::Struct qw(add_validators);
|
||||
|
||||
my $grammar = q{
|
||||
line: expr(s)
|
||||
expr: number operator number
|
||||
number: int | float
|
||||
int: /\d+/
|
||||
float: /\d*\\.\d+/
|
||||
operator: '+' | '-' | '*' | '/'
|
||||
};
|
||||
|
||||
my $parse = Parse::RecDescent->new($grammar);
|
||||
|
||||
add_validators(calc => sub { defined $parse->line($_[0]) ? 1 : 0; });
|
||||
|
||||
my $val = Data::Validate::Struct->new({line => 'calc'});
|
||||
|
||||
if ($val->validate({line => "@ARGV"})) {
|
||||
my $r;
|
||||
eval "\$r = @ARGV";
|
||||
print "$r\n";
|
||||
}
|
||||
else {
|
||||
print "syntax error\n";
|
||||
}
|
||||
|
||||
Now you can use it as follows:
|
||||
|
||||
./mycalc 54 + 100 - .1
|
||||
153.9
|
||||
|
||||
./mycalc 8^2
|
||||
syntax error
|
||||
|
||||
=head2 NEGATED VALIDATOR
|
||||
|
||||
A negative/reverse match is automatically added as well, see
|
||||
L</NEGATIVE MATCHING>.
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
Take a look to F<t/run.t> for lots of examples.
|
||||
@@ -799,36 +874,11 @@ For example to debug the regex matching during processing try this:
|
||||
Data::Validate::Struct depends on the module L<Data::Validate>,
|
||||
L<Data::Validate:IP>, L<Regexp::Common>, L<File::Spec> and L<File::stat>.
|
||||
|
||||
=head1 TODO
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
|
||||
Perhaps add code validation too, for example we could have
|
||||
a type 'perl' which tries to evaluate the given value. On the
|
||||
other side this may lead to security holes - so I might never do it.
|
||||
|
||||
=item *
|
||||
|
||||
Plugin System
|
||||
|
||||
=item *
|
||||
|
||||
Possibly add support for grammars. This might be much more powerful
|
||||
than regular expressions, say:
|
||||
|
||||
{ name => 'expr OP expr | expr' }
|
||||
|
||||
or something like this.
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
T. v.Dein <tlinden |AT| cpan.org>
|
||||
|
||||
Per Carlson <pelle |AT| hemmop.com>
|
||||
Per Carlson <pelle |AT| cpan.org>
|
||||
|
||||
Thanks to David Cantrell for his helpful hints.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user