App-Module-Template
view release on metacpan or search on metacpan
lib/App/Module/Template.pm view on Meta::CPAN
package App::Module::Template;
use 5.016;
use strict;
use warnings;
our $VERSION = '0.11';
use base qw(Exporter);
use App::Module::Template::Initialize;
use Carp;
use Config::General;
use File::Copy;
use File::HomeDir;
use File::Path qw/make_path/;
use File::Spec;
use Getopt::Std;
use POSIX qw(strftime);
use Template;
use Try::Tiny;
our (@EXPORT_OK, %EXPORT_TAGS);
@EXPORT_OK = qw(
run
_get_config
_get_config_path
_get_module_dirs
_get_module_fqfn
_get_template_path
_module_path_exists
_process_dirs
_process_file
_process_template
_validate_module_name
);
%EXPORT_TAGS = (
ALL => [ @EXPORT_OK ],
);
#-------------------------------------------------------------------------------
sub run {
my $class = shift;
my %opt;
# -c config file
# -m module name
# -t template dir, location of template files
getopts('c:m:t:', \%opt);
unless ( ( exists $opt{m} ) and ( defined $opt{m} ) ) {
croak "-m <Module::Name> is required. exiting...\n";
}
my $module = $opt{m};
my $dist = $module; $dist =~ s/::/-/gmsx;
my $file = $module; $file =~ s/.*:://msx; $file .= '.pm';
my $dist_dir = File::Spec->catdir( File::Spec->curdir, $dist );
my $tmpl_vars;
try {
_validate_module_name($module);
} catch {
croak "$_ module-template. exiting...";
};
if ( _module_path_exists($dist_dir) ) {
croak "Destination directory $dist_dir exists. exiting...";
}
my $template_dir = _get_template_path($opt{t});
my $config_file = _get_config_path($opt{c}, $template_dir);
my $cfg = _get_config($config_file);
# Setting this lets TT2 handle creating the destination files/directories
$cfg->{template_toolkit}{OUTPUT_PATH} = $dist_dir;
my $tt2 = Template->new( $cfg->{template_toolkit} );
# don't need this in the $tmpl_vars
delete $cfg->{template_toolkit};
my $dirs = _get_module_dirs( $module );
# Template Vars
$tmpl_vars = $cfg;
$tmpl_vars->{module} = $module;
$tmpl_vars->{today} = strftime('%Y-%m-%d', localtime());
$tmpl_vars->{year} = strftime('%Y', localtime());
$tmpl_vars->{module_path} = File::Spec->catfile( @{$dirs}, $file );
_process_dirs($tt2, $tmpl_vars, $template_dir, $template_dir);
# add the distribution dir to the front so our module ends up in the
# right place
unshift @{$dirs}, $dist_dir;
my $fqfn = _get_module_fqfn( $dirs, $file );
# create the module directory to receive the named module.pm
make_path( File::Spec->catdir( @{$dirs} ) );
# rename the template file with the module file name
move( File::Spec->catfile( $dist_dir, 'lib', 'Module.pm' ), $fqfn );
return 1;
}
#-------------------------------------------------------------------------------
sub _get_config {
my ($config_file) = @_;
my %cfg = Config::General->new(
-ConfigFile => $config_file,
-MergeDuplicateBlocks => 1,
-MergeDuplicateOptions => 1,
-AutoLaunder => 1,
-SplitPolicy => 'equalsign',
-InterPolateVars => 1,
-UTF8 => 1,
lib/App/Module/Template.pm view on Meta::CPAN
#-------------------------------------------------------------------------------
# Walk the template directory
#-------------------------------------------------------------------------------
sub _process_dirs {
my ($tt2, $tmpl_vars, $template_dir, $source) = @_;
if ( -d $source ) {
my $dir;
unless ( opendir $dir, $source ) {
croak "Couldn't open directory $source: $!; skipping.\n";
}
while ( my $file = readdir $dir ) {
next if $file eq '.' or $file eq '..';
my $target = File::Spec->catfile($source, $file);
_process_dirs($tt2, $tmpl_vars, $template_dir, $target);
}
closedir $dir;
}
else {
my $output = _process_file($template_dir, $source);
_process_template($tt2, $tmpl_vars, $source, $output);
}
return $source;
}
#-------------------------------------------------------------------------------
# Return the output path for TT2
#-------------------------------------------------------------------------------
sub _process_file {
my ($template_dir, $source_file) = @_;
# regex matches paths on *nix or *dos
my ($stub) = $source_file =~ m{\A$template_dir[/\\](.*)\z}mosx;
return $stub;
}
#-------------------------------------------------------------------------------
sub _process_template {
my ($tt2, $tmpl_vars, $template, $output) = @_;
$tt2->process($template, $tmpl_vars, $output) or croak $tt2->error();
return $template;
}
#-------------------------------------------------------------------------------
# Validate the module naming convention
#
# 1. No top-level namespaces
# 2. No all lower case names
# 3. Match XXX::XXX
#-------------------------------------------------------------------------------
sub _validate_module_name {
my ($module_name) = @_;
given ( $module_name ) {
when ( $module_name =~ m/\A[A-Za-z]+\z/msx )
{
croak "'$module_name' is a top-level namespace";
}
when ( $module_name =~ m/\A[a-z]+\:\:[a-z]+/msx )
{
croak "'$module_name' is an all lower-case namespace";
}
# module name conforms
when ( $module_name =~ m/\A[A-Z][A-Za-z]+(?:\:\:[A-Z][A-Za-z]+)+\z/msx )
{
return 1;
}
default {
croak "'$module_name' does not meet naming requirements";
}
}
}
1;
__END__
=pod
=head1 NAME
App::Module::Template - Perl module scaffolding with Template Toolkit
=head1 VERSION
This documentation refers to App::Module::Template version 0.11.
=head1 SYNOPSIS
use App::Module::Template;
App::Module::Template->run(@ARGS);
=head1 DESCRIPTION
App::Module::Template contains the subroutines to support 'module-template'. See module-template for usage.
=head1 SUBROUTINES/METHODS
=over
=item C<run>
This function is called by module-template to execute logic of the program.
=back
=head1 DIAGNOSTICS
None.
( run in 1.451 second using v1.01-cache-2.11-cpan-5b529ec07f3 )