File Coverage

blib/lib/POE/Session.pm
Criterion Covered Total %
statement 210 249 84.3
branch 70 120 58.3
condition 5 12 41.6
subroutine 27 30 90.0
pod 8 8 100.0
total 320 419 76.3


line stmt bran cond sub pod time code
1             package POE::Session;
2              
3 194     194   2459 use strict;
  194         1202  
  194         7373  
4              
5 194     194   1002 use vars qw($VERSION);
  194         354  
  194         9334  
6             $VERSION = '1.370'; # NOTE - Should be #.### (three decimal places)
7              
8 194     194   1689 use Carp qw(carp croak);
  194         687  
  194         10311  
9 194     194   2288 use Errno;
  194         502  
  194         37445  
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 194     194   899 no strict 'refs';
  194         412  
  194         32768  
41 194     194   524 foreach my $name (@_) {
42              
43 194         751 local $^W = 0;
44              
45 194 50       277 next if defined *{"ASSERT_$name"}{CODE};
  194         1196  
46 194 50       251 if (defined *{"POE::Kernel::ASSERT_$name"}{CODE}) {
  194         1086  
47             eval(
48             "sub ASSERT_$name () { " .
49 0         0 *{"POE::Kernel::ASSERT_$name"}{CODE}->() .
  0         0  
50             "}"
51             );
52 0 0       0 die if $@;
53             }
54             else {
55 194         5873 eval "sub ASSERT_$name () { ASSERT_DEFAULT }";
56 194 50       1052 die if $@;
57             }
58             }
59             }
60              
61             # Shorthand for defining a trace constant.
62             sub _define_trace {
63 194     194   1643 no strict 'refs';
  194         377  
  194         41695  
64              
65 194     194   443 local $^W = 0;
66              
67 194         305 foreach my $name (@_) {
68 194 50       285 next if defined *{"TRACE_$name"}{CODE};
  194         858  
69 194 50       315 if (defined *{"POE::Kernel::TRACE_$name"}{CODE}) {
  194         930  
70             eval(
71             "sub TRACE_$name () { " .
72 0         0 *{"POE::Kernel::TRACE_$name"}{CODE}->() .
  0         0  
73             "}"
74             );
75 0 0       0 die if $@;
76             }
77             else {
78 194         5771 eval "sub TRACE_$name () { TRACE_DEFAULT }";
79 194 50       31134 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 194 50   194   1495 unless (defined &ASSERT_DEFAULT) {
91 194 50       813 if (defined &POE::Kernel::ASSERT_DEFAULT) {
92 194         10125 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 194 50       1236 unless (defined &TRACE_DEFAULT) {
104 194 50       551 if (defined &POE::Kernel::TRACE_DEFAULT) {
105 194         6040 eval( "sub TRACE_DEFAULT () { " . &POE::Kernel::TRACE_DEFAULT . " }" );
106             }
107             else {
108 0         0 eval 'sub TRACE_DEFAULT () { 0 }';
109             }
110             };
111              
112 194         767 _define_assert("STATES");
113 194         429 _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 411     411   2453 my $package = caller();
144 194     194   1076 no strict 'refs';
  194         890  
  194         428818  
145 411         1842 *{ $package . '::OBJECT' } = \&OBJECT;
  411         2095  
146 411         2071 *{ $package . '::SESSION' } = \&SESSION;
  411         1829  
147 411         867 *{ $package . '::KERNEL' } = \&KERNEL;
  411         2017  
148 411         767 *{ $package . '::HEAP' } = \&HEAP;
  411         1672  
149 411         779 *{ $package . '::STATE' } = \&STATE;
  411         1293  
150 411         685 *{ $package . '::SENDER' } = \&SENDER;
  411         2387  
151 411         1438 *{ $package . '::ARG0' } = \&ARG0;
  411         2930  
152 411         800 *{ $package . '::ARG1' } = \&ARG1;
  411         1327  
153 411         532 *{ $package . '::ARG2' } = \&ARG2;
  411         1233  
154 411         530 *{ $package . '::ARG3' } = \&ARG3;
  411         1088  
155 411         507 *{ $package . '::ARG4' } = \&ARG4;
  411         1181  
156 411         497 *{ $package . '::ARG5' } = \&ARG5;
  411         1058  
157 411         494 *{ $package . '::ARG6' } = \&ARG6;
  411         1033  
158 411         504 *{ $package . '::ARG7' } = \&ARG7;
  411         910  
159 411         526 *{ $package . '::ARG8' } = \&ARG8;
  411         1035  
160 411         462 *{ $package . '::ARG9' } = \&ARG9;
  411         807  
161 411         472 *{ $package . '::CALLER_FILE' } = \&CALLER_FILE;
  411         984  
162 411         518 *{ $package . '::CALLER_LINE' } = \&CALLER_LINE;
  411         1058  
163 411         548 *{ $package . '::CALLER_STATE' } = \&CALLER_STATE;
  411         10296  
164             }
165              
166             sub instantiate {
167 828     828 1 1839 my $type = shift;
168              
169 828 50       2171 croak "$type requires a working Kernel"
170             unless defined $POE::Kernel::poe_kernel;
171              
172 828         2470 my $self =
173             bless [ { }, # SE_NAMESPACE
174             { }, # SE_OPTIONS
175             { }, # SE_STATES
176             ], $type;
177              
178 828         1349 if (ASSERT_STATES) {
179             $self->[SE_OPTIONS]->{+OPT_DEFAULT} = 1;
180             }
181              
182 828         3749 return $self;
183             }
184              
185             sub try_alloc {
186 1492     828 1 2881 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 828 50       1689 if (exists $self->[SE_STATES]->{+EN_START}) {
192 828         3863 $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 763         21280 $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 830     830 1 7207418 my ($type, @params) = @_;
212 830         1480 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 830 100       2791 if (@params & 1) {
218 2         249 croak "odd number of events/handlers (missing one or the other?)";
219             }
220 828         5029 my %params = @params;
221              
222 828         4414 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 828 100       2531 if (exists $params{+CREATE_ARGS}) {
229 370 50       1560 if (ref($params{+CREATE_ARGS}) eq 'ARRAY') {
230 370         635 push @args, @{$params{+CREATE_ARGS}};
  370         1029  
231             }
232             else {
233 0         0 push @args, $params{+CREATE_ARGS};
234             }
235 370         677 delete $params{+CREATE_ARGS};
236             }
237              
238             # Process session options here. Several options may be set.
239              
240 828 100       2000 if (exists $params{+CREATE_OPTIONS}) {
241 4 50       18 if (ref($params{+CREATE_OPTIONS}) eq 'HASH') {
242 4         11 $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 828         3175 while (my ($param_name, $param_value) = each %params) {
253              
254             # Inline states are expected to be state-name/coderef pairs.
255              
256 1228 100       3728 if ($param_name eq CREATE_INLINES) {
    100          
    100          
    50          
257 721 50       2366 croak "$param_name does not refer to a hash"
258             unless (ref($param_value) eq 'HASH');
259              
260 721         2473 while (my ($state, $handler) = each(%$param_value)) {
261 5061 50       7239 croak "inline state for '$state' needs a CODE reference"
262             unless (ref($handler) eq 'CODE');
263 5061         6968 $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       684 croak "$param_name does not refer to an array"
275             unless (ref($param_value) eq 'ARRAY');
276 200 50       474 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         410 my @param_value = @$param_value;
281 200         795 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       470 if (ref($handlers) eq 'ARRAY') {
    50          
292 100         466 foreach my $method (@$handlers) {
293 863         1472 $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         17 while (my ($state, $method) = each %$handlers) {
302 7         18 $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       177 croak "$param_name does not refer to an array"
321             unless (ref($param_value) eq 'ARRAY');
322 104 50       193 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         125 my @param_value = @$param_value;
327 104         393 while (@param_value) {
328 7         20 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       20 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       29 if (ref($handlers) eq 'ARRAY') {
    50          
340 4         9 foreach my $method (@$handlers) {
341 13         22 $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         17 $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 203         668 $self->[SE_NAMESPACE] = $param_value;
366             }
367              
368             else {
369 0         0 croak "unknown $type parameter: $param_name";
370             }
371             }
372              
373 828         2192 return $self->try_alloc(@args);
374             }
375              
376             #------------------------------------------------------------------------------
377              
378             sub DESTROY {
379 570     570   1389 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 570         11849 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 8834     8568   100195 my ($self, $source_session, $state, $etc, $file, $line, $fromstate) = @_;
407              
408             # Trace the state invocation if tracing is enabled.
409              
410 8834 100       491867 if ($self->[SE_OPTIONS]->{+OPT_TRACE}) {
411 274         1265 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 8834 100       19995 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 527 100       1884 unless (exists $self->[SE_STATES]->{+EN_DEFAULT}) {
427 407 50       1842 $! = exists &Errno::ENOSYS ? &Errno::ENOSYS : &Errno::EIO;
428 407 100 66     1163 if ($self->[SE_OPTIONS]->{+OPT_DEFAULT} and $state ne EN_SIGNAL) {
429 267         2367 my $loggable_self =
430             $POE::Kernel::poe_kernel->_data_alias_loggable($self->ID);
431 1755         5423 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 141         369 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       313 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         306 $etc = [ $state, [@$etc] ];
455 122         234 $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 8427 100       19549 if (ref($self->[SE_STATES]->{$state}) eq 'CODE') {
464 6016         34115 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 2411         2736 my ($object, $method) = @{$self->[SE_STATES]->{$state}};
  2411         4323  
482             return
483 2411         9842 $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 8074     8074   17790 my ($self, $name, $handler, $method) = @_;
502 8074 100       12597 $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 8074 50       12438 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 8074 100       10650 if ($handler) {
532              
533             # Coderef handlers are inline states.
534              
535 7116 100       14723 if (ref($handler) eq 'CODE') {
    50          
536             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 6226 50 66     9815 (exists $self->[SE_STATES]->{$name})
541             );
542 6226         30064 $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             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 890 0 33     1762 (exists $self->[SE_STATES]->{$name})
554             );
555 890         3951 $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 958         8893 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 836     836   1648 my ($self, $id) = @_;
595 836         2279 $self->[SE_ID] = $id;
596             }
597              
598             sub ID {
599 833722     833722 1 1230931 return shift()->[SE_ID];
600             }
601              
602             #------------------------------------------------------------------------------
603             # Set or fetch session options.
604              
605             sub option {
606 8     8 1 2242 my $self = shift;
607 8         14 my %return_values;
608              
609             # Options are set in pairs.
610              
611 8         23 while (@_ >= 2) {
612 4         13 my ($flag, $value) = splice(@_, 0, 2);
613 4         10 $flag = lc($flag);
614              
615             # If the value is defined, then set the option.
616              
617 4 50       11 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       12 ($value = 0) if ($value =~ /^(no|off|false)$/i);
624              
625 4         11 $return_values{$flag} = $self->[SE_OPTIONS]->{$flag};
626 4         13 $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       20 if (@_) {
640 4         12 my $flag = lc(shift);
641             $return_values{$flag} =
642             ( exists($self->[SE_OPTIONS]->{$flag})
643 4 50       16 ? $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         23 my @return_keys = keys(%return_values);
652 8 50       27 if (@return_keys == 1) {
653 8         29 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 5 my $self = shift;
666 2         26 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   887 my $self = shift;
686 15         56 my $parent_id = delete $anonevent_parent_id{$self};
687 15 50       53 unless (delete $anonevent_weakened{$self}) {
688 15         60 $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 194 50   194   1209 if (exists $INC{'Tk.pm'}) {
709 0         0 eval 'sub USING_TK () { 1 }';
710             }
711             else {
712 194         50962 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 68 my ($self, $event, @etc) = @_;
722 7         59 my $id = $POE::Kernel::poe_kernel->ID_session_to_id($self);
723              
724             my $postback = bless sub {
725 7     7   311 $POE::Kernel::poe_kernel->post( $id, $event, [ @etc ], [ @_ ] );
726 7         24 return 0;
727 7         60 }, 'POE::Session::AnonEvent';
728              
729 7         39 $anonevent_parent_id{$postback} = $id;
730 7         27 $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   10 return sub { $postback->(@_) } if USING_TK;
  0         0  
737 7         32 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 34 my ($self, $event, @etc) = @_;
745 8         30 my $id = $POE::Kernel::poe_kernel->ID_session_to_id($self);
746              
747             my $callback = bless sub {
748 8     8   388 $POE::Kernel::poe_kernel->call( $id, $event, [ @etc ], [ @_ ] );
749 8         87 }, 'POE::Session::AnonEvent';
750              
751 8         32 $anonevent_parent_id{$callback} = $id;
752 8         30 $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   10 return sub { $callback->(@_) } if USING_TK;
  0            
759 8         40 return $callback;
760             }
761              
762             1;
763              
764             __END__