| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Specio::Declare; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 28 |  |  | 28 |  | 811748 | use strict; | 
|  | 28 |  |  |  |  | 728 |  | 
|  | 28 |  |  |  |  | 822 |  | 
| 4 | 28 |  |  | 28 |  | 143 | use warnings; | 
|  | 28 |  |  |  |  | 44 |  | 
|  | 28 |  |  |  |  | 717 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 28 |  |  | 28 |  | 3451 | use parent 'Exporter'; | 
|  | 28 |  |  |  |  | 2208 |  | 
|  | 28 |  |  |  |  | 167 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | our $VERSION = '0.46'; | 
| 9 |  |  |  |  |  |  |  | 
| 10 | 28 |  |  | 28 |  | 1837 | use Carp qw( croak ); | 
|  | 28 |  |  |  |  | 48 |  | 
|  | 28 |  |  |  |  | 1223 |  | 
| 11 | 28 |  |  | 28 |  | 10978 | use Specio::Coercion; | 
|  | 28 |  |  |  |  | 68 |  | 
|  | 28 |  |  |  |  | 871 |  | 
| 12 | 28 |  |  | 28 |  | 11052 | use Specio::Constraint::Simple; | 
|  | 28 |  |  |  |  | 65 |  | 
|  | 28 |  |  |  |  | 856 |  | 
| 13 | 28 |  |  | 28 |  | 4295 | use Specio::DeclaredAt; | 
|  | 28 |  |  |  |  | 53 |  | 
|  | 28 |  |  |  |  | 722 |  | 
| 14 | 28 |  |  | 28 |  | 143 | use Specio::Helpers qw( install_t_sub _STRINGLIKE ); | 
|  | 28 |  |  |  |  | 50 |  | 
|  | 28 |  |  |  |  | 1286 |  | 
| 15 | 28 |  |  | 28 |  | 3043 | use Specio::Registry qw( internal_types_for_package register ); | 
|  | 28 |  |  |  |  | 52 |  | 
|  | 28 |  |  |  |  | 38593 |  | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | ## no critic (Modules::ProhibitAutomaticExportation) | 
| 18 |  |  |  |  |  |  | our @EXPORT = qw( | 
| 19 |  |  |  |  |  |  | anon | 
| 20 |  |  |  |  |  |  | any_can_type | 
| 21 |  |  |  |  |  |  | any_does_type | 
| 22 |  |  |  |  |  |  | any_isa_type | 
| 23 |  |  |  |  |  |  | coerce | 
| 24 |  |  |  |  |  |  | declare | 
| 25 |  |  |  |  |  |  | enum | 
| 26 |  |  |  |  |  |  | intersection | 
| 27 |  |  |  |  |  |  | object_can_type | 
| 28 |  |  |  |  |  |  | object_does_type | 
| 29 |  |  |  |  |  |  | object_isa_type | 
| 30 |  |  |  |  |  |  | union | 
| 31 |  |  |  |  |  |  | ); | 
| 32 |  |  |  |  |  |  | ## use critic | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | sub import { | 
| 35 | 92 |  |  | 92 |  | 8286 | my $package = shift; | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | # What the heck is this monstrosity? | 
| 38 |  |  |  |  |  |  | # | 
| 39 |  |  |  |  |  |  | # Moose version 2.0901 included a first pass at support for Specio. This | 
| 40 |  |  |  |  |  |  | # was based on Specio c. 0.06 when Specio itself still used | 
| 41 |  |  |  |  |  |  | # Moose. Unfortunately, recent changes to Specio broke this support and | 
| 42 |  |  |  |  |  |  | # the Moose core needs updating. | 
| 43 |  |  |  |  |  |  | # | 
| 44 |  |  |  |  |  |  | # However, stable versions of Moose have since shipped with a test that | 
| 45 |  |  |  |  |  |  | # attempts to test itself with Specio 0.07+. This was fine until I wanted | 
| 46 |  |  |  |  |  |  | # to release a non-TRIAL Specio. | 
| 47 |  |  |  |  |  |  | # | 
| 48 |  |  |  |  |  |  | # Once that's out, anyone installing Specio will cause future attempts to | 
| 49 |  |  |  |  |  |  | # install Moose to fail until Moose includes updated Specio support! | 
| 50 |  |  |  |  |  |  | # Breaking Moose is not acceptable, thus this mess. | 
| 51 |  |  |  |  |  |  | # | 
| 52 |  |  |  |  |  |  | # Note that since Moose 2.1207 this test was renamed and the Specio tests | 
| 53 |  |  |  |  |  |  | # actually run (and pass). We still need to leave this in here for quite | 
| 54 |  |  |  |  |  |  | # some time. People should be able to install Specio and then install an | 
| 55 |  |  |  |  |  |  | # older Moose indefinitely (or at least for a year or two). | 
| 56 | 92 | 50 | 33 |  |  | 663 | if (   $ENV{HARNESS_ACTIVE} | 
| 57 |  |  |  |  |  |  | && $0 =~ m{t[\\/]type_constraints[\\/]specio\.t$} ) { | 
| 58 |  |  |  |  |  |  |  | 
| 59 | 0 |  |  |  |  | 0 | require Test::More; | 
| 60 | 0 |  |  |  |  | 0 | Test::More::plan( skip_all => | 
| 61 |  |  |  |  |  |  | 'These tests will not pass with this version of Specio' ); | 
| 62 | 0 |  |  |  |  | 0 | exit 0; | 
| 63 |  |  |  |  |  |  | } | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 92 |  |  |  |  | 222 | my $caller = caller(); | 
| 66 |  |  |  |  |  |  |  | 
| 67 | 92 |  |  |  |  | 9406 | $package->export_to_level( 1, $package, @_ ); | 
| 68 |  |  |  |  |  |  |  | 
| 69 | 92 |  |  |  |  | 700 | install_t_sub( | 
| 70 |  |  |  |  |  |  | $caller, | 
| 71 |  |  |  |  |  |  | internal_types_for_package($caller) | 
| 72 |  |  |  |  |  |  | ); | 
| 73 |  |  |  |  |  |  |  | 
| 74 | 92 |  |  |  |  | 7976 | return; | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | sub declare { | 
| 78 | 801 | 50 |  | 801 | 1 | 2071 | my $name = _STRINGLIKE(shift) | 
| 79 |  |  |  |  |  |  | or croak 'You must provide a name for declared types'; | 
| 80 | 801 |  |  |  |  | 2105 | my %p = @_; | 
| 81 |  |  |  |  |  |  |  | 
| 82 | 801 |  |  |  |  | 2016 | my $tc = _make_tc( name => $name, %p ); | 
| 83 |  |  |  |  |  |  |  | 
| 84 | 801 |  |  |  |  | 5403 | register( scalar caller(), $name, $tc, 'exportable' ); | 
| 85 |  |  |  |  |  |  |  | 
| 86 | 801 |  |  |  |  | 1848 | return $tc; | 
| 87 |  |  |  |  |  |  | } | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | sub anon { | 
| 90 | 10 |  |  | 10 | 1 | 45 | return _make_tc(@_); | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | sub enum { | 
| 94 | 3 |  |  | 3 | 1 | 17880 | my $name; | 
| 95 | 3 | 50 |  |  |  | 15 | $name = shift if @_ % 2; | 
| 96 | 3 |  |  |  |  | 9 | my %p = @_; | 
| 97 |  |  |  |  |  |  |  | 
| 98 | 3 |  |  |  |  | 1380 | require Specio::Constraint::Enum; | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | my $tc = _make_tc( | 
| 101 |  |  |  |  |  |  | ( defined $name ? ( name => $name ) : () ), | 
| 102 |  |  |  |  |  |  | values     => $p{values}, | 
| 103 | 3 | 50 |  |  |  | 25 | type_class => 'Specio::Constraint::Enum', | 
| 104 |  |  |  |  |  |  | ); | 
| 105 |  |  |  |  |  |  |  | 
| 106 | 3 | 50 |  |  |  | 34 | register( scalar caller(), $name, $tc, 'exportable' ) | 
| 107 |  |  |  |  |  |  | if defined $name; | 
| 108 |  |  |  |  |  |  |  | 
| 109 | 3 |  |  |  |  | 9 | return $tc; | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | sub object_can_type { | 
| 113 | 5 |  |  | 5 | 1 | 134592 | my $name; | 
| 114 | 5 | 100 |  |  |  | 36 | $name = shift if @_ % 2; | 
| 115 | 5 |  |  |  |  | 23 | my %p = @_; | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | # This cannot be loaded earlier, since it loads Specio::Library::Builtins, | 
| 118 |  |  |  |  |  |  | # which in turn wants to load Specio::Declare (the current module). | 
| 119 | 5 |  |  |  |  | 1007 | require Specio::Constraint::ObjectCan; | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | my $tc = _make_tc( | 
| 122 |  |  |  |  |  |  | ( defined $name ? ( name => $name ) : () ), | 
| 123 |  |  |  |  |  |  | methods    => $p{methods}, | 
| 124 | 5 | 100 |  |  |  | 38 | type_class => 'Specio::Constraint::ObjectCan', | 
| 125 |  |  |  |  |  |  | ); | 
| 126 |  |  |  |  |  |  |  | 
| 127 | 5 | 100 |  |  |  | 58 | register( scalar caller(), $name, $tc, 'exportable' ) | 
| 128 |  |  |  |  |  |  | if defined $name; | 
| 129 |  |  |  |  |  |  |  | 
| 130 | 5 |  |  |  |  | 20 | return $tc; | 
| 131 |  |  |  |  |  |  | } | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | sub object_does_type { | 
| 134 | 7 |  |  | 7 | 1 | 49446 | my $name; | 
| 135 | 7 | 100 |  |  |  | 32 | $name = shift if @_ % 2; | 
| 136 | 7 |  |  |  |  | 22 | my %p = @_; | 
| 137 |  |  |  |  |  |  |  | 
| 138 | 7 |  |  |  |  | 18 | my $caller = scalar caller(); | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | # If we are being called repeatedly with a single argument, then we don't | 
| 141 |  |  |  |  |  |  | # want to blow up because the type has already been declared. This would | 
| 142 |  |  |  |  |  |  | # force the user to use t() for all calls but the first, making their code | 
| 143 |  |  |  |  |  |  | # pointlessly more complicated. | 
| 144 | 7 | 100 |  |  |  | 26 | unless ( keys %p ) { | 
| 145 | 4 | 100 |  |  |  | 20 | if ( my $exists = internal_types_for_package($caller)->{$name} ) { | 
| 146 | 2 |  |  |  |  | 10 | return $exists; | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  | } | 
| 149 |  |  |  |  |  |  |  | 
| 150 | 5 |  |  |  |  | 2091 | require Specio::Constraint::ObjectDoes; | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | my $tc = _make_tc( | 
| 153 |  |  |  |  |  |  | ( defined $name ? ( name => $name ) : () ), | 
| 154 | 5 | 100 |  |  |  | 45 | role       => ( defined $p{role} ? $p{role} : $name ), | 
|  |  | 100 |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | type_class => 'Specio::Constraint::ObjectDoes', | 
| 156 |  |  |  |  |  |  | ); | 
| 157 |  |  |  |  |  |  |  | 
| 158 | 5 | 100 |  |  |  | 52 | register( scalar caller(), $name, $tc, 'exportable' ) | 
| 159 |  |  |  |  |  |  | if defined $name; | 
| 160 |  |  |  |  |  |  |  | 
| 161 | 5 |  |  |  |  | 18 | return $tc; | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | sub object_isa_type { | 
| 165 | 4 |  |  | 4 | 1 | 36951 | my $name; | 
| 166 | 4 | 100 |  |  |  | 25 | $name = shift if @_ % 2; | 
| 167 | 4 |  |  |  |  | 13 | my %p = @_; | 
| 168 |  |  |  |  |  |  |  | 
| 169 | 4 |  |  |  |  | 11 | my $caller = scalar caller(); | 
| 170 | 4 | 100 |  |  |  | 18 | unless ( keys %p ) { | 
| 171 | 3 | 100 |  |  |  | 17 | if ( my $exists = internal_types_for_package($caller)->{$name} ) { | 
| 172 | 1 |  |  |  |  | 6 | return $exists; | 
| 173 |  |  |  |  |  |  | } | 
| 174 |  |  |  |  |  |  | } | 
| 175 |  |  |  |  |  |  |  | 
| 176 | 3 |  |  |  |  | 1381 | require Specio::Constraint::ObjectIsa; | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | my $tc = _make_tc( | 
| 179 |  |  |  |  |  |  | ( defined $name ? ( name => $name ) : () ), | 
| 180 | 3 | 100 |  |  |  | 30 | class      => ( defined $p{class} ? $p{class} : $name ), | 
|  |  | 100 |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | type_class => 'Specio::Constraint::ObjectIsa', | 
| 182 |  |  |  |  |  |  | ); | 
| 183 |  |  |  |  |  |  |  | 
| 184 | 3 | 100 |  |  |  | 33 | register( $caller, $name, $tc, 'exportable' ) | 
| 185 |  |  |  |  |  |  | if defined $name; | 
| 186 |  |  |  |  |  |  |  | 
| 187 | 3 |  |  |  |  | 10 | return $tc; | 
| 188 |  |  |  |  |  |  | } | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | sub any_can_type { | 
| 191 | 2 |  |  | 2 | 1 | 23134 | my $name; | 
| 192 | 2 | 100 |  |  |  | 170 | $name = shift if @_ % 2; | 
| 193 | 2 |  |  |  |  | 8 | my %p = @_; | 
| 194 |  |  |  |  |  |  |  | 
| 195 |  |  |  |  |  |  | # This cannot be loaded earlier, since it loads Specio::Library::Builtins, | 
| 196 |  |  |  |  |  |  | # which in turn wants to load Specio::Declare (the current module). | 
| 197 | 2 |  |  |  |  | 1247 | require Specio::Constraint::AnyCan; | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | my $tc = _make_tc( | 
| 200 |  |  |  |  |  |  | ( defined $name ? ( name => $name ) : () ), | 
| 201 |  |  |  |  |  |  | methods    => $p{methods}, | 
| 202 | 2 | 100 |  |  |  | 17 | type_class => 'Specio::Constraint::AnyCan', | 
| 203 |  |  |  |  |  |  | ); | 
| 204 |  |  |  |  |  |  |  | 
| 205 | 2 | 100 |  |  |  | 26 | register( scalar caller(), $name, $tc, 'exportable' ) | 
| 206 |  |  |  |  |  |  | if defined $name; | 
| 207 |  |  |  |  |  |  |  | 
| 208 | 2 |  |  |  |  | 7 | return $tc; | 
| 209 |  |  |  |  |  |  | } | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | sub any_does_type { | 
| 212 | 7 |  |  | 7 | 1 | 54878 | my $name; | 
| 213 | 7 | 100 |  |  |  | 56 | $name = shift if @_ % 2; | 
| 214 | 7 |  |  |  |  | 22 | my %p = @_; | 
| 215 |  |  |  |  |  |  |  | 
| 216 | 7 |  |  |  |  | 19 | my $caller = scalar caller(); | 
| 217 | 7 | 100 |  |  |  | 24 | unless ( keys %p ) { | 
| 218 | 3 | 50 |  |  |  | 11 | if ( my $exists = internal_types_for_package($caller)->{$name} ) { | 
| 219 | 3 |  |  |  |  | 12 | return $exists; | 
| 220 |  |  |  |  |  |  | } | 
| 221 |  |  |  |  |  |  | } | 
| 222 |  |  |  |  |  |  |  | 
| 223 | 4 |  |  |  |  | 1702 | require Specio::Constraint::AnyDoes; | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | my $tc = _make_tc( | 
| 226 |  |  |  |  |  |  | ( defined $name ? ( name => $name ) : () ), | 
| 227 | 4 | 100 |  |  |  | 39 | role       => ( defined $p{role} ? $p{role} : $name ), | 
|  |  | 50 |  |  |  |  |  | 
| 228 |  |  |  |  |  |  | type_class => 'Specio::Constraint::AnyDoes', | 
| 229 |  |  |  |  |  |  | ); | 
| 230 |  |  |  |  |  |  |  | 
| 231 | 4 | 100 |  |  |  | 43 | register( scalar caller(), $name, $tc, 'exportable' ) | 
| 232 |  |  |  |  |  |  | if defined $name; | 
| 233 |  |  |  |  |  |  |  | 
| 234 | 4 |  |  |  |  | 16 | return $tc; | 
| 235 |  |  |  |  |  |  | } | 
| 236 |  |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  | sub any_isa_type { | 
| 238 | 5 |  |  | 5 | 1 | 66300 | my $name; | 
| 239 | 5 | 100 |  |  |  | 30 | $name = shift if @_ % 2; | 
| 240 | 5 |  |  |  |  | 24 | my %p = @_; | 
| 241 |  |  |  |  |  |  |  | 
| 242 | 5 |  |  |  |  | 15 | my $caller = scalar caller(); | 
| 243 | 5 | 100 |  |  |  | 22 | unless ( keys %p ) { | 
| 244 | 2 | 100 |  |  |  | 12 | if ( my $exists = internal_types_for_package($caller)->{$name} ) { | 
| 245 | 1 |  |  |  |  | 6 | return $exists; | 
| 246 |  |  |  |  |  |  | } | 
| 247 |  |  |  |  |  |  | } | 
| 248 |  |  |  |  |  |  |  | 
| 249 | 4 |  |  |  |  | 1798 | require Specio::Constraint::AnyIsa; | 
| 250 |  |  |  |  |  |  |  | 
| 251 |  |  |  |  |  |  | my $tc = _make_tc( | 
| 252 |  |  |  |  |  |  | ( defined $name ? ( name => $name ) : () ), | 
| 253 | 4 | 100 |  |  |  | 39 | class      => ( defined $p{class} ? $p{class} : $name ), | 
|  |  | 100 |  |  |  |  |  | 
| 254 |  |  |  |  |  |  | type_class => 'Specio::Constraint::AnyIsa', | 
| 255 |  |  |  |  |  |  | ); | 
| 256 |  |  |  |  |  |  |  | 
| 257 | 4 | 100 |  |  |  | 48 | register( scalar caller(), $name, $tc, 'exportable' ) | 
| 258 |  |  |  |  |  |  | if defined $name; | 
| 259 |  |  |  |  |  |  |  | 
| 260 | 4 |  |  |  |  | 15 | return $tc; | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  |  | 
| 263 |  |  |  |  |  |  | sub intersection { | 
| 264 | 3 |  |  | 3 | 1 | 14 | my $name; | 
| 265 | 3 | 100 |  |  |  | 13 | $name = shift if @_ % 2; | 
| 266 | 3 |  |  |  |  | 10 | my %p = @_; | 
| 267 |  |  |  |  |  |  |  | 
| 268 | 3 |  |  |  |  | 30 | require Specio::Constraint::Intersection; | 
| 269 |  |  |  |  |  |  |  | 
| 270 | 3 | 100 |  |  |  | 16 | my $tc = _make_tc( | 
| 271 |  |  |  |  |  |  | ( defined $name ? ( name => $name ) : () ), | 
| 272 |  |  |  |  |  |  | %p, | 
| 273 |  |  |  |  |  |  | type_class => 'Specio::Constraint::Intersection', | 
| 274 |  |  |  |  |  |  | ); | 
| 275 |  |  |  |  |  |  |  | 
| 276 | 3 | 100 |  |  |  | 51 | register( scalar caller(), $name, $tc, 'exportable' ) | 
| 277 |  |  |  |  |  |  | if defined $name; | 
| 278 |  |  |  |  |  |  |  | 
| 279 | 3 |  |  |  |  | 11 | return $tc; | 
| 280 |  |  |  |  |  |  | } | 
| 281 |  |  |  |  |  |  |  | 
| 282 |  |  |  |  |  |  | sub union { | 
| 283 | 4 |  |  | 4 | 1 | 15 | my $name; | 
| 284 | 4 | 100 |  |  |  | 15 | $name = shift if @_ % 2; | 
| 285 | 4 |  |  |  |  | 16 | my %p = @_; | 
| 286 |  |  |  |  |  |  |  | 
| 287 | 4 |  |  |  |  | 416 | require Specio::Constraint::Union; | 
| 288 |  |  |  |  |  |  |  | 
| 289 | 4 | 100 |  |  |  | 25 | my $tc = _make_tc( | 
| 290 |  |  |  |  |  |  | ( defined $name ? ( name => $name ) : () ), | 
| 291 |  |  |  |  |  |  | %p, | 
| 292 |  |  |  |  |  |  | type_class => 'Specio::Constraint::Union', | 
| 293 |  |  |  |  |  |  | ); | 
| 294 |  |  |  |  |  |  |  | 
| 295 | 4 | 100 |  |  |  | 37 | register( scalar caller(), $name, $tc, 'exportable' ) | 
| 296 |  |  |  |  |  |  | if defined $name; | 
| 297 |  |  |  |  |  |  |  | 
| 298 | 4 |  |  |  |  | 12 | return $tc; | 
| 299 |  |  |  |  |  |  | } | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | sub _make_tc { | 
| 302 | 844 |  |  | 844 |  | 2056 | my %p = @_; | 
| 303 |  |  |  |  |  |  |  | 
| 304 | 844 |  | 100 |  |  | 2354 | my $class = delete $p{type_class} || 'Specio::Constraint::Simple'; | 
| 305 |  |  |  |  |  |  |  | 
| 306 | 844 | 100 |  |  |  | 1627 | $p{constraint}        = delete $p{where}   if exists $p{where}; | 
| 307 | 844 | 50 |  |  |  | 1471 | $p{message_generator} = delete $p{message} if exists $p{message}; | 
| 308 | 844 | 100 |  |  |  | 1706 | $p{inline_generator}  = delete $p{inline}  if exists $p{inline}; | 
| 309 |  |  |  |  |  |  |  | 
| 310 | 844 |  |  |  |  | 3001 | return $class->new( | 
| 311 |  |  |  |  |  |  | %p, | 
| 312 |  |  |  |  |  |  | declared_at => Specio::DeclaredAt->new_from_caller(2), | 
| 313 |  |  |  |  |  |  | ); | 
| 314 |  |  |  |  |  |  | } | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | sub coerce { | 
| 317 | 16 |  |  | 16 | 1 | 25 | my $to = shift; | 
| 318 | 16 |  |  |  |  | 48 | my %p  = @_; | 
| 319 |  |  |  |  |  |  |  | 
| 320 | 16 | 100 |  |  |  | 48 | $p{coercion}         = delete $p{using}  if exists $p{using}; | 
| 321 | 16 | 100 |  |  |  | 41 | $p{inline_generator} = delete $p{inline} if exists $p{inline}; | 
| 322 |  |  |  |  |  |  |  | 
| 323 | 16 |  |  |  |  | 88 | return $to->add_coercion( | 
| 324 |  |  |  |  |  |  | Specio::Coercion->new( | 
| 325 |  |  |  |  |  |  | to => $to, | 
| 326 |  |  |  |  |  |  | %p, | 
| 327 |  |  |  |  |  |  | declared_at => Specio::DeclaredAt->new_from_caller(1), | 
| 328 |  |  |  |  |  |  | ) | 
| 329 |  |  |  |  |  |  | ); | 
| 330 |  |  |  |  |  |  | } | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | 1; | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | # ABSTRACT: Specio declaration subroutines | 
| 335 |  |  |  |  |  |  |  | 
| 336 |  |  |  |  |  |  | __END__ | 
| 337 |  |  |  |  |  |  |  | 
| 338 |  |  |  |  |  |  | =pod | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | =encoding UTF-8 | 
| 341 |  |  |  |  |  |  |  | 
| 342 |  |  |  |  |  |  | =head1 NAME | 
| 343 |  |  |  |  |  |  |  | 
| 344 |  |  |  |  |  |  | Specio::Declare - Specio declaration subroutines | 
| 345 |  |  |  |  |  |  |  | 
| 346 |  |  |  |  |  |  | =head1 VERSION | 
| 347 |  |  |  |  |  |  |  | 
| 348 |  |  |  |  |  |  | version 0.46 | 
| 349 |  |  |  |  |  |  |  | 
| 350 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 351 |  |  |  |  |  |  |  | 
| 352 |  |  |  |  |  |  | package MyApp::Type::Library; | 
| 353 |  |  |  |  |  |  |  | 
| 354 |  |  |  |  |  |  | use parent 'Specio::Exporter'; | 
| 355 |  |  |  |  |  |  |  | 
| 356 |  |  |  |  |  |  | use Specio::Declare; | 
| 357 |  |  |  |  |  |  | use Specio::Library::Builtins; | 
| 358 |  |  |  |  |  |  |  | 
| 359 |  |  |  |  |  |  | declare( | 
| 360 |  |  |  |  |  |  | 'Foo', | 
| 361 |  |  |  |  |  |  | parent => t('Str'), | 
| 362 |  |  |  |  |  |  | where  => sub { $_[0] =~ /foo/i }, | 
| 363 |  |  |  |  |  |  | ); | 
| 364 |  |  |  |  |  |  |  | 
| 365 |  |  |  |  |  |  | declare( | 
| 366 |  |  |  |  |  |  | 'ArrayRefOfInt', | 
| 367 |  |  |  |  |  |  | parent => t( 'ArrayRef', of => t('Int') ), | 
| 368 |  |  |  |  |  |  | ); | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  | my $even = anon( | 
| 371 |  |  |  |  |  |  | parent => t('Int'), | 
| 372 |  |  |  |  |  |  | inline => sub { | 
| 373 |  |  |  |  |  |  | my $type      = shift; | 
| 374 |  |  |  |  |  |  | my $value_var = shift; | 
| 375 |  |  |  |  |  |  |  | 
| 376 |  |  |  |  |  |  | return $value_var . ' % 2 == 0'; | 
| 377 |  |  |  |  |  |  | }, | 
| 378 |  |  |  |  |  |  | ); | 
| 379 |  |  |  |  |  |  |  | 
| 380 |  |  |  |  |  |  | coerce( | 
| 381 |  |  |  |  |  |  | t('ArrayRef'), | 
| 382 |  |  |  |  |  |  | from  => t('Foo'), | 
| 383 |  |  |  |  |  |  | using => sub { [ $_[0] ] }, | 
| 384 |  |  |  |  |  |  | ); | 
| 385 |  |  |  |  |  |  |  | 
| 386 |  |  |  |  |  |  | coerce( | 
| 387 |  |  |  |  |  |  | $even, | 
| 388 |  |  |  |  |  |  | from  => t('Int'), | 
| 389 |  |  |  |  |  |  | using => sub { $_[0] % 2 ? $_[0] + 1 : $_[0] }, | 
| 390 |  |  |  |  |  |  | ); | 
| 391 |  |  |  |  |  |  |  | 
| 392 |  |  |  |  |  |  | # Specio name is DateTime | 
| 393 |  |  |  |  |  |  | any_isa_type('DateTime'); | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | # Specio name is DateTimeObject | 
| 396 |  |  |  |  |  |  | object_isa_type( 'DateTimeObject', class => 'DateTime' ); | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | any_can_type( | 
| 399 |  |  |  |  |  |  | 'Duck', | 
| 400 |  |  |  |  |  |  | methods => [ 'duck_walk', 'quack' ], | 
| 401 |  |  |  |  |  |  | ); | 
| 402 |  |  |  |  |  |  |  | 
| 403 |  |  |  |  |  |  | object_can_type( | 
| 404 |  |  |  |  |  |  | 'DuckObject', | 
| 405 |  |  |  |  |  |  | methods => [ 'duck_walk', 'quack' ], | 
| 406 |  |  |  |  |  |  | ); | 
| 407 |  |  |  |  |  |  |  | 
| 408 |  |  |  |  |  |  | enum( | 
| 409 |  |  |  |  |  |  | 'Colors', | 
| 410 |  |  |  |  |  |  | values => [qw( blue green red )], | 
| 411 |  |  |  |  |  |  | ); | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | intersection( | 
| 414 |  |  |  |  |  |  | 'HashRefAndArrayRef', | 
| 415 |  |  |  |  |  |  | of => [ t('HashRef'), t('ArrayRef') ], | 
| 416 |  |  |  |  |  |  | ); | 
| 417 |  |  |  |  |  |  |  | 
| 418 |  |  |  |  |  |  | union( | 
| 419 |  |  |  |  |  |  | 'IntOrArrayRef', | 
| 420 |  |  |  |  |  |  | of => [ t('Int'), t('ArrayRef') ], | 
| 421 |  |  |  |  |  |  | ); | 
| 422 |  |  |  |  |  |  |  | 
| 423 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | This package exports a set of type declaration helpers. Importing this package | 
| 426 |  |  |  |  |  |  | also causes it to create a C<t> subroutine the caller. | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | =head1 SUBROUTINES | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  | This module exports the following subroutines. | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | =head2 t('name') | 
| 433 |  |  |  |  |  |  |  | 
| 434 |  |  |  |  |  |  | This subroutine lets you access any types you have declared so far, as well as | 
| 435 |  |  |  |  |  |  | any types you imported from another type library. | 
| 436 |  |  |  |  |  |  |  | 
| 437 |  |  |  |  |  |  | If you pass an unknown name, it throws an exception. | 
| 438 |  |  |  |  |  |  |  | 
| 439 |  |  |  |  |  |  | =head2 declare(...) | 
| 440 |  |  |  |  |  |  |  | 
| 441 |  |  |  |  |  |  | This subroutine declares a named type. The first argument is the type name, | 
| 442 |  |  |  |  |  |  | followed by a set of key/value parameters: | 
| 443 |  |  |  |  |  |  |  | 
| 444 |  |  |  |  |  |  | =over 4 | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | =item * parent => $type | 
| 447 |  |  |  |  |  |  |  | 
| 448 |  |  |  |  |  |  | The parent should be another type object. Specifically, it can be anything | 
| 449 |  |  |  |  |  |  | which does the L<Specio::Constraint::Role::Interface> role. The parent can be a | 
| 450 |  |  |  |  |  |  | named or anonymous type. | 
| 451 |  |  |  |  |  |  |  | 
| 452 |  |  |  |  |  |  | =item * where => sub { ... } | 
| 453 |  |  |  |  |  |  |  | 
| 454 |  |  |  |  |  |  | This is a subroutine which defines the type constraint. It will be passed a | 
| 455 |  |  |  |  |  |  | single argument, the value to check, and it should return true or false to | 
| 456 |  |  |  |  |  |  | indicate whether or not the value is valid for the type. | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  | This parameter is mutually exclusive with the C<inline> parameter. | 
| 459 |  |  |  |  |  |  |  | 
| 460 |  |  |  |  |  |  | =item * inline => sub { ... } | 
| 461 |  |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  | This is a subroutine that is called to generate inline code to validate the | 
| 463 |  |  |  |  |  |  | type. Inlining can be I<much> faster than simply providing a subroutine with | 
| 464 |  |  |  |  |  |  | the C<where> parameter, but is often more complicated to get right. | 
| 465 |  |  |  |  |  |  |  | 
| 466 |  |  |  |  |  |  | The inline generator is called as a method on the type with one argument. This | 
| 467 |  |  |  |  |  |  | argument is a I<string> containing the variable name to use in the generated | 
| 468 |  |  |  |  |  |  | code. Typically this is something like C<'$_[0]'> or C<'$value'>. | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | The inline generator subroutine should return a I<string> of code representing | 
| 471 |  |  |  |  |  |  | a single term, and it I<should not> be terminated with a semicolon. This | 
| 472 |  |  |  |  |  |  | allows the inlined code to be safely included in an C<if> statement, for | 
| 473 |  |  |  |  |  |  | example. You can use C<do { }> blocks and ternaries to get everything into one | 
| 474 |  |  |  |  |  |  | term. Do not assign to the variable you are testing. This single term should | 
| 475 |  |  |  |  |  |  | evaluate to true or false. | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | The inline generator is expected to include code to implement both the current | 
| 478 |  |  |  |  |  |  | type and all its parents. Typically, the easiest way to do this is to write a | 
| 479 |  |  |  |  |  |  | subroutine something like this: | 
| 480 |  |  |  |  |  |  |  | 
| 481 |  |  |  |  |  |  | sub { | 
| 482 |  |  |  |  |  |  | my $self = shift; | 
| 483 |  |  |  |  |  |  | my $var  = shift; | 
| 484 |  |  |  |  |  |  |  | 
| 485 |  |  |  |  |  |  | return $self->parent->inline_check($var) | 
| 486 |  |  |  |  |  |  | . ' and more checking code goes here'; | 
| 487 |  |  |  |  |  |  | } | 
| 488 |  |  |  |  |  |  |  | 
| 489 |  |  |  |  |  |  | Or, more concisely: | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | sub { $_[0]->parent->inline_check( $_[1] ) . 'more code that checks $_[1]' } | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  | The C<inline> parameter is mutually exclusive with the C<where> parameter. | 
| 494 |  |  |  |  |  |  |  | 
| 495 |  |  |  |  |  |  | =item * message_generator => sub { ... } | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  | A subroutine to generate an error message when the type check fails. The | 
| 498 |  |  |  |  |  |  | default message says something like "Validation failed for type named Int | 
| 499 |  |  |  |  |  |  | declared in package Specio::Library::Builtins | 
| 500 |  |  |  |  |  |  | (.../Specio/blib/lib/Specio/Library/Builtins.pm) at line 147 in sub named (eval) | 
| 501 |  |  |  |  |  |  | with value 1.1". | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | You can override this to provide something more specific about the way the | 
| 504 |  |  |  |  |  |  | type failed. | 
| 505 |  |  |  |  |  |  |  | 
| 506 |  |  |  |  |  |  | The subroutine you provide will be called as a method on the type with two | 
| 507 |  |  |  |  |  |  | arguments. The first is the description of the type (the bit in the message | 
| 508 |  |  |  |  |  |  | above that starts with "type named Int ..." and ends with "... in sub named | 
| 509 |  |  |  |  |  |  | (eval)". This description says what the thing is and where it was defined. | 
| 510 |  |  |  |  |  |  |  | 
| 511 |  |  |  |  |  |  | The second argument is the value that failed the type check, after any | 
| 512 |  |  |  |  |  |  | coercions that might have been applied. | 
| 513 |  |  |  |  |  |  |  | 
| 514 |  |  |  |  |  |  | =back | 
| 515 |  |  |  |  |  |  |  | 
| 516 |  |  |  |  |  |  | =head2 anon(...) | 
| 517 |  |  |  |  |  |  |  | 
| 518 |  |  |  |  |  |  | This subroutine declares an anonymous type. It is identical to C<declare> | 
| 519 |  |  |  |  |  |  | except that it expects a list of key/value parameters without a type name as | 
| 520 |  |  |  |  |  |  | the first parameter. | 
| 521 |  |  |  |  |  |  |  | 
| 522 |  |  |  |  |  |  | =head2 coerce(...) | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  | This declares a coercion from one type to another. The first argument should | 
| 525 |  |  |  |  |  |  | be an object which does the L<Specio::Constraint::Role::Interface> role. This | 
| 526 |  |  |  |  |  |  | can be either a named or anonymous type. This type is the type that the | 
| 527 |  |  |  |  |  |  | coercion is I<to>. | 
| 528 |  |  |  |  |  |  |  | 
| 529 |  |  |  |  |  |  | The remaining arguments are key/value parameters: | 
| 530 |  |  |  |  |  |  |  | 
| 531 |  |  |  |  |  |  | =over 4 | 
| 532 |  |  |  |  |  |  |  | 
| 533 |  |  |  |  |  |  | =item * from => $type | 
| 534 |  |  |  |  |  |  |  | 
| 535 |  |  |  |  |  |  | This must be an object which does the L<Specio::Constraint::Role::Interface> | 
| 536 |  |  |  |  |  |  | role. This is type that we are coercing I<from>. Again, this can be either a | 
| 537 |  |  |  |  |  |  | named or anonymous type. | 
| 538 |  |  |  |  |  |  |  | 
| 539 |  |  |  |  |  |  | =item * using => sub { ... } | 
| 540 |  |  |  |  |  |  |  | 
| 541 |  |  |  |  |  |  | This is a subroutine which defines the type coercion. It will be passed a | 
| 542 |  |  |  |  |  |  | single argument, the value to coerce. It should return a new value of the type | 
| 543 |  |  |  |  |  |  | this coercion is to. | 
| 544 |  |  |  |  |  |  |  | 
| 545 |  |  |  |  |  |  | This parameter is mutually exclusive with the C<inline> parameter. | 
| 546 |  |  |  |  |  |  |  | 
| 547 |  |  |  |  |  |  | =item * inline => sub { ... } | 
| 548 |  |  |  |  |  |  |  | 
| 549 |  |  |  |  |  |  | This is a subroutine that is called to generate inline code to perform the | 
| 550 |  |  |  |  |  |  | coercion. | 
| 551 |  |  |  |  |  |  |  | 
| 552 |  |  |  |  |  |  | The inline generator is called as a method on the type with one argument. This | 
| 553 |  |  |  |  |  |  | argument is a I<string> containing the variable name to use in the generated | 
| 554 |  |  |  |  |  |  | code. Typically this is something like C<'$_[0]'> or C<'$value'>. | 
| 555 |  |  |  |  |  |  |  | 
| 556 |  |  |  |  |  |  | The inline generator subroutine should return a I<string> of code representing | 
| 557 |  |  |  |  |  |  | a single term, and it I<should not> be terminated with a semicolon. This | 
| 558 |  |  |  |  |  |  | allows the inlined code to be safely included in an C<if> statement, for | 
| 559 |  |  |  |  |  |  | example. You can use C<do { }> blocks and ternaries to get everything into one | 
| 560 |  |  |  |  |  |  | term. This single term should evaluate to the new value. | 
| 561 |  |  |  |  |  |  |  | 
| 562 |  |  |  |  |  |  | =back | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  | =head1 DECLARATION HELPERS | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | This module also exports some helper subs for declaring certain kinds of types: | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | =head2 any_isa_type, object_isa_type | 
| 569 |  |  |  |  |  |  |  | 
| 570 |  |  |  |  |  |  | The C<any_isa_type> helper creates a type which accepts a class name or | 
| 571 |  |  |  |  |  |  | object of the given class. The C<object_isa_type> helper creates a type | 
| 572 |  |  |  |  |  |  | which only accepts an object of the given class. | 
| 573 |  |  |  |  |  |  |  | 
| 574 |  |  |  |  |  |  | These subroutines take a type name as the first argument. The remaining | 
| 575 |  |  |  |  |  |  | arguments are key/value pairs. Currently this is just the C<class> key, which | 
| 576 |  |  |  |  |  |  | should be a class name. This is the class that the type requires. | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | The type name argument can be omitted to create an anonymous type. | 
| 579 |  |  |  |  |  |  |  | 
| 580 |  |  |  |  |  |  | You can also pass just a single argument, in which case that will be used as | 
| 581 |  |  |  |  |  |  | both the type's name and the class for the constraint to check. | 
| 582 |  |  |  |  |  |  |  | 
| 583 |  |  |  |  |  |  | =head2 any_does_type, object_does_type | 
| 584 |  |  |  |  |  |  |  | 
| 585 |  |  |  |  |  |  | The C<any_does_type> helper creates a type which accepts a class name or | 
| 586 |  |  |  |  |  |  | object which does the given role. The C<object_does_type> helper creates a | 
| 587 |  |  |  |  |  |  | type which only accepts an object which does the given role. | 
| 588 |  |  |  |  |  |  |  | 
| 589 |  |  |  |  |  |  | These subroutines take a type name as the first argument. The remaining | 
| 590 |  |  |  |  |  |  | arguments are key/value pairs. Currently this is just the C<role> key, which | 
| 591 |  |  |  |  |  |  | should be a role name. This is the class that the type requires. | 
| 592 |  |  |  |  |  |  |  | 
| 593 |  |  |  |  |  |  | This should just work (I hope) with roles created by L<Moose>, L<Mouse>, and | 
| 594 |  |  |  |  |  |  | L<Moo> (using L<Role::Tiny>). | 
| 595 |  |  |  |  |  |  |  | 
| 596 |  |  |  |  |  |  | The type name argument can be omitted to create an anonymous type. | 
| 597 |  |  |  |  |  |  |  | 
| 598 |  |  |  |  |  |  | You can also pass just a single argument, in which case that will be used as | 
| 599 |  |  |  |  |  |  | both the type's name and the role for the constraint to check. | 
| 600 |  |  |  |  |  |  |  | 
| 601 |  |  |  |  |  |  | =head2 any_can_type, object_can_type | 
| 602 |  |  |  |  |  |  |  | 
| 603 |  |  |  |  |  |  | The C<any_can_type> helper creates a type which accepts a class name or | 
| 604 |  |  |  |  |  |  | object with the given methods. The C<object_can_type> helper creates a type | 
| 605 |  |  |  |  |  |  | which only accepts an object with the given methods. | 
| 606 |  |  |  |  |  |  |  | 
| 607 |  |  |  |  |  |  | These subroutines take a type name as the first argument. The remaining | 
| 608 |  |  |  |  |  |  | arguments are key/value pairs. Currently this is just the C<methods> key, | 
| 609 |  |  |  |  |  |  | which can be either a string or array reference of strings. These strings are | 
| 610 |  |  |  |  |  |  | the required methods for the type. | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  | The type name argument can be omitted to create an anonymous type. | 
| 613 |  |  |  |  |  |  |  | 
| 614 |  |  |  |  |  |  | =head2 enum | 
| 615 |  |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  | This creates a type which accepts a string matching a given list of acceptable | 
| 617 |  |  |  |  |  |  | values. | 
| 618 |  |  |  |  |  |  |  | 
| 619 |  |  |  |  |  |  | The first argument is the type name. The remaining arguments are key/value | 
| 620 |  |  |  |  |  |  | pairs. Currently this is just the C<values> key. This should an array | 
| 621 |  |  |  |  |  |  | reference of acceptable string values. | 
| 622 |  |  |  |  |  |  |  | 
| 623 |  |  |  |  |  |  | The type name argument can be omitted to create an anonymous type. | 
| 624 |  |  |  |  |  |  |  | 
| 625 |  |  |  |  |  |  | =head2 intersection | 
| 626 |  |  |  |  |  |  |  | 
| 627 |  |  |  |  |  |  | This creates a type which is the intersection of two or more other types. A | 
| 628 |  |  |  |  |  |  | union only accepts values which match all of its underlying types. | 
| 629 |  |  |  |  |  |  |  | 
| 630 |  |  |  |  |  |  | The first argument is the type name. The remaining arguments are key/value | 
| 631 |  |  |  |  |  |  | pairs. Currently this is just the C<of> key. This should an array | 
| 632 |  |  |  |  |  |  | reference of types. | 
| 633 |  |  |  |  |  |  |  | 
| 634 |  |  |  |  |  |  | The type name argument can be omitted to create an anonymous type. | 
| 635 |  |  |  |  |  |  |  | 
| 636 |  |  |  |  |  |  | =head2 union | 
| 637 |  |  |  |  |  |  |  | 
| 638 |  |  |  |  |  |  | This creates a type which is the union of two or more other types. A union | 
| 639 |  |  |  |  |  |  | accepts any of its underlying types. | 
| 640 |  |  |  |  |  |  |  | 
| 641 |  |  |  |  |  |  | The first argument is the type name. The remaining arguments are key/value | 
| 642 |  |  |  |  |  |  | pairs. Currently this is just the C<of> key. This should an array | 
| 643 |  |  |  |  |  |  | reference of types. | 
| 644 |  |  |  |  |  |  |  | 
| 645 |  |  |  |  |  |  | The type name argument can be omitted to create an anonymous type. | 
| 646 |  |  |  |  |  |  |  | 
| 647 |  |  |  |  |  |  | =head1 PARAMETERIZED TYPES | 
| 648 |  |  |  |  |  |  |  | 
| 649 |  |  |  |  |  |  | You can create a parameterized type by calling C<t> with additional | 
| 650 |  |  |  |  |  |  | parameters, like this: | 
| 651 |  |  |  |  |  |  |  | 
| 652 |  |  |  |  |  |  | my $arrayref_of_int = t( 'ArrayRef', of => t('Int') ); | 
| 653 |  |  |  |  |  |  |  | 
| 654 |  |  |  |  |  |  | my $arrayref_of_hashref_of_int = t( | 
| 655 |  |  |  |  |  |  | 'ArrayRef', | 
| 656 |  |  |  |  |  |  | of => t( | 
| 657 |  |  |  |  |  |  | 'HashRef', | 
| 658 |  |  |  |  |  |  | of => t('Int'), | 
| 659 |  |  |  |  |  |  | ), | 
| 660 |  |  |  |  |  |  | ); | 
| 661 |  |  |  |  |  |  |  | 
| 662 |  |  |  |  |  |  | The C<t> subroutine assumes that if it receives more than one argument, it | 
| 663 |  |  |  |  |  |  | should look up the named type and call C<< $type->parameterize(...) >> with | 
| 664 |  |  |  |  |  |  | the additional arguments. | 
| 665 |  |  |  |  |  |  |  | 
| 666 |  |  |  |  |  |  | If the named type cannot be parameterized, it throws an error. | 
| 667 |  |  |  |  |  |  |  | 
| 668 |  |  |  |  |  |  | You can also call C<< $type->parameterize >> directly if needed. See | 
| 669 |  |  |  |  |  |  | L<Specio::Constraint::Parameterizable> for details. | 
| 670 |  |  |  |  |  |  |  | 
| 671 |  |  |  |  |  |  | =head1 SUPPORT | 
| 672 |  |  |  |  |  |  |  | 
| 673 |  |  |  |  |  |  | Bugs may be submitted at L<https://github.com/houseabsolute/Specio/issues>. | 
| 674 |  |  |  |  |  |  |  | 
| 675 |  |  |  |  |  |  | I am also usually active on IRC as 'autarch' on C<irc://irc.perl.org>. | 
| 676 |  |  |  |  |  |  |  | 
| 677 |  |  |  |  |  |  | =head1 SOURCE | 
| 678 |  |  |  |  |  |  |  | 
| 679 |  |  |  |  |  |  | The source code repository for Specio can be found at L<https://github.com/houseabsolute/Specio>. | 
| 680 |  |  |  |  |  |  |  | 
| 681 |  |  |  |  |  |  | =head1 AUTHOR | 
| 682 |  |  |  |  |  |  |  | 
| 683 |  |  |  |  |  |  | Dave Rolsky <autarch@urth.org> | 
| 684 |  |  |  |  |  |  |  | 
| 685 |  |  |  |  |  |  | =head1 COPYRIGHT AND LICENSE | 
| 686 |  |  |  |  |  |  |  | 
| 687 |  |  |  |  |  |  | This software is Copyright (c) 2012 - 2020 by Dave Rolsky. | 
| 688 |  |  |  |  |  |  |  | 
| 689 |  |  |  |  |  |  | This is free software, licensed under: | 
| 690 |  |  |  |  |  |  |  | 
| 691 |  |  |  |  |  |  | The Artistic License 2.0 (GPL Compatible) | 
| 692 |  |  |  |  |  |  |  | 
| 693 |  |  |  |  |  |  | The full text of the license can be found in the | 
| 694 |  |  |  |  |  |  | F<LICENSE> file included with this distribution. | 
| 695 |  |  |  |  |  |  |  | 
| 696 |  |  |  |  |  |  | =cut |