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