summaryrefslogtreecommitdiff
path: root/lib/Attribute/Params/Validate.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Attribute/Params/Validate.pm')
-rw-r--r--lib/Attribute/Params/Validate.pm208
1 files changed, 208 insertions, 0 deletions
diff --git a/lib/Attribute/Params/Validate.pm b/lib/Attribute/Params/Validate.pm
new file mode 100644
index 0000000..f72c16a
--- /dev/null
+++ b/lib/Attribute/Params/Validate.pm
@@ -0,0 +1,208 @@
+package Attribute::Params::Validate;
+
+use strict;
+use warnings;
+
+our $VERSION = '1.20';
+
+use attributes;
+
+use Attribute::Handlers 0.79;
+
+# this will all be re-exported
+use Params::Validate qw(:all);
+
+require Exporter;
+
+our @ISA = qw(Exporter);
+
+my %tags = (
+ types => [
+ qw( SCALAR ARRAYREF HASHREF CODEREF GLOB GLOBREF SCALARREF HANDLE UNDEF OBJECT )
+ ],
+);
+
+our %EXPORT_TAGS = (
+ 'all' => [ qw( validation_options ), map { @{ $tags{$_} } } keys %tags ],
+ %tags,
+);
+our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} }, 'validation_options' );
+
+
+sub UNIVERSAL::Validate : ATTR(CODE, INIT) {
+ _wrap_sub( 'named', @_ );
+}
+
+sub UNIVERSAL::ValidatePos : ATTR(CODE, INIT) {
+ _wrap_sub( 'positional', @_ );
+}
+
+sub _wrap_sub {
+ my ( $type, $package, $symbol, $referent, $attr, $params ) = @_;
+
+ my @p = ref $params ? @{$params} : $params;
+
+ my $subname = $package . '::' . *{$symbol}{NAME};
+
+ my %attributes = map { $_ => 1 } attributes::get($referent);
+ my $is_method = $attributes{method};
+
+ {
+ no warnings 'redefine';
+ no strict 'refs';
+
+ # An unholy mixture of closure and eval. This is done so that
+ # the code to automatically create the relevant scalars from
+ # the hash of params can create the scalars in the proper
+ # place lexically.
+
+ my $code = <<"EOF";
+sub
+{
+ package $package;
+EOF
+
+ $code .= " my \$object = shift;\n" if $is_method;
+
+ if ( $type eq 'named' ) {
+ $params = {@p};
+ $code .= " Params::Validate::validate(\@_, \$params);\n";
+ }
+ else {
+ $code .= " Params::Validate::validate_pos(\@_, \@p);\n";
+ }
+
+ $code .= " unshift \@_, \$object if \$object;\n" if $is_method;
+
+ $code .= <<"EOF";
+ \$referent->(\@_);
+}
+EOF
+
+ my $sub = eval $code;
+ die $@ if $@;
+
+ *{$subname} = $sub;
+ }
+}
+
+1;
+
+# ABSTRACT: Define validation through subroutine attributes
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Attribute::Params::Validate - Define validation through subroutine attributes
+
+=head1 VERSION
+
+version 1.20
+
+=head1 SYNOPSIS
+
+ use Attribute::Params::Validate qw(:all);
+
+ # takes named params (hash or hashref)
+ # foo is mandatory, bar is optional
+ sub foo : Validate( foo => 1, bar => 0 )
+ {
+ # insert code here
+ }
+
+ # takes positional params
+ # first two are mandatory, third is optional
+ sub bar : ValidatePos( 1, 1, 0 )
+ {
+ # insert code here
+ }
+
+ # for some reason Perl insists that the entire attribute be on one line
+ sub foo2 : Validate( foo => { type => ARRAYREF }, bar => { can => [ 'print', 'flush', 'frobnicate' ] }, baz => { type => SCALAR, callbacks => { 'numbers only' => sub { shift() =~ /^\d+$/ }, 'less than 90' => sub { shift() < 90 } } } )
+ {
+ # insert code here
+ }
+
+ # note that this is marked as a method. This is very important!
+ sub baz : Validate( foo => { type => ARRAYREF }, bar => { isa => 'Frobnicator' } ) method
+ {
+ # insert code here
+ }
+
+=head1 DESCRIPTION
+
+The Attribute::Params::Validate module allows you to validate method
+or function call parameters just like Params::Validate does. However,
+this module allows you to specify your validation spec as an
+attribute, rather than by calling the C<validate> routine.
+
+Please see Params::Validate for more information on how you can
+specify what validation is performed.
+
+=head2 EXPORT
+
+This module exports everything that Params::Validate does except for
+the C<validate> and C<validate_pos> subroutines.
+
+=head2 ATTRIBUTES
+
+=over 4
+
+=item * Validate
+
+This attribute corresponds to the C<validate> subroutine in
+Params::Validate.
+
+=item * ValidatePos
+
+This attribute corresponds to the C<validate_pos> subroutine in
+Params::Validate.
+
+=back
+
+=head2 OO
+
+If you are using this module to mark B<methods> for validation, as
+opposed to subroutines, it is crucial that you mark these methods with
+the C<:method> attribute, as well as the C<Validate> or C<ValidatePos>
+attribute.
+
+If you do not do this, then the object or class used in the method
+call will be passed to the validation routines, which is probably not
+what you want.
+
+=head2 CAVEATS
+
+You B<must> put all the arguments to the C<Validate> or C<ValidatePos>
+attribute on a single line, or Perl will complain.
+
+=head1 SEE ALSO
+
+Params::Validate
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+Dave Rolsky <autarch@urth.org>
+
+=item *
+
+Ilya Martynov <ilya@martynov.org>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is Copyright (c) 2001 - 2015 by Dave Rolsky and Ilya Martynov.
+
+This is free software, licensed under:
+
+ The Artistic License 2.0 (GPL Compatible)
+
+=cut