File Coverage

blib/lib/Class/MOP/Method/Wrapped.pm
Criterion Covered Total %
statement 59 60 98.3
branch 6 8 75.0
condition 6 9 66.6
subroutine 58 58 100.0
pod 8 8 100.0
total 137 143 95.8


line stmt bran cond sub pod time code
1             package Class::MOP::Method::Wrapped;
2             our $VERSION = '2.2206';
3              
4 450     280720   3278 use strict;
  450         968  
  450         13794  
5 450     141662   2304 use warnings;
  450         1031  
  450         12269  
6              
7 450     84111   2467 use Scalar::Util 'blessed';
  450         1037  
  450         25040  
8 450     75502   2905 use Sub::Util 1.40 'set_subname';
  450         8941  
  450         22561  
9              
10 450     64579   3121 use parent 'Class::MOP::Method';
  450         1151  
  450         2987  
11              
12             # NOTE:
13             # this ugly beast is the result of trying
14             # to micro optimize this as much as possible
15             # while not completely loosing maintainability.
16             # At this point it's "fast enough", after all
17             # you can't get something for nothing :)
18             my $_build_wrapped_method = sub {
19             my $modifier_table = shift;
20             my ($before, $after, $around) = (
21             $modifier_table->{before},
22             $modifier_table->{after},
23             $modifier_table->{around},
24             );
25             if (@$before && @$after) {
26             $modifier_table->{cache} = sub {
27             for my $c (@$before) { $c->(@_) };
28             my @rval;
29             ((defined wantarray) ?
30             ((wantarray) ?
31             (@rval = $around->{cache}->(@_))
32             :
33             ($rval[0] = $around->{cache}->(@_)))
34             :
35             $around->{cache}->(@_));
36             for my $c (@$after) { $c->(@_) };
37             return unless defined wantarray;
38             return wantarray ? @rval : $rval[0];
39             }
40             }
41             elsif (@$before) {
42             $modifier_table->{cache} = sub {
43             for my $c (@$before) { $c->(@_) };
44             return $around->{cache}->(@_);
45             }
46             }
47             elsif (@$after) {
48             $modifier_table->{cache} = sub {
49             my @rval;
50             ((defined wantarray) ?
51             ((wantarray) ?
52             (@rval = $around->{cache}->(@_))
53             :
54             ($rval[0] = $around->{cache}->(@_)))
55             :
56             $around->{cache}->(@_));
57             for my $c (@$after) { $c->(@_) };
58             return unless defined wantarray;
59             return wantarray ? @rval : $rval[0];
60             }
61             }
62             else {
63             $modifier_table->{cache} = $around->{cache};
64             }
65             };
66              
67             sub wrap {
68 15530     70476 1 52420 my ( $class, $code, %params ) = @_;
69              
70 15530 100 66     84424 (blessed($code) && $code->isa('Class::MOP::Method'))
71             || $class->_throw_exception( CanOnlyWrapBlessedCode => params => \%params,
72             class => $class,
73             code => $code
74             );
75              
76 15529         127788 my $modifier_table = {
77             cache => undef,
78             orig => $code->body,
79             before => [],
80             after => [],
81             around => {
82             cache => $code->body,
83             methods => [],
84             },
85             };
86 15529         45224 $_build_wrapped_method->($modifier_table);
87              
88             # get these from the original unless explicitly overridden
89 15529   66     39797 my $pkg_name = $params{package_name} || $code->package_name;
90 15529   66     36791 my $method_name = $params{name} || $code->name;
91              
92             return $class->SUPER::wrap(
93             sub {
94             my $wrapped
95             = set_subname( "${pkg_name}::_wrapped_${method_name}" =>
96 262201     312263   1722482 $modifier_table->{cache} );
        303615      
        299408      
        293680      
        292438      
        289553      
        294472      
        288517      
        461746      
        517037      
        483071      
        479134      
        643524      
        821135      
        660153      
        489633      
        481932      
        480078      
        528515      
        475040      
        472874      
        468542      
        466923      
        168670      
        35118      
        7907      
        5947      
        5247      
        5247      
        5247      
        5247      
        2651      
        2651      
        2041      
        2041      
        2041      
        2041      
        2041      
        2041      
        2041      
        2041      
        2041      
        2041      
97 262201         627048 return $wrapped->(@_) ;
98             },
99 15529         115672 package_name => $pkg_name,
100             name => $method_name,
101             original_method => $code,
102             modifier_table => $modifier_table,
103             );
104             }
105              
106             sub _new {
107 15529     220756   28295 my $class = shift;
108 15529 100       35023 return Class::MOP::Class->initialize($class)->new_object(@_)
109             if $class ne __PACKAGE__;
110              
111 15528 50       35383 my $params = @_ == 1 ? $_[0] : {@_};
112              
113             return bless {
114             # inherited from Class::MOP::Method
115             'body' => $params->{body},
116             'associated_metaclass' => $params->{associated_metaclass},
117             'package_name' => $params->{package_name},
118             'name' => $params->{name},
119             'original_method' => $params->{original_method},
120              
121             # defined in this class
122             'modifier_table' => $params->{modifier_table}
123 15528         98993 } => $class;
124             }
125              
126             sub get_original_method {
127 2     32155 1 15 my $code = shift;
128 2         16 $code->original_method;
129             }
130              
131             sub add_before_modifier {
132 157     24235 1 1878 my $code = shift;
133 157         283 my $modifier = shift;
134 157         291 unshift @{$code->{'modifier_table'}->{before}} => $modifier;
  157         590  
135 157         548 $_build_wrapped_method->($code->{'modifier_table'});
136             }
137              
138             sub before_modifiers {
139 4     20871 1 8 my $code = shift;
140 4         8 return @{$code->{'modifier_table'}->{before}};
  4         32  
141             }
142              
143             sub add_after_modifier {
144 57     18758 1 1299 my $code = shift;
145 57         112 my $modifier = shift;
146 57         125 push @{$code->{'modifier_table'}->{after}} => $modifier;
  57         276  
147 57         223 $_build_wrapped_method->($code->{'modifier_table'});
148             }
149              
150             sub after_modifiers {
151 4     16539 1 12 my $code = shift;
152 4         7 return @{$code->{'modifier_table'}->{after}};
  4         28  
153             }
154              
155             {
156             # NOTE:
157             # this is another possible candidate for
158             # optimization as well. There is an overhead
159             # associated with the currying that, if
160             # eliminated might make around modifiers
161             # more manageable.
162             my $compile_around_method = sub {{
163             my $f1 = pop;
164             return $f1 unless @_;
165             my $f2 = pop;
166             push @_, sub { $f2->( $f1, @_ ) };
167             redo;
168             }};
169              
170             sub add_around_modifier {
171 15341     29710 1 29877 my $code = shift;
172 15341         23060 my $modifier = shift;
173 15341         23081 unshift @{$code->{'modifier_table'}->{around}->{methods}} => $modifier;
  15341         47810  
174             $code->{'modifier_table'}->{around}->{cache} = $compile_around_method->(
175 15341         43482 @{$code->{'modifier_table'}->{around}->{methods}},
176             $code->{'modifier_table'}->{orig}
177 15341         24548 );
178 15341         35193 $_build_wrapped_method->($code->{'modifier_table'});
179             }
180             }
181              
182             sub around_modifiers {
183 4     10889 1 10 my $code = shift;
184 4         7 return @{$code->{'modifier_table'}->{around}->{methods}};
  4         39  
185             }
186              
187             sub _make_compatible_with {
188 5     8724   12 my $self = shift;
189 5         12 my ($other) = @_;
190              
191             # XXX: this is pretty gross. the issue here is that CMOP::Method::Wrapped
192             # objects are subclasses of CMOP::Method, but when we get to moose, they'll
193             # need to be compatible with Moose::Meta::Method, which isn't possible. the
194             # right solution here is to make ::Wrapped into a role that gets applied to
195             # whatever the method_metaclass happens to be and get rid of
196             # wrapped_method_metaclass entirely, but that's not going to happen until
197             # we ditch cmop and get roles into the bootstrapping, so. i'm not
198             # maintaining the previous behavior of turning them into instances of the
199             # new method_metaclass because that's equally broken, and at least this way
200             # any issues will at least be detectable and potentially fixable. -doy
201 5 50       198 return $self unless $other->_is_compatible_with($self->_real_ref_name);
202              
203 0           return $self->SUPER::_make_compatible_with(@_);
204             }
205              
206             1;
207              
208             # ABSTRACT: Method Meta Object for methods with before/after/around modifiers
209              
210             __END__
211              
212             =pod
213              
214             =encoding UTF-8
215              
216             =head1 NAME
217              
218             Class::MOP::Method::Wrapped - Method Meta Object for methods with before/after/around modifiers
219              
220             =head1 VERSION
221              
222             version 2.2206
223              
224             =head1 DESCRIPTION
225              
226             This is a L<Class::MOP::Method> subclass which implements before,
227             after, and around method modifiers.
228              
229             =head1 METHODS
230              
231             =head2 Class::MOP::Method::Wrapped->wrap($metamethod, %options)
232              
233             This is the constructor. It accepts a L<Class::MOP::Method> object and
234             a hash of options.
235              
236             The options are:
237              
238             =over 4
239              
240             =item * name
241              
242             The method name (without a package name). This will be taken from the
243             provided L<Class::MOP::Method> object if it is not provided.
244              
245             =item * package_name
246              
247             The package name for the method. This will be taken from the provided
248             L<Class::MOP::Method> object if it is not provided.
249              
250             =item * associated_metaclass
251              
252             An optional L<Class::MOP::Class> object. This is the metaclass for the
253             method's class.
254              
255             =back
256              
257             =head2 $metamethod->get_original_method
258              
259             This returns the L<Class::MOP::Method> object that was passed to the
260             constructor.
261              
262             =head2 $metamethod->add_before_modifier($code)
263              
264             =head2 $metamethod->add_after_modifier($code)
265              
266             =head2 $metamethod->add_around_modifier($code)
267              
268             These methods all take a subroutine reference and apply it as a
269             modifier to the original method.
270              
271             =head2 $metamethod->before_modifiers
272              
273             =head2 $metamethod->after_modifiers
274              
275             =head2 $metamethod->around_modifiers
276              
277             These methods all return a list of subroutine references which are
278             acting as the specified type of modifier.
279              
280             =head1 AUTHORS
281              
282             =over 4
283              
284             =item *
285              
286             Stevan Little <stevan@cpan.org>
287              
288             =item *
289              
290             Dave Rolsky <autarch@urth.org>
291              
292             =item *
293              
294             Jesse Luehrs <doy@cpan.org>
295              
296             =item *
297              
298             Shawn M Moore <sartak@cpan.org>
299              
300             =item *
301              
302             יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
303              
304             =item *
305              
306             Karen Etheridge <ether@cpan.org>
307              
308             =item *
309              
310             Florian Ragwitz <rafl@debian.org>
311              
312             =item *
313              
314             Hans Dieter Pearcey <hdp@cpan.org>
315              
316             =item *
317              
318             Chris Prather <chris@prather.org>
319              
320             =item *
321              
322             Matt S Trout <mstrout@cpan.org>
323              
324             =back
325              
326             =head1 COPYRIGHT AND LICENSE
327              
328             This software is copyright (c) 2006 by Infinity Interactive, Inc.
329              
330             This is free software; you can redistribute it and/or modify it under
331             the same terms as the Perl 5 programming language system itself.
332              
333             =cut