File Coverage

blib/lib/Catmandu/Importer/JSON.pm
Criterion Covered Total %
statement 15 15 100.0
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 21 21 100.0


line stmt bran cond sub pod time code
1              
2             use Catmandu::Sane;
3 5     5   87348  
  5         11  
  5         34  
4             our $VERSION = '1.2019';
5              
6             use Cpanel::JSON::XS ();
7 5     5   34 use Moo;
  5         8  
  5         106  
8 5     5   113 use namespace::clean;
  5         12  
  5         26  
9 5     5   1660  
  5         17  
  5         39  
10             with 'Catmandu::Importer';
11              
12             has line_delimited => (is => 'ro', default => sub {0});
13             has byte_buffer_size => (is => 'ro', default => sub {256});
14             has json => (is => 'lazy');
15              
16             my ($self) = @_;
17             Cpanel::JSON::XS->new->utf8($self->encoding eq ':raw');
18 8     8   69 }
19 8         90  
20              
21             my ($self) = @_;
22 8     8   128  
23             if ($self->line_delimited) {
24             return sub {
25             state $json = $self->json;
26             state $fh = $self->fh;
27             if (defined(my $line = <$fh>)) {
28             return $json->decode($line);
29             }
30             return;
31             };
32             }
33              
34             # switch to incremental parser
35             sub {
36             state $json = $self->json;
37             state $fh = $self->fh;
38             state $buf_size = $self->byte_buffer_size;
39              
40             for (;;) {
41             my $res = sysread($fh, my $buf, $buf_size);
42             $res // Catmandu::Error->throw($!);
43             $json->incr_parse($buf); # void context, so no parsing
44             $json->incr_text =~ s/^[^{]+//;
45             return if $json->incr_text =~ /^$/;
46             last if $json->incr_text =~ /^{/;
47             }
48              
49             # read data until we get a single json object
50             for (;;) {
51             if (my $data = $json->incr_parse) {
52             return $data;
53             }
54              
55             my $res = sysread($fh, my $buf, $buf_size);
56             $res // Catmandu::Error->throw($!);
57             $res
58             || Catmandu::Error->throw(
59             "JSON syntax error: unexpected end of object");
60             $json->incr_parse($buf);
61             }
62              
63             return;
64              
65             };
66             }
67              
68             1;
69              
70              
71             =pod
72              
73             =head1 NAME
74              
75             Catmandu::Importer::JSON - Package that imports JSON data
76              
77             =head1 SYNOPSIS
78              
79             # From the command line
80            
81             $ catmandu convert JSON to YAML < data.json
82              
83             # or for faster newline delimited input
84              
85             $ catmandu convert JSON --line_delimited 1 to YAML < data.json
86              
87             # In a Perl script
88              
89             use Catmandu;
90              
91             my $importer = Catmandu->importer('JSON', file => "/foo/bar.json");
92              
93             my $n = $importer->each(sub {
94             my $hashref = $_[0];
95             # ...
96             });
97              
98             =head1 DESCRIPTION
99              
100             This package imports JSON data. The parser is quite liberal in the input
101             it accepts. You can use the C<line_delimited> option to parse "newline
102             delimited JSON" faster:
103              
104             { "recordno": 1, "name": "Alpha" }
105             { "recordno": 2, "name": "Beta" }
106             { "recordno": 3, "name": "Gamma" }
107              
108             =head1 CONFIGURATION
109              
110             =over
111              
112             =item file
113              
114             Read input from a local file given by its path. Alternatively a scalar
115             reference can be passed to read from a string.
116              
117             =item fh
118              
119             Read input from an L<IO::Handle>. If not specified, L<Catmandu::Util::io> is used to
120             create the input stream from the C<file> argument or by using STDIN.
121              
122             =item encoding
123              
124             Binmode of the input stream C<fh>. Set to C<:utf8> by default.
125              
126             =item fix
127              
128             An ARRAY of one or more fixes or file scripts to be applied to imported items.
129              
130             =item line_delimited
131              
132             Read line-delimited JSON line-by-line with a non-incremental parser.
133              
134             =item byte_buffer_size
135              
136             Number of bytes that is read by each iteration of the incremental parser.
137             Ignored if C<line_delinmited> is C<1>. Default is C<256>.
138              
139             =back
140              
141             =head1 METHODS
142              
143             Every L<Catmandu::Importer> is a L<Catmandu::Iterable> all its methods are
144             inherited. The methods are not idempotent: JSON streams can only be read once.
145              
146             =head1 SEE ALSO
147              
148             L<Catmandu::Exporter::JSON>
149              
150             =cut