Special case new to avoid unexpected exceptions on unloaded classes
Matt S Trout [Fri, 18 May 2012 21:18:07 +0000 (21:18 +0000)]
Changes
lib/MooseX/Types/TypeDecorator.pm
t/22_class_type.t

diff --git a/Changes b/Changes
index 20817e0..0005a0c 100644 (file)
--- a/Changes
+++ b/Changes
@@ -2,6 +2,8 @@ Revision history for MooseX-Types
 
 {{$NEXT}}
 
+        - Special case new to avoid unexpected exceptions on unloaded classes
+
 0.33    2012-05-18
 
         - Switch delegation order to prioritise type over class except for new
index 056eff7..16e4fe0 100644 (file)
@@ -159,8 +159,9 @@ sub DESTROY {
 
 Delegate to the decorator target, unless this is a class type, in which
 case it will try to delegate to the type object, then if that fails try
-the class. The method 'new' is special cased to go to the class first
-if present.
+the class. The method 'new' is special cased to only be permitted on
+the class; if there is no class, or it does not provide a new method,
+an exception will be thrown.
 
 =cut
 
@@ -192,9 +193,15 @@ sub _try_delegate {
     }
         
     my $inv = do {
-      if ($tc->can($method) and $method ne 'new') {
-            $tc
-        } elsif ($class && $class->can($method)) {
+        if ($method eq 'new') {
+            die "new called on type decorator for non-class-type ".$tc->name
+                unless $class;
+            die "new called on class type decorator ".$tc->name."\n"
+                ." for class ${class}\n"
+                ." which does not provide a new method - did you forget to load it?"
+                unless $class->can('new');
+            $class
+        } elsif ($class && !$tc->can($method)) {
             $class
         } else {
             $tc
index fe90fac..8df1e4c 100644 (file)
@@ -5,13 +5,24 @@ use Test::More;
 BEGIN {
   package MyTypes;
 
-  use MooseX::Types -declare => [ 'ClassyType' ];
+  use MooseX::Types -declare => [ 'ClassyType', 'NoClass' ];
 
   class_type 'ClassyClass';
 
   subtype ClassyType, as 'ClassyClass';
 
-  #class_type ClassyType, { class => 'ClassyClass' };
+  subtype NoClass, as 'Item', where { 1 };
+}
+
+BEGIN {
+
+  ok(!eval { MyTypes::ClassyType->new }, 'new without class loaded explodes');
+
+  like($@, qr/does not provide/, 'right exception');
+
+  ok(!eval { MyTypes::NoClass->new }, 'new on non-class type');
+
+  like($@, qr/non-class-type/, 'right exception');
 }
 
 BEGIN {