File Coverage

blib/lib/Module/Starter/PBP.pm
Criterion Covered Total %
statement 25 153 16.3
branch 1 44 2.2
condition 2 6 33.3
subroutine 8 16 50.0
pod 6 6 100.0
total 42 225 18.6


line stmt bran cond sub pod time code
1             package Module::Starter::PBP;
2 1     1   33887 use base 'Module::Starter::Simple';
  1         2  
  1         1095  
3              
4 1     1   24701 use version; $VERSION = qv('0.0.3');
  1         2526  
  1         9  
5              
6 1     1   104 use warnings;
  1         8  
  1         37  
7 1     1   5 use strict;
  1         2  
  1         32  
8 1     1   5 use Carp;
  1         3  
  1         1081  
9              
10             sub module_guts {
11 0     0 1 0 my $self = shift;
12 0         0 my %context = (
13             'MODULE NAME' => shift,
14             'RT NAME' => shift,
15             'DATE' => scalar localtime,
16             'YEAR' => $self->_thisyear(),
17             );
18              
19 0         0 return $self->_load_and_expand_template('Module.pm', \%context);
20             }
21              
22              
23             sub Makefile_PL_guts {
24 0     0 1 0 my $self = shift;
25 0         0 my %context = (
26             'MAIN MODULE' => shift,
27             'MAIN PM FILE' => shift,
28             'DATE' => scalar localtime,
29             'YEAR' => $self->_thisyear(),
30             );
31              
32 0         0 return $self->_load_and_expand_template('Makefile.PL', \%context);
33             }
34              
35             sub Build_PL_guts {
36 0     0 1 0 my $self = shift;
37 0         0 my %context = (
38             'MAIN MODULE' => shift,
39             'MAIN PM FILE' => shift,
40             'DATE' => scalar localtime,
41             'YEAR' => $self->_thisyear(),
42             );
43              
44 0         0 return $self->_load_and_expand_template('Build.PL', \%context);
45             }
46              
47             sub Changes_guts {
48 0     0 1 0 my $self = shift;
49              
50 0         0 my %context = (
51             'DATE' => scalar localtime,
52             'YEAR' => $self->_thisyear(),
53             );
54              
55 0         0 return $self->_load_and_expand_template('Changes', \%context);
56             }
57              
58             sub README_guts {
59 0     0 1 0 my $self = shift;
60              
61 0         0 my %context = (
62             'BUILD INSTRUCTIONS' => shift,
63             'DATE' => scalar localtime,
64             'YEAR' => $self->_thisyear(),
65             );
66              
67 0         0 return $self->_load_and_expand_template('README', \%context);
68             }
69              
70             sub t_guts {
71 0     0 1 0 my $self = shift;
72 0         0 my @modules = @_;
73 0         0 my %context = (
74             'DATE' => scalar localtime,
75             'YEAR' => $self->_thisyear(),
76             );
77              
78 0         0 my %t_files;
79 0         0 for my $test_file ( map { s{\A .*/t/}{}xms; $_; }
  0         0  
  0         0  
80             glob "$self->{template_dir}/t/*" ) {
81 0         0 $t_files{$test_file}
82             = $self->_load_and_expand_template("t/$test_file", \%context);
83             }
84              
85 0         0 my $nmodules = @modules;
86 0         0 my $main_module = $modules[0];
87 0         0 my $use_lines = join( "\n", map { "use_ok( '$_' );" } @modules );
  0         0  
88              
89 0         0 $t_files{'00.load.t'} = <<"END_LOAD";
90             use Test::More tests => $nmodules;
91              
92             BEGIN {
93             $use_lines
94             }
95              
96             diag( "Testing $main_module \$${main_module}::VERSION" );
97             END_LOAD
98              
99 0         0 return %t_files;
100             }
101              
102             sub _load_and_expand_template {
103 0     0   0 my ($self, $rel_file_path, $context_ref) = @_;
104              
105 0         0 @{$context_ref}{map {uc} keys %$self} = values %$self;
  0         0  
  0         0  
106              
107 0 0       0 die "Can't find directory that holds Module::Starter::PBP templates\n",
108             "(no 'template_dir: ' in config file)\n"
109             if not defined $self->{template_dir};
110              
111 0 0       0 die "Can't access Module::Starter::PBP template directory\n",
112             "(perhaps 'template_dir: $self->{template_dir}' is wrong in config file?)\n"
113             if not -d $self->{template_dir};
114              
115 0         0 my $abs_file_path = "$self->{template_dir}/$rel_file_path";
116              
117 0 0       0 die "The Module::Starter::PBP template: $rel_file_path\n",
118             "isn't in the template directory ($self->{template_dir})\n\n"
119             if not -e $abs_file_path;
120              
121 0 0       0 die "The Module::Starter::PBP template: $rel_file_path\n",
122             "isn't readable in the template directory ($self->{template_dir})\n\n"
123             if not -r $abs_file_path;
124              
125 0 0       0 open my $fh, '<', $abs_file_path or croak $!;
126 0         0 local $/;
127 0         0 my $text = <$fh>;
128              
129 0         0 $text =~ s{<([A-Z ]+)>}
130 0 0       0 { $context_ref->{$1}
131             || die "Unknown placeholder <$1> in $rel_file_path\n"
132             }xmseg;
133              
134 0         0 return $text;
135             }
136              
137             sub import {
138 1     1   12 my $class = shift;
139 1         4 my ($setup, @other_args) = @_;
140              
141             # If this is not a setup request,
142             # refer the import request up the hierarchy...
143 1 50 33     11 if (@other_args || !$setup || $setup ne 'setup') {
      33        
144 1         19 return $class->SUPER::import(@_);
145             }
146              
147             # Otherwise, gather the necessary tools...
148 1     1   7 use ExtUtils::Command qw( mkpath );
  1         2  
  1         61  
149 1     1   6 use File::Spec;
  1         2  
  1         1383  
150 0           local $| = 1;
151              
152             # Locate the home directory...
153 0 0         if (!defined $ENV{HOME}) {
154 0           print 'Please enter the full path of your home directory: ';
155 0           $ENV{HOME} = <>;
156 0           chomp $ENV{HOME};
157 0 0         croak 'Not a valid directory. Aborting.'
158             if !-d $ENV{HOME};
159             }
160              
161             # Create the directories...
162 0           my $template_dir
163             = File::Spec->catdir( $ENV{HOME}, '.module-starter', 'PBP' );
164 0 0         if ( not -d $template_dir ) {
165 0           print {*STDERR} "Creating $template_dir...";
  0            
166 0           local @ARGV = $template_dir;
167 0           mkpath;
168 0           print {*STDERR} "done.\n";
  0            
169             }
170              
171 0           my $template_test_dir
172             = File::Spec->catdir( $ENV{HOME}, '.module-starter', 'PBP', 't' );
173 0 0         if ( not -d $template_test_dir ) {
174 0           print {*STDERR} "Creating $template_test_dir...";
  0            
175 0           local @ARGV = $template_test_dir;
176 0           mkpath;
177 0           print {*STDERR} "done.\n";
  0            
178             }
179              
180             # Create or update the config file (making a backup, of course)...
181 0           my $config_file
182             = File::Spec->catfile( $ENV{HOME}, '.module-starter', 'config' );
183              
184 0           my @config_info;
185              
186 0 0         if ( -e $config_file ) {
187 0           print {*STDERR} "Backing up $config_file...";
  0            
188 0           my $backup
189             = File::Spec->catfile( $ENV{HOME}, '.module-starter', 'config.bak' );
190 0           rename($config_file, $backup);
191 0           print {*STDERR} "done.\n";
  0            
192              
193 0           print {*STDERR} "Updating $config_file...";
  0            
194 0 0         open my $fh, '<', $backup or die "$config_file: $!\n";
195             @config_info
196 0           = grep { not /\A (?: template_dir | plugins ) : /xms } <$fh>;
  0            
197 0 0         close $fh or die "$config_file: $!\n";
198             }
199             else {
200 0           print {*STDERR} "Creating $config_file...\n";
  0            
201              
202 0           my $author = _prompt_for('your full name');
203 0           my $email = _prompt_for('an email address');
204              
205 0           @config_info = (
206             "author: $author\n",
207             "email: $email\n",
208             "builder: ExtUtils::MakeMaker Module::Build\n",
209             );
210              
211 0           print {*STDERR} "Writing $config_file...\n";
  0            
212             }
213              
214 0           push @config_info, (
215             "plugins: Module::Starter::PBP\n",
216             "template_dir: $template_dir\n",
217             );
218              
219 0 0         open my $fh, '>', $config_file or die "$config_file: $!\n";
220 0 0         print {$fh} @config_info or die "$config_file: $!\n";
  0            
221 0 0         close $fh or die "$config_file: $!\n";
222 0           print {*STDERR} "done.\n";
  0            
223              
224 0           print {*STDERR} "Installing templates...\n";
  0            
225             # Then install the various files...
226 0           my @files = (
227             ['Build.PL'],
228             ['Makefile.PL'],
229             ['README'],
230             ['Changes'],
231             ['Module.pm'],
232             ['t', 'pod-coverage.t'],
233             ['t', 'pod.t'],
234             ['t', 'perlcritic.t'],
235             );
236              
237 0           my %contents_of = do { local $/; "", split /_____\[ (\S+) \]_+\n/, };
  0            
  0            
238 0           for (values %contents_of) {
239 0           s/^!=([a-z])/=$1/gxms;
240             }
241              
242 0           for my $ref_path ( @files ) {
243 0           my $abs_path
244 0           = File::Spec->catfile( $ENV{HOME}, '.module-starter', 'PBP', @{$ref_path} );
245 0           print {*STDERR} "\t$abs_path...";
  0            
246 0 0         open my $fh, '>', $abs_path or die "$abs_path: $!\n";
247 0 0         print {$fh} $contents_of{$ref_path->[-1]} or die "$abs_path: $!\n";
  0            
248 0 0         close $fh or die "$abs_path: $!\n";
249 0           print {*STDERR} "done\n";
  0            
250             }
251 0           print {*STDERR} "Installation complete.\n";
  0            
252              
253 0           exit;
254             }
255              
256             sub _prompt_for {
257 0     0     my ($requested_info) = @_;
258 0           my $response;
259 0           RESPONSE: while (1) {
260 0           print "Please enter $requested_info: ";
261 0           $response = <>;
262 0 0         if (not defined $response) {
263 0           warn "\n[Installation cancelled]\n";
264 0           exit;
265             }
266 0           $response =~ s/\A \s+ | \s+ \Z//gxms;
267 0 0         last RESPONSE if $response =~ /\S/;
268             }
269 0           return $response;
270             }
271              
272              
273             1; # Magic true value required at end of module
274              
275             =pod
276              
277             =head1 NAME
278              
279             Module::Starter::PBP - Create a module as recommended in "Perl Best Practices"
280              
281              
282             =head1 VERSION
283              
284             This document describes Module::Starter::PBP version 0.0.3
285              
286              
287             =head1 SYNOPSIS
288              
289             # In your ~/.module-starter/config file...
290              
291             author:
292             email:
293             plugins: Module::Starter::PBP
294             template_dir:
295              
296              
297             # Then on the command-line...
298              
299             > module-starter --module=Your::New::Module
300              
301              
302             # Or, if you're lazy and happy to go with
303             # the recommendations in "Perl Best Practices"...
304              
305             > perl -MModule::Starter::PBP=setup
306            
307            
308             =head1 DESCRIPTION
309              
310             This module implements a simple approach to creating modules and their support
311             files, based on the Module::Starter approach. Module::Starter needs to be
312             installed before this module can be used.
313              
314             When used as a Module::Starter plugin, this module allows you to specify a
315             simple directory of templates which are filled in with module-specific
316             information, and thereafter form the basis of your new module.
317              
318             The default templates that this module initially provides are based on
319             the recommendations in the book "Perl Best Practices".
320              
321              
322             =head1 INTERFACE
323              
324             Thsi module simply acts as a plugin for Module::Starter. So it uses the same
325             command-line interface as that module.
326              
327             The template files it is to use are specified in your Module::Starter
328             C file, by adding a C configuration variable that
329             gives the full path name of the directory in which you want to put
330             the templates.
331              
332             The easiest way to set up this C file, the associated directory, and
333             the necessary template files is to type:
334              
335             > perl -MModule::Starter::PBP=setup
336              
337             on the command line. You will then be asked for your name, email address, and
338             the full path name of the directory where you want to keep the templates,
339             after which they will be created and installed.
340              
341             Then you can create a new module by typing:
342              
343             > module-starter --module=Your::New::Module
344              
345              
346             =head2 Template format
347              
348             The templates are plain files named:
349              
350             Build.PL
351             Makefile.PL
352             README
353             Changes
354             Module.pm
355             t/whatever_you_like.t
356              
357             The C file is the template for the C<.pm> file for your module. Any
358             files in the C subdirectory become the templates for the testing files of
359             your module. All the remaining files are templates for the ditribution files
360             of the same names.
361              
362             In those files, the following placeholders are replaced by the appropriate
363             information specific to the file:
364              
365             =over
366              
367             =item
368              
369             The nominated author. Taken from the C setting in
370             your Module::Starter C file.
371              
372             =item
373              
374             Makefile or Module::Build instructions. Computed automatically according to
375             the C setting in your Module::Starter C file.
376              
377             =item
378              
379             The current date (as returned by C). Computed automagically
380              
381             =item
382              
383             The name of the complete module distribution. Computed automatically from the
384             name of the module.
385              
386             =item
387              
388             Where to send feedback. Taken from the C setting in
389             your Module::Starter C file.
390              
391             =item
392              
393             The licence under which the module is released. Taken from the C
394             setting in your Module::Starter C file.
395              
396             =item
397              
398             The name of the main module of the distribution.
399              
400             =item
401              
402             The name of the C<.pm> file for the main module.
403              
404             =item
405              
406             The name of the current module being created within the distribution.
407              
408             =item
409              
410             The name to use for bug reports to the RT system.
411             That is:
412              
413             Please report any bugs or feature requests to
414             bug-@rt.cpan.org>
415              
416             =item
417              
418             The current year. Computed automatically
419              
420             =back
421              
422              
423             =head1 DIAGNOSTICS
424              
425             =over
426              
427             =item C<< Can't find directory that holds Module::Starter::PBP templates >>
428              
429             You did not tell Module::Starter::PBP where your templates are stored.
430             You need a 'template_dir' specification. Typically this would go in
431             your ~/.module-starter/config file. Something like:
432              
433             template_dir: /users/you/.module-starter/Templates
434              
435              
436             =item C<< Can't access Module::Starter::PBP template directory >>
437              
438             You specified a 'template_dir', but the path didn't lead to a readable
439             directory.
440              
441              
442             =item C<< The template: %s isn't in the template directory (%s) >>
443              
444             One of the required templates:
445              
446             was missing from the template directory you specified.
447              
448              
449             =item C<< The template: %s isn't readable in the template directory (%s) >>
450              
451             One of the templates in the template directory you specified was not readable.
452              
453              
454             =item C<< Unknown placeholder <%s> in %s >>
455              
456             One of the templates in the template directory contained a replacement item
457             that wasn't a known piece of information.
458              
459             =back
460              
461              
462             =head1 CONFIGURATION AND ENVIRONMENT
463              
464             See the documentation for C and C.
465              
466              
467             =head1 DEPENDENCIES
468              
469             Requires the C module.
470              
471              
472             =head1 INCOMPATIBILITIES
473              
474             None reported.
475              
476              
477             =head1 BUGS AND LIMITATIONS
478              
479             No bugs have been reported.
480              
481             Please report any bugs or feature requests to
482             C, or through the web interface at
483             L.
484              
485              
486             =head1 AUTHOR
487              
488             Damian Conway C<< >>
489              
490              
491             =head1 LICENCE AND COPYRIGHT
492              
493             Copyright (c) 2005, Damian Conway C<< >>. All rights reserved.
494              
495             This module is free software; you can redistribute it and/or
496             modify it under the same terms as Perl itself.
497              
498              
499             =head1 DISCLAIMER OF WARRANTY
500              
501             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
502             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
503             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
504             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
505             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
506             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
507             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
508             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
509             NECESSARY SERVICING, REPAIR, OR CORRECTION.
510              
511             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
512             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
513             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
514             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
515             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
516             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
517             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
518             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
519             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
520             SUCH DAMAGES.
521              
522             =cut
523              
524              
525              
526             __DATA__