File Coverage

blib/lib/Config/PackageGlobal/OO.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package Config::PackageGlobal::OO;
4              
5 1     1   29819 use strict;
  1         2  
  1         34  
6 1     1   5 use warnings;
  1         1  
  1         20  
7              
8 1     1   4 use Carp ();
  1         10  
  1         12  
9              
10 1     1   363 use Context::Handle ();
  0            
  0            
11              
12             our $VERSION = "0.02";
13              
14             sub new {
15             my ( $class, $pkg, @methods ) = @_;
16              
17             my %methods;
18             foreach my $method ( @methods ) {
19             no strict 'refs';
20             $methods{$method} = \&{ $pkg . "::" . "$method" };
21             defined &{$methods{$method}}
22             || Carp::croak("The function '$method' does not exist in $pkg");
23             }
24              
25             bless {
26             pkg => $pkg,
27             methods => \%methods,
28             conf => { },
29             conf_subs => { },
30             }, $class;
31             }
32              
33             my %sub_cache;
34             sub AUTOLOAD {
35             my ( $self, @args ) = @_;
36             my ( $method ) = ( our $AUTOLOAD =~ /([^:]+)$/ );
37              
38             if ( my $sub = $self->{methods}{$method} ) {
39             my $prev = $self->_set_conf( $self->{conf} );
40              
41             local $@;
42             my $rv = Context::Handle->new(sub {
43             eval { $sub->( @args ) };
44             });
45              
46             $self->_set_conf( $prev );
47             die $@ if $@;
48              
49             # $rv->return barfs here, either because of the goto or because of the AUTOLOAD
50             # bus error in autoload, illegal instruction in goto
51             return $rv->value;
52             } else {
53             unless ( exists $self->{conf}{$method} ) {
54             # initial value is copied from package
55             $self->{conf}{$method} = $self->_conf_accessor( $method );
56             }
57              
58             $self->{conf}{$method} = \@args if @args;
59              
60             return scalar @{ $self->{conf}{$method} } != 1 ? @{ $self->{conf}{$method} } : $self->{conf}{$method}[0];
61             }
62             }
63              
64             sub _set_conf {
65             my ( $self, $conf ) = @_;
66              
67             my %prev;
68              
69             foreach my $key ( keys %$conf ) {
70             $prev{$key} = $self->_set_conf_key( $key, $conf->{$key} );
71             }
72              
73             \%prev;
74             }
75              
76             sub _conf_accessor {
77             my ( $self, $key ) = ( shift, shift );
78              
79             my $accessor = $sub_cache{$self->{pkg}}{$key} ||= do {
80             no strict 'refs';
81             my $sub;
82             my $sym = $self->{pkg} . '::' . $key;
83             my $symtable = \%{ $self->{pkg} . '::' };
84              
85             if ( exists $symtable->{$key} ) {
86             if ( *$sym{CODE} ) {
87             my $orig = \&{$sym};
88             $sub = sub { [ $orig->(@_) ] }
89             } elsif ( *$sym{ARRAY} ) {
90             my $var = \@{$sym};
91             $sub = sub {
92             @$var = @_ if @_;
93             [ @$var ];
94             }
95             } else {
96             my $var = \${$sym};
97             $sub = sub {
98             $$var = shift if @_;
99             [ $$var ];
100             };
101             }
102             } elsif ( exists $symtable->{"get_$key"} ) {
103             my ( $get, $set ) = map { \&{ $self->{pkg} . '::' . $_ . '_' . $key } } qw/get set/;
104             $sub = sub {
105             $set->( @_ ) if @_;
106             [ $get->() ];
107             };
108             } else {
109             Carp::croak("The field '$key' does not exist in $self->{pkg}");
110             }
111              
112             $sub_cache{$self->{pkg}}{$key} = $sub;
113             };
114              
115             $accessor->( @_ );
116             }
117              
118             sub _set_conf_key {
119             my ( $self, $key, $new ) = @_;
120              
121             my $prev = $self->_conf_accessor( $key );
122             $self->_conf_accessor( $key, @$new );
123             return $prev;
124             }
125              
126             sub DESTROY { } # shush autoload
127              
128             __PACKAGE__;
129              
130             __END__