File Coverage

blib/lib/POE/Session/Attribute.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 POE::Session::Attribute ;
2              
3 1     1   24729 use strict ;
  1         2  
  1         34  
4 1     1   6 use warnings ;
  1         2  
  1         32  
5              
6 1     1   1723 use POE qw(Session) ;
  0            
  0            
7             use Attribute::Handlers ;
8             use Class::ISA ;
9             use Carp qw(croak) ;
10              
11             our $VERSION = '0.80';
12              
13             my $states = {} ;
14              
15             sub Object : ATTR(CODE) { goto &__mod_attr }
16             sub Package : ATTR(CODE) { goto &__mod_attr }
17             sub Inline : ATTR(CODE) { goto &__mod_attr }
18             sub state : ATTR(CODE) { goto &__mod_attr }
19              
20             sub __pkg_states {
21             my $pkg = $_[-1] ;
22             my $st = $states->{$pkg} ;
23              
24             if (!$st) {
25             $st = {} ;
26             for (Class::ISA::super_path($pkg)) {
27             if (my $pst = $states->{$_}) {
28             $st = { %$pst } ;
29             last ;
30             }
31             }
32             $states->{$pkg} = $st ;
33             }
34             return $st ;
35             }
36              
37             sub __mod_attr {
38             my ($pkg, $sym, $sub, $attr, $data, $phase) = @_ ;
39             my $handler = $sym ? *{$sym}{NAME} : $sub ;
40             my @states ;
41             $attr = 'Inline' if $attr eq 'state' ;
42              
43             if ($data) {
44             @states = ref($data) eq 'ARRAY' ? (@$data) : ($data) ;
45             } else {
46             @states = (*{$sym}{NAME}) or croak 'cannot determine state name' ;
47             }
48              
49             croak "cannot use unnamed $sub as $attr state"
50             if $attr ne 'Inline' && !$sym ;
51            
52             $pkg->__pkg_states->{$_} = [$attr, $handler] for @states ;
53             }
54              
55             sub new { bless {}, shift }
56              
57             sub spawn { shift->create(args => [@_]) }
58              
59             sub create {
60             my ($class, %opts) = @_ ;
61             my $self ;
62              
63             for (my $i = 0;
64             $class eq __PACKAGE__ || !$class->isa(__PACKAGE__); $i ++) {
65             my @c = caller($i) or last ;
66             $class = shift @c ;
67             }
68              
69             croak 'cannot determine caller package' if $class eq __PACKAGE__ ;
70              
71             while (my ($state, $ar) = each %{$class->__pkg_states}) {
72             my ($attr, $handler) = @$ar ;
73              
74             if ($attr eq 'Inline') {
75              
76             if (!ref($handler)) {
77             $handler = $class->can($handler) or
78             croak "$class can't `$handler'"
79             }
80             ($opts{inline_states} ||= {})->{$state} = $handler ;
81             } elsif ($attr eq 'Object') {
82             my $t = ($opts{object_states} ||= [
83             ($self ||= $class->new(@{$opts{args} || []})) => {}
84             ]) ;
85             $t->[1]->{$state} = $handler ;
86             } elsif ($attr eq 'Package') {
87             my $t = ($opts{package_states} ||= [$class => {}]) ;
88             $t->[1]->{$state} = $handler ;
89             } else {
90             die "unknown attribute `$attr' for method $class -> $handler" ;
91             }
92             }
93              
94             my $sid = POE::Session->create(%opts) ;
95             return (wantarray && $self) ? ($sid, $self) : $sid ;
96             }
97              
98             1;
99             __END__