File Coverage

blib/lib/Monkey/Patch/Action/Handle.pm
Criterion Covered Total %
statement 79 81 97.5
branch 23 24 95.8
condition 7 12 58.3
subroutine 14 15 93.3
pod 0 1 0.0
total 123 133 92.4


line stmt bran cond sub pod time code
1             package Monkey::Patch::Action::Handle;
2              
3 1     1   18 use 5.010;
  1         4  
  1         42  
4 1     1   5 use strict;
  1         3  
  1         27  
5 1     1   5 use warnings;
  1         2  
  1         26  
6              
7 1     1   5 use Scalar::Util qw(weaken);
  1         2  
  1         138  
8 1     1   810 use Sub::Delete;
  1         1139  
  1         325  
9              
10             our $VERSION = '0.04'; # VERSION
11              
12             my %stacks;
13              
14             sub __find_previous {
15 10     10   20 my ($stack, $code) = @_;
16 10     0   17 state $empty = sub {};
  0         0  
17              
18 10         34 for my $i (1..$#$stack) {
19 17 100       719 if ($stack->[$i][1] == $code) {
20 10   66     117 return $stack->[$i-1][2] // $stack->[$i-1][1];
21             }
22             }
23 0         0 $empty;
24             }
25              
26             sub new {
27 17     17 0 115 my ($class, %args) = @_;
28              
29 17         40 my $type = $args{-type};
30 17         43 delete $args{-type};
31              
32 17         32 my $code = $args{code};
33              
34 17         37 my $name = "$args{package}::$args{subname}";
35 17         21 my $stack;
36 17 100       53 if (!$stacks{$name}) {
37 3         10 $stacks{$name} = [];
38 3 100       18 push @{$stacks{$name}}, [sub => \&$name] if defined(&$name);
  1         5  
39             }
40 17         35 $stack = $stacks{$name};
41              
42 17         59 my $self = bless \%args, $class;
43              
44 1     1   7 no strict 'refs';
  1         2  
  1         44  
45 1     1   5 no warnings 'redefine';
  1         2  
  1         451  
46 17 100       77 if ($type eq 'sub') {
    100          
    50          
47 6         15 push @$stack, [$type => $code];
48 6         37 *$name = $code;
49             } elsif ($type eq 'delete') {
50 4     1   18 $code = sub {};
  1         7  
51 4         512 $args{code} = $code;
52 4         12 push @$stack, [$type, $code];
53 4         21 delete_sub $name;
54             } elsif ($type eq 'wrap') {
55 7         28 weaken($self);
56             my $wrapper = sub {
57 10     10   11825 my $ctx = {
58             package => $self->{package},
59             subname => $self->{subname},
60             extra => $self->{extra},
61             orig => __find_previous($stack, $self->{code}),
62             };
63 10         28 unshift @_, $ctx;
64 10         13 goto &{$self->{code}};
  10         49  
65 7         33 };
66 7         22 push @$stack, [$type => $code => $wrapper];
67 7         35 *$name = $wrapper;
68             }
69              
70 17         567 $self;
71             }
72              
73             sub DESTROY {
74 17     17   35244 my $self = shift;
75              
76 17         142 my $name = "$self->{package}::$self->{subname}";
77 17         34 my $stack = $stacks{$name};
78 17         28 my $code = $self->{code};
79              
80 17         52 for my $i (0..$#$stack) {
81 37 100       129 if($stack->[$i][1] == $code) {
82 17 100       53 if ($stack->[$i+1]) {
83             # check conflict
84 2 100 66     29 if ($stack->[$i+1][0] eq 'wrap' &&
      33        
85             ($i == 0 || $stack->[$i-1][0] eq 'delete')) {
86 1         3 my $p = $self->{patcher};
87 1         37 warn "Warning: unapplying patch to $name ".
88             "(applied in $p->[1]:$p->[2]) before a wrapping patch";
89             }
90             }
91              
92 1     1   6 no strict 'refs';
  1         2  
  1         40  
93 17 100       61 if ($i == @$stack-1) {
94 15 100       37 if ($i) {
95 1     1   6 no warnings 'redefine';
  1         2  
  1         176  
96 12 100       37 if ($stack->[$i-1][0] eq 'delete') {
97 2         81 delete_sub $name;
98             } else {
99 10   66     224 *$name = $stack->[$i-1][2] // $stack->[$i-1][1];
100             }
101             } else {
102 3         14 delete_sub $name;
103             }
104             }
105 17         635 splice @$stack, $i, 1;
106 17         193 last;
107             }
108             }
109             }
110              
111             1;
112              
113              
114             __END__
115             =pod
116              
117             =head1 NAME
118              
119             Monkey::Patch::Action::Handle
120              
121             =head1 VERSION
122              
123             version 0.04
124              
125             =for Pod::Coverage .*
126              
127             =head1 AUTHOR
128              
129             Steven Haryanto <stevenharyanto@gmail.com>
130              
131             =head1 COPYRIGHT AND LICENSE
132              
133             This software is copyright (c) 2012 by Steven Haryanto.
134              
135             This is free software; you can redistribute it and/or modify it under
136             the same terms as the Perl 5 programming language system itself.
137              
138             =cut
139