add friendly error message when giving argless plugins args
[gitmo/MooseX-Runnable.git] / lib / MooseX / Runnable / Invocation.pm
index 77e3b0b..2fb34b7 100644 (file)
@@ -1,7 +1,8 @@
 package MooseX::Runnable::Invocation;
 use Moose;
 use MooseX::Types -declare => ['RunnableClass'];
-use MooseX::Types::Moose qw(Str ClassName);
+use MooseX::Types::Moose qw(Str HashRef ArrayRef);
+use namespace::autoclean;
 
 require Class::MOP;
 
@@ -12,12 +13,9 @@ subtype RunnableClass,
   as Str,
   where { $_ =~ /^[:A-Za-z_]+$/ };
 
-use namespace::clean -except => 'meta';
 
-# this class is just as runnable as any other, so I guess we should tag it
-with 'MooseX::Runnable', 'MooseX::Object::Pluggable';
-
-has '+_plugin_ns' => ( default => 'MooseX::Runnable::Invocation::Plugin' );
+with 'MooseX::Runnable'; # this class technically follows
+                         # MX::Runnable's protocol
 
 has 'class' => (
     is       => 'ro',
@@ -27,15 +25,54 @@ has 'class' => (
 
 has 'plugins' => (
     is         => 'ro',
-    isa        => 'ArrayRef[Str]',
-    default    => sub { [] },
+    isa        => HashRef[ArrayRef[Str]],
+    default    => sub { +{} },
     required   => 1,
     auto_deref => 1,
 );
 
 sub BUILD {
     my $self = shift;
-    $self->load_plugin($_) for $self->plugins;
+
+    # it would be nice to use MX::Object::Pluggable, but our plugins
+    # are too configurable
+
+    my $plugin_ns = 'MooseX::Runnable::Invocation::Plugin::';
+    for my $plugin (keys %{$self->plugins}){
+        my $orig = $plugin;
+        $plugin = "$plugin_ns$plugin" unless $plugin =~ /^[+]/;
+        $plugin =~ s/^[+]//g;
+
+        Class::MOP::load_class( $plugin );
+
+        my $does_cmdline = $plugin->meta->
+          does_role('MooseX::Runnable::Invocation::Plugin::Role::CmdlineArgs');
+
+        my $args;
+        if($does_cmdline){
+            $args = eval {
+                $plugin->_build_initargs_from_cmdline(
+                    @{$self->plugins->{$orig}},
+                );
+            };
+
+            if($@) {
+                confess "Error building initargs for $plugin: $@";
+            }
+        }
+        elsif(!$does_cmdline && scalar @{$self->plugins->{$orig}} > 0){
+            confess "You supplied arguments to the $orig plugin, but it".
+              " does not know how to accept them.  Perhaps the plugin".
+              " should consume the".
+              " 'MooseX::Runnable::Invocation::Plugin::Role::CmdlineArgs'".
+              " role?";
+        }
+
+        $plugin->meta->apply(
+            $self,
+            defined $args ? (rebless_params => $args) : (),
+        );
+    }
 }
 
 sub load_class {
@@ -66,9 +103,11 @@ sub apply_scheme {
         $self->_convert_role_to_scheme($_)
     } $class->calculate_all_roles;
 
-    foreach my $scheme (@schemes) {
-        $scheme->apply($self);
-    }
+    eval {
+        foreach my $scheme (@schemes) {
+            $scheme->apply($self);
+        }
+    };
 }
 
 
@@ -87,13 +126,12 @@ sub _convert_role_to_scheme {
     };
 }
 
-
 sub validate_class {
     my ($self, $class) = @_;
 
     my @bad_attributes = map { $_->name } grep {
-        $_->is_required && $_->has_default || $_->has_builder
-    } $class->compute_all_applicable_attributes;
+        $_->is_required && !($_->has_default || $_->has_builder)
+    } $class->get_all_attributes;
 
     confess
        'By default, MooseX::Runnable calls the constructor with no'.