Data::Sah::Manual::ParamsValidating - Validating function/method parameters using Data::Sah
This document describes version 0.88 of Data::Sah::Manual::ParamsValidating (from Perl distribution Data-Sah), released on 2017-07-10.
There are several choices when it comes to validating function/method parameters using Sah schemas and Data::Sah. The job of Data::Sah is just to generate Perl code from a Sah schema. The Perl code can be integrated into your code in several ways. The final result might or might not need Data::Sah itself.
The document is divided into two parts depending on where the Sah schemas are put.
One recommended way to put the schemas are in the Rinci function metadata. With Rinci metadata you specify more than just types/constraints for your function parameters/arguments, including: summary & description, return value, command-line short options, tab completion, and so on.
Once you have your Rinci metadata, e.g.:
$SPEC{foo} = { v => 1.1, summary => 'Does foo', args => { a1 => { summary => 'First argument', schema => 'int*', req => 1, }, a2 => { summary => 'Second argument', schema => ['array', of=>'int*', min_len=>1], default => [1], }, }, }; sub foo { my %args = @_; ... }
You can decide whether you want to depend on Data::Sah or not during runtime.
If you do not want to depend on Data::Sah, what you can do is insert the generated validator code:
my %args = @_; # VALIDATE_ARGS
This requires that your code be organized as a Perl distribution, and you use Dist::Zilla to build your distribution, and you use the Dist::Zilla::Plugin::Rinci::Validate plugin to scan for the # VALIDATE_ARGS labels and insert the validator code there (all in one long line, as to not mess with line numbers). Also, the validator code will only be present in the built version of your code. But this way, you can avoid an extra sub call to the validator code and the validator code no longer needs need Data::Sah. The the overhead of compilation from Sah schema to Perl code is moved into distribution build time.
# VALIDATE_ARGS
If you use this method, it is advisable that you also put this attribute in your Rinci metadata (the dzil plugin will remind you):
'x.func.validate_args' => 1
This is to express that your function already performs argument validation and other tools/frameworks (e.g. Perinci::CmdLine::Lite or Perinci::Sub::Wrapper, see below) can skip doing argument validation again. Forgetting to add this attribute is not dangerous, it just means you're validating twice (where once is already enough).
If you find the above method too cumbersome, you can also generate the validator dynamically using Perinci::Sub::ValidateArgs.
use Perinci::Sub::ValidateArgs; $SPEC{foo} = { ... }; sub foo { state $validator = gen_args_validator(); my %args = @_; if (my $err = $validator->(\%args)) { return $err } ... }
or, if you want to die on validation failure:
$SPEC{foo} = { ... }; sub foo { state $validator = gen_args_validator(die => 1); my %args = @_; $validator->(\%args); ... }
Perinci::Sub::ValidateArgs will retrieve the Rinci metadata from the caller's %SPEC package variable, then generate Perl validator code for all the arguments specified in the Rinci metadata, and compose them into a single arguments validator subroutine which is then returned for you to use. This generation process is only done once, the first time your function is called. The subsequent call will be faster since the arguments validator routine is cached by the state variable. Note that state variable is available from perl 5.010. If you are stuck with older perl, you can use the alternative solution like:
%SPEC
my $validator_foo; sub foo { $validator_foo ||= gen_args_validator(); if (my $err = $validator_foo->(\%args)) { return $err } ... }
or perhaps:
{ my $validator; sub foo { $validator ||= gen_args_validator(); if (my $err = $validator->(\%args)) { return $err } ... } }
Using Perinci::Sub::ValidateArgs is more convenient than using the dzil plugin because you do not need to build a Perl distribution first. But this method is a tiny bit slower during runtime and will require Data::Sah during runtime.
Two other alternatives are available under some situation.
If you only use your function through a CLI using Perinci::CmdLine::Lite or Perinci::CmdLine::Inline framework, you can skip validating in the function body and let the framework validate (or generate a validator) for you.
During runtime, Perinci::CmdLine::Lite will retrieve your function's Rinci metadata and generate Data::Sah validators for all the specified arguments and check them. This means you will require Data::Sah during runtime.
Perinci::CmdLine::Inline on the other hand will generate a CLI script with the arguments validator embedded in it. Data::Sah will no longer be required during runtime.
Note that if your Rinci metadata already contains this attribute x.perl.validate_args set to true, argument validation will not be done.
x.perl.validate_args
Perinci::Sub::Wrapper will create a wrapper for your function and add functionalities (including argument validation) according to information from Rinci metadata. This can be done dynamically, or the wrapper code can be included in the source code during distribution build time using Dist::Zilla::Plugin::Rinci::Wrap.
Perinci::CmdLine::Classic is a CLI framework which uses Perinci::Sub::Wrapper to perform argument validation.
TBD. Data::Sah::Params.
Please visit the project's homepage at https://metacpan.org/release/Data-Sah.
Source repository is at https://github.com/perlancar/perl-Data-Sah.
Please report any bugs or feature requests on the bugtracker website https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Sah
When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature.
Alternatives to Sah/Data::Sah to validate your function/method parameters: Params::Validate, Type::Tiny/Type::Params (see Type::Tiny::Manual::Params).
perlancar <perlancar@cpan.org>
This software is copyright (c) 2017, 2016, 2015, 2014, 2013, 2012 by perlancar@cpan.org.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
To install Data::Sah, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Data::Sah
CPAN shell
perl -MCPAN -e shell install Data::Sah
For more information on module installation, please visit the detailed CPAN module installation guide.