1# 2001/01/25 shizukesa@pobox.com
2
3package POE::Filter::RecordBlock;
4
5use strict;
6use POE::Filter;
7
8use vars qw($VERSION @ISA);
9$VERSION = '1.368'; # NOTE - Should be #.### (three decimal places)
10@ISA = qw(POE::Filter);
11
12use Carp qw(croak);
13
14sub BLOCKSIZE () { 0 };
15sub GETBUFFER () { 1 };
16sub PUTBUFFER () { 2 };
17sub CHECKPUT  () { 3 };
18sub FIRST_UNUSED () { 4 }
19
20use base 'Exporter';
21our @EXPORT_OK = qw( FIRST_UNUSED );
22
23
24#------------------------------------------------------------------------------
25
26sub new {
27  my $type = shift;
28
29  croak "$type must be given an even number of parameters" if @_ & 1;
30  my %params = @_;
31
32  # Block size
33  croak "BlockSize must be greater than 0" unless (
34    defined($params{BlockSize}) && ($params{BlockSize} > 0)
35  );
36  my $block_size = $params{BlockSize};
37
38  # check put
39  my $check_put = $params{CheckPut};
40
41  delete @params{ qw( BlockSize CheckPut ) };
42  carp("$type ignores unknown parameters: ", join(', ', sort keys %params))
43    if scalar keys %params;
44
45  my $self = bless [
46    $block_size,        # BLOCKSIZE
47    [],                 # GETBUFFER
48    [],                 # PUTBUFFER
49    $check_put         # CHECKPUT
50  ], $type;
51}
52
53sub clone {
54  my $self = shift;
55  my $clone = bless [
56    $self->[0], # BLOCKSIZE
57    [],         # GETBUFFER
58    [],         # PUTBUFFER
59    $self->[3]  # CHECKPUT
60  ], ref $self;
61  $clone;
62}
63
64#------------------------------------------------------------------------------
65# get() is inherited from POE::Filter.
66
67#------------------------------------------------------------------------------
68# 2001-07-27 RCC: Add get_one_start() and get_one() to correct filter
69# changing and make input flow control possible.
70
71sub get_one_start {
72  my ($self, $data) = @_;
73  push @{$self->[GETBUFFER]}, @$data;
74}
75
76sub get_one {
77  my $self = shift;
78
79  return [ ] unless @{$self->[GETBUFFER]} >= $self->[BLOCKSIZE];
80  return [ [ splice @{$self->[GETBUFFER]}, 0, $self->[BLOCKSIZE] ] ];
81}
82
83#------------------------------------------------------------------------------
84
85sub put {
86  my ($self, $data) = @_;
87  my @result;
88
89  if ($self->[CHECKPUT]) {
90    foreach (@$data) {
91      push @{$self->[PUTBUFFER]}, @$_;
92    }
93    while (@{$self->[PUTBUFFER]} >= $self->[BLOCKSIZE]) {
94      push @result, splice @{$self->[PUTBUFFER]}, 0, $self->[BLOCKSIZE];
95    }
96  }
97  else {
98    push @result, splice(@{$self->[PUTBUFFER]}, 0);
99    foreach (@$data) {
100      push @result, @$_;
101    }
102  }
103  \@result;
104}
105
106#------------------------------------------------------------------------------
107
108sub get_pending {
109  my $self = shift;
110  return undef unless @{$self->[GETBUFFER]};
111  return [ @{$self->[GETBUFFER]} ];
112}
113
114#------------------------------------------------------------------------------
115
116sub put_pending {
117  my ($self) = @_;
118  return undef unless $self->[CHECKPUT];
119  return undef unless @{$self->[PUTBUFFER]};
120  return [ @{$self->[PUTBUFFER]} ];
121}
122
123#------------------------------------------------------------------------------
124
125sub blocksize {
126  my ($self, $size) = @_;
127  if (defined($size) && ($size > 0)) {
128    $self->[BLOCKSIZE] = $size;
129  }
130  $self->[BLOCKSIZE];
131}
132
133#------------------------------------------------------------------------------
134
135sub checkput {
136  my ($self, $val) = @_;
137  if (defined($val)) {
138    $self->[CHECKPUT] = $val;
139  }
140  $self->[CHECKPUT];
141}
142
1431;
144
145__END__
146
147=head1 NAME
148
149POE::Filter::RecordBlock - translate between discrete records and blocks of them
150
151=head1 SYNOPSIS
152
153Hello, dear reader.  This SYNOPSIS does not contain a fully
154functioning sample program because your humble documenter cannot come
155up with a short, reasonable use case for this module.  Please contact
156the maintainer if this module is useful to you.  Otherwise you may wake
157up one morning to discover that it has been deprecated.
158
159  $filter = new POE::Filter::RecordBlock( BlockSize => 4 );
160  $arrayref_of_arrayrefs = $filter->get($arrayref_of_raw_data);
161  $arrayref_of_raw_chunks = $filter->put($arrayref_of_arrayrefs);
162  $arrayref_of_raw_chunks = $filter->put($single_arrayref);
163  $arrayref_of_leftovers = $filter->get_pending;
164  $arrayref_of_leftovers = $filter->put_pending;
165
166=head1 DESCRIPTION
167
168On input, POE::Filter::RecordBlock translates a stream of discrete
169items into a "block" of them.  It does this by collecting items until
170it has BlockSize of them, then returning the lot of them in an array
171reference.
172
173On output, this module flattens array references.
174
175This module may be deprecated in the future.  Please contact the
176maintainer if this module is useful to you.
177
178=head1 PUBLIC FILTER METHODS
179
180In addition to the usual POE::Filter methods, POE::Filter::RecordBlock
181supports the following.
182
183=head2 new
184
185new() takes at least one mandatory argument, BlockSize, which must be
186defined and greater than zero.  new() also accepts a CheckPut Boolean
187parameter that indicates whether put() should check for the proper
188BlockSize before allowing data to be serialized.
189
190Using CheckPut is not recommended, as it enables a write buffer in the
191filter, therefore breaking put() for normal use.
192
193=head2 put_pending
194
195put_pending() returns an arrayref of any records that are waiting to
196be sent.  It is the outbound equivalent of POE::Filter's get_pending()
197accessor.  put_pending() is not part of the canonical POE::Filter API,
198so nothing will use it.  It's up to applications to handle pending
199output, whenever it's appropriate to do so.
200
201=head2 blocksize
202
203blocksize() is an accessor/mutator for POE::Filter::RecordBlock's
204BlockSize value.
205
206=head2 checkput
207
208checkput() is an accessor/mutator for POE::Filter::RecordBlock's
209CheckPut flag.
210
211=head1 SEE ALSO
212
213L<POE::Filter> for more information about filters in general.
214
215L<POE::Filter::Stackable> for more details on stacking filters.
216
217=head1 BUGS
218
219This filter may maintain an output buffer that no other part of POE
220will know about.
221
222This filter implements a highly specialized and seemingly not
223generally useful feature.
224
225Does anyone use this filter?  This filter may be deprecated if nobody
226speaks up.
227
228=head1 AUTHORS & COPYRIGHTS
229
230The RecordBlock filter was contributed by Dieter Pearcey.
231Documentation is provided by Rocco Caputo.
232
233Please see the L<POE> manpage for more information about authors and
234contributors.
235
236=cut
237
238# rocco // vim: ts=2 sw=2 expandtab
239# TODO - Edit.
240