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   721 use Mojo::Base -strict;
  101         191  
  101         4093  
3              
4 101     101   597 use Carp qw(carp croak);
  101         198  
  101         8369  
5 101     101   63717 use Data::Dumper ();
  101         684326  
  101         3311  
6 101     101   700 use Digest::MD5 qw(md5 md5_hex);
  101         223  
  101         7160  
7 101     101   55469 use Digest::SHA qw(hmac_sha1_hex sha1 sha1_hex);
  101         313638  
  101         9573  
8 101     101   58089 use Encode qw(find_encoding);
  101         983654  
  101         7665  
9 101     101   748 use Exporter qw(import);
  101         206  
  101         3217  
10 101     101   1883 use File::Basename qw(dirname);
  101         222  
  101         10647  
11 101     101   76416 use Getopt::Long qw(GetOptionsFromArray);
  101         1272920  
  101         560  
12 101     101   77709 use IO::Compress::Gzip;
  101         4219255  
  101         6254  
13 101     101   48764 use IO::Poll qw(POLLIN POLLPRI);
  101         85754  
  101         7550  
14 101     101   57610 use IO::Uncompress::Gunzip;
  101         1515356  
  101         5857  
15 101     101   793 use List::Util qw(min);
  101         240  
  101         11517  
16 101     101   47682 use MIME::Base64 qw(decode_base64 encode_base64);
  101         65983  
  101         6942  
17 101     101   57349 use Pod::Usage qw(pod2usage);
  101         3831983  
  101         8867  
18 101     101   62432 use Socket qw(inet_pton AF_INET6 AF_INET);
  101         388794  
  101         18616  
19 101     101   44079 use Sub::Util qw(set_subname);
  101         32349  
  101         6381  
20 101     101   778 use Symbol qw(delete_package);
  101         262  
  101         5108  
21 101     101   51275 use Time::HiRes ();
  101         132467  
  101         2680  
22 101     101   58029 use Unicode::Normalize ();
  101         207804  
  101         7064  
23              
24             # Check for monotonic clock support
25 101     101   852 use constant MONOTONIC => !!eval { Time::HiRes::clock_gettime(Time::HiRes::CLOCK_MONOTONIC()) };
  101         254  
  101         232  
  101         661  
26              
27             # Punycode bootstring parameters
28             use constant {
29 101         240525 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   13080 };
  101         291  
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 119189     119189 1 223943 MONOTONIC ? sub () { Time::HiRes::clock_gettime(Time::HiRes::CLOCK_MONOTONIC()) } : \&Time::HiRes::time);
90              
91             sub camelize {
92 42     42 1 1786 my $str = shift;
93 42 100       206 return $str if $str =~ /^[A-Z]/;
94              
95             # CamelCase words
96             return join '::', map {
97 39         153 join('', map { ucfirst lc } split /_/)
  53         153  
  81         413  
98             } split /-/, $str;
99             }
100              
101             sub class_to_file {
102 10     10 1 2882 my $class = shift;
103 10         59 $class =~ s/::|'//g;
104 10         51 $class =~ s/([A-Z])([A-Z]*)/$1 . lc $2/ge;
  18         77  
105 10         29 return decamelize($class);
106             }
107              
108 836     836 1 308681 sub class_to_path { join '.', join('/', split(/::|'/, shift)), 'pm' }
109              
110             sub decamelize {
111 28     28 1 3516 my $str = shift;
112 28 100       173 return $str if $str !~ /^[A-Z]/;
113              
114             # snake_case words
115             return join '-', map {
116 23         103 join('_', map {lc} grep {length} split /([A-Z]{1}[^A-Z]*)/)
  26         147  
  49         278  
  98         165  
117             } split /::/, $str;
118             }
119              
120             sub decode {
121 7332     7332 1 26860 my ($encoding, $bytes) = @_;
122 7332 100       11094 return undef unless eval { $bytes = _encoding($encoding)->decode("$bytes", 1); 1 };
  7332         16514  
  7247         70748  
123 7247         23763 return $bytes;
124             }
125              
126             sub deprecated {
127 2     2 1 4157 local $Carp::CarpLevel = 1;
128 2 100       268 $ENV{MOJO_FATAL_DEPRECATIONS} ? croak @_ : carp @_;
129             }
130              
131 258     258 1 4254 sub dumper { Data::Dumper->new([@_])->Indent(1)->Sortkeys(1)->Terse(1)->Useqq(1)->Dump }
132              
133 10330     10330 1 45992 sub encode { _encoding($_[0])->encode("$_[1]", 0) }
134              
135             sub extract_usage {
136 26 100   26 1 3070 my $file = @_ ? "$_[0]" : (caller)[1];
137              
138 26         359 open my $handle, '>', \my $output;
139 26         972 pod2usage -exitval => 'noexit', -input => $file, -output => $handle;
140 26         460672 $output =~ s/^.*\n|\n$//;
141 26         147 $output =~ s/\n$//;
142              
143 26         102 return unindent($output);
144             }
145              
146             sub getopt {
147 116 100   116 1 13148 my ($array, $opts) = map { ref $_[0] eq 'ARRAY' ? shift : $_ } \@ARGV, [];
  232         1084  
148              
149 116         777 my $save = Getopt::Long::Configure(qw(default no_auto_abbrev no_ignore_case), @$opts);
150 116         10760 my $result = GetOptionsFromArray $array, @_;
151 116         43058 Getopt::Long::Configure($save);
152              
153 116         10836 return $result;
154             }
155              
156             sub gunzip {
157 2     2 1 1077 my $compressed = shift;
158 2 50       45 IO::Uncompress::Gunzip::gunzip \$compressed, \my $uncompressed
159             or croak "Couldn't gunzip: $IO::Uncompress::Gunzip::GzipError";
160 2         4323 return $uncompressed;
161             }
162              
163             sub gzip {
164 54     54 1 11438 my $uncompressed = shift;
165 54 50       344 IO::Compress::Gzip::gzip \$uncompressed, \my $compressed or croak "Couldn't gzip: $IO::Compress::Gzip::GzipError";
166 54         170845 return $compressed;
167             }
168              
169             sub header_params {
170 16     16 1 3553 my $value = shift;
171              
172 16         28 my $params = {};
173 16         98 while ($value =~ /\G[;\s]*([^=;, ]+)\s*/gc) {
174 20         47 my $name = $1;
175              
176             # Quoted value
177 20 100 66     136 if ($value =~ /$QUOTED_VALUE_RE/gco) { $params->{$name} //= unquote($1) }
  4 100       52  
178              
179             # Unquoted value
180 15   66     102 elsif ($value =~ /$UNQUOTED_VALUE_RE/gco) { $params->{$name} //= $1 }
181             }
182              
183 16   100     129 return ($params, substr($value, pos($value) // 0));
184             }
185              
186 33867     33867 1 52985 sub html_attr_unescape { _html(shift, 1) }
187 2634     2634 1 22101 sub html_unescape { _html(shift, 0) }
188              
189             sub humanize_bytes {
190 19     19 1 2538 my $size = shift;
191              
192 19 100       85 my $prefix = $size < 0 ? '-' : '';
193              
194 19 100       61 return "$prefix${size}B" if ($size = abs $size) < 1024;
195 16 100       65 return $prefix . _round($size) . 'KiB' if ($size /= 1024) < 1024;
196 11 100       29 return $prefix . _round($size) . 'MiB' if ($size /= 1024) < 1024;
197 8 100       31 return $prefix . _round($size) . 'GiB' if ($size /= 1024) < 1024;
198 2         15 return $prefix . _round($size /= 1024) . 'TiB';
199             }
200              
201             sub monkey_patch {
202 53146     53146 1 139167 my ($class, %patch) = @_;
203 101     101   957 no strict 'refs';
  101         279  
  101         3964  
204 101     101   757 no warnings 'redefine';
  101         348  
  101         39821  
205 53146         354775 *{"${class}::$_"} = set_subname("${class}::$_", $patch{$_}) for keys %patch;
  53363         662122  
206             }
207              
208             sub network_contains {
209 99     99 1 7135 my ($cidr, $addr) = @_;
210 99 100 100     438 return undef unless length $cidr && length $addr;
211              
212             # Parse inputs
213 93         301 my ($net, $mask) = split m!/!, $cidr, 2;
214 93         261 my $v6 = $net =~ /:/;
215 93 100 100     352 return undef if $v6 xor $addr =~ /:/;
216              
217             # Convert addresses to binary
218 91 100       408 return undef unless $net = inet_pton($v6 ? AF_INET6 : AF_INET, $net);
    100          
219 89 100       352 return undef unless $addr = inet_pton($v6 ? AF_INET6 : AF_INET, $addr);
    100          
220 87 100       174 my $length = $v6 ? 128 : 32;
221              
222             # Apply mask if given
223 87 100       427 $addr &= pack "B$length", '1' x $mask if defined $mask;
224              
225             # Compare
226 87         747 return 0 == unpack "B$length", ($net ^ $addr);
227             }
228              
229             # Direct translation of RFC 3492
230             sub punycode_decode {
231 23     23 1 2493 my $input = shift;
232 101     101   924 use integer;
  101         255  
  101         855  
233              
234 23         55 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       183 push @output, split(//, $1) if $input =~ s/(.*)\x2d//s;
238              
239 23         71 while (length $input) {
240 219         332 my ($oldi, $w) = ($i, 1);
241              
242             # Base to infinity in steps of base
243 219         320 for (my $k = PC_BASE; 1; $k += PC_BASE) {
244 458         687 my $digit = ord substr $input, 0, 1, '';
245 458 100       690 $digit = $digit < 0x40 ? $digit + (26 - 0x30) : ($digit & 0x1f) - 1;
246 458         536 $i += $digit * $w;
247 458         543 my $t = $k - $bias;
248 458 100       739 $t = $t < PC_TMIN ? PC_TMIN : $t > PC_TMAX ? PC_TMAX : $t;
    100          
249 458 100       760 last if $digit < $t;
250 239         340 $w *= PC_BASE - $t;
251             }
252              
253 219         378 $bias = _adapt($i - $oldi, @output + 1, $oldi == 0);
254 219         319 $n += $i / (@output + 1);
255 219         295 $i = $i % (@output + 1);
256 219         543 splice @output, $i++, 0, chr $n;
257             }
258              
259 23         150 return join '', @output;
260             }
261              
262             # Direct translation of RFC 3492
263             sub punycode_encode {
264 64     64 1 15854 my $output = shift;
265 101     101   35782 use integer;
  101         268  
  101         481  
266              
267 64         141 my ($n, $delta, $bias) = (PC_INITIAL_N, 0, PC_INITIAL_BIAS);
268              
269             # Extract basic code points
270 64         219 my @input = map {ord} split //, $output;
  553         816  
271 64         394 $output =~ s/[^\x00-\x7f]+//gs;
272 64         168 my $h = my $basic = length $output;
273 64 100       189 $output .= "\x2d" if $basic > 0;
274              
275 64         128 for my $m (sort grep { $_ >= PC_INITIAL_N } @input) {
  553         987  
276 260 100       480 next if $m < $n;
277 218         347 $delta += ($m - $n) * ($h + 1);
278 218         282 $n = $m;
279              
280 218         305 for my $c (@input) {
281              
282 3630 100       5693 if ($c < $n) { $delta++ }
  2033 100       2475  
283             elsif ($c == $n) {
284 260         310 my $q = $delta;
285              
286             # Base to infinity in steps of base
287 260         360 for (my $k = PC_BASE; 1; $k += PC_BASE) {
288 581         736 my $t = $k - $bias;
289 581 100       965 $t = $t < PC_TMIN ? PC_TMIN : $t > PC_TMAX ? PC_TMAX : $t;
    100          
290 581 100       1005 last if $q < $t;
291 321         432 my $o = $t + (($q - $t) % (PC_BASE - $t));
292 321 100       702 $output .= chr $o + ($o < 26 ? 0x61 : 0x30 - 26);
293 321         606 $q = ($q - $t) / (PC_BASE - $t);
294             }
295              
296 260 50       557 $output .= chr $q + ($q < 26 ? 0x61 : 0x30 - 26);
297 260         525 $bias = _adapt($delta, $h + 1, $h == $basic);
298 260         320 $delta = 0;
299 260         407 $h++;
300             }
301             }
302              
303 218         259 $delta++;
304 218         290 $n++;
305             }
306              
307 64         302 return $output;
308             }
309              
310             sub quote {
311 21     21 1 2906 my $str = shift;
312 21         127 $str =~ s/(["\\])/\\$1/g;
313 21         95 return qq{"$str"};
314             }
315              
316 18     18 1 2701 sub scope_guard { Mojo::Util::_Guard->new(cb => shift) }
317              
318             sub secure_compare {
319 86     86 1 12349 my ($one, $two) = @_;
320 86         177 my $r = length $one != length $two;
321 86 100       202 $two = $one if $r;
322 86         1575 $r |= ord(substr $one, $_) ^ ord(substr $two, $_) for 0 .. length($one) - 1;
323 86         472 return $r == 0;
324             }
325              
326             sub slugify {
327 14     14 1 2473 my ($value, $allow_unicode) = @_;
328              
329 14 100       35 if ($allow_unicode) {
330              
331             # Force unicode semantics by upgrading string
332 6         82 utf8::upgrade($value = Unicode::Normalize::NFKC($value));
333 6         52 $value =~ s/[^\w\s-]+//g;
334             }
335             else {
336 8         67 $value = Unicode::Normalize::NFKD($value);
337 101     101   91939 $value =~ s/[^a-zA-Z0-9_\p{PosixSpace}-]+//g;
  101         280  
  101         1668  
  8         65  
338             }
339 14         35 (my $new = lc trim($value)) =~ s/[-\s]+/-/g;
340              
341 14         5950 return $new;
342             }
343              
344 995     995 1 6241 sub split_cookie_header { _header(shift, 1) }
345 206     206 1 3576 sub split_header { _header(shift, 0) }
346              
347             sub tablify {
348 18     18 1 2603 my $rows = shift;
349              
350 18         34 my @spec;
351 18         43 for my $row (@$rows) {
352 87         176 for my $i (0 .. $#$row) {
353 176   100     375 ($row->[$i] //= '') =~ y/\r\n//d;
354 176         243 my $len = length $row->[$i];
355 176 100 100     500 $spec[$i] = $len if $len >= ($spec[$i] // 0);
356             }
357             }
358              
359 18         69 my @fm = (map({"\%-${_}s"} @spec[0 .. $#spec - 1]), '%s');
  23         100  
360 18         41 return join '', map { sprintf join(' ', @fm[0 .. $#$_]) . "\n", @$_ } @$rows;
  87         438  
361             }
362              
363             sub term_escape {
364 4     4 1 2590 my $str = shift;
365 4         26 $str =~ s/([\x00-\x09\x0b-\x1f\x7f\x80-\x9f])/sprintf '\\x%02x', ord $1/ge;
  16         62  
366 4         70 return $str;
367             }
368              
369             sub trim {
370 1370     1370 1 5011 my $str = shift;
371 1370         4331 $str =~ s/^\s+//;
372 1370         4066 $str =~ s/\s+$//;
373 1370         3994 return $str;
374             }
375              
376             sub unindent {
377 37     37 1 3349 my $str = shift;
378 37 100       222 my $min = min map { m/^([ \t]*)/; length $1 || () } split /\n/, $str;
  426         795  
  426         1051  
379 37 100       726 $str =~ s/^[ \t]{0,$min}//gm if $min;
380 37         584 return $str;
381             }
382              
383             sub unquote {
384 48     48 1 2546 my $str = shift;
385 48 50       276 return $str unless $str =~ s/^"(.*)"$/$1/g;
386 48         131 $str =~ s/\\\\/\\/g;
387 48         111 $str =~ s/\\"/"/g;
388 48         124 return $str;
389             }
390              
391             sub url_escape {
392 5814     5814 1 19515 my ($str, $pattern) = @_;
393              
394 5814 100       10294 if ($pattern) {
395 5799 100       13273 unless (exists $PATTERN{$pattern}) {
396 133         1436 (my $quoted = $pattern) =~ s!([/\$\[])!\\$1!g;
397 133 50       26161 $PATTERN{$pattern} = eval "sub { \$_[0] =~ s/([$quoted])/sprintf '%%%02X', ord \$1/ge }" or croak $@;
398             }
399 5799         127892 $PATTERN{$pattern}->($str);
400             }
401 15         94 else { $str =~ s/([^A-Za-z0-9\-._~])/sprintf '%%%02X', ord $1/ge }
  22         126  
402              
403 5814         22547 return $str;
404             }
405              
406             sub url_unescape {
407 7526     7526 1 17645 my $str = shift;
408 7526         15552 $str =~ s/%([0-9a-fA-F]{2})/chr hex $1/ge;
  787         2888  
409 7526         16564 return $str;
410             }
411              
412             sub xml_escape {
413 486 100 66 486 1 8347 return $_[0] if ref $_[0] && ref $_[0] eq 'Mojo::ByteStream';
  7982 100 100 7982   63866  
414 485   50     954 my $str = shift // '';
  6188   100     12683  
415 485         989 $str =~ s/([&<>"'])/$XML{$1}/ge;
  42         161  
  6188         12852  
  7688         21088  
416 485         1813 return $str;
  6187         14467  
417             }
418              
419             sub xor_encode {
420 294     294 1 3158 my ($input, $key) = @_;
421              
422             # Encode with variable key length
423 294         502 my $len = length $key;
424 294         489 my $buffer = my $output = '';
425 294         2158 $output .= $buffer ^ $key while length($buffer = substr($input, 0, $len, '')) == $len;
426 294         1747 return $output .= $buffer ^ substr($key, 0, length $buffer, '');
427             }
428              
429             sub _adapt {
430 479     479   830 my ($delta, $numpoints, $firsttime) = @_;
431 101     101   2224529 use integer;
  101         269  
  101         710  
432              
433 479 100       739 $delta = $firsttime ? $delta / PC_DAMP : $delta / 2;
434 479         613 $delta += $delta / $numpoints;
435 479         599 my $k = 0;
436 479         785 while ($delta > ((PC_BASE - PC_TMIN) * PC_TMAX) / 2) {
437 110         128 $delta /= PC_BASE - PC_TMIN;
438 110         171 $k += PC_BASE;
439             }
440              
441 479         790 return $k + (((PC_BASE - PC_TMIN + 1) * $delta) / ($delta + PC_SKEW));
442             }
443              
444 17662   66 17662   122735 sub _encoding { $ENCODING{$_[0]} //= find_encoding($_[0]) // croak "Unknown encoding '$_[0]'" }
      66        
445              
446             sub _entity {
447 991     991   2333 my ($point, $name, $attr) = @_;
448              
449             # Code point
450 991 100       2128 return chr($point !~ /^x/ ? $point : hex $point) unless defined $name;
    100          
451              
452             # Named character reference
453 950         1249 my $rest = my $last = '';
454 950         1696 while (length $name) {
455             return $ENTITIES{$name} . reverse $rest
456 988 100 100     5468 if exists $ENTITIES{$name} && (!$attr || $name =~ /;$/ || $last !~ /[A-Za-z0-9=]/);
      100        
457 48         111 $rest .= $last = chop $name;
458             }
459 10         52 return '&' . reverse $rest;
460             }
461              
462             sub _header {
463 1201     1201   2547 my ($str, $cookie) = @_;
464              
465 1201         2078 my (@tree, @part);
466 1201         4229 while ($str =~ /\G[,;\s]*([^=;, ]+)\s*/gc) {
467 798         2030 push @part, $1, undef;
468 798   100     2947 my $expires = $cookie && @part > 2 && lc $1 eq 'expires';
469              
470             # Special "expires" value
471 798 100 100     5249 if ($expires && $str =~ /\G=\s*$EXPIRES_RE/gco) { $part[-1] = $1 }
  120 100       301  
    100          
472              
473             # Quoted value
474 42         103 elsif ($str =~ /$QUOTED_VALUE_RE/gco) { $part[-1] = unquote $1 }
475              
476             # Unquoted value
477 538         1246 elsif ($str =~ /$UNQUOTED_VALUE_RE/gco) { $part[-1] = $1 }
478              
479             # Separator
480 798 100       2914 next unless $str =~ /\G[;\s]*,\s*/gc;
481 107         314 push @tree, [@part];
482 107         380 @part = ();
483             }
484              
485             # Take care of final part
486 1201 100       5044 return [@part ? (@tree, \@part) : @tree];
487             }
488              
489             sub _html {
490 36501     36501   53749 my ($str, $attr) = @_;
491 36501         47844 $str =~ s/$ENTITY_RE/_entity($1, $2, $attr)/geo;
  991         1835  
492 36501         168264 return $str;
493             }
494              
495             sub _options {
496              
497             # Hash or name (one)
498 1801 100   1801   5571 return ref $_[0] eq 'HASH' ? (undef, %{shift()}) : @_ if @_ == 1;
  996 100       3476  
499              
500             # Name and values (odd)
501 349 100       1054 return shift, @_ if @_ % 2;
502              
503             # Name and hash or just values (even)
504 269 100       1182 return ref $_[1] eq 'HASH' ? (shift, %{shift()}) : (undef, @_);
  18         103  
505             }
506              
507             # This may break in the future, but is worth it for performance
508 760     760   13249 sub _readable { !!(IO::Poll::_poll(@_[0, 1], my $m = POLLIN | POLLPRI) > 0) }
509              
510 16 100   16   181 sub _round { $_[0] < 10 ? int($_[0] * 10 + 0.5) / 10 : int($_[0] + 0.5) }
511              
512             sub _stash {
513 20923     20923   37553 my ($name, $object) = (shift, shift);
514              
515             # Hash
516 20923 100 100     109076 return $object->{$name} //= {} unless @_;
517              
518             # Get
519 1316 100 100     5189 return $object->{$name}{$_[0]} unless @_ > 1 || ref $_[0];
520              
521             # Set
522 1086 100       3882 my $values = ref $_[0] ? $_[0] : {@_};
523 1086         3642 @{$object->{$name}}{keys %$values} = values %$values;
  1086         3078  
524              
525 1086         4471 return $object;
526             }
527              
528             sub _teardown {
529 826 50   826   40825 return unless my $class = shift;
530              
531             # @ISA has to be cleared first because of circular references
532 101     101   99068 no strict 'refs';
  101         306  
  101         9642  
533 826         1175 @{"${class}::ISA"} = ();
  826         11911  
534 826         3475 delete_package $class;
535             }
536              
537             package Mojo::Util::_Guard;
538 101     101   725 use Mojo::Base -base;
  101         228  
  101         1001  
539              
540 18     18   1157 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