21:09 < Sartak> no_plan is the worst
[gitmo/Moose.git] / lib / Moose / Util / TypeConstraints.pm
CommitLineData
a15dff8d 1
2package Moose::Util::TypeConstraints;
3
4use strict;
5use warnings;
6
998a8a25 7use Carp ();
9e856c83 8use List::MoreUtils qw( all any );
9a63faba 9use Scalar::Util qw( blessed reftype );
e606ae5f 10use Moose::Exporter;
a15dff8d 11
180899ed 12our $VERSION = '0.73';
e606ae5f 13$VERSION = eval $VERSION;
d44714be 14our $AUTHORITY = 'cpan:STEVAN';
a15dff8d 15
d9b40005 16## --------------------------------------------------------
e85d2a5d 17# Prototyped subs must be predeclared because we have a
18# circular dependency with Moose::Meta::Attribute et. al.
19# so in case of us being use'd first the predeclaration
d9b40005 20# ensures the prototypes are in scope when consumers are
21# compiled.
22
d9b40005 23# dah sugah!
180899ed 24sub where (&);
25sub via (&);
26sub message (&);
d9b40005 27sub optimize_as (&);
d9b40005 28
d9b40005 29## --------------------------------------------------------
8c4acc60 30
4e036ee4 31use Moose::Meta::TypeConstraint;
3726f905 32use Moose::Meta::TypeConstraint::Union;
0fbd4b0a 33use Moose::Meta::TypeConstraint::Parameterized;
7e4e1ad4 34use Moose::Meta::TypeConstraint::Parameterizable;
620db045 35use Moose::Meta::TypeConstraint::Class;
36use Moose::Meta::TypeConstraint::Role;
dabed765 37use Moose::Meta::TypeConstraint::Enum;
2ca63f5d 38use Moose::Meta::TypeCoercion;
3726f905 39use Moose::Meta::TypeCoercion::Union;
22aed3c0 40use Moose::Meta::TypeConstraint::Registry;
28ffb449 41use Moose::Util::TypeConstraints::OptimizedConstraints;
4e036ee4 42
e606ae5f 43Moose::Exporter->setup_import_methods(
44 as_is => [
45 qw(
180899ed 46 type subtype class_type role_type maybe_type duck_type
1b2c9bda 47 as where message optimize_as
e606ae5f 48 coerce from via
49 enum
50 find_type_constraint
51 register_type_constraint )
52 ],
53 _export_to_main => 1,
54);
a15dff8d 55
d9b40005 56## --------------------------------------------------------
57## type registry and some useful functions for it
58## --------------------------------------------------------
59
22aed3c0 60my $REGISTRY = Moose::Meta::TypeConstraint::Registry->new;
587ae0d2 61
180899ed 62sub get_type_constraint_registry {$REGISTRY}
63sub list_all_type_constraints { keys %{ $REGISTRY->type_constraints } }
64
d9b40005 65sub export_type_constraints_as_functions {
66 my $pkg = caller();
67 no strict 'refs';
180899ed 68 foreach my $constraint ( keys %{ $REGISTRY->type_constraints } ) {
69 my $tc = $REGISTRY->get_type_constraint($constraint)
70 ->_compiled_type_constraint;
71 *{"${pkg}::${constraint}"}
72 = sub { $tc->( $_[0] ) ? 1 : undef }; # the undef is for compat
a0f8153d 73 }
d9b40005 74}
182134e8 75
0c015f1b 76sub create_type_constraint_union {
d9b40005 77 my @type_constraint_names;
e85d2a5d 78
180899ed 79 if ( scalar @_ == 1 && _detect_type_constraint_union( $_[0] ) ) {
80 @type_constraint_names = _parse_type_constraint_union( $_[0] );
d9b40005 81 }
82 else {
83 @type_constraint_names = @_;
429ccc11 84 }
180899ed 85
86 ( scalar @type_constraint_names >= 2 )
87 || __PACKAGE__->_throw_error(
88 "You must pass in at least 2 type names to make a union");
e85d2a5d 89
84a9c64c 90 my @type_constraints = map {
180899ed 91 find_or_parse_type_constraint($_)
92 || __PACKAGE__->_throw_error(
93 "Could not locate type constraint ($_) for the union");
08380fdb 94 } @type_constraint_names;
84a9c64c 95
3726f905 96 return Moose::Meta::TypeConstraint::Union->new(
180899ed 97 type_constraints => \@type_constraints );
182134e8 98}
a15dff8d 99
0c015f1b 100sub create_parameterized_type_constraint {
d9b40005 101 my $type_constraint_name = shift;
180899ed 102 my ( $base_type, $type_parameter )
103 = _parse_parameterized_type_constraint($type_constraint_name);
e85d2a5d 104
180899ed 105 ( defined $base_type && defined $type_parameter )
106 || __PACKAGE__->_throw_error(
107 "Could not parse type name ($type_constraint_name) correctly");
e85d2a5d 108
180899ed 109 if ( $REGISTRY->has_type_constraint($base_type) ) {
90e78884 110 my $base_type_tc = $REGISTRY->get_type_constraint($base_type);
111 return _create_parameterized_type_constraint(
112 $base_type_tc,
113 $type_parameter
114 );
180899ed 115 }
116 else {
117 __PACKAGE__->_throw_error(
118 "Could not locate the base type ($base_type)");
90e78884 119 }
22aed3c0 120}
121
90e78884 122sub _create_parameterized_type_constraint {
123 my ( $base_type_tc, $type_parameter ) = @_;
124 if ( $base_type_tc->can('parameterize') ) {
125 return $base_type_tc->parameterize($type_parameter);
180899ed 126 }
127 else {
90e78884 128 return Moose::Meta::TypeConstraint::Parameterized->new(
180899ed 129 name => $base_type_tc->name . '[' . $type_parameter . ']',
90e78884 130 parent => $base_type_tc,
180899ed 131 type_parameter =>
132 find_or_create_isa_type_constraint($type_parameter),
90e78884 133 );
134 }
180899ed 135}
90e78884 136
4ab662d6 137#should we also support optimized checks?
0c015f1b 138sub create_class_type_constraint {
620db045 139 my ( $class, $options ) = @_;
140
180899ed 141# too early for this check
142#find_type_constraint("ClassName")->check($class)
143# || __PACKAGE__->_throw_error("Can't create a class type constraint because '$class' is not a class name");
3fef8ce8 144
620db045 145 my %options = (
146 class => $class,
147 name => $class,
148 %{ $options || {} },
4ab662d6 149 );
620db045 150
151 $options{name} ||= "__ANON__";
152
180899ed 153 Moose::Meta::TypeConstraint::Class->new(%options);
3fef8ce8 154}
155
0c015f1b 156sub create_role_type_constraint {
620db045 157 my ( $role, $options ) = @_;
e85d2a5d 158
180899ed 159# too early for this check
160#find_type_constraint("ClassName")->check($class)
161# || __PACKAGE__->_throw_error("Can't create a class type constraint because '$class' is not a class name");
e85d2a5d 162
620db045 163 my %options = (
164 role => $role,
165 name => $role,
166 %{ $options || {} },
167 );
e85d2a5d 168
620db045 169 $options{name} ||= "__ANON__";
170
180899ed 171 Moose::Meta::TypeConstraint::Role->new(%options);
620db045 172}
173
0c015f1b 174sub find_or_create_type_constraint {
620db045 175 my ( $type_constraint_name, $options_for_anon_type ) = @_;
176
180899ed 177 if ( my $constraint
178 = find_or_parse_type_constraint($type_constraint_name) ) {
620db045 179 return $constraint;
d9b40005 180 }
620db045 181 elsif ( defined $options_for_anon_type ) {
180899ed 182
d9b40005 183 # NOTE:
4ab662d6 184 # if there is no $options_for_anon_type
185 # specified, then we assume they don't
f3c4e20e 186 # want to create one, and return nothing.
f3c4e20e 187
d9b40005 188 # otherwise assume that we should create
e85d2a5d 189 # an ANON type with the $options_for_anon_type
d9b40005 190 # options which can be passed in. It should
e85d2a5d 191 # be noted that these don't get registered
d9b40005 192 # so we need to return it.
193 # - SL
194 return Moose::Meta::TypeConstraint->new(
195 name => '__ANON__',
e85d2a5d 196 %{$options_for_anon_type}
d9b40005 197 );
198 }
e85d2a5d 199
620db045 200 return;
201}
202
0c015f1b 203sub find_or_create_isa_type_constraint {
620db045 204 my $type_constraint_name = shift;
180899ed 205 find_or_parse_type_constraint($type_constraint_name)
206 || create_class_type_constraint($type_constraint_name);
620db045 207}
208
0c015f1b 209sub find_or_create_does_type_constraint {
620db045 210 my $type_constraint_name = shift;
180899ed 211 find_or_parse_type_constraint($type_constraint_name)
212 || create_role_type_constraint($type_constraint_name);
620db045 213}
214
0c015f1b 215sub find_or_parse_type_constraint {
eb4c4e82 216 my $type_constraint_name = normalize_type_constraint_name(shift);
620db045 217 my $constraint;
180899ed 218
219 if ( $constraint = find_type_constraint($type_constraint_name) ) {
e606ae5f 220 return $constraint;
180899ed 221 }
222 elsif ( _detect_type_constraint_union($type_constraint_name) ) {
620db045 223 $constraint = create_type_constraint_union($type_constraint_name);
180899ed 224 }
225 elsif ( _detect_parameterized_type_constraint($type_constraint_name) ) {
226 $constraint
227 = create_parameterized_type_constraint($type_constraint_name);
228 }
229 else {
620db045 230 return;
231 }
bb6c8335 232
d9b40005 233 $REGISTRY->add_type_constraint($constraint);
e85d2a5d 234 return $constraint;
d9b40005 235}
22aed3c0 236
eb4c4e82 237sub normalize_type_constraint_name {
84a9c64c 238 my $type_constraint_name = shift;
c8f663b2 239 $type_constraint_name =~ s/\s//g;
eb4c4e82 240 return $type_constraint_name;
241}
242
5f223879 243sub _confess {
244 my $error = shift;
245
246 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
247 Carp::confess($error);
248}
249
22aed3c0 250## --------------------------------------------------------
251## exported functions ...
252## --------------------------------------------------------
253
0c015f1b 254sub find_type_constraint {
eeedfc8a 255 my $type = shift;
256
257 if ( blessed $type and $type->isa("Moose::Meta::TypeConstraint") ) {
258 return $type;
e606ae5f 259 }
260 else {
261 return unless $REGISTRY->has_type_constraint($type);
eeedfc8a 262 return $REGISTRY->get_type_constraint($type);
263 }
264}
22aed3c0 265
0c015f1b 266sub register_type_constraint {
3fef8ce8 267 my $constraint = shift;
180899ed 268 __PACKAGE__->_throw_error("can't register an unnamed type constraint")
269 unless defined $constraint->name;
3fef8ce8 270 $REGISTRY->add_type_constraint($constraint);
dabed765 271 return $constraint;
3fef8ce8 272}
273
7c13858b 274# type constructors
a15dff8d 275
9c27968f 276sub type {
180899ed 277
9e856c83 278 # back-compat version, called without sugar
180899ed 279 if ( !any { ( reftype($_) || '' ) eq 'HASH' } @_ ) {
9e856c83 280 return _create_type_constraint( $_[0], undef, $_[1] );
9a63faba 281 }
9a63faba 282
9e856c83 283 my $name = shift;
9a63faba 284
9e856c83 285 my %p = map { %{$_} } @_;
286
180899ed 287 return _create_type_constraint(
288 $name, undef, $p{where}, $p{message},
289 $p{optimize_as}
290 );
a15dff8d 291}
292
9c27968f 293sub subtype {
180899ed 294
9a63faba 295 # crazy back-compat code for being called without sugar ...
e3979c3e 296 #
9a63faba 297 # subtype 'Parent', sub { where };
298 if ( scalar @_ == 2 && ( reftype( $_[1] ) || '' ) eq 'CODE' ) {
299 return _create_type_constraint( undef, @_ );
300 }
301
302 # subtype 'Parent', sub { where }, sub { message };
303 # subtype 'Parent', sub { where }, sub { message }, sub { optimized };
304 if ( scalar @_ >= 3 && all { ( reftype($_) || '' ) eq 'CODE' }
180899ed 305 @_[ 1 .. $#_ ] ) {
9a63faba 306 return _create_type_constraint( undef, @_ );
307 }
308
309 # subtype 'Name', 'Parent', ...
310 if ( scalar @_ >= 2 && all { !ref } @_[ 0, 1 ] ) {
311 return _create_type_constraint(@_);
312 }
313
180899ed 314 if ( @_ == 1 && !ref $_[0] ) {
315 __PACKAGE__->_throw_error(
316 'A subtype cannot consist solely of a name, it must have a parent'
317 );
f75f625d 318 }
319
f6c0c589 320 # The blessed check is mostly to accommodate MooseX::Types, which
321 # uses an object which overloads stringification as a type name.
180899ed 322 my $name = ref $_[0] && !blessed $_[0] ? undef : shift;
9a63faba 323
324 my %p = map { %{$_} } @_;
325
326 # subtype Str => where { ... };
180899ed 327 if ( !exists $p{as} ) {
9e856c83 328 $p{as} = $name;
9a63faba 329 $name = undef;
330 }
331
180899ed 332 return _create_type_constraint(
333 $name, $p{as}, $p{where}, $p{message},
334 $p{optimize_as}
335 );
a15dff8d 336}
337
9c27968f 338sub class_type {
4ab662d6 339 register_type_constraint(
340 create_class_type_constraint(
341 $_[0],
180899ed 342 ( defined( $_[1] ) ? $_[1] : () ),
4ab662d6 343 )
344 );
3fef8ce8 345}
346
620db045 347sub role_type ($;$) {
348 register_type_constraint(
349 create_role_type_constraint(
350 $_[0],
180899ed 351 ( defined( $_[1] ) ? $_[1] : () ),
620db045 352 )
353 );
354}
355
1b2c9bda 356sub maybe_type {
357 my ($type_parameter) = @_;
358
28ce1444 359 register_type_constraint(
ed7060d9 360 $REGISTRY->get_type_constraint('Maybe')->parameterize($type_parameter)
28ce1444 361 );
1b2c9bda 362}
363
180899ed 364sub duck_type {
365 my ($type_name, @methods) = @_;
366 if ( ref $type_name eq 'ARRAY' && !@methods ) {
367 @methods = @$type_name;
368 $type_name = undef;
369 }
370
371 register_type_constraint(
372 _create_type_constraint(
373 $type_name, 'Object',
374 sub {
375 my $obj = $_;
376 my @missing_methods = grep { !$obj->can($_) } @methods;
377 return ! scalar @missing_methods;
378 },
379 sub {
380 my $obj = $_;
381 my @missing_methods = grep { !$obj->can($_) } @methods;
382 return
383 "${\blessed($obj)} is missing methods '@missing_methods'";
384 },
385 )
386 );
387}
388
9c27968f 389sub coerce {
180899ed 390 my ( $type_name, @coercion_map ) = @_;
391 _install_type_coercions( $type_name, \@coercion_map );
182134e8 392}
393
f6c0c589 394# The trick of returning @_ lets us avoid having to specify a
395# prototype. Perl will parse this:
396#
397# subtype 'Foo'
398# => as 'Str'
399# => where { ... }
400#
401# as this:
402#
403# subtype( 'Foo', as( 'Str', where { ... } ) );
404#
405# If as() returns all it's extra arguments, this just works, and
406# preserves backwards compatibility.
180899ed 407sub as { { as => shift }, @_ }
9e856c83 408sub where (&) { { where => $_[0] } }
409sub message (&) { { message => $_[0] } }
410sub optimize_as (&) { { optimize_as => $_[0] } }
8ecb1fa0 411
9a63faba 412sub from {@_}
413sub via (&) { $_[0] }
a15dff8d 414
9c27968f 415sub enum {
180899ed 416 my ( $type_name, @values ) = @_;
417
4ab662d6 418 # NOTE:
419 # if only an array-ref is passed then
9f4334a1 420 # you get an anon-enum
421 # - SL
180899ed 422 if ( ref $type_name eq 'ARRAY' && !@values ) {
9f4334a1 423 @values = @$type_name;
424 $type_name = undef;
425 }
180899ed 426 ( scalar @values >= 2 )
427 || __PACKAGE__->_throw_error(
428 "You must have at least two values to enumerate through");
c4fe165f 429 my %valid = map { $_ => 1 } @values;
dabed765 430
431 register_type_constraint(
432 create_enum_type_constraint(
433 $type_name,
434 \@values,
435 )
436 );
437}
438
0c015f1b 439sub create_enum_type_constraint {
dabed765 440 my ( $type_name, $values ) = @_;
e606ae5f 441
dabed765 442 Moose::Meta::TypeConstraint::Enum->new(
180899ed 443 name => $type_name || '__ANON__',
dabed765 444 values => $values,
a0f8153d 445 );
fcec2383 446}
447
d9b40005 448## --------------------------------------------------------
449## desugaring functions ...
450## --------------------------------------------------------
451
e85d2a5d 452sub _create_type_constraint ($$$;$$) {
9a63faba 453 my $name = shift;
454 my $parent = shift;
455 my $check = shift;
456 my $message = shift;
457 my $optimized = shift;
d9b40005 458
9a63faba 459 my $pkg_defined_in = scalar( caller(1) );
e85d2a5d 460
1da6728b 461 if ( defined $name ) {
d9b40005 462 my $type = $REGISTRY->get_type_constraint($name);
e85d2a5d 463
5f223879 464 ( $type->_package_defined_in eq $pkg_defined_in )
465 || _confess(
466 "The type constraint '$name' has already been created in "
467 . $type->_package_defined_in
468 . " and cannot be created again in "
469 . $pkg_defined_in )
470 if defined $type;
eee1a213 471
472 $name =~ /^[\w:\.]+$/
473 or die qq{$name contains invalid characters for a type name.}
33c8a6d0 474 . qq{ Names can contain alphanumeric character, ":", and "."\n};
e85d2a5d 475 }
1da6728b 476
9ceb576e 477 my %opts = (
9a63faba 478 name => $name,
d9b40005 479 package_defined_in => $pkg_defined_in,
e85d2a5d 480
1da6728b 481 ( $check ? ( constraint => $check ) : () ),
482 ( $message ? ( message => $message ) : () ),
483 ( $optimized ? ( optimized => $optimized ) : () ),
d9b40005 484 );
1da6728b 485
9ceb576e 486 my $constraint;
180899ed 487 if (
488 defined $parent
1da6728b 489 and $parent
180899ed 490 = blessed $parent
491 ? $parent
492 : find_or_create_isa_type_constraint($parent)
493 ) {
85a9908f 494 $constraint = $parent->create_child_type(%opts);
1da6728b 495 }
496 else {
497 $constraint = Moose::Meta::TypeConstraint->new(%opts);
4ab662d6 498 }
d9b40005 499
500 $REGISTRY->add_type_constraint($constraint)
501 if defined $name;
502
503 return $constraint;
504}
505
e85d2a5d 506sub _install_type_coercions ($$) {
180899ed 507 my ( $type_name, $coercion_map ) = @_;
e606ae5f 508 my $type = find_type_constraint($type_name);
180899ed 509 ( defined $type )
510 || __PACKAGE__->_throw_error(
511 "Cannot find type '$type_name', perhaps you forgot to load it.");
512 if ( $type->has_coercion ) {
41e007e4 513 $type->coercion->add_type_coercions(@$coercion_map);
514 }
515 else {
516 my $type_coercion = Moose::Meta::TypeCoercion->new(
517 type_coercion_map => $coercion_map,
518 type_constraint => $type
519 );
520 $type->coercion($type_coercion);
521 }
d9b40005 522}
523
524## --------------------------------------------------------
f1917f58 525## type notation parsing ...
526## --------------------------------------------------------
527
528{
180899ed 529
e85d2a5d 530 # All I have to say is mugwump++ cause I know
531 # do not even have enough regexp-fu to be able
532 # to have written this (I can only barely
f1917f58 533 # understand it as it is)
e85d2a5d 534 # - SL
535
f1917f58 536 use re "eval";
537
eee1a213 538 my $valid_chars = qr{[\w:\.]};
f1917f58 539 my $type_atom = qr{ $valid_chars+ };
540
be722745 541 my $any;
542
180899ed 543 my $type = qr{ $valid_chars+ (?: \[ \s* (??{$any}) \s* \] )? }x;
544 my $type_capture_parts
545 = qr{ ($valid_chars+) (?: \[ \s* ((??{$any})) \s* \] )? }x;
546 my $type_with_parameter
547 = qr{ $valid_chars+ \[ \s* (??{$any}) \s* \] }x;
f1917f58 548
3796382a 549 my $op_union = qr{ \s* \| \s* }x;
f1917f58 550 my $union = qr{ $type (?: $op_union $type )+ }x;
551
84a9c64c 552 $any = qr{ $type | $union }x;
f1917f58 553
0fbd4b0a 554 sub _parse_parameterized_type_constraint {
180899ed 555 { no warnings 'void'; $any; } # force capture of interpolated lexical
84a9c64c 556 $_[0] =~ m{ $type_capture_parts }x;
180899ed 557 return ( $1, $2 );
f1917f58 558 }
559
0fbd4b0a 560 sub _detect_parameterized_type_constraint {
180899ed 561 { no warnings 'void'; $any; } # force capture of interpolated lexical
e85d2a5d 562 $_[0] =~ m{ ^ $type_with_parameter $ }x;
f1917f58 563 }
564
565 sub _parse_type_constraint_union {
180899ed 566 { no warnings 'void'; $any; } # force capture of interpolated lexical
e85d2a5d 567 my $given = shift;
568 my @rv;
569 while ( $given =~ m{ \G (?: $op_union )? ($type) }gcx ) {
82a5b1a7 570 push @rv => $1;
e85d2a5d 571 }
180899ed 572 ( pos($given) eq length($given) )
573 || __PACKAGE__->_throw_error( "'$given' didn't parse (parse-pos="
574 . pos($given)
575 . " and str-length="
576 . length($given)
577 . ")" );
e85d2a5d 578 @rv;
f1917f58 579 }
580
581 sub _detect_type_constraint_union {
180899ed 582 { no warnings 'void'; $any; } # force capture of interpolated lexical
e85d2a5d 583 $_[0] =~ m{^ $type $op_union $type ( $op_union .* )? $}x;
f1917f58 584 }
585}
586
587## --------------------------------------------------------
d9b40005 588# define some basic built-in types
589## --------------------------------------------------------
a15dff8d 590
3cae4250 591# By making these classes immutable before creating all the types we
592# below, we avoid repeatedly calling the slow MOP-based accessors.
593$_->make_immutable(
594 inline_constructor => 1,
595 constructor_name => "_new",
596
597 # these are Class::MOP accessors, so they need inlining
598 inline_accessors => 1
599 ) for grep { $_->is_mutable }
600 map { $_->meta }
601 qw(
602 Moose::Meta::TypeConstraint
603 Moose::Meta::TypeConstraint::Union
604 Moose::Meta::TypeConstraint::Parameterized
605 Moose::Meta::TypeConstraint::Parameterizable
606 Moose::Meta::TypeConstraint::Class
607 Moose::Meta::TypeConstraint::Role
608 Moose::Meta::TypeConstraint::Enum
609 Moose::Meta::TypeConstraint::Registry
610);
611
180899ed 612type 'Any' => where {1}; # meta-type including all
613type 'Item' => where {1}; # base-type
a15dff8d 614
fd542f49 615subtype 'Undef' => as 'Item' => where { !defined($_) };
180899ed 616subtype 'Defined' => as 'Item' => where { defined($_) };
617
618subtype 'Bool' => as 'Item' =>
619 where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' };
620
621subtype 'Value' => as 'Defined' => where { !ref($_) } =>
622 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Value;
623
624subtype 'Ref' => as 'Defined' => where { ref($_) } =>
625 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Ref;
626
627subtype 'Str' => as 'Value' => where {1} =>
628 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Str;
629
630subtype 'Num' => as 'Value' =>
631 where { Scalar::Util::looks_like_number($_) } =>
632 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Num;
633
634subtype 'Int' => as 'Num' => where { "$_" =~ /^-?[0-9]+$/ } =>
635 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Int;
636
637subtype 'ScalarRef' => as 'Ref' => where { ref($_) eq 'SCALAR' } =>
638 optimize_as
639 \&Moose::Util::TypeConstraints::OptimizedConstraints::ScalarRef;
640subtype 'CodeRef' => as 'Ref' => where { ref($_) eq 'CODE' } =>
641 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::CodeRef;
642subtype 'RegexpRef' => as 'Ref' => where { ref($_) eq 'Regexp' } =>
643 optimize_as
644 \&Moose::Util::TypeConstraints::OptimizedConstraints::RegexpRef;
645subtype 'GlobRef' => as 'Ref' => where { ref($_) eq 'GLOB' } =>
646 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::GlobRef;
a15dff8d 647
0a5bd159 648# NOTE:
e85d2a5d 649# scalar filehandles are GLOB refs,
0a5bd159 650# but a GLOB ref is not always a filehandle
180899ed 651subtype 'FileHandle' => as 'GlobRef' => where {
652 Scalar::Util::openhandle($_) || ( blessed($_) && $_->isa("IO::Handle") );
653} => optimize_as
654 \&Moose::Util::TypeConstraints::OptimizedConstraints::FileHandle;
0a5bd159 655
e85d2a5d 656# NOTE:
a15dff8d 657# blessed(qr/.../) returns true,.. how odd
180899ed 658subtype 'Object' => as 'Ref' =>
659 where { blessed($_) && blessed($_) ne 'Regexp' } =>
660 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Object;
a15dff8d 661
180899ed 662subtype 'Role' => as 'Object' => where { $_->can('does') } =>
663 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Role;
e85d2a5d 664
180899ed 665my $_class_name_checker = sub { };
0e0709ea 666
180899ed 667subtype 'ClassName' => as 'Str' =>
668 where { Class::MOP::is_class_loaded($_) } => optimize_as
669 \&Moose::Util::TypeConstraints::OptimizedConstraints::ClassName;
02a0fb52 670
180899ed 671subtype 'RoleName' => as 'ClassName' => where {
672 ( ( $_->can('meta') || return )->($_) || return )
673 ->isa('Moose::Meta::Role');
674} => optimize_as
675 \&Moose::Util::TypeConstraints::OptimizedConstraints::RoleName;
f0cac16f 676
d9b40005 677## --------------------------------------------------------
7e4e1ad4 678# parameterizable types ...
679
680$REGISTRY->add_type_constraint(
681 Moose::Meta::TypeConstraint::Parameterizable->new(
180899ed 682 name => 'ArrayRef',
683 package_defined_in => __PACKAGE__,
684 parent => find_type_constraint('Ref'),
685 constraint => sub { ref($_) eq 'ARRAY' },
686 optimized =>
687 \&Moose::Util::TypeConstraints::OptimizedConstraints::ArrayRef,
7e4e1ad4 688 constraint_generator => sub {
689 my $type_parameter = shift;
180899ed 690 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 691 return sub {
692 foreach my $x (@$_) {
180899ed 693 ( $check->($x) ) || return;
694 }
695 1;
696 }
7e4e1ad4 697 }
698 )
699);
700
701$REGISTRY->add_type_constraint(
702 Moose::Meta::TypeConstraint::Parameterizable->new(
180899ed 703 name => 'HashRef',
704 package_defined_in => __PACKAGE__,
705 parent => find_type_constraint('Ref'),
706 constraint => sub { ref($_) eq 'HASH' },
707 optimized =>
708 \&Moose::Util::TypeConstraints::OptimizedConstraints::HashRef,
7e4e1ad4 709 constraint_generator => sub {
4ab662d6 710 my $type_parameter = shift;
180899ed 711 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 712 return sub {
180899ed 713 foreach my $x ( values %$_ ) {
714 ( $check->($x) ) || return;
715 }
716 1;
717 }
7e4e1ad4 718 }
719 )
720);
721
722$REGISTRY->add_type_constraint(
723 Moose::Meta::TypeConstraint::Parameterizable->new(
724 name => 'Maybe',
725 package_defined_in => __PACKAGE__,
726 parent => find_type_constraint('Item'),
180899ed 727 constraint => sub {1},
7e4e1ad4 728 constraint_generator => sub {
4ab662d6 729 my $type_parameter = shift;
180899ed 730 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 731 return sub {
180899ed 732 return 1 if not( defined($_) ) || $check->($_);
7e4e1ad4 733 return;
180899ed 734 }
7e4e1ad4 735 }
736 )
737);
738
180899ed 739my @PARAMETERIZABLE_TYPES
740 = map { $REGISTRY->get_type_constraint($_) } qw[ArrayRef HashRef Maybe];
741
742sub get_all_parameterizable_types {@PARAMETERIZABLE_TYPES}
7e4e1ad4 743
4ab662d6 744sub add_parameterizable_type {
7e4e1ad4 745 my $type = shift;
180899ed 746 ( blessed $type
747 && $type->isa('Moose::Meta::TypeConstraint::Parameterizable') )
748 || __PACKAGE__->_throw_error(
749 "Type must be a Moose::Meta::TypeConstraint::Parameterizable not $type"
750 );
7e4e1ad4 751 push @PARAMETERIZABLE_TYPES => $type;
4ab662d6 752}
7e4e1ad4 753
754## --------------------------------------------------------
d9b40005 755# end of built-in types ...
756## --------------------------------------------------------
757
943596a6 758{
759 my @BUILTINS = list_all_type_constraints();
180899ed 760 sub list_all_builtin_type_constraints {@BUILTINS}
943596a6 761}
762
6ea98933 763sub _throw_error {
6b83828f 764 shift;
6ea98933 765 require Moose;
766 unshift @_, 'Moose';
767 goto &Moose::throw_error;
768}
769
a15dff8d 7701;
771
772__END__
773
774=pod
775
776=head1 NAME
777
e522431d 778Moose::Util::TypeConstraints - Type constraint system for Moose
a15dff8d 779
780=head1 SYNOPSIS
781
782 use Moose::Util::TypeConstraints;
783
e85d2a5d 784 subtype 'Natural'
e606ae5f 785 => as 'Int'
a15dff8d 786 => where { $_ > 0 };
e85d2a5d 787
788 subtype 'NaturalLessThanTen'
2c0cbef7 789 => as 'Natural'
79592a54 790 => where { $_ < 10 }
791 => message { "This number ($_) is not less than ten!" };
e85d2a5d 792
793 coerce 'Num'
2c0cbef7 794 => from 'Str'
e85d2a5d 795 => via { 0+$_ };
796
2c0cbef7 797 enum 'RGBColors' => qw(red green blue);
a15dff8d 798
e7fcb7b2 799 no Moose::Util::TypeConstraints;
800
a15dff8d 801=head1 DESCRIPTION
802
e85d2a5d 803This module provides Moose with the ability to create custom type
6549b0d1 804constraints to be used in attribute definition.
e522431d 805
6ba6d68c 806=head2 Important Caveat
807
e85d2a5d 808This is B<NOT> a type system for Perl 5. These are type constraints,
809and they are not used by Moose unless you tell it to. No type
e7fcb7b2 810inference is performed, expressions are not typed, etc. etc. etc.
6ba6d68c 811
e7fcb7b2 812A type constraint is at heart a small "check if a value is valid"
813function. A constraint can be associated with an attribute. This
814simplifies parameter validation, and makes your code clearer to read,
815because you can refer to constraints by name.
6ba6d68c 816
2c0cbef7 817=head2 Slightly Less Important Caveat
818
e7fcb7b2 819It is B<always> a good idea to quote your type names.
004222dc 820
e7fcb7b2 821This prevents Perl from trying to execute the call as an indirect
822object call. This can be an issue when you have a subtype with the
823same name as a valid class.
2c0cbef7 824
e7fcb7b2 825For instance:
e85d2a5d 826
2c0cbef7 827 subtype DateTime => as Object => where { $_->isa('DateTime') };
828
e7fcb7b2 829will I<just work>, while this:
2c0cbef7 830
831 use DateTime;
832 subtype DateTime => as Object => where { $_->isa('DateTime') };
833
e85d2a5d 834will fail silently and cause many headaches. The simple way to solve
835this, as well as future proof your subtypes from classes which have
e7fcb7b2 836yet to have been created, is to quote the type name:
2c0cbef7 837
838 use DateTime;
d44714be 839 subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };
2c0cbef7 840
6ba6d68c 841=head2 Default Type Constraints
e522431d 842
e606ae5f 843This module also provides a simple hierarchy for Perl 5 types, here is
004222dc 844that hierarchy represented visually.
e522431d 845
846 Any
e85d2a5d 847 Item
5a4c5493 848 Bool
7e4e1ad4 849 Maybe[`a]
f65cb534 850 Undef
851 Defined
5a4c5493 852 Value
853 Num
854 Int
855 Str
9af1d28b 856 ClassName
ed87d4fd 857 RoleName
5a4c5493 858 Ref
859 ScalarRef
7e4e1ad4 860 ArrayRef[`a]
861 HashRef[`a]
5a4c5493 862 CodeRef
863 RegexpRef
3f7376b0 864 GlobRef
0a5bd159 865 FileHandle
e85d2a5d 866 Object
2cbb5233 867 Role
e522431d 868
4ab662d6 869B<NOTE:> Any type followed by a type parameter C<[`a]> can be
7e4e1ad4 870parameterized, this means you can say:
871
757e07ef 872 ArrayRef[Int] # an array of integers
7e4e1ad4 873 HashRef[CodeRef] # a hash of str to CODE ref mappings
874 Maybe[Str] # value may be a string, may be undefined
875
4e8a0f64 876If Moose finds a name in brackets that it does not recognize as an
877existing type, it assumes that this is a class name, for example
878C<ArrayRef[DateTime]>.
879
e7fcb7b2 880B<NOTE:> Unless you parameterize a type, then it is invalid to include
881the square brackets. I.e. C<ArrayRef[]> will be treated as a new type
882name, I<not> as a parameterization of C<ArrayRef>.
e606ae5f 883
4ab662d6 884B<NOTE:> The C<Undef> type constraint for the most part works
885correctly now, but edge cases may still exist, please use it
6549b0d1 886sparingly.
703e92fb 887
7e4e1ad4 888B<NOTE:> The C<ClassName> type constraint does a complex package
e7fcb7b2 889existence check. This means that your class B<must> be loaded for this
890type constraint to pass.
9af1d28b 891
e7fcb7b2 892B<NOTE:> The C<RoleName> constraint checks a string is a I<package
893name> which is a role, like C<'MyApp::Role::Comparable'>. The C<Role>
894constraint checks that an I<object does> the named role.
ed87d4fd 895
e606ae5f 896=head2 Type Constraint Naming
004222dc 897
eee1a213 898Type name declared via this module can only contain alphanumeric
899characters, colons (:), and periods (.).
900
e606ae5f 901Since the types created by this module are global, it is suggested
902that you namespace your types just as you would namespace your
e7fcb7b2 903modules. So instead of creating a I<Color> type for your
904B<My::Graphics> module, you would call the type
905I<My::Graphics::Types::Color> instead.
004222dc 906
703e92fb 907=head2 Use with Other Constraint Modules
908
e7fcb7b2 909This module can play nicely with other constraint modules with some
910slight tweaking. The C<where> clause in types is expected to be a
911C<CODE> reference which checks it's first argument and returns a
912boolean. Since most constraint modules work in a similar way, it
913should be simple to adapt them to work with Moose.
703e92fb 914
e85d2a5d 915For instance, this is how you could use it with
916L<Declare::Constraints::Simple> to declare a completely new type.
703e92fb 917
9e856c83 918 type 'HashOfArrayOfObjects',
919 {
920 where => IsHashRef(
703e92fb 921 -keys => HasLength,
9e856c83 922 -values => IsArrayRef(IsObject)
923 )
924 };
703e92fb 925
e7fcb7b2 926For more examples see the F<t/200_examples/004_example_w_DCS.t> test
927file.
703e92fb 928
e85d2a5d 929Here is an example of using L<Test::Deep> and it's non-test
930related C<eq_deeply> function.
703e92fb 931
e85d2a5d 932 type 'ArrayOfHashOfBarsAndRandomNumbers'
703e92fb 933 => where {
e85d2a5d 934 eq_deeply($_,
703e92fb 935 array_each(subhashof({
936 bar => isa('Bar'),
937 random_number => ignore()
e85d2a5d 938 })))
703e92fb 939 };
940
e606ae5f 941For a complete example see the
e7fcb7b2 942F<t/200_examples/005_example_w_TestDeep.t> test file.
e85d2a5d 943
a15dff8d 944=head1 FUNCTIONS
945
946=head2 Type Constraint Constructors
947
e7fcb7b2 948The following functions are used to create type constraints. They
949will also register the type constraints your create in a global
950registry that is used to look types up by name.
a15dff8d 951
25f2c3fc 952See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 953
6ba6d68c 954=over 4
a15dff8d 955
9a63faba 956=item B<subtype 'Name' => as 'Parent' => where { } ...>
182134e8 957
e85d2a5d 958This creates a named subtype.
d6e2d9a1 959
dba9208a 960If you provide a parent that Moose does not recognize, it will
961automatically create a new class type constraint for this name.
962
9e856c83 963When creating a named type, the C<subtype> function should either be
964called with the sugar helpers (C<where>, C<message>, etc), or with a
965name and a hashref of parameters:
966
967 subtype( 'Foo', { where => ..., message => ... } );
968
969The valid hashref keys are C<as> (the parent), C<where>, C<message>,
970and C<optimize_as>.
9a63faba 971
972=item B<subtype as 'Parent' => where { } ...>
182134e8 973
e85d2a5d 974This creates an unnamed subtype and will return the type
975constraint meta-object, which will be an instance of
976L<Moose::Meta::TypeConstraint>.
a15dff8d 977
9e856c83 978When creating an anonymous type, the C<subtype> function should either
979be called with the sugar helpers (C<where>, C<message>, etc), or with
980just a hashref of parameters:
981
982 subtype( { where => ..., message => ... } );
983
620db045 984=item B<class_type ($class, ?$options)>
3fef8ce8 985
ed87d4fd 986Creates a new subtype of C<Object> with the name C<$class> and the
987metaclass L<Moose::Meta::TypeConstraint::Class>.
3fef8ce8 988
620db045 989=item B<role_type ($role, ?$options)>
990
ed87d4fd 991Creates a C<Role> type constraint with the name C<$role> and the
992metaclass L<Moose::Meta::TypeConstraint::Role>.
620db045 993
1b2c9bda 994=item B<maybe_type ($type)>
995
996Creates a type constraint for either C<undef> or something of the
997given type.
998
fcec2383 999=item B<enum ($name, @values)>
1000
e85d2a5d 1001This will create a basic subtype for a given set of strings.
1002The resulting constraint will be a subtype of C<Str> and
4ce56d04 1003will match any of the items in C<@values>. It is case sensitive.
1004See the L<SYNOPSIS> for a simple example.
2c0cbef7 1005
6549b0d1 1006B<NOTE:> This is not a true proper enum type, it is simply
1007a convenient constraint builder.
2c0cbef7 1008
9f4334a1 1009=item B<enum (\@values)>
1010
4ab662d6 1011If passed an ARRAY reference instead of the C<$name>, C<@values> pair,
9f4334a1 1012this will create an unnamed enum. This can then be used in an attribute
1013definition like so:
1014
1015 has 'sort_order' => (
1016 is => 'ro',
4ab662d6 1017 isa => enum([qw[ ascending descending ]]),
9f4334a1 1018 );
1019
e7fcb7b2 1020=item B<as 'Parent'>
a15dff8d 1021
6ba6d68c 1022This is just sugar for the type constraint construction syntax.
a15dff8d 1023
e7fcb7b2 1024It takes a single argument, which is the name of a parent type.
1025
1026=item B<where { ... }>
a15dff8d 1027
6ba6d68c 1028This is just sugar for the type constraint construction syntax.
76d37e5a 1029
e7fcb7b2 1030It takes a subroutine reference as an argument. When the type
1031constraint is tested, the reference is run with the value to be tested
1032in C<$_>. This reference should return true or false to indicate
1033whether or not the constraint check passed.
e606ae5f 1034
e7fcb7b2 1035=item B<message { ... }>
76d37e5a 1036
1037This is just sugar for the type constraint construction syntax.
a15dff8d 1038
e7fcb7b2 1039It takes a subroutine reference as an argument. When the type
1040constraint fails, then the code block is run with the value provided
1041in C<$_>. This reference should return a string, which will be used in
1042the text of the exception thrown.
e606ae5f 1043
e7fcb7b2 1044=item B<optimize_as { ... }>
8ecb1fa0 1045
e85d2a5d 1046This can be used to define a "hand optimized" version of your
d44714be 1047type constraint which can be used to avoid traversing a subtype
6549b0d1 1048constraint hierarchy.
d44714be 1049
e85d2a5d 1050B<NOTE:> You should only use this if you know what you are doing,
1051all the built in types use this, so your subtypes (assuming they
d44714be 1052are shallow) will not likely need to use this.
1053
e7fcb7b2 1054=item B<type 'Name' => where { } ... >
1055
1056This creates a base type, which has no parent.
1057
1058The C<type> function should either be called with the sugar helpers
1059(C<where>, C<message>, etc), or with a name and a hashref of
1060parameters:
1061
1062 type( 'Foo', { where => ..., message => ... } );
1063
1064The valid hashref keys are C<where>, C<message>, and C<optimize_as>.
1065
6ba6d68c 1066=back
a15dff8d 1067
6ba6d68c 1068=head2 Type Coercion Constructors
a15dff8d 1069
e7fcb7b2 1070You can define coercions for type constraints, which allow you to
1071automatically transform values to something valid for the type
1072constraint. If you ask your accessor to coerce, then Moose will run
1073the type-coercion code first, followed by the type constraint
1074check. This feature should be used carefully as it is very powerful
1075and could easily take off a limb if you are not careful.
a15dff8d 1076
25f2c3fc 1077See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 1078
6ba6d68c 1079=over 4
a15dff8d 1080
e7fcb7b2 1081=item B<< coerce 'Name' => from 'OtherName' => via { ... } >>
a15dff8d 1082
e7fcb7b2 1083This defines a coercion from one type to another. The C<Name> argument
1084is the type you are coercing I<to>.
1085
1086=item B<from 'OtherName'>
a15dff8d 1087
6ba6d68c 1088This is just sugar for the type coercion construction syntax.
1089
e7fcb7b2 1090It takes a single type name (or type object), which is the type being
1091coerced I<from>.
1092
1093=item B<via { ... }>
a15dff8d 1094
6ba6d68c 1095This is just sugar for the type coercion construction syntax.
a15dff8d 1096
e7fcb7b2 1097It takes a subroutine reference. This reference will be called with
1098the value to be coerced in C<$_>. It is expected to return a new value
1099of the proper type for the coercion.
1100
a15dff8d 1101=back
1102
e7fcb7b2 1103=head2 Creating and Finding Type Constraints
1104
1105These are additional functions for creating and finding type
1106constraints. Most of these functions are not available for
1107importing. The ones that are importable as specified.
004222dc 1108
1109=over 4
1110
e7fcb7b2 1111=item B<find_type_constraint($type_name)>
eb4c4e82 1112
e7fcb7b2 1113This function can be used to locate the L<Moose::Meta::TypeConstraint>
1114object for a named type.
eb4c4e82 1115
e7fcb7b2 1116This function is importable.
004222dc 1117
e7fcb7b2 1118=item B<register_type_constraint($type_object)>
004222dc 1119
e7fcb7b2 1120This function will register a L<Moose::Meta::TypeConstraint> with the
1121global type registry.
004222dc 1122
e7fcb7b2 1123This function is importable.
004222dc 1124
e7fcb7b2 1125=item B<normalize_type_constraint_name($type_constraint_name)>
004222dc 1126
e7fcb7b2 1127This method takes a type constraint name and returns the normalized
1128form. This removes any whitespace in the string.
004222dc 1129
e7fcb7b2 1130=item B<create_type_constraint_union($pipe_separated_types | @type_constraint_names)>
004222dc 1131
e7fcb7b2 1132This can take a union type specification like C<'Int|ArrayRef[Int]'>,
1133or a list of names. It returns a new
1134L<Moose::Meta::TypeConstraint::Union> object.
004222dc 1135
e7fcb7b2 1136=item B<create_parameterized_type_constraint($type_name)>
620db045 1137
e7fcb7b2 1138Given a C<$type_name> in the form of C<'BaseType[ContainerType]'>,
1139this will create a new L<Moose::Meta::TypeConstraint::Parameterized>
1140object. The C<BaseType> must exist already exist as a parameterizable
1141type.
620db045 1142
e7fcb7b2 1143=item B<create_class_type_constraint($class, $options)>
dabed765 1144
e7fcb7b2 1145Given a class name this function will create a new
1146L<Moose::Meta::TypeConstraint::Class> object for that class name.
004222dc 1147
e7fcb7b2 1148The C<$options> is a hash reference that will be passed to the
1149L<Moose::Meta::TypeConstraint::Class> constructor (as a hash).
620db045 1150
e7fcb7b2 1151=item B<create_role_type_constraint($role, $options)>
620db045 1152
e7fcb7b2 1153Given a role name this function will create a new
1154L<Moose::Meta::TypeConstraint::Role> object for that role name.
620db045 1155
e7fcb7b2 1156The C<$options> is a hash reference that will be passed to the
1157L<Moose::Meta::TypeConstraint::Role> constructor (as a hash).
620db045 1158
8a6c8c47 1159=item B<create_enum_type_constraint($name, $values)>
1160
1161Given a enum name this function will create a new
1162L<Moose::Meta::TypeConstraint::Enum> object for that enum name.
1163
e7fcb7b2 1164=item B<find_or_parse_type_constraint($type_name)>
620db045 1165
ec4b72d2 1166Given a type name, this first attempts to find a matching constraint
e7fcb7b2 1167in the global registry.
620db045 1168
e7fcb7b2 1169If the type name is a union or parameterized type, it will create a
1170new object of the appropriate, but if given a "regular" type that does
1171not yet exist, it simply returns false.
620db045 1172
e7fcb7b2 1173When given a union or parameterized type, the member or base type must
1174already exist.
620db045 1175
e7fcb7b2 1176If it creates a new union or parameterized type, it will add it to the
1177global registry.
004222dc 1178
e7fcb7b2 1179=item B<find_or_create_isa_type_constraint($type_name)>
004222dc 1180
e7fcb7b2 1181=item B<find_or_create_does_type_constraint($type_name)>
004222dc 1182
e7fcb7b2 1183These functions will first call C<find_or_parse_type_constraint>. If
1184that function does not return a type, a new anonymous type object will
1185be created.
004222dc 1186
e7fcb7b2 1187The C<isa> variant will use C<create_class_type_constraint> and the
1188C<does> variant will use C<create_role_type_constraint>.
004222dc 1189
1190=item B<get_type_constraint_registry>
1191
e7fcb7b2 1192Returns the L<Moose::Meta::TypeConstraint::Registry> object which
004222dc 1193keeps track of all type constraints.
1194
1195=item B<list_all_type_constraints>
1196
e7fcb7b2 1197This will return a list of type constraint names in the global
1198registry. You can then fetch the actual type object using
1199C<find_type_constraint($type_name)>.
004222dc 1200
1201=item B<list_all_builtin_type_constraints>
1202
e7fcb7b2 1203This will return a list of builtin type constraints, meaning those
1204which are defined in this module. See the L<Default Type Constraints>
1205section for a complete list.
004222dc 1206
1207=item B<export_type_constraints_as_functions>
1208
e7fcb7b2 1209This will export all the current type constraints as functions into
1210the caller's namespace (C<Int()>, C<Str()>, etc). Right now, this is
1211mostly used for testing, but it might prove useful to others.
004222dc 1212
1213=item B<get_all_parameterizable_types>
1214
e7fcb7b2 1215This returns all the parameterizable types that have been registered,
1216as a list of type objects.
004222dc 1217
e7fcb7b2 1218=item B<add_parameterizable_type($type)>
004222dc 1219
1220Adds C<$type> to the list of parameterizable types
1221
1222=back
1223
a15dff8d 1224=head1 BUGS
1225
e85d2a5d 1226All complex software has bugs lurking in it, and this module is no
a15dff8d 1227exception. If you find a bug please either email me, or add the bug
1228to cpan-RT.
1229
a15dff8d 1230=head1 AUTHOR
1231
1232Stevan Little E<lt>stevan@iinteractive.comE<gt>
1233
1234=head1 COPYRIGHT AND LICENSE
1235
2840a3b2 1236Copyright 2006-2009 by Infinity Interactive, Inc.
a15dff8d 1237
1238L<http://www.iinteractive.com>
1239
1240This library is free software; you can redistribute it and/or modify
e85d2a5d 1241it under the same terms as Perl itself.
a15dff8d 1242
81dc201f 1243=cut