File Coverage

blib/lib/Module/Starter/PBP.pm
Criterion Covered Total %
statement 22 152 14.4
branch 1 48 2.0
condition 2 6 33.3
subroutine 7 15 46.6
pod 6 6 100.0
total 38 227 16.7


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