File Coverage

lib/Sub/Override.pm
Criterion Covered Total %
statement 49 49 100.0
branch 8 8 100.0
condition 5 5 100.0
subroutine 13 13 100.0
pod 3 3 100.0
total 78 78 100.0


line stmt bran cond sub pod time code
1             package Sub::Override;
2              
3 1     1   70124 use strict;
  1         2  
  1         126  
4 1     1   6 use warnings;
  1         1  
  1         145  
5              
6             our $VERSION = '0.09';
7              
8             my $_croak = sub {
9             local *__ANON__ = '__ANON__croak';
10             my ( $proto, $message ) = @_;
11             require Carp;
12             Carp::croak($message);
13             };
14              
15             my $_validate_code_slot = sub {
16             local *__ANON__ = '__ANON__validate_code_slot';
17             my ( $self, $code_slot ) = @_;
18 1     1   5 no strict 'refs';
  1         6  
  1         1011  
19             unless ( defined *{$code_slot}{CODE} ) {
20             $self->$_croak("Cannot replace non-existent sub ($code_slot)");
21             }
22             return $self;
23             };
24              
25             my $_validate_sub_ref = sub {
26             local *__ANON__ = '__ANON__validate_sub_ref';
27             my ( $self, $sub_ref ) = @_;
28             unless ( 'CODE' eq ref $sub_ref ) {
29             $self->$_croak("($sub_ref) must be a code reference");
30             }
31             return $self;
32             };
33              
34             my $_normalize_sub_name = sub {
35             local *__ANON__ = '__ANON__normalize_sub_name';
36             my ( $self, $subname ) = @_;
37             if ( ( $subname || '' ) =~ /^\w+$/ ) { # || "" for suppressing test warnings
38             my $package = do {
39             my $call_level = 0;
40             my $this_package;
41             while ( !$this_package || __PACKAGE__ eq $this_package ) {
42             ($this_package) = caller($call_level);
43             $call_level++;
44             }
45             $this_package;
46             };
47             $subname = "${package}::$subname";
48             }
49             return $subname;
50             };
51              
52             sub new {
53 4     4 1 5482 my $class = shift;
54 4         17 my $self = bless {}, $class;
55 4 100       20 $self->replace(@_) if @_;
56 4         10 return $self;
57             }
58              
59             # because override() was a better name and this is what it should have been
60             # called.
61             *override = *replace{CODE};
62              
63             sub replace {
64 11     11 1 4161 my ( $self, $sub_to_replace, $new_sub ) = @_;
65 11         1364 $sub_to_replace = $self->$_normalize_sub_name($sub_to_replace);
66 11         25 $self->$_validate_code_slot($sub_to_replace)->$_validate_sub_ref($new_sub);
67             {
68 1     1   6 no strict 'refs';
  1         2  
  1         35  
  9         15  
69 9   100     94 $self->{$sub_to_replace} ||= *$sub_to_replace{CODE};
70 1     1   5 no warnings 'redefine';
  1         1  
  1         175  
71 9         32 *$sub_to_replace = $new_sub;
72             }
73 9         29 return $self;
74             }
75              
76             sub restore {
77 7     7 1 10927 my ( $self, $name_of_sub ) = @_;
78 7         23 $name_of_sub = $self->$_normalize_sub_name($name_of_sub);
79 7 100 100     39 if ( !$name_of_sub && 1 == keys %$self ) {
80 1         3 ($name_of_sub) = keys %$self;
81             }
82 7 100       27 $self->$_croak(
83             sprintf 'You must provide the name of a sub to restore: (%s)' => join
84             ', ' => sort keys %$self )
85             unless $name_of_sub;
86 6 100       25 $self->$_croak("Cannot restore a sub that was not replaced ($name_of_sub)")
87             unless exists $self->{$name_of_sub};
88 1     1   5 no strict 'refs';
  1         1  
  1         23  
89 1     1   4 no warnings 'redefine';
  1         9  
  1         136  
90 4         31 *$name_of_sub = delete $self->{$name_of_sub};
91 4         12 return $self;
92             }
93              
94             sub DESTROY {
95 4     4   8835 my $self = shift;
96 1     1   4 no strict 'refs';
  1         2  
  1         31  
97 1     1   4 no warnings 'redefine';
  1         2  
  1         81  
98 4         614 while ( my ( $sub_name, $sub_ref ) = each %$self ) {
99 3         29 *$sub_name = $sub_ref;
100             }
101             }
102              
103             1;
104              
105             __END__