removed the Data::Dump debugging code
[gitmo/MooseX-Types.git] / lib / MooseX / Types.pm
index eb443bf..4a39855 100644 (file)
@@ -7,9 +7,6 @@ MooseX::Types - Organise your Moose types in libraries
 
 =cut
 
-#use warnings;
-#use strict;
-
 use Moose::Util::TypeConstraints;
 use MooseX::Types::TypeDecorator;
 use MooseX::Types::Base             ();
@@ -19,8 +16,8 @@ use Carp::Clan                      qw( ^MooseX::Types );
 
 use namespace::clean -except => [qw( meta )];
 
-our $VERSION = 0.05;
-
+use 5.008;
+our $VERSION = 0.10;
 my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'};
 
 =head1 SYNOPSIS
@@ -31,12 +28,16 @@ my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'};
 
   # predeclare our own types
   use MooseX::Types 
-      -declare => [qw( PositiveInt NegativeInt )];
+    -declare => [qw(
+        PositiveInt NegativeInt
+        ArrayRefOfPositiveInt ArrayRefOfAtLeastThreeNegativeInts
+        LotsOfInnerConstraints StrOrArrayRef
+    )];
 
   # import builtin types
   use MooseX::Types::Moose 'Int';
 
-  # type definition
+  # type definition.
   subtype PositiveInt, 
       as Int, 
       where { $_ > 0 },
@@ -52,6 +53,23 @@ my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'};
       from Int,
           via { 1 };
 
+  # with parameterized constraints.
+  
+  subtype ArrayRefOfPositiveInt,
+    as ArrayRef[PositiveInt];
+    
+  subtype ArrayRefOfAtLeastThreeNegativeInts,
+    as ArrayRef[NegativeInt],
+    where { scalar(@$_) > 2 };
+
+  subtype LotsOfInnerConstraints,
+    as ArrayRef[ArrayRef[HashRef[Int]]];
+    
+  # with TypeConstraint Unions
+  
+  subtype StrOrArrayRef,
+    as Str|ArrayRef;
+
   1;
 
 =head2 Usage
@@ -242,7 +260,38 @@ The fully qualified name of this type as L<Moose> knows it.
 A message that will be thrown when type functionality is used but the
 type does not yet exist.
 
-=back
+=head1 RECURSIVE SUBTYPES
+
+As of version 0.08, L<Moose::Types> has experimental support for Recursive
+subtypes.  This will allow:
+
+    subtype Tree() => as HashRef[Str|Tree];
+
+Which validates things like:
+
+    {key=>'value'};
+    {key=>{subkey1=>'value', subkey2=>'value'}}
+    
+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
+
+L<MooseX::Types> uses L<MooseX::Types::TypeDecorator> to do some overloading
+which generally allows you to easily create union types:
+
+  subtype StrOrArrayRef,
+    as Str|ArrayRef;    
+
+As with parameterized constrains, this overloading extends to modules using the
+types you define in a type library.
+
+    use Moose;
+    use MooseX::Types::Moose qw(HashRef Int);
+    
+    has 'attr' => (isa=>HashRef|Int);
+
+And everything should just work as you'd think.
 
 =head1 METHODS
 
@@ -301,16 +350,79 @@ yet defined.
 =cut
 
 sub type_export_generator {
-    my ($class, $type, $full) = @_;
+    my ($class, $type, $name) = @_;
+    
+    ## Return an anonymous subroutine that will generate the proxied type
+    ## constraint for you.
+    
     return sub {
-        my @args = @_;
-        use Data::Dump qw/dump/; warn @args;
-        my $type_constraint = find_type_constraint($full)
-         || MooseX::Types::UndefinedType->new($full);
-        return MooseX::Types::TypeDecorator->new(type_constraint=>$type_constraint);
+        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 {
+                croak 'Arguments must be an ArrayRef, not '. ref $params;
+            }
+        } else {
+            $type_constraint = $class->create_base_type_constraint($name);
+        }
+
+        $type_constraint = defined($type_constraint) ? $type_constraint
+         : MooseX::Types::UndefinedType->new($name);
+         
+        my $type_decorator = $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 and parameterize
+it with @args.
+
+=cut
+
+sub create_arged_type_constraint {
+    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)
+
+Given a String $name, find the matching typeconstraint.
+
+=cut
+
+sub create_base_type_constraint {
+    my ($class, $name) = @_;
+    return find_type_constraint($name);
+}
+
+=head2 create_type_decorator ($type_constraint)
+
+Given a $type_constraint, return a lightweight L<MooseX::Types::TypeDecorator>
+instance.
+
+=cut
+
+sub create_type_decorator {
+    my ($class, $type_constraint) = @_;
+    return MooseX::Types::TypeDecorator->new($type_constraint);
+}
+
 =head2 coercion_export_generator
 
 This generates a coercion handler function, e.g. C<to_Int($value)>. 
@@ -353,11 +465,72 @@ sub check_export_generator {
 
 =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>, 
@@ -370,6 +543,8 @@ L<Sub::Exporter>
 Robert 'phaylon' Sedlacek C<E<lt>rs@474.atE<gt>>, with many thanks to
 the C<#moose> cabal on C<irc.perl.org>.
 
+Additional features by John Napiorkowski (jnapiorkowski) <jjnapiork@cpan.org>.
+
 =head1 LICENSE
 
 This program is free software; you can redistribute it and/or modify