Make coercion work for parameterized types
Daisuke Maki [Sat, 7 Mar 2009 09:07:25 +0000 (09:07 +0000)]
lib/Mouse/Util/TypeConstraints.pm
t/043-parameterized-type.t

index e811ad5..6410243 100644 (file)
@@ -90,7 +90,13 @@ sub subtype {
     if ($TYPE{$name} && $TYPE_SOURCE{$name} ne $pkg) {
         Carp::croak "The type constraint '$name' has already been created in $TYPE_SOURCE{$name} and cannot be created again in $pkg";
     };
-    my $constraint = $conf{where} || do { $TYPE{delete $conf{as} || 'Any' } };
+    my $constraint = $conf{where} || do {
+        my $as = delete $conf{as} || 'Any';
+        if (! exists $TYPE{$as}) { # Perhaps it's a parameterized source?
+            Mouse::Meta::Attribute::_build_type_constraint($as);
+        }
+        $TYPE{$as};
+    };
     my $as         = $conf{as} || '';
 
     $TYPE_SOURCE{$name} = $pkg;
@@ -116,8 +122,14 @@ sub coerce {
         Carp::croak "A coercion action already exists for '$type'"
             if $COERCE{$name}->{$type};
 
-        Carp::croak "Could not find the type constraint ($type) to coerce from"
-            unless $TYPE{$type};
+        if (! $TYPE{$type}) {
+            # looks parameterized
+            if ($type =~ /^[^\[]+\[.+\]$/) {
+                Mouse::Meta::Attribute::_build_type_constraint($type);
+            } else {
+                Carp::croak "Could not find the type constraint ($type) to coerce from"
+            }
+        }
 
         push @{ $COERCE_KEYS{$name} }, $type;
         $COERCE{$name}->{$type} = $code;
index 7bc3edb..8c20411 100644 (file)
@@ -1,7 +1,7 @@
 #!/usr/bin/env perl
 use strict;
 use warnings;
-use Test::More tests => 7;
+use Test::More tests => 9;
 use Test::Exception;
 
 {
@@ -52,5 +52,39 @@ use Test::Exception;
     } qr/Attribute \(complex\) does not pass the type constraint because: Validation failed for 'ArrayRef\[HashRef\[Int\]\]' failed with value/, "Bad args for complex types throws an exception";
 }
 
+{
+    {
+        package Bar;
+        use Mouse;
+        use Mouse::Util::TypeConstraints;
+        
+        subtype 'Bar::List'
+            => as 'ArrayRef[HashRef]'
+        ;
+        coerce 'Bar::List'
+            => from 'ArrayRef[Str]'
+            => via {
+                [ map { +{ $_ => 1 } } @$_ ]
+            }
+        ;
+        has 'list' => (
+            is => 'ro',
+            isa => 'Bar::List',
+            coerce => 1,
+        );
+    }
+
+    lives_and {
+        my @list = ( {a => 1}, {b => 1}, {c => 1} );
+        my $bar = Bar->new(list => [ qw(a b c) ]);
+
+        is_deeply( $bar->list, \@list, "list is as expected");
+    } "coercion works";
+
+    throws_ok {
+        Bar->new(list => [ { 1 => 2 }, 2, 3 ]);
+    } qr/Attribute \(list\) does not pass the type constraint because: Validation failed for 'Bar::List' failed with value/, "Bad coercion parameter throws an error";
+}
+