Type::TinyX::Facets - Easily create a facet parameterized Type::Tiny type
version 0.02
package My::Types; use Carp; use Type::Utils; use Type::Library -base, -declare => 'MinMax', 'Bounds', 'Positive'; use Types::Standard -types, 'is_Num'; use Type::TinyX::Facets; # independent facets facet 'min', sub { my ( $o, $var ) = @_; return unless exists $o->{min}; croak( "argument to 'min' facet must be a number\n" ) unless is_Num( $o->{min} ); sprintf( '%s >= %s', $var, delete $o->{min} ); }; facet 'max', sub { my ( $o, $var ) = @_; return unless exists $o->{max}; croak( "argument to 'max' facet must be a number\n" ) unless is_Num( $o->{max} ); sprintf( '%s <= %s', $var, delete $o->{max} ); }; facetize qw[min max], declare MinMax, as Num; # related facets facet bounds => sub { my ( $o, $var ) = @_; return unless exists $o->{max} || exists $o->{min}; croak( "constraint fails condition: max >= min\n" ) if exists $o->{max} && exists $o->{min} && $o->{max} < $o->{min}; my @code; if ( exists $o->{min} ) { croak( "argument to 'min' facet must be a number\n" ) unless is_Num( $o->{min} ); push @code, sprintf( '%s >= %s', $var, delete $o->{min} ); } if ( exists $o->{max} ) { croak( "argument to 'max' facet must be a number\n" ) unless is_Num( $o->{max} ); push @code, sprintf( '%s <= %s', $var, delete $o->{max} ); } return join( ' and ', @code ); }; facetize qw[bounds], declare Bounds, as Num; # on-the-fly creation of a facet facetize positive => sub { my ( $o, $var ) = @_; return unless exists $o->{positive}; delete $o->{positive}; sprintf( '%s > 0', $var ); }, qw[ min max ], declare Positive, as Num; 1;
And in some other code:
use My::Types -types; use Type::Params qw[ validate ]; validate( [5], MinMax [ min => 2 ] ); # passes validate( [5], MinMax [ min => 2, max => 6 ] ); # passes validate( [5], Bounds [ min => 2 ] ); # passes validate( [5], Bounds [ min => 2, max => 6 ] ); # passes validate( [5], Bounds [ min => 5, max => 2 ] ) ; # fails to construct as min > max validate( [0], Positive [ positive => 1 ] ); # fails! validate( [1], Positive [ positive => 1 ] ); # passes
Type::TinyX::Facets make it easy to create parameterized types with facets.
Type::Tiny allows definition of types which can accept parameters:
Type::Tiny
use Types::Standard -types; my $t1 = Array[Int]; my $t2 = Tuple[Int, HashRef];
This defines $t1 as an array of integers. and $t2 as a tuple of two elements, an integer and a hash.
$t1
$t2
Parameters are passed as a list to the parameterized constraint generation machinery, and there is great freedom in how they may be interpreted.
This module makes it easy to create a parameterized type which takes name - value pairs or,facets. (The terminology is taken from Types::XSD::Lite, to which this module owes its existence.)
Type::TinyX::Facets uses Exporter::Tiny, so one might correct(!?) the spelling of "facetize" thusly:
use Type::TinyX::Facets facetize => { -as => "facetise" };
Declare a facet with the given name and code generator. $coderef will be called as
$coderef
$coderef->( $options, $name, $facet_name );
where $options is a hash of the parameters passed to the type, and $name is the name of the variable to check against.
$options
$name
The code should return if the passed options are of no interest (and thus the facet should not be applied), otherwise it should return a string containing the validation code. It must delete the parameters that it uses from $o.
$o
For example, to implement a minimum value check:
facet 'min', sub { my ( $o, $var ) = @_; return unless exists $o->{min}; croak( "argument to 'min' facet must be a number\n" ) unless is_Num( $o->{min} ); sprintf('%s >= %s', $var, delete $o->{min} ); };
Add the specified facets to the given type. The type should not have any constraints other than through inheritance from a parent type.
@facets is a list of facets. If a facet was previously created with the "facet" subroutine, only the name (as a string) need be specified. A facet may also be specified as a name, coderef pair, e.g.
@facets
@facets = ( 'min', positive => sub { my ($o, $var) = @_; return unless exists $o->{positive}; delete $o->{positive}; sprintf('%s > 0', $var); } );
Typically facetize is applied directly to a "declare" in Type::Utils statement, e.g.:
facetize @facets, declare T1, as Num;
Facets defined in one package are not available to another package.
The idea and most of the code was lifted from Types::XSD::Lite. Any bugs are definitely mine.
The development version is on GitLab at https://gitlab.com/djerius/type-tinyx-facets.
Please report any bugs or feature requests on the bugtracker website https://rt.cpan.org/Public/Dist/Display.html?Name=Type-TinyX-Facets
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.
Diab Jerius <djerius@cpan.org>
This software is copyright (c) 2017 by Smithsonian Astrophysical Observatory.
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 Type::TinyX::Facets, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Type::TinyX::Facets
CPAN shell
perl -MCPAN -e shell install Type::TinyX::Facets
For more information on module installation, please visit the detailed CPAN module installation guide.