File Coverage

lib/Convert/Pheno/IO.pm
Criterion Covered Total %
statement 63 68 92.6
branch 7 8 87.5
condition n/a
subroutine 18 19 94.7
pod 0 6 0.0
total 88 101 87.1


line stmt bran cond sub pod time code
1             package Convert::Pheno::IO;
2              
3 6     6   45 use strict;
  6         11  
  6         190  
4 6     6   29 use warnings;
  6         17  
  6         144  
5 6     6   26 use autodie;
  6         12  
  6         50  
6 6     6   33619 use feature qw(say);
  6         14  
  6         525  
7 6     6   40 use Path::Tiny;
  6         11  
  6         391  
8 6     6   40 use File::Basename;
  6         12  
  6         501  
9 6     6   37 use List::Util qw(any);
  6         55  
  6         470  
10 6     6   2978 use YAML::XS qw(LoadFile DumpFile);
  6         18220  
  6         395  
11             $YAML::XS::Boolean = 'JSON::PP'; # use JSON::PP::Boolean objects
12 6     6   66 use JSON::XS;
  6         25  
  6         372  
13 6     6   46 use Sort::Naturally qw(nsort);
  6         15  
  6         276  
14 6     6   3213 use Data::Leaf::Walker;
  6         9203  
  6         226  
15 6     6   38 use Exporter 'import';
  6         11  
  6         3915  
16             our @EXPORT = qw(read_json read_yaml io_yaml_or_json write_json write_yaml);
17              
18             #########################
19             #########################
20             # SUBROUTINES FOR I/O #
21             #########################
22             #########################
23              
24             sub read_json {
25              
26 10     10 0 85 my $str = path(shift)->slurp_utf8;
27 10         15418 return decode_json($str); # Decode to Perl data structure
28             }
29              
30             sub read_yaml {
31              
32 12     12 0 112 my $data = LoadFile(shift); # Decode to Perl data structure
33 7         6255 traverse_yaml_data_to_coerce_numbers($data)
34             ; # revert floatings getting stringified by YAML::XS
35 7         505 return $data;
36             }
37              
38             sub io_yaml_or_json {
39              
40 32     32 0 72 my $arg = shift;
41 32         76 my $file = $arg->{filepath};
42 32         61 my $mode = $arg->{mode};
43 32 100       106 my $data = $mode eq 'write' ? $arg->{data} : undef;
44              
45             # Checking only for qw(.yaml .yml .json)
46 32         112 my @exts = qw(.yaml .yml .json);
47 32         167 my $msg = qq(Can't recognize <$file> extension. Extensions allowed are: )
48             . join ',', @exts;
49 32         2155 my ( undef, undef, $ext ) = fileparse( $file, @exts );
50 32 100   72   365 die $msg unless any { $_ eq $ext } @exts;
  72         2682  
51              
52             # To simplify return values, we create a hash
53 30         181 $ext =~ tr/a.//d; # Unify $ext (delete 'a' and '.')
54 30         302 my $return = {
55             read => { json => \&read_json, yml => \&read_yaml },
56             write => { json => \&write_json, yml => \&write_yaml }
57             };
58              
59             # We return according to the mode (read or write) and format
60             return $mode eq 'read'
61             ? $return->{$mode}{$ext}->($file)
62 30 100       184 : $return->{$mode}{$ext}->( { filepath => $file, data => $data } );
63             }
64              
65             sub write_json {
66              
67 8     8 0 32 my $arg = shift;
68 8         23 my $file = $arg->{filepath};
69 8         15 my $json_data = $arg->{data};
70 8         34193 my $json = JSON::XS->new->utf8->canonical->pretty->encode($json_data);
71 8         155 path($file)->spew_utf8($json);
72 8         21203 return 1;
73             }
74              
75             sub write_yaml {
76              
77 0     0 0 0 my $arg = shift;
78 0         0 my $file = $arg->{filepath};
79 0         0 my $json_data = $arg->{data};
80 0         0 DumpFile( $file, $json_data );
81 0         0 return 1;
82             }
83              
84             sub traverse_yaml_data_to_coerce_numbers {
85              
86 7     7 0 17 my $data = shift;
87              
88             # Traversing the data to force numbers to be numbers
89             # NB: Changing the original data structure
90 7         98 my $walker = Data::Leaf::Walker->new($data);
91 7         286 while ( my ( $key_path, $value ) = $walker->each ) {
92 1218 50       49888 $walker->store( $key_path, $value + 0 )
93             if Scalar::Util::looks_like_number $value;
94             }
95             }
96             1;