removed parenthesis hackage and updated docs
[gitmo/MooseX-Types.git] / lib / MooseX / Types.pm
index 44b1996..f2c60a7 100644 (file)
@@ -1,4 +1,5 @@
 package MooseX::Types;
+use Moose;
 
 =head1 NAME
 
@@ -9,18 +10,16 @@ MooseX::Types - Organise your Moose types in libraries
 #use warnings;
 #use strict;
 
-use Sub::Uplevel;
 use Moose::Util::TypeConstraints;
+use MooseX::Types::TypeDecorator;
 use MooseX::Types::Base             ();
 use MooseX::Types::Util             qw( filter_tags );
 use MooseX::Types::UndefinedType;
-use Sub::Install                    qw( install_sub );
-use Carp                            qw( croak );
-use Moose;
+use Carp::Clan                      qw( ^MooseX::Types );
 
 use namespace::clean -except => [qw( meta )];
 
-our $VERSION = 0.02;
+our $VERSION = 0.06;
 
 my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'};
 
@@ -29,11 +28,14 @@ my $UndefMsg = q{Action for type '%s' not yet defined in library '%s'};
 =head2 Library Definition
 
   package MyLibrary;
-  use strict;
 
   # 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';
@@ -54,6 +56,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
@@ -146,9 +165,12 @@ library which can export all types that come with Moose.
 You will have to define coercions for your types or your library won't
 export a L</to_$type> coercion helper for it.
 
-Note that you currently cannot define types containint C<::>, since 
+Note that you currently cannot define types containing C<::>, since 
 exporting would be a problem.
 
+You also don't need to use C<warnings> and C<strict>, since the
+definition of a library automatically exports those.
+
 =head1 LIBRARY USAGE
 
 You can import the L<"type helpers"|/"TYPE HANDLER FUNCTIONS"> of a
@@ -161,6 +183,12 @@ you want all of them, use the C<:all> tag. For example:
 MooseX::Types comes with a library of Moose' built-in types called
 L<MooseX::Types::Moose>.
 
+The exporting mechanism is, since version 0.5, implemented via a wrapper
+around L<Sub::Exporter>. This means you can do something like this:
+
+  use MyLibrary TypeA => { -as => 'MyTypeA' },
+                TypeB => { -as => 'MyTypeB' };
+
 =head1 WRAPPING A LIBRARY
 
 You can define your own wrapper subclasses to manipulate the behaviour
@@ -235,8 +263,24 @@ 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 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
 
 =head2 import
@@ -253,6 +297,10 @@ sub import {
     my ($class, %args) = @_;
     my  $callee = caller;
 
+    # everyone should want this
+    strict->import;
+    warnings->import;
+
     # inject base class into new library
     {   no strict 'refs';
         unshift @{ $callee . '::ISA' }, 'MooseX::Types::Base';
@@ -261,19 +309,19 @@ sub import {
     # generate predeclared type helpers
     if (my @orig_declare = @{ $args{ -declare } || [] }) {
         my ($tags, $declare) = filter_tags @orig_declare;
+        my @to_export;
 
         for my $type (@$declare) {
 
             croak "Cannot create a type containing '::' ($type) at the moment"
                 if $type =~ /::/;
 
+            # add type to library and remember to export
             $callee->add_type($type);
-            $callee->export_type_into(
-                $callee, $type, 
-                sprintf($UndefMsg, $type, $callee), 
-                -full => 1,
-            );
+            push @to_export, $type;
         }
+
+        $callee->import({ -full => 1, -into => $callee }, @to_export);
     }
 
     # run type constraints import
@@ -290,13 +338,66 @@ yet defined.
 =cut
 
 sub type_export_generator {
-    my ($class, $type, $full) = @_;
-    return sub { 
-        return find_type_constraint($full)
-            || MooseX::Types::UndefinedType->new($full);
+    my ($class, $type, $name) = @_;
+    return sub {
+        my $type_constraint;
+        if(defined(my $params = shift @_)) {
+            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(@_) {
+            return ($type_decorator, @_);
+        } else {
+            return $type_decorator;
+        }
     };
 }
 
+=head2 create_arged_type_constraint ($name, @args)
+
+Given a String $name with @args find the matching typeconstraint.
+
+=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)>. 
@@ -346,13 +447,18 @@ a type's actual full name.
 
 =head1 SEE ALSO
 
-L<Moose>, L<Moose::Util::TypeConstraints>, L<MooseX::Types::Moose>
+L<Moose>, 
+L<Moose::Util::TypeConstraints>, 
+L<MooseX::Types::Moose>,
+L<Sub::Exporter>
 
 =head1 AUTHOR AND COPYRIGHT
 
 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