File Coverage

blib/lib/Data/Transform.pm
Criterion Covered Total %
statement 57 63 90.4
branch 17 18 94.4
condition 5 6 83.3
subroutine 13 17 76.4
pod 8 8 100.0
total 100 112 89.2


line stmt bran cond sub pod time code
1             # vim: ts=2 sw=2 expandtab
2             package Data::Transform;
3 8     8   23941 use strict;
  8         15  
  8         277  
4              
5 8     8   43 use vars qw($VERSION);
  8         13  
  8         462  
6             $VERSION = '0.06';
7              
8 8     8   45 use Carp qw(croak);
  8         19  
  8         477  
9 8     8   187 use Scalar::Util qw(blessed);
  8         20  
  8         653  
10 8     8   4911 use Data::Transform::Meta;
  8         20  
  8         5426  
11              
12             =head1 NAME
13              
14             Data::Transform - base class for protocol abstractions
15              
16             =head1 DESCRIPTION
17              
18             POE::Filter objects plug into the wheels and define how the data will
19             be serialized for writing and parsed after reading. POE::Wheel
20             objects are responsible for moving data, and POE::Filter objects
21             define how the data should look.
22              
23             POE::Filter objects are simple by design. They do not use POE
24             internally, so they are limited to serialization and parsing. This
25             may complicate implementation of certain protocols (like HTTP 1.x),
26             but it allows filters to be used in stand-alone programs.
27              
28             Stand-alone use is very important. It allows application developers
29             to create lightweight blocking libraries that may be used as simple
30             clients for POE servers. POE::Component::IKC::ClientLite is a notable
31             example. This lightweight, blocking event-passing client supports
32             thin clients for gridded POE applications. The canonical use case is
33             to inject events into an IKC application or grid from CGI interfaces,
34             which require lightweight resource use.
35              
36             POE filters and drivers pass data in array references. This is
37             slightly awkward, but it minimizes the amount of data that must be
38             copied on Perl's stack.
39              
40              
41             =head1 PUBLIC INTERFACE
42              
43             All Data::Transform classes must support the minimal interface,
44             defined here. Specific filters may implement and document additional
45             methods.
46              
47             =cut
48              
49             =head2 new PARAMETERS
50              
51             new() creates and initializes a new filter. Constructor parameters
52             vary from one Data::Transform subclass to the next, so please consult the
53             documentation for your desired filter.
54              
55             =cut
56              
57             sub new {
58 1     1 1 14 my $type = shift;
59 1         204 croak "$type is not meant to be used directly";
60             }
61              
62             =head2 get_one_start ARRAYREF
63              
64             get_one_start() accepts an array reference containing unprocessed
65             stream chunks. The chunks are added to the filter's internal buffer
66             for parsing by get_one().
67              
68             =cut
69              
70             sub get_one_start {
71 78     78 1 5171 my ($self, $stream) = @_;
72              
73 78         116 push (@{$self->[0]}, @$stream);
  78         279  
74             }
75              
76             =head2 get_one
77              
78             get_one() parses zero or one complete item from the filter's internal
79             buffer.
80              
81             get_one() is the lazy form of get(). It only parses only one item at
82             a time from the filter's buffer. This is vital for applications that
83             may switch filters in mid-stream, as it ensures that the right filter
84             is in use at any given time.
85              
86             =cut
87              
88             sub get_one {
89 230     230 1 24131 my $self = shift;
90              
91 230 100       622 if (my $val = $self->_handle_get_data) {
92 4         14 return [ $val ];
93             }
94 226 100       228 return [ ] unless (@{$self->[0]});
  226         626  
95              
96 164         205 while (defined (my $data = shift (@{$self->[0]}))) {
  199         551  
97 181 100 66     810 if (blessed $data and $data->isa('Data::Transform::Meta')) {
98 11         79 return [ $self->_handle_get_meta($data) ];
99             }
100 170         420 my $ret = $self->_handle_get_data($data);
101 170 100       805 if (defined $ret) {
102 135         425 return [ $ret ];
103             }
104             }
105 18         40 return [];
106             }
107              
108             =head2 get ARRAYREF
109              
110             get() is the greedy form of get_one(). It accepts an array reference
111             containing unprocessed stream chunks, and it adds that data to the
112             filter's internal buffer. It then parses as many full items as
113             possible from the buffer and returns them in another array reference.
114             Any unprocessed data remains in the filter's buffer for the next call.
115              
116             This should only be used if you don't care how long the processing takes.
117             Unless responsiveness doesn't matter for your application, you should
118             really be using get_one_start() and get_one().
119              
120             =cut
121              
122             sub get {
123 59     59 1 23780 my ($self, $stream) = @_;
124 59         74 my @return;
125              
126 59         157 $self->get_one_start($stream);
127 59         77 while (1) {
128 164         311 my $next = $self->get_one();
129 164 100       371 last unless @$next;
130 105         205 push @return, @$next;
131             }
132              
133 59         181 return \@return;
134             }
135              
136             =head2 put ARRAYREF
137              
138             put() serializes items into a stream of octets that may be written to
139             a file or sent across a socket. It accepts a reference to a list of
140             items, and it returns a reference to a list of marshalled stream
141             chunks. The number of output chunks is not necessarily related to the
142             number of input items.
143              
144             =cut
145              
146             sub put {
147 47     47 1 30314 my ($self, $packets) = @_;
148 47         62 my @raw;
149              
150 47         122 foreach my $packet (@$packets) {
151 129 100 100     865 if (blessed $packet and $packet->isa('Data::Transform::Meta')) {
    100          
152 11 50       621 if (my @ret = $self->_handle_put_meta($packet)) {
153 11         23 push @raw, @ret;
154             }
155 11         35 next;
156             } elsif (my @data = $self->_handle_put_data($packet)) {
157 105         552 push @raw, @data;
158             }
159             }
160              
161 47         195 return \@raw;
162             }
163              
164             =head2 meta
165              
166             A flag method that always returns 1. This can be used in e.g. POE to check
167             if the class supports L, which all Data::Transform
168             subclasses should, but L classes don't. Doing it this way
169             instead of checking if a filter is a Data::Transform subclass allows for
170             yet another filters implementation that is meant to transparently replace
171             this to be used by POE without changes to POE.
172              
173             =cut
174              
175             sub meta {
176 0     0 1 0 return 1;
177             }
178              
179             =head2 clone
180              
181             clone() creates and initializes a new filter based on the constructor
182             parameters of the existing one. The new filter is a near-identical
183             copy, except that its buffers are empty.
184              
185             =cut
186              
187             sub clone {
188 0     0 1 0 my $self = shift;
189 0         0 my $type = ref $self;
190 0         0 croak "$type has to implement a clone method";
191             }
192              
193             =head2 get_pending
194              
195             get_pending() returns any data remaining in a filter's input buffer.
196             The filter's input buffer is not cleared, however. get_pending()
197             returns a list reference if there's any data, or undef if the filter
198             was empty.
199              
200             Full items are serialized whole, so there is no corresponding "put"
201             buffer or accessor.
202              
203             =cut
204              
205             sub get_pending {
206 20     20 1 3671 my $self = shift;
207              
208 20 100       30 return [ @{$self->[0]} ] if @{$self->[0]};
  10         39  
  20         60  
209 10         40 return undef;
210             }
211              
212             =head1 IMPLEMENTORS NOTES
213              
214             L implements most of the public API above to help
215             ensure uniform behaviour across all subclasses. This implementation
216             expects your object to be an array ref. Data::Transform provides
217             a default implementation for the following methods:
218              
219             =over 2
220              
221             =item get(), get_one_start(), get_one()
222              
223             get() is implemented in terms of get_one_start() and get_one(). Since
224             having to handle L packets means that you have
225             to keep a list of incoming packets, it is highly unlikely that you
226             will ever need to override get_one_start(), since all it does is add
227             to the list. It assumes the list is kept as an array ref in the first
228             entry of your object's list.
229              
230             get_one is in turn implemented in terms of the following two methods:
231              
232             =over 2
233              
234             =cut
235              
236             =item _handle_get_data()
237              
238             This is where you do all your filter's input work. There is no default
239             implementation. It has a single method parameter which may contain a single
240             chunk of raw data to process. get_one() will also call it without new
241             data to see if not all raw data from the previous chunk had been processed.
242              
243             =cut
244              
245             sub _handle_get_data {
246 0     0   0 croak ref($_[0]) . " must implement _handle_get_data";
247             }
248              
249             =item _handle_get_meta()
250              
251             Override this if you need to act on metadata packets that are embedded
252             into the input stream. The default implementation just returns the
253             packet. If you override this, make sure you return the packet as well, so
254             that if your filter is being used in a filter stack, the filters below you
255             get a chance to handle it as well.
256              
257             =back
258              
259             =cut
260              
261             sub _handle_get_meta {
262 11     11   40 return $_[1];
263             }
264              
265             =item put()
266              
267             put() is implemented in terms of the following methods. It's unlikely
268             you want to override put() instead of these:
269              
270             =over 2
271              
272             =cut
273              
274             =item _handle_put_data()
275              
276             Gets called for each packet of regular data in the list passed to put().
277              
278             =cut
279              
280             sub _handle_put_data {
281 0     0   0 croak ref($_[0]) . " must implement _handle_put_data";
282             }
283              
284             =item _handle_put_meta()
285              
286             Gets called for each packet of metadata in the list passed to put(). The
287             default implementation just returns the packet. If you override this,
288             make sure you end with returning it too, so that when your filter is
289             used in a stack, the filters above you get a chance to handle it too.
290              
291             =cut
292              
293             sub _handle_put_meta {
294 11     11   50 return $_[1];
295             }
296              
297             1;
298              
299             __END__