File Coverage

blib/lib/MojoX/CustomTemplateFileParser.pm
Criterion Covered Total %
statement 155 159 97.4
branch 41 46 89.1
condition 11 17 64.7
subroutine 13 14 92.8
pod 0 2 0.0
total 220 238 92.4


line stmt bran cond sub pod time code
1             package MojoX::CustomTemplateFileParser;
2              
3 4     4   174215 use strict;
  4         8  
  4         109  
4 4     4   21 use warnings;
  4         8  
  4         107  
5 4     4   48 use 5.10.1;
  4         13  
6             our $VERSION = '0.1002'; # VERSION
7             # ABSTRACT: Parses a custom Mojo template file format (deprecated)
8              
9 4     4   3525 use Moose;
  4         1918099  
  4         27  
10             with 'MooseX::Object::Pluggable';
11              
12 4     4   31640 use HTML::Entities;
  4         25074  
  4         326  
13 4     4   4925 use Path::Tiny();
  4         37556  
  4         122  
14 4     4   4041 use Storable qw/dclone/;
  4         15331  
  4         6489  
15              
16             has path => (
17             is => 'ro',
18             isa => 'Str',
19             required => 1,
20             );
21             has structure => (
22             is => 'rw',
23             isa => 'HashRef',
24             default => sub { { } },
25             );
26             has test_index => (
27             is => 'rw',
28             isa => 'HashRef',
29             default => sub { { } },
30             );
31             has output => (
32             is => 'ro',
33             isa => 'ArrayRef',
34             default => sub { [ ] },
35             );
36              
37             sub BUILD {
38 4     4 0 6828 my $self = shift;
39 4         17 $self->_parse;
40              
41 4         6 foreach my $plugin (@{ $self->output } ) {
  4         229  
42 3         96 $self->load_plugin("To::$plugin");
43             }
44             }
45              
46             sub _parse {
47 4     4   7 my $self = shift;
48 4         20 my $baseurl = $self->_get_baseurl;
49 4         184 my @lines = split /\n/ => Path::Tiny::path($self->path)->slurp;
50              
51             # matches ==test== ==no test== ==test loop(a thing or two)== ==test example ==test 1== ==test example 2==
52 4         952 my $test_start = qr/==(?:(NO) )?TEST(?: loop\(([^)]+)\))?( EXAMPLE)?(?: (?:\d+))?==/i;
53 4         10 my $template_separator = '--t--';
54 4         9 my $expected_separator = '--e--';
55              
56 4         7 my $environment = 'head';
57              
58 4         24 my $info = {
59             head_lines => [],
60             tests => [],
61             indexed => {},
62             };
63 4         10 my $test = {};
64              
65 4         25 my $row = 0;
66 4         60 my $testcount = 0;
67              
68             LINE:
69 4         13 foreach my $line (@lines) {
70 156         182 ++$row;
71              
72 156 100       318 if($environment eq 'head') {
73 16 100       109 if($line =~ $test_start) {
74              
75 4         12 my $skipit = $1;
76 4 50       23 $test->{'loop'} = defined $2 ? [ split / / => $2 ] : [];
77 4         16 $test = $self->_reset_test();
78              
79 4 50 33     24 if(defined $skipit && $skipit eq lc 'no') {
80 0         0 $test->{'skip'} = $skipit;
81             }
82              
83 4         6 push @{ $info->{'head_lines'} } => '';
  4         14  
84 4         10 $test->{'test_number'} = ++$testcount;
85 4 50       17 $test->{'is_example'} = defined $3 ? 1 : 0;;
86 4         10 $test->{'test_start_line'} = $row;
87 4         6 $test->{'test_number'} = $testcount;
88 4         33 $test->{'test_name'} = sprintf '%s_%s' => $baseurl, $testcount;
89 4         6 $environment = 'beginning';
90              
91 4         10 next LINE;
92             }
93 12         16 push @{ $info->{'head_lines'} } => $line;
  12         31  
94 12         24 next LINE;
95             }
96 140 100       279 if($environment eq 'beginning') {
97 24 100       58 if($line eq $template_separator) {
98 16         24 $environment = 'template';
99 16         26 next LINE;
100             }
101 8         12 push @{ $test->{'lines_before'} } => $line;
  8         20  
102 8         16 next LINE;
103             }
104 116 100       224 if($environment eq 'template') {
105 32 100       70 if($line eq $template_separator) {
106 16 100       23 if(scalar @{ $test->{'lines_template'} }) {
  16         45  
107 12         15 unshift @{ $test->{'lines_template'} } => '';
  12         29  
108 12         20 push @{ $test->{'lines_template'} } => '';
  12         24  
109             }
110 16         23 $environment = 'between';
111 16         30 next LINE;
112             }
113             # If we have no template lines, don't push empty lines.
114             # This way we can avoid empty templates, meaning we can leave empty test blocks in the
115             # source files without messing up the tests.
116 16 100 66     18 push @{ $test->{'lines_template'} } => $line if scalar @{ $test->{'lines_template'} } || $line !~ m{^\s*$};
  12         27  
  16         128  
117 16         36 next LINE;
118             }
119 84 100       167 if($environment eq 'between') {
120 24 100       54 if($line eq $expected_separator) {
121 16         25 $environment = 'expected';
122 16         23 next LINE;
123             }
124 8         15 push @{ $test->{'lines_between'} } => $line;
  8         21  
125 8         18 next LINE;
126             }
127 60 100       128 if($environment eq 'expected') {
128 32 100       71 if($line eq $expected_separator) {
129 16         23 $environment = 'ending';
130 16 50       19 if(scalar @{ $test->{'lines_expected'} }) {
  16         49  
131 16         19 unshift @{ $test->{'lines_expected'} } => '';
  16         34  
132 16         23 push @{ $test->{'lines_expected'} } => '';
  16         29  
133             }
134 16         33 next LINE;
135             }
136 16         19 push @{ $test->{'lines_expected'} } => $line;
  16         36  
137 16         36 next LINE;
138             }
139 28 50       67 if($environment eq 'ending') {
140 28 100       164 if($line =~ $test_start) {
141 12         44 $self->_add_test($info, $test);
142              
143 12         28 $test = $self->_reset_test();
144 12         52 my $skipit = $1;
145 12 100 66     53 if(defined $skipit && $skipit eq lc 'no') {
146 4         9 $test->{'skip'} = 1;
147             }
148 12 100       54 $test->{'loop'} = defined $2 ? [ split / / => $2 ] : [];
149 12         26 $test->{'test_start_line'} = $row;
150 12         19 $test->{'test_number'} = ++$testcount;;
151 12   50     61 $test->{'is_example'} = $3 || 0;
152 12         45 $test->{'test_name'} = sprintf '%s_%s' => $baseurl, $testcount;
153 12         19 $environment = 'beginning';
154              
155 12         25 next LINE;
156             }
157 16 100 100     21 push @{ $test->{'lines_after'} } => $line if scalar @{ $test->{'lines_after'} } || $line !~ m{^\s*$};
  8         19  
  16         101  
158 16         32 next LINE;
159             }
160             }
161              
162 4         13 $self->_add_test($info, $test);
163              
164 4         199 $self->test_index(delete $info->{'indexed'});
165 4         181 $self->structure($info);
166              
167 4         36 return $self;
168             }
169              
170             sub test_count {
171 0     0 0 0 my $self = shift;
172 0         0 return keys %{ $self->{'test_index'} };
  0         0  
173             }
174              
175             sub _add_test {
176 16     16   25 my $self = shift;
177 16         23 my $info = shift;
178 16         23 my $test = shift;
179              
180             #* Nothing to test
181 16 100 66     23 return if !scalar @{ $test->{'lines_template'} } || $test->{'skip'};
  16         89  
182              
183             #* No loop, just add it
184 8 100       12 if(!scalar @{ $test->{'loop'} }) {
  8         26  
185 4         6 push @{ $info->{'tests'} } => $test;
  4         10  
186 4         16 $info->{'indexed'}{ $test->{'test_number'} } = [ $test ];
187 4         9 return;
188             }
189 4         25 $info->{'indexed'}{ $test->{'test_number'} } = [ ];
190              
191 4         14 foreach my $var (@{ $test->{'loop'} }) {
  4         11  
192 8         584 my $copy = dclone $test;
193              
194 8         14 map { $_ =~ s{\[var\]}{$var}g } @{ $copy->{'lines_template'} };
  24         125  
  8         19  
195 8         15 map { $_ =~ s{\[var\]}{$var}g } @{ $copy->{'lines_expected'} };
  24         56  
  8         16  
196 8         18 $copy->{'loop_variable'} = $var;
197 8         19 $copy->{'test_name'} .= "_$var";
198 8         11 push @{ $info->{'tests'} } => $copy;
  8         18  
199 8         11 push @{ $info->{'indexed'}{ $copy->{'test_number'} } } => $copy;
  8         24  
200             }
201 4         11 return;
202              
203             }
204              
205             sub _reset_test {
206 16     16   26 my $self = shift;
207             return {
208 16         124 is_example => 0,
209             lines_before => [],
210             lines_template => [],
211             lines_after => [],
212             lines_between => [],
213             lines_expected => [],
214             test_number => undef,
215             test_start_line => undef,
216             test_name => undef,
217             loop => [],
218             loop_variable => undef,
219             };
220             }
221              
222             sub _get_filename {
223 6     6   266 return Path::Tiny::path(shift->path)->basename;
224             }
225              
226             sub _get_baseurl {
227 5     5   9 my $self = shift;
228 5         22 my $filename = $self->_get_filename;
229 5         573 (my $baseurl = $filename) =~ s{^([^\.]+)\..*}{$1}; # remove suffix
230 5         23 $baseurl =~ s{-}{_};
231 5         16 return $baseurl;
232             }
233              
234             1;
235              
236             __END__
237              
238             =pod
239              
240             =encoding UTF-8
241              
242             =head1 NAME
243              
244             MojoX::CustomTemplateFileParser - Parses a custom Mojo template file format (deprecated)
245              
246              
247              
248             =begin HTML
249              
250             <p><img src="https://img.shields.io/badge/perl-5.14+-brightgreen.svg" alt="Requires Perl 5.14+" /> <a href="https://travis-ci.org/Csson/p5-mojox-customtemplatefileparser"><img src="https://api.travis-ci.org/Csson/p5-mojox-customtemplatefileparser.svg?branch=master" alt="Travis status" /></a></p>
251              
252             =end HTML
253              
254              
255             =begin markdown
256              
257             ![Requires Perl 5.14+](https://img.shields.io/badge/perl-5.14+-brightgreen.svg) [![Travis status](https://api.travis-ci.org/Csson/p5-mojox-customtemplatefileparser.svg?branch=master)](https://travis-ci.org/Csson/p5-mojox-customtemplatefileparser)
258              
259             =end markdown
260              
261             =head1 VERSION
262              
263             Version 0.1002, released 2015-11-26.
264              
265             =head1 SYNOPSIS
266              
267             use MojoX::CustomTemplateFileParser;
268              
269             my $parser = MojoX::CustomTemplateFileParser->new(path => '/path/to/file.mojo', output => [qw/Html Pod Test]);
270              
271             print $parser->to_html;
272             print $parser->to_pod;
273             print $parser->to_test;
274              
275             =head1 STATUS
276              
277             Deprecated. Replaced by L<Stenciller>.
278              
279             =head1 DESCRIPTION
280              
281             MojoX::CustomTemplateFileParser parses files containing L<Mojo::Templates|Mojo::Template> mixed with the expected rendering.
282              
283             The parsing creates a data structure that can be output in various formats using plugins.
284              
285             Its purpose is to facilitate development of tag helpers.
286              
287             =head2 Options
288              
289             B<C<path>>
290              
291             The path to the file that should be parsed. Parsing occurs at object creation.
292              
293             B<C<output>>
294              
295             An array reference to plugins in the C<::Plugin::To> namespace.
296              
297             =head2 Methods
298              
299             No public methods. See plugins for output options.
300              
301             =head1 PLUGINS
302              
303             Currently available plugins:
304              
305             =over 4
306              
307             =item *
308              
309             L<MojoX::CustomTemplateFileParser::To::Html>
310              
311             =item *
312              
313             L<MojoX::CustomTemplateFileParser::To::Pod>
314              
315             =item *
316              
317             L<MojoX::CustomTemplateFileParser::To::Test>
318              
319             =back
320              
321             =head1 SEE ALSO
322              
323             =over 4
324              
325             =item *
326              
327             L<Dist::Zilla::Plugin::Test::CreateFromMojoTemplates>
328              
329             =item *
330              
331             L<Dist::Zilla::Plugin::InsertExample::FromMojoTemplates>
332              
333             =back
334              
335             =head1 SOURCE
336              
337             L<https://github.com/Csson/p5-mojox-customtemplatefileparser>
338              
339             =head1 HOMEPAGE
340              
341             L<https://metacpan.org/release/MojoX-CustomTemplateFileParser>
342              
343             =head1 AUTHOR
344              
345             Erik Carlsson <info@code301.com>
346              
347             =head1 COPYRIGHT AND LICENSE
348              
349             This software is copyright (c) 2015 by Erik Carlsson.
350              
351             This is free software; you can redistribute it and/or modify it under
352             the same terms as the Perl 5 programming language system itself.
353              
354             =cut