📄 validate.pm
字号:
# Copyright (c) 2000-2004 Dave Rolsky# All rights reserved.# This program is free software; you can redistribute it and/or# modify it under the same terms as Perl itself. See the LICENSE# file that comes with this distribution for more details.package Params::Validate;use strict;BEGIN{ use Exporter; use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS %OPTIONS $options $NO_VALIDATION ); @ISA = 'Exporter'; $VERSION = '0.73'; my %tags = ( types => [ qw( SCALAR ARRAYREF HASHREF CODEREF GLOB GLOBREF SCALARREF HANDLE BOOLEAN UNDEF OBJECT ) ], ); %EXPORT_TAGS = ( 'all' => [ qw( validate validate_pos validation_options validate_with ), map { @{ $tags{$_} } } keys %tags ], %tags, ); @EXPORT_OK = ( @{ $EXPORT_TAGS{all} }, 'set_options' ); @EXPORT = qw( validate validate_pos ); $NO_VALIDATION = $ENV{PERL_NO_VALIDATION}; eval { require Params::ValidateXS; } unless $ENV{PV_TEST_PERL}; if ( $@ || $ENV{PV_TEST_PERL} ) { # suppress subroutine redefined warnings local $^W = 0; require Params::ValidatePP; }}1;__END__=head1 NAMEParams::Validate - Validate method/function parameters=head1 SYNOPSIS use Params::Validate qw(:all); # takes named params (hash or hashref) sub foo { validate( @_, { foo => 1, # mandatory bar => 0, # optional } ); } # takes positional params sub bar { # first two are mandatory, third is optional validate_pos( @_, 1, 1, 0 ); } sub foo2 { validate( @_, { foo => # specify a type { type => ARRAYREF }, bar => # specify an interface { can => [ 'print', 'flush', 'frobnicate' ] }, baz => { type => SCALAR, # a scalar ... # ... that is a plain integer ... regex => qr/^\d+$/, callbacks => { # ... and smaller than 90 'less than 90' => sub { shift() < 90 }, }, } } ); } sub with_defaults { my %p = validate( @_, { foo => 1, # required # $p{bar} will be 99 if bar is not # given. bar is now optional. bar => { default => 99 } } ); } sub pos_with_defaults { my @p = validate_pos( @_, 1, { default => 99 } ); } sub sets_options_on_call { my %p = validate_with ( params => \@_, spec => { foo => { type SCALAR, default => 2 } }, normalize_keys => sub { $_[0] =~ s/^-//; lc $_[0] }, ); }=head1 DESCRIPTIONThe Params::Validate module allows you to validate method or functioncall parameters to an arbitrary level of specificity. At the simplestlevel, it is capable of validating the required parameters were givenand that no unspecified additional parameters were passed in.It is also capable of determining that a parameter is of a specifictype, that it is an object of a certain class hierarchy, that itpossesses certain methods, or applying validation callbacks toarguments.=head2 EXPORTThe module always exports the C<validate()> and C<validate_pos()>functions.It also has an additional function available for export,C<validate_with>, which can be used to validate any type ofparameters, and set various options on a per-invocation basis.In addition, it can export the following constants, which are used aspart of the type checking. These are C<SCALAR>, C<ARRAYREF>,C<HASHREF>, C<CODEREF>, C<GLOB>, C<GLOBREF>, and C<SCALARREF>,C<UNDEF>, C<OBJECT>, C<BOOLEAN>, and C<HANDLE>. These are explainedin the section on L<Type Validation|Params::Validate/Type Validation>.The constants are available via the export tag C<:types>. There isalso an C<:all> tag which includes all of the constants as well as theC<validation_options()> function.=head1 PARAMETER VALIDATIONThe validation mechanisms provided by this module can handle bothnamed or positional parameters. For the most part, the same featuresare available for each. The biggest difference is the way that thevalidation specification is given to the relevant subroutine. Theother difference is in the error messages produced when validationchecks fail.When handling named parameters, the module is capable of handlingeither a hash or a hash reference transparently.Subroutines expecting named parameters should call the C<validate()>subroutine like this: validate( @_, { parameter1 => validation spec, parameter2 => validation spec, ... } );Subroutines expecting positional parameters should call theC<validate_pos()> subroutine like this: validate_pos( @_, { validation spec }, { validation spec } );=head2 Mandatory/Optional ParametersIf you just want to specify that some parameters are mandatory andothers are optional, this can be done very simply.For a subroutine expecting named parameters, you would do this: validate( @_, { foo => 1, bar => 1, baz => 0 } );This says that the "foo" and "bar" parameters are mandatory and thatthe "baz" parameter is optional. The presence of any otherparameters will cause an error.For a subroutine expecting positional parameters, you would do this: validate_pos( @_, 1, 1, 0, 0 );This says that you expect at least 2 and no more than 4 parameters.If you have a subroutine that has a minimum number of parameters butcan take any maximum number, you can do this: validate_pos( @_, 1, 1, (0) x (@_ - 2) );This will always be valid as long as at least two parameters aregiven. A similar construct could be used for the more complexvalidation parameters described further on.Please note that this: validate_pos( @_, 1, 1, 0, 1, 1 );makes absolutely no sense, so don't do it. Any zeros must come at theend of the validation specification.In addition, if you specify that a parameter can have a default, thenit is considered optional.=head2 Type ValidationThis module supports the following simple types, which can beL<exported as constants|EXPORT>:=over 4=item * SCALARA scalar which is not a reference, such as C<10> or C<'hello'>. Aparameter that is undefined is B<not> treated as a scalar. If youwant to allow undefined values, you will have to specify C<SCALAR |UNDEF>.=item * ARRAYREFAn array reference such as C<[1, 2, 3]> or C<\@foo>.=item * HASHREFA hash reference such as C<{ a => 1, b => 2 }> or C<\%bar>.=item * CODEREFA subroutine reference such as C<\&foo_sub> or C<sub { print "hello" }>.=item * GLOBThis one is a bit tricky. A glob would be something like C<*FOO>, butnot C<\*FOO>, which is a glob reference. It should be noted that thistrick: my $fh = do { local *FH; };makes C<$fh> a glob, not a glob reference. On the other hand, thereturn value from C<Symbol::gensym> is a glob reference. Either canbe used as a file or directory handle.=item * GLOBREFA glob reference such as C<\*FOO>. See the L<GLOB|GLOB> entry abovefor more details.=item * SCALARREFA reference to a scalar such as C<\$x>.=item * UNDEFAn undefined value=item * OBJECTA blessed reference.=item * BOOLEANThis is a special option, and is just a shortcut for C<UNDEF | SCALAR>.=item * HANDLEThis option is also special, and is just a shortcut for C<GLOB |GLOBREF>. However, it seems likely that most people interested ineither globs or glob references are likely to really be interested inwhether the parameter in questoin could be a valid file or directoryhandle.=backTo specify that a parameter must be of a given type when using namedparameters, do this: validate( @_, { foo => { type => SCALAR }, bar => { type => HASHREF } } );If a parameter can be of more than one type, just use the bitwise or(C<|>) operator to combine them. validate( @_, { foo => { type => GLOB | GLOBREF } );For positional parameters, this can be specified as follows: validate_pos( @_, { type => SCALAR | ARRAYREF }, { type => CODEREF } );=head2 Interface ValidationTo specify that a parameter is expected to have a certain set ofmethods, we can do the following: validate( @_, { foo => # just has to be able to ->bar { can => 'bar' } } ); ... or ... validate( @_, { foo => # must be able to ->bar and ->print { can => [ qw( bar print ) ] } } );=head2 Class ValidationA word of warning. When constructing your external interfaces, it isprobably better to specify what methods you expect an object tohave rather than what class it should be of (or a child of). Thiswill make your API much more flexible.With that said, if you want to validate that an incoming parameterbelongs to a class (or child class) or classes, do: validate( @_, { foo => { isa => 'My::Frobnicator' } } ); ... or ... validate( @_, { foo => { isa => [ qw( My::Frobnicator IO::Handle ) ] } } ); # must be both, not either!=head2 Regex ValidationIf you want to specify that a given parameter must match a specificregular expression, this can be done with "regex" spec key. Forexample: validate( @_, { foo => { regex => qr/^\d+$/ } } );The value of the "regex" key may be either a string or a pre-compiledregex created via C<qr>.The C<Regexp::Common> module on CPAN is an excellent source of regularexpressions suitable for validating input.=head2 Callback ValidationIf none of the above are enough, it is possible to pass in one or morecallbacks to validate the parameter. The callback will be given theB<value> of the parameter as its first argument. Its second argumentwill be all the parameters, as a reference to either a hash or array.Callbacks are specified as hash reference. The key is an id for thecallback (used in error messages) and the value is a subroutinereference, such as:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -