File Coverage

blib/lib/POE/Component/SubWrapper.pm
Criterion Covered Total %
statement 77 78 98.7
branch 5 6 83.3
condition 4 6 66.6
subroutine 15 16 93.7
pod 5 5 100.0
total 106 111 95.5


line stmt bran cond sub pod time code
1             package POE::Component::SubWrapper;
2              
3             =head1 NAME
4              
5             POE::Component::SubWrapper - event based wrapper for subs
6              
7             =head1 SYNOPSIS
8              
9             use POE::Component::SubWrapper;
10             POE::Component::SubWrapper->spawn('main');
11             $kernel->post('main', 'my_sub', [ $arg1, $arg2, $arg3 ], 'callback_state');
12              
13             =head1 DESCRIPTION
14              
15             This is a module which provides an event based wrapper for subroutines.
16              
17              
18             =head1 METHODS
19              
20             =cut
21              
22 2     2   259803 use warnings;
  2         6  
  2         74  
23 2     2   11 use strict;
  2         4  
  2         156  
24              
25 2     2   23 use Carp qw(croak);
  2         3  
  2         181  
26 2     2   996 use POE;
  2         83626  
  2         26  
27 2     2   120730 use Devel::Symdump;
  2         5  
  2         58  
28              
29 2     2   2334 use Exporter::Lite;
  2         1914  
  2         15  
30             our @EXPORT = qw(poeize);
31              
32              
33             our $VERSION = '2.01';
34              
35 2     2   201 use constant DEBUG => 0;
  2         6  
  2         460  
36              
37             =head2 spawn
38              
39             POE::Component::SubWrapper->spawn('main');
40              
41             SubWrapper components are not normal objects, but are instead 'spawned' as
42             separate sessions. This is done with with PoCo::SubWrapper's 'spawn'
43             method, which takes one required and one optional argument. The first
44             argument is the package name to wrap. This is required. The second argument
45             is optional and contains an alias to give to the session created. If no
46             alias is supplied, the package name is used as an alias.
47              
48             =cut
49              
50             sub spawn { #{{{
51 2     2 1 192 DEBUG && print "PoCo::SubWrapper->spawn: Entering\n";
52            
53 2         3 my $type = shift;
54 2         6 my $package = shift;
55 2         3 my $alias = shift;
56              
57 2 50       6 croak "Too many args" if scalar @_;
58 2 100 66     16 $alias = $package unless defined($alias) and length($alias);
59              
60 2         2 DEBUG && print "PoCo::SubWrapper->spawn: type = [$type], package = [$package], alias = [$alias]\n";
61              
62             # get subroutines defined by package.
63 2         3 my @subs;
64              
65 2         576 my $sym = Devel::Symdump->new($package);
66             {
67 2     2   13 no strict 'refs';
  2         6  
  2         208  
  2         3  
68 2         140 foreach my $function ($sym->functions) {
69 43         152 *p = *$function;
70 43         62 my $coderef = *p{CODE};
71 43         427 my ($key) = ($function =~ /([^:]*)$/);
72              
73 2     2   3198 use Data::Dumper;
  2         17224  
  2         1335  
74 43         50 DEBUG && print "Symbol is $function\n";
75 43         46 DEBUG && print "key is $key\n";
76 43         40 DEBUG && print "Coderef is [", Dumper($coderef), "]\n";
77              
78 43         792 push @subs, { name => $key, code => $coderef };
79             }
80             }
81              
82 2         9 my %states;
83 2         4 foreach my $sub (@subs) {
84 43         50 DEBUG && print "Building state for ", $sub->{name}, "\n";
85 43         79 $states{$sub->{name}} = build_handler($package, $sub->{code});
86             }
87              
88 2         8 $states{'_start'} = \&wrapper_start;
89 2     2   30 $states{'_stop'} = sub {};
  2         1131  
90              
91 2         31 my $s = POE::Session->create(
92             inline_states => \%states,
93             heap => {
94             alias => $alias,
95             }
96             );
97 2         375 return $s;
98             } #}}}
99              
100              
101             =head2 poeize
102              
103             poeize My::Package;
104              
105             Another way to create SubWrapper components is to use the C method,
106             which is included in the default export list of the package. You can simply
107             do:
108              
109             poeize Data::Dumper;
110              
111             and Data::Dumper will be wrapped into a session with the alias
112             'Data::Dumper'.
113              
114             =cut
115              
116             sub poeize (*) { #{{{
117 1     1 1 10 my $package = shift;
118 1         5 spawn($package, $package);
119             } #}}}
120              
121             =begin devel
122              
123             =head2 wrapper_start
124              
125             Sets our alias
126              
127             =cut
128              
129             sub wrapper_start { #{{{
130 2     2 1 812 $_[KERNEL]->alias_set($_[HEAP]->{alias});
131             } #}}}
132              
133              
134             =head2 shutdown
135              
136             Provides a way to forcibly shutdown our session.
137             This is done by removing our alias. Assuming there are no events on the
138             queue for us, we should shut down immediately.
139              
140             =cut
141              
142             sub shutdown { #{{{
143 0     0 1 0 $_[KERNEL]->alias_remove($_[HEAP]->{alias});
144             } #}}}
145              
146             =head2 build_handler
147              
148             return a closure that knows how to call the specified sub and post
149             the results back.
150              
151             =cut
152              
153             sub build_handler { #{{{
154 43     43 1 199 my ($package, $sub) = @_;
155              
156             my $ref = sub {
157 3     3   763 my ($kernel, $heap, $args_ref, $callback, $context, $sender) = @_[KERNEL, HEAP, ARG0, ARG1, ARG2, SENDER];
158 3         11 warn Dumper($kernel->alias_list($_[SESSION]));
159 3         594 DEBUG && print "Handler called for package=[$package], sub = [$sub]\n";
160            
161 3         9 my @sub_args = @$args_ref;
162 3         4 my $result;
163             #my $name = "${package}::${sub}";
164 3         3 DEBUG && print "handler: calling [$sub]\n";
165            
166 3 100 66     21 if (defined($context) and $context eq 'SCALAR') {
167             # scalar context. default if not supplied.
168 2         3 DEBUG && print "handler: calling in scalar context\n";
169            
170 2         2 $result = scalar &{$sub}(@sub_args);
  2         8  
171             } else {
172             # array context.
173 1         2 my @result;
174 1         2 DEBUG && print "handler: calling in array context\n";
175 1         3 @result = &{$sub}(@sub_args);
  1         6  
176 1         7 $result = \@result;
177             }
178              
179 3         91 $kernel->post($sender, $callback, $result);
180 3         226 return;
181 43         259 };
182              
183 43         132 return $ref;
184             } #}}}
185              
186             1;
187              
188             __END__