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.2205';
3              
4 450     280719   3392 use strict;
  450         979  
  450         13902  
5 450     141662   2341 use warnings;
  450         1042  
  450         12320  
6              
7 450     84111   2492 use Scalar::Util 'blessed';
  450         1061  
  450         25347  
8 450     75502   3023 use Sub::Util 1.40 'set_subname';
  450         8919  
  450         22509  
9              
10 450     64579   3151 use parent 'Class::MOP::Method';
  450         1175  
  450         3021  
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 52425 my ( $class, $code, %params ) = @_;
69              
70 15530 100 66     84135 (blessed($code) && $code->isa('Class::MOP::Method'))
71             || $class->_throw_exception( CanOnlyWrapBlessedCode => params => \%params,
72             class => $class,
73             code => $code
74             );
75              
76 15529         128439 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         45313 $_build_wrapped_method->($modifier_table);
87              
88             # get these from the original unless explicitly overridden
89 15529   66     36606 my $pkg_name = $params{package_name} || $code->package_name;
90 15529   66     36468 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 262200     312262   1725232 $modifier_table->{cache} );
        303614      
        299407      
        293679      
        292437      
        289552      
        294471      
        288516      
        461744      
        517035      
        483069      
        479132      
        643521      
        821131      
        660150      
        489631      
        481930      
        480076      
        528513      
        475038      
        472872      
        468540      
        466921      
        168670      
        35118      
        7907      
        5947      
        5247      
        5247      
        5247      
        5247      
        2651      
        2651      
        2041      
        2041      
        2041      
        2041      
        2041      
        2041      
        2041      
        2041      
        2041      
        2041      
97 262200         628511 return $wrapped->(@_) ;
98             },
99 15529         117505 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     220755   28130 my $class = shift;
108 15529 100       35257 return Class::MOP::Class->initialize($class)->new_object(@_)
109             if $class ne __PACKAGE__;
110              
111 15528 50       35742 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         98781 } => $class;
124             }
125              
126             sub get_original_method {
127 2     32155 1 19 my $code = shift;
128 2         20 $code->original_method;
129             }
130              
131             sub add_before_modifier {
132 157     24235 1 2155 my $code = shift;
133 157         308 my $modifier = shift;
134 157         307 unshift @{$code->{'modifier_table'}->{before}} => $modifier;
  157         563  
135 157         526 $_build_wrapped_method->($code->{'modifier_table'});
136             }
137              
138             sub before_modifiers {
139 4     20871 1 13 my $code = shift;
140 4         8 return @{$code->{'modifier_table'}->{before}};
  4         38  
141             }
142              
143             sub add_after_modifier {
144 57     18758 1 1358 my $code = shift;
145 57         127 my $modifier = shift;
146 57         123 push @{$code->{'modifier_table'}->{after}} => $modifier;
  57         272  
147 57         229 $_build_wrapped_method->($code->{'modifier_table'});
148             }
149              
150             sub after_modifiers {
151 4     16539 1 9 my $code = shift;
152 4         11 return @{$code->{'modifier_table'}->{after}};
  4         52  
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 30121 my $code = shift;
172 15341         22712 my $modifier = shift;
173 15341         23140 unshift @{$code->{'modifier_table'}->{around}->{methods}} => $modifier;
  15341         47441  
174             $code->{'modifier_table'}->{around}->{cache} = $compile_around_method->(
175 15341         44102 @{$code->{'modifier_table'}->{around}->{methods}},
176             $code->{'modifier_table'}->{orig}
177 15341         24858 );
178 15341         35319 $_build_wrapped_method->($code->{'modifier_table'});
179             }
180             }
181              
182             sub around_modifiers {
183 4     10889 1 10 my $code = shift;
184 4         6 return @{$code->{'modifier_table'}->{around}->{methods}};
  4         40  
185             }
186              
187             sub _make_compatible_with {
188 5     8724   11 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       28 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.2205
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