File Coverage

blib/lib/Google/Data/JSON.pm
Criterion Covered Total %
statement 28 30 93.3
branch n/a
condition n/a
subroutine 10 10 100.0
pod n/a
total 38 40 95.0


line stmt bran cond sub pod time code
1             package Google::Data::JSON;
2              
3 2     2   98818 use warnings;
  2         4  
  2         76  
4 2     2   10 use strict;
  2         4  
  2         71  
5              
6 2     2   2783 use version; our $VERSION = qv('0.1.10');
  2         4731  
  2         14  
7              
8 2     2   1214 use File::Slurp;
  2         23704  
  2         176  
9 2     2   2047 use JSON::Any;
  2         78960  
  2         25  
10 2     2   26844 use List::MoreUtils qw( any uniq );
  2         3631  
  2         227  
11 2     2   2694 use Perl6::Export::Attrs;
  2         15091  
  2         15  
12 2     2   2733 use Storable qw(dclone);
  2         27718  
  2         194  
13 2     2   1792 use UNIVERSAL::require;
  2         3287  
  2         22  
14 2     2   1112 use XML::Simple;
  0            
  0            
15              
16             ## XML::Simple
17             my $CONFIG = {
18             XMLin => {
19             KeepRoot => 1,
20             ContentKey => '$t',
21             KeyAttr => [],
22             ForceArray => 0,
23             ForceContent => 1,
24             },
25             XMLout => {
26             KeepRoot => 1,
27             ContentKey => '$t',
28             KeyAttr => [],
29             XMLDecl => '',
30             NoSort => 1,
31             }
32             };
33              
34             use vars qw( $ERROR );
35              
36             sub error {
37             my $msg = $_[1] || '';
38             $msg .= "\n" unless $msg =~ /\n$/;
39             if (ref($_[0])) {
40             $_[0]->{_errstr} = $msg;
41             } else {
42             $ERROR = $msg;
43             }
44             return;
45             }
46              
47             sub errstr { ref($_[0]) ? $_[0]->{_errstr} : $ERROR }
48              
49             sub new {
50             my $class = shift;
51             my ($type, $stream);
52             if (@_ > 1) {
53             ($type, $stream) = @_;
54             if ($type eq 'file') {
55             $stream = read_file $stream;
56             $type = get_type_as_dwim($stream);
57             }
58             }
59             else {
60             warn 'DWIM-style constructor is DEPRECATED';
61             ($stream) = @_;
62             $stream = read_file $stream if $stream !~ /[\r\n]/ && -f $stream;
63             $type = get_type_as_dwim($stream);
64             }
65             return __PACKAGE__->error("Bad type: $type")
66             unless $type eq 'xml' || $type eq 'json' || $type eq 'hash' || $type eq 'atom';
67             return __PACKAGE__->error("Bad stream: $type => $stream")
68             if ($type eq 'xml' && $stream !~ /^
69             || ($type eq 'json' && $stream !~ /^\{/)
70             || ($type eq 'hash' && !UNIVERSAL::isa($stream, 'HASH'))
71             || ($type eq 'atom' && !UNIVERSAL::isa($stream, 'XML::Atom::Base'));
72             bless { $type => $stream }, $class;
73             }
74              
75             sub get_type_as_dwim {
76             my ($stream) = @_;
77             return UNIVERSAL::isa($stream, 'XML::Atom::Base') ? 'atom'
78             : UNIVERSAL::isa($stream, 'HASH') ? 'hash'
79             : $stream =~ /^\{/ ? 'json'
80             : $stream =~ /^
81             : __PACKAGE__->error("Bad stream: $stream");
82             }
83              
84             sub gdata :Export { __PACKAGE__->new(@_) }
85              
86             sub as_xml {
87             my $self = shift;
88             if ( $self->{xml} ) {
89             return $self->{xml};
90             }
91             elsif ( $self->{atom} ) {
92             return $self->{xml} = atom_to_xml( $self->{atom} );
93             }
94             elsif ( $self->{hash} ) {
95             return $self->{xml} = hash_to_xml( $self->{hash} );
96             }
97             elsif ( $self->{json} ) {
98             $self->{hash} = json_to_hash( $self->{json} );
99             return $self->{xml} = hash_to_xml( $self->{hash} );
100             }
101             }
102              
103             sub as_atom {
104             my $self = shift;
105             if ( $self->{atom} ) {
106             return $self->{atom};
107             }
108             elsif ( $self->{xml} ) {
109             return $self->{atom} = xml_to_atom( $self->{xml} );
110             }
111             elsif ( $self->{hash} ) {
112             $self->{xml} = hash_to_xml( $self->{hash} );
113             return $self->{atom} = xml_to_atom( $self->{xml} );
114             }
115             elsif ( $self->{json} ) {
116             $self->{hash} = json_to_hash( $self->{json} );
117             $self->{xml} = hash_to_xml( $self->{hash} );
118             return $self->{atom} = xml_to_atom( $self->{xml} );
119             }
120             }
121              
122             sub as_hash {
123             my $self = shift;
124             if ( $self->{hash} ) {
125             return $self->{hash};
126             }
127             elsif ( $self->{json} ) {
128             return $self->{hash} = json_to_hash( $self->{json} );
129             }
130             elsif ( $self->{xml} ) {
131             return $self->{hash} = xml_to_hash( $self->{xml} );
132             }
133             elsif ( $self->{atom} ) {
134             $self->{xml} = atom_to_xml( $self->{atom} );
135             return $self->{hash} = xml_to_hash( $self->{xml} );
136             }
137             }
138              
139             sub as_json {
140             my $self = shift;
141             if ( $self->{json} ) {
142             return $self->{json};
143             }
144             elsif ( $self->{hash} ) {
145             return $self->{json} = hash_to_json( $self->{hash} );
146             }
147             elsif ( $self->{xml} ) {
148             $self->{hash} = xml_to_hash( $self->{xml} );
149             return $self->{json} = hash_to_json( $self->{hash} );
150             }
151             elsif ( $self->{atom} ) {
152             $self->{xml} = atom_to_xml( $self->{atom} );
153             $self->{hash} = xml_to_hash( $self->{xml} );
154             return $self->{json} = hash_to_json( $self->{hash} );
155             }
156             }
157              
158             sub xml_to_atom :Export {
159             my ($xml) = shift;
160             my ($root) = $xml =~ /<\?xml[^>]+?\?>\s*<(?:\w+:)?(\w+)/ms;
161             my $module = 'XML::Atom::' . ucfirst($root);
162             "$module"->require or return __PACKAGE__->error($@);
163             return $module->new(\$xml);
164             }
165              
166             sub xml_to_hash :Export { fix_ns( XMLin( $_[0], %{ $CONFIG->{XMLin} } ) ) }
167              
168             sub xml_to_json :Export { hash_to_json( xml_to_hash(@_) ) }
169              
170             sub atom_to_xml :Export { $_[0]->as_xml }
171              
172             sub atom_to_hash :Export { xml_to_hash( atom_to_xml(@_) ) }
173              
174             sub atom_to_json :Export { xml_to_json( atom_to_xml(@_) ) }
175              
176             sub hash_to_xml :Export { XMLout( fix_ns2(dclone $_[0]), %{ $CONFIG->{XMLout} } ) }
177              
178             sub hash_to_atom :Export { xml_to_atom( hash_to_xml(@_) ) }
179              
180             sub hash_to_json :Export { JSON::Any->objToJson( $_[0] ) }
181              
182             sub json_to_xml :Export { hash_to_xml( json_to_hash(@_) ) }
183              
184             sub json_to_atom :Export { hash_to_atom( json_to_hash(@_) ) }
185              
186             sub json_to_hash :Export { JSON::Any->jsonToObj( $_[0] ) }
187              
188             sub as_hashref {
189             warn 'as_hashref is DEPRECATED and renamed to as_hash';
190             $_[0]->as_hash;
191             }
192              
193             sub xml_to_hashref :Export {
194             warn 'xml_to_hashref is DEPRECATED and renamed to xml_to_hash';
195             xml_to_hash(@_);
196             }
197              
198             sub atom_to_hashref :Export {
199             warn 'xml_to_hashref is DEPRECATED and renamed to atom_to_hash';
200             atom_to_hash(@_);
201             }
202              
203             sub json_to_hashref :Export {
204             warn 'xml_to_hashref is DEPRECATED and renamed to json_to_hash';
205             json_to_hash(@_);
206             }
207              
208             sub fix_ns {
209             my ($h) = shift;
210             for my $k (keys %$h) {
211             if (UNIVERSAL::isa($h->{$k}, 'HASH')) {
212             $h->{$k} = fix_ns($h->{$k});
213             }
214             elsif (UNIVERSAL::isa($h->{$k}, 'ARRAY')) {
215             $h->{$k} = [ map fix_ns($_), @{ $h->{$k} } ];
216             }
217             if ($k =~ /(.+):(.+)/) {
218             $h->{"$1\$$2"} = $h->{$k};
219             delete $h->{$k};
220             }
221             }
222             return $h;
223             }
224              
225             sub fix_ns2 {
226             my ($h) = shift;
227             for my $k (keys %$h) {
228             if (UNIVERSAL::isa($h->{$k}, 'HASH')) {
229             $h->{$k} = fix_ns2($h->{$k});
230             }
231             elsif (UNIVERSAL::isa($h->{$k}, 'ARRAY')) {
232             $h->{$k} = [ map fix_ns2($_), @{ $h->{$k} } ];
233             }
234             if ($k =~ /(.+)\$(.+)/) {
235             $h->{"$1:$2"} = $h->{$k};
236             delete $h->{$k};
237             }
238             }
239             return $h;
240             }
241              
242             1; # Magic true value required at end of module
243             __END__