Some changes to make MX::Types::Combine detect errors earlier
Dave Rolsky [Mon, 8 Nov 2010 15:52:51 +0000 (09:52 -0600)]
We check that all the packages we are combining actually have a ->type_names
method.

Type libs are loaded when the provided type libs are set, rather than every
time import is called.

Generate the list of exported types when the provided type libs are set,
rather than every time import is called.

lib/MooseX/Types/Combine.pm
t/18_combined_libs.t

index f41fd6e..bb8d166 100644 (file)
@@ -36,20 +36,17 @@ sub import {
     my ($class, @types) = @_;
     my $caller = caller;
 
-    my @type_libs = $class->provide_types_from;
-    Class::MOP::load_class($_) for @type_libs;
-
-    my %types = map {
-        my $lib = $_;
-        map +($_ => $lib), $lib->type_names
-    } @type_libs;
+    my %types = $class->_provided_types;
 
     my %from;
     for my $type (@types) {
-        die
-            "$caller asked for a type ($type) which is not found in any of the"
-            . " type libraries (@type_libs) combined by $class\n"
-            unless $types{$type};
+        unless ($types{$type}) {
+            my @type_libs = $class->provide_types_from;
+
+            die
+                "$caller asked for a type ($type) which is not found in any of the"
+                . " type libraries (@type_libs) combined by $class\n";
+        }
 
         push @{ $from{ $types{$type} } }, $type;
     }
@@ -72,11 +69,42 @@ sub provide_types_from {
     my $store =
      do { no strict 'refs'; \@{ "${class}::__MOOSEX_TYPELIBRARY_LIBRARIES" } };
 
-    @$store = @libs if @libs;
+    if (@libs) {
+        $class->_check_type_lib($_) for @libs;
+        @$store = @libs;
+
+        my %types = map {
+            my $lib = $_;
+            map +( $_ => $lib ), $lib->type_names
+        } @libs;
+
+        $class->_provided_types(%types);
+    }
 
     @$store;
 }
 
+sub _provided_types {
+    my ($class, %types) = @_;
+
+    my $types =
+     do { no strict 'refs'; \%{ "${class}::__MOOSEX_TYPELIBRARY_TYPES" } };
+
+    %$types = %types
+        if keys %types;
+
+    %$types;
+}
+
+sub _check_type_lib {
+    my ($class, $lib) = @_;
+
+    Class::MOP::load_class($lib);
+
+    die "Cannot use $lib in a combined type library, it does not provide any types"
+        unless $lib->can('type_names');
+}
+
 =head1 SEE ALSO
 
 L<MooseX::Types>
index cd2178d..23ba549 100644 (file)
@@ -2,9 +2,9 @@
 use strict;
 use warnings;
 use FindBin;
-use lib "$FindBin::Bin/lib";   
+use lib "$FindBin::Bin/lib";
 
-use Test::More tests => 5;
+use Test::More tests => 7;
 use Test::Fatal;
 
 BEGIN { use_ok 'Combined', qw/Foo2Alias MTFNPY NonEmptyStr/ }
@@ -21,3 +21,17 @@ is NonEmptyStr->name, 'TestLibrary2::NonEmptyStr',
 like exception { Combined->import('NonExistentType') },
 qr/\Qmain asked for a type (NonExistentType) which is not found in any of the type libraries (TestLibrary TestLibrary2) combined by Combined/,
 'asking for a non-existent type from a combined type library gives a useful error';
+
+{
+    package BadCombined;
+
+    use base 'MooseX::Types::Combine';
+
+    ::like ::exception { __PACKAGE__->provide_types_from('Empty') },
+    qr/Cannot use Empty in a combined type library, it does not provide any types/,
+    'cannot combine types from a package which is not a type library';
+
+    ::like ::exception { __PACKAGE__->provide_types_from('DoesNotExist') },
+    qr/Can't locate DoesNotExist\.pm/,
+    'cannot combine types from a package which does not exist';
+}