more-tweaks
[gitmo/Moose.git] / lib / Moose / Util / TypeConstraints.pm
index 3e6a854..b70c870 100644 (file)
@@ -4,102 +4,85 @@ package Moose::Util::TypeConstraints;
 use strict;
 use warnings;
 
-use Sub::Name    'subname';
+use Carp         'confess';
 use Scalar::Util 'blessed';
 
 our $VERSION = '0.02';
 
+use Moose::Meta::TypeConstraint;
+use Moose::Meta::TypeCoercion;
+
 sub import {
        shift;
        my $pkg = shift || caller();
-       return if $pkg eq ':no_export';
+       return if $pkg eq '-no-export';
        no strict 'refs';
-       foreach my $export (qw(type subtype coerce as where to)) {
+       foreach my $export (qw(type subtype as where coerce from via find_type_constraint)) {
                *{"${pkg}::${export}"} = \&{"${export}"};
        }       
 }
 
 {
     my %TYPES;
-    sub find_type_constraint { 
-        my $type_name = shift;
-        $TYPES{$type_name}; 
+    sub find_type_constraint { $TYPES{$_[0]} }
+
+    sub _create_type_constraint { 
+        my ($name, $parent, $check) = @_;
+        (!exists $TYPES{$name})
+            || confess "The type constraint '$name' has already been created"
+                if defined $name;
+        $parent = $TYPES{$parent} if defined $parent;
+        my $constraint = Moose::Meta::TypeConstraint->new(
+            name       => $name || '__ANON__',
+            parent     => $parent,            
+            constraint => $check,           
+        );
+        $TYPES{$name} = $constraint if defined $name;
+        return $constraint;
     }
 
-    sub register_type_constraint { 
-        my ($type_name, $type_constraint) = @_;
-        $TYPES{$type_name} = $type_constraint;
+    sub _install_type_coercions { 
+        my ($type_name, $coercion_map) = @_;
+        my $type = $TYPES{$type_name};
+        (!$type->has_coercion)
+            || confess "The type coercion for '$type_name' has already been registered";        
+        my $type_coercion = Moose::Meta::TypeCoercion->new(
+            type_coercion_map => $coercion_map,
+            type_constraint   => $type
+        );            
+        $type->coercion($type_coercion);
     }
     
     sub export_type_contstraints_as_functions {
         my $pkg = caller();
            no strict 'refs';
        foreach my $constraint (keys %TYPES) {
-               *{"${pkg}::${constraint}"} = $TYPES{$constraint};
+               *{"${pkg}::${constraint}"} = $TYPES{$constraint}->_compiled_type_constraint;
        }        
-    }
-}
-
-{
-    my %COERCIONS;
-    sub find_type_coercion { 
-        my $type_name = shift;
-        $COERCIONS{$type_name}; 
-    }
-
-    sub register_type_coercion { 
-        my ($type_name, $type_coercion) = @_;
-        $COERCIONS{$type_name} = $type_coercion;
-    }
+    }    
 }
 
+# type constructors
 
 sub type ($$) {
        my ($name, $check) = @_;
-       my $full_name = caller() . "::${name}";
-       register_type_constraint($name => subname $full_name => sub { 
-               return find_type_constraint($name) unless defined $_[0];
-               local $_ = $_[0];
-               return undef unless $check->($_[0]);
-               $_[0];
-       });
+       _create_type_constraint($name, undef, $check);
 }
 
 sub subtype ($$;$) {
-       my ($name, $parent, $check) = @_;
-       if (defined $check) {
-           my $full_name = caller() . "::${name}";
-               $parent = find_type_constraint($parent) 
-                   unless $parent && ref($parent) eq 'CODE';
-               register_type_constraint($name => subname $full_name => sub { 
-                       return find_type_constraint($name) unless defined $_[0];                        
-                       local $_ = $_[0];
-                       return undef unless defined $parent->($_[0]) && $check->($_[0]);
-                       $_[0];
-               });     
-       }
-       else {
-               ($parent, $check) = ($name, $parent);
-               $parent = find_type_constraint($parent) 
-                   unless $parent && ref($parent) eq 'CODE';           
-               return subname '__anon_subtype__' => sub {                      
-                       local $_ = $_[0];
-                       return undef unless defined $parent->($_[0]) && $check->($_[0]);
-                       $_[0];
-               };              
-       }
+       unshift @_ => undef if scalar @_ == 2;
+       _create_type_constraint(@_);
 }
 
-sub coerce {
-    my ($type_name, %coercion_map) = @_;
-    register_type_coercion($type_name, sub { 
-        %coercion_map 
-    });
+sub coerce ($@) {
+    my ($type_name, @coercion_map) = @_;   
+    _install_type_coercions($type_name, \@coercion_map);
 }
 
 sub as    ($) { $_[0] }
+sub from  ($) { $_[0] }
 sub where (&) { $_[0] }
-sub to    (&) { $_[0] }
+sub via   (&) { $_[0] }
 
 # define some basic types
 
@@ -144,6 +127,10 @@ Moose::Util::TypeConstraints - Type constraint system for Moose
   subtype NaturalLessThanTen 
       => as Natural
       => where { $_ < 10 };
+      
+  coerce Num 
+      => from Str
+        => via { 0+$_ }; 
 
 =head1 DESCRIPTION
 
@@ -153,10 +140,6 @@ validation.
 
 This is B<NOT> a type system for Perl 5.
 
-The type and subtype constraints are basically functions which will 
-validate their first argument. If called with no arguments, they will 
-return themselves (this is syntactic sugar for Moose attributes).
-
 This module also provides a simple hierarchy for Perl 5 types, this 
 could probably use some work, but it works for me at the moment.
 
@@ -182,11 +165,9 @@ Suggestions for improvement are welcome.
 
 =item B<find_type_constraint ($type_name)>
 
-=item B<register_type_constraint ($type_name, $type_constraint)>
+=item B<_create_type_constraint ($type_name, $type_constraint)>
 
-=item B<find_type_coercion>
-
-=item B<register_type_coercion>
+=item B<_install_type_coercions>
 
 =item B<export_type_contstraints_as_functions>
 
@@ -206,7 +187,9 @@ Suggestions for improvement are welcome.
 
 =item B<coerce>
 
-=item B<to>
+=item B<from>
+
+=item B<via>
 
 =back