File Coverage

blib/lib/Mojolicious/Plugin/InstallablePaths.pm
Criterion Covered Total %
statement 23 24 95.8
branch 8 10 80.0
condition 2 3 66.6
subroutine 5 5 100.0
pod 1 2 50.0
total 39 44 88.6


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::InstallablePaths;
2 5     5   1314534 use Mojo::Base 'Mojolicious::Plugin';
  5         12095  
  5         35  
3              
4             our $VERSION = '0.03';
5             $VERSION = eval $VERSION;
6              
7 5     5   6181 use File::Spec;
  5         14  
  5         163  
8 5     5   4496 use File::ShareDir ();
  5         42220  
  5         3028  
9              
10             has 'app_class';
11              
12             has 'dist_dir' => sub {
13             my $self = shift;
14             my $dist = $self->app_class;
15             $dist =~ s{::}{-}g;
16             return eval { File::ShareDir::dist_dir( $dist ) };
17             };
18              
19             has 'class_path' => sub {
20             my $self = shift;
21             my $app_class = $self->app_class;
22             my $class_path = $app_class;
23             $class_path =~ s{::}{/}g;
24              
25             $class_path = $INC{"$class_path.pm"}
26             || die "Cannot find $class_path.pm, do you need to load $app_class?\n";;
27             $class_path =~ s/\.pm$//;
28             return $class_path;
29             };
30              
31             has 'files_path' => sub {
32             my $self = shift;
33             return File::Spec->catdir( $self->class_path, 'files');
34             };
35              
36             sub register {
37 2     2 1 119 my ($self, $app, $conf) = @_;
38 2         53 $self->app_class( ref $app );
39              
40 2 50       30 if ( my $public = $self->find_path('public') ) {
41 2         56 $app->static->paths->[0] = $public;
42             }
43              
44 2 50       89 if ( my $templates = $self->find_path('templates') ) {
45 0         0 $app->renderer->paths->[0] = $templates;
46             }
47              
48             }
49              
50             sub find_path {
51 8     8 0 907 my $self = shift;
52 8         16 my $target = shift;
53              
54 8         207 my $local = File::Spec->catdir($self->files_path, $target);
55 8 100       255 return $local if -d $local;
56              
57 6         170 my $dist_dir = $self->dist_dir;
58 6 100 66     2111 if ( $dist_dir && -d $dist_dir ) {
59 4         27 my $share = File::Spec->catdir($dist_dir, $target);
60 4 100       96 return $share if -d $share;
61             }
62              
63 4         32 return undef;
64             }
65              
66             1;
67              
68             =head1 NAME
69              
70             Mojolicious::Plugin::InstallablePaths - Easy installation configuration for Mojolicious apps
71              
72             =head1 SYNOPSIS
73              
74             # MyApp.pm
75             package MyApp;
76             use Mojo::Base 'Mojolicious';
77              
78             sub startup {
79             my $app = shift;
80             $app->plugin( 'InstallablePaths' );
81             ...
82             }
83              
84             then if using L
85              
86             # Build.PL
87             use Module::Build::Mojolicious clean_install => 1;
88             my $builder = Module::Build::Mojolicious->new(
89             configure_requires => {
90             'Module::Build::Mojolicious' => 0,
91             'Module::Build' => 0.38,
92             },
93             ...
94             );
95             $builder->create_build_script;
96              
97             =head1 DESCRIPTION
98              
99             L applications work nicely from a working directory, but once the app is bundled for installation some of the configuration gets a little bit tricky. Though some examples are shown in the L documentation, the process is still rather involved. However, L handles all the configuration for you (provided you follow a proscribed directory tree)!
100              
101             =head1 DIRECTORY STRUCTURE
102              
103             myapp # Application directory
104             |- bin # Script directory
105             | +- myapp # Application script
106             |- lib # Library directory
107             | |- MyApp.pm # Application class
108             | +- MyApp # Application namespace
109             | |- Example.pm # Controller class
110             | +- files # Shared directory for all non-module content
111             | |- public # Static file directory (served automatically)
112             | | +- index.html # Static HTML file
113             | +- templates # Template directory
114             | |- layouts # Template directory for layouts
115             | | +- default.html.ep # Layout template
116             | +- example # Template directory for "Example" controller
117             | +- welcome.html.ep # Template for "welcome" action
118             |- t # Test directory
119             | +- basic.t # Random test
120             +- Build.PL # Build file uses Module::Build::Mojolicious
121              
122             As you can see, all non-module content is placed inside a directory named C directly inside the folder named for the module. In the above example this is the C directory. If the app had been C then the directory would be C.
123              
124             There is no allowance for different names of these folders nor of different locations for them relative to the main module. Patches will be considered, but the primary purpose of this module is the simple generic case; to do strange things the Mojolicious path manipulation system should be used directly.
125              
126             =head1 PLUGIN
127              
128             The magic happens when your app loads the C plugin.
129              
130             $app->plugin('InstallablePaths');
131              
132             Before this call, the directories are not set correctly, so be sure to use it early! The plugin will detect if the directory tree exists as above (i.e. before installation) and use it directly or else it will attempt to use the L system to locate the directories (i.e. after installation). In this way, your app should always find its needed files, no matter what phase of development or installation!
133              
134             =head1 MAKEFILE.PL SCRIPT
135              
136             When using L the files are installed directly and the plugin finds them from the main tree. Just install as usual.
137              
138             =head1 BUILD.PL SCRIPT
139              
140             If L is more your flavor (it is mine), included with L is a subclass of L named L (of course). The purpose of this subclass is to add the necessary directory to the list of shared folders using the L integration. This is done completely behind the scenes, provided the directory exists. Simply change the name of your build module and use as normal:
141              
142             use Module::Build::Mojolicious clean_install => 1;
143             my $builder = Module::Build::Mojolicious->new(
144             configure_requires => {
145             'Module::Build::Mojolicious' => 0,
146             'Module::Build' => 0.38,
147             },
148             ...
149             );
150             $builder->create_build_script;
151              
152             Later, this directory can be found using the usual mechanisms that that L provides. Keep in mind that you should add it to the C key as you should for any module used in a C file.
153              
154             Finally note that if passing C<< clean_install => 1 >> at import, L will be inserted into the inheritance tree at import time. This module ensures that old files are removed before upgrading an already installed module. The author recommends this option be enabled.
155              
156             =head1 SEE ALSO
157              
158             =over
159              
160             =item *
161              
162             L
163              
164             =item *
165              
166             L
167              
168             =item *
169              
170             L
171              
172             =back
173              
174             =head1 SOURCE REPOSITORY
175              
176             L
177              
178             =head1 AUTHOR
179              
180             Joel Berger, Ejoel.a.berger@gmail.comE
181              
182             =head1 COPYRIGHT AND LICENSE
183              
184             Copyright (C) 2012 by Joel Berger
185              
186             This library is free software; you can redistribute it and/or modify
187             it under the same terms as Perl itself.
188              
189             =cut
190              
191