line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
package JSON::Streaming::Writer; |
3
|
|
|
|
|
|
|
|
4
|
3
|
|
|
3
|
|
27523
|
use strict; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
101
|
|
5
|
3
|
|
|
3
|
|
15
|
use warnings; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
68
|
|
6
|
3
|
|
|
3
|
|
2555
|
use IO::File; |
|
3
|
|
|
|
|
36631
|
|
|
3
|
|
|
|
|
2664
|
|
7
|
3
|
|
|
3
|
|
26
|
use Carp; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
161
|
|
8
|
3
|
|
|
3
|
|
15
|
use B; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
107
|
|
9
|
|
|
|
|
|
|
|
10
|
3
|
|
|
3
|
|
14
|
use constant ROOT_STATE => {}; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
7437
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = '0.03'; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub for_stream { |
15
|
34
|
|
|
34
|
0
|
50
|
my ($class, $fh) = @_; |
16
|
|
|
|
|
|
|
|
17
|
34
|
|
|
|
|
83
|
my $self = bless {}, $class; |
18
|
|
|
|
|
|
|
|
19
|
34
|
|
|
|
|
79
|
$self->{fh} = $fh; |
20
|
34
|
|
|
|
|
54
|
$self->{state} = ROOT_STATE; |
21
|
34
|
|
|
|
|
59
|
$self->{state_stack} = []; |
22
|
34
|
|
|
|
|
67
|
$self->{used} = 0; |
23
|
34
|
|
|
|
|
49
|
$self->{pretty} = 0; |
24
|
34
|
|
|
|
|
47
|
$self->{indent_level} = 0; |
25
|
|
|
|
|
|
|
|
26
|
34
|
|
|
|
|
83
|
return $self; |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub for_file { |
30
|
0
|
|
|
0
|
0
|
0
|
my ($class, $filename) = @_; |
31
|
|
|
|
|
|
|
|
32
|
0
|
|
|
|
|
0
|
my $fh = IO::File->new($filename, O_WRONLY); |
33
|
0
|
|
|
|
|
0
|
return $class->for_stream($fh); |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
sub for_stdout { |
37
|
0
|
|
|
0
|
0
|
0
|
my ($class, $filename) = @_; |
38
|
|
|
|
|
|
|
|
39
|
0
|
|
|
|
|
0
|
return $class->for_stream(\*STDOUT); |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub pretty_output { |
43
|
102
|
|
|
102
|
0
|
112
|
my $self = shift; |
44
|
|
|
|
|
|
|
|
45
|
102
|
50
|
|
|
|
200
|
if (@_) { |
46
|
0
|
0
|
|
|
|
0
|
$self->{pretty} = $_[0] ? 1 : 0; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
102
|
|
|
|
|
308
|
$self->{pretty}; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub start_object { |
53
|
10
|
|
|
10
|
1
|
34
|
my ($self) = @_; |
54
|
|
|
|
|
|
|
|
55
|
10
|
50
|
|
|
|
24
|
Carp::croak("Can't start_object here") unless $self->_can_start_value; |
56
|
|
|
|
|
|
|
|
57
|
10
|
|
|
|
|
26
|
$self->_make_separator(); |
58
|
10
|
|
|
|
|
23
|
$self->_print("{"); |
59
|
10
|
|
|
|
|
29
|
my $state = $self->_push_state(); |
60
|
9
|
|
|
|
|
25
|
$state->{in_object} = 1; |
61
|
9
|
|
|
|
|
22
|
$self->_indent(); |
62
|
9
|
|
|
|
|
18
|
return undef; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub end_object { |
66
|
7
|
|
|
7
|
1
|
21
|
my ($self) = @_; |
67
|
|
|
|
|
|
|
|
68
|
7
|
50
|
|
|
|
17
|
Carp::croak("Can't end_object here: not in an object") unless $self->_in_object; |
69
|
7
|
|
|
|
|
18
|
$self->_outdent(); |
70
|
7
|
|
|
|
|
16
|
$self->_make_end_block(); |
71
|
7
|
|
|
|
|
18
|
$self->_pop_state(); |
72
|
7
|
|
|
|
|
66
|
$self->_print("}"); |
73
|
7
|
50
|
33
|
|
|
19
|
$self->_print("\n") if $self->_state == ROOT_STATE && $self->pretty_output; |
74
|
|
|
|
|
|
|
|
75
|
7
|
50
|
|
|
|
18
|
$self->_state->{made_value} = 1 unless $self->_state == ROOT_STATE; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub start_property { |
79
|
9
|
|
|
9
|
1
|
23
|
my ($self, $name) = @_; |
80
|
|
|
|
|
|
|
|
81
|
9
|
100
|
|
|
|
23
|
Carp::croak("Can't start_property here") unless $self->_can_start_property; |
82
|
|
|
|
|
|
|
|
83
|
5
|
|
|
|
|
13
|
$self->_make_separator(); |
84
|
5
|
|
|
|
|
13
|
my $state = $self->_push_state(); |
85
|
5
|
|
|
|
|
12
|
$state->{in_property} = 1; |
86
|
5
|
|
|
|
|
13
|
$self->_print($self->_json_string($name), ":"); |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub end_property { |
90
|
5
|
|
|
5
|
1
|
14
|
my ($self) = @_; |
91
|
|
|
|
|
|
|
|
92
|
5
|
50
|
|
|
|
13
|
Carp::croak("Can't end_property here: not in a property") unless $self->_in_property; |
93
|
5
|
50
|
|
|
|
10
|
Carp::croak("Can't end_property here: haven't generated a value") unless $self->_made_value; |
94
|
|
|
|
|
|
|
|
95
|
5
|
|
|
|
|
11
|
$self->_pop_state(); |
96
|
5
|
|
|
|
|
17
|
$self->_state->{made_value} = 1; |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# end_property requires no output |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub start_array { |
102
|
17
|
|
|
17
|
1
|
48
|
my ($self) = @_; |
103
|
|
|
|
|
|
|
|
104
|
17
|
50
|
|
|
|
38
|
Carp::croak("Can't start_array here") unless $self->_can_start_value; |
105
|
|
|
|
|
|
|
|
106
|
17
|
|
|
|
|
45
|
$self->_make_separator(); |
107
|
17
|
|
|
|
|
41
|
$self->_print("["); |
108
|
17
|
|
|
|
|
45
|
my $state = $self->_push_state(); |
109
|
17
|
|
|
|
|
39
|
$self->_indent(); |
110
|
17
|
|
|
|
|
25
|
$state->{in_array} = 1; |
111
|
17
|
|
|
|
|
26
|
return undef; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub end_array { |
115
|
15
|
|
|
15
|
1
|
37
|
my ($self) = @_; |
116
|
|
|
|
|
|
|
|
117
|
15
|
50
|
|
|
|
33
|
Carp::croak("Can't end_array here: not in an array") unless $self->_in_array; |
118
|
15
|
|
|
|
|
40
|
$self->_outdent(); |
119
|
15
|
|
|
|
|
25
|
$self->_make_end_block(); |
120
|
15
|
|
|
|
|
32
|
$self->_pop_state(); |
121
|
15
|
|
|
|
|
42
|
$self->_print("]"); |
122
|
15
|
50
|
33
|
|
|
32
|
$self->_print("\n") if $self->_state == ROOT_STATE && $self->pretty_output; |
123
|
|
|
|
|
|
|
|
124
|
15
|
50
|
|
|
|
33
|
$self->_state->{made_value} = 1 unless $self->_state == ROOT_STATE; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub add_string { |
128
|
9
|
|
|
9
|
1
|
23
|
my ($self, $value) = @_; |
129
|
|
|
|
|
|
|
|
130
|
9
|
100
|
|
|
|
22
|
Carp::croak("Can't add_string here") unless $self->_can_start_simple_value; |
131
|
|
|
|
|
|
|
|
132
|
5
|
|
|
|
|
13
|
$self->_make_separator(); |
133
|
5
|
|
|
|
|
15
|
$self->_print($self->_json_string($value)); |
134
|
5
|
|
|
|
|
13
|
$self->_state->{made_value} = 1; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub add_number { |
138
|
7
|
|
|
7
|
1
|
19
|
my ($self, $value) = @_; |
139
|
|
|
|
|
|
|
|
140
|
7
|
100
|
|
|
|
14
|
Carp::croak("Can't add_number here") unless $self->_can_start_simple_value; |
141
|
|
|
|
|
|
|
|
142
|
5
|
|
|
|
|
15
|
$self->_make_separator(); |
143
|
5
|
|
|
|
|
66
|
$self->_print($value+0); |
144
|
5
|
|
|
|
|
14
|
$self->_state->{made_value} = 1; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub add_boolean { |
148
|
7
|
|
|
7
|
1
|
17
|
my ($self, $value) = @_; |
149
|
|
|
|
|
|
|
|
150
|
7
|
100
|
|
|
|
16
|
Carp::croak("Can't add_boolean here") unless $self->_can_start_simple_value; |
151
|
|
|
|
|
|
|
|
152
|
6
|
|
|
|
|
19
|
$self->_make_separator(); |
153
|
6
|
100
|
|
|
|
21
|
$self->_print($value ? 'true' : 'false'); |
154
|
6
|
|
|
|
|
15
|
$self->_state->{made_value} = 1; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub add_null { |
158
|
11
|
|
|
11
|
1
|
26
|
my ($self) = @_; |
159
|
|
|
|
|
|
|
|
160
|
11
|
100
|
|
|
|
27
|
Carp::croak("Can't add_null here") unless $self->_can_start_simple_value; |
161
|
|
|
|
|
|
|
|
162
|
10
|
|
|
|
|
27
|
$self->_make_separator(); |
163
|
10
|
|
|
|
|
21
|
$self->_print('null'); |
164
|
10
|
|
|
|
|
24
|
$self->_state->{made_value} = 1; |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub add_value { |
168
|
32
|
|
|
32
|
1
|
113
|
my ($self, $value) = @_; |
169
|
|
|
|
|
|
|
|
170
|
32
|
|
|
|
|
47
|
my $type = ref($value); |
171
|
|
|
|
|
|
|
|
172
|
32
|
100
|
|
|
|
114
|
if (! defined($value)) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
173
|
6
|
|
|
|
|
14
|
$self->add_null(); |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
elsif (! $type) { |
176
|
11
|
|
|
|
|
63
|
my $b_obj = B::svref_2object(\$value); |
177
|
11
|
|
|
|
|
53
|
my $flags = $b_obj->FLAGS; |
178
|
|
|
|
|
|
|
|
179
|
11
|
100
|
66
|
|
|
131
|
if (($flags & B::SVf_IOK or $flags & B::SVp_IOK or $flags & B::SVf_NOK or $flags & B::SVp_NOK) and !($flags & B::SVf_POK )) { |
|
|
|
66
|
|
|
|
|
180
|
5
|
|
|
|
|
13
|
$self->add_number($value); |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
else { |
183
|
6
|
|
|
|
|
17
|
$self->add_string($value); |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
elsif ($type eq 'ARRAY') { |
187
|
8
|
|
|
|
|
18
|
$self->start_array(); |
188
|
8
|
|
|
|
|
18
|
foreach my $item (@$value) { |
189
|
11
|
|
|
|
|
26
|
$self->add_value($item); |
190
|
|
|
|
|
|
|
} |
191
|
8
|
|
|
|
|
21
|
$self->end_array(); |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
elsif ($type eq 'HASH') { |
194
|
2
|
|
|
|
|
6
|
$self->start_object(); |
195
|
2
|
|
|
|
|
10
|
foreach my $k (sort keys %$value) { |
196
|
1
|
|
|
|
|
6
|
$self->add_property($k, $value->{$k}); |
197
|
|
|
|
|
|
|
} |
198
|
2
|
|
|
|
|
11
|
$self->end_object(); |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
elsif ($type eq 'SCALAR') { |
201
|
5
|
100
|
|
|
|
20
|
if ($$value eq '1') { |
|
|
50
|
|
|
|
|
|
202
|
3
|
|
|
|
|
13
|
$self->add_boolean(1); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
elsif ($$value eq '0') { |
205
|
2
|
|
|
|
|
5
|
$self->add_boolean(0); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
else { |
208
|
0
|
|
|
|
|
0
|
Carp::croak("Don't know what to generate for $value"); |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
else { |
212
|
0
|
|
|
|
|
0
|
Carp::croak("Don't know what to generate for $value"); |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub add_property { |
217
|
5
|
|
|
5
|
1
|
21
|
my ($self, $key, $value) = @_; |
218
|
|
|
|
|
|
|
|
219
|
5
|
|
|
|
|
14
|
$self->start_property($key); |
220
|
3
|
|
|
|
|
10
|
$self->add_value($value); |
221
|
3
|
|
|
|
|
9
|
$self->end_property(); |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub intentionally_ending_early { |
225
|
5
|
|
|
5
|
0
|
25
|
my ($self) = @_; |
226
|
5
|
|
|
|
|
12
|
$self->{intentionally_ending_early} = 1; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
sub _print { |
230
|
89
|
|
|
89
|
|
168
|
my ($self, @data) = @_; |
231
|
|
|
|
|
|
|
|
232
|
89
|
|
|
|
|
385
|
$self->{fh}->print(join('', @data)); |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub _push_state { |
236
|
32
|
|
|
32
|
|
43
|
my ($self) = @_; |
237
|
|
|
|
|
|
|
|
238
|
32
|
100
|
100
|
|
|
61
|
Carp::croak("Can't add anything else: JSON output is complete") if $self->_state == ROOT_STATE && $self->{used}; |
239
|
|
|
|
|
|
|
|
240
|
31
|
|
|
|
|
86
|
$self->{used} = 1; |
241
|
|
|
|
|
|
|
|
242
|
31
|
|
|
|
|
32
|
push @{$self->{state_stack}}, $self->{state}; |
|
31
|
|
|
|
|
74
|
|
243
|
|
|
|
|
|
|
|
244
|
31
|
|
|
|
|
128
|
$self->{state} = { |
245
|
|
|
|
|
|
|
in_object => 0, |
246
|
|
|
|
|
|
|
in_array => 0, |
247
|
|
|
|
|
|
|
in_property => 0, |
248
|
|
|
|
|
|
|
made_value => 0, |
249
|
|
|
|
|
|
|
}; |
250
|
|
|
|
|
|
|
|
251
|
31
|
|
|
|
|
67
|
return $self->{state}; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub _pop_state { |
255
|
27
|
|
|
27
|
|
36
|
my ($self) = @_; |
256
|
|
|
|
|
|
|
|
257
|
27
|
|
|
|
|
25
|
my $state = pop @{$self->{state_stack}}; |
|
27
|
|
|
|
|
54
|
|
258
|
27
|
|
|
|
|
52
|
return $self->{state} = $state; |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
sub _state { |
262
|
399
|
|
|
399
|
|
462
|
my ($self) = @_; |
263
|
|
|
|
|
|
|
|
264
|
399
|
|
|
|
|
3745
|
return $self->{state}; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
sub _in_object { |
268
|
77
|
100
|
|
77
|
|
144
|
return $_[0]->_state->{in_object} ? 1 : 0; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub _in_array { |
272
|
15
|
50
|
|
15
|
|
33
|
return $_[0]->_state->{in_array} ? 1 : 0; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub _in_property { |
276
|
66
|
100
|
|
66
|
|
115
|
return $_[0]->_state->{in_property} ? 1 : 0; |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
sub _made_value { |
280
|
68
|
100
|
|
68
|
|
108
|
return $_[0]->_state->{made_value} ? 1 : 0; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
sub _can_start_value { |
284
|
|
|
|
|
|
|
|
285
|
61
|
50
|
66
|
61
|
|
130
|
return 0 if $_[0]->_in_property && $_[0]->_made_value; |
286
|
|
|
|
|
|
|
|
287
|
61
|
100
|
|
|
|
143
|
return $_[0]->_in_object ? 0 : 1; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
sub _can_start_simple_value { |
291
|
|
|
|
|
|
|
# Can't generate simple values in the root state |
292
|
34
|
|
100
|
34
|
|
71
|
return $_[0]->_can_start_value && $_[0]->_state != ROOT_STATE; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
sub _can_start_property { |
296
|
9
|
100
|
|
9
|
|
21
|
return $_[0]->_in_object ? 1 : 0; |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
sub _make_separator { |
300
|
58
|
100
|
|
58
|
|
114
|
$_[0]->_print(",") if $_[0]->_made_value; |
301
|
58
|
50
|
|
|
|
130
|
if ($_[0]->pretty_output) { |
302
|
0
|
0
|
|
|
|
0
|
if ($_[0]->_in_property) { |
303
|
0
|
|
|
|
|
0
|
$_[0]->_print(" "); |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
else { |
306
|
0
|
|
|
|
|
0
|
$_[0]->_print("\n"); |
307
|
0
|
|
|
|
|
0
|
$_[0]->_make_indent(); |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub _make_end_block { |
313
|
22
|
50
|
|
22
|
|
49
|
return unless $_[0]->pretty_output; |
314
|
|
|
|
|
|
|
|
315
|
0
|
0
|
|
|
|
0
|
if ($_[0]->_made_value) { |
316
|
0
|
|
|
|
|
0
|
$_[0]->_print("\n"); |
317
|
0
|
|
|
|
|
0
|
$_[0]->_make_indent(); |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
sub _make_indent { |
322
|
0
|
|
|
0
|
|
0
|
$_[0]->_print(" " x $_[0]->{indent_level}); |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub _indent { |
326
|
26
|
|
|
26
|
|
49
|
$_[0]->{indent_level}++; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub _outdent { |
330
|
22
|
|
|
22
|
|
43
|
$_[0]->{indent_level}--; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
my %esc = ( |
334
|
|
|
|
|
|
|
"\n" => '\n', |
335
|
|
|
|
|
|
|
"\r" => '\r', |
336
|
|
|
|
|
|
|
"\t" => '\t', |
337
|
|
|
|
|
|
|
"\f" => '\f', |
338
|
|
|
|
|
|
|
"\b" => '\b', |
339
|
|
|
|
|
|
|
"\"" => '\"', |
340
|
|
|
|
|
|
|
"\\" => '\\\\', |
341
|
|
|
|
|
|
|
"\'" => '\\\'', |
342
|
|
|
|
|
|
|
); |
343
|
|
|
|
|
|
|
sub _json_string { |
344
|
10
|
|
|
10
|
|
19
|
my ($class, $value) = @_; |
345
|
|
|
|
|
|
|
|
346
|
10
|
|
|
|
|
20
|
$value =~ s/([\x22\x5c\n\r\t\f\b])/$esc{$1}/eg; |
|
0
|
|
|
|
|
0
|
|
347
|
10
|
|
|
|
|
22
|
$value =~ s/\//\\\//g; |
348
|
10
|
|
|
|
|
14
|
$value =~ s/([\x00-\x08\x0b\x0e-\x1f])/'\\u00' . unpack('H2', $1)/eg; |
|
0
|
|
|
|
|
0
|
|
349
|
|
|
|
|
|
|
|
350
|
10
|
|
|
|
|
37
|
return '"'.$value.'"'; |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
sub DESTROY { |
354
|
34
|
|
|
34
|
|
10717
|
my ($self) = @_; |
355
|
|
|
|
|
|
|
|
356
|
34
|
50
|
66
|
|
|
79
|
if ($self->_state != ROOT_STATE && ! $self->{intentionally_ending_early}) { |
357
|
0
|
|
|
|
|
|
warn "JSON::Streaming::Writer object was destroyed with incomplete output"; |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
1; |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=head1 NAME |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
JSON::Streaming::Writer - Generate JSON output in a streaming manner |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=head1 SYNOPSIS |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
my $jsonw = JSON::Streaming::Writer->for_stream($fh) |
370
|
|
|
|
|
|
|
$jsonw->start_object(); |
371
|
|
|
|
|
|
|
$jsonw->add_simple_property("someName" => "someValue"); |
372
|
|
|
|
|
|
|
$jsonw->add_simple_property("someNumber" => 5); |
373
|
|
|
|
|
|
|
$jsonw->start_property("someObject"); |
374
|
|
|
|
|
|
|
$jsonw->start_object(); |
375
|
|
|
|
|
|
|
$jsonw->add_simple_property("someOtherName" => "someOtherValue"); |
376
|
|
|
|
|
|
|
$jsonw->add_simple_property("someOtherNumber" => 6); |
377
|
|
|
|
|
|
|
$jsonw->end_object(); |
378
|
|
|
|
|
|
|
$jsonw->end_property(); |
379
|
|
|
|
|
|
|
$jsonw->start_property("someArray"); |
380
|
|
|
|
|
|
|
$jsonw->start_array(); |
381
|
|
|
|
|
|
|
$jsonw->add_simple_item("anotherStringValue"); |
382
|
|
|
|
|
|
|
$jsonw->add_simple_item(10); |
383
|
|
|
|
|
|
|
$jsonw->start_object(); |
384
|
|
|
|
|
|
|
# No items; this object is empty |
385
|
|
|
|
|
|
|
$jsonw->end_object(); |
386
|
|
|
|
|
|
|
$jsonw->end_array(); |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
=head1 DESCRIPTION |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
Most JSON libraries work in terms of in-memory data structures. In Perl, |
391
|
|
|
|
|
|
|
JSON serializers often expect to be provided with a HASH or ARRAY ref |
392
|
|
|
|
|
|
|
containing all of the data you want to serialize. |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
This library allows you to generate syntactically-correct JSON without |
395
|
|
|
|
|
|
|
first assembling your complete data structure in memory. This allows |
396
|
|
|
|
|
|
|
large structures to be returned without requiring those |
397
|
|
|
|
|
|
|
structures to be memory-resident, and also allows parts of the output |
398
|
|
|
|
|
|
|
to be made available to a streaming-capable JSON parser while |
399
|
|
|
|
|
|
|
the rest of the output is being generated, which may improve |
400
|
|
|
|
|
|
|
performance of JSON-based network protocols. |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
=head1 RAW API |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
The raw API allows the caller precise control over the generated |
405
|
|
|
|
|
|
|
data structure by providing explicit methods for each fundamental JSON |
406
|
|
|
|
|
|
|
construct. |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
As a general rule, methods with names starting with C and C |
409
|
|
|
|
|
|
|
methods wrap a multi-step construct and must be used symmetrically, while |
410
|
|
|
|
|
|
|
methods with names starting with C stand alone and generate output |
411
|
|
|
|
|
|
|
in a single step. |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
The raw API methods are described below |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=head2 start_object, end_object |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
These methods delimit a JSON object. C can be called |
418
|
|
|
|
|
|
|
as the first method call on a writer object to produce a top-level |
419
|
|
|
|
|
|
|
object, or it can be called in any state where a value is expected |
420
|
|
|
|
|
|
|
to produce a nested object. |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
JSON objects contain properties, so only property-related methods |
423
|
|
|
|
|
|
|
may be used while in the context of an object. |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
=head2 start_array, end_array |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
These methods delimit a JSON array. C can be called |
428
|
|
|
|
|
|
|
as the first method call on a writer object to produce a top-level |
429
|
|
|
|
|
|
|
array, or it can be called in any state where a value is expected |
430
|
|
|
|
|
|
|
to produce a nested array. |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
JSON arrays contain properties, so only value-producing methods |
433
|
|
|
|
|
|
|
may be used while in the context of an array. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=head2 start_property($name), end_property |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
These methods delimit a property or member of a JSON object. |
438
|
|
|
|
|
|
|
C may be called only when in the context of an |
439
|
|
|
|
|
|
|
object. The C<$name> parameter, a string, gives the name that |
440
|
|
|
|
|
|
|
the generated property will have. |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
Only value-producing methods may be used while in the context |
443
|
|
|
|
|
|
|
of a property. |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
Since a property can contain only one value, only a single |
446
|
|
|
|
|
|
|
value-producing method may be called between a pair of |
447
|
|
|
|
|
|
|
C and C calls. |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head2 add_string($value) |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
Produces a JSON string with the given value. |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=head2 add_number($value) |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
Produces a JSON number whose value is Perl's numeric interpretation of the given value. |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=head2 add_boolean($value) |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
Produces a JSON boolean whose value is Perl's boolean interpretation of the given value. |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=head2 add_null |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
Produces a JSON C. |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=head1 DWIM API |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
The DWIM API allows you to provide normal Perl data structures and have the library |
468
|
|
|
|
|
|
|
figure out a sensible JSON representation for them. You can mix use of the raw |
469
|
|
|
|
|
|
|
and DWIM APIs to allow you to exercise fine control where required but use |
470
|
|
|
|
|
|
|
a simpler API for normal cases. |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=head2 add_value($value) |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
Produces a JSON value representing the given Perl value. This library can handle |
475
|
|
|
|
|
|
|
Perl strings, integers (i.e. scalars that have most recently been used as numbers), |
476
|
|
|
|
|
|
|
references to the values 0 and 1 representing booleans and C representing |
477
|
|
|
|
|
|
|
a JSON C. It can also accept ARRAY and HASH refs that contain such values |
478
|
|
|
|
|
|
|
and produce JSON array and object values recursively, much like a non-streaming |
479
|
|
|
|
|
|
|
JSON producer library would do. |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
This method is a wrapper around the corresponding raw API calls, so the error |
482
|
|
|
|
|
|
|
messages it generates will often refer to the underlying raw API. |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
=head2 add_property($name, $value) |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
Produces a property inside a JSON object whose value is derived from the provided |
487
|
|
|
|
|
|
|
value using the same mappings as used by C. This can only be used |
488
|
|
|
|
|
|
|
inside the context of an object, and is really just a wrapper around a C, |
489
|
|
|
|
|
|
|
C, C sequence for convenience. |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
=head1 OPTIONS |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=head2 Pretty Output |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
This library can optionally pretty-print the JSON string it produces. To enable this, |
496
|
|
|
|
|
|
|
call the C method with a true value as its first argument. |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
You can enable and disable pretty-printing during output, though if you do the |
499
|
|
|
|
|
|
|
results are likely to be sub-optimal as the additional whitespace may not be |
500
|
|
|
|
|
|
|
generated where you'd expect. In particular, where the whitespace is generated |
501
|
|
|
|
|
|
|
may change in future versions. |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=head1 INTERNALS |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
Internally this library maintains a simple state stack that allows |
506
|
|
|
|
|
|
|
it to remember where it is without needing to remember the data |
507
|
|
|
|
|
|
|
it has already generated. |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
The state stack means that it will use more memory for deeper |
510
|
|
|
|
|
|
|
data structures. |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
=head1 LICENSE |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
Copyright 2009 Martin Atkins . |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under |
517
|
|
|
|
|
|
|
the same terms as Perl itself. |