| 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 |