Easily create a facet parameterized Type::Tiny type
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
examples
lib/Type/TinyX
t
.hgtags
Changes
LICENSE
MANIFEST.SKIP
Makefile.PL
README.mkdn
cpanfile
dist.ini
weaver.ini

README.mkdn

NAME

Type::TinyX::Facets - Easily create a facet parameterized Type::Tiny type

VERSION

version 0.01

SYNOPSIS

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

DESCRIPTION

Type::TinyX::Facets make it easy to create parameterized types with facets.

Type::Tiny allows definition of types which can accept parameters:

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.

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.)

SUBROUTINES

facet( $name, $coderef )

Declare a facet with the given name and code generator. $coderef will be called as

$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.

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.

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} );
    };

facetize( @facets, $type )

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 = (
    '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;

LIMITATIONS

Facets defined in one package are not available to another package.

THANKS

BUGS

Please report any bugs or feature requests on the bugtracker website https://rt.cpan.org/Public/Dist/Display.html?Name=Type-TinyX-Facets or by email to bug-Type-TinyX-Facets@rt.cpan.org.

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.

AUTHOR

Diab Jerius djerius@cpan.org

COPYRIGHT AND LICENSE

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.