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 101     101   707 use Mojo::Base -strict;
  101         184  
  101         4393  
3              
4 101     101   603 use Carp qw(carp croak);
  101         172  
  101         8649  
5 101     101   66753 use Data::Dumper ();
  101         709270  
  101         3435  
6 101     101   693 use Digest::MD5 qw(md5 md5_hex);
  101         202  
  101         7602  
7 101     101   61094 use Digest::SHA qw(hmac_sha1_hex sha1 sha1_hex);
  101         322789  
  101         9893  
8 101     101   60627 use Encode qw(find_encoding);
  101         1010779  
  101         8333  
9 101     101   822 use Exporter qw(import);
  101         204  
  101         3067  
10 101     101   1944 use File::Basename qw(dirname);
  101         198  
  101         11344  
11 101     101   80055 use Getopt::Long qw(GetOptionsFromArray);
  101         1317583  
  101         571  
12 101     101   80832 use IO::Compress::Gzip;
  101         4364999  
  101         6402  
13 101     101   49588 use IO::Poll qw(POLLIN POLLPRI);
  101         88619  
  101         7960  
14 101     101   59949 use IO::Uncompress::Gunzip;
  101         1567659  
  101         5546  
15 101     101   802 use List::Util qw(min);
  101         269  
  101         12540  
16 101     101   50661 use MIME::Base64 qw(decode_base64 encode_base64);
  101         68990  
  101         7106  
17 101     101   58800 use Pod::Usage qw(pod2usage);
  101         3975952  
  101         9418  
18 101     101   65941 use Socket qw(inet_pton AF_INET6 AF_INET);
  101         404993  
  101         18627  
19 101     101   46806 use Sub::Util qw(set_subname);
  101         32882  
  101         6723  
20 101     101   901 use Symbol qw(delete_package);
  101         338  
  101         5297  
21 101     101   52184 use Time::HiRes ();
  101         135592  
  101         2832  
22 101     101   60079 use Unicode::Normalize ();
  101         222902  
  101         7336  
23              
24             # Check for monotonic clock support
25 101     101   911 use constant MONOTONIC => !!eval { Time::HiRes::clock_gettime(Time::HiRes::CLOCK_MONOTONIC()) };
  101         287  
  101         235  
  101         782  
26              
27             # Punycode bootstring parameters
28             use constant {
29 101         252473 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 101     101   13613 };
  101         366  
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 124182     124182 1 230456 MONOTONIC ? sub () { Time::HiRes::clock_gettime(Time::HiRes::CLOCK_MONOTONIC()) } : \&Time::HiRes::time);
90              
91             sub camelize {
92 42     42 1 1870 my $str = shift;
93 42 100       189 return $str if $str =~ /^[A-Z]/;
94              
95             # CamelCase words
96             return join '::', map {
97 39         166 join('', map { ucfirst lc } split /_/)
  53         129  
  81         406  
98             } split /-/, $str;
99             }
100              
101             sub class_to_file {
102 10     10 1 2927 my $class = shift;
103 10         56 $class =~ s/::|'//g;
104 10         54 $class =~ s/([A-Z])([A-Z]*)/$1 . lc $2/ge;
  18         78  
105 10         36 return decamelize($class);
106             }
107              
108 836     836 1 320121 sub class_to_path { join '.', join('/', split(/::|'/, shift)), 'pm' }
109              
110             sub decamelize {
111 28     28 1 3317 my $str = shift;
112 28 100       209 return $str if $str !~ /^[A-Z]/;
113              
114             # snake_case words
115             return join '-', map {
116 23         104 join('_', map {lc} grep {length} split /([A-Z]{1}[^A-Z]*)/)
  26         133  
  49         323  
  98         163  
117             } split /::/, $str;
118             }
119              
120             sub decode {
121 7332     7332 1 26345 my ($encoding, $bytes) = @_;
122 7332 100       11194 return undef unless eval { $bytes = _encoding($encoding)->decode("$bytes", 1); 1 };
  7332         16330  
  7247         73168  
123 7247         24045 return $bytes;
124             }
125              
126             sub deprecated {
127 2     2 1 4850 local $Carp::CarpLevel = 1;
128 2 100       301 $ENV{MOJO_FATAL_DEPRECATIONS} ? croak @_ : carp @_;
129             }
130              
131 258     258 1 4931 sub dumper { Data::Dumper->new([@_])->Indent(1)->Sortkeys(1)->Terse(1)->Useqq(1)->Dump }
132              
133 10330     10330 1 48415 sub encode { _encoding($_[0])->encode("$_[1]", 0) }
134              
135             sub extract_usage {
136 26 100   26 1 3223 my $file = @_ ? "$_[0]" : (caller)[1];
137              
138 26         397 open my $handle, '>', \my $output;
139 26         1220 pod2usage -exitval => 'noexit', -input => $file, -output => $handle;
140 26         468544 $output =~ s/^.*\n|\n$//;
141 26         171 $output =~ s/\n$//;
142              
143 26         100 return unindent($output);
144             }
145              
146             sub getopt {
147 116 100   116 1 13345 my ($array, $opts) = map { ref $_[0] eq 'ARRAY' ? shift : $_ } \@ARGV, [];
  232         1116  
148              
149 116         802 my $save = Getopt::Long::Configure(qw(default no_auto_abbrev no_ignore_case), @$opts);
150 116         11629 my $result = GetOptionsFromArray $array, @_;
151 116         45219 Getopt::Long::Configure($save);
152              
153 116         11162 return $result;
154             }
155              
156             sub gunzip {
157 2     2 1 1267 my $compressed = shift;
158 2 50       61 IO::Uncompress::Gunzip::gunzip \$compressed, \my $uncompressed
159             or croak "Couldn't gunzip: $IO::Uncompress::Gunzip::GzipError";
160 2         5117 return $uncompressed;
161             }
162              
163             sub gzip {
164 54     54 1 10153 my $uncompressed = shift;
165 54 50       369 IO::Compress::Gzip::gzip \$uncompressed, \my $compressed or croak "Couldn't gzip: $IO::Compress::Gzip::GzipError";
166 54         181238 return $compressed;
167             }
168              
169             sub header_params {
170 16     16 1 3494 my $value = shift;
171              
172 16         27 my $params = {};
173 16         90 while ($value =~ /\G[;\s]*([^=;, ]+)\s*/gc) {
174 20         42 my $name = $1;
175              
176             # Quoted value
177 20 100 66     144 if ($value =~ /$QUOTED_VALUE_RE/gco) { $params->{$name} //= unquote($1) }
  4 100       28  
178              
179             # Unquoted value
180 15   66     98 elsif ($value =~ /$UNQUOTED_VALUE_RE/gco) { $params->{$name} //= $1 }
181             }
182              
183 16   100     146 return ($params, substr($value, pos($value) // 0));
184             }
185              
186 33867     33867 1 54206 sub html_attr_unescape { _html(shift, 1) }
187 2634     2634 1 25088 sub html_unescape { _html(shift, 0) }
188              
189             sub humanize_bytes {
190 19     19 1 2994 my $size = shift;
191              
192 19 100       56 my $prefix = $size < 0 ? '-' : '';
193              
194 19 100       73 return "$prefix${size}B" if ($size = abs $size) < 1024;
195 16 100       77 return $prefix . _round($size) . 'KiB' if ($size /= 1024) < 1024;
196 11 100       33 return $prefix . _round($size) . 'MiB' if ($size /= 1024) < 1024;
197 8 100       30 return $prefix . _round($size) . 'GiB' if ($size /= 1024) < 1024;
198 2         5 return $prefix . _round($size /= 1024) . 'TiB';
199             }
200              
201             sub monkey_patch {
202 53146     53146 1 142123 my ($class, %patch) = @_;
203 101     101   1019 no strict 'refs';
  101         296  
  101         4188  
204 101     101   740 no warnings 'redefine';
  101         382  
  101         41513  
205 53146         363918 *{"${class}::$_"} = set_subname("${class}::$_", $patch{$_}) for keys %patch;
  53363         688334  
206             }
207              
208             sub network_contains {
209 99     99 1 8673 my ($cidr, $addr) = @_;
210 99 100 100     441 return undef unless length $cidr && length $addr;
211              
212             # Parse inputs
213 93         281 my ($net, $mask) = split m!/!, $cidr, 2;
214 93         251 my $v6 = $net =~ /:/;
215 93 100 100     379 return undef if $v6 xor $addr =~ /:/;
216              
217             # Convert addresses to binary
218 91 100       439 return undef unless $net = inet_pton($v6 ? AF_INET6 : AF_INET, $net);
    100          
219 89 100       333 return undef unless $addr = inet_pton($v6 ? AF_INET6 : AF_INET, $addr);
    100          
220 87 100       178 my $length = $v6 ? 128 : 32;
221              
222             # Apply mask if given
223 87 100       430 $addr &= pack "B$length", '1' x $mask if defined $mask;
224              
225             # Compare
226 87         1000 return 0 == unpack "B$length", ($net ^ $addr);
227             }
228              
229             # Direct translation of RFC 3492
230             sub punycode_decode {
231 23     23 1 3459 my $input = shift;
232 101     101   920 use integer;
  101         238  
  101         911  
233              
234 23         56 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       191 push @output, split(//, $1) if $input =~ s/(.*)\x2d//s;
238              
239 23         78 while (length $input) {
240 219         363 my ($oldi, $w) = ($i, 1);
241              
242             # Base to infinity in steps of base
243 219         294 for (my $k = PC_BASE; 1; $k += PC_BASE) {
244 458         679 my $digit = ord substr $input, 0, 1, '';
245 458 100       717 $digit = $digit < 0x40 ? $digit + (26 - 0x30) : ($digit & 0x1f) - 1;
246 458         629 $i += $digit * $w;
247 458         544 my $t = $k - $bias;
248 458 100       770 $t = $t < PC_TMIN ? PC_TMIN : $t > PC_TMAX ? PC_TMAX : $t;
    100          
249 458 100       740 last if $digit < $t;
250 239         344 $w *= PC_BASE - $t;
251             }
252              
253 219         400 $bias = _adapt($i - $oldi, @output + 1, $oldi == 0);
254 219         325 $n += $i / (@output + 1);
255 219         282 $i = $i % (@output + 1);
256 219         550 splice @output, $i++, 0, chr $n;
257             }
258              
259 23         161 return join '', @output;
260             }
261              
262             # Direct translation of RFC 3492
263             sub punycode_encode {
264 64     64 1 19509 my $output = shift;
265 101     101   36778 use integer;
  101         299  
  101         552  
266              
267 64         145 my ($n, $delta, $bias) = (PC_INITIAL_N, 0, PC_INITIAL_BIAS);
268              
269             # Extract basic code points
270 64         231 my @input = map {ord} split //, $output;
  553         796  
271 64         413 $output =~ s/[^\x00-\x7f]+//gs;
272 64         163 my $h = my $basic = length $output;
273 64 100       193 $output .= "\x2d" if $basic > 0;
274              
275 64         140 for my $m (sort grep { $_ >= PC_INITIAL_N } @input) {
  553         1006  
276 260 100       482 next if $m < $n;
277 218         306 $delta += ($m - $n) * ($h + 1);
278 218         287 $n = $m;
279              
280 218         364 for my $c (@input) {
281              
282 3630 100       5763 if ($c < $n) { $delta++ }
  2033 100       2563  
283             elsif ($c == $n) {
284 260         327 my $q = $delta;
285              
286             # Base to infinity in steps of base
287 260         347 for (my $k = PC_BASE; 1; $k += PC_BASE) {
288 581         727 my $t = $k - $bias;
289 581 100       985 $t = $t < PC_TMIN ? PC_TMIN : $t > PC_TMAX ? PC_TMAX : $t;
    100          
290 581 100       991 last if $q < $t;
291 321         461 my $o = $t + (($q - $t) % (PC_BASE - $t));
292 321 100       690 $output .= chr $o + ($o < 26 ? 0x61 : 0x30 - 26);
293 321         553 $q = ($q - $t) / (PC_BASE - $t);
294             }
295              
296 260 50       555 $output .= chr $q + ($q < 26 ? 0x61 : 0x30 - 26);
297 260         523 $bias = _adapt($delta, $h + 1, $h == $basic);
298 260         335 $delta = 0;
299 260         365 $h++;
300             }
301             }
302              
303 218         282 $delta++;
304 218         315 $n++;
305             }
306              
307 64         318 return $output;
308             }
309              
310             sub quote {
311 21     21 1 3037 my $str = shift;
312 21         125 $str =~ s/(["\\])/\\$1/g;
313 21         117 return qq{"$str"};
314             }
315              
316 18     18 1 3199 sub scope_guard { Mojo::Util::_Guard->new(cb => shift) }
317              
318             sub secure_compare {
319 86     86 1 15018 my ($one, $two) = @_;
320 86         228 my $r = length $one != length $two;
321 86 100       251 $two = $one if $r;
322 86         1597 $r |= ord(substr $one, $_) ^ ord(substr $two, $_) for 0 .. length($one) - 1;
323 86         532 return $r == 0;
324             }
325              
326             sub slugify {
327 14     14 1 2946 my ($value, $allow_unicode) = @_;
328              
329 14 100       38 if ($allow_unicode) {
330              
331             # Force unicode semantics by upgrading string
332 6         100 utf8::upgrade($value = Unicode::Normalize::NFKC($value));
333 6         57 $value =~ s/[^\w\s-]+//g;
334             }
335             else {
336 8         73 $value = Unicode::Normalize::NFKD($value);
337 101     101   95441 $value =~ s/[^a-zA-Z0-9_\p{PosixSpace}-]+//g;
  101         272  
  101         1986  
  8         66  
338             }
339 14         58 (my $new = lc trim($value)) =~ s/[-\s]+/-/g;
340              
341 14         6140 return $new;
342             }
343              
344 995     995 1 10066 sub split_cookie_header { _header(shift, 1) }
345 206     206 1 3568 sub split_header { _header(shift, 0) }
346              
347             sub tablify {
348 18     18 1 2898 my $rows = shift;
349              
350 18         34 my @spec;
351 18         54 for my $row (@$rows) {
352 87         165 for my $i (0 .. $#$row) {
353 176   100     372 ($row->[$i] //= '') =~ y/\r\n//d;
354 176         241 my $len = length $row->[$i];
355 176 100 100     476 $spec[$i] = $len if $len >= ($spec[$i] // 0);
356             }
357             }
358              
359 18         68 my @fm = (map({"\%-${_}s"} @spec[0 .. $#spec - 1]), '%s');
  23         121  
360 18         88 return join '', map { sprintf join(' ', @fm[0 .. $#$_]) . "\n", @$_ } @$rows;
  87         473  
361             }
362              
363             sub term_escape {
364 4     4 1 3100 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         99 return $str;
367             }
368              
369             sub trim {
370 1370     1370 1 5206 my $str = shift;
371 1370         4382 $str =~ s/^\s+//;
372 1370         4079 $str =~ s/\s+$//;
373 1370         4015 return $str;
374             }
375              
376             sub unindent {
377 37     37 1 3492 my $str = shift;
378 37 100       227 my $min = min map { m/^([ \t]*)/; length $1 || () } split /\n/, $str;
  426         806  
  426         1479  
379 37 100       758 $str =~ s/^[ \t]{0,$min}//gm if $min;
380 37         687 return $str;
381             }
382              
383             sub unquote {
384 48     48 1 2959 my $str = shift;
385 48 50       283 return $str unless $str =~ s/^"(.*)"$/$1/g;
386 48         149 $str =~ s/\\\\/\\/g;
387 48         124 $str =~ s/\\"/"/g;
388 48         138 return $str;
389             }
390              
391             sub url_escape {
392 5814     5814 1 21407 my ($str, $pattern) = @_;
393              
394 5814 100       10609 if ($pattern) {
395 5799 100       13707 unless (exists $PATTERN{$pattern}) {
396 133         1516 (my $quoted = $pattern) =~ s!([/\$\[])!\\$1!g;
397 133 50       28248 $PATTERN{$pattern} = eval "sub { \$_[0] =~ s/([$quoted])/sprintf '%%%02X', ord \$1/ge }" or croak $@;
398             }
399 5799         130713 $PATTERN{$pattern}->($str);
400             }
401 15         101 else { $str =~ s/([^A-Za-z0-9\-._~])/sprintf '%%%02X', ord $1/ge }
  22         127  
402              
403 5814         23172 return $str;
404             }
405              
406             sub url_unescape {
407 7526     7526 1 18887 my $str = shift;
408 7526         15745 $str =~ s/%([0-9a-fA-F]{2})/chr hex $1/ge;
  787         2866  
409 7526         17033 return $str;
410             }
411              
412             sub xml_escape {
413 486 100 66 486 1 11759 return $_[0] if ref $_[0] && ref $_[0] eq 'Mojo::ByteStream';
  7982 100 100 7982   64183  
414 485   50     1042 my $str = shift // '';
  6188   100     12950  
415 485         1027 $str =~ s/([&<>"'])/$XML{$1}/ge;
  42         170  
  6188         12848  
  7688         20159  
416 485         1882 return $str;
  6187         14650  
417             }
418              
419             sub xor_encode {
420 294     294 1 3511 my ($input, $key) = @_;
421              
422             # Encode with variable key length
423 294         506 my $len = length $key;
424 294         552 my $buffer = my $output = '';
425 294         2074 $output .= $buffer ^ $key while length($buffer = substr($input, 0, $len, '')) == $len;
426 294         1852 return $output .= $buffer ^ substr($key, 0, length $buffer, '');
427             }
428              
429             sub _adapt {
430 479     479   763 my ($delta, $numpoints, $firsttime) = @_;
431 101     101   2324259 use integer;
  101         267  
  101         731  
432              
433 479 100       737 $delta = $firsttime ? $delta / PC_DAMP : $delta / 2;
434 479         593 $delta += $delta / $numpoints;
435 479         585 my $k = 0;
436 479         823 while ($delta > ((PC_BASE - PC_TMIN) * PC_TMAX) / 2) {
437 110         124 $delta /= PC_BASE - PC_TMIN;
438 110         177 $k += PC_BASE;
439             }
440              
441 479         761 return $k + (((PC_BASE - PC_TMIN + 1) * $delta) / ($delta + PC_SKEW));
442             }
443              
444 17662   66 17662   128952 sub _encoding { $ENCODING{$_[0]} //= find_encoding($_[0]) // croak "Unknown encoding '$_[0]'" }
      66        
445              
446             sub _entity {
447 991     991   2392 my ($point, $name, $attr) = @_;
448              
449             # Code point
450 991 100       2044 return chr($point !~ /^x/ ? $point : hex $point) unless defined $name;
    100          
451              
452             # Named character reference
453 950         1309 my $rest = my $last = '';
454 950         1699 while (length $name) {
455             return $ENTITIES{$name} . reverse $rest
456 988 100 100     5664 if exists $ENTITIES{$name} && (!$attr || $name =~ /;$/ || $last !~ /[A-Za-z0-9=]/);
      100        
457 48         99 $rest .= $last = chop $name;
458             }
459 10         78 return '&' . reverse $rest;
460             }
461              
462             sub _header {
463 1201     1201   2667 my ($str, $cookie) = @_;
464              
465 1201         2048 my (@tree, @part);
466 1201         4298 while ($str =~ /\G[,;\s]*([^=;, ]+)\s*/gc) {
467 798         2141 push @part, $1, undef;
468 798   100     3043 my $expires = $cookie && @part > 2 && lc $1 eq 'expires';
469              
470             # Special "expires" value
471 798 100 100     5553 if ($expires && $str =~ /\G=\s*$EXPIRES_RE/gco) { $part[-1] = $1 }
  120 100       324  
    100          
472              
473             # Quoted value
474 42         118 elsif ($str =~ /$QUOTED_VALUE_RE/gco) { $part[-1] = unquote $1 }
475              
476             # Unquoted value
477 538         1288 elsif ($str =~ /$UNQUOTED_VALUE_RE/gco) { $part[-1] = $1 }
478              
479             # Separator
480 798 100       2993 next unless $str =~ /\G[;\s]*,\s*/gc;
481 107         306 push @tree, [@part];
482 107         396 @part = ();
483             }
484              
485             # Take care of final part
486 1201 100       5376 return [@part ? (@tree, \@part) : @tree];
487             }
488              
489             sub _html {
490 36501     36501   53981 my ($str, $attr) = @_;
491 36501         49170 $str =~ s/$ENTITY_RE/_entity($1, $2, $attr)/geo;
  991         1839  
492 36501         168473 return $str;
493             }
494              
495             sub _options {
496              
497             # Hash or name (one)
498 1801 100   1801   5781 return ref $_[0] eq 'HASH' ? (undef, %{shift()}) : @_ if @_ == 1;
  996 100       3461  
499              
500             # Name and values (odd)
501 349 100       1099 return shift, @_ if @_ % 2;
502              
503             # Name and hash or just values (even)
504 269 100       1210 return ref $_[1] eq 'HASH' ? (shift, %{shift()}) : (undef, @_);
  18         112  
505             }
506              
507             # This may break in the future, but is worth it for performance
508 760     760   14832 sub _readable { !!(IO::Poll::_poll(@_[0, 1], my $m = POLLIN | POLLPRI) > 0) }
509              
510 16 100   16   231 sub _round { $_[0] < 10 ? int($_[0] * 10 + 0.5) / 10 : int($_[0] + 0.5) }
511              
512             sub _stash {
513 20923     20923   38674 my ($name, $object) = (shift, shift);
514              
515             # Hash
516 20923 100 100     111630 return $object->{$name} //= {} unless @_;
517              
518             # Get
519 1316 100 100     5866 return $object->{$name}{$_[0]} unless @_ > 1 || ref $_[0];
520              
521             # Set
522 1086 100       4282 my $values = ref $_[0] ? $_[0] : {@_};
523 1086         3698 @{$object->{$name}}{keys %$values} = values %$values;
  1086         3169  
524              
525 1086         4498 return $object;
526             }
527              
528             sub _teardown {
529 826 50   826   39576 return unless my $class = shift;
530              
531             # @ISA has to be cleared first because of circular references
532 101     101   98601 no strict 'refs';
  101         261  
  101         9782  
533 826         1193 @{"${class}::ISA"} = ();
  826         11981  
534 826         3507 delete_package $class;
535             }
536              
537             package Mojo::Util::_Guard;
538 101     101   798 use Mojo::Base -base;
  101         221  
  101         1233  
539              
540 18     18   1272 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