File Coverage

blib/lib/Sub/Versive.pm
Criterion Covered Total %
statement 61 67 91.0
branch 7 16 43.7
condition n/a
subroutine 12 12 100.0
pod 0 3 0.0
total 80 98 81.6


line stmt bran cond sub pod time code
1             package Sub::Versive;
2              
3             require 5.6.1;
4 1     1   508 use strict;
  1         1  
  1         25  
5 1     1   6 use warnings;
  1         1  
  1         28  
6 1     1   12 use Carp;
  1         5  
  1         87  
7 1     1   111826 use Devel::Peek q/CvGV/;
  1         756  
  1         8  
8 1     1   124 no warnings 'redefine'; # Oh yes.
  1         3  
  1         1146  
9              
10             require Exporter;
11              
12             our @ISA = qw(Exporter);
13              
14             # Items to export into callers namespace by default. Note: do not export
15             # names by default without a very good reason. Use EXPORT_OK instead.
16             # Do not simply export all your public functions/methods/constants.
17              
18             # This allows declaration use Sub::Versive ':all';
19             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
20             # will save memory.
21             our %EXPORT_TAGS = ( 'all' => [ qw(
22             append_to_sub
23             prepend_to_sub
24             builtinify
25             ) ] );
26              
27             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
28              
29             our @EXPORT = qw(
30            
31             );
32             our $VERSION = '0.01';
33              
34              
35             # This *is* pure evil.
36              
37             sub _prep {
38 4     4   7 my $orig = shift;
39 4         6 my $ref;
40 4 50       11 if (ref $orig eq "CODE") {
41 4         7 $ref = $orig;
42 4         17 $orig = CvGV($orig);
43 4         32 $orig =~ s/.//;
44             } else {
45 0         0 $ref = eval "\\\&$orig";# This is evil too.
46             }
47 4 100       15 if (not exists $Sub::Version::stash{$orig}) {
48 2         9 $Sub::Version::stash{$orig}{orig} = $ref;
49 2         9 my $code = 'sub '.$orig.' {
50             for (@{$Sub::Version::stash{"'.$orig.'"}{precall}}) {
51             my @x = $_->(@_);
52             return @x if ($@); # Signal a return
53             }
54             my @rv = $Sub::Version::stash{"'.$orig.'"}{orig}->(@_);
55             for (@{$Sub::Version::stash{"'.$orig.'"}{postcall}}) {
56             my @x = $_->(@_);
57             return @x if ($@); # Signal a return
58             }
59             return @rv;
60             }';
61 2 50   1   450 eval $code; $@ and die "$code:$@";
  2 0   1   10  
  1 50       31  
  1 50       6  
  0 0       0  
  0         0  
  1         5  
  1         56  
  1         4  
  3         8  
  3         143  
  1         3  
  1         48  
  1         5  
  1         6  
  1         70  
  1         6  
  1         61  
  1         6  
  0         0  
  0         0  
  1         4  
62             }
63 4         17 return ($ref, $orig);
64             }
65             sub append_to_sub (&\&) {
66 3     3 0 23 my ($newcode, $orig) = @_;
67 3         4 my $ref;
68 3         8 ($ref, $orig) = _prep($orig);
69 3         5 push @{$Sub::Version::stash{$orig}{postcall}}, $newcode;
  3         13  
70             };
71              
72             sub prepend_to_sub (&\&) {
73 1     1 0 56 my ($newcode, $orig) = @_;
74 1         3 my $ref;
75 1         4 ($ref, $orig) = _prep($orig);
76 1         4 unshift @{$Sub::Version::stash{$orig}{precall}}, $newcode;
  1         7  
77             };
78              
79             # Let's go, guys!
80              
81             if (defined &UNIVERSAL::AUTOLOAD) {
82             prepend_to_sub {
83             my $foo = $UNIVERSAL::AUTOLOAD;
84             $foo =~ s/.*:://;
85             if (exists $Sub::Versive::builtins{$foo}) {
86             $@="Die alien swine!";
87             return $Sub::Versive::builtins{$foo}->(@_);
88             }
89             } &UNIVERSAL::AUTOLOAD;
90             }
91             else {
92 1 50   1   62 eval <<'EOF';
  1         7  
  1         23  
  1         6  
  0         0  
93             sub UNIVERSAL::AUTOLOAD {
94             my $foo = $UNIVERSAL::AUTOLOAD;
95             $foo =~ s/.*:://;
96             if (exists $Sub::Versive::builtins{$foo}) {
97             return $Sub::Versive::builtins{$foo}->(@_);
98             }
99             # Fake it.
100             croak "Undefined subroutine $UNIVERSAL::AUTOLOAD called";
101             }
102             EOF
103             }
104              
105             sub builtinify (\&) {
106 1     1 0 6 my $sub = shift;
107 1         6 my $whence = CvGV($sub);
108 1         11 $whence =~ s/.*:://;
109 1         5 $Sub::Versive::builtins{$whence} = $sub;
110             }
111             1;
112             __END__