Merge branch 'pr/135' into release-candidates/rc-5.90116
[catagits/Catalyst-Runtime.git] / lib / Catalyst / ScriptRunner.pm
1 package Catalyst::ScriptRunner;
2 use Moose;
3 use FindBin;
4 use lib;
5 use File::Spec;
6 use Class::Load qw/ load_first_existing_class load_optional_class /;
7 use Catalyst::Utils;
8 use namespace::autoclean -also => 'subclass_with_traits';
9 use Try::Tiny;
10
11 sub find_script_class {
12     my ($self, $app, $script) = @_;
13     return load_first_existing_class("${app}::Script::${script}", "Catalyst::Script::$script");
14 }
15
16 sub find_script_traits {
17     my ($self, @try) = @_;
18
19     return grep { load_optional_class($_) } @try;
20 }
21
22 sub subclass_with_traits {
23     my ($base, @traits) = @_;
24
25     my $meta = Class::MOP::class_of($base)->create_anon_class(
26         superclasses => [ $base   ],
27         roles        => [ @traits ],
28         cache        => 1,
29     );
30     $meta->add_method(meta => sub { $meta });
31
32     return $meta->name;
33 }
34
35 sub run {
36     my ($self, $appclass, $scriptclass) = @_;
37
38     if (grep { -f File::Spec->catfile($FindBin::Bin, '..', $_) } Catalyst::Utils::dist_indicator_file_list()) {
39         lib->import(File::Spec->catdir($FindBin::Bin, '..', 'lib'));
40     }
41
42     my $class = $self->find_script_class($appclass, $scriptclass);
43
44     my @possible_traits = ("${appclass}::TraitFor::Script::${scriptclass}", "${appclass}::TraitFor::Script");
45     my @traits = $self->find_script_traits(@possible_traits);
46
47     $class = subclass_with_traits($class, @traits)
48         if @traits;
49
50     $class->new_with_options( application_name => $appclass )->run;
51 }
52
53 __PACKAGE__->meta->make_immutable;
54 1;
55
56 =head1 NAME
57
58 Catalyst::ScriptRunner - The Catalyst Framework script runner
59
60 =head1 SYNOPSIS
61
62     # Will run MyApp::Script::Server if it exists, otherwise
63     # will run Catalyst::Script::Server.
64     Catalyst::ScriptRunner->run('MyApp', 'Server');
65
66 =head1 DESCRIPTION
67
68 This class is responsible for loading and running scripts, either in the
69 application specific namespace
70 (e.g. C<MyApp::Script::Server>), or the Catalyst namespace (e.g. C<Catalyst::Script::Server>).
71
72 If your application contains a custom script, then it will be used in preference to the generic
73 script, and is expected to sub-class the standard script.
74
75 =head1 TRAIT LOADING
76
77 Catalyst will automatically load and apply roles to the scripts in your
78 application.
79
80 C<MyApp::TraitFor::Script> will be loaded if present, and will be applied to B<ALL>
81 scripts.
82
83 C<MyApp::TraitFor::Script::XXXX> will be loaded (if present) and for script
84 individually.
85
86 =head1 METHODS
87
88 =head2 run ($application_class, $scriptclass)
89
90 Called with two parameters, the application class (e.g. MyApp)
91 and the script class, (i.e. one of Server/FastCGI/CGI/Create/Test)
92
93 =head2 find_script_class ($appname, $script_name)
94
95 Finds and loads the class for the script, trying the application specific
96 script first, and falling back to the generic script. Returns the script
97 which was loaded.
98
99 =head2 find_script_traits ($appname, @try)
100
101 Finds and loads a set of traits. Returns the list of traits which were loaded.
102
103 =head1 AUTHORS
104
105 Catalyst Contributors, see Catalyst.pm
106
107 =head1 COPYRIGHT
108
109 This library is free software. You can redistribute it and/or modify it under
110 the same terms as Perl itself.
111
112 =cut