File Coverage

blib/lib/WWW/Suffit/Util.pm
Criterion Covered Total %
statement 38 104 36.5
branch 0 44 0.0
condition 1 30 3.3
subroutine 13 22 59.0
pod 10 10 100.0
total 62 210 29.5


line stmt bran cond sub pod time code
1             package WWW::Suffit::Util;
2 1     1   68133 use strict;
  1         9  
  1         30  
3 1     1   646 use utf8;
  1         15  
  1         5  
4              
5             =encoding utf8
6              
7             =head1 NAME
8              
9             WWW::Suffit::Util - The Suffit utilities
10              
11             =head1 VERSION
12              
13             Version 1.00
14              
15             =head1 SYNOPSIS
16              
17             use WWW::Suffit::Util;
18              
19             =head1 DESCRIPTION
20              
21             Exported utility functions
22              
23             =head2 fbytes
24              
25             print fbytes( 123456 );
26              
27             Returns formatted size value
28              
29             =head2 fdate
30              
31             print fdate( time );
32              
33             Returns formatted date value
34              
35             =head2 fdatetime
36              
37             print fdatetime( time );
38              
39             Returns formatted date value
40              
41             =head2 fduration
42              
43             print fduration( 123 );
44              
45             Returns formatted duration value
46              
47             =head2 human2bytes
48              
49             my $bytes = human2bytes("100 kB");
50              
51             Converts a human readable byte count into the pure number of bytes without any suffix
52              
53             =head2 json_load
54              
55             my $hash = json_load( $file );
56              
57             Loads JSON file and returns data as perl struct
58              
59             =head2 json_save
60              
61             my $path = json_save( $file, {foo => [1, 2], bar => 'hello!', baz => \1} );
62              
63             Save perl struct to file as JSON document and returns the L object
64              
65             =head2 md5sum
66              
67             my $md5 = md5sum( $file );
68              
69             See L
70              
71             =head2 parse_expire
72              
73             print parse_expire("+1d"); # 86400
74             print parse_expire("-1d"); # -86400
75              
76             Returns offset of expires time (in secs).
77              
78             Original this function is the part of CGI::Util::expire_calc!
79              
80             This internal routine creates an expires time exactly some number of hours from the current time.
81             It incorporates modifications from Mark Fisher.
82              
83             format for time can be in any of the forms:
84              
85             now -- expire immediately
86             +180s -- in 180 seconds
87             +2m -- in 2 minutes
88             +12h -- in 12 hours
89             +1d -- in 1 day
90             +3M -- in 3 months
91             +2y -- in 2 years
92             -3m -- 3 minutes ago(!)
93              
94             If you don't supply one of these forms, we assume you are specifying the date yourself
95              
96             =head2 parse_time_offset
97              
98             my $off = parse_time_offset("1h2m24s"); # 4344
99             my $off = parse_time_offset("1h 2m 24s"); # 4344
100              
101             Returns offset of time (in secs)
102              
103             =head1 HISTORY
104              
105             See C file
106              
107             =head1 TO DO
108              
109             See C file
110              
111             =head1 SEE ALSO
112              
113             L
114              
115             =head1 AUTHOR
116              
117             Serż Minus (Sergey Lepenkov) L Eabalama@cpan.orgE
118              
119             =head1 COPYRIGHT
120              
121             Copyright (C) 1998-2023 D&D Corporation. All Rights Reserved
122              
123             =head1 LICENSE
124              
125             This program is free software; you can redistribute it and/or
126             modify it under the same terms as Perl itself.
127              
128             See C file and L
129              
130             =cut
131              
132 1     1   58 use vars qw/ $VERSION @EXPORT_OK @EXPORT /;
  1         2  
  1         76  
133             $VERSION = '1.00';
134              
135 1     1   6 use Carp;
  1         2  
  1         51  
136 1     1   536 use POSIX qw/ ceil strftime /;
  1         6409  
  1         5  
137 1     1   1462 use Digest::MD5;
  1         2  
  1         54  
138              
139 1     1   573 use Mojo::Util qw/ trim /;
  1         202343  
  1         210  
140 1     1   493 use Mojo::JSON qw/ decode_json encode_json /;
  1         21664  
  1         92  
141 1     1   514 use Mojo::File qw/ path /;
  1         32681  
  1         67  
142              
143 1     1   514 use WWW::Suffit::Const qw/ DATE_FORMAT DATETIME_FORMAT /;
  1         2  
  1         81  
144              
145 1     1   7 use base qw/Exporter/;
  1         2  
  1         168  
146             @EXPORT = (qw/
147             parse_expire parse_time_offset
148             /);
149             @EXPORT_OK = (qw/
150             fbytes fdate fdatetime fduration human2bytes
151             md5sum
152             json_load json_save
153             /, @EXPORT);
154              
155 1         1270 use constant HUMAN_SUFFIXES => {
156             'B' => 0,
157             'K' => 10, 'KB' => 10, 'KIB' => 10,
158             'M' => 20, 'MB' => 20, 'MIB' => 20,
159             'G' => 30, 'GB' => 30, 'GIB' => 30,
160             'T' => 40, 'TB' => 40, 'TIB' => 40,
161             'P' => 50, 'PB' => 50, 'PIB' => 50,
162             'E' => 60, 'EB' => 60, 'EIB' => 60,
163             'Z' => 70, 'ZB' => 70, 'ZIB' => 70,
164             'Y' => 80, 'YB' => 80, 'YIB' => 80,
165 1     1   7 };
  1         2  
166              
167             sub fbytes {
168 0     0 1 0 my $n = int(shift);
169 0 0       0 if ($n >= 1024 ** 3) {
    0          
    0          
170 0         0 return sprintf "%.3g GiB", $n / (1024 ** 3);
171             } elsif ($n >= 1024 ** 2) {
172 0         0 return sprintf "%.3g MiB", $n / (1024.0 * 1024);
173             } elsif ($n >= 1024) {
174 0         0 return sprintf "%.3g KiB", $n / 1024.0;
175             } else {
176 0         0 return "$n B"; # bytes
177             }
178             }
179             sub human2bytes {
180 0   0 0 1 0 my $h = shift || 0;
181 0 0       0 return 0 unless $h;
182 0         0 my ($bts, $sfx) = $h =~ /([0-9.]+)\s*([a-zA-Z]*)/;
183 0 0       0 return 0 unless $bts;
184 0   0     0 my $exp = HUMAN_SUFFIXES->{($sfx ? uc($sfx) : "B")} || 0;
185 0         0 return ceil($bts * (2 ** $exp));
186             }
187             sub fduration {
188 0   0 0 1 0 my $msecs = shift || 0;
189 0         0 my $secs = int($msecs);
190 0         0 my $hours = int($secs / (60*60));
191 0         0 $secs -= $hours * 60*60;
192 0         0 my $mins = int($secs / 60);
193 0         0 $secs %= 60;
194 0 0       0 if ($hours) {
    0          
    0          
195 0         0 return sprintf("%d hours %d minutes", $hours, $mins);
196             } elsif ($mins >= 2) {
197 0         0 return sprintf("%d minutes", $mins);
198             } elsif ($secs < 2*60) {
199 0         0 return sprintf("%.4f seconds", $msecs);
200             } else {
201 0         0 $secs += $mins * 60;
202 0         0 return sprintf("%d seconds", $secs);
203             }
204             }
205             sub fdate {
206 0   0 0 1 0 my $t = shift || time;
207 0         0 return strftime(DATE_FORMAT, localtime($t));
208             }
209             sub fdatetime {
210 1   33 1 1 585 my $t = shift || time;
211 1         89 return strftime(DATETIME_FORMAT, localtime($t));
212             }
213             sub parse_expire {
214 0   0 0 1   my $t = trim(shift(@_) // 0);
215 0           my %mult = (
216             's' => 1,
217             'm' => 60,
218             'h' => 60*60,
219             'd' => 60*60*24,
220             'w' => 60*60*24*7,
221             'M' => 60*60*24*30,
222             'y' => 60*60*24*365
223             );
224 0 0 0       if (!$t || (lc($t) eq 'now')) {
    0          
    0          
225 0           return 0;
226             } elsif ($t =~ /^\d+$/) {
227 0           return $t; # secs
228             } elsif ($t=~/^([+-]?(?:\d+|\d*\.\d*))([smhdwMy])/) {
229 0   0       return ($mult{$2} || 1) * $1;
230             }
231 0           return $t;
232             }
233             sub parse_time_offset {
234 0   0 0 1   my $s = trim(shift(@_) // 0);
235 0 0         return $s if $s =~ /^\d+$/;
236 0           my $r = 0;
237 0           my $c = 0;
238 0           while ($s =~ s/([+-]?(?:\d+|\d*\.\d*)[smhdMy])//) {
239 0           my $i = parse_expire("$1");
240 0 0         $c++ if $i < 0;
241 0 0         $r += $i < 0 ? $i*-1 : $i;
242             }
243 0 0         return $c ? $r*-1 : $r;
244             }
245             sub md5sum {
246 0     0 1   my $f = shift;
247 0           my $md5 = Digest::MD5->new;
248 0           my $sum = '';
249 0 0         return $sum unless -e $f;
250 0 0 0       open( my $md5_fh, '<', $f) or (carp("Can't open '$f': $!") && return $sum);
251 0 0         if ($md5_fh) {
252 0           binmode($md5_fh);
253 0           $md5->addfile($md5_fh);
254 0           $sum = $md5->hexdigest;
255 0           close($md5_fh);
256             }
257 0           return $sum;
258             }
259             sub json_save {
260 0   0 0 1   my $file = shift // '';
261 0           my $data = shift;
262 0 0         croak("No file specified") unless length $file;
263 0 0 0       croak("No data (perl struct) specified") unless ref $data eq 'ARRAY' || ref $data eq 'HASH';
264              
265             # my $bytes = encode_json {foo => [1, 2], bar => 'hello!', baz => \1};
266 0           my $path = path($file)->spurt( encode_json($data) );
267 0           return $path;
268             }
269             sub json_load {
270 0   0 0 1   my $file = shift // '';
271 0 0         croak("No file specified") unless length $file;
272 0 0         unless (-e $file) {
273 0           carp("JSON file not found: $file");
274 0           return undef;
275             }
276              
277             # my $hash = decode_json $bytes;
278 0           my $data = decode_json( path($file)->slurp );
279 0           return $data;
280             }
281              
282             1;
283              
284             __END__