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