File Coverage

blib/lib/Kelp/Generator.pm
Criterion Covered Total %
statement 54 54 100.0
branch 7 10 70.0
condition n/a
subroutine 7 7 100.0
pod 3 3 100.0
total 71 74 95.9


line stmt bran cond sub pod time code
1             package Kelp::Generator;
2              
3 3     3   20 use Kelp::Base;
  3         7  
  3         23  
4 3     3   2725 use Path::Tiny;
  3         51356  
  3         203  
5 3     3   1486 use Kelp::Template;
  3         9  
  3         15  
6 3     3   15 use Carp;
  3         5  
  3         3252  
7              
8             attr -templates_dir => sub { path(__FILE__)->parent . '/templates' };
9              
10             sub list_templates
11             {
12 2     2 1 5 my ($self) = @_;
13              
14 2         17 my $dir = $self->templates_dir;
15 2         454 return map { path($_)->basename } glob "$dir/*";
  4         148  
16             }
17              
18             sub get_template_files
19             {
20 1     1 1 4 my ($self, $template) = @_;
21              
22 1         6 my $dir = $self->templates_dir;
23              
24             # instead of just globbing for files, introduce template files that will
25             # list all the files for a template (otherwise any old files will just stay
26             # there and be generated in new versions)
27 1         5 my ($index_file) = map { "$dir/$_/template" }
28 1         270 grep { $_ eq $template }
  2         68  
29             $self->list_templates
30             ;
31 1 50       7 return unless $index_file;
32              
33 1         3 my $index = path($index_file);
34 1 50       39 return unless $index->is_file;
35              
36 1         45 my @files = map { s/^\s+//; s/\s+$//; $_ } $index->lines({chomp => 1});
  11         401  
  11         66  
  11         21  
37 1         5 return map { "$dir/$template/$_" } grep { length } @files;
  10         26  
  11         18  
38             }
39              
40             sub get_template
41             {
42 2     2 1 9 my ($self, $template, $name, %args) = @_;
43              
44 2 100       9 croak "Invalid name $name - not a Perl package name"
45             unless $name =~ m/^[\w:]+$/;
46              
47 1         4 my $vars = {name => $name, %args};
48 1         5 my @parts = split(/::/, $name);
49 1         4 $vars->{module_file} = pop @parts;
50 1         4 $vars->{module_path} = join('/', @parts);
51              
52 1         6 my @list = $self->get_template_files($template);
53 1 50       5 croak "There's no generation template for $template"
54             unless @list > 0;
55              
56 1         3 my @retval;
57 1         15 my $tt = Kelp::Template->new();
58 1         3 for my $path (@list) {
59 10         34 my $file = path($path);
60              
61             # resolve the destination name
62             # hyphens become directory separators
63 10         483 (my $dest_file = $file->basename) =~ s{-}{/}g;
64 10         511 $dest_file =~ s/NAME/$vars->{name}/g;
65 10         28 $dest_file =~ s/PATH/$vars->{module_path}/g;
66 10         20 $dest_file =~ s/FILE/$vars->{module_file}/g;
67 10         20 $dest_file =~ s/DOT/./g;
68              
69             # process the template, if it is .gen (generated)
70 10         48 my $contents = $file->slurp({binmode => ':encoding(UTF-8)'});
71 10 100       5425 if ($dest_file =~ /\.gen$/) {
72 9         37 $dest_file =~ s/\.gen$//;
73 9         40 $contents = $tt->process(\$contents, $vars);
74             }
75              
76 10         65 push @retval, [$dest_file, $contents];
77             }
78              
79 1         27 return \@retval;
80             }
81              
82             1;
83              
84             =pod
85              
86             =head1 NAME
87              
88             Kelp::Generator - Generation templates
89              
90             =head1 SYNOPSIS
91              
92             use Kelp::Generator;
93              
94             my $gen = Kelp::Generator->new;
95             # get available templates
96             my @template = $gen->list_templates;
97              
98             # get parsed files (ready to be saved)
99             my $files_aref = $gen->get_template($template, 'App::Name');
100              
101             for my $file (@$files_aref) {
102             my ($file_name, $file_contents) = @$file;
103             }
104              
105             =head1 DESCRIPTION
106              
107             This is a class for discovery and parsing of generation templates for Kelp. A
108             generation template is a set of files that can be parsed using
109             L<Template::Tiny> and inserted into a given directory. This class only handles
110             the discovery and parsing of these templates. The C<kelp-generator> script or
111             custom script should handle saving them in a destination directory.
112              
113             =head1 TEMPLATE CREATION
114              
115             =head2 Discovery
116              
117             This class will look into a directory in its installation tree to discover
118             available templates. The folder is C<Kelp/templates> by default and can be
119             changed by constructing the object with different C<templates_dir> attribute.
120             This means that CPAN modules can add templates to L<Kelp/templates> and they
121             will be discovered as long as they have been installed in the same root
122             directory as Kelp without changing the contents of the package variable. Any
123             template that can be discovered in the default directory will be usable in the
124             C<kelp-generator> script.
125              
126             =head2 Contents
127              
128             The directory structure of C<Kelp/templates> directory is as follows:
129              
130             + templates
131             | + template_name
132             | - template
133             | - file1.pl.gen
134             | - NAME.pm.gen
135             | + another_template_name
136             | - template
137             | - file1.tt
138              
139             Each template directory must have a file named C<template>, which lists all the
140             files in that template like this:
141              
142             file1.pl.gen
143             NAME.pm.gen
144              
145             Any file that is not listed will not be used.
146              
147             =head2 Template files
148              
149             Each template file can contain L<Template> code:
150              
151             My::App::Name eq [% name %]
152             Name eq [% module_file %]
153             My/App eq [% module_path %]
154              
155             It will be replaced accordingly, but only if the file ends with C<.gen>
156             extension. This extension also allows template files not to be confused with
157             real files, so should be used most of the time. The only case where the C<.gen>
158             extension should not be used in when generating template files using the same
159             syntax as L<Template>, because there's no way to tell which directives should
160             not be interpreted right away.
161              
162             Files can also contain NAME, FILE, PATH and DOT in their name, which will be
163             replaced by C<name>, C<module_file>, C<module_path> and C<.>.
164              
165             =head1 INTERFACE
166              
167             =head2 Methods
168              
169             =head3 new
170              
171             my $gen = Kelp::Generator->new(templates_dir => $dir);
172              
173             Constructs a Kelp::Generator instance. C<templates_dir> is optional.
174              
175             =head3 templates_dir
176              
177             Returns the current templates directory. Can be changed by passing an argument
178             of this name to C<new>
179              
180             =head3 get_template
181              
182             my $template_aref = $gen->get_template($template_name, $application_name, %more_vars);
183              
184             Finds and parses template with L<Template::Tiny>, returning an array reference of files:
185              
186             ['file1.pl', 'contents'],
187             ['replaced_name.pm', 'contents'],
188             ...
189              
190             Filenames will have directories and C<.gen> suffix stripped and all
191             placeholders replaced. File contents will be ready for saving.
192              
193             C<%more_vars> can be specified to insert more variables into the template.
194              
195             =head3 list_templates
196              
197             my @templates = $gen->list_templates;
198              
199             Discovers and returns all the generation template names as a list.
200              
201             =head3 get_template_files
202              
203             my @files = $gen->get_template_files($template_name);
204              
205             Returns the list of template files for a given template. Will return full
206             paths, not just file names.
207              
208             =cut
209