File Coverage

blib/lib/App/Module/Setup.pm
Criterion Covered Total %
statement 18 105 17.1
branch 0 52 0.0
condition 0 19 0.0
subroutine 6 10 60.0
pod 1 2 50.0
total 25 188 13.3


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