File Coverage

blib/lib/Class/Component/Component/Autocall/SingletonMethod.pm
Criterion Covered Total %
statement 59 59 100.0
branch 8 10 80.0
condition n/a
subroutine 11 11 100.0
pod 0 2 0.0
total 78 82 95.1


line stmt bran cond sub pod time code
1             package Class::Component::Component::Autocall::SingletonMethod;
2              
3 3     3   18 use strict;
  3         5  
  3         109  
4 3     3   17 use warnings;
  3         7  
  3         100  
5              
6 3     3   16 use Carp::Clan qw/Class::Component/;
  3         42  
  3         24  
7              
8             my $instance_counter = 0;
9             my $alloc_map = {};
10             sub register_method {
11 10     10 0 51 my($self, @methods) = @_;
12              
13 10         69 $self->NEXT( register_method => @methods );
14              
15 10         19 my %add_methods;
16 10         40 while (my($method, $plugin) = splice @methods, 0, 2) {
17 10         41 $add_methods{$method} = $plugin
18             }
19 10 50       25 return unless %add_methods;
20              
21 10         13 my $singleton_class;
22 10         17 my $pkg = ref($self);
23 10 100       41 unless ($pkg =~ /::_Singletons::\d+$/) {
24 5         11 $singleton_class = "$pkg\::_Singletons::";
25 5         6 my $count;
26 5         16 for my $c (0..$instance_counter) {
27 3     3   1063 no strict 'refs';
  3         4  
  3         247  
28 5 100       25 next if $alloc_map->{"$singleton_class$c"};
29 3         7 $count = $c;
30 3         8 last;
31             }
32 5 100       97 $count = ++$instance_counter unless defined $count;
33 5         9 $singleton_class .= $count;
34 5         13 $alloc_map->{$singleton_class} = 1;
35            
36 3     3   65 { no strict 'refs'; @{"$singleton_class\::ISA"} = $pkg; }
  3         6  
  3         314  
  5         7  
  5         8  
  5         210  
37 5 50       27 bless $self, $singleton_class if ref($self);
38 5         22 Class::Component::Implement->component_isa_list->{$singleton_class} = Class::Component::Implement->component_isa_list->{$pkg};
39             } else {
40 5         9 $singleton_class = $pkg;
41             }
42              
43 10         27 for my $method (keys %add_methods) {
44 3     3   17 no strict 'refs';
  3         11  
  3         423  
45 10     6   38 *{"$singleton_class\::$method"} = sub { shift->call($method, @_) };
  10         153  
  6         2320  
46             }
47             }
48              
49             sub remove_method {
50 3     3 0 7 my($self, @methods) = @_;
51 3         15 $self->NEXT( remove_method => @methods );
52 3         10 while (my($method, $plugin) = splice @methods, 0, 2) {
53 3     3   16 no strict 'refs';
  3         5  
  3         380  
54 4         6 delete ${ref($self) . "::"}{$method};
  4         34  
55             }
56             }
57              
58             sub DESTROY {
59 2     2   407 my $self = shift;
60 2         3 $self->remove_method(%{ $self->class_component_methods });
  2         6  
61 2         15 $self->class_component_clear_isa_list;
62 2         134 delete $alloc_map->{ref $self};
63             }
64              
65             1;