File Coverage

blib/lib/Text/Template/Simple/Util.pm
Criterion Covered Total %
statement 74 92 80.4
branch 20 44 45.4
condition 7 12 58.3
subroutine 16 18 88.8
pod 9 9 100.0
total 126 175 72.0


line stmt bran cond sub pod time code
1             package Text::Template::Simple::Util;
2 60     60   195 use strict;
  60         56  
  60         1313  
3 60     60   166 use warnings;
  60         55  
  60         1286  
4 60     60   159 use base qw( Exporter );
  60         57  
  60         3188  
5 60     60   191 use Carp qw( croak );
  60         60  
  60         2382  
6 60         14740 use Text::Template::Simple::Constants qw(
7             :info
8             DIGEST_MODS
9             EMPTY_STRING
10 60     60   240 );
  60         59  
11              
12             our $VERSION = '0.90';
13              
14             BEGIN {
15 60     60   95 if ( UNICODE_PERL ) {
16             # older perl binmode() does not accept a second param
17             *binary_mode = sub {
18 2     2   5 my($fh, $layer) = @_;
19 2         13 binmode $fh, q{:} . $layer;
20 60         251 };
21             }
22             else {
23             *binary_mode = sub { binmode $_[0] };
24             }
25 60         290 our %EXPORT_TAGS = (
26             util => [qw( binary_mode DIGEST trim rtrim ltrim escape )],
27             debug => [qw( fatal DEBUG LOG L )],
28             misc => [qw( visualize_whitespace )],
29             );
30 60         140 our @EXPORT_OK = map { @{ $EXPORT_TAGS{$_} } } keys %EXPORT_TAGS;
  180         132  
  180         407  
31 60         134 $EXPORT_TAGS{all} = \@EXPORT_OK;
32 60         51578 our @EXPORT = @EXPORT_OK;
33             }
34              
35             my $lang = {
36             error => {
37             q{tts.base.examine.notglob} => q{Unknown template parameter passed as %s reference! Supported types are GLOB, PATH and STRING.},
38             q{tts.base.examine.notfh} => q{This GLOB is not a filehandle},
39             q{tts.main.cdir} => q{Cache dir %s does not exist!},
40             q{tts.main.bogus_args} => q{Malformed add_args parameter! 'add_args' must be an arrayref!},
41             q{tts.main.bogus_delims} => q{Malformed delimiters parameter! 'delimiters' must be a two element arrayref!},
42             q{tts.cache.opendir} => q{Can not open cache dir (%s) for reading: %s},
43             q{tts.util.digest} => q{Can not load a digest module. Disable cache or install one of these (%s or %s). Last error was: %s},
44             q{tts.cache.dumper} => q{Can not dump in-memory cache! Your version of Data::Dumper (%s) does not implement the Deparse() method. Please upgrade this module!},
45             q{tts.cache.pformat} => q{Parameters must be in 'param => value' format},
46             q{tts.cache.incache} => q{I need an 'id' or a 'data' parameter for cache check!},
47             q{tts.main.dslen} => q{Start delimiter is smaller than 2 characters},
48             q{tts.main.delen} => q{End delimiter is smaller than 2 characters},
49             q{tts.main.dsws} => q{Start delimiter contains whitespace},
50             q{tts.main.dews} => q{End delimiter contains whitespace},
51             q{tts.main.import.invalid} => q{%s isn't a valid import parameter for %s},
52             q{tts.main.import.undef} => q{%s is not defined in %s},
53             q{tts.main.import.redefine} => q{%s is already defined in %s},
54             q{tts.main.tts.args} => q{Nothing to compile!},
55             q{tts.main.connector.args} => q{connector(): id is missing},
56             q{tts.main.connector.invalid} => q{connector(): invalid id: %s},
57             q{tts.main.init.thandler} => q{user_thandler parameter must be a CODE reference},
58             q{tts.main.init.include} => q{include_paths parameter must be a ARRAY reference},
59             q{tts.util.escape} => q{Missing the character to escape},
60             q{tts.tokenizer.new.ds} => q{Start delimiter is missing},
61             q{tts.tokenizer.new.de} => q{End delimiter is missing},
62             q{tts.tokenizer.tokenize.tmp} => q{Template string is missing},
63             q{tts.tokenizer._get_symbols.regex} => q{Regex is missing},
64             q{tts.io.validate.type} => q{No type specified},
65             q{tts.io.validate.path} => q{No path specified},
66             q{tts.io.validate.file} => q{validate(file) is not yet implemented},
67             q{tts.io.layer.fh} => q{Filehandle is absent},
68             q{tts.io.slurp.open} => q{Error opening '%s' for reading: %s},
69             q{tts.io.slurp.taint} => q{Can't untaint FH},
70             q{tts.io.hls.invalid} => q{FH is either absent or invalid},
71             q{tts.caller.stack.hash} => q{Parameters to stack() must be a HASH},
72             q{tts.caller.stack.type} => q{Unknown caller stack type: %s},
73             q{tts.caller._text_table.module} => q{Caller stack type 'text_table' requires Text::Table: %s},
74             q{tts.cache.new.parent} => q{Parent object is missing},
75             q{tts.cache.dumper.hash} => q{Parameters to dumper() must be a HASHref},
76             q{tts.cache.dumper.type} => q{Dumper type '%s' is not valid},
77             q{tts.cache.develsize.buggy} => q{Your Devel::Size version (%s) has a known bug. Upgrade Devel::Size to 0.72 or newer or do not use the size() method},
78             q{tts.cache.develsize.total} => q{Devel::Size::total_size(): %s},
79             q{tts.cache.hit.meta} => q{Can not get meta data: %s},
80             q{tts.cache.hit.cache} => q{Error loading from disk cache: %s},
81             q{tts.cache.populate.write} => q{Error writing disk-cache %s : %s},
82             q{tts.cache.populate.chmod} => q{Can not change file mode},
83             q{tts.base.compiler._compile.notmp} => q{No template specified},
84             q{tts.base.compiler._compile.param} => q{params must be an arrayref!},
85             q{tts.base.compiler._compile.opt} => q{opts must be a hashref!},
86             q{tts.base.compiler._wrap_compile.parsed} => q{nothing to compile},
87             q{tts.base.compiler._mini_compiler.notmp} => q{_mini_compiler(): missing the template},
88             q{tts.base.compiler._mini_compiler.noparam} => q{_mini_compiler(): missing the parameters},
89             q{tts.base.compiler._mini_compiler.opt} => q{_mini_compiler(): options must be a hash},
90             q{tts.base.compiler._mini_compiler.param} => q{_mini_compiler(): parameters must be a HASH},
91             q{tts.base.examine._examine_type.ftype} => q{ARRAY does not contain the type},
92             q{tts.base.examine._examine_type.fthing} => q{ARRAY does not contain the data},
93             q{tts.base.examine._examine_type.extra} => q{Type array has unknown extra fields},
94             q{tts.base.examine._examine_type.unknown} => q{Unknown first argument of %s type to compile()},
95             q{tts.base.include._include.unknown} => q{Unknown include type: %s},
96             q{tts.base.include._interpolate.bogus_share} => q{Only SCALARs can be shared. You have tried to share a variable }
97             .q{type of %s named "%s". Consider converting it to a SCALAR or try }
98             .q{the monolith option to enable automatic variable sharing. }
99             .q{But please read the fine manual first},
100             q{tts.base.include._interpolate.bogus_share_notbare} => q{It looks like you've tried to share an expression (%s) instead of a simple variable.},
101             q{tts.base.parser._internal.id} => q{_internal(): id is missing},
102             q{tts.base.parser._internal.rv} => q{_internal(): id is invalid},
103             q{tts.base.parser._parse.unbalanced} => q{%d unbalanced %s delimiter(s) in template %s},
104             q{tts.cache.id.generate.data} => q{Can't generate id without data!},
105             q{tts.cache.id._custom.data} => q{Can't generate id without data!},
106             },
107             warning => {
108             q{tts.base.include.dynamic.recursion} => q{%s Deep recursion (>=%d) detected in the included file: %s},
109             }
110             };
111              
112             my @WHITESPACE_SYMBOLS = map { q{\\} . $_ } qw( r n f s );
113              
114             my $DEBUG = 0; # Disabled by default
115             my $DIGEST; # Will hold digester class name.
116              
117             sub L {
118 6     6 1 15 my($type, $id, @param) = @_;
119 6 50       15 croak q{Type parameter to L() is missing} if ! $type;
120 6 50       12 croak q{ID parameter ro L() is missing} if ! $id;
121 6   33     22 my $root = $lang->{ $type } || croak "$type is not a valid L() type";
122 6   33     21 my $value = $root->{ $id } || croak "$id is not a valid L() ID";
123 6 50       659 return @param ? sprintf($value, @param) : $value;
124             }
125              
126             sub fatal {
127 4     4 1 165 my @args = @_;
128 4         12 return croak L( error => @args );
129             }
130              
131             sub escape {
132 1440     1440 1 1496 my($c, $s) = @_;
133 1440 50       2019 fatal('tts.util.escape') if ! $c;
134 1440 50       1811 return $s if ! $s; # false or undef
135 1440         1339 my $e = quotemeta $c;
136 1440         7253 $s =~ s{$e}{\\$c}xmsg;
137 1440         6304 return $s;
138             }
139              
140             sub trim {
141 332     332 1 275 my $s = shift;
142 332 50       457 return $s if ! $s; # false or undef
143 332   50     806 my $extra = shift || EMPTY_STRING;
144 332         962 $s =~ s{\A \s+ }{$extra}xms;
145 332         918 $s =~ s{ \s+ \z}{$extra}xms;
146 332         647 return $s;
147             }
148              
149             sub ltrim {
150 46     46 1 50 my $s = shift;
151 46 50       80 return $s if ! $s; # false or undef
152 46   100     127 my $extra = shift || EMPTY_STRING;
153 46         131 $s =~ s{\A \s+ }{$extra}xms;
154 46         97 return $s;
155             }
156              
157             sub rtrim {
158 26     26 1 23 my $s = shift;
159 26 50       37 return $s if ! $s; # false or undef
160 26   100     152 my $extra = shift || EMPTY_STRING;
161 26         106 $s =~ s{ \s+ \z}{$extra}xms;
162 26         51 return $s;
163             }
164              
165             sub visualize_whitespace {
166 0     0 1 0 my($str) = @_;
167 0         0 $str =~ s<[$_]><$_>xmsg for @WHITESPACE_SYMBOLS;
168 0         0 return $str;
169             }
170              
171             *LOG = __PACKAGE__->can('MYLOG') || sub {
172 0     0   0 my @args = @_;
173 0 0       0 my $self = ref $args[0] ? shift @args : undef;
174 0         0 my $id = shift @args;
175 0         0 my $message = shift @args;
176 0 0       0 $id = 'DEBUG' if not defined $id;
177 0 0       0 $message = '<NO MESSAGE>' if not defined $message;
178 0         0 $id =~ s{_}{ }xmsg;
179 0         0 $message = sprintf q{[ % 15s ] %s}, $id, $message;
180 0         0 warn "$message\n";
181 0         0 return;
182             };
183              
184             sub DEBUG {
185 10206     10206 1 7729 my $thing = shift;
186              
187             # so that one can use: $self->DEBUG or DEBUG
188 10206 100       10417 $thing = shift if _is_parent_object( $thing );
189              
190 10206 100       13198 $DEBUG = $thing+0 if defined $thing; # must be numeric
191 10206         18956 return $DEBUG;
192             }
193              
194             sub DIGEST {
195 26 100   26 1 110 return $DIGEST->new if $DIGEST;
196              
197 8         27 local $SIG{__DIE__};
198             # local $@;
199 8         30 foreach my $mod ( DIGEST_MODS ) {
200 8         35 (my $file = $mod) =~ s{::}{/}xmsog;
201 8         15 $file .= '.pm';
202 8         12 my $ok = eval { require $file; };
  8         4004  
203 8 50       20141 if ( ! $ok ) {
204 0 0       0 LOG( FAILED => "$mod - $file" ) if DEBUG;
205 0         0 next;
206             }
207 8         13 $DIGEST = $mod;
208 8         16 last;
209             }
210              
211 8 50       24 if ( not $DIGEST ) {
212 0         0 my @report = DIGEST_MODS;
213 0         0 my $last_error = pop @report;
214 0         0 fatal( 'tts.util.digest' => join(', ', @report), $last_error, $@ );
215             }
216              
217 8 50       36 LOG( DIGESTER => $DIGEST . ' v' . $DIGEST->VERSION ) if DEBUG;
218 8         33 return $DIGEST->new;
219             }
220              
221             sub _is_parent_object {
222 10206     10206   6731 my $test = shift;
223 10206 0       20691 return ! defined $test ? 0
    0          
    50          
    100          
224             : ref $test ? 1
225             : $test eq __PACKAGE__ ? 1
226             : $test eq PARENT ? 1
227             : 0
228             ;
229             }
230              
231             1;
232              
233             __END__
234              
235             =head1 NAME
236              
237             Text::Template::Simple::Util - Utility functions
238              
239             =head1 SYNOPSIS
240              
241             TODO
242              
243             =head1 DESCRIPTION
244              
245             This document describes version C<0.90> of C<Text::Template::Simple::Util>
246             released on C<5 July 2016>.
247              
248             Contains utility functions for Text::Template::Simple.
249              
250             =head1 FUNCTIONS
251              
252             =head2 DEBUG
253              
254             Returns the debug status.
255              
256             =head2 DIGEST
257              
258             Returns the C<digester> object.
259              
260             =head2 binary_mode FILE_HANDLE, LAYER
261              
262             Sets the I/O layer of C<FILE_HANDLE> in modern C<perls>, only sets C<binmode>
263             on C<FILE_HANDLE> otherwise.
264              
265             =head2 L TYPE, ID [, PARAMETERS]
266              
267             Internal method.
268              
269             =head2 fatal ID [, PARAMETERS]
270              
271             Internal method.
272              
273             =head2 C<trim STRING>
274              
275             Returns the trimmed version of the C<STRING>.
276              
277             =head2 C<ltrim STRING>
278              
279             Returns the left trimmed version of the C<STRING>.
280              
281             =head2 C<rtrim STRING>
282              
283             Returns the right trimmed version of the C<STRING>.
284              
285             =head2 escape CHAR, STRING
286              
287             Escapes all occurrences of C<CHAR> in C<STRING> with backslashes.
288              
289             =head2 visualize_whitespace STRING
290              
291             Replaces the white space in C<STRING> with visual representations.
292              
293             =head1 C<OVERRIDABLE FUNCTIONS>
294              
295             =head2 LOG
296              
297             If debugging mode is enabled in Text::Template::Simple, all
298             debugging messages will be captured by this function and will
299             be printed to C<STDERR>.
300              
301             If a sub named C<Text::Template::Simple::Util::MYLOG> is defined,
302             then all calls to C<LOG> will be redirected to this sub. If you want to
303             save the debugging messages to a file or to a database, you must define
304             the C<MYLOG> sub.
305              
306             =head1 AUTHOR
307              
308             Burak Gursoy <burak@cpan.org>.
309              
310             =head1 COPYRIGHT
311              
312             Copyright 2004 - 2016 Burak Gursoy. All rights reserved.
313              
314             =head1 LICENSE
315              
316             This library is free software; you can redistribute it and/or modify
317             it under the same terms as Perl itself, either Perl version 5.24.0 or,
318             at your option, any later version of Perl 5 you may have available.
319             =cut