—use
v5.40;
package
Minima::Project;
use
File::Share;
use
Path::Tiny;
use
Template;
our
$tdir
= path(
File::Share::dist_dir(
'Minima'
)
)->child(
'/templates'
);
our
$verbose
= 0;
sub
create (
$dir
,
$user_config
= {})
{
my
$project
= path(
$dir
//
'.'
)->absolute;
my
%config
= (
'static'
=> 1,
'verbose'
=> 0,
%$user_config
);
$verbose
=
$config
{verbose};
# Test if directory can be used
if
(
$project
->
exists
) {
die
"Project destination must be a directory\n"
unless
$project
->is_dir;
die
"Project destination must be empty.\n"
if
$project
->children;
}
else
{
$project
->
mkdir
;
}
chdir
$project
;
# Create files
for
my
(
$file
,
$content
) (get_templates(\
%config
)) {
my
$dest
= path(
$file
);
my
$dir
=
$dest
->parent;
unless
(
$dir
->is_dir) {
_info(
"mkdir $dir"
);
$dir
->
mkdir
;
}
_info(
" spew $dest"
);
$dest
->spew_utf8(
$content
);
}
}
sub
get_templates (
$config
)
{
my
%files
;
my
$tt
= Template->new(
INCLUDE_PATH
=>
$tdir
,
OUTLINE_TAG
=>
'@@'
,
TAG_STYLE
=>
'star'
,
);
$config
->{version} = Minima->VERSION;
foreach
(
glob
"$tdir/*.[sd]tpl"
) {
my
$content
= path(
$_
)->slurp_utf8;
$_
= path(
$_
)->basename;
tr
|-|/|;
tr
|+|.|;
if
(/\.dtpl$/) {
# Process .d(ynamic) template
my
$template
=
$content
;
my
$processed
;
$tt
->process(\
$template
,
$config
, \
$processed
);
$content
=
$processed
;
}
s/\.\w+$//;
$files
{
$_
} =
$content
;
}
map
{
$_
,
$files
{
$_
} }
sort
keys
%files
;
}
sub
_info (
$m
)
{
say
$m
if
(
$verbose
);
}
1;
__END__
=head1 NAME
Minima::Project - Backend for L<minima>, the project manager
=head1 SYNOPSIS
use Minima::Project;
Minima::Project::create('app');
=head1 DESCRIPTION
This module is not intended to be used directly by third parties. It is
the backend for L<minima(1)|minima>. No functions are exported by
default.
Templates used for generating projects reside in Minima's F<lib>, which
is stored in a package variable named C<$tdir>. Templates can have two
extensions:
=over 8
=item F<.stpl>
Static templates, which are copied directly.
=item F<.dtpl>
Dynamic templates, which are processed with
L<Template::Toolkit|Template> and then copied.
=back
The C<.[sd]> extensions are removed and the template name is converted
to a proper path by L<C<get_templates>|/get_templates>.
=head1 SUBROUTINES
=head2 create
sub create ($dir, $config)
Creates a project at C<$dir> with the specified configuration, passed as
a hash reference in C<$config>. The configuration is forwarded to the
templates and is optional.
If the directory is either not empty or not a directory at all, it dies.
This subroutine calls L<C<get_templates>|/get_templates> to retrieve
information about what needs to be generated and where.
=head2 get_templates
sub get_templates ($config)
Gets the available templates, processes them, and returns a hash
reference containing the paths as keys and contents as values.
Templates are stored in flattened files. This subroutine converts dashes
to directory slashes and plus signs to dots, allowing all template files
to be stored together in a visible structure, even if they represent
hidden files.
=head1 SEE ALSO
L<Minima(3)|Minima>, L<minima(1)|minima>.
=head1 AUTHOR
Cesar Tessarin, <cesar@tessarin.com.br>.
Written in September 2024.