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.61';
3 21     21   149 use Carp qw( croak longmess );
  21         40  
  21         1375  
4 21     21   1935 use Module::Runtime qw(require_module);
  21         3980  
  21         133  
5 21     21   14625 use Data::Dumper;
  21         154479  
  21         1574  
6 21     21   9184 use Data::UUID;
  21         14664  
  21         1464  
7 21     21   174 use Fcntl qw( :DEFAULT );
  21         40  
  21         8628  
8 21     21   10259 use File::Spec::Functions qw(catdir catfile);
  21         18049  
  21         1482  
9 21     21   9791 use JSON::MaybeXS;
  21         181663  
  21         1291  
10 21     21   10293 use Time::Duration::Parse;
  21         42492  
  21         141  
11 21     21   12919 use Try::Tiny;
  21         45118  
  21         1264  
12 21     21   152 use strict;
  21         46  
  21         398  
13 21     21   101 use warnings;
  21         42  
  21         532  
14 21     21   113 use base qw(Exporter);
  21         49  
  21         19572  
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 51     51 0 164 my ($class_name) = @_;
41              
42 51         87 my $result;
43             try {
44 51     51   3032 require_module($class_name);
45 22         43912 $result = 1;
46             }
47             catch {
48 29 50 33 29   7175 if ( /Can\'t locate .* in \@INC/ && !/Compilation failed/ ) {
49 29         228 $result = 0;
50             }
51             else {
52 0         0 die $_;
53             }
54 51         470 };
55 51         887 return $result;
56             }
57              
58             sub dump_one_line {
59 12     12 0 27 my ($value) = @_;
60              
61 12         67 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 46     46 0 107 my ($dir) = @_;
68              
69             ## no critic (RequireInitializationForLocalVars)
70 46         140 local *DIRH;
71 46 50       1154 opendir( DIRH, $dir ) or croak "cannot open '$dir': $!";
72 46 100       1144 return grep { $_ ne "." && $_ ne ".." } readdir(DIRH);
  278         1576  
73             }
74              
75             sub read_file {
76 5414     5414 0 11819 my ($file) = @_;
77              
78             # Fast slurp, adapted from File::Slurp::read, with unnecessary options removed
79             #
80 5414         8643 my $buf = "";
81 5414         7126 my $read_fh;
82 5414 50       188776 unless ( sysopen( $read_fh, $file, $Fetch_Flags ) ) {
83 0         0 croak "read_file '$file' - sysopen: $!";
84             }
85 5414         53653 my $size_left = -s $read_fh;
86 5414         12510 while (1) {
87 5414         60866 my $read_cnt = sysread( $read_fh, $buf, $size_left, length $buf );
88 5414 50       16341 if ( defined $read_cnt ) {
89 5414 50       11330 last if $read_cnt == 0;
90 5414         8217 $size_left -= $read_cnt;
91 5414 50       14205 last if $size_left <= 0;
92             }
93             else {
94 0         0 croak "read_file '$file' - sysread: $!";
95             }
96             }
97 5414         88675 return $buf;
98             }
99              
100             sub write_file {
101 2228     2228 0 4731 my ( $file, $data, $file_create_mode ) = @_;
102 2228 50       4666 $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 2228         3302 my $write_fh;
  2228         3205  
108 2228 100       158941 unless ( sysopen( $write_fh, $file, $Store_Flags, $file_create_mode ) )
109             {
110 2         70 croak "write_file '$file' - sysopen: $!";
111             }
112 2226         11298 my $size_left = length($data);
113 2226         3762 my $offset = 0;
114 2226         3865 do {
115 2226         63668 my $write_cnt = syswrite( $write_fh, $data, $size_left, $offset );
116 2226 50       9109 unless ( defined $write_cnt ) {
117 0         0 croak "write_file '$file' - syswrite: $!";
118             }
119 2226         3805 $size_left -= $write_cnt;
120 2226         41456 $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 2537 100 66 2537 0 11168 if ( !$suffix || !defined($uuid) ) {
135 9         1704 my $ug = Data::UUID->new();
136 9         15455 $uuid = $ug->create_hex();
137             }
138 2537         12153 my $hex = sprintf( '%s%04x', $uuid, $suffix );
139 2537         5371 $suffix = ( $suffix + 1 ) & 0xffff;
140 2537         6745 return $hex;
141             }
142             }
143              
144 21         8818 use constant _FILE_SPEC_USING_UNIX =>
145 21     21   175 ( $File::Spec::ISA[0] eq 'File::Spec::Unix' );
  21         41  
146              
147             sub fast_catdir {
148 2416     2416 0 3550 if (_FILE_SPEC_USING_UNIX) {
149 2416         9953 return join '/', @_;
150             }
151             else {
152             return catdir(@_);
153             }
154             }
155              
156             sub fast_catfile {
157 11496     11496 0 16157 if (_FILE_SPEC_USING_UNIX) {
158 11496         37844 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 12     12 0 31 my $size = shift;
169 12 100       175 if ( $size =~ /^\d+b?$/ ) {
    100          
170 1         4 return $size;
171             }
172             elsif ( my ( $quantity, $unit ) = ( $size =~ /^(\d+)\s*([km])b?$/i ) ) {
173 10         207 return $quantity * $memory_size_units{ lc($unit) };
174             }
175             else {
176 1         16 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 771     771 0 5933 $json->encode( $_[0] );
188             }
189              
190             1;
191              
192             __END__