File Coverage

blib/lib/Class/C3/Componentised/ApplyHooks.pm
Criterion Covered Total %
statement 62 62 100.0
branch 13 14 92.8
condition n/a
subroutine 7 7 100.0
pod 2 2 100.0
total 84 85 98.8


line stmt bran cond sub pod time code
1             package Class::C3::Componentised::ApplyHooks;
2              
3 3     3   129735 use strict;
  3         9  
  3         170  
4 3     3   21 use warnings;
  3         246  
  3         7910  
5              
6             our %Before;
7             our %After;
8              
9             sub BEFORE_APPLY (&) {
10 6     6 1 2546 push @{$Before{scalar caller}}, $_[0];
  6         23  
11 6         130 $Class::C3::Componentised::APPLICATOR_FOR{scalar caller} = __PACKAGE__;
12             }
13             sub AFTER_APPLY (&) {
14 4     4 1 77 push @{$After {scalar caller}}, $_[0];
  4         15  
15 4         81 $Class::C3::Componentised::APPLICATOR_FOR{scalar caller} = __PACKAGE__;
16             }
17              
18             sub _apply_component_to_class {
19 4     4   12 my ($me, $comp, $target, $apply) = @_;
20 4         5 my @heritage = @{mro::get_linear_isa($comp)};
  4         21  
21              
22 7         16 my @before = map {
23 4         10 my $to_run = $Before{$_};
24 7 100       32 ($to_run?[$_,$to_run]:())
25             } @heritage;
26              
27 4         9 for my $todo (@before) {
28 6         25 my ($parent, $fn) = @$todo;
29 6         12 for my $f (reverse @$fn) {
30 11         144 $target->$f($parent)
31             }
32             }
33              
34 4         47 $apply->();
35              
36 7         17 my @after = map {
37 4         16 my $to_run = $After{$_};
38 7 100       27 ($to_run?[$_,$to_run]:())
39             } @heritage;
40              
41 4         18 for my $todo (reverse @after) {
42 5         25 my ($parent, $fn) = @$todo;
43 5         12 for my $f (@$fn) {
44 9         50 $target->$f($parent)
45             }
46             }
47             }
48              
49             {
50 3     3   28 no strict 'refs';
  3         6  
  3         1821  
51             sub import {
52 5     5   4155 my ($from, @args) = @_;
53 5         29 my $to = caller;
54              
55 5         130 my $default = 1;
56 5         10 my $i = 0;
57 5         9 my $skip = 0;
58 5         10 my @import;
59 5         13 for my $arg (@args) {
60 8 100       26 if ($skip) {
61 3         5 $skip--;
62 3         5 $i++;
63             next
64 3         7 }
65              
66 5 100       35 if ($arg eq '-before_apply') {
    100          
    50          
67 2         6 $default = 0;
68 2         4 $skip = 1;
69 2         4 push @{$Before{$to}}, $args[$i + 1];
  2         11  
70 2         6 $Class::C3::Componentised::APPLICATOR_FOR{$to} = $from;
71             } elsif ($arg eq '-after_apply') {
72 1         3 $default = 0;
73 1         2 $skip = 1;
74 1         1 push @{$After{$to}}, $args[$i + 1];
  1         6  
75 1         5 $Class::C3::Componentised::APPLICATOR_FOR{$to} = $from;
76             } elsif ($arg =~ /^BEFORE_APPLY|AFTER_APPLY$/) {
77 2         3 $default = 0;
78 2         4 push @import, $arg
79             }
80 5         9 $i++;
81             }
82 5 100       24 @import = qw(BEFORE_APPLY AFTER_APPLY)
83             if $default;
84              
85 5         35 *{"$to\::$_"} = \&{"$from\::$_"} for @import
  8         1243  
  8         226  
86             }
87             }
88              
89             1;
90              
91             =head1 NAME
92              
93             Class::C3::Componentised::ApplyHooks
94              
95             =head1 SYNOPSIS
96              
97             package MyComponent;
98              
99             our %statistics;
100              
101             use Class::C3::Componentised::ApplyHooks
102             -before_apply => sub {
103             my ($class, $component) = @_;
104              
105             push @{$statistics{$class}}, '-before_apply';
106             },
107             -after_apply => sub {
108             my ($class, $component) = @_;
109              
110             push @{$statistics{$class}}, '-after_apply';
111             }, qw(BEFORE_APPLY AFTER_APPLY);
112              
113             BEFORE_APPLY { push @{$statistics{$class}}, 'BEFORE_APPLY' };
114             AFTER_APPLY { push @{$statistics{$class}}, 'AFTER_APPLY' };
115             AFTER_APPLY { use Devel::Dwarn; Dwarn %statistics };
116              
117             1;
118              
119             =head1 DESCRIPTION
120              
121             This package allows a given component to run methods on the class that is being
122             injected into before or after the component is injected. Note from the
123             L that all C may be run more than once.
124              
125             =head1 IMPORT ACTION
126              
127             Both import actions simply run a list of coderefs that will be passed the class
128             that is being acted upon and the component that is being added to the class.
129              
130             =head1 IMPORT OPTIONS
131              
132             =head2 -before_apply
133              
134             Adds a before apply action for the current component without importing
135             any subroutines into your namespace.
136              
137             =head2 -after_apply
138              
139             Adds an after apply action for the current component without importing
140             any subroutines into your namespace.
141              
142             =head1 EXPORTED SUBROUTINES
143              
144             =head2 BEFORE_APPLY
145              
146             BEFORE_APPLY { warn "about to apply $_[1] to class $_[0]" };
147              
148             Adds a before apply action for the current component.
149              
150             =head2 AFTER_APPLY
151              
152             AFTER_APPLY { warn "just applied $_[1] to class $_[0]" };
153              
154             Adds an after apply action for the current component.
155              
156             =cut