File Coverage

blib/lib/Mojo/Util.pm
Criterion Covered Total %
statement 343 343 100.0
branch 126 132 95.4
condition 46 52 88.4
subroutine 78 78 100.0
pod 36 36 100.0
total 629 641 98.1


line stmt bran cond sub pod time code
1             package Mojo::Util;
2 102     102   707 use Mojo::Base -strict;
  102         204  
  102         2359  
3              
4 102     102   633 use Carp qw(carp croak);
  102         179  
  102         8971  
5 102     102   69824 use Data::Dumper ();
  102         734083  
  102         3475  
6 102     102   710 use Digest::MD5 qw(md5 md5_hex);
  102         207  
  102         7706  
7 102     102   62050 use Digest::SHA qw(hmac_sha1_hex sha1 sha1_hex);
  102         331478  
  102         10052  
8 102     102   62937 use Encode qw(find_encoding);
  102         1042900  
  102         8151  
9 102     102   803 use Exporter qw(import);
  102         199  
  102         3113  
10 102     102   1907 use File::Basename qw(dirname);
  102         227  
  102         11956  
11 102     102   84804 use Getopt::Long qw(GetOptionsFromArray);
  102         1358433  
  102         566  
12 102     102   81058 use IO::Compress::Gzip;
  102         4514283  
  102         6554  
13 102     102   51801 use IO::Poll qw(POLLIN POLLPRI);
  102         92893  
  102         8062  
14 102     102   62604 use IO::Uncompress::Gunzip;
  102         1620851  
  102         5620  
15 102     102   854 use List::Util qw(min);
  102         320  
  102         12855  
16 102     102   50719 use MIME::Base64 qw(decode_base64 encode_base64);
  102         69089  
  102         7589  
17 102     102   62005 use Pod::Usage qw(pod2usage);
  102         4093180  
  102         9296  
18 102     102   68255 use Socket qw(inet_pton AF_INET6 AF_INET);
  102         415748  
  102         18898  
19 102     102   47771 use Sub::Util qw(set_subname);
  102         33523  
  102         6620  
20 102     102   868 use Symbol qw(delete_package);
  102         286  
  102         5280  
21 102     102   55080 use Time::HiRes ();
  102         140172  
  102         2932  
22 102     102   63212 use Unicode::Normalize ();
  102         225811  
  102         8042  
23              
24             # Check for monotonic clock support
25 102     102   888 use constant MONOTONIC => !!eval { Time::HiRes::clock_gettime(Time::HiRes::CLOCK_MONOTONIC()) };
  102         265  
  102         302  
  102         759  
26              
27             # Punycode bootstring parameters
28             use constant {
29 102         262176 PC_BASE => 36,
30             PC_TMIN => 1,
31             PC_TMAX => 26,
32             PC_SKEW => 38,
33             PC_DAMP => 700,
34             PC_INITIAL_BIAS => 72,
35             PC_INITIAL_N => 128
36 102     102   13944 };
  102         313  
37              
38             # To generate a new HTML entity table run this command
39             # perl examples/entities.pl > lib/Mojo/resources/html_entities.txt
40             my %ENTITIES;
41             {
42             # Don't use Mojo::File here due to circular dependencies
43             my $path = File::Spec->catfile(dirname(__FILE__), 'resources', 'html_entities.txt');
44              
45             open my $file, '<', $path or croak "Unable to open html entities file ($path): $!";
46             my $lines = do { local $/; <$file> };
47              
48             for my $line (split /\n/, $lines) {
49             next unless $line =~ /^(\S+)\s+U\+(\S+)(?:\s+U\+(\S+))?/;
50             $ENTITIES{$1} = defined $3 ? (chr(hex $2) . chr(hex $3)) : chr(hex $2);
51             }
52             }
53              
54             # Characters that should be escaped in XML
55             my %XML = ('&' => '&', '<' => '<', '>' => '>', '"' => '"', '\'' => ''');
56              
57             # "Sun, 06 Nov 1994 08:49:37 GMT" and "Sunday, 06-Nov-94 08:49:37 GMT"
58             my $EXPIRES_RE = qr/(\w+\W+\d+\W+\w+\W+\d+\W+\d+:\d+:\d+\W*\w+)/;
59              
60             # Header key/value pairs
61             my $QUOTED_VALUE_RE = qr/\G=\s*("(?:\\\\|\\"|[^"])*")/;
62             my $UNQUOTED_VALUE_RE = qr/\G=\s*([^;, ]*)/;
63              
64             # HTML entities
65             my $ENTITY_RE = qr/&(?:\#((?:[0-9]{1,7}|x[0-9a-fA-F]{1,6}));|(\w+[;=]?))/;
66              
67             # Encoding and pattern cache
68             my (%ENCODING, %PATTERN);
69              
70             our @EXPORT_OK = (
71             qw(b64_decode b64_encode camelize class_to_file class_to_path decamelize decode deprecated dumper encode),
72             qw(extract_usage getopt gunzip gzip header_params hmac_sha1_sum html_attr_unescape html_unescape humanize_bytes),
73             qw(md5_bytes md5_sum monkey_patch network_contains punycode_decode punycode_encode quote scope_guard secure_compare),
74             qw(sha1_bytes sha1_sum slugify split_cookie_header split_header steady_time tablify term_escape trim unindent),
75             qw(unquote url_escape url_unescape xml_escape xor_encode)
76             );
77              
78             # Aliases
79             monkey_patch(__PACKAGE__, 'b64_decode', \&decode_base64);
80             monkey_patch(__PACKAGE__, 'b64_encode', \&encode_base64);
81             monkey_patch(__PACKAGE__, 'hmac_sha1_sum', \&hmac_sha1_hex);
82             monkey_patch(__PACKAGE__, 'md5_bytes', \&md5);
83             monkey_patch(__PACKAGE__, 'md5_sum', \&md5_hex);
84             monkey_patch(__PACKAGE__, 'sha1_bytes', \&sha1);
85             monkey_patch(__PACKAGE__, 'sha1_sum', \&sha1_hex);
86              
87             # Use a monotonic clock if possible
88             monkey_patch(__PACKAGE__, 'steady_time',
89 116935     116935 1 226312 MONOTONIC ? sub () { Time::HiRes::clock_gettime(Time::HiRes::CLOCK_MONOTONIC()) } : \&Time::HiRes::time);
90              
91             sub camelize {
92 42     42 1 1385 my $str = shift;
93 42 100       201 return $str if $str =~ /^[A-Z]/;
94              
95             # CamelCase words
96             return join '::', map {
97 39         164 join('', map { ucfirst lc } split /_/)
  53         148  
  81         447  
98             } split /-/, $str;
99             }
100              
101             sub class_to_file {
102 10     10 1 2561 my $class = shift;
103 10         64 $class =~ s/::|'//g;
104 10         60 $class =~ s/([A-Z])([A-Z]*)/$1 . lc $2/ge;
  18         78  
105 10         24 return decamelize($class);
106             }
107              
108 849     849 1 333546 sub class_to_path { join '.', join('/', split(/::|'/, shift)), 'pm' }
109              
110             sub decamelize {
111 28     28 1 2917 my $str = shift;
112 28 100       172 return $str if $str !~ /^[A-Z]/;
113              
114             # snake_case words
115             return join '-', map {
116 23         100 join('_', map {lc} grep {length} split /([A-Z]{1}[^A-Z]*)/)
  26         135  
  49         321  
  98         165  
117             } split /::/, $str;
118             }
119              
120             sub decode {
121 7598     7598 1 25567 my ($encoding, $bytes) = @_;
122 7598 100       11600 return undef unless eval { $bytes = _encoding($encoding)->decode("$bytes", 1); 1 };
  7598         17205  
  7511         68582  
123 7511         24898 return $bytes;
124             }
125              
126             sub deprecated {
127 2     2 1 4346 local $Carp::CarpLevel = 1;
128 2 100       289 $ENV{MOJO_FATAL_DEPRECATIONS} ? croak @_ : carp @_;
129             }
130              
131 294     294 1 4581 sub dumper { Data::Dumper->new([@_])->Indent(1)->Sortkeys(1)->Terse(1)->Useqq(1)->Dump }
132              
133 10756     10756 1 47653 sub encode { _encoding($_[0])->encode("$_[1]", 0) }
134              
135             sub extract_usage {
136 26 100   26 1 2883 my $file = @_ ? "$_[0]" : (caller)[1];
137              
138 26         411 open my $handle, '>', \my $output;
139 26         971 pod2usage -exitval => 'noexit', -input => $file, -output => $handle;
140 26         476564 $output =~ s/^.*\n|\n$//;
141 26         184 $output =~ s/\n$//;
142              
143 26         120 return unindent($output);
144             }
145              
146             sub getopt {
147 117 100   117 1 11656 my ($array, $opts) = map { ref $_[0] eq 'ARRAY' ? shift : $_ } \@ARGV, [];
  234         1096  
148              
149 117         979 my $save = Getopt::Long::Configure(qw(default no_auto_abbrev no_ignore_case), @$opts);
150 117         11475 my $result = GetOptionsFromArray $array, @_;
151 117         46454 Getopt::Long::Configure($save);
152              
153 117         11433 return $result;
154             }
155              
156             sub gunzip {
157 2     2 1 1174 my $compressed = shift;
158 2 50       58 IO::Uncompress::Gunzip::gunzip \$compressed, \my $uncompressed
159             or croak "Couldn't gunzip: $IO::Uncompress::Gunzip::GzipError";
160 2         4747 return $uncompressed;
161             }
162              
163             sub gzip {
164 58     58 1 11478 my $uncompressed = shift;
165 58 50       597 IO::Compress::Gzip::gzip \$uncompressed, \my $compressed or croak "Couldn't gzip: $IO::Compress::Gzip::GzipError";
166 58         198149 return $compressed;
167             }
168              
169             sub header_params {
170 16     16 1 3094 my $value = shift;
171              
172 16         29 my $params = {};
173 16         87 while ($value =~ /\G[;\s]*([^=;, ]+)\s*/gc) {
174 20         45 my $name = $1;
175              
176             # Quoted value
177 20 100 66     141 if ($value =~ /$QUOTED_VALUE_RE/gco) { $params->{$name} //= unquote($1) }
  4 100       30  
178              
179             # Unquoted value
180 15   66     103 elsif ($value =~ /$UNQUOTED_VALUE_RE/gco) { $params->{$name} //= $1 }
181             }
182              
183 16   100     112 return ($params, substr($value, pos($value) // 0));
184             }
185              
186 34133     34133 1 52294 sub html_attr_unescape { _html(shift, 1) }
187 3006     3006 1 23193 sub html_unescape { _html(shift, 0) }
188              
189             sub humanize_bytes {
190 19     19 1 2621 my $size = shift;
191              
192 19 100       63 my $prefix = $size < 0 ? '-' : '';
193              
194 19 100       71 return "$prefix${size}B" if ($size = abs $size) < 1024;
195 16 100       68 return $prefix . _round($size) . 'KiB' if ($size /= 1024) < 1024;
196 11 100       46 return $prefix . _round($size) . 'MiB' if ($size /= 1024) < 1024;
197 8 100       43 return $prefix . _round($size) . 'GiB' if ($size /= 1024) < 1024;
198 2         12 return $prefix . _round($size /= 1024) . 'TiB';
199             }
200              
201             sub monkey_patch {
202 54664     54664 1 144652 my ($class, %patch) = @_;
203 102     102   1104 no strict 'refs';
  102         298  
  102         4344  
204 102     102   824 no warnings 'redefine';
  102         321  
  102         43211  
205 54664         373560 *{"${class}::$_"} = set_subname("${class}::$_", $patch{$_}) for keys %patch;
  54884         704832  
206             }
207              
208             sub network_contains {
209 99     99 1 7361 my ($cidr, $addr) = @_;
210 99 100 100     417 return undef unless length $cidr && length $addr;
211              
212             # Parse inputs
213 93         314 my ($net, $mask) = split m!/!, $cidr, 2;
214 93         272 my $v6 = $net =~ /:/;
215 93 100 100     386 return undef if $v6 xor $addr =~ /:/;
216              
217             # Convert addresses to binary
218 91 100       504 return undef unless $net = inet_pton($v6 ? AF_INET6 : AF_INET, $net);
    100          
219 89 100       300 return undef unless $addr = inet_pton($v6 ? AF_INET6 : AF_INET, $addr);
    100          
220 87 100       196 my $length = $v6 ? 128 : 32;
221              
222             # Apply mask if given
223 87 100       492 $addr &= pack "B$length", '1' x $mask if defined $mask;
224              
225             # Compare
226 87         1022 return 0 == unpack "B$length", ($net ^ $addr);
227             }
228              
229             # Direct translation of RFC 3492
230             sub punycode_decode {
231 23     23 1 2597 my $input = shift;
232 102     102   988 use integer;
  102         249  
  102         919  
233              
234 23         60 my ($n, $i, $bias, @output) = (PC_INITIAL_N, 0, PC_INITIAL_BIAS);
235              
236             # Consume all code points before the last delimiter
237 23 100       208 push @output, split(//, $1) if $input =~ s/(.*)\x2d//s;
238              
239 23         76 while (length $input) {
240 219         321 my ($oldi, $w) = ($i, 1);
241              
242             # Base to infinity in steps of base
243 219         288 for (my $k = PC_BASE; 1; $k += PC_BASE) {
244 458         691 my $digit = ord substr $input, 0, 1, '';
245 458 100       699 $digit = $digit < 0x40 ? $digit + (26 - 0x30) : ($digit & 0x1f) - 1;
246 458         547 $i += $digit * $w;
247 458         567 my $t = $k - $bias;
248 458 100       744 $t = $t < PC_TMIN ? PC_TMIN : $t > PC_TMAX ? PC_TMAX : $t;
    100          
249 458 100       806 last if $digit < $t;
250 239         319 $w *= PC_BASE - $t;
251             }
252              
253 219         379 $bias = _adapt($i - $oldi, @output + 1, $oldi == 0);
254 219         338 $n += $i / (@output + 1);
255 219         282 $i = $i % (@output + 1);
256 219         593 splice @output, $i++, 0, chr $n;
257             }
258              
259 23         157 return join '', @output;
260             }
261              
262             # Direct translation of RFC 3492
263             sub punycode_encode {
264 64     64 1 16414 my $output = shift;
265 102     102   38132 use integer;
  102         306  
  102         569  
266              
267 64         152 my ($n, $delta, $bias) = (PC_INITIAL_N, 0, PC_INITIAL_BIAS);
268              
269             # Extract basic code points
270 64         241 my @input = map {ord} split //, $output;
  553         817  
271 64         391 $output =~ s/[^\x00-\x7f]+//gs;
272 64         163 my $h = my $basic = length $output;
273 64 100       194 $output .= "\x2d" if $basic > 0;
274              
275 64         127 for my $m (sort grep { $_ >= PC_INITIAL_N } @input) {
  553         1034  
276 260 100       472 next if $m < $n;
277 218         324 $delta += ($m - $n) * ($h + 1);
278 218         344 $n = $m;
279              
280 218         319 for my $c (@input) {
281              
282 3630 100       5774 if ($c < $n) { $delta++ }
  2033 100       2497  
283             elsif ($c == $n) {
284 260         311 my $q = $delta;
285              
286             # Base to infinity in steps of base
287 260         334 for (my $k = PC_BASE; 1; $k += PC_BASE) {
288 581         723 my $t = $k - $bias;
289 581 100       990 $t = $t < PC_TMIN ? PC_TMIN : $t > PC_TMAX ? PC_TMAX : $t;
    100          
290 581 100       957 last if $q < $t;
291 321         454 my $o = $t + (($q - $t) % (PC_BASE - $t));
292 321 100       682 $output .= chr $o + ($o < 26 ? 0x61 : 0x30 - 26);
293 321         558 $q = ($q - $t) / (PC_BASE - $t);
294             }
295              
296 260 50       563 $output .= chr $q + ($q < 26 ? 0x61 : 0x30 - 26);
297 260         530 $bias = _adapt($delta, $h + 1, $h == $basic);
298 260         342 $delta = 0;
299 260         380 $h++;
300             }
301             }
302              
303 218         255 $delta++;
304 218         306 $n++;
305             }
306              
307 64         308 return $output;
308             }
309              
310             sub quote {
311 21     21 1 2939 my $str = shift;
312 21         132 $str =~ s/(["\\])/\\$1/g;
313 21         112 return qq{"$str"};
314             }
315              
316 18     18 1 2857 sub scope_guard { Mojo::Util::_Guard->new(cb => shift) }
317              
318             sub secure_compare {
319 86     86 1 12871 my ($one, $two) = @_;
320 86         183 my $r = length $one != length $two;
321 86 100       233 $two = $one if $r;
322 86         1564 $r |= ord(substr $one, $_) ^ ord(substr $two, $_) for 0 .. length($one) - 1;
323 86         487 return $r == 0;
324             }
325              
326             sub slugify {
327 14     14 1 2622 my ($value, $allow_unicode) = @_;
328              
329 14 100       37 if ($allow_unicode) {
330              
331             # Force unicode semantics by upgrading string
332 6         93 utf8::upgrade($value = Unicode::Normalize::NFKC($value));
333 6         57 $value =~ s/[^\w\s-]+//g;
334             }
335             else {
336 8         81 $value = Unicode::Normalize::NFKD($value);
337 102     102   99424 $value =~ s/[^a-zA-Z0-9_\p{PosixSpace}-]+//g;
  102         300  
  102         1853  
  8         72  
338             }
339 14         41 (my $new = lc trim($value)) =~ s/[-\s]+/-/g;
340              
341 14         6164 return $new;
342             }
343              
344 1007     1007 1 5949 sub split_cookie_header { _header(shift, 1) }
345 210     210 1 3220 sub split_header { _header(shift, 0) }
346              
347             sub tablify {
348 18     18 1 2453 my $rows = shift;
349              
350 18         32 my @spec;
351 18         55 for my $row (@$rows) {
352 87         164 for my $i (0 .. $#$row) {
353 176   100     378 ($row->[$i] //= '') =~ y/\r\n//d;
354 176         273 my $len = length $row->[$i];
355 176 100 100     469 $spec[$i] = $len if $len >= ($spec[$i] // 0);
356             }
357             }
358              
359 18         86 my @fm = (map({"\%-${_}s"} @spec[0 .. $#spec - 1]), '%s');
  23         94  
360 18         46 return join '', map { sprintf join(' ', @fm[0 .. $#$_]) . "\n", @$_ } @$rows;
  87         506  
361             }
362              
363             sub term_escape {
364 4     4 1 2723 my $str = shift;
365 4         28 $str =~ s/([\x00-\x09\x0b-\x1f\x7f\x80-\x9f])/sprintf '\\x%02x', ord $1/ge;
  16         65  
366 4         28 return $str;
367             }
368              
369             sub trim {
370 1372     1372 1 4827 my $str = shift;
371 1372         4467 $str =~ s/^\s+//;
372 1372         3872 $str =~ s/\s+$//;
373 1372         3887 return $str;
374             }
375              
376             sub unindent {
377 37     37 1 3041 my $str = shift;
378 37 100       614 my $min = min map { m/^([ \t]*)/; length $1 || () } split /\n/, $str;
  426         809  
  426         1141  
379 37 100       808 $str =~ s/^[ \t]{0,$min}//gm if $min;
380 37         653 return $str;
381             }
382              
383             sub unquote {
384 48     48 1 2674 my $str = shift;
385 48 50       280 return $str unless $str =~ s/^"(.*)"$/$1/g;
386 48         140 $str =~ s/\\\\/\\/g;
387 48         114 $str =~ s/\\"/"/g;
388 48         125 return $str;
389             }
390              
391             sub url_escape {
392 6170     6170 1 20413 my ($str, $pattern) = @_;
393              
394 6170 100       11171 if ($pattern) {
395 6155 100       14103 unless (exists $PATTERN{$pattern}) {
396 136         1715 (my $quoted = $pattern) =~ s!([/\$\[])!\\$1!g;
397 136 50       30247 $PATTERN{$pattern} = eval "sub { \$_[0] =~ s/([$quoted])/sprintf '%%%02X', ord \$1/ge }" or croak $@;
398             }
399 6155         137256 $PATTERN{$pattern}->($str);
400             }
401 15         108 else { $str =~ s/([^A-Za-z0-9\-._~])/sprintf '%%%02X', ord $1/ge }
  22         129  
402              
403 6170         24200 return $str;
404             }
405              
406             sub url_unescape {
407 7753     7753 1 19571 my $str = shift;
408 7753         16235 $str =~ s/%([0-9a-fA-F]{2})/chr hex $1/ge;
  793         2884  
409 7753         17521 return $str;
410             }
411              
412             sub xml_escape {
413 486 100 66 486 1 8515 return $_[0] if ref $_[0] && ref $_[0] eq 'Mojo::ByteStream';
  8561 100 100 8561   70504  
414 485   50     1002 my $str = shift // '';
  6594   100     13960  
415 485         998 $str =~ s/([&<>"'])/$XML{$1}/ge;
  42         164  
  6594         13681  
  7808         22023  
416 485         1974 return $str;
  6593         16125  
417             }
418              
419             sub xor_encode {
420 294     294 1 3089 my ($input, $key) = @_;
421              
422             # Encode with variable key length
423 294         476 my $len = length $key;
424 294         548 my $buffer = my $output = '';
425 294         2176 $output .= $buffer ^ $key while length($buffer = substr($input, 0, $len, '')) == $len;
426 294         1873 return $output .= $buffer ^ substr($key, 0, length $buffer, '');
427             }
428              
429             sub _adapt {
430 479     479   806 my ($delta, $numpoints, $firsttime) = @_;
431 102     102   2391922 use integer;
  102         262  
  102         683  
432              
433 479 100       751 $delta = $firsttime ? $delta / PC_DAMP : $delta / 2;
434 479         613 $delta += $delta / $numpoints;
435 479         600 my $k = 0;
436 479         845 while ($delta > ((PC_BASE - PC_TMIN) * PC_TMAX) / 2) {
437 110         124 $delta /= PC_BASE - PC_TMIN;
438 110         176 $k += PC_BASE;
439             }
440              
441 479         799 return $k + (((PC_BASE - PC_TMIN + 1) * $delta) / ($delta + PC_SKEW));
442             }
443              
444 18354   66 18354   132147 sub _encoding { $ENCODING{$_[0]} //= find_encoding($_[0]) // croak "Unknown encoding '$_[0]'" }
      66        
445              
446             sub _entity {
447 1021     1021   2569 my ($point, $name, $attr) = @_;
448              
449             # Code point
450 1021 100       2245 return chr($point !~ /^x/ ? $point : hex $point) unless defined $name;
    100          
451              
452             # Named character reference
453 980         1329 my $rest = my $last = '';
454 980         1895 while (length $name) {
455             return $ENTITIES{$name} . reverse $rest
456 1018 100 100     6074 if exists $ENTITIES{$name} && (!$attr || $name =~ /;$/ || $last !~ /[A-Za-z0-9=]/);
      100        
457 48         109 $rest .= $last = chop $name;
458             }
459 10         61 return '&' . reverse $rest;
460             }
461              
462             sub _header {
463 1217     1217   2623 my ($str, $cookie) = @_;
464              
465 1217         2166 my (@tree, @part);
466 1217         4320 while ($str =~ /\G[,;\s]*([^=;, ]+)\s*/gc) {
467 798         2077 push @part, $1, undef;
468 798   100     2869 my $expires = $cookie && @part > 2 && lc $1 eq 'expires';
469              
470             # Special "expires" value
471 798 100 100     5544 if ($expires && $str =~ /\G=\s*$EXPIRES_RE/gco) { $part[-1] = $1 }
  120 100       342  
    100          
472              
473             # Quoted value
474 42         120 elsif ($str =~ /$QUOTED_VALUE_RE/gco) { $part[-1] = unquote $1 }
475              
476             # Unquoted value
477 538         1231 elsif ($str =~ /$UNQUOTED_VALUE_RE/gco) { $part[-1] = $1 }
478              
479             # Separator
480 798 100       3010 next unless $str =~ /\G[;\s]*,\s*/gc;
481 107         301 push @tree, [@part];
482 107         382 @part = ();
483             }
484              
485             # Take care of final part
486 1217 100       5160 return [@part ? (@tree, \@part) : @tree];
487             }
488              
489             sub _html {
490 37139     37139   52962 my ($str, $attr) = @_;
491 37139         48468 $str =~ s/$ENTITY_RE/_entity($1, $2, $attr)/geo;
  1021         1956  
492 37139         162608 return $str;
493             }
494              
495             sub _options {
496              
497             # Hash or name (one)
498 1804 100   1804   5758 return ref $_[0] eq 'HASH' ? (undef, %{shift()}) : @_ if @_ == 1;
  999 100       3427  
499              
500             # Name and values (odd)
501 349 100       1165 return shift, @_ if @_ % 2;
502              
503             # Name and hash or just values (even)
504 269 100       1180 return ref $_[1] eq 'HASH' ? (shift, %{shift()}) : (undef, @_);
  18         104  
505             }
506              
507             # This may break in the future, but is worth it for performance
508 771     771   14571 sub _readable { !!(IO::Poll::_poll(@_[0, 1], my $m = POLLIN | POLLPRI) > 0) }
509              
510 16 100   16   214 sub _round { $_[0] < 10 ? int($_[0] * 10 + 0.5) / 10 : int($_[0] + 0.5) }
511              
512             sub _stash {
513 21250     21250   38573 my ($name, $object) = (shift, shift);
514              
515             # Hash
516 21250 100 100     113028 return $object->{$name} //= {} unless @_;
517              
518             # Get
519 1337 100 100     5374 return $object->{$name}{$_[0]} unless @_ > 1 || ref $_[0];
520              
521             # Set
522 1099 100       4092 my $values = ref $_[0] ? $_[0] : {@_};
523 1099         3770 @{$object->{$name}}{keys %$values} = values %$values;
  1099         3133  
524              
525 1099         4550 return $object;
526             }
527              
528             sub _teardown {
529 826 50   826   41307 return unless my $class = shift;
530              
531             # @ISA has to be cleared first because of circular references
532 102     102   100842 no strict 'refs';
  102         282  
  102         10004  
533 826         1258 @{"${class}::ISA"} = ();
  826         12457  
534 826         3745 delete_package $class;
535             }
536              
537             package Mojo::Util::_Guard;
538 102     102   827 use Mojo::Base -base;
  102         257  
  102         1226  
539              
540 18     18   1415 sub DESTROY { shift->{cb}() }
541              
542             1;
543              
544             =encoding utf8
545              
546             =head1 NAME
547              
548             Mojo::Util - Portable utility functions
549              
550             =head1 SYNOPSIS
551              
552             use Mojo::Util qw(b64_encode url_escape url_unescape);
553              
554             my $str = 'test=23';
555             my $escaped = url_escape $str;
556             say url_unescape $escaped;
557             say b64_encode $escaped, '';
558              
559             =head1 DESCRIPTION
560              
561             L provides portable utility functions for L.
562              
563             =head1 FUNCTIONS
564              
565             L implements the following functions, which can be imported individually.
566              
567             =head2 b64_decode
568              
569             my $bytes = b64_decode $b64;
570              
571             Base64 decode bytes with L.
572              
573             =head2 b64_encode
574              
575             my $b64 = b64_encode $bytes;
576             my $b64 = b64_encode $bytes, "\n";
577              
578             Base64 encode bytes with L, the line ending defaults to a newline.
579              
580             =head2 camelize
581              
582             my $camelcase = camelize $snakecase;
583              
584             Convert C string to C and replace C<-> with C<::>.
585              
586             # "FooBar"
587             camelize 'foo_bar';
588              
589             # "FooBar::Baz"
590             camelize 'foo_bar-baz';
591              
592             # "FooBar::Baz"
593             camelize 'FooBar::Baz';
594              
595             =head2 class_to_file
596              
597             my $file = class_to_file 'Foo::Bar';
598              
599             Convert a class name to a file.
600              
601             # "foo_bar"
602             class_to_file 'Foo::Bar';
603              
604             # "foobar"
605             class_to_file 'FOO::Bar';
606              
607             # "foo_bar"
608             class_to_file 'FooBar';
609              
610             # "foobar"
611             class_to_file 'FOOBar';
612              
613             =head2 class_to_path
614              
615             my $path = class_to_path 'Foo::Bar';
616              
617             Convert class name to path, as used by C<%INC>.
618              
619             # "Foo/Bar.pm"
620             class_to_path 'Foo::Bar';
621              
622             # "FooBar.pm"
623             class_to_path 'FooBar';
624              
625             =head2 decamelize
626              
627             my $snakecase = decamelize $camelcase;
628              
629             Convert C string to C and replace C<::> with C<->.
630              
631             # "foo_bar"
632             decamelize 'FooBar';
633              
634             # "foo_bar-baz"
635             decamelize 'FooBar::Baz';
636              
637             # "foo_bar-baz"
638             decamelize 'foo_bar-baz';
639              
640             =head2 decode
641              
642             my $chars = decode 'UTF-8', $bytes;
643              
644             Decode bytes to characters with L, or return C if decoding failed.
645              
646             =head2 deprecated
647              
648             deprecated 'foo is DEPRECATED in favor of bar';
649              
650             Warn about deprecated feature from perspective of caller. You can also set the C environment
651             variable to make them die instead with L.
652              
653             =head2 dumper
654              
655             my $perl = dumper {some => 'data'};
656              
657             Dump a Perl data structure with L.
658              
659             =head2 encode
660              
661             my $bytes = encode 'UTF-8', $chars;
662              
663             Encode characters to bytes with L.
664              
665             =head2 extract_usage
666              
667             my $usage = extract_usage;
668             my $usage = extract_usage '/home/sri/foo.pod';
669              
670             Extract usage message from the SYNOPSIS section of a file containing POD documentation, defaults to using the file this
671             function was called from.
672              
673             # "Usage: APPLICATION test [OPTIONS]\n"
674             extract_usage;
675              
676             =head1 SYNOPSIS
677              
678             Usage: APPLICATION test [OPTIONS]
679              
680             =cut
681              
682             =head2 getopt
683              
684             getopt
685             'H|headers=s' => \my @headers,
686             't|timeout=i' => \my $timeout,
687             'v|verbose' => \my $verbose;
688             getopt $array,
689             'H|headers=s' => \my @headers,
690             't|timeout=i' => \my $timeout,
691             'v|verbose' => \my $verbose;
692             getopt $array, ['pass_through'],
693             'H|headers=s' => \my @headers,
694             't|timeout=i' => \my $timeout,
695             'v|verbose' => \my $verbose;
696              
697             Extract options from an array reference with L, but without changing its global configuration, defaults
698             to using C<@ARGV>. The configuration options C and C are enabled by default.
699              
700             # Extract "charset" option
701             getopt ['--charset', 'UTF-8'], 'charset=s' => \my $charset;
702             say $charset;
703              
704             =head2 gunzip
705              
706             my $uncompressed = gunzip $compressed;
707              
708             Uncompress bytes with L.
709              
710             =head2 gzip
711              
712             my $compressed = gzip $uncompressed;
713              
714             Compress bytes with L.
715              
716             =head2 header_params
717              
718             my ($params, $remainder) = header_params 'one=foo; two="bar", three=baz';
719              
720             Extract HTTP header field parameters until the first comma according to L.
721             Note that this function is B and might change without warning!
722              
723             =head2 hmac_sha1_sum
724              
725             my $checksum = hmac_sha1_sum $bytes, 'passw0rd';
726              
727             Generate HMAC-SHA1 checksum for bytes with L.
728              
729             # "11cedfd5ec11adc0ec234466d8a0f2a83736aa68"
730             hmac_sha1_sum 'foo', 'passw0rd';
731              
732             =head2 html_attr_unescape
733              
734             my $str = html_attr_unescape $escaped;
735              
736             Same as L, but handles special rules from the L
737             for HTML attributes.
738              
739             # "foo=bar<est=baz"
740             html_attr_unescape 'foo=bar<est=baz';
741              
742             # "foo=bar
743             html_attr_unescape 'foo=bar<est=baz';
744              
745             =head2 html_unescape
746              
747             my $str = html_unescape $escaped;
748              
749             Unescape all HTML entities in string.
750              
751             # "
"
752             html_unescape '<div>';
753              
754             =head2 humanize_bytes
755              
756             my $str = humanize_bytes 1234;
757              
758             Turn number of bytes into a simplified human readable format.
759              
760             # "1B"
761             humanize_bytes 1;
762              
763             # "7.5GiB"
764             humanize_bytes 8007188480;
765              
766             # "13GiB"
767             humanize_bytes 13443399680;
768              
769             # "-685MiB"
770             humanize_bytes -717946880;
771              
772             =head2 md5_bytes
773              
774             my $checksum = md5_bytes $bytes;
775              
776             Generate binary MD5 checksum for bytes with L.
777              
778             =head2 md5_sum
779              
780             my $checksum = md5_sum $bytes;
781              
782             Generate MD5 checksum for bytes with L.
783              
784             # "acbd18db4cc2f85cedef654fccc4a4d8"
785             md5_sum 'foo';
786              
787             =head2 monkey_patch
788              
789             monkey_patch $package, foo => sub {...};
790             monkey_patch $package, foo => sub {...}, bar => sub {...};
791              
792             Monkey patch functions into package.
793              
794             monkey_patch 'MyApp',
795             one => sub { say 'One!' },
796             two => sub { say 'Two!' },
797             three => sub { say 'Three!' };
798              
799             =head2 punycode_decode
800              
801             my $str = punycode_decode $punycode;
802              
803             Punycode decode string as described in L.
804              
805             # "bücher"
806             punycode_decode 'bcher-kva';
807              
808             =head2 network_contains
809              
810             my $bool = network_contains $network, $address;
811              
812             Check that a given address is contained within a network in CIDR form. If the network is a single address, the
813             addresses must be equivalent.
814              
815             # True
816             network_contains('10.0.0.0/8', '10.10.10.10');
817             network_contains('10.10.10.10', '10.10.10.10');
818             network_contains('fc00::/7', 'fc::c0:ff:ee');
819              
820             # False
821             network_contains('10.0.0.0/29', '10.10.10.10');
822             network_contains('10.10.10.12', '10.10.10.10');
823             network_contains('fc00::/7', '::1');
824              
825             =head2 punycode_encode
826              
827             my $punycode = punycode_encode $str;
828              
829             Punycode encode string as described in L.
830              
831             # "bcher-kva"
832             punycode_encode 'bücher';
833              
834             =head2 quote
835              
836             my $quoted = quote $str;
837              
838             Quote string.
839              
840             =head2 scope_guard
841              
842             my $guard = scope_guard sub {...};
843              
844             Create anonymous scope guard object that will execute the passed callback when the object is destroyed.
845              
846             # Execute closure at end of scope
847             {
848             my $guard = scope_guard sub { say "Mojo!" };
849             say "Hello";
850             }
851              
852             =head2 secure_compare
853              
854             my $bool = secure_compare $str1, $str2;
855              
856             Constant time comparison algorithm to prevent timing attacks. The secret string should be the second argument, to avoid
857             leaking information about the length of the string.
858              
859             =head2 sha1_bytes
860              
861             my $checksum = sha1_bytes $bytes;
862              
863             Generate binary SHA1 checksum for bytes with L.
864              
865             =head2 sha1_sum
866              
867             my $checksum = sha1_sum $bytes;
868              
869             Generate SHA1 checksum for bytes with L.
870              
871             # "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
872             sha1_sum 'foo';
873              
874             =head2 slugify
875              
876             my $slug = slugify $string;
877             my $slug = slugify $string, $bool;
878              
879             Returns a URL slug generated from the input string. Non-word characters are removed, the string is trimmed and
880             lowercased, and whitespace characters are replaced by a dash. By default, non-ASCII characters are normalized to ASCII
881             word characters or removed, but if a true value is passed as the second parameter, all word characters will be allowed
882             in the result according to unicode semantics.
883              
884             # "joel-is-a-slug"
885             slugify 'Joel is a slug';
886              
887             # "this-is-my-resume"
888             slugify 'This is: my - résumé! ☃ ';
889              
890             # "this-is-my-résumé"
891             slugify 'This is: my - résumé! ☃ ', 1;
892              
893             =head2 split_cookie_header
894              
895             my $tree = split_cookie_header 'a=b; expires=Thu, 07 Aug 2008 07:07:59 GMT';
896              
897             Same as L, but handles C values from L.
898              
899             =head2 split_header
900              
901             my $tree = split_header 'foo="bar baz"; test=123, yada';
902              
903             Split HTTP header value into key/value pairs, each comma separated part gets its own array reference, and keys without
904             a value get C assigned.
905              
906             # "one"
907             split_header('one; two="three four", five=six')->[0][0];
908              
909             # "two"
910             split_header('one; two="three four", five=six')->[0][2];
911              
912             # "three four"
913             split_header('one; two="three four", five=six')->[0][3];
914              
915             # "five"
916             split_header('one; two="three four", five=six')->[1][0];
917              
918             # "six"
919             split_header('one; two="three four", five=six')->[1][1];
920              
921             =head2 steady_time
922              
923             my $time = steady_time;
924              
925             High resolution time elapsed from an arbitrary fixed point in the past, resilient to time jumps if a monotonic clock is
926             available through L.
927              
928             =head2 tablify
929              
930             my $table = tablify [['foo', 'bar'], ['baz', 'yada']];
931              
932             Row-oriented generator for text tables.
933              
934             # "foo bar\nyada yada\nbaz yada\n"
935             tablify [['foo', 'bar'], ['yada', 'yada'], ['baz', 'yada']];
936              
937             =head2 term_escape
938              
939             my $escaped = term_escape $str;
940              
941             Escape all POSIX control characters except for C<\n>.
942              
943             # "foo\\x09bar\\x0d\n"
944             term_escape "foo\tbar\r\n";
945              
946             =head2 trim
947              
948             my $trimmed = trim $str;
949              
950             Trim whitespace characters from both ends of string.
951              
952             # "foo bar"
953             trim ' foo bar ';
954              
955             =head2 unindent
956              
957             my $unindented = unindent $str;
958              
959             Unindent multi-line string.
960              
961             # "foo\nbar\nbaz\n"
962             unindent " foo\n bar\n baz\n";
963              
964             =head2 unquote
965              
966             my $str = unquote $quoted;
967              
968             Unquote string.
969              
970             =head2 url_escape
971              
972             my $escaped = url_escape $str;
973             my $escaped = url_escape $str, '^A-Za-z0-9\-._~';
974              
975             Percent encode unsafe characters in string as described in L, the pattern
976             used defaults to C<^A-Za-z0-9\-._~>.
977              
978             # "foo%3Bbar"
979             url_escape 'foo;bar';
980              
981             =head2 url_unescape
982              
983             my $str = url_unescape $escaped;
984              
985             Decode percent encoded characters in string as described in L.
986              
987             # "foo;bar"
988             url_unescape 'foo%3Bbar';
989              
990             =head2 xml_escape
991              
992             my $escaped = xml_escape $str;
993              
994             Escape unsafe characters C<&>, C>, C>, C<"> and C<'> in string, but do not escape L
995             objects.
996              
997             # "<div>"
998             xml_escape '
';
999              
1000             # "
"
1001             use Mojo::ByteStream qw(b);
1002             xml_escape b('
');
1003              
1004             =head2 xor_encode
1005              
1006             my $encoded = xor_encode $str, $key;
1007              
1008             XOR encode string with variable length key.
1009              
1010             =head1 SEE ALSO
1011              
1012             L, L, L.
1013              
1014             =cut