File Coverage

blib/lib/MooX/Async.pm
Criterion Covered Total %
statement 37 43 86.0
branch 4 4 100.0
condition n/a
subroutine 12 24 50.0
pod 2 4 50.0
total 55 75 73.3


line stmt bran cond sub pod time code
1             package MooX::Async;
2              
3             our $VERSION = '0.006';
4             $VERSION = eval $VERSION;
5              
6             =head1 NAME
7              
8             MooX::IOAsync - BovIinate Oout :of: ASsync
9              
10             =head1 SYNOPSIS
11              
12             package Thing;
13             use Moo;
14             use MooX::Async;
15              
16             # Extend an IO::Async module with MooX::Async:
17             extends MooXAsync('Notifier');
18              
19             # Define a lazy attribute which will hold a callback subref with
20             # an (optional) default implementation.
21             event on_foo => sub { say "foo" };
22              
23             =head1 DESCRIPTION
24              
25             Allows a L class to extend a L subclass with
26             the L role and the magic necessary to make
27             L work as a L object.
28              
29             =head1 BUGS
30              
31             Certainly.
32              
33             =cut
34              
35 1     1   72797 use Modern::Perl '2017';
  1         11851  
  1         8  
36 1     1   922 use strictures 2;
  1         2082  
  1         51  
37 1     1   905 use Moo (); # For _install_tracked
  1         14355  
  1         33  
38 1     1   577 use Moo::Role; # For me
  1         10306  
  1         9  
39 1     1   552 use Module::Runtime qw(compose_module_name module_notional_filename);
  1         2  
  1         6  
40 1     1   595 use namespace::clean;
  1         14381  
  1         10  
41              
42             sub import {
43 4     4   20 my $pkg = caller;
44 4 100       81 my $has = $pkg->can('has') or return;
45             Moo::_install_tracked $pkg, event => sub {
46 8     8   2057 my $event = shift;
47 8 100       33 my $sub = @_ % 2 ? pop : sub { die "$event event unimplemented" };
  0         0  
48 8     0   35 $has->($event, @_, is => lazy => builder => sub { $sub });
  0     0   0  
        0      
        0      
        0      
        0      
        0      
        0      
49 3         26 };
50 3         91 Moo::_install_tracked $pkg, MooXAsync => \&MooXAsync;
51             }
52              
53             =head1 EXPORTS
54              
55             L and L are exported unconditionally.
56              
57             =over
58              
59             =item event($name, [@args], [$subref]) => void
60              
61             Install a lazy attribute to handle the event C<$name>. This is basically just:
62              
63             has $event => (@args, builder => sub { $subref });
64              
65             =item MooXAsync($notifier) => $async_moo_class
66              
67             Creates and returns the name of a class which extends C<$notifier>,
68             which can be an object or the name of a class which subclasses
69             L with L and L.
70              
71             Prepends C to C<$notifier> if it doesn't contain
72             C<::>. If C<$notifier> begins with C<::> then it is removed.
73              
74             If C<$notifier> is an object then it is re-blessed into the new
75             package.
76              
77             =back
78              
79             =cut
80              
81             sub MooXAsync {
82             my $notifier = shift;
83             # Ensure DOES('IO::Async::Notifier') and DOESN'T MooX::Async
84             my $class = ref $notifier || $notifier; # Those who bless into '0' deserve what they get
85             my $parent = $class =~ /^IO::Async::/ ? $class : compose_module_name('IO::Async', $class);
86             my $pkg = $parent . '::' . __PACKAGE__;
87 1     1   780 no strict 'refs';
  1         4  
  1         286  
88             # This is ugly but I'm lazy.
89             if (not scalar keys %{"$pkg\::"}) {
90 1     1 0 6 eval <<"TOP" . <<'BOTTOM' or die; # Keep interpolated part seperate
  1     1 0 2  
  1     0 1 4  
  1     0 1 6  
  1     0   2  
  1     0   6  
  0            
  0            
  0            
  0            
91             package $pkg;
92             use Moo;
93             extends '$parent';
94             TOP
95             sub configure_unknown { }
96             sub FOREIGNBUILDARGS { shift; @_ }
97             around can_event => sub {
98             my ($orig, $self, $event) = @_;
99             return $self->$event if $self->can("_build_$event");
100             $self->$orig($event);
101             };
102             1;
103             BOTTOM
104             $INC{module_notional_filename($pkg)} = 1;
105             }
106             bless $notifier, $pkg if ref $notifier; # Any extra mooification?
107             return $pkg;
108             }
109              
110 1     1   9 use namespace::clean qw(MooXAsync);
  1         3  
  1         7  
111              
112             1;
113              
114             =back
115              
116             =head1 HISTORY
117              
118             =over
119              
120             =item MooX::Async 0.004
121              
122             Have I got it right yet?
123              
124             =back
125              
126             =head1 SEE ALSO
127              
128             L
129              
130             L
131              
132             =head1 AUTHOR
133              
134             Matthew King
135              
136             =cut