File Coverage

blib/lib/CHI/Util.pm
Criterion Covered Total %
statement 42 103 40.7
branch 0 26 0.0
condition 0 6 0.0
subroutine 14 27 51.8
pod 0 11 0.0
total 56 173 32.3


line stmt bran cond sub pod time code
1             package CHI::Util;
2             $CHI::Util::VERSION = '0.59';
3 2     2   10 use Carp qw( croak longmess );
  2         3  
  2         142  
4 2     2   1400 use Module::Runtime qw(require_module);
  2         2947  
  2         11  
5 2     2   1304 use Data::Dumper;
  2         16068  
  2         314  
6 2     2   907 use Data::UUID;
  2         2318  
  2         124  
7 2     2   12 use Fcntl qw( :DEFAULT );
  2         2  
  2         734  
8 2     2   951 use File::Spec::Functions qw(catdir catfile);
  2         1376  
  2         163  
9 2     2   1455 use JSON;
  2         19606  
  2         9  
10 2     2   1186 use Time::Duration::Parse;
  2         3014  
  2         11  
11 2     2   950 use Try::Tiny;
  2         2142  
  2         115  
12 2     2   10 use strict;
  2         3  
  2         44  
13 2     2   6 use warnings;
  2         11  
  2         43  
14 2     2   8 use base qw(Exporter);
  2         3  
  2         1444  
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             # Map null, true and false to real Perl values
36             if ( JSON->VERSION < 2 ) {
37             $JSON::UnMapping = 1;
38             }
39              
40             sub can_load {
41              
42             # Load $class_name if possible. Return 1 if successful, 0 if it could not be
43             # found, and rethrow load error (other than not found).
44             #
45 0     0 0   my ($class_name) = @_;
46              
47 0           my $result;
48             try {
49 0     0     require_module($class_name);
50 0           $result = 1;
51             }
52             catch {
53 0 0 0 0     if ( /Can\'t locate .* in \@INC/ && !/Compilation failed/ ) {
54 0           $result = 0;
55             }
56             else {
57 0           die $_;
58             }
59 0           };
60 0           return $result;
61             }
62              
63             sub dump_one_line {
64 0     0 0   my ($value) = @_;
65              
66 0           return Data::Dumper->new( [$value] )->Indent(0)->Sortkeys(1)->Quotekeys(0)
67             ->Terse(1)->Dump();
68             }
69              
70             # Simplified read_dir cribbed from File::Slurp
71             sub read_dir {
72 0     0 0   my ($dir) = @_;
73              
74             ## no critic (RequireInitializationForLocalVars)
75 0           local *DIRH;
76 0 0         opendir( DIRH, $dir ) or croak "cannot open '$dir': $!";
77 0 0         return grep { $_ ne "." && $_ ne ".." } readdir(DIRH);
  0            
78             }
79              
80             sub read_file {
81 0     0 0   my ($file) = @_;
82              
83             # Fast slurp, adapted from File::Slurp::read, with unnecessary options removed
84             #
85 0           my $buf = "";
86 0           my $read_fh;
87 0 0         unless ( sysopen( $read_fh, $file, $Fetch_Flags ) ) {
88 0           croak "read_file '$file' - sysopen: $!";
89             }
90 0           my $size_left = -s $read_fh;
91 0           while (1) {
92 0           my $read_cnt = sysread( $read_fh, $buf, $size_left, length $buf );
93 0 0         if ( defined $read_cnt ) {
94 0 0         last if $read_cnt == 0;
95 0           $size_left -= $read_cnt;
96 0 0         last if $size_left <= 0;
97             }
98             else {
99 0           croak "read_file '$file' - sysread: $!";
100             }
101             }
102 0           return $buf;
103             }
104              
105             sub write_file {
106 0     0 0   my ( $file, $data, $file_create_mode ) = @_;
107 0 0         $file_create_mode = oct(666) if !defined($file_create_mode);
108              
109             # Fast spew, adapted from File::Slurp::write, with unnecessary options removed
110             #
111             {
112 0           my $write_fh;
  0            
113 0 0         unless ( sysopen( $write_fh, $file, $Store_Flags, $file_create_mode ) )
114             {
115 0           croak "write_file '$file' - sysopen: $!";
116             }
117 0           my $size_left = length($data);
118 0           my $offset = 0;
119 0           do {
120 0           my $write_cnt = syswrite( $write_fh, $data, $size_left, $offset );
121 0 0         unless ( defined $write_cnt ) {
122 0           croak "write_file '$file' - syswrite: $!";
123             }
124 0           $size_left -= $write_cnt;
125 0           $offset += $write_cnt;
126             } while ( $size_left > 0 );
127             }
128             }
129              
130             {
131              
132             # For efficiency, use Data::UUID to generate an initial unique id, then suffix it to
133             # generate a series of 0x10000 unique ids. Not to be used for hard-to-guess ids, obviously.
134              
135             my $uuid;
136             my $suffix = 0;
137              
138             sub unique_id {
139 0 0 0 0 0   if ( !$suffix || !defined($uuid) ) {
140 0           my $ug = Data::UUID->new();
141 0           $uuid = $ug->create_hex();
142             }
143 0           my $hex = sprintf( '%s%04x', $uuid, $suffix );
144 0           $suffix = ( $suffix + 1 ) & 0xffff;
145 0           return $hex;
146             }
147             }
148              
149 2         666 use constant _FILE_SPEC_USING_UNIX =>
150 2     2   10 ( $File::Spec::ISA[0] eq 'File::Spec::Unix' );
  2         5  
151              
152             sub fast_catdir {
153 0     0 0   if (_FILE_SPEC_USING_UNIX) {
154 0           return join '/', @_;
155             }
156             else {
157             return catdir(@_);
158             }
159             }
160              
161             sub fast_catfile {
162 0     0 0   if (_FILE_SPEC_USING_UNIX) {
163 0           return join '/', @_;
164             }
165             else {
166             return catfile(@_);
167             }
168             }
169              
170             my %memory_size_units = ( 'k' => 1024, 'm' => 1024 * 1024 );
171              
172             sub parse_memory_size {
173 0     0 0   my $size = shift;
174 0 0         if ( $size =~ /^\d+b?$/ ) {
    0          
175 0           return $size;
176             }
177             elsif ( my ( $quantity, $unit ) = ( $size =~ /^(\d+)\s*([km])b?$/i ) ) {
178 0           return $quantity * $memory_size_units{ lc($unit) };
179             }
180             else {
181 0           croak "cannot parse memory size '$size'";
182             }
183             }
184              
185             # Maintain compatibility with both JSON 1 and 2. Borrowed from Data::Serializer::JSON.
186             #
187 2     2   11 use constant _OLD_JSON => JSON->VERSION < 2;
  2         1  
  2         343  
188             my $json = _OLD_JSON ? JSON->new : JSON->new->utf8->canonical;
189              
190             sub json_decode {
191 0     0 0   return _OLD_JSON
192             ? $json->jsonToObj( $_[0] )
193             : $json->decode( $_[0] );
194             }
195              
196             sub json_encode {
197 0     0 0   return _OLD_JSON
198             ? $json->objToJson( $_[0] )
199             : $json->encode( $_[0] );
200             }
201              
202             1;
203              
204             __END__