File Coverage

blib/lib/Reflex/POE/Wheel.pm
Criterion Covered Total %
statement 41 43 95.3
branch 6 8 75.0
condition 1 3 33.3
subroutine 9 10 90.0
pod 3 7 42.8
total 60 71 84.5


line stmt bran cond sub pod time code
1             package Reflex::POE::Wheel;
2             # vim: ts=2 sw=2 noexpandtab
3             $Reflex::POE::Wheel::VERSION = '0.100';
4 1     1   624 use Moose;
  1         1  
  1         7  
5             extends 'Reflex::Base';
6 1     1   4995 use Scalar::Util qw(weaken);
  1         1  
  1         54  
7 1     1   10 use POE::Wheel;
  1         2  
  1         457  
8              
9             has wheel => (
10             isa => 'Maybe[POE::Wheel]',
11             is => 'rw',
12             );
13              
14             my %wheel_id_to_object;
15              
16             sub BUILD {
17 2     2 0 4 my ($self, $args) = @_;
18              
19 2         8 my $wheel_class = $self->wheel_class();
20              
21             # Get rid of stuff we don't need.
22 2         13 foreach my $param (keys %$args) {
23 14 100       22 delete $args->{$param} unless exists $self->valid_params()->{$param};
24             }
25              
26             # Map methods to events in the wheel parameters.
27 2         8 my $events_to_indices = $self->events_to_indices();
28 2         12 while (my ($wheel_param, $event_idx) = each %$events_to_indices) {
29 10         28 $args->{$wheel_param} = "wheel_event_$event_idx";
30             }
31              
32 2         10 $self->create_wheel($wheel_class, $args);
33             }
34              
35             sub create_wheel {
36 4     4 0 6 my ($self, $wheel_class, $args) = @_;
37              
38 4 100       15 return unless $self->call_gate("create_wheel", $wheel_class, $args);
39              
40 2         34 my $wheel = $wheel_class->new( %$args );
41 2         7266 $self->wheel($wheel);
42              
43 2         22 $wheel_id_to_object{$wheel->ID()} = $self;
44 2         33 weaken $wheel_id_to_object{$wheel->ID()};
45             }
46              
47             sub wheel_id {
48 2     2 1 3 my $self = shift;
49 2         54 return $self->wheel()->ID();
50             }
51              
52             sub put {
53 0     0 1 0 my $self = shift;
54 0         0 $self->wheel()->put(@_);
55             }
56              
57             sub DEMOLISH {
58 2     2 0 3 my $self = shift;
59 2         9 $self->demolish_wheel();
60             }
61              
62             sub demolish_wheel {
63 2     2 1 2 my $self = shift;
64 2 50 33     56 return unless defined($self->wheel()) and $self->call_gate("demolish_wheel");
65 2         25 delete $wheel_id_to_object{ $self->wheel_id() };
66 2         59 $self->wheel(undef);
67             }
68              
69             sub deliver {
70 17     17 0 39 my ($class, $event_idx, @event_args) = @_;
71              
72             # Map parameter offsets to named parameters.
73 17         53 my ($event_type, $event_name, @field_names) = $class->index_to_event(
74             $event_idx
75             );
76              
77 17         23 my $i = 0;
78 17         25 my %event_args = map { $_ => $event_args[$i++] } @field_names;
  40         111  
79              
80             # Get the wheel that sent us an event.
81              
82 17         33 my $wheel_id = delete $event_args{wheel_id};
83 17         17 delete $event_args{_discard_};
84              
85             # Get the Reflex::Base object that owns this wheel.
86              
87 17         19 my $self = $wheel_id_to_object{$wheel_id};
88 17 50       36 die unless $self;
89              
90             # Emit the event.
91 17         81 $self->emit(
92             -name => $event_name,
93             -type => $event_type,
94             %event_args
95             );
96             }
97              
98             __PACKAGE__->meta->make_immutable;
99              
100             1;
101              
102             __END__
103              
104             =pod
105              
106             =encoding UTF-8
107              
108             =for :stopwords Rocco Caputo
109              
110             =head1 NAME
111              
112             Reflex::POE::Wheel - Base class for POE::Wheel wrappers.
113              
114             =head1 VERSION
115              
116             This document describes version 0.100, released on April 02, 2017.
117              
118             =head1 SYNOPSIS
119              
120             There is no concise synopsis at this time. Setting up a new
121             Reflex::POE::Wheel is rather involved. The source for
122             L<Reflex::POE::Wheel::Run> may serve as an example.
123              
124             =head1 DESCRIPTION
125              
126             Reflex::POE::Wheel is a base class for Reflex objects that wrap and
127             watch POE::Wheel objects. Subclasses define a handful of methods
128             that describe the wheels they wrap. Reflex::POE::Wheel will use the
129             configuration to validate constructor parameters, map wheel events to
130             Reflex events, and map positional callback parameters to named ones.
131              
132             It's rather handy once you get used to it.
133              
134             =head2 Public Attributes
135              
136             =head3 wheel
137              
138             Currently Reflex::POE::Wheel exposes the raw POE::Wheel via its
139             wheel() attribute. This will be undefined if the wheel hasn't been
140             set up yet.
141              
142             =head2 Public Methods
143              
144             =head3 wheel_id
145              
146             The wheel_id() method returns the ID of the POE::Wheel being managed.
147             C<< $foo->wheel()->ID() >> can also be used instead.
148              
149             =head3 demolish_wheel
150              
151             Cause the internal wheel to be demolished. Provided as a method since
152             some wheels may require special handling.
153              
154             =head3 put
155              
156             put() sends its parameters to the POE::Wheel's put() method.
157              
158             $reflex_poe_wheel->put("one", "two");
159              
160             =head2 Required Subclass Methods
161              
162             These subclass methods are used to configure subclasses for their
163             chosen POE::Wheel objects.
164              
165             =head3 event_to_index
166              
167             event_to_index() maps POE::Wheel events to consecutive integer event
168             IDs. event_emit_names() will provide Reflex-friendly event names
169             based on the event IDs. event_param_names() will provide parameter
170             names that correspond to the wheel's positional parameters.
171              
172             This mapping is from Reflex::POE::Wheel::Run. It will make more sense
173             in the context of event_emit_names() and event_param_names().
174              
175             sub event_to_index {
176             return(
177             {
178             StdinEvent => 0,
179             StdoutEvent => 1,
180             StderrEvent => 2,
181             ErrorEvent => 3,
182             CloseEvent => 4,
183             },
184             );
185             }
186              
187             =head3 event_emit_names
188              
189             event_emit_names() returns an array reference that maps
190             Reflex::POE::Wheel's event IDs to Reflex-friendly event names.
191              
192             Here's an example from Reflex::POE::Wheel::Run. The wheel's
193             StdinEvent (ID 0) is emitted as "stdin" (the 0th element in
194             event_emit_names()). StdoutEvent becomes "stdout", and so on.
195              
196             sub event_emit_names {
197             return(
198             [
199             'stdin', # StdinEvent
200             'stdout', # StdoutEvent
201             'stderr', # StderrEvent
202             'error', # ErrorEvent
203             'closed', # ClosedEvent
204             ],
205             );
206             }
207              
208             =head3 event_param_names
209              
210             event_param_names() returns an array reference that maps
211             Reflex::POE::Wheel's event IDs to Reflex-friendly lists of parameter
212             names. The underlying POE::Wheel's positional parameters will be
213             mapped to these names before the Reflex object emits them.
214              
215             Here's yet another example from Reflex::POE::Wheel::Run. StdinEvent
216             and StdoutEvent each return two parameters. The Reflex object will
217             emit their ARG0 as the named parameter "output", and ARG1 becomes the
218             named parameter "wheel_id".
219              
220             sub event_param_names {
221             return(
222             [
223             [ "wheel_id" ],
224             [ "output", "wheel_id" ],
225             [ "output", "wheel_id" ],
226             [ "operation", "errnum", "errstr", "wheel_id", "handle_name" ],
227             [ "wheel_id" ],
228             ]
229             );
230             }
231              
232             =head3 wheel_class
233              
234             wheel_class() returns a simple string---the class name of the wheel to
235             construct.
236              
237             =head3 valid_params
238              
239             The valid_params() method returns a hash reference keyed on valid
240             constructor parameters. Values don't matter at this time.
241             Reflex::POE::Wheel uses this hash reference to pre-validate
242             construction of underlying POE::Wheel objects.
243              
244             POE::Wheel::Run takes quite a lot of parameters, most of which are
245             optional.
246              
247             sub valid_params {
248             return(
249             {
250             CloseOnCall => 1,
251             Conduit => 1,
252             Filter => 1,
253             Group => 1,
254             NoSetPgrp => 1,
255             NoSetSid => 1,
256             Priority => 1,
257             Program => 1,
258             ProgramArgs => 1,
259             StderrDriver => 1,
260             StderrFilter => 1,
261             StdinDriver => 1,
262             StdinFilter => 1,
263             StdioDriver => 1,
264             StdioFilter => 1,
265             StdoutDriver => 1,
266             StdoutFilter => 1,
267             User => 1,
268             }
269             );
270             }
271              
272             =for Pod::Coverage BUILD DEMOLISH create_wheel deliver
273              
274             =head1 CAVEATS
275              
276             The demolish() name is heading towards deprecation in favor of
277             something shorter and more widely recognized, perhaps stop(). The
278             jury is still out, however.
279              
280             Methods are not yet converted automatically. It seems more sensible
281             to provide a native Reflex::Base interface. On the other hand, it
282             may be possible for Moose's "handles" attribute option to pass the
283             wheel's methods through the wrapper. More investigation is required.
284              
285             wheel() or wheel_id() will be deprecated, depending upon which is
286             considered redundant.
287              
288             =head1 SEE ALSO
289              
290             Please see those modules/websites for more information related to this module.
291              
292             =over 4
293              
294             =item *
295              
296             L<Reflex|Reflex>
297              
298             =item *
299              
300             L<Moose::Manual::Concepts>
301              
302             =item *
303              
304             L<Reflex>
305              
306             =item *
307              
308             L<Reflex::POE::Event>
309              
310             =item *
311              
312             L<Reflex::POE::Postback>
313              
314             =item *
315              
316             L<Reflex::POE::Session>
317              
318             =item *
319              
320             L<Reflex::POE::Wheel::Run>
321              
322             =item *
323              
324             L<Reflex/ACKNOWLEDGEMENTS>
325              
326             =item *
327              
328             L<Reflex/ASSISTANCE>
329              
330             =item *
331              
332             L<Reflex/AUTHORS>
333              
334             =item *
335              
336             L<Reflex/BUGS>
337              
338             =item *
339              
340             L<Reflex/BUGS>
341              
342             =item *
343              
344             L<Reflex/CONTRIBUTORS>
345              
346             =item *
347              
348             L<Reflex/COPYRIGHT>
349              
350             =item *
351              
352             L<Reflex/LICENSE>
353              
354             =item *
355              
356             L<Reflex/TODO>
357              
358             =back
359              
360             =head1 BUGS AND LIMITATIONS
361              
362             You can make new bug reports, and view existing ones, through the
363             web interface at L<http://rt.cpan.org/Public/Dist/Display.html?Name=Reflex>.
364              
365             =head1 AUTHOR
366              
367             Rocco Caputo <rcaputo@cpan.org>
368              
369             =head1 COPYRIGHT AND LICENSE
370              
371             This software is copyright (c) 2017 by Rocco Caputo.
372              
373             This is free software; you can redistribute it and/or modify it under
374             the same terms as the Perl 5 programming language system itself.
375              
376             =head1 AVAILABILITY
377              
378             The latest version of this module is available from the Comprehensive Perl
379             Archive Network (CPAN). Visit L<http://www.perl.com/CPAN/> to find a CPAN
380             site near you, or see L<https://metacpan.org/module/Reflex/>.
381              
382             =head1 DISCLAIMER OF WARRANTY
383              
384             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
385             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT
386             WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER
387             PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND,
388             EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
389             IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
390             PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
391             SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME
392             THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.
393              
394             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
395             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
396             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE
397             TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR
398             CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
399             SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
400             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
401             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
402             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
403             DAMAGES.
404              
405             =cut