File Coverage

blib/lib/CHI/Util.pm
Criterion Covered Total %
statement 95 100 95.0
branch 18 26 69.2
condition 3 6 50.0
subroutine 25 26 96.1
pod 0 11 0.0
total 141 169 83.4


line stmt bran cond sub pod time code
1             package CHI::Util;
2             $CHI::Util::VERSION = '0.60';
3 21     21   90 use Carp qw( croak longmess );
  21         32  
  21         1431  
4 21     21   1294 use Module::Runtime qw(require_module);
  21         3422  
  21         129  
5 21     21   2494 use Data::Dumper;
  21         19336  
  21         1080  
6 21     21   9903 use Data::UUID;
  21         13402  
  21         1464  
7 21     21   129 use Fcntl qw( :DEFAULT );
  21         27  
  21         8818  
8 21     21   10991 use File::Spec::Functions qw(catdir catfile);
  21         15278  
  21         1567  
9 21     21   10419 use JSON::MaybeXS;
  21         112881  
  21         1373  
10 21     21   11606 use Time::Duration::Parse;
  21         38749  
  21         145  
11 21     21   13046 use Try::Tiny;
  21         25855  
  21         1227  
12 21     21   128 use strict;
  21         28  
  21         619  
13 21     21   90 use warnings;
  21         43  
  21         639  
14 21     21   99 use base qw(Exporter);
  21         29  
  21         17708  
15              
16             our @EXPORT_OK = qw(
17             can_load
18             dump_one_line
19             fast_catdir
20             fast_catfile
21             has_moose_class
22             json_decode
23             json_encode
24             parse_duration
25             parse_memory_size
26             read_file
27             read_dir
28             unique_id
29             write_file
30             );
31              
32             my $Fetch_Flags = O_RDONLY | O_BINARY;
33             my $Store_Flags = O_WRONLY | O_CREAT | O_BINARY;
34              
35             sub can_load {
36              
37             # Load $class_name if possible. Return 1 if successful, 0 if it could not be
38             # found, and rethrow load error (other than not found).
39             #
40 49     49 0 92 my ($class_name) = @_;
41              
42 49         58 my $result;
43             try {
44 49     49   1674 require_module($class_name);
45 20         21627 $result = 1;
46             }
47             catch {
48 29 50 33 29   8000 if ( /Can\'t locate .* in \@INC/ && !/Compilation failed/ ) {
49 29         125 $result = 0;
50             }
51             else {
52 0         0 die $_;
53             }
54 49         474 };
55 49         706 return $result;
56             }
57              
58             sub dump_one_line {
59 12     12 0 20 my ($value) = @_;
60              
61 12         104 return Data::Dumper->new( [$value] )->Indent(0)->Sortkeys(1)->Quotekeys(0)
62             ->Terse(1)->Dump();
63             }
64              
65             # Simplified read_dir cribbed from File::Slurp
66             sub read_dir {
67 24     24 0 30 my ($dir) = @_;
68              
69             ## no critic (RequireInitializationForLocalVars)
70 24         61 local *DIRH;
71 24 50       466 opendir( DIRH, $dir ) or croak "cannot open '$dir': $!";
72 24 100       232 return grep { $_ ne "." && $_ ne ".." } readdir(DIRH);
  146         665  
73             }
74              
75             sub read_file {
76 5199     5199 0 6731 my ($file) = @_;
77              
78             # Fast slurp, adapted from File::Slurp::read, with unnecessary options removed
79             #
80 5199         5538 my $buf = "";
81 5199         4336 my $read_fh;
82 5199 50       148192 unless ( sysopen( $read_fh, $file, $Fetch_Flags ) ) {
83 0         0 croak "read_file '$file' - sysopen: $!";
84             }
85 5199         25501 my $size_left = -s $read_fh;
86 5199         4911 while (1) {
87 5199         26107 my $read_cnt = sysread( $read_fh, $buf, $size_left, length $buf );
88 5199 50       9192 if ( defined $read_cnt ) {
89 5199 50       9377 last if $read_cnt == 0;
90 5199         5561 $size_left -= $read_cnt;
91 5199 50       12343 last if $size_left <= 0;
92             }
93             else {
94 0         0 croak "read_file '$file' - sysread: $!";
95             }
96             }
97 5199         56853 return $buf;
98             }
99              
100             sub write_file {
101 2053     2053 0 3462 my ( $file, $data, $file_create_mode ) = @_;
102 2053 50       4171 $file_create_mode = oct(666) if !defined($file_create_mode);
103              
104             # Fast spew, adapted from File::Slurp::write, with unnecessary options removed
105             #
106             {
107 2053         2102 my $write_fh;
  2053         2185  
108 2053 100       148362 unless ( sysopen( $write_fh, $file, $Store_Flags, $file_create_mode ) )
109             {
110 2         63 croak "write_file '$file' - sysopen: $!";
111             }
112 2051         5404 my $size_left = length($data);
113 2051         2788 my $offset = 0;
114 2051         2991 do {
115 2051         56219 my $write_cnt = syswrite( $write_fh, $data, $size_left, $offset );
116 2051 50       5316 unless ( defined $write_cnt ) {
117 0         0 croak "write_file '$file' - syswrite: $!";
118             }
119 2051         3303 $size_left -= $write_cnt;
120 2051         28439 $offset += $write_cnt;
121             } while ( $size_left > 0 );
122             }
123             }
124              
125             {
126              
127             # For efficiency, use Data::UUID to generate an initial unique id, then suffix it to
128             # generate a series of 0x10000 unique ids. Not to be used for hard-to-guess ids, obviously.
129              
130             my $uuid;
131             my $suffix = 0;
132              
133             sub unique_id {
134 2326 100 66 2326 0 9094 if ( !$suffix || !defined($uuid) ) {
135 8         1073 my $ug = Data::UUID->new();
136 8         1778 $uuid = $ug->create_hex();
137             }
138 2326         10049 my $hex = sprintf( '%s%04x', $uuid, $suffix );
139 2326         3915 $suffix = ( $suffix + 1 ) & 0xffff;
140 2326         5892 return $hex;
141             }
142             }
143              
144 21         7475 use constant _FILE_SPEC_USING_UNIX =>
145 21     21   161 ( $File::Spec::ISA[0] eq 'File::Spec::Unix' );
  21         37  
146              
147             sub fast_catdir {
148 2153     2153 0 2186 if (_FILE_SPEC_USING_UNIX) {
149 2153         8051 return join '/', @_;
150             }
151             else {
152             return catdir(@_);
153             }
154             }
155              
156             sub fast_catfile {
157 10730     10730 0 10917 if (_FILE_SPEC_USING_UNIX) {
158 10730         34112 return join '/', @_;
159             }
160             else {
161             return catfile(@_);
162             }
163             }
164              
165             my %memory_size_units = ( 'k' => 1024, 'm' => 1024 * 1024 );
166              
167             sub parse_memory_size {
168 11     11 0 23 my $size = shift;
169 11 100       118 if ( $size =~ /^\d+b?$/ ) {
    100          
170 1         4 return $size;
171             }
172             elsif ( my ( $quantity, $unit ) = ( $size =~ /^(\d+)\s*([km])b?$/i ) ) {
173 9         205 return $quantity * $memory_size_units{ lc($unit) };
174             }
175             else {
176 1         27 croak "cannot parse memory size '$size'";
177             }
178             }
179              
180             my $json = JSON::MaybeXS->new( utf8 => 1, canonical => 1 );
181              
182             sub json_decode {
183 0     0 0 0 $json->decode( $_[0] );
184             }
185              
186             sub json_encode {
187 555     555 0 4301 $json->encode( $_[0] );
188             }
189              
190             1;
191              
192             __END__