File Coverage

blib/lib/App/Module/Setup.pm
Criterion Covered Total %
statement 15 93 16.1
branch 0 48 0.0
condition 0 16 0.0
subroutine 5 9 55.5
pod 1 2 50.0
total 21 168 12.5


line stmt bran cond sub pod time code
1             #! perl
2              
3             package App::Module::Setup;
4              
5             ### Please use this module via the command line module-setup tool.
6              
7             our $VERSION = '0.08';
8              
9 1     1   68499 use warnings;
  1         3  
  1         36  
10 1     1   5 use strict;
  1         2  
  1         19  
11 1     1   5 use File::Find;
  1         2  
  1         61  
12 1     1   6 use File::Basename qw( dirname );
  1         2  
  1         69  
13 1     1   7 use File::Path qw( mkpath );
  1         2  
  1         1196  
14              
15             sub main {
16 0     0 1   my $options = shift;
17             # Just in case we're called as a method.
18 0 0         eval { $options->{module} || 1 } or $options = shift;
  0 0          
19              
20 0           my $tpldir = "templates/". $options->{template};
21 0           my $mod = $options->{module};
22              
23             # Replacement variables
24             my $vars =
25             { "module.name" => $mod, # Foo::Bar
26             "module.version" => "0.01",
27             "module.license" => $options->{license} || "perl_5",
28             "current.year" => $options->{year} || 1900 + (localtime)[5],
29             "author.name" => $options->{author} || (getpwuid($<))[6],
30             "author.email" => $options->{email},
31             "author.cpanid" => $options->{cpanid},
32             "author.githubid" => $options->{githubid},
33 0   0       "perl.minversion" => $options->{minperl} || '5.008000',
      0        
      0        
      0        
34             };
35              
36 0           my $dir;
37 0 0         if ( $options->{'install-templates'} ) {
38 0           $dir = $tpldir;
39             }
40             else {
41 0           ( $dir = $mod ) =~ s/::/-/g;
42 0           $vars->{"module.distname"} = $dir; # Foo-Bar
43 0           $vars->{"module.distnamelc"} = lc($dir);
44 0           ( my $t = $mod ) =~ s/::/\//g;
45 0           $vars->{"module.filename"} = $t . ".pm"; # Foo/Bar.pm
46             $vars->{"author.cpanid"} ||= $1
47             if $options->{email}
48 0 0 0       && $options->{email} =~ /^(.*)\@cpan.org$/i;
      0        
49             $vars->{"author.cpanid"} = uc( $vars->{"author.cpanid"} )
50 0 0         if $vars->{"author.cpanid"};
51             }
52              
53 0 0         if ( -d $dir ) {
54 0           die( "Directory $dir exists. Aborted!\n" );
55             }
56              
57             # Get template names and data.
58 0           my ( $files, $dirs, $data );
59 0           for my $cfg ( "./", @{ $options->{_configs} } ) {
  0            
60 0 0         if ( -d "$cfg$tpldir" ) {
61 0           ( $files, $dirs, $data ) =
62             load_templates_from_directory( "$cfg$tpldir" );
63 0 0         last if $files;
64             }
65             }
66              
67             # Nope. Use built-in defaults.
68 0 0         unless ( $files ) {
69 0 0         unless ( $options->{template} eq "default" ) {
70             warn( "No templates found for ", $options->{template},
71 0           ", using default templates\n" );
72             }
73 0           require App::Module::Setup::Templates::Default;
74 0           ( $files, $dirs, $data ) =
75             App::Module::Setup::Templates::Default->load;
76             }
77              
78 0 0         if ( $options->{'install-templates'} ) {
79 0           warn( "Writing built-in templates to $dir\n" );
80             }
81             else {
82             # Change the magic _Module.pm name to
83             # the module file name.
84 0           for my $file ( @$files ) {
85 0 0         if ( $file =~ /^(.*)_Module.pm$/ ) {
86 0           my $t = $1 . $vars->{"module.filename"};
87 0           push( @$dirs, dirname($t) );
88 0           $data->{$t} = delete $data->{$file};
89 0           $file = $t;
90             }
91             }
92             }
93              
94 0           my $massage;
95 0 0         if ( $options->{'install-templates'} ) {
96 0     0     $massage = sub { $_[0] };
  0            
97             }
98             else {
99 0           require App::Module::Setup::Templates;
100 0           $massage = App::Module::Setup::Templates->can("templater");
101             }
102              
103             # Create the neccessary directories.
104 0           mkpath($dir, $options->{trace}, 0777 );
105 0 0         chdir($dir) or die( "Error creating directory $dir\n" );
106 0           mkpath( $dirs, $options->{trace}, 0777 );
107              
108 0           for my $target ( @$files ) {
109 0           $vars->{" file"} = $target;
110 0 0         open( my $fd, '>', $target )
111             or die( "Error opening ", "$dir/$target: $!\n" );
112 0           print { $fd } $massage->( $data->{$target}, $vars );
  0            
113 0 0         close($fd)
114             or die( "Error writing $target: $!\n" );
115             warn( "Wrote: $dir/$target\n" )
116 0 0         if $options->{verbose};
117             }
118              
119             # Postprocessing, e.g., set up git repo.
120 0           foreach my $cmd ( @{ $options->{postcmd} } ) {
  0            
121 0           system( $cmd );
122             }
123              
124             # If we have a git repo, add all boilerplate files.
125 0 0         if ( -d ".git" ) {
126 0           system( "git", "add", @$files );
127             }
128              
129 0           chdir(".."); # see t/90-ivp.t
130              
131 0           return 1; # assume everything went ok
132             }
133              
134             sub load_templates_from_directory {
135 0     0 0   my ( $dir ) = shift;
136 0           my $dl = length($dir);
137 0 0         $dl++ unless $dir =~ m;/$;;
138 0           my ( $files, $dirs, $data );
139              
140             find( { wanted => sub {
141 0 0   0     return if length($_) < $dl; # skip top
142 0           my $f = substr( $_, $dl ); # file relative to top
143 0 0         if ( -d $_ ) {
144 0           push( @$dirs, $f );
145 0           return;
146             }
147 0 0         return unless -f $_;
148 0 0         return if /~$/;
149              
150 0           push( @$files, $f );
151 0 0         open( my $fd, '<', $_ )
152             or die( "Error reading template $_: $!\n" );
153 0           local $/;
154 0           $data->{$f} = <$fd>;
155 0           close($fd);
156             },
157 0           no_chdir => 1,
158             }, $dir );
159              
160 0           return ( $files, $dirs, $data );
161             }
162              
163              
164             =head1 NAME
165              
166             App::Module::Setup - a simple setup for a new module
167              
168              
169             =head1 SYNOPSIS
170              
171             Nothing in here is meant for public consumption. Use F
172             from the command line.
173              
174             module-setup --author="A.U. Thor" --email=a.u.thor@example.com Foo::Bar
175              
176              
177             =head1 DESCRIPTION
178              
179             This is the core module for App::Module::Setup. If you're not looking
180             to extend or alter the behavior of this module, you probably want to
181             look at L instead.
182              
183             App::Module::Setup is used to create a skeletal CPAN distribution,
184             including basic builder scripts, tests, documentation, and module
185             code. This is done through just one method, C
.
186              
187              
188             =head1 METHODS
189              
190             =head2 App::Module::Setup->main( $options )
191              
192             C
is the only method you should need to use from outside this
193             module; all the other methods are called internally by this one.
194              
195             This method creates the distribution and populates it with the all the
196             requires files.
197              
198             It takes a reference to a hash of params, as follows:
199              
200             module # module to create in distro
201             version # initial version
202             author # author's full name (taken from C if not provided)
203             email # author's email address
204             verbose # bool: print progress messages; defaults to 0
205             template # template set to use
206             postcmd # array ref of commands to execute after creating
207             install-templates # bool: just install the selected templates
208             minperl # minimal perl version, e.g. 5.010000
209             license # e.g. perl_5
210              
211             =cut
212              
213              
214             =head1 AUTHOR
215              
216             Johan Vromans, C<< >>
217              
218             =head1 BUGS
219              
220             Please report any bugs or feature requests to C, or through
221             the web interface at L. I will be notified, and then you'll
222             automatically be notified of progress on your bug as I make changes.
223              
224             =head1 SUPPORT
225              
226             Development of this module takes place on GitHub:
227             https://github.com/sciurius/perl-module-starter.
228              
229             You can find documentation for this module with the perldoc command.
230              
231             perldoc App::Module::Setup
232              
233             Please report any bugs or feature requests using the issue tracker on
234             GitHub.
235              
236             =head1 ACKNOWLEDGEMENTS
237              
238             David Golden, for giving me the final incentive to write this module.
239              
240             I borrowed many ideas from L which was originally
241             written by Andy Lester (PETDANCE). Its current design came from
242             Ricardo Signes (RJBS). Sawyer X added features and maintains the
243             module after them.
244              
245             =head1 COPYRIGHT & LICENSE
246              
247             Copyright 2013,2018 Johan Vromans, all rights reserved.
248              
249             This program is free software; you can redistribute it and/or modify it
250             under the same terms as Perl itself.
251              
252              
253             =cut
254              
255             1; # End of App::Module::Setup