getting-there
[gitmo/Moose.git] / lib / Moose / Util / TypeConstraints.pm
index f21e348..eb5524d 100644 (file)
@@ -10,12 +10,14 @@ use Scalar::Util 'blessed';
 
 our $VERSION = '0.02';
 
+use Moose::Meta::TypeConstraint;
+
 sub import {
        shift;
        my $pkg = shift || caller();
        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)) {
                *{"${pkg}::${export}"} = \&{"${export}"};
        }       
 }
@@ -29,28 +31,39 @@ sub import {
 
     sub register_type_constraint { 
         my ($type_name, $type_constraint) = @_;
-        $TYPES{$type_name} = $type_constraint;
+        (not exists $TYPES{$type_name})
+            || confess "The type constraint '$type_name' has already been registered";
+        $TYPES{$type_name} = Moose::Meta::TypeConstraint->new(
+            name            => $type_name,
+            constraint_code => $type_constraint
+        );
+    }
+    
+    sub dump_type_constraints {
+        require Data::Dumper;
+        $Data::Dumper::Deparse = 1;
+        Data::Dumper::Dumper(\%TYPES);
     }
     
     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}->constraint_code;
        }        
     }
-}
 
-{
-    my %COERCIONS;
     sub find_type_coercion { 
         my $type_name = shift;
-        $COERCIONS{$type_name}; 
+        $TYPES{$type_name}->coercion_code; 
     }
 
     sub register_type_coercion { 
         my ($type_name, $type_coercion) = @_;
-        $COERCIONS{$type_name} = $type_coercion;
+        my $type = $TYPES{$type_name};
+        (!$type->has_coercion)
+            || confess "The type coercion for '$type_name' has already been registered";        
+        $type->set_coercion_code($type_coercion);
     }
 }
 
@@ -59,7 +72,6 @@ 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];
@@ -70,10 +82,9 @@ sub subtype ($$;$) {
        my ($name, $parent, $check) = @_;
        if (defined $check) {
            my $full_name = caller() . "::${name}";
-               $parent = find_type_constraint($parent) 
+               $parent = find_type_constraint($parent)->constraint_code 
                    unless $parent && ref($parent) eq 'CODE';
-               register_type_constraint($name => subname $full_name => sub { 
-                       return find_type_constraint($name) unless defined $_[0];                        
+               register_type_constraint($name => subname $full_name => sub {                   
                        local $_ = $_[0];
                        return undef unless defined $parent->($_[0]) && $check->($_[0]);
                        $_[0];
@@ -81,7 +92,7 @@ sub subtype ($$;$) {
        }
        else {
                ($parent, $check) = ($name, $parent);
-               $parent = find_type_constraint($parent) 
+               $parent = find_type_constraint($parent)->constraint_code 
                    unless $parent && ref($parent) eq 'CODE';           
                return subname '__anon_subtype__' => sub {                      
                        local $_ = $_[0];
@@ -91,12 +102,14 @@ sub subtype ($$;$) {
        }
 }
 
-sub coerce {
+sub coerce ($@) {
     my ($type_name, @coercion_map) = @_;
+    #use Data::Dumper;
+    #warn Dumper \@coercion_map;    
     my @coercions;
     while (@coercion_map) {
         my ($constraint_name, $action) = splice(@coercion_map, 0, 2);
-        my $constraint = find_type_constraint($constraint_name);
+        my $constraint = find_type_constraint($constraint_name)->constraint_code;
         (defined $constraint)
             || confess "Could not find the type constraint ($constraint_name)";
         push @coercions => [  $constraint, $action ];
@@ -106,6 +119,7 @@ sub coerce {
         foreach my $coercion (@coercions) {
             my ($constraint, $converter) = @$coercion;
             if (defined $constraint->($thing)) {
+                           local $_ = $thing;                
                 return $converter->($thing);
             }
         }
@@ -114,8 +128,9 @@ sub coerce {
 }
 
 sub as    ($) { $_[0] }
+sub from  ($) { $_[0] }
 sub where (&) { $_[0] }
-sub to    (&) { $_[0] }
+sub via   (&) { $_[0] }
 
 # define some basic types
 
@@ -160,6 +175,10 @@ Moose::Util::TypeConstraints - Type constraint system for Moose
   subtype NaturalLessThanTen 
       => as Natural
       => where { $_ < 10 };
+      
+  coerce Num 
+      => from Str
+        => via { 0+$_ }; 
 
 =head1 DESCRIPTION
 
@@ -169,10 +188,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.
 
@@ -206,6 +221,8 @@ Suggestions for improvement are welcome.
 
 =item B<export_type_contstraints_as_functions>
 
+=item B<dump_type_constraints>
+
 =back
 
 =head2 Type Constraint Constructors
@@ -222,7 +239,9 @@ Suggestions for improvement are welcome.
 
 =item B<coerce>
 
-=item B<to>
+=item B<from>
+
+=item B<via>
 
 =back