use namespace::clean -except => [qw( meta )];
-our $VERSION = 0.06;
-
+use 5.008;
+our $VERSION = 0.09;
my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'};
=head1 SYNOPSIS
# import builtin types
use MooseX::Types::Moose 'Int';
- # type definition
+ # type definition.
subtype PositiveInt,
as Int,
where { $_ > 0 },
from Int,
via { 1 };
- # with parameterized constraints. Please note the containing '(...)'
+ # with parameterized constraints.
subtype ArrayRefOfPositiveInt,
- as (ArrayRef[PositiveInt]);
+ as ArrayRef[PositiveInt];
subtype ArrayRefOfAtLeastThreeNegativeInts,
- as (ArrayRef[NegativeInt]),
+ as ArrayRef[NegativeInt],
where { scalar(@$_) > 2 };
subtype LotsOfInnerConstraints,
- as (ArrayRef[ArrayRef[HashRef[Int]]]);
+ as ArrayRef[ArrayRef[HashRef[Int]]];
# with TypeConstraint Unions
A message that will be thrown when type functionality is used but the
type does not yet exist.
-=back
-
-=head1 NOTES REGARDING PARAMETERIZED CONSTRAINTS
-
-L<MooseX::Types> uses L<MooseX::Types::TypeDecorator> to do some overloading
-which generally allows you to easily create types with parameters such as:
+=head1 RECURSIVE SUBTYPES
- subtype ParameterType,
- as (ArrayRef[Int]);
+As of version 0.08, L<Moose::Types> has experimental support for Recursive
+subtypes. This will allow:
-However, due to an outstanding issue you will need to wrap the parameterized
-type inside parenthesis, as in the example above. Hopefully this limitation
-will be lifted in a future version of this module.
+ subtype Tree() => as HashRef[Str|Tree];
-If you are using paramterized types in the options section of an attribute
-declaration, the parenthesis are not needed:
+Which validates things like:
- use Moose;
- use MooseX::Types::Moose qw(HashRef Int);
+ {key=>'value'};
+ {key=>{subkey1=>'value', subkey2=>'value'}}
- has 'attr' => (isa=>HashRef[Str]);
+And so on. This feature is new and there may be lurking bugs so don't be afraid
+to hunt me down with patches and test cases if you have trouble.
=head1 NOTES REGARDING TYPE UNIONS
has 'attr' => (isa=>HashRef|Int);
And everything should just work as you'd think.
-
+
=head1 METHODS
=head2 import
sub type_export_generator {
my ($class, $type, $name) = @_;
+
+ ## Return an anonymous subroutine that will generate the proxied type
+ ## constraint for you.
+
return sub {
my $type_constraint;
if(defined(my $params = shift @_)) {
+ ## We currently only allow a TC to accept a single, ArrayRef
+ ## parameter, as in HashRef[Int], where [Int] is what's inside the
+ ## ArrayRef passed.
if(ref $params eq 'ARRAY') {
$type_constraint = $class->create_arged_type_constraint($name, @$params);
} else {
} else {
$type_constraint = $class->create_base_type_constraint($name);
}
+
$type_constraint = defined($type_constraint) ? $type_constraint
: MooseX::Types::UndefinedType->new($name);
- return $class->create_type_decorator($type_constraint);
+ my $type_decorator = $class->create_type_decorator($type_constraint);
- #if(@_ && wantarray) {
- # return ($class->create_type_decorator($type_constraint), @_);
- #} else {
- # return $class->create_type_decorator($type_constraint);
- #}
+ ## If there are additional args, that means it's probably stuff that
+ ## needs to be returned to the subtype. Not an ideal solution here but
+ ## doesn't seem to cause trouble.
+
+ if(@_) {
+ return ($type_decorator, @_);
+ } else {
+ return $type_decorator;
+ }
};
}
=head2 create_arged_type_constraint ($name, @args)
-Given a String $name with @args find the matching typeconstraint.
+Given a String $name with @args find the matching typeconstraint and parameterize
+it with @args.
=cut
sub create_arged_type_constraint {
- my ($class, $name, @args) = @_;
- ### This whole section is a real TODO :) Ugly hack to get the base tests working.
- my $fullname = $name."[$args[0]]";
-
- #use Data::Dump qw/dump/;
- #my $tc = Moose::Util::TypeConstraints::find_or_create_type_constraint($name);
-
- return Moose::Util::TypeConstraints::create_parameterized_type_constraint($fullname);
+ my ($class, $name, @args) = @_;
+ my $type_constraint = Moose::Util::TypeConstraints::find_or_create_type_constraint("$name");
+ return $type_constraint->parameterize(@args);
}
=head2 create_base_type_constraint ($name)
=head1 CAVEATS
+The following are lists of gotcha's and their workarounds for developers coming
+from the standard string based type constraint names
+
+=head2 Uniqueness
+
A library makes the types quasi-unique by prefixing their names with (by
default) the library package name. If you're only using the type handler
functions provided by MooseX::Types, you shouldn't ever have to use
a type's actual full name.
+=head2 Argument separation ('=>' versus ',')
+
+The Perlop manpage has this to say about the '=>' operator: "The => operator is
+a synonym for the comma, but forces any word (consisting entirely of word
+characters) to its left to be interpreted as a string (as of 5.001). This
+includes words that might otherwise be considered a constant or function call."
+
+Due to this stringification, the following will NOT work as you might think:
+
+ subtype StrOrArrayRef => as Str|ArrayRef;
+
+The 'StrOrArrayRef' will have it's stringification activated this causes the
+subtype to not be created. Since the bareword type constraints are not strings
+you really should not try to treat them that way. You will have to use the ','
+operator instead. The author's of this package realize that all the L<Moose>
+documention and examples nearly uniformly use the '=>' version of the comma
+operator and this could be an issue if you are converting code.
+
+Patches welcome for discussion.
+
+=head2 Compatibility with Sub::Exporter
+
+If you want to use L<Sub::Exporter> with a Type Library, you need to make sure
+you export all the type constraints declared AS WELL AS any additional export
+targets. For example if you do:
+
+ package TypeAndSubExporter; {
+
+ use MooseX::Types::Moose qw(Str);
+ use MooseX::Types -declare => [qw(MyStr)];
+ use Sub::Exporter -setup => { exports => [ qw(something) ] };
+
+ subtype MyStr,
+ as Str;
+
+ sub something {
+ return 1;
+ }
+
+ } 1;
+
+ package Foo; {
+ use TypeAndSubExporter qw(MyStr);
+ } 1;
+
+You'll get a '"MyStr" is not exported by the TypeAndSubExporter module' error.
+Upi can workaround by:
+
+ - use Sub::Exporter -setup => { exports => [ qw(something) ] };
+ + use Sub::Exporter -setup => { exports => [ qw(something MyStr) ] };
+
+This is a workaround and I am exploring how to make these modules work better
+together. I realize this workaround will lead a lot of duplication in your
+export declarations and will be onerous for large type libraries. Patches and
+detailed test cases welcome. See the tests directory for a start on this.
+
=head1 SEE ALSO
L<Moose>,