| 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 | 8 | 8 | 31 | use strict; | |||
| 8 | 10 | ||||||
| 8 | 200 | ||||||
| 4 | 8 | 8 | 28 | use warnings; | |||
| 8 | 11 | ||||||
| 8 | 160 | ||||||
| 5 | 8 | 8 | 4413 | use HTML::Entities; | |||
| 8 | 37063 | ||||||
| 8 | 6927 | ||||||
| 6 | |||||||
| 7 | our $VERSION = "1.000000"; | ||||||
| 8 | $VERSION = eval $VERSION; | ||||||
| 9 | |||||||
| 10 | =head1 NAME | ||||||
| 11 | |||||||
| 12 | Tenjin::Util - Utility methods for Tenjin. | ||||||
| 13 | |||||||
| 14 | =head1 SYNOPSIS | ||||||
| 15 | |||||||
| 16 | # in your templates: | ||||||
| 17 | |||||||
| 18 | # encode a URL | ||||||
| 19 | [== encode_url('http://www.google.com/search?q=tenjin&ie=utf-8&oe=utf-8&aq=t') =] | ||||||
| 20 | # returns http%3A//www.google.com/search%3Fq%3Dtenjin%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt | ||||||
| 21 | |||||||
| 22 | # escape a string of lines of HTML code | ||||||
| 23 | You & Me\nMe & You'; ?> |
||||||
| 24 | [== text2html($string) =] | ||||||
| 25 | # returns <h1>You & Me</h1> \n<h2>Me & You</h2> |
||||||
| 26 | |||||||
| 27 | =head1 DESCRIPTION | ||||||
| 28 | |||||||
| 29 | This module provides a few utility functions which can be used in your | ||||||
| 30 | templates for your convenience. These include functions to (un)escape | ||||||
| 31 | and (en/de)code URLs. | ||||||
| 32 | |||||||
| 33 | =head1 METHODS | ||||||
| 34 | |||||||
| 35 | =head2 expand_tabs( $str, [$tabwidth] ) | ||||||
| 36 | |||||||
| 37 | Receives a string that might contain tabs in it, and replaces those | ||||||
| 38 | tabs with spaces, each tab with the number of spaces defined by C<$tabwidth>, | ||||||
| 39 | or, if C<$tabwidth> was not passed, with 8 spaces. | ||||||
| 40 | |||||||
| 41 | =cut | ||||||
| 42 | |||||||
| 43 | sub expand_tabs { | ||||||
| 44 | 0 | 0 | 1 | 0 | my ($str, $tabwidth) = @_; | ||
| 45 | |||||||
| 46 | 0 | 0 | 0 | $tabwidth ||= 8; | |||
| 47 | 0 | 0 | my $s = ''; | ||||
| 48 | 0 | 0 | my $pos = 0; | ||||
| 49 | 0 | 0 | while ($str =~ /.*?\t/sg) { # /(.*?)\t/ may be slow | ||||
| 50 | 0 | 0 | my $end = $+[0]; | ||||
| 51 | 0 | 0 | my $text = substr($str, $pos, $end - 1 - $pos); | ||||
| 52 | 0 | 0 | my $n = rindex($text, "\n"); | ||||
| 53 | 0 | 0 | 0 | my $col = $n >= 0 ? length($text) - $n - 1 : length($text); | |||
| 54 | 0 | 0 | $s .= $text; | ||||
| 55 | 0 | 0 | $s .= ' ' x ($tabwidth - $col % $tabwidth); | ||||
| 56 | 0 | 0 | $pos = $end; | ||||
| 57 | } | ||||||
| 58 | 0 | 0 | my $rest = substr($str, $pos); | ||||
| 59 | 0 | 0 | return $s; | ||||
| 60 | } | ||||||
| 61 | |||||||
| 62 | =head2 escape_xml( $str ) | ||||||
| 63 | |||||||
| 64 | Receives a string of XML (or (x)HTML) code and converts the characters | ||||||
| 65 | <>&\' to HTML entities. This is the method that is invoked when you use | ||||||
| 66 | [= $expression =] in your templates. | ||||||
| 67 | |||||||
| 68 | =cut | ||||||
| 69 | |||||||
| 70 | sub escape_xml { | ||||||
| 71 | 1 | 1 | 1 | 12 | encode_entities($_[0], '<>&"\''); | ||
| 72 | } | ||||||
| 73 | |||||||
| 74 | =head2 unescape_xml( $str ) | ||||||
| 75 | |||||||
| 76 | Receives a string of escaped XML (or (x)HTML) code (for example, a string | ||||||
| 77 | that was escaped with the L |
||||||
| 78 | and 'unescapes' all HTML entities back to their actual characters. | ||||||
| 79 | |||||||
| 80 | =cut | ||||||
| 81 | |||||||
| 82 | sub unescape_xml { | ||||||
| 83 | 1 | 1 | 1 | 219 | decode_entities($_[0]); | ||
| 84 | } | ||||||
| 85 | |||||||
| 86 | =head2 encode_url( $url ) | ||||||
| 87 | |||||||
| 88 | Receives a URL and encodes it by escaping 'non-standard' characters. | ||||||
| 89 | |||||||
| 90 | =cut | ||||||
| 91 | |||||||
| 92 | sub encode_url { | ||||||
| 93 | 1 | 1 | 1 | 9 | my $url = shift; | ||
| 94 | |||||||
| 95 | 1 | 5 | $url =~ s/([^-A-Za-z0-9_.\/])/sprintf("%%%02X", ord($1))/sge; | ||||
| 9 | 24 | ||||||
| 96 | 1 | 3 | $url =~ tr/ /+/; | ||||
| 97 | 1 | 3 | return $url; | ||||
| 98 | } | ||||||
| 99 | |||||||
| 100 | =head2 decode_url( $url ) | ||||||
| 101 | |||||||
| 102 | Does the opposite of L |
||||||
| 103 | |||||||
| 104 | =cut | ||||||
| 105 | |||||||
| 106 | sub decode_url { | ||||||
| 107 | 0 | 0 | 1 | 0 | my $url = shift; | ||
| 108 | |||||||
| 109 | 0 | 0 | $url =~ s/\%([a-fA-F0-9][a-fA-F0-9])/pack('C', hex($1))/sge; | ||||
| 0 | 0 | ||||||
| 110 | 0 | 0 | return $url; | ||||
| 111 | } | ||||||
| 112 | |||||||
| 113 | =head2 checked( $val ) | ||||||
| 114 | |||||||
| 115 | Receives a value of some sort, and if it is a true value, returns the string | ||||||
| 116 | ' checked="checked"' which can be appended to HTML checkboxes. | ||||||
| 117 | |||||||
| 118 | =cut | ||||||
| 119 | |||||||
| 120 | sub checked { | ||||||
| 121 | 0 | 0 | 0 | 1 | 0 | $_[0] ? ' checked="checked"' : ''; | |
| 122 | } | ||||||
| 123 | |||||||
| 124 | =head2 selected( $val ) | ||||||
| 125 | |||||||
| 126 | Receives a value of some sort, and if it is a true value, returns the string | ||||||
| 127 | ' selected="selected"' which can be used in an option in an HTML select box. | ||||||
| 128 | |||||||
| 129 | =cut | ||||||
| 130 | |||||||
| 131 | sub selected { | ||||||
| 132 | 0 | 0 | 0 | 1 | 0 | $_[0] ? ' selected="selected"' : ''; | |
| 133 | } | ||||||
| 134 | |||||||
| 135 | =head2 disabled( $val ) | ||||||
| 136 | |||||||
| 137 | Receives a value of some sort, and if it is a true value, returns the string | ||||||
| 138 | ' disabled="disabled"' which can be used in an HTML input. | ||||||
| 139 | |||||||
| 140 | =cut | ||||||
| 141 | |||||||
| 142 | sub disabled { | ||||||
| 143 | 0 | 0 | 0 | 1 | 0 | $_[0] ? ' disabled="disabled"' : ''; | |
| 144 | } | ||||||
| 145 | |||||||
| 146 | =head2 nl2br( $text ) | ||||||
| 147 | |||||||
| 148 | Receives a string of text containing lines delimited by newline characters | ||||||
| 149 | (\n, or possibly \r\n) and appends an HTML line break ( ) to every |
||||||
| 150 | line (the newline character is left untouched). | ||||||
| 151 | |||||||
| 152 | =cut | ||||||
| 153 | |||||||
| 154 | sub nl2br { | ||||||
| 155 | 0 | 0 | 1 | 0 | my $text = shift; | ||
| 156 | |||||||
| 157 | 0 | 0 | $text =~ s/(\r?\n)/ $1/g; |
||||
| 158 | 0 | 0 | return $text; | ||||
| 159 | } | ||||||
| 160 | |||||||
| 161 | =head2 text2html( $text ) | ||||||
| 162 | |||||||
| 163 | Receives a string of text containing lines delimited by newline characters, | ||||||
| 164 | and possibly some XML (or (x)HTML) code, escapes that code with | ||||||
| 165 | L |
||||||
| 166 | to every line with L |
||||||
| 167 | |||||||
| 168 | =cut | ||||||
| 169 | |||||||
| 170 | sub text2html { | ||||||
| 171 | 0 | 0 | 1 | 0 | nl2br(escape_xml($_[0])); | ||
| 172 | } | ||||||
| 173 | |||||||
| 174 | =head2 tagattr( $name, $expr, [$value] ) | ||||||
| 175 | |||||||
| 176 | =cut | ||||||
| 177 | |||||||
| 178 | sub tagattr { | ||||||
| 179 | 0 | 0 | 1 | 0 | my ($name, $expr, $value) = @_; | ||
| 180 | |||||||
| 181 | 0 | 0 | 0 | return '' unless $expr; | |||
| 182 | 0 | 0 | 0 | $value = $expr unless defined $value; | |||
| 183 | 0 | 0 | return " $name=\"$value\""; | ||||
| 184 | } | ||||||
| 185 | |||||||
| 186 | =head2 tagattrs( %attrs ) | ||||||
| 187 | |||||||
| 188 | =cut | ||||||
| 189 | |||||||
| 190 | sub tagattrs { | ||||||
| 191 | 0 | 0 | 1 | 0 | my (%attrs) = @_; | ||
| 192 | |||||||
| 193 | 0 | 0 | my $s = ''; | ||||
| 194 | 0 | 0 | while (my ($k, $v) = each %attrs) { | ||||
| 195 | 0 | 0 | 0 | $s .= " $k=\"".escape_xml($v)."\"" if defined $v; | |||
| 196 | } | ||||||
| 197 | 0 | 0 | return $s; | ||||
| 198 | } | ||||||
| 199 | |||||||
| 200 | =head2 new_cycle( @items ) | ||||||
| 201 | |||||||
| 202 | Creates a subroutine reference that can be used for cycling through the | ||||||
| 203 | items of the C<@items> array. So, for example, you can: | ||||||
| 204 | |||||||
| 205 | my $cycle = new_cycle(qw/red green blue/); | ||||||
| 206 | print $cycle->(); # prints 'red' | ||||||
| 207 | print $cycle->(); # prints 'green' | ||||||
| 208 | print $cycle->(); # prints 'blue' | ||||||
| 209 | print $cycle->(); # prints 'red' again | ||||||
| 210 | |||||||
| 211 | =cut | ||||||
| 212 | |||||||
| 213 | sub new_cycle { | ||||||
| 214 | 0 | 0 | 1 | 0 | my $i = 0; | ||
| 215 | 0 | 0 | 0 | sub { $_[$i++ % scalar @_] }; # returns | |||
| 0 | 0 | ||||||
| 216 | } | ||||||
| 217 | |||||||
| 218 | =head1 INTERNAL(?) METHODS | ||||||
| 219 | |||||||
| 220 | =head2 _p( $expression ) | ||||||
| 221 | |||||||
| 222 | Wraps a Perl expression in a customized wrapper which will be processed | ||||||
| 223 | by the Tenjin preprocessor and replaced with the standard [== $expression =]. | ||||||
| 224 | |||||||
| 225 | =cut | ||||||
| 226 | |||||||
| 227 | sub _p { | ||||||
| 228 | 1 | 1 | 11 | "<`\#$_[0]\#`>"; | |||
| 229 | } | ||||||
| 230 | |||||||
| 231 | =head2 _P( $expression ) | ||||||
| 232 | |||||||
| 233 | Wrap a Perl expression in a customized wrapper which will be processed | ||||||
| 234 | by the Tenjin preprocessor and replaced with the standard [= $expression =], | ||||||
| 235 | which means the expression will be escaped. | ||||||
| 236 | |||||||
| 237 | =cut | ||||||
| 238 | |||||||
| 239 | sub _P { | ||||||
| 240 | 1 | 1 | 4 | "<`\$$_[0]\$`>"; | |||
| 241 | } | ||||||
| 242 | |||||||
| 243 | =head2 _decode_params( $s ) | ||||||
| 244 | |||||||
| 245 | =cut | ||||||
| 246 | |||||||
| 247 | sub _decode_params { | ||||||
| 248 | 0 | 0 | my $s = shift; | ||||
| 249 | |||||||
| 250 | 0 | 0 | return '' unless $s; | ||||
| 251 | |||||||
| 252 | 0 | $s =~ s/%3C%60%23(.*?)%23%60%3E/'[=='.decode_url($1).'=]'/ge; | |||||
| 0 | |||||||
| 253 | 0 | $s =~ s/%3C%60%24(.*?)%24%60%3E/'[='.decode_url($1).'=]'/ge; | |||||
| 0 | |||||||
| 254 | 0 | $s =~ s/<`\#(.*?)\#`>/'[=='.unescape_xml($1).'=]'/ge; | |||||
| 0 | |||||||
| 255 | 0 | $s =~ s/<`\$(.*?)\$`>/'[='.unescape_xml($1).'=]'/ge; | |||||
| 0 | |||||||
| 256 | 0 | $s =~ s/<`\#(.*?)\#`>/[==$1=]/g; | |||||
| 257 | 0 | $s =~ s/<`\$(.*?)\$`>/[=$1=]/g; | |||||
| 258 | |||||||
| 259 | 0 | return $s; | |||||
| 260 | } | ||||||
| 261 | |||||||
| 262 | 1; | ||||||
| 263 | |||||||
| 264 | =head1 SEE ALSO | ||||||
| 265 | |||||||
| 266 | L |
||||||
| 267 | |||||||
| 268 | =head1 AUTHOR, LICENSE AND COPYRIGHT | ||||||
| 269 | |||||||
| 270 | See L |
||||||
| 271 | |||||||
| 272 | =cut |