File Coverage

blib/lib/autodie/Scope/GuardStack.pm
Criterion Covered Total %
statement 32 32 100.0
branch n/a
condition 2 3 66.6
subroutine 8 8 100.0
pod 2 2 100.0
total 44 45 97.7


line stmt bran cond sub pod time code
1             package autodie::Scope::GuardStack;
2              
3 59     59   254 use strict;
  59         84  
  59         1985  
4 59     59   242 use warnings;
  59         80  
  59         1477  
5              
6 59     59   22749 use autodie::Scope::Guard;
  59         108  
  59         16621  
7              
8             # ABSTRACT: Hook stack for managing scopes via %^H
9             our $VERSION = '2.27'; # VERSION
10              
11             my $H_KEY_STEM = __PACKAGE__ . '/guard';
12             my $COUNTER = 0;
13              
14             # This code schedules the cleanup of subroutines at the end of
15             # scope. It's directly inspired by chocolateboy's excellent
16             # Scope::Guard module.
17              
18             sub new {
19 110     110 1 211 my ($class) = @_;
20              
21 110         526 return bless([], $class);
22             }
23              
24             sub push_hook {
25 138     138 1 243 my ($self, $hook) = @_;
26 138         575 my $h_key = $H_KEY_STEM . ($COUNTER++);
27 138         199 my $size = @{$self};
  138         331  
28             $^H{$h_key} = autodie::Scope::Guard->new(sub {
29             # Pop the stack until we reach the right size
30             # - this may seem weird, but it is to avoid relying
31             # on "destruction order" of keys in %^H.
32             #
33             # Example:
34             # {
35             # use autodie; # hook 1
36             # no autodie; # hook 2
37             # use autodie; # hook 3
38             # }
39             #
40             # Here we want call hook 3, then hook 2 and finally hook 1.
41             # Any other order could have undesired consequences.
42             #
43             # Suppose hook 2 is destroyed first, it will pop hook 3 and
44             # then hook 2. hook 3 will then be destroyed, but do nothing
45             # since its "frame" was already popped and finally hook 1
46             # will be popped and take its own frame with it.
47             #
48             # We need to check that $self still exists since things can get weird
49             # during global destruction.
50 133   66 133   568 $self->_pop_hook while $self && @{$self} > $size;
  266         6378  
51 138         1243 });
52 138         232 push(@{$self}, [$hook, $h_key]);
  138         470  
53 138         352 return;
54             }
55              
56             sub _pop_hook {
57 133     133   213 my ($self) = @_;
58 133         193 my ($hook, $key) = @{ pop(@{$self}) };
  133         296  
  133         355  
59 133         534 my $ref = delete($^H{$key});
60 133         368 $hook->();
61 133         1128 return;
62             }
63              
64             sub DESTROY {
65 105     105   189 my ($self) = @_;
66              
67             # To be honest, I suspect @{$self} will always be empty here due
68             # to the subs in %^H having references to the stack (which would
69             # keep the stack alive until those have been destroyed). Anyhow,
70             # it never hurt to be careful.
71 105         171 $self->_pop_hook while @{$self};
  105         357  
72 105         75486 return;
73             }
74              
75             1;
76              
77             __END__
78              
79             =head1 NAME
80              
81             autodie::Scope::GuardStack - Hook stack for managing scopes via %^H
82              
83             =head1 SYNOPSIS
84              
85             use autodie::Scope::GuardStack;
86             my $stack = autodie::Scope::GuardStack->new
87             $^H{'my-key'} = $stack;
88              
89             $stack->push_hook(sub {});
90              
91             =head1 DESCRIPTION
92              
93             This class is a stack of hooks to be called in the right order as
94             scopes go away. The stack is only useful when inserted into C<%^H>
95             and will pop hooks as their "scope" is popped. This is useful for
96             uninstalling or reinstalling subs in a namespace as a pragma goes
97             out of scope.
98              
99             Due to how C<%^H> works, this class is only useful during the
100             compilation phase of a perl module and relies on the internals of how
101             perl handles references in C<%^H>. This module is not a part of
102             autodie's public API.
103              
104             =head2 Methods
105              
106             =head3 new
107              
108             my $stack = autodie::Scope::GuardStack->new;
109              
110             Creates a new C<autodie::Scope::GuardStack>. The stack is initially
111             empty and must be inserted into C<%^H> by the creator.
112              
113             =head3 push_hook
114              
115             $stack->push_hook(sub {});
116              
117             Add a sub to the stack. The sub will be called once the current
118             compile-time "scope" is left. Multiple hooks can be added per scope
119              
120             =head1 AUTHOR
121              
122             Copyright 2013, Niels Thykier E<lt>niels@thykier.netE<gt>
123              
124             =head1 LICENSE
125              
126             This module is free software. You may distribute it under the
127             same terms as Perl itself.