1 package MooseX::Runnable::Invocation;
3 use MooseX::Types -declare => ['RunnableClass'];
4 use MooseX::Types::Moose qw(Str HashRef ArrayRef);
5 use namespace::autoclean;
9 # we can't load the class until plugins are loaded,
10 # so we have to handle this outside of coerce
12 subtype RunnableClass,
14 where { $_ =~ /^[:A-Za-z_]+$/ };
17 with 'MooseX::Runnable'; # this class technically follows
18 # MX::Runnable's protocol
28 isa => HashRef[ArrayRef[Str]],
29 default => sub { [] },
37 # it would be nice to use MX::Object::Pluggable, but our plugins
38 # are too configurable
40 my $plugin_ns = 'MooseX::Runnable::Invocation::Plugin::';
41 for my $plugin (keys %{$self->plugins}){
43 $plugin = "$plugin_ns$plugin" unless $plugin =~ /^[+]/;
46 Class::MOP::load_class( $plugin );
49 $plugin->_build_initargs_from_cmdline(
50 @{$self->plugins->{$orig}},
53 if($@ && $plugin->can('_build_initargs_from_cmdline')){
54 confess "Error building initargs for $plugin: $@";
59 defined $args ? (rebless_params => $args) : (),
66 my $class = $self->class;
68 Class::MOP::load_class( $class );
70 confess 'We can only work with Moose classes with "meta" methods'
71 if !$class->can('meta');
73 my $meta = $class->meta;
75 confess "The metaclass of $class is not a Moose::Meta::Class, it's $meta"
76 unless $meta->isa('Moose::Meta::Class');
78 confess 'MooseX::Runnable can only run classes tagged with '.
79 'the MooseX::Runnable role'
80 unless $meta->does_role('MooseX::Runnable');
86 my ($self, $class) = @_;
88 my @schemes = grep { defined } map {
89 $self->_convert_role_to_scheme($_)
90 } $class->calculate_all_roles;
93 foreach my $scheme (@schemes) {
94 $scheme->apply($self);
100 sub _convert_role_to_scheme {
101 my ($self, $role) = @_;
103 my $name = $role->name;
104 return if $name =~ /\|/;
105 $name = "MooseX::Runnable::Invocation::Scheme::$name";
108 Class::MOP::load_class($name);
109 warn "$name was loaded OK, but it's not a role!" and return
110 unless $name->meta->isa('Moose::Meta::Role');
116 my ($self, $class) = @_;
118 my @bad_attributes = map { $_->name } grep {
119 $_->is_required && !($_->has_default || $_->has_builder)
120 } $class->get_all_attributes;
123 'By default, MooseX::Runnable calls the constructor with no'.
124 ' args, but that will result in an error for your class. You'.
125 ' need to provide a MooseX::Runnable::Invocation::Plugin or'.
126 ' ::Scheme for this class that will satisfy the requirements.'.
128 "The class is @{[$class->name]}, and the required attributes are ".
129 join ', ', map { "'$_'" } @bad_attributes
132 return; # return value is meaningless
135 sub create_instance {
136 my ($self, $class, @args) = @_;
137 return ($class->name->new, @args);
140 sub start_application {
142 my $instance = shift;
145 return $instance->run(@args);
152 my $class = $self->load_class;
153 $self->apply_scheme($class);
154 $self->validate_class($class);
155 my ($instance, @more_args) = $self->create_instance($class, @args);
156 my $exit_code = $self->start_application($instance, @more_args);