File Coverage

blib/lib/Text/Xslate/Bridge/TT2Like.pm
Criterion Covered Total %
statement 207 280 73.9
branch 51 134 38.0
condition 10 34 29.4
subroutine 62 78 79.4
pod n/a
total 330 526 62.7


line stmt bran cond sub pod time code
1             package Text::Xslate::Bridge::TT2Like;
2 5     5   321790 use 5.008001;
  5         21  
  5         218  
3 5     5   29 use strict;
  5         8  
  5         169  
4 5     5   26 use warnings;
  5         33  
  5         264  
5 5     5   28 use base qw(Text::Xslate::Bridge);
  5         10  
  5         7440  
6              
7             our $VERSION = '0.00010';
8              
9 5     5   12248 use Scalar::Util 'blessed';
  5         11  
  5         1464  
10 5     5   32 use Text::Xslate;
  5         11  
  5         12311  
11              
12             our $TRUNCATE_LENGTH = 32;
13             our $TRUNCATE_ADDON = '...';
14              
15             __PACKAGE__->bridge(
16             scalar => {
17             item => \&_text_item,
18             list => \&_text_list,
19             hash => \&_text_hash,
20             length => \&_text_length,
21             size => \&_text_size,
22             defined => \&_text_defined,
23             match => \&_text_match,
24             search => \&_text_search,
25             repeat => \&_text_repeat,
26             replace => \&_text_replace,
27             remove => \&_text_remove,
28             split => \&_text_split,
29             chunk => \&_text_chunk,
30             substr => \&_text_substr,
31             },
32             hash => {
33             item => \&_hash_item,
34             hash => \&_hash_hash,
35             size => \&_hash_size,
36             each => \&_hash_each,
37             keys => \&_hash_keys,
38             values => \&_hash_values,
39             items => \&_hash_items,
40             pairs => \&_hash_pairs,
41             list => \&_hash_list,
42             exists => \&_hash_exists,
43             defined => \&_hash_defined,
44             delete => \&_hash_delete,
45             import => \&_hash_import,
46             sort => \&_hash_sort,
47             nsort => \&_hash_nsort,
48             },
49             array => {
50             item => \&_list_item,
51             list => \&_list_list,
52             hash => \&_list_hash,
53             push => \&_list_push,
54             pop => \&_list_pop,
55             unshift => \&_list_unshift,
56             shift => \&_list_shift,
57             max => \&_list_max,
58             size => \&_list_size,
59             defined => \&_list_defined,
60             first => \&_list_first,
61             last => \&_list_last,
62             reverse => \&_list_reverse,
63             grep => \&_list_grep,
64             join => \&_list_join,
65             sort => \&_list_sort,
66             nsort => \&_list_nsort,
67             unique => \&_list_unique,
68             import => \&_list_import,
69             merge => \&_list_merge,
70             slice => \&_list_slice,
71             splice => \&_list_splice,
72             },
73             function => {
74             # 'html' => \&_html_filter, # Xslate has builtin filter for html escape, and it is not overridable.
75             html_para => Text::Xslate::html_builder(\&_html_paragraph),
76             html_break => Text::Xslate::html_builder(\&_html_para_break),
77             html_para_break => Text::Xslate::html_builder(\&_html_para_break),
78             html_line_break => Text::Xslate::html_builder(\&_html_line_break),
79             xml => Text::Xslate::html_builder(\&_xml_filter),
80             # 'uri' => \&uri_escape, # builtin from version 0.1052
81             url => \&Text::Xslate::uri_escape,
82             upper => sub { uc $_[0] },
83             lower => sub { lc $_[0] },
84             ucfirst => sub { ucfirst $_[0] },
85             lcfirst => sub { lcfirst $_[0] },
86             # 'stderr' => sub { print STDERR @_; return '' }, # anyone want this??
87             trim => sub { for ($_[0]) { s/^\s+//; s/\s+$// }; $_[0] },
88             null => sub { return '' },
89             collapse => sub { for ($_[0]) { s/^\s+//; s/\s+$//; s/\s+/ /g };
90             $_[0] },
91             indent => \&_indent_filter_factory,
92             format => \&_format_filter_factory,
93             truncate => \&_truncate_filter_factory,
94             repeat => \&_repeat_filter_factory,
95             replace => \&_replace_filter_factory,
96             remove => \&_remove_filter_factory,
97             },
98             );
99              
100             sub _text_item {
101 0     0   0 $_[0];
102             }
103              
104             sub _text_list {
105 0     0   0 [ $_[0] ];
106             }
107              
108             sub _text_hash {
109 0     0   0 { value => $_[0] };
110             }
111              
112             sub _text_length {
113 1     1   2738260 length $_[0];
114             }
115              
116             sub _text_size {
117 1     1   2531 return 1;
118             }
119              
120             sub _text_defined {
121 0     0   0 return 1;
122             }
123              
124             sub _text_match {
125 1     1   3619 my ($str, $search, $global) = @_;
126 1 50 33     12 return $str unless defined $str and defined $search;
127 1 50       19 my @matches = $global ? ($str =~ /$search/g)
128             : ($str =~ /$search/);
129 1 50       10 return @matches ? \@matches : '';
130             }
131              
132             sub _text_search {
133 2     2   13452 my ($str, $pattern) = @_;
134 2 50 33     20 return $str unless defined $str and defined $pattern;
135 2         68 return $str =~ /$pattern/;
136             }
137              
138             sub _text_repeat {
139 0     0   0 my ($str, $count) = @_;
140 0 0       0 $str = '' unless defined $str;
141 0 0       0 return '' unless $count;
142 0   0     0 $count ||= 1;
143 0         0 return $str x $count;
144             }
145              
146             sub _text_replace {
147 1     1   3787 my ($text, $pattern, $replace, $global) = @_;
148 1 50       6 $text = '' unless defined $text;
149 1 50       3 $pattern = '' unless defined $pattern;
150 1 50       4 $replace = '' unless defined $replace;
151 1 50       3 $global = 1 unless defined $global;
152              
153 1 50       7 if ($replace =~ /\$\d+/) {
154             # replacement string may contain backrefs
155             my $expand = sub {
156 0     0   0 my ($chunk, $start, $end) = @_;
157 0         0 $chunk =~ s{ \\(\\|\$) | \$ (\d+) }{
158 0 0 0     0 $1 ? $1
    0          
159             : ($2 > $#$start || $2 == 0) ? ''
160             : substr($text, $start->[$2], $end->[$2] - $start->[$2]);
161             }exg;
162 0         0 $chunk;
163 0         0 };
164 0 0       0 if ($global) {
165 0         0 $text =~ s{$pattern}{ &$expand($replace, [@-], [@+]) }eg;
  0         0  
166             }
167             else {
168 0         0 $text =~ s{$pattern}{ &$expand($replace, [@-], [@+]) }e;
  0         0  
169             }
170             }
171             else {
172 1 50       3 if ($global) {
173 1         23 $text =~ s/$pattern/$replace/g;
174             }
175             else {
176 0         0 $text =~ s/$pattern/$replace/;
177             }
178             }
179 1         15 return $text;
180             }
181              
182             sub _text_remove {
183 1     1   2745 my ($str, $search) = @_;
184 1 50 33     10 return $str unless defined $str and defined $search;
185 1         17 $str =~ s/$search//g;
186 1         11 return $str;
187             }
188            
189             sub _text_split {
190 3     3   8556 my ($str, $split, $limit) = @_;
191 3 50       12 $str = '' unless defined $str;
192            
193             # we have to be very careful about spelling out each possible
194             # combination of arguments because split() is very sensitive
195             # to them, for example C behaves differently
196             # to C<$space=' '; split($space, ...)>
197            
198 3 50       10 if (defined $limit) {
199 0 0       0 return [ defined $split
200             ? split($split, $str, $limit)
201             : split(' ', $str, $limit) ];
202             }
203             else {
204 3 50       51 return [ defined $split
205             ? split($split, $str)
206             : split(' ', $str) ];
207             }
208             }
209              
210             sub _text_chunk {
211 2     2   7121 my ($string, $size) = @_;
212 2         4 my @list;
213 2   50     11 $size ||= 1;
214 2 50       11 if ($size < 0) {
215             # sexeger! It's faster to reverse the string, search
216             # it from the front and then reverse the output than to
217             # search it from the end, believe it nor not!
218 0         0 $string = reverse $string;
219 0         0 $size = -$size;
220 0         0 unshift(@list, scalar reverse $1)
221             while ($string =~ /((.{$size})|(.+))/g);
222             }
223             else {
224 2         91 push(@list, $1) while ($string =~ /((.{$size})|(.+))/g);
225             }
226 2         31 return \@list;
227             }
228              
229             sub _text_substr {
230 2     2   5724 my ($text, $offset, $length, $replacement) = @_;
231 2   50     13 $offset ||= 0;
232            
233 2 50       24 if(defined $length) {
234 2 100       6 if (defined $replacement) {
235 1         3 substr( $text, $offset, $length, $replacement );
236 1         12 return $text;
237             }
238             else {
239 1         11 return substr( $text, $offset, $length );
240             }
241             }
242             else {
243 0         0 return substr( $text, $offset );
244             }
245             }
246              
247             sub _hash_item {
248 2     2   108085 my ($hash, $item) = @_;
249 2 50       8 $item = '' unless defined $item;
250 2         31 $hash->{ $item };
251             }
252              
253             sub _hash_hash {
254 0     0   0 $_[0];
255             }
256              
257             sub _hash_size {
258 1     1   2305 scalar keys %{$_[0]};
  1         11  
259             }
260              
261             sub _hash_each {
262             # this will be changed in TT3 to do what hash_pairs() does
263 0     0   0 [ %{ $_[0] } ];
  0         0  
264             }
265              
266             sub _hash_keys {
267 1     1   4075 [ keys %{ $_[0] } ];
  1         11  
268             }
269              
270             sub _hash_values {
271 0     0   0 [ values %{ $_[0] } ];
  0         0  
272             }
273              
274             sub _hash_items {
275 0     0   0 [ %{ $_[0] } ];
  0         0  
276             }
277              
278             sub _hash_pairs {
279 5         43 [ map {
280 2         15 { key => $_ , value => $_[0]->{ $_ } }
281             }
282 2     2   5239 sort keys %{ $_[0] }
283             ];
284             }
285              
286             sub _hash_list {
287 0     0   0 my ($hash, $what) = @_;
288 0   0     0 $what ||= '';
289 0         0 return ($what eq 'keys') ? [ keys %$hash ]
290             : ($what eq 'values') ? [ values %$hash ]
291             : ($what eq 'each') ? [ %$hash ]
292             : # for now we do what pairs does but this will be changed
293             # in TT3 to return [ $hash ] by default
294 0 0       0 [ map { { key => $_ , value => $hash->{ $_ } } }
    0          
    0          
295             sort keys %$hash
296             ];
297             }
298              
299             sub _hash_exists {
300 2     2   8239 exists $_[0]->{ $_[1] };
301             }
302              
303             sub _hash_defined {
304             # return the item requested, or 1 if no argument
305             # to indicate that the hash itself is defined
306 1     1   1873 my $hash = shift;
307 1 50       13 return @_ ? defined $hash->{ $_[0] } : 1;
308             }
309              
310             sub _hash_delete {
311 1     1   5668 my $hash = shift;
312 1         9 delete $hash->{ $_ } for @_;
313             }
314              
315             sub _hash_import {
316 0     0   0 my ($hash, $imp) = @_;
317 0 0       0 $imp = {} unless ref $imp eq 'HASH';
318 0         0 @$hash{ keys %$imp } = values %$imp;
319 0         0 return '';
320             }
321              
322             sub _hash_sort {
323 1     1   3638 my ($hash) = @_;
324 1         9 [ sort { lc $hash->{$a} cmp lc $hash->{$b} } (keys %$hash) ];
  3         25  
325             }
326              
327             sub _hash_nsort {
328 0     0   0 my ($hash) = @_;
329 0         0 [ sort { $hash->{$a} <=> $hash->{$b} } (keys %$hash) ];
  0         0  
330             }
331              
332             sub _list_item {
333 1   50 1   3495 $_[0]->[ $_[1] || 0 ];
334             }
335              
336             sub _list_list {
337 0     0   0 $_[0];
338             }
339              
340             sub _list_hash {
341 0     0   0 my $list = shift;
342 0 0       0 if (@_) {
343 0   0     0 my $n = shift || 0;
344 0         0 return { map { ($n++, $_) } @$list };
  0         0  
345             }
346 5     5   45 no warnings;
  5         9  
  5         904  
347 0         0 return { @$list };
348             }
349              
350             sub _list_push {
351 1     1   2871 my $list = shift;
352 1         3 push(@$list, @_);
353 1         10 return '';
354             }
355              
356             sub _list_pop {
357 1     1   2301 my $list = shift;
358 1         11 pop(@$list);
359             }
360              
361             sub _list_unshift {
362 4     4   13363 my $list = shift;
363 4         12 unshift(@$list, @_);
364 4         25 return '';
365             }
366              
367             sub _list_shift {
368 2     2   1772 my $list = shift;
369 2         17 shift(@$list);
370             }
371              
372             sub _list_max {
373 5     5   28 no warnings;
  5         10  
  5         255  
374 1     1   1641 my $list = shift;
375 1         12 $#$list;
376             }
377              
378             sub _list_size {
379 5     5   30 no warnings;
  5         22  
  5         24006  
380 3     3   96029 my $list = shift;
381 3         47 $#$list + 1;
382             }
383              
384             sub _list_defined {
385             # return the item requested, or 1 if no argument to
386             # indicate that the hash itself is defined
387 1     1   1796 my $list = shift;
388 1 50       11 return @_ ? defined $list->[$_[0]] : 1;
389             }
390              
391             sub _list_first {
392 1     1   1776 my $list = shift;
393 1 50       13 return $list->[0] unless @_;
394 0         0 return [ @$list[0..$_[0]-1] ];
395             }
396              
397             sub _list_last {
398 1     1   1703 my $list = shift;
399 1 50       12 return $list->[-1] unless @_;
400 0         0 return [ @$list[-$_[0]..-1] ];
401             }
402              
403             sub _list_reverse {
404 1     1   2301 my $list = shift;
405 1         6 [ reverse @$list ];
406             }
407              
408             sub _list_grep {
409 1     1   2771 my ($list, $pattern) = @_;
410 1   50     7 $pattern ||= '';
411 1         47 return [ grep /$pattern/, @$list ];
412             }
413              
414             sub _list_join {
415 11     11   2778 my ($list, $joint) = @_;
416 53 50       253 join(defined $joint ? $joint : ' ',
417 11 50       39 map { defined $_ ? $_ : '' } @$list);
418             }
419              
420             sub _list_sort_make_key {
421 0     0   0 my ($item, $fields) = @_;
422 0         0 my @keys;
423              
424 0 0       0 if (ref($item) eq 'HASH') {
    0          
425 0         0 @keys = map { $item->{ $_ } } @$fields;
  0         0  
426             }
427             elsif (blessed $item) {
428 0 0       0 @keys = map { $item->can($_) ? $item->$_() : $item } @$fields;
  0         0  
429             }
430             else {
431 0         0 @keys = $item;
432             }
433            
434             # ugly hack to generate a single string using a delimiter that is
435             # unlikely (but not impossible) to be found in the wild.
436 0 0       0 return lc join('/*^UNLIKELY^*/', map { defined $_ ? $_ : '' } @keys);
  0         0  
437             }
438              
439             sub _list_sort {
440 2     2   4 my ($list, @fields) = @_;
441 2 50       10 return $list unless @$list > 1; # no need to sort 1 item lists
442             return [
443             @fields # Schwartzian Transform
444 0         0 ? map { $_->[0] } # for case insensitivity
  0         0  
445 0         0 sort { $a->[1] cmp $b->[1] }
446 8         28 map { [ $_, _list_sort_make_key($_, \@fields) ] }
447             @$list
448 12         22 : map { $_->[0] }
449 8         27 sort { $a->[1] cmp $b->[1] }
450 2 50       10 map { [ $_, lc $_ ] }
451             @$list,
452             ];
453             }
454              
455             sub _list_nsort {
456 1     1   3 my ($list, @fields) = @_;
457 1 50       4 return $list unless @$list > 1; # no need to sort 1 item lists
458             return [
459             @fields # Schwartzian Transform
460 0         0 ? map { $_->[0] } # for case insensitivity
  0         0  
461 0         0 sort { $a->[1] <=> $b->[1] }
462 6         15 map { [ $_, _list_sort_make_key($_, \@fields) ] }
463             @$list
464 11         16 : map { $_->[0] }
465 6         17 sort { $a->[1] <=> $b->[1] }
466 1 50       4 map { [ $_, lc $_ ] }
467             @$list,
468             ];
469             }
470              
471             sub _list_unique {
472 1     1   2 my %u;
473 1         2 [ grep { ++$u{$_} == 1 } @{$_[0]} ];
  6         25  
  1         3  
474             }
475              
476             sub _list_import {
477 1     1   6344 my $list = shift;
478 1 50       12 push(@$list, grep defined, map ref eq 'ARRAY' ? @$_ : undef, @_);
479 1         7 return $list;
480             }
481              
482             sub _list_merge {
483 2     2   12303 my $list = shift;
484 2 50       29 return [ @$list, grep defined, map ref eq 'ARRAY' ? @$_ : undef, @_ ];
485             }
486              
487             sub _list_slice {
488 1     1   4161 my ($list, $from, $to) = @_;
489 1   50     7 $from ||= 0;
490 1 50       5 $to = $#$list unless defined $to;
491 1 50       5 $from += @$list if $from < 0;
492 1 50       5 $to += @$list if $to < 0;
493 1         10 return [ @$list[$from..$to] ];
494             }
495              
496             sub _list_splice {
497 1     1   10551 my ($list, $offset, $length, @replace) = @_;
498 1 50       6 if (@replace) {
    0          
    0          
499             # @replace can contain a list of multiple replace items, or
500             # be a single reference to a list
501 1 50 33     13 @replace = @{ $replace[0] }
  1         4  
502             if @replace == 1 && ref $replace[0] eq 'ARRAY';
503 1         12 return [ splice @$list, $offset, $length, @replace ];
504             }
505             elsif (defined $length) {
506 0         0 return [ splice @$list, $offset, $length ];
507             }
508             elsif (defined $offset) {
509 0         0 return [ splice @$list, $offset ];
510             }
511             else {
512 0         0 return [ splice(@$list) ];
513             }
514             }
515              
516             sub _xml_filter {
517 1     1   1985 my $text = shift;
518 1         4 for ($text) {
519 1         5 s/&/&/g;
520 1         3 s/
521 1         2 s/>/>/g;
522 1         1 s/"/"/g;
523 1         4 s/'/'/g;
524             }
525 1         5 return $text;
526             }
527              
528             sub _html_paragraph {
529 3     3   203547 my $text = shift;
530 3         130 return "

\n"

531             . join("\n

\n\n

\n", split(/(?:\r?\n){2,}/, Text::Xslate::Util::html_escape($text)))

532             . "

\n";
533             }
534              
535             sub _html_para_break {
536 4     4   11341 my $text = shift;
537 4         22 $text = Text::Xslate::Util::html_escape($text);
538 4         65 $text =~ s|(\r?\n){2,}|$1
$1
$1|g;
539 4         16 return $text;
540             }
541              
542             sub _html_line_break {
543 2     2   4719 my $text = shift;
544 2         12 $text = Text::Xslate::Util::html_escape($text);
545 2         28 $text =~ s|(\r?\n)|
$1|g;
546 2         11 return $text;
547             }
548              
549             sub _indent_filter_factory {
550 1     1   2421 my ($pad) = @_;
551 1 50       5 $pad = 4 unless defined $pad;
552 1 50       5 $pad = ' ' x $pad if $pad =~ /^\d+$/;
553              
554             return sub {
555 1     1   2 my $text = shift;
556 1 50       6 $text = '' unless defined $text;
557 1         6 $text =~ s/^/$pad/mg;
558 1         10 return $text;
559             }
560 1         6 }
561              
562             sub _format_filter_factory {
563 1     1   2261 my ($format) = @_;
564 1 50       3 $format = '%s' unless defined $format;
565              
566             return sub {
567 1     1   2 my $text = shift;
568 1 50       4 $text = '' unless defined $text;
569 1         5 return join("\n", map{ sprintf($format, $_) } split(/\n/, $text));
  1         15  
570             }
571 1         7 }
572              
573             sub _truncate_filter_factory {
574 1     1   2384 my ($len, $char) = @_;
575 1 50       5 $len = $TRUNCATE_LENGTH unless defined $len;
576 1 50       6 $char = $TRUNCATE_ADDON unless defined $char;
577              
578             # Length of char is the minimum length
579 1         2 my $lchar = length $char;
580 1 50       6 if ($len < $lchar) {
581 0         0 $char = substr($char, 0, $len);
582 0         0 $lchar = $len;
583             }
584              
585             return sub {
586 1     1   2 my $text = shift;
587 1 50       4 return $text if length $text <= $len;
588 1         13 return substr($text, 0, $len - $lchar) . $char;
589             }
590 1         8 }
591              
592             sub _repeat_filter_factory {
593 1     1   2480 my ($iter) = @_;
594 1 50 33     11 $iter = 1 unless defined $iter and length $iter;
595              
596             return sub {
597 1     1   2 my $text = shift;
598 1 50       5 $text = '' unless defined $text;
599 1         13 return join('\n', $text) x $iter;
600             }
601 1         8 }
602              
603             sub _replace_filter_factory {
604 1     1   2713 my ($search, $replace) = @_;
605 1 50       5 $search = '' unless defined $search;
606 1 50       4 $replace = '' unless defined $replace;
607              
608             return sub {
609 1     1   2 my $text = shift;
610 1 50       3 $text = '' unless defined $text;
611 1         18 $text =~ s/$search/$replace/g;
612 1         11 return $text;
613             }
614 1         6 }
615              
616             sub _remove_filter_factory {
617 1     1   2300 my ($search) = @_;
618              
619             return sub {
620 1     1   2 my $text = shift;
621 1 50       4 $text = '' unless defined $text;
622 1         14 $text =~ s/$search//g;
623 1         11 return $text;
624             }
625 1         7 }
626              
627             1;