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         239  
4 6     6   33 use warnings;
  6         15  
  6         141  
5 6     6   29 use autodie;
  6         7  
  6         43  
6 6     6   33542 use feature qw(say);
  6         19  
  6         482  
7 6     6   42 use Path::Tiny;
  6         21  
  6         377  
8 6     6   46 use File::Basename;
  6         9  
  6         480  
9 6     6   37 use List::Util qw(any);
  6         61  
  6         447  
10 6     6   2820 use YAML::XS qw(LoadFile DumpFile);
  6         17829  
  6         398  
11             $YAML::XS::Boolean = 'JSON::PP'; # use JSON::PP::Boolean objects
12 6     6   41 use JSON::XS;
  6         32  
  6         336  
13 6     6   39 use Sort::Naturally qw(nsort);
  6         9  
  6         267  
14 6     6   3117 use Data::Leaf::Walker;
  6         9142  
  6         200  
15 6     6   39 use Exporter 'import';
  6         11  
  6         3839  
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 82 my $str = path(shift)->slurp_utf8;
27 10         13817 return decode_json($str); # Decode to Perl data structure
28             }
29              
30             sub read_yaml {
31              
32 12     12 0 86 my $data = LoadFile(shift); # Decode to Perl data structure
33 7         6650 traverse_yaml_data_to_coerce_numbers($data)
34             ; # revert floatings getting stringified by YAML::XS
35 7         535 return $data;
36             }
37              
38             sub io_yaml_or_json {
39              
40 32     32 0 75 my $arg = shift;
41 32         77 my $file = $arg->{filepath};
42 32         63 my $mode = $arg->{mode};
43 32 100       139 my $data = $mode eq 'write' ? $arg->{data} : undef;
44              
45             # Checking only for qw(.yaml .yml .json)
46 32         115 my @exts = qw(.yaml .yml .json);
47 32         186 my $msg = qq(Can't recognize <$file> extension. Extensions allowed are: )
48             . join ',', @exts;
49 32         2460 my ( undef, undef, $ext ) = fileparse( $file, @exts );
50 32 100   72   378 die $msg unless any { $_ eq $ext } @exts;
  72         4001  
51              
52             # To simplify return values, we create a hash
53 30         167 $ext =~ tr/a.//d; # Unify $ext (delete 'a' and '.')
54 30         328 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       203 : $return->{$mode}{$ext}->( { filepath => $file, data => $data } );
63             }
64              
65             sub write_json {
66              
67 8     8 0 23 my $arg = shift;
68 8         17 my $file = $arg->{filepath};
69 8         16 my $json_data = $arg->{data};
70 8         31874 my $json = JSON::XS->new->utf8->canonical->pretty->encode($json_data);
71 8         120 path($file)->spew_utf8($json);
72 8         19166 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 23 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         303 while ( my ( $key_path, $value ) = $walker->each ) {
92 1218 50       50982 $walker->store( $key_path, $value + 0 )
93             if Scalar::Util::looks_like_number $value;
94             }
95             }
96             1;