File Coverage

lib/DataFlow/Types.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package DataFlow::Types;
2              
3 1     1   2035 use strict;
  1         2  
  1         39  
4 1     1   7 use warnings;
  1         2  
  1         68  
5              
6             # ABSTRACT: Type definitions for DataFlow
7              
8             our $VERSION = '1.121830'; # VERSION
9              
10 0           use MooseX::Types -declare => [
11             qw(Processor ProcessorList WrappedProcList ProcessorSub ProcPolicy),
12             qw(ConversionSubs ConversionDirection),
13             qw(Encoder Decoder),
14             qw(HTMLFilterTypes),
15 1     1   533 ];
  0            
16              
17             use namespace::autoclean;
18              
19             use MooseX::Types::Moose qw/Str CodeRef ArrayRef HashRef/;
20             class_type 'DataFlow';
21             class_type 'DataFlow::Proc';
22             class_type 'DataFlow::ProcWrapper';
23             role_type 'DataFlow::Role::Processor';
24             role_type 'DataFlow::Role::ProcPolicy';
25              
26             use Moose::Util::TypeConstraints 1.01;
27             use Scalar::Util qw/blessed/;
28             use Encode;
29              
30             sub _is_loaded {
31             my $class = shift;
32             eval { $class->meta };
33             return 0 if $@;
34             return 1;
35             }
36              
37             sub _load_class {
38             my $name = shift;
39             return q{DataFlow::Proc} if $name eq 'Proc';
40              
41             if ( $name =~ m/::/ ) {
42             return $name if _is_loaded($name);
43             eval "use $name"; ## no critic
44             return $name unless $@;
45             }
46              
47             my $class = "DataFlow::Proc::$name";
48             return $class if _is_loaded($class);
49             eval "use $class"; ## no critic
50             return $class unless $@;
51              
52             return $name if _is_loaded($name);
53             eval "use $name"; ## no critic
54             return $name unless $@;
55             die qq{Cannot load class from '$name'};
56             }
57              
58             sub _str_to_proc {
59             my ( $procname, @args ) = @_;
60             my $class = _load_class($procname);
61             my $obj = eval { $class->new(@args) };
62             die "$@" if "$@";
63             return $obj;
64             }
65              
66             sub _is_processor {
67             my $obj = shift;
68             return
69             blessed($obj)
70             && $obj->can('does')
71             && $obj->does('DataFlow::Role::Processor');
72             }
73              
74             # where any can be of types:
75             # - Str
76             # - [ Str, <options> ]
77             # - CodeRef
78             # - DataFlow::Role::Processor
79             sub _any_to_proc {
80             my $elem = shift;
81             my $ref = ref($elem);
82             if ( $ref eq '' ) { # Str?
83             return _str_to_proc($elem);
84             }
85             elsif ( $ref eq 'ARRAY' ) { # [ Str, <options> ]
86             return _str_to_proc( @{$elem} );
87             }
88             elsif ( $ref eq 'CODE' ) {
89             require DataFlow::Proc;
90             return DataFlow::Proc->new( p => $elem );
91             }
92             return $elem;
93             }
94              
95             sub _wrap_proc {
96             my $proc = shift;
97             return $proc if ref($proc) eq 'DataFlow::ProcWrapper';
98             eval 'use DataFlow::ProcWrapper'; ## no critic
99             return DataFlow::ProcWrapper->new( wraps => $proc );
100             }
101              
102             # subtypes CORE
103              
104             subtype 'Processor' => as 'DataFlow::Role::Processor';
105             coerce 'Processor' => from 'Any' => via { _any_to_proc($_) };
106              
107             subtype 'ProcessorList' => as 'ArrayRef[DataFlow::Role::Processor]' =>
108             where { scalar @{$_} > 0 } =>
109             message { 'DataFlow must have at least one processor' };
110             coerce 'ProcessorList' => from 'ArrayRef' => via {
111             my @list = @{$_};
112             my @res = map { _any_to_proc($_) } @list;
113             return [@res];
114             },
115             from
116             'Str' => via { [ _str_to_proc($_) ] },
117             from
118             'CodeRef' => via { [ _any_to_proc($_) ] },
119             from 'DataFlow::Role::Processor' => via { [$_] };
120              
121             subtype 'WrappedProcList' => as 'ArrayRef[DataFlow::ProcWrapper]' =>
122             where { scalar @{$_} > 0 } =>
123             message { 'DataFlow must have at least one processor' };
124             coerce 'WrappedProcList' => from 'ArrayRef' => via {
125             my @list = @{$_};
126             my @res = map { _wrap_proc( _any_to_proc($_) ) } @list;
127             return [@res];
128             },
129             from
130             'Str' => via { [ _wrap_proc( _str_to_proc($_) ) ] },
131             from
132             'CodeRef' => via { [ _wrap_proc( _any_to_proc($_) ) ] },
133             from 'DataFlow::Role::Processor' => via { [ _wrap_proc($_) ] };
134              
135             subtype 'ProcessorSub' => as 'CodeRef';
136             coerce 'ProcessorSub' => from 'DataFlow::Role::Processor' => via {
137             my $f = $_;
138             return sub { $f->process($_) };
139             };
140              
141             subtype 'ProcPolicy' => as 'DataFlow::Role::ProcPolicy';
142             coerce 'ProcPolicy' => from 'Str' => via { _make_policy($_) };
143             coerce 'ProcPolicy' => from 'ArrayRef' => via { _make_policy( @{$_} ) };
144              
145             sub _make_policy {
146             my ( $policy, @args ) = @_;
147             my $class = 'DataFlow::Policy::' . $policy;
148             my $obj;
149             eval 'use ' . $class . '; $obj = ' . $class . '->new(@args)'; ## no critic
150             die $@ if $@;
151             return $obj;
152             }
153              
154             # subtypes for DataFlow::Proc::Converter ######################
155              
156             enum 'ConversionDirection' => [ 'CONVERT_TO', 'CONVERT_FROM' ];
157             coerce 'ConversionDirection' => from 'Str' => via {
158             return 'CONVERT_TO' if m/to_/i;
159             return 'CONVERT_FROM' if m/from_/i;
160             };
161              
162             subtype 'ConversionSubs' => as 'HashRef[CodeRef]' => where {
163             scalar( keys %{$_} ) == 2
164             && exists $_->{CONVERT_TO}
165             && exists $_->{CONVERT_FROM};
166             } => message { q(Invalid hash of type 'ConversionSubs') };
167              
168             # subtypes for DataFlow::Proc::Encoding ######################
169              
170             subtype 'Decoder' => as 'CodeRef';
171             coerce 'Decoder' => from 'Str' => via {
172             my $encoding = $_;
173             return sub { return decode( $encoding, shift ) };
174             };
175              
176             subtype 'Encoder' => as 'CodeRef';
177             coerce 'Encoder' => from 'Str' => via {
178             my $encoding = $_;
179             return sub { return encode( $encoding, shift ) };
180             };
181              
182             1;
183              
184              
185              
186             __END__
187             =pod
188              
189             =encoding utf-8
190              
191             =head1 NAME
192              
193             DataFlow::Types - Type definitions for DataFlow
194              
195             =head1 VERSION
196              
197             version 1.121830
198              
199             =head1 SYNOPSIS
200              
201             When defining a Moose attribute. Example:
202              
203             has 'direction' => (
204             is => 'ro',
205             isa => 'ConversionDirection',
206             );
207              
208             =head1 DESCRIPTION
209              
210             This module contains only type definitions. Most of the time there will be
211             no need to work or mess with this code, unless there is a bug in DataFlow
212             and/or you are developing a new feature which requires a new type or an
213             adjustment to an existing one.
214              
215             =head1 SUBTYPES
216              
217             =head2 Processor
218              
219             A L<DataFlow::Proc> object, with coercions.
220              
221             =head3 Coercions
222              
223             =head4 from Str
224              
225             Named processors. If it contains the substring '::', DataFlow will try to
226             create an object of that type. If it does not, then DataFlow will attempt to
227             create an object of the type C<< DataFlow::Proc::<STRING> >>. The string 'Proc'
228             is reserved for creating an object of the type <DataFlow::Proc>.
229              
230             =head4 from ArrayRef
231              
232             Named processor with parameters. The first element of the array must be a
233             text string, subject to the rules used in the previous item. The rest of the
234             array is passed as-is for the constructor of the object.
235              
236             =head4 from CodeRef
237              
238             Code reference, a.k.a. a C<sub>. A processor object will be created:
239              
240             DataFlow::Proc->new( p => CODE )
241              
242             =head4 from DataFlow::Role::Processor
243              
244             An object that can B<process> something. Objects from both L<DataFlow> and
245             L<DataFlow::Proc> classes will consume that role, so will all its descendants.
246             If the element is blessed and C<< ->does('DataFlow::Role::Processor') >>, a
247             processor object will be created wrapping it:
248              
249             DataFlow::Proc->new( p => sub { PROCESSOR->process($_) } )
250              
251             =head2 ProcessorList
252              
253             An ArrayRef of L<DataFlow::Role::Processor> objects, with at least one element.
254              
255             =head3 Coercions
256              
257             =head4 from ArrayRef
258              
259             Attempts to make C<DataFlow::Role::Processor> objects out of different things
260             provided in an ArrayRef. It currently works for:
261              
262             =over 4
263              
264             =item *
265              
266             Str
267              
268             =item *
269              
270             ArrayRef
271              
272             =item *
273              
274             CodeRef
275              
276             =item *
277              
278             DataFlow::Role::Processor
279              
280             =back
281              
282             using the same rules as in the subtype C<Processor> described above.
283             Anything else will trigger an error.
284              
285             =head4 from Str
286              
287             An ArrayRef will be created wrapping a named processor, as described in the
288             coercion section of the C<Processor> subtype above.
289              
290             =head4 from CodeRef
291              
292             An ArrayRef will be created wrapping a processor, as described in the
293             coercion section of the C<Processor> subtype above.
294              
295             =head4 from DataFlow::Role::Processor
296              
297             An ArrayRef will be created wrapping the processor, as described in the
298             coercion section of the C<Processor> subtype above.
299              
300             =head2 WrappedProcList
301              
302             An ArrayRef of L<DataFlow::ProcWrapper> objects, with at least one element.
303              
304             =head3 Coercions
305              
306             =head4 from ArrayRef
307              
308             Attempts to make C<DataFlow::ProcWrapper> objects out of different things
309             provided in an ArrayRef. It currently works for:
310              
311             =over 4
312              
313             =item *
314              
315             Str
316              
317             =item *
318              
319             ArrayRef
320              
321             =item *
322              
323             CodeRef
324              
325             =item *
326              
327             DataFlow::Role::Processor
328              
329             =back
330              
331             using the same rules as in the subtype C<Processor> described above and
332             wrapping the resulting C<Processor> in a C<DataFlow::ProcWrapper> object.
333             Anything else will trigger an error.
334              
335             =head4 from Str
336              
337             An ArrayRef will be created wrapping a named processor, as described in the
338             coercion section of the C<Processor> subtype above and
339             wrapping the resulting C<Processor> in a C<DataFlow::ProcWrapper> object.
340              
341             =head4 from CodeRef
342              
343             An ArrayRef will be created wrapping a processor, as described in the
344             coercion section of the C<Processor> subtype above and
345             wrapping the resulting C<Processor> in a C<DataFlow::ProcWrapper> object.
346              
347             =head4 from DataFlow::Role::Processor
348              
349             An ArrayRef will be created wrapping the processor, as described in the
350             coercion section of the C<Processor> subtype above and
351             wrapping the resulting C<Processor> in a C<DataFlow::ProcWrapper> object.
352              
353             =head2 ProcessorSub
354              
355             A CodeRef, with coercions.
356              
357             =head3 Coercions
358              
359             =head4 from DataFlow::Role::Processor
360              
361             An ArrayRef will be created wrapping the processor.
362             The rules used above for DataFlow::Role::Processor elements in the ArrayRef
363             apply.
364              
365             =head2 ConversionDirection
366              
367             An enumeration used by type L<DataFlow::Proc::Converter>,
368             containing two elements:
369              
370             =over 4
371              
372             =item *
373              
374             CONVERT_TO
375              
376             Indicates the conversion will occur towards a specified type
377              
378             =item *
379              
380             CONVERT_FROM
381              
382             Conversely, indicates the conversion will occur from a specfied type
383              
384             =back
385              
386             See DataFlow::Proc::Converter for more information.
387              
388             =head2 ConversionSubs
389              
390             A HashRef[CodeRef] also used by DataFlow::Proc::Converter. It must have two
391             keys only, 'CONVERT_TO' and 'CONVERT_FROM', holding a code reference (sub) for
392             each of those.
393              
394             See DataFlow::Proc::Converter for more information.
395              
396             =head2 Decoder
397              
398             A CodeRef used by L<DataFlow::Proc::Encoding>. It will be used to decode
399             strings from some particular character encoding to Perl's internal
400             representation.
401              
402             =head3 Coercions
403              
404             =head4 from Str
405              
406             It will automagically create a C<sub> that uses function C<< decode() >> from
407             module L<Encode> to decode from a named encoding.
408              
409             =head2 Encoder
410              
411             A CodeRef used by L<DataFlow::Proc::Encoding>. It will be used to encode
412             strings from Perl's internal representation to some particular character
413             encoding.
414              
415             =head3 Coercions
416              
417             =head4 from Str
418              
419             It will automagically create a C<sub> that uses function C<< encode() >> from
420             module L<Encode> to encode to a named encoding.
421              
422             =head1 SEE ALSO
423              
424             Please see those modules/websites for more information related to this module.
425              
426             =over 4
427              
428             =item *
429              
430             L<DataFlow|DataFlow>
431              
432             =back
433              
434             =head1 AUTHOR
435              
436             Alexei Znamensky <russoz@cpan.org>
437              
438             =head1 COPYRIGHT AND LICENSE
439              
440             This software is copyright (c) 2011 by Alexei Znamensky.
441              
442             This is free software; you can redistribute it and/or modify it under
443             the same terms as the Perl 5 programming language system itself.
444              
445             =head1 BUGS AND LIMITATIONS
446              
447             You can make new bug reports, and view existing ones, through the
448             web interface at L<http://rt.cpan.org>.
449              
450             =head1 DISCLAIMER OF WARRANTY
451              
452             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
453             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT
454             WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER
455             PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND,
456             EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
457             IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
458             PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
459             SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME
460             THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.
461              
462             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
463             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
464             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE
465             TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR
466             CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
467             SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
468             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
469             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
470             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
471             DAMAGES.
472              
473             =cut
474