File Coverage

blib/lib/POE/Session.pm
Criterion Covered Total %
statement 210 249 84.3
branch 71 120 59.1
condition 5 12 41.6
subroutine 27 30 90.0
pod 8 8 100.0
total 321 419 76.6


line stmt bran cond sub pod time code
1             package POE::Session;
2              
3 169     169   1815 use strict;
  169         225  
  169         6398  
4              
5 169     169   677 use vars qw($VERSION);
  169         216  
  169         7666  
6             $VERSION = '1.365'; # NOTE - Should be #.### (three decimal places)
7              
8 169     169   794 use Carp qw(carp croak);
  169         268  
  169         10807  
9 169     169   877 use Errno;
  169         221  
  169         38171  
10              
11             sub SE_NAMESPACE () { 0 }
12             sub SE_OPTIONS () { 1 }
13             sub SE_STATES () { 2 }
14             sub SE_ID () { 3 }
15              
16             sub CREATE_ARGS () { 'args' }
17             sub CREATE_OPTIONS () { 'options' }
18             sub CREATE_INLINES () { 'inline_states' }
19             sub CREATE_PACKAGES () { 'package_states' }
20             sub CREATE_OBJECTS () { 'object_states' }
21             sub CREATE_HEAP () { 'heap' }
22              
23             sub OPT_TRACE () { 'trace' }
24             sub OPT_DEBUG () { 'debug' }
25             sub OPT_DEFAULT () { 'default' }
26              
27             sub EN_START () { '_start' }
28             sub EN_DEFAULT () { '_default' }
29             sub EN_SIGNAL () { '_signal' }
30              
31             #------------------------------------------------------------------------------
32             # Debugging flags for subsystems. They're done as double evals here
33             # so that someone may define them before using POE::Session (or POE),
34             # and the pre-defined value will take precedence over the defaults
35             # here.
36              
37             # Shorthand for defining an assert constant.
38              
39             sub _define_assert {
40 169     169   788 no strict 'refs';
  169         217  
  169         24100  
41 169     169   386 foreach my $name (@_) {
42              
43 169         631 local $^W = 0;
44              
45 169 50       230 next if defined *{"ASSERT_$name"}{CODE};
  169         1114  
46 169 50       220 if (defined *{"POE::Kernel::ASSERT_$name"}{CODE}) {
  169         867  
47             eval(
48 0         0 "sub ASSERT_$name () { " .
49 0         0 *{"POE::Kernel::ASSERT_$name"}{CODE}->() .
50             "}"
51             );
52 0 0       0 die if $@;
53             }
54             else {
55 169         5170 eval "sub ASSERT_$name () { ASSERT_DEFAULT }";
56 169 50       1042 die if $@;
57             }
58             }
59             }
60              
61             # Shorthand for defining a trace constant.
62             sub _define_trace {
63 169     169   779 no strict 'refs';
  169         216  
  169         33295  
64              
65 169     169   390 local $^W = 0;
66              
67 169         324 foreach my $name (@_) {
68 169 50       223 next if defined *{"TRACE_$name"}{CODE};
  169         939  
69 169 50       214 if (defined *{"POE::Kernel::TRACE_$name"}{CODE}) {
  169         933  
70             eval(
71 0         0 "sub TRACE_$name () { " .
72 0         0 *{"POE::Kernel::TRACE_$name"}{CODE}->() .
73             "}"
74             );
75 0 0       0 die if $@;
76             }
77             else {
78 169         5207 eval "sub TRACE_$name () { TRACE_DEFAULT }";
79 169 50       37176 die if $@;
80             }
81             }
82             }
83              
84             BEGIN {
85              
86             # ASSERT_DEFAULT changes the default value for other ASSERT_*
87             # constants. It inherits POE::Kernel's ASSERT_DEFAULT value, if
88             # it's present.
89              
90 169 50   169   725 unless (defined &ASSERT_DEFAULT) {
91 169 50       655 if (defined &POE::Kernel::ASSERT_DEFAULT) {
92 169         6512 eval( "sub ASSERT_DEFAULT () { " . &POE::Kernel::ASSERT_DEFAULT . " }" );
93             }
94             else {
95 0         0 eval 'sub ASSERT_DEFAULT () { 0 }';
96             }
97             };
98              
99             # TRACE_DEFAULT changes the default value for other TRACE_*
100             # constants. It inherits POE::Kernel's TRACE_DEFAULT value, if
101             # it's present.
102              
103 169 50       745 unless (defined &TRACE_DEFAULT) {
104 169 50       486 if (defined &POE::Kernel::TRACE_DEFAULT) {
105 169         4813 eval( "sub TRACE_DEFAULT () { " . &POE::Kernel::TRACE_DEFAULT . " }" );
106             }
107             else {
108 0         0 eval 'sub TRACE_DEFAULT () { 0 }';
109             }
110             };
111              
112 169         581 _define_assert("STATES");
113 169         409 _define_trace("DESTROY");
114             }
115              
116             #------------------------------------------------------------------------------
117             # Export constants into calling packages. This is evil; perhaps
118             # EXPORT_OK instead? The parameters NFA has in common with SESSION
119             # (and other sessions) must be kept at the same offsets as each-other.
120              
121             sub OBJECT () { 0 } # TODO - deprecate and replace with SELF
122             sub SESSION () { 1 }
123             sub KERNEL () { 2 }
124             sub HEAP () { 3 }
125             sub STATE () { 4 } # TODO - deprecate and replace with EVENT
126             sub SENDER () { 5 }
127             # NFA keeps its state in 6. unused in session so that args match up.
128             sub CALLER_FILE () { 7 }
129             sub CALLER_LINE () { 8 }
130             sub CALLER_STATE () { 9 } # TODO - deprecate and replace with CALLER_EVENT
131             sub ARG0 () { 10 }
132             sub ARG1 () { 11 }
133             sub ARG2 () { 12 }
134             sub ARG3 () { 13 }
135             sub ARG4 () { 14 }
136             sub ARG5 () { 15 }
137             sub ARG6 () { 16 }
138             sub ARG7 () { 17 }
139             sub ARG8 () { 18 }
140             sub ARG9 () { 19 }
141              
142             sub import {
143 359     359   897 my $package = caller();
144 169     169   919 no strict 'refs';
  169         258  
  169         376071  
145 359         675 *{ $package . '::OBJECT' } = \&OBJECT;
  359         1721  
146 359         578 *{ $package . '::SESSION' } = \&SESSION;
  359         1161  
147 359         481 *{ $package . '::KERNEL' } = \&KERNEL;
  359         1030  
148 359         479 *{ $package . '::HEAP' } = \&HEAP;
  359         1506  
149 359         517 *{ $package . '::STATE' } = \&STATE;
  359         1050  
150 359         486 *{ $package . '::SENDER' } = \&SENDER;
  359         989  
151 359         513 *{ $package . '::ARG0' } = \&ARG0;
  359         1446  
152 359         507 *{ $package . '::ARG1' } = \&ARG1;
  359         938  
153 359         449 *{ $package . '::ARG2' } = \&ARG2;
  359         1182  
154 359         473 *{ $package . '::ARG3' } = \&ARG3;
  359         927  
155 359         482 *{ $package . '::ARG4' } = \&ARG4;
  359         1054  
156 359         494 *{ $package . '::ARG5' } = \&ARG5;
  359         975  
157 359         455 *{ $package . '::ARG6' } = \&ARG6;
  359         919  
158 359         486 *{ $package . '::ARG7' } = \&ARG7;
  359         1073  
159 359         460 *{ $package . '::ARG8' } = \&ARG8;
  359         925  
160 359         503 *{ $package . '::ARG9' } = \&ARG9;
  359         883  
161 359         462 *{ $package . '::CALLER_FILE' } = \&CALLER_FILE;
  359         1005  
162 359         448 *{ $package . '::CALLER_LINE' } = \&CALLER_LINE;
  359         973  
163 359         475 *{ $package . '::CALLER_STATE' } = \&CALLER_STATE;
  359         10322  
164             }
165              
166             sub instantiate {
167 787     787 1 1351 my $type = shift;
168              
169 787 50       2031 croak "$type requires a working Kernel"
170             unless defined $POE::Kernel::poe_kernel;
171              
172 787         3079 my $self =
173             bless [ { }, # SE_NAMESPACE
174             { }, # SE_OPTIONS
175             { }, # SE_STATES
176             ], $type;
177              
178 787         962 if (ASSERT_STATES) {
179             $self->[SE_OPTIONS]->{+OPT_DEFAULT} = 1;
180             }
181              
182 787         2799 return $self;
183             }
184              
185             sub try_alloc {
186 1423     787 1 2551 my ($self, @args) = @_;
187             # Verify that the session has a special start state, otherwise how
188             # do we know what to do? Don't even bother registering the session
189             # if the start state doesn't exist.
190              
191 787 50       2117 if (exists $self->[SE_STATES]->{+EN_START}) {
192 787         3284 $POE::Kernel::poe_kernel->session_alloc($self, @args);
193             }
194             else {
195 0         0 carp( "discarding session ",
196             $POE::Kernel::poe_kernel->ID_session_to_id($self),
197             " - no '_start' state"
198             );
199 0         0 $self = undef;
200             }
201              
202 723         12592 $self;
203             }
204              
205             #------------------------------------------------------------------------------
206             # New style constructor. This uses less DWIM and more DWIS, and it's
207             # more comfortable for some folks; especially the ones who don't quite
208             # know WTM.
209              
210             sub create {
211 789     789 1 245467 my ($type, @params) = @_;
212 789         1073 my @args;
213              
214             # We treat the parameter list strictly as a hash. Rather than dying
215             # here with a Perl error, we'll catch it and blame it on the user.
216              
217 789 100       2429 if (@params & 1) {
218 2         215 croak "odd number of events/handlers (missing one or the other?)";
219             }
220 787         2814 my %params = @params;
221              
222 787         2850 my $self = $type->instantiate(\%params);
223              
224             # Process _start arguments. We try to do the right things with what
225             # we're given. If the arguments are a list reference, map its items
226             # to ARG0..ARGn; otherwise make whatever the heck it is be ARG0.
227              
228 787 100       2527 if (exists $params{+CREATE_ARGS}) {
229 347 50       1267 if (ref($params{+CREATE_ARGS}) eq 'ARRAY') {
230 347         471 push @args, @{$params{+CREATE_ARGS}};
  347         748  
231             }
232             else {
233 0         0 push @args, $params{+CREATE_ARGS};
234             }
235 347         805 delete $params{+CREATE_ARGS};
236             }
237              
238             # Process session options here. Several options may be set.
239              
240 787 100       1996 if (exists $params{+CREATE_OPTIONS}) {
241 4 50       15 if (ref($params{+CREATE_OPTIONS}) eq 'HASH') {
242 4         10 $self->[SE_OPTIONS] = $params{+CREATE_OPTIONS};
243             }
244             else {
245 0         0 croak "options for $type constructor is expected to be a HASH reference";
246             }
247 4         10 delete $params{+CREATE_OPTIONS};
248             }
249              
250             # Get down to the business of defining states.
251              
252 787         2985 while (my ($param_name, $param_value) = each %params) {
253              
254             # Inline states are expected to be state-name/coderef pairs.
255              
256 1165 100       3552 if ($param_name eq CREATE_INLINES) {
    100          
    100          
    50          
257 680 50       1914 croak "$param_name does not refer to a hash"
258             unless (ref($param_value) eq 'HASH');
259              
260 680         2409 while (my ($state, $handler) = each(%$param_value)) {
261 4709 50       7587 croak "inline state for '$state' needs a CODE reference"
262             unless (ref($handler) eq 'CODE');
263 4709         6423 $self->_register_state($state, $handler);
264             }
265             }
266              
267             # Package states are expected to be package-name/list-or-hashref
268             # pairs. If the second part of the pair is a arrayref, then the
269             # package methods are expected to be named after the states
270             # they'll handle. If it's a hashref, then the keys are state
271             # names and the values are package methods that implement them.
272              
273             elsif ($param_name eq CREATE_PACKAGES) {
274 200 50       557 croak "$param_name does not refer to an array"
275             unless (ref($param_value) eq 'ARRAY');
276 200 50       585 croak "the array for $param_name has an odd number of elements"
277             if (@$param_value & 1);
278              
279             # Copy the parameters so they aren't destroyed.
280 200         498 my @param_value = @$param_value;
281 200         988 while (my ($package, $handlers) = splice(@param_value, 0, 2)) {
282              
283             # TODO What do we do if the package name has some sort of
284             # blessing? Do we use the blessed thingy's package, or do we
285             # maybe complain because the user might have wanted to make
286             # object states instead?
287              
288             # An array of handlers. The array's items are passed through
289             # as both state names and package method names.
290              
291 103 100       2625 if (ref($handlers) eq 'ARRAY') {
    50          
292 100         340 foreach my $method (@$handlers) {
293 863         1229 $self->_register_state($method, $package, $method);
294             }
295             }
296              
297             # A hash of handlers. Hash keys are state names; values are
298             # package methods to implement them.
299              
300             elsif (ref($handlers) eq 'HASH') {
301 3         16 while (my ($state, $method) = each %$handlers) {
302 7         17 $self->_register_state($state, $package, $method);
303             }
304             }
305              
306             else {
307 0         0 croak( "states for package '$package' " .
308             "need to be a hash or array ref"
309             );
310             }
311             }
312             }
313              
314             # Object states are expected to be object-reference/
315             # list-or-hashref pairs. They must be passed to &create in a list
316             # reference instead of a hash reference because making object
317             # references into hash keys loses their blessings.
318              
319             elsif ($param_name eq CREATE_OBJECTS) {
320 104 50       236 croak "$param_name does not refer to an array"
321             unless (ref($param_value) eq 'ARRAY');
322 104 50       232 croak "the array for $param_name has an odd number of elements"
323             if (@$param_value & 1);
324              
325             # Copy the parameters so they aren't destroyed.
326 104         156 my @param_value = @$param_value;
327 104         367 while (@param_value) {
328 7         18 my ($object, $handlers) = splice(@param_value, 0, 2);
329              
330             # Verify that the object is an object. This may catch simple
331             # mistakes; or it may be overkill since it already checks that
332             # $param_value is a arrayref.
333              
334 7 50       27 carp "'$object' is not an object" unless ref($object);
335              
336             # An array of handlers. The array's items are passed through
337             # as both state names and object method names.
338              
339 7 100       30 if (ref($handlers) eq 'ARRAY') {
    50          
340 4         11 foreach my $method (@$handlers) {
341 13         24 $self->_register_state($method, $object, $method);
342             }
343             }
344              
345             # A hash of handlers. Hash keys are state names; values are
346             # package methods to implement them.
347              
348             elsif (ref($handlers) eq 'HASH') {
349 3         13 while (my ($state, $method) = each %$handlers) {
350 7         15 $self->_register_state($state, $object, $method);
351             }
352             }
353              
354             else {
355 0         0 croak "states for object '$object' need to be a hash or array ref";
356             }
357              
358             }
359             }
360              
361             # Import an external heap. This is a convenience, since it
362             # eliminates the need to connect _start options to heap values.
363              
364             elsif ($param_name eq CREATE_HEAP) {
365 181         693 $self->[SE_NAMESPACE] = $param_value;
366             }
367              
368             else {
369 0         0 croak "unknown $type parameter: $param_name";
370             }
371             }
372              
373 787         2300 return $self->try_alloc(@args);
374             }
375              
376             #------------------------------------------------------------------------------
377              
378             sub DESTROY {
379 543     543   1194 my $self = shift;
380              
381             # Session's data structures are destroyed through Perl's usual
382             # garbage collection. TRACE_DESTROY here just shows what's in the
383             # session before the destruction finishes.
384              
385 543         10224 TRACE_DESTROY and do {
386             require Data::Dumper;
387             POE::Kernel::_warn(
388             "----- Session $self Leak Check -----\n",
389             "-- Namespace (HEAP):\n",
390             Data::Dumper::Dumper($self->[SE_NAMESPACE]),
391             "-- Options:\n",
392             );
393             foreach (sort keys (%{$self->[SE_OPTIONS]})) {
394             POE::Kernel::_warn(" $_ = ", $self->[SE_OPTIONS]->{$_}, "\n");
395             }
396             POE::Kernel::_warn("-- States:\n");
397             foreach (sort keys (%{$self->[SE_STATES]})) {
398             POE::Kernel::_warn(" $_ = ", $self->[SE_STATES]->{$_}, "\n");
399             }
400             };
401             }
402              
403             #------------------------------------------------------------------------------
404              
405             sub _invoke_state {
406 8948     8696   67729 my ($self, $source_session, $state, $etc, $file, $line, $fromstate) = @_;
407              
408             # Trace the state invocation if tracing is enabled.
409              
410 8948 100       378714 if ($self->[SE_OPTIONS]->{+OPT_TRACE}) {
411 260         3097 POE::Kernel::_warn(
412             $POE::Kernel::poe_kernel->ID_session_to_id($self),
413             " -> $state (from $file at $line)\n"
414             );
415             }
416              
417             # The desired destination state doesn't exist in this session.
418             # Attempt to redirect the state transition to _default.
419              
420 8948 100       23643 unless (exists $self->[SE_STATES]->{$state}) {
421              
422             # There's no _default either; redirection's not happening today.
423             # Drop the state transition event on the floor, and optionally
424             # make some noise about it.
425              
426 566 100       2408 unless (exists $self->[SE_STATES]->{+EN_DEFAULT}) {
427 446 50       2070 $! = exists &Errno::ENOSYS ? &Errno::ENOSYS : &Errno::EIO;
428 446 100 66     1462 if ($self->[SE_OPTIONS]->{+OPT_DEFAULT} and $state ne EN_SIGNAL) {
429 253         2417 my $loggable_self =
430             $POE::Kernel::poe_kernel->_data_alias_loggable($self->ID);
431 1601         10313 POE::Kernel::_warn(
432             "a '$state' event was sent from $file at $line to $loggable_self ",
433             "but $loggable_self has neither a handler for it ",
434             "nor one for _default\n"
435             );
436             }
437 194         441 return undef;
438             }
439              
440             # If we get this far, then there's a _default state to redirect
441             # the transition to. Trace the redirection.
442              
443 122 50       315 if ($self->[SE_OPTIONS]->{+OPT_TRACE}) {
444 0         0 POE::Kernel::_warn(
445             $POE::Kernel::poe_kernel->ID_session_to_id($self),
446             " -> $state redirected to _default\n"
447             );
448             }
449              
450             # Transmogrify the original state transition into a corresponding
451             # _default invocation. ARG1 is copied from $etc so it can't be
452             # altered from a distance.
453              
454 122         344 $etc = [ $state, [@$etc] ];
455 122         185 $state = EN_DEFAULT;
456             }
457              
458             # If we get this far, then the state can be invoked. So invoke it
459             # already!
460              
461             # Inline states are invoked this way.
462              
463 8502 100       23627 if (ref($self->[SE_STATES]->{$state}) eq 'CODE') {
464 5975         27295 return $self->[SE_STATES]->{$state}->
465             ( undef, # object
466             $self, # session
467             $POE::Kernel::poe_kernel, # kernel
468             $self->[SE_NAMESPACE], # heap
469             $state, # state
470             $source_session, # sender
471             undef, # unused #6
472             $file, # caller file name
473             $line, # caller file line
474             $fromstate, # caller state
475             @$etc # args
476             );
477             }
478              
479             # Package and object states are invoked this way.
480              
481 2527         2575 my ($object, $method) = @{$self->[SE_STATES]->{$state}};
  2527         5616  
482             return
483 2527         12443 $object->$method # package/object (implied)
484             ( $self, # session
485             $POE::Kernel::poe_kernel, # kernel
486             $self->[SE_NAMESPACE], # heap
487             $state, # state
488             $source_session, # sender
489             undef, # unused #6
490             $file, # caller file name
491             $line, # caller file line
492             $fromstate, # caller state
493             @$etc # args
494             );
495             }
496              
497             #------------------------------------------------------------------------------
498             # Add, remove or replace states in the session.
499              
500             sub _register_state {
501 7625     7625   10267 my ($self, $name, $handler, $method) = @_;
502 7625 100       12963 $method = $name unless defined $method;
503              
504             # Deprecate _signal.
505             # RC 2004-09-07 - Decided to leave this in because it blames
506             # problems with _signal on the user for using it. It should
507             # probably go away after a little while, but not during the other
508             # deprecations.
509              
510 7625 50       12018 if ($name eq EN_SIGNAL) {
511              
512             # Report the problem outside POE.
513 0         0 my $caller_level = 0;
514 0         0 local $Carp::CarpLevel = 1;
515 0         0 while ( (caller $caller_level)[0] =~ /^POE::/ ) {
516 0         0 $caller_level++;
517 0         0 $Carp::CarpLevel++;
518             }
519              
520             croak(
521 0         0 ",----- DEPRECATION ERROR -----\n",
522             "| The _signal event is deprecated. Please use sig() to register\n",
523             "| an explicit signal handler instead.\n",
524             "`-----------------------------\n",
525             );
526             }
527              
528             # There is a handler, so try to define the state. This replaces an
529             # existing state.
530              
531 7625 100       10560 if ($handler) {
532              
533             # Coderef handlers are inline states.
534              
535 6700 100       12780 if (ref($handler) eq 'CODE') {
    50          
536 5810 50 66     12920 carp( "redefining handler for event($name) for session(",
537             $POE::Kernel::poe_kernel->ID_session_to_id($self), ")"
538             )
539             if ( $self->[SE_OPTIONS]->{+OPT_DEBUG} &&
540             (exists $self->[SE_STATES]->{$name})
541             );
542 5810         21849 $self->[SE_STATES]->{$name} = $handler;
543             }
544              
545             # Non-coderef handlers may be package or object states. See if
546             # the method belongs to the handler.
547              
548             elsif ($handler->can($method)) {
549 890 50 33     1620 carp( "redefining handler for event($name) for session(",
550             $POE::Kernel::poe_kernel->ID_session_to_id($self), ")"
551             )
552             if ( $self->[SE_OPTIONS]->{+OPT_DEBUG} &&
553             (exists $self->[SE_STATES]->{$name})
554             );
555 890         3559 $self->[SE_STATES]->{$name} = [ $handler, $method ];
556             }
557              
558             # Something's wrong. This code also seems wrong, since
559             # ref($handler) can't be 'CODE'.
560              
561             else {
562 0 0 0     0 if ( (ref($handler) eq 'CODE') and
563             $self->[SE_OPTIONS]->{+OPT_TRACE}
564             ) {
565 0         0 carp( $POE::Kernel::poe_kernel->ID_session_to_id($self),
566             " : handler for event($name) is not a proper ref - not registered"
567             )
568             }
569             else {
570 0 0       0 unless ($handler->can($method)) {
571 0 0       0 if (length ref($handler)) {
572 0         0 croak "object $handler does not have a '$method' method"
573             }
574             else {
575 0         0 croak "package $handler does not have a '$method' method";
576             }
577             }
578             }
579             }
580             }
581              
582             # No handler. Delete the state!
583              
584             else {
585 925         8474 delete $self->[SE_STATES]->{$name};
586             }
587             }
588              
589             #------------------------------------------------------------------------------
590             # Return the session's ID. This is a thunk into POE::Kernel, where
591             # the session ID really lies.
592              
593             sub _set_id {
594 795     795   1366 my ($self, $id) = @_;
595 795         2216 $self->[SE_ID] = $id;
596             }
597              
598             sub ID {
599 833252     833252 1 1793895 return shift()->[SE_ID];
600             }
601              
602             #------------------------------------------------------------------------------
603             # Set or fetch session options.
604              
605             sub option {
606 8     8 1 2246 my $self = shift;
607 8         11 my %return_values;
608              
609             # Options are set in pairs.
610              
611 8         22 while (@_ >= 2) {
612 4         9 my ($flag, $value) = splice(@_, 0, 2);
613 4         9 $flag = lc($flag);
614              
615             # If the value is defined, then set the option.
616              
617 4 50       9 if (defined $value) {
618              
619             # Change some handy values into boolean representations. This
620             # clobbers the user's original values for the sake of DWIM-ism.
621              
622 4 50       11 ($value = 1) if ($value =~ /^(on|yes|true)$/i);
623 4 50       10 ($value = 0) if ($value =~ /^(no|off|false)$/i);
624              
625 4         12 $return_values{$flag} = $self->[SE_OPTIONS]->{$flag};
626 4         11 $self->[SE_OPTIONS]->{$flag} = $value;
627             }
628              
629             # Remove the option if the value is undefined.
630              
631             else {
632 0         0 $return_values{$flag} = delete $self->[SE_OPTIONS]->{$flag};
633             }
634             }
635              
636             # If only one option is left, then there's no value to set, so we
637             # fetch its value.
638              
639 8 100       18 if (@_) {
640 4         8 my $flag = lc(shift);
641 4 50       27 $return_values{$flag} =
642             ( exists($self->[SE_OPTIONS]->{$flag})
643             ? $self->[SE_OPTIONS]->{$flag}
644             : undef
645             );
646             }
647              
648             # If only one option was set or fetched, then return it as a scalar.
649             # Otherwise return it as a hash of option names and values.
650              
651 8         21 my @return_keys = keys(%return_values);
652 8 50       18 if (@return_keys == 1) {
653 8         34 return $return_values{$return_keys[0]};
654             }
655             else {
656 0         0 return \%return_values;
657             }
658             }
659              
660             # Fetch the session's heap. In rare cases, libraries may need to
661             # break encapsulation this way, probably also using
662             # $kernel->get_current_session as an accessory to the crime.
663              
664             sub get_heap {
665 2     2 1 6 my $self = shift;
666 2         11 return $self->[SE_NAMESPACE];
667             }
668              
669             #------------------------------------------------------------------------------
670             # Create an anonymous sub that, when called, posts an event back to a
671             # session. This maps postback references (stringified; blessing, and
672             # thus refcount, removed) to parent session IDs. Members are set when
673             # postbacks are created, and postbacks' DESTROY methods use it to
674             # perform the necessary cleanup when they go away. Thanks to njt for
675             # steering me right on this one.
676              
677             my %anonevent_parent_id;
678             my %anonevent_weakened;
679              
680             # I assume that when the postback owner loses all reference to it,
681             # they are done posting things back to us. That's when the postback's
682             # DESTROY is triggered, and referential integrity is maintained.
683              
684             sub POE::Session::AnonEvent::DESTROY {
685 15     15   667 my $self = shift;
686 15         61 my $parent_id = delete $anonevent_parent_id{$self};
687 15 50       55 unless (delete $anonevent_weakened{$self}) {
688 15         79 $POE::Kernel::poe_kernel->refcount_decrement( $parent_id, 'anon_event' );
689             }
690             }
691              
692             sub POE::Session::AnonEvent::weaken {
693 0     0   0 my $self = shift;
694 0 0       0 unless ($anonevent_weakened{$self}) {
695 0         0 my $parent_id = $anonevent_parent_id{$self};
696 0         0 $POE::Kernel::poe_kernel->refcount_decrement( $parent_id, 'anon_event' );
697 0         0 $anonevent_weakened{$self} = 1;
698             }
699 0         0 return $self;
700             }
701              
702             # Tune postbacks depending on variations in toolkit behavior.
703              
704             BEGIN {
705             # Tk blesses its callbacks internally, so we need to wrap our
706             # blessed callbacks in unblessed ones. Otherwise our postback's
707             # DESTROY method probably won't be called.
708 169 50   169   785 if (exists $INC{'Tk.pm'}) {
709 0         0 eval 'sub USING_TK () { 1 }';
710             }
711             else {
712 169         45835 eval 'sub USING_TK () { 0 }';
713             }
714             };
715              
716             # Create a postback closure, maintaining referential integrity in the
717             # process. The next step is to give it to something that expects to
718             # be handed a callback.
719              
720             sub postback {
721 7     7 1 54 my ($self, $event, @etc) = @_;
722 7         32 my $id = $POE::Kernel::poe_kernel->ID_session_to_id($self);
723              
724             my $postback = bless sub {
725 7     7   480 $POE::Kernel::poe_kernel->post( $id, $event, [ @etc ], [ @_ ] );
726 7         32 return 0;
727 7         53 }, 'POE::Session::AnonEvent';
728              
729 7         36 $anonevent_parent_id{$postback} = $id;
730 7         26 $POE::Kernel::poe_kernel->refcount_increment( $id, 'anon_event' );
731              
732             # Tk blesses its callbacks, so we must present one that isn't
733             # blessed. Otherwise Tk's blessing would divert our DESTROY call to
734             # its own, and that's not right.
735              
736 7     0   8 return sub { $postback->(@_) } if USING_TK;
  0         0  
737 7         40 return $postback;
738             }
739              
740             # Create a synchronous callback closure. The return value will be
741             # passed to whatever is handed the callback.
742              
743             sub callback {
744 8     8 1 28 my ($self, $event, @etc) = @_;
745 8         32 my $id = $POE::Kernel::poe_kernel->ID_session_to_id($self);
746              
747             my $callback = bless sub {
748 8     8   503 $POE::Kernel::poe_kernel->call( $id, $event, [ @etc ], [ @_ ] );
749 8         60 }, 'POE::Session::AnonEvent';
750              
751 8         29 $anonevent_parent_id{$callback} = $id;
752 8         36 $POE::Kernel::poe_kernel->refcount_increment( $id, 'anon_event' );
753              
754             # Tk blesses its callbacks, so we must present one that isn't
755             # blessed. Otherwise Tk's blessing would divert our DESTROY call to
756             # its own, and that's not right.
757              
758 8     0   8 return sub { $callback->(@_) } if USING_TK;
  0            
759 8         40 return $callback;
760             }
761              
762             1;
763              
764             __END__