blib/lib/Tenjin/Util.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 18 | 68 | 26.4 |
branch | 0 | 16 | 0.0 |
condition | 0 | 2 | 0.0 |
subroutine | 8 | 20 | 40.0 |
pod | 13 | 13 | 100.0 |
total | 39 | 119 | 32.7 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package Tenjin::Util; | ||||||
2 | |||||||
3 | 7 | 7 | 44 | use strict; | |||
7 | 12 | ||||||
7 | 239 | ||||||
4 | 7 | 7 | 39 | use warnings; | |||
7 | 13 | ||||||
7 | 164 | ||||||
5 | 7 | 7 | 6667 | use HTML::Entities; | |||
7 | 57735 | ||||||
7 | 10967 | ||||||
6 | |||||||
7 | our $VERSION = "0.070001"; | ||||||
8 | $VERSION = eval $VERSION; | ||||||
9 | |||||||
10 | =head1 NAME | ||||||
11 | |||||||
12 | Tenjin::Util - Utility methods for Tenjin. | ||||||
13 | |||||||
14 | =head1 VERSION | ||||||
15 | |||||||
16 | version 0.070001 | ||||||
17 | |||||||
18 | =head1 SYNOPSIS | ||||||
19 | |||||||
20 | # in your templates: | ||||||
21 | |||||||
22 | # encode a URL | ||||||
23 | [== encode_url('http://www.google.com/search?q=tenjin&ie=utf-8&oe=utf-8&aq=t') =] | ||||||
24 | # returns http%3A//www.google.com/search%3Fq%3Dtenjin%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt | ||||||
25 | |||||||
26 | # escape a string of lines of HTML code | ||||||
27 | You & Me\nMe & You'; ?> |
||||||
28 | [== text2html($string) =] | ||||||
29 | # returns <h1>You & Me</h1> \n<h2>Me & You</h2> |
||||||
30 | |||||||
31 | =head1 DESCRIPTION | ||||||
32 | |||||||
33 | This module provides a few utility functions which can be used in your | ||||||
34 | templates for your convenience. These include functions to (un)escape | ||||||
35 | and (en/de)code URLs. | ||||||
36 | |||||||
37 | =head1 METHODS | ||||||
38 | |||||||
39 | =head2 expand_tabs( $str, [$tabwidth] ) | ||||||
40 | |||||||
41 | Receives a string that might contain tabs in it, and replaces those | ||||||
42 | tabs with spaces, each tab with the number of spaces defined by C<$tabwidth>, | ||||||
43 | or, if C<$tabwidth> was not passed, with 8 spaces. | ||||||
44 | |||||||
45 | =cut | ||||||
46 | |||||||
47 | sub expand_tabs { | ||||||
48 | 0 | 0 | 1 | 0 | my ($str, $tabwidth) = @_; | ||
49 | |||||||
50 | 0 | 0 | 0 | $tabwidth ||= 8; | |||
51 | 0 | 0 | my $s = ''; | ||||
52 | 0 | 0 | my $pos = 0; | ||||
53 | 0 | 0 | while ($str =~ /.*?\t/sg) { # /(.*?)\t/ may be slow | ||||
54 | 0 | 0 | my $end = $+[0]; | ||||
55 | 0 | 0 | my $text = substr($str, $pos, $end - 1 - $pos); | ||||
56 | 0 | 0 | my $n = rindex($text, "\n"); | ||||
57 | 0 | 0 | 0 | my $col = $n >= 0 ? length($text) - $n - 1 : length($text); | |||
58 | 0 | 0 | $s .= $text; | ||||
59 | 0 | 0 | $s .= ' ' x ($tabwidth - $col % $tabwidth); | ||||
60 | 0 | 0 | $pos = $end; | ||||
61 | } | ||||||
62 | 0 | 0 | my $rest = substr($str, $pos); | ||||
63 | 0 | 0 | return $s; | ||||
64 | } | ||||||
65 | |||||||
66 | =head2 escape_xml( $str ) | ||||||
67 | |||||||
68 | Receives a string of XML (or (x)HTML) code and converts the characters | ||||||
69 | <>&\' to HTML entities. This is the method that is invoked when you use | ||||||
70 | [= $expression =] in your templates. | ||||||
71 | |||||||
72 | =cut | ||||||
73 | |||||||
74 | sub escape_xml { | ||||||
75 | 1 | 1 | 1 | 28 | encode_entities($_[0], '<>&"\''); | ||
76 | } | ||||||
77 | |||||||
78 | =head2 unescape_xml( $str ) | ||||||
79 | |||||||
80 | Receives a string of escaped XML (or (x)HTML) code (for example, a string | ||||||
81 | that was escaped with the L |
||||||
82 | and 'unescapes' all HTML entities back to their actual characters. | ||||||
83 | |||||||
84 | =cut | ||||||
85 | |||||||
86 | sub unescape_xml { | ||||||
87 | 1 | 1 | 1 | 407 | decode_entities($_[0]); | ||
88 | } | ||||||
89 | |||||||
90 | =head2 encode_url( $url ) | ||||||
91 | |||||||
92 | Receives a URL and encodes it by escaping 'non-standard' characters. | ||||||
93 | |||||||
94 | =cut | ||||||
95 | |||||||
96 | sub encode_url { | ||||||
97 | 1 | 1 | 1 | 9 | my $url = shift; | ||
98 | |||||||
99 | 1 | 7 | $url =~ s/([^-A-Za-z0-9_.\/])/sprintf("%%%02X", ord($1))/sge; | ||||
9 | 31 | ||||||
100 | 1 | 3 | $url =~ tr/ /+/; | ||||
101 | 1 | 4 | return $url; | ||||
102 | } | ||||||
103 | |||||||
104 | =head2 decode_url( $url ) | ||||||
105 | |||||||
106 | Does the opposite of L |
||||||
107 | |||||||
108 | =cut | ||||||
109 | |||||||
110 | sub decode_url { | ||||||
111 | 0 | 0 | 1 | 0 | my $url = shift; | ||
112 | |||||||
113 | 0 | 0 | $url =~ s/\%([a-fA-F0-9][a-fA-F0-9])/pack('C', hex($1))/sge; | ||||
0 | 0 | ||||||
114 | 0 | 0 | return $url; | ||||
115 | } | ||||||
116 | |||||||
117 | =head2 checked( $val ) | ||||||
118 | |||||||
119 | Receives a value of some sort, and if it is a true value, returns the string | ||||||
120 | ' checked="checked"' which can be appended to HTML checkboxes. | ||||||
121 | |||||||
122 | =cut | ||||||
123 | |||||||
124 | sub checked { | ||||||
125 | 0 | 0 | 0 | 1 | 0 | $_[0] ? ' checked="checked"' : ''; | |
126 | } | ||||||
127 | |||||||
128 | =head2 selected( $val ) | ||||||
129 | |||||||
130 | Receives a value of some sort, and if it is a true value, returns the string | ||||||
131 | ' selected="selected"' which can be used in an option in an HTML select box. | ||||||
132 | |||||||
133 | =cut | ||||||
134 | |||||||
135 | sub selected { | ||||||
136 | 0 | 0 | 0 | 1 | 0 | $_[0] ? ' selected="selected"' : ''; | |
137 | } | ||||||
138 | |||||||
139 | =head2 disabled( $val ) | ||||||
140 | |||||||
141 | Receives a value of some sort, and if it is a true value, returns the string | ||||||
142 | ' disabled="disabled"' which can be used in an HTML input. | ||||||
143 | |||||||
144 | =cut | ||||||
145 | |||||||
146 | sub disabled { | ||||||
147 | 0 | 0 | 0 | 1 | 0 | $_[0] ? ' disabled="disabled"' : ''; | |
148 | } | ||||||
149 | |||||||
150 | =head2 nl2br( $text ) | ||||||
151 | |||||||
152 | Receives a string of text containing lines delimited by newline characters | ||||||
153 | (\n, or possibly \r\n) and appends an HTML line break ( ) to every |
||||||
154 | line (the newline character is left untouched). | ||||||
155 | |||||||
156 | =cut | ||||||
157 | |||||||
158 | sub nl2br { | ||||||
159 | 0 | 0 | 1 | 0 | my $text = shift; | ||
160 | |||||||
161 | 0 | 0 | $text =~ s/(\r?\n)/ $1/g; |
||||
162 | 0 | 0 | return $text; | ||||
163 | } | ||||||
164 | |||||||
165 | =head2 text2html( $text ) | ||||||
166 | |||||||
167 | Receives a string of text containing lines delimited by newline characters, | ||||||
168 | and possibly some XML (or (x)HTML) code, escapes that code with | ||||||
169 | L |
||||||
170 | to every line with L |
||||||
171 | |||||||
172 | =cut | ||||||
173 | |||||||
174 | sub text2html { | ||||||
175 | 0 | 0 | 1 | 0 | nl2br(escape_xml($_[0])); | ||
176 | } | ||||||
177 | |||||||
178 | =head2 tagattr( $name, $expr, [$value] ) | ||||||
179 | |||||||
180 | =cut | ||||||
181 | |||||||
182 | sub tagattr { | ||||||
183 | 0 | 0 | 1 | 0 | my ($name, $expr, $value) = @_; | ||
184 | |||||||
185 | 0 | 0 | 0 | return '' unless $expr; | |||
186 | 0 | 0 | 0 | $value = $expr unless defined $value; | |||
187 | 0 | 0 | return " $name=\"$value\""; | ||||
188 | } | ||||||
189 | |||||||
190 | =head2 tagattrs( %attrs ) | ||||||
191 | |||||||
192 | =cut | ||||||
193 | |||||||
194 | sub tagattrs { | ||||||
195 | 0 | 0 | 1 | 0 | my (%attrs) = @_; | ||
196 | |||||||
197 | 0 | 0 | my $s = ''; | ||||
198 | 0 | 0 | while (my ($k, $v) = each %attrs) { | ||||
199 | 0 | 0 | 0 | $s .= " $k=\"".escape_xml($v)."\"" if defined $v; | |||
200 | } | ||||||
201 | 0 | 0 | return $s; | ||||
202 | } | ||||||
203 | |||||||
204 | =head2 new_cycle( @items ) | ||||||
205 | |||||||
206 | Creates a subroutine reference that can be used for cycling through the | ||||||
207 | items of the C<@items> array. So, for example, you can: | ||||||
208 | |||||||
209 | my $cycle = new_cycle(qw/red green blue/); | ||||||
210 | print $cycle->(); # prints 'red' | ||||||
211 | print $cycle->(); # prints 'green' | ||||||
212 | print $cycle->(); # prints 'blue' | ||||||
213 | print $cycle->(); # prints 'red' again | ||||||
214 | |||||||
215 | =cut | ||||||
216 | |||||||
217 | sub new_cycle { | ||||||
218 | 0 | 0 | 1 | 0 | my $i = 0; | ||
219 | 0 | 0 | 0 | sub { $_[$i++ % scalar @_] }; # returns | |||
0 | 0 | ||||||
220 | } | ||||||
221 | |||||||
222 | =head1 INTERNAL(?) METHODS | ||||||
223 | |||||||
224 | =head2 _p( $expression ) | ||||||
225 | |||||||
226 | Wraps a Perl expression in a customized wrapper which will be processed | ||||||
227 | by the Tenjin preprocessor and replaced with the standard [== $expression =]. | ||||||
228 | |||||||
229 | =cut | ||||||
230 | |||||||
231 | sub _p { | ||||||
232 | 1 | 1 | 19 | "<`\#$_[0]\#`>"; | |||
233 | } | ||||||
234 | |||||||
235 | =head2 _P( $expression ) | ||||||
236 | |||||||
237 | Wrap a Perl expression in a customized wrapper which will be processed | ||||||
238 | by the Tenjin preprocessor and replaced with the standard [= $expression =], | ||||||
239 | which means the expression will be escaped. | ||||||
240 | |||||||
241 | =cut | ||||||
242 | |||||||
243 | sub _P { | ||||||
244 | 1 | 1 | 6 | "<`\$$_[0]\$`>"; | |||
245 | } | ||||||
246 | |||||||
247 | =head2 _decode_params( $s ) | ||||||
248 | |||||||
249 | =cut | ||||||
250 | |||||||
251 | sub _decode_params { | ||||||
252 | 0 | 0 | my $s = shift; | ||||
253 | |||||||
254 | 0 | 0 | return '' unless $s; | ||||
255 | |||||||
256 | 0 | $s =~ s/%3C%60%23(.*?)%23%60%3E/'[=='.decode_url($1).'=]'/ge; | |||||
0 | |||||||
257 | 0 | $s =~ s/%3C%60%24(.*?)%24%60%3E/'[='.decode_url($1).'=]'/ge; | |||||
0 | |||||||
258 | 0 | $s =~ s/<`\#(.*?)\#`>/'[=='.unescape_xml($1).'=]'/ge; | |||||
0 | |||||||
259 | 0 | $s =~ s/<`\$(.*?)\$`>/'[='.unescape_xml($1).'=]'/ge; | |||||
0 | |||||||
260 | 0 | $s =~ s/<`\#(.*?)\#`>/[==$1=]/g; | |||||
261 | 0 | $s =~ s/<`\$(.*?)\$`>/[=$1=]/g; | |||||
262 | |||||||
263 | 0 | return $s; | |||||
264 | } | ||||||
265 | |||||||
266 | 1; | ||||||
267 | |||||||
268 | =head1 SEE ALSO | ||||||
269 | |||||||
270 | L |
||||||
271 | |||||||
272 | =head1 AUTHOR | ||||||
273 | |||||||
274 | The CPAN version of Tenjin was forked by Ido Perlmuter E |
||||||
275 | from version 0.0.2 of the original plTenjin, which is developed by Makoto Kuwata | ||||||
276 | at L |
||||||
277 | |||||||
278 | Development of Tenjin is done with github at L |
||||||
279 | |||||||
280 | =head1 LICENSE AND COPYRIGHT | ||||||
281 | |||||||
282 | Tenjin is licensed under the MIT license. | ||||||
283 | |||||||
284 | Copyright (c) 2007-2010 the aforementioned authors. | ||||||
285 | |||||||
286 | Permission is hereby granted, free of charge, to any person obtaining | ||||||
287 | a copy of this software and associated documentation files (the | ||||||
288 | "Software"), to deal in the Software without restriction, including | ||||||
289 | without limitation the rights to use, copy, modify, merge, publish, | ||||||
290 | distribute, sublicense, and/or sell copies of the Software, and to | ||||||
291 | permit persons to whom the Software is furnished to do so, subject to | ||||||
292 | the following conditions: | ||||||
293 | |||||||
294 | The above copyright notice and this permission notice shall be | ||||||
295 | included in all copies or substantial portions of the Software. | ||||||
296 | |||||||
297 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
298 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||||
299 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||||
300 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||||||
301 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||||||
302 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||||
303 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||||
304 | |||||||
305 | =cut |