File Coverage

blib/lib/Types/Common/Numeric.pm
Criterion Covered Total %
statement 24 24 100.0
branch n/a
condition n/a
subroutine 9 9 100.0
pod n/a
total 33 33 100.0


line stmt bran cond sub pod time code
1             package Types::Common::Numeric;
2              
3 49     49   148572 use 5.008001;
  49         239  
4 49     49   334 use strict;
  49         116  
  49         1578  
5 49     49   266 use warnings;
  49         122  
  49         7849  
6              
7             BEGIN {
8 49     49   221 $Types::Common::Numeric::AUTHORITY = 'cpan:TOBYINK';
9 49         4538 $Types::Common::Numeric::VERSION = '2.010001';
10             }
11              
12             $Types::Common::Numeric::VERSION =~ tr/_//d;
13              
14 49         693 use Type::Library -base, -declare => qw(
15             PositiveNum PositiveOrZeroNum
16             PositiveInt PositiveOrZeroInt
17             NegativeNum NegativeOrZeroNum
18             NegativeInt NegativeOrZeroInt
19             SingleDigit
20             NumRange IntRange
21 49     49   9066 );
  49         233  
22              
23 49     49   4919 use Type::Tiny ();
  49         113  
  49         1734  
24 49     49   11802 use Types::Standard qw( Num Int );
  49         192  
  49         576  
25 49     49   5212 use Types::TypeTiny qw( BoolLike );
  49         120  
  49         379  
26              
27 14     14   219 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  14         79  
28              
29             my $meta = __PACKAGE__->meta;
30              
31             $meta->add_type(
32             name => 'PositiveNum',
33             parent => Num,
34             constraint => sub { $_ > 0 },
35             inlined => sub { undef, qq($_ > 0) },
36             message => sub { "Must be a positive number" },
37             );
38              
39             $meta->add_type(
40             name => 'PositiveOrZeroNum',
41             parent => Num,
42             constraint => sub { $_ >= 0 },
43             inlined => sub { undef, qq($_ >= 0) },
44             message => sub { "Must be a number greater than or equal to zero" },
45             type_default => sub { return 0; },
46             );
47              
48             my ( $pos_int, $posz_int );
49             if ( Type::Tiny::_USE_XS ) {
50             $pos_int = Type::Tiny::XS::get_coderef_for( 'PositiveInt' )
51             if Type::Tiny::XS->VERSION >= 0.013; # fixed bug with "00"
52             $posz_int = Type::Tiny::XS::get_coderef_for( 'PositiveOrZeroInt' );
53             }
54              
55             $meta->add_type(
56             name => 'PositiveInt',
57             parent => Int,
58             constraint => sub { $_ > 0 },
59             inlined => sub {
60             if ( $pos_int ) {
61             my $xsub = Type::Tiny::XS::get_subname_for( $_[0]->name );
62             return "$xsub($_[1])" if $xsub && !$Type::Tiny::AvoidCallbacks;
63             }
64             undef, qq($_ > 0);
65             },
66             message => sub { "Must be a positive integer" },
67             $pos_int ? ( compiled_type_constraint => $pos_int ) : (),
68             );
69              
70             $meta->add_type(
71             name => 'PositiveOrZeroInt',
72             parent => Int,
73             constraint => sub { $_ >= 0 },
74             inlined => sub {
75             if ( $posz_int ) {
76             my $xsub = Type::Tiny::XS::get_subname_for( $_[0]->name );
77             return "$xsub($_[1])" if $xsub && !$Type::Tiny::AvoidCallbacks;
78             }
79             undef, qq($_ >= 0);
80             },
81             message => sub { "Must be an integer greater than or equal to zero" },
82             $posz_int ? ( compiled_type_constraint => $posz_int ) : (),
83             type_default => sub { return 0; },
84             );
85              
86             $meta->add_type(
87             name => 'NegativeNum',
88             parent => Num,
89             constraint => sub { $_ < 0 },
90             inlined => sub { undef, qq($_ < 0) },
91             message => sub { "Must be a negative number" },
92             );
93              
94             $meta->add_type(
95             name => 'NegativeOrZeroNum',
96             parent => Num,
97             constraint => sub { $_ <= 0 },
98             inlined => sub { undef, qq($_ <= 0) },
99             message => sub { "Must be a number less than or equal to zero" },
100             type_default => sub { return 0; },
101             );
102              
103             $meta->add_type(
104             name => 'NegativeInt',
105             parent => Int,
106             constraint => sub { $_ < 0 },
107             inlined => sub { undef, qq($_ < 0) },
108             message => sub { "Must be a negative integer" },
109             );
110              
111             $meta->add_type(
112             name => 'NegativeOrZeroInt',
113             parent => Int,
114             constraint => sub { $_ <= 0 },
115             inlined => sub { undef, qq($_ <= 0) },
116             message => sub { "Must be an integer less than or equal to zero" },
117             type_default => sub { return 0; },
118             );
119              
120             $meta->add_type(
121             name => 'SingleDigit',
122             parent => Int,
123             constraint => sub { $_ >= -9 and $_ <= 9 },
124             inlined => sub { undef, qq($_ >= -9), qq($_ <= 9) },
125             message => sub { "Must be a single digit" },
126             type_default => sub { return 0; },
127             );
128              
129             for my $base ( qw/Num Int/ ) {
130             $meta->add_type(
131             name => "${base}Range",
132             parent => Types::Standard->get_type( $base ),
133             constraint_generator => sub {
134             return $meta->get_type( "${base}Range" ) unless @_;
135            
136             my $base_obj = Types::Standard->get_type( $base );
137            
138             Type::Tiny::check_parameter_count_for_parameterized_type( 'Types::Common::Numeric', "${base}Range", \@_, 4 );
139             my ( $min, $max, $min_excl, $max_excl ) = @_;
140             !defined( $min )
141             or $base_obj->check( $min )
142             or _croak(
143             "${base}Range min must be a %s; got %s", lc( $base ),
144             $min
145             );
146             !defined( $max )
147             or $base_obj->check( $max )
148             or _croak(
149             "${base}Range max must be a %s; got %s", lc( $base ),
150             $max
151             );
152             !defined( $min_excl )
153             or BoolLike->check( $min_excl )
154             or _croak( "${base}Range minexcl must be a boolean; got $min_excl" );
155             !defined( $max_excl )
156             or BoolLike->check( $max_excl )
157             or _croak( "${base}Range maxexcl must be a boolean; got $max_excl" );
158            
159             # this is complicated so defer to the inline generator
160             eval sprintf(
161             'sub { %s }',
162             join ' and ',
163             grep defined,
164             $meta->get_type( "${base}Range" )->inline_generator->( @_ )->( undef, '$_[0]' ),
165             );
166             },
167             inline_generator => sub {
168             my ( $min, $max, $min_excl, $max_excl ) = @_;
169            
170             my $gt = $min_excl ? '>' : '>=';
171             my $lt = $max_excl ? '<' : '<=';
172            
173             return sub {
174             my $v = $_[1];
175             my @code = ( undef ); # parent constraint
176             push @code, "$v $gt $min";
177             push @code, "$v $lt $max" if defined $max;
178             return @code;
179             };
180             },
181             deep_explanation => sub {
182             my ( $type, $value, $varname ) = @_;
183             my ( $min, $max, $min_excl, $max_excl ) = @{ $type->parameters || [] };
184             my @whines;
185             if ( defined $max ) {
186             push @whines, sprintf(
187             '"%s" expects %s to be %s %d and %s %d',
188             $type,
189             $varname,
190             $min_excl ? 'greater than' : 'at least',
191             $min,
192             $max_excl ? 'less than' : 'at most',
193             $max,
194             );
195             } #/ if ( defined $max )
196             else {
197             push @whines, sprintf(
198             '"%s" expects %s to be %s %d',
199             $type,
200             $varname,
201             $min_excl ? 'greater than' : 'at least',
202             $min,
203             );
204             }
205             push @whines, sprintf(
206             "%s is %s",
207             $varname,
208             $value,
209             );
210             return \@whines;
211             },
212             );
213             } #/ for my $base ( qw/Num Int/)
214              
215             __PACKAGE__->meta->make_immutable;
216              
217             1;
218              
219             __END__