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 List::MoreUtils qw(uniq);
+use namespace::autoclean;
require Class::MOP;
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',
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 {
my ($self, $class) = @_;
my @schemes = grep { defined } map {
- $self->_convert_role_to_scheme($_)
- } $class->calculate_all_roles;
+ eval { $self->_convert_role_to_scheme($_) }
+ } map {
+ eval { $_->meta->calculate_all_roles };
+ } $class->linearized_isa;
eval {
- foreach my $scheme (@schemes) {
+ foreach my $scheme (uniq @schemes) {
$scheme->apply($self);
}
};
};
}
-
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'.