File Coverage

blib/lib/Text/ZPL/Stream.pm
Criterion Covered Total %
statement 56 57 98.2
branch 16 18 88.8
condition 5 5 100.0
subroutine 13 13 100.0
pod 5 5 100.0
total 95 98 96.9


line stmt bran cond sub pod time code
1             package Text::ZPL::Stream;
2             $Text::ZPL::Stream::VERSION = '0.003001';
3 1     1   13536 use strict; use warnings FATAL => 'all';
  1     1   1  
  1         24  
  1         4  
  1         1  
  1         24  
4 1     1   3 use Carp;
  1         1  
  1         59  
5              
6 1     1   325 use Text::ZPL ();
  1         2  
  1         664  
7              
8              
9             sub BUF_MAX () { 0 }
10             sub BUF () { 1 }
11             sub MAYBE_EXTRA_EOL () { 2 }
12             sub ROOT () { 3 }
13             sub CURRENT () { 4 }
14             sub LEVEL () { 5 }
15             sub TREE () { 6 }
16              
17              
18             sub new {
19             # max_buffer_size =>
20             # string =>
21 6     6 1 4901 my ($class, %param) = @_;
22 6         10 my $root = +{};
23             bless [
24 6   100     41 ($param{max_buffer_size} || 0), # BUF_MAX
25             '', # BUF
26             0, # MAYBE_EXTRA_EOL
27             $root, # ROOT
28             $root, # CURRENT
29             0, # LEVEL
30             [], # TREE
31             ], $class
32             }
33              
34             sub max_buffer_size {
35 1146 50   1146 1 2165 defined $_[0]->[BUF_MAX] ?
36             $_[0]->[BUF_MAX] : ( $_[0]->[BUF_MAX] = 0 )
37             }
38              
39              
40             sub _maybe_extra_eol {
41 1196     1196   1415 $_[0]->[MAYBE_EXTRA_EOL]
42             }
43              
44             sub _maybe_extra_eol_off {
45 2     2   3 $_[0]->[MAYBE_EXTRA_EOL] = 0
46             }
47              
48             sub _maybe_extra_eol_on {
49 2     2   3 $_[0]->[MAYBE_EXTRA_EOL] = 1
50             }
51              
52              
53             sub _parse_current_buffer {
54 68     68   55 my ($self) = @_;
55 68         65 my $line = $self->[BUF];
56              
57 68 100       103 unless ( Text::ZPL::_decode_prepare_line($line) ) {
58             # skippable:
59 12         12 $self->[BUF] = '';
60             return
61 12         8 }
62              
63             Text::ZPL::_decode_handle_level(
64 56         117 0,
65             $line,
66             $self->[ROOT],
67             $self->[CURRENT],
68             $self->[LEVEL],
69             $self->[TREE],
70             );
71            
72 55 100       92 if ( (my $sep_pos = index($line, '=')) > 0 ) {
73 38         59 my ($k, $v) = Text::ZPL::_decode_parse_kv(
74             0, $line, $self->[LEVEL], $sep_pos
75             );
76 38         62 Text::ZPL::_decode_add_kv(
77             0, $self->[CURRENT], $k, $v
78             );
79              
80 38         27 $self->[BUF] = '';
81             return
82 38         42 }
83              
84 17         17 my $re = $Text::ZPL::ValidName;
85 17 50       141 if (my ($subsect) = $line =~ /^(?:\s+)?($re)(?:\s+?#.*)?$/) {
86 17         36 Text::ZPL::_decode_add_subsection(
87             0, $self->[CURRENT], $subsect, $self->[TREE]
88             );
89              
90 17         16 $self->[BUF] = '';
91             return
92 17         19 }
93              
94 0         0 confess "Parse failed in ZPL stream; bad input '$line'"
95             }
96              
97              
98 5     5 1 27 sub get { shift->[ROOT] }
99              
100 1     1 1 6 sub get_buffer { shift->[BUF] }
101              
102              
103             sub push {
104 291     291 1 726 my $self = shift;
105 291         469 my @chrs = split '', join '', @_;
106              
107 291         196 my $handled = 0;
108              
109 291         228 CHAR: for my $chr (@chrs) {
110 1198 100       1312 if ($chr eq "\015") {
111             # got \r, maybe an unneeded \n coming up, _maybe_extra_eol_on
112 2         4 $self->_maybe_extra_eol_on;
113 2         2 $self->_parse_current_buffer;
114 2         2 ++$handled;
115             next CHAR
116 2         3 }
117 1196 100       1234 if ($chr eq "\012") {
118 67 100       65 if ($self->_maybe_extra_eol) {
119 1         3 $self->_maybe_extra_eol_off;
120             } else {
121 66         62 $self->_parse_current_buffer;
122 65         54 ++$handled;
123             }
124             next CHAR
125 66         74 }
126              
127 1129 100       953 $self->_maybe_extra_eol_off if $self->_maybe_extra_eol;
128              
129 1129 100 100     1016 confess "Exceeded maximum buffer size for ZPL stream"
130             if $self->max_buffer_size
131             and length($self->[BUF]) >= $self->max_buffer_size;
132              
133 1128         978 $self->[BUF] .= $chr
134             }
135              
136             $handled
137 289         360 }
138              
139              
140             1;
141              
142             =pod
143              
144             =for Pod::Coverage BUF(_MAX)? MAYBE_EXTRA_EOL ROOT CURRENT LEVEL TREE
145              
146             =head1 NAME
147              
148             Text::ZPL::Stream - Streaming ZPL decoder
149              
150             =head1 SYNOPSIS
151              
152             use Text::ZPL::Stream;
153              
154             my $stream = Text::ZPL::Stream->new;
155              
156             if ( $stream->push($zpl_chrs) ) {
157             # Parsed at least one complete line:
158             my $ref = $stream->get;
159             # ...
160             }
161              
162             # Or in a loop:
163             while ( defined(my $zpl_chrs = magically_get_some_zpl) ) {
164             $stream->push($zpl_chrs);
165             }
166             my $ref = $stream->get;
167             # ...
168              
169             =head1 DESCRIPTION
170              
171             A streaming decoder for C files using L.
172              
173             See the L documentation for more on C and parsing-related
174             details.
175              
176             =head2 new
177              
178             my $stream = Text::ZPL::Stream->new(
179             # Optional:
180             max_buffer_size => 512,
181             );
182              
183             Constructs an object representing a new C stream.
184              
185             Accepts the following options:
186              
187             =over
188              
189             =item max_buffer_size
190              
191             The maximum line length allowed in buffers before an exception is thrown.
192              
193             Defaults to 0 (unlimited).
194              
195             =back
196              
197             =head2 push
198              
199             $stream->push(@chars);
200             $stream->push($string);
201              
202             Takes characters (individually or as strings) and collects until an
203             end-of-line marker (C<\r>, C<\n>, or C<\r\n>) is encountered, at which point a
204             parse is called and the reference returned by L is altered
205             appropriately.
206              
207             An exception is thrown if parsing fails, or if L is reached
208             -- if you're unsure of your incoming data, you may want to wrap C calls
209             with L or similar.
210              
211             Returns the number of complete lines parsed, which can be useful as an
212             indicator that L ought be called:
213              
214             if ( $stream->push($zpl) ) {
215             # Parsed at least one complete line:
216             my $ref = $stream->get;
217             ...
218             }
219              
220             =head2 get
221              
222             my $ref = $stream->get;
223              
224             Returns the C reference to the decoded structure.
225              
226             B<< This is the actual reference in use by the decoder, not a copy! >>
227             Altering the structure of the C may have unintended consequences, in
228             which case you may want to make use of L to create a safe
229             copy.
230              
231             =head2 get_buffer
232              
233             Returns a string containing the current character buffer (that is, any
234             incomplete line).
235              
236             =head1 AUTHOR
237              
238             Jon Portnoy
239              
240             =cut