File Coverage

blib/lib/Module/Starter/PBP.pm
Criterion Covered Total %
statement 22 153 14.3
branch 1 48 2.0
condition 2 6 33.3
subroutine 7 15 46.6
pod 6 6 100.0
total 38 228 16.6


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