File Coverage

blib/lib/Class/MOP/Mixin/HasMethods.pm
Criterion Covered Total %
statement 98 98 100.0
branch 37 38 97.3
condition 36 41 87.8
subroutine 21 21 100.0
pod 0 8 0.0
total 192 206 93.2


line stmt bran cond sub pod time code
1             package Class::MOP::Mixin::HasMethods;
2             our $VERSION = '2.2206';
3              
4 450     450   79670 use strict;
  450         971  
  450         13540  
5 450     450   2377 use warnings;
  450         1010  
  450         13136  
6              
7 450     450   207627 use Class::MOP::Method::Meta;
  450         1290  
  450         15504  
8              
9 450     450   3129 use Scalar::Util 'blessed', 'reftype';
  450         1041  
  450         24321  
10 450     450   2819 use Sub::Util 1.40 'set_subname';
  450         9839  
  450         21069  
11              
12 450     450   2854 use parent 'Class::MOP::Mixin';
  450         1018  
  450         2257  
13              
14 10021     10021   67264 sub _meta_method_class { 'Class::MOP::Method::Meta' }
15              
16             sub _add_meta_method {
17 13044     13044   26540 my $self = shift;
18 13044         28436 my ($name) = @_;
19 13044 50       75443 my $existing_method = $self->can('find_method_by_name')
20             ? $self->find_method_by_name($name)
21             : $self->get_method($name);
22 13044 100 100     42802 return if $existing_method
23             && $existing_method->isa($self->_meta_method_class);
24 12939         44008 $self->add_method(
25             $name => $self->_meta_method_class->wrap(
26             name => $name,
27             package_name => $self->name,
28             associated_metaclass => $self,
29             )
30             );
31             }
32              
33             sub wrap_method_body {
34 29251     29251 0 90623 my ( $self, %args ) = @_;
35              
36             ( $args{body} && 'CODE' eq reftype $args{body} )
37 29251 100 66     131844 || $self->_throw_exception( CodeBlockMustBeACodeRef => instance => $self,
38             params => \%args
39             );
40 29250         230765 $self->method_metaclass->wrap(
41             package_name => $self->name,
42             %args,
43             );
44             }
45              
46             sub add_method {
47 179169     179169 0 374191 my ( $self, $method_name, $method ) = @_;
48 179169 100 100     685322 ( defined $method_name && length $method_name )
49             || $self->_throw_exception( MustDefineAMethodName => instance => $self );
50              
51 179166         475158 my $package_name = $self->name;
52              
53 179164         256822 my $body;
54 179164 100 100     974389 if ( blessed($method) && $method->isa('Class::MOP::Method') ) {
55 170324         412115 $body = $method->body;
56 170324 100       461358 if ( $method->package_name ne $package_name ) {
57 18407         50015 $method = $method->clone(
58             package_name => $package_name,
59             name => $method_name,
60             );
61             }
62              
63 170324         433528 $method->attach_to_class($self);
64             }
65             else {
66             # If a raw code reference is supplied, its method object is not created.
67             # The method object won't be created until required.
68 8840         15173 $body = $method;
69             }
70              
71 179164         1064447 $self->_method_map->{$method_name} = $method;
72              
73 179164         738414 my ($current_package, $current_name) = Class::MOP::get_code_info($body);
74              
75 179164 100 66     1719763 set_subname($package_name . '::' . $method_name, $body)
76             unless defined $current_name && $current_name !~ /^__ANON__/;
77              
78 179164         786098 $self->add_package_symbol("&$method_name", $body);
79              
80             # we added the method to the method map too, so it's still valid
81 179164         538284 $self->update_package_cache_flag;
82             }
83              
84             sub _code_is_mine {
85 53036     53036   96742 my ( $self, $code ) = @_;
86              
87 53036         188988 my ( $code_package, $code_name ) = Class::MOP::get_code_info($code);
88              
89 53036   66     352428 return ( $code_package && $code_package eq $self->name )
90             || ( $code_package eq 'constant' && $code_name eq '__ANON__' );
91             }
92              
93             sub has_method {
94 25683     25683 0 167926 my ( $self, $method_name ) = @_;
95              
96 25683 100 100     100297 ( defined $method_name && length $method_name )
97             || $self->_throw_exception( MustDefineAMethodName => instance => $self );
98              
99 25679         59154 my $method = $self->_get_maybe_raw_method($method_name);
100 25679 100       118397 return if not $method;
101              
102 1439         10430 return defined($self->_method_map->{$method_name} = $method);
103             }
104              
105             sub get_method {
106 269517     269517 0 523926 my ( $self, $method_name ) = @_;
107              
108 269517 100 100     817389 ( defined $method_name && length $method_name )
109             || $self->_throw_exception( MustDefineAMethodName => instance => $self );
110              
111 269514         512819 my $method = $self->_get_maybe_raw_method($method_name);
112 269514 100       725681 return if not $method;
113              
114 81353 100 100     443585 return $method if blessed($method) && $method->isa('Class::MOP::Method');
115              
116 29250         72963 return $self->_method_map->{$method_name} = $self->wrap_method_body(
117             body => $method,
118             name => $method_name,
119             associated_metaclass => $self,
120             );
121             }
122              
123             sub _get_maybe_raw_method {
124 295193     295193   475256 my ( $self, $method_name ) = @_;
125              
126 295193         1097927 my $map_entry = $self->_method_map->{$method_name};
127 295193 100       643131 return $map_entry if defined $map_entry;
128              
129 241636         707745 my $code = $self->get_package_symbol("&$method_name");
130              
131 241636 100 100     733982 return unless $code && $self->_code_is_mine($code);
132              
133 29235         61224 return $code;
134             }
135              
136             sub remove_method {
137 84     84 0 1381 my ( $self, $method_name ) = @_;
138              
139 84 100 100     468 ( defined $method_name && length $method_name )
140             || $self->_throw_exception( MustDefineAMethodName => instance => $self );
141              
142 81         504 my $removed_method = delete $self->_method_map->{$method_name};
143              
144 81         561 $self->remove_package_symbol("&$method_name");
145              
146 81 100 66     1442 $removed_method->detach_from_class
147             if blessed($removed_method) && $removed_method->isa('Class::MOP::Method');
148              
149             # still valid, since we just removed the method from the map
150 81         302 $self->update_package_cache_flag;
151              
152 81         260 return $removed_method;
153             }
154              
155             sub get_method_list {
156 215     215 0 4301 my $self = shift;
157              
158 215         320 return keys %{ $self->_full_method_map };
  215         672  
159             }
160              
161             sub _get_local_methods {
162 7695     7695   14184 my $self = shift;
163              
164 7695         11662 return values %{ $self->_full_method_map };
  7695         20674  
165             }
166              
167             sub _restore_metamethods_from {
168 133     133   1613 my $self = shift;
169 133         349 my ($old_meta) = @_;
170              
171 133         482 my $package_name = $self->name;
172              
173             # Check if Perl debugger is enabled
174 133         1246 my $debugger_enabled = ($^P & 0x10);
175 133         585 my $debug_method_info;
176              
177 133         552 for my $method ($old_meta->_get_local_methods) {
178 164         699 my $method_name = $method->name;
179              
180             # Track DB::sub information for this method if debugger is enabled.
181             # This contains original method filename and line numbers.
182 164         323 $debug_method_info = '';
183 164 100       979 if ($debugger_enabled) {
184 8         27 $debug_method_info = $DB::sub{$package_name . "::" . $method_name}
185             }
186              
187 164         2021 $method->_make_compatible_with($self->method_metaclass);
188 161         958 $self->add_method($method_name => $method);
189              
190             # Restore method debug information, which can be clobbered by add_method.
191             # Note that we handle this here instead of in add_method, because we
192             # only want to preserve the original debug info in cases where we are
193             # restoring a method, not overwriting a method.
194 161 100 66     886 if ($debugger_enabled && $debug_method_info) {
195 8         31 $DB::sub{$package_name . "::" . $method_name} = $debug_method_info;
196             }
197             }
198             }
199              
200 1584     1584 0 7895 sub reset_package_cache_flag { (shift)->{'_package_cache_flag'} = undef }
201             sub update_package_cache_flag {
202 179245     179245 0 287813 my $self = shift;
203             # NOTE:
204             # we can manually update the cache number
205             # since we are actually adding the method
206             # to our cache as well. This avoids us
207             # having to regenerate the method_map.
208             # - SL
209 179245         1348018 $self->{'_package_cache_flag'} = Class::MOP::check_package_cache_flag($self->name);
210             }
211              
212             sub _full_method_map {
213 7910     7910   12914 my $self = shift;
214              
215 7910         30025 my $pkg_gen = Class::MOP::check_package_cache_flag($self->name);
216              
217 7910 100 100     36186 if (($self->{_package_cache_flag_full} || -1) != $pkg_gen) {
218             # forcibly reify all method map entries
219             $self->get_method($_)
220 3424         15452 for $self->list_all_package_symbols('CODE');
221 3424         13485 $self->{_package_cache_flag_full} = $pkg_gen;
222             }
223              
224 7910         91085 return $self->_method_map;
225             }
226              
227             1;
228              
229             # ABSTRACT: Methods for metaclasses which have methods
230              
231             __END__
232              
233             =pod
234              
235             =encoding UTF-8
236              
237             =head1 NAME
238              
239             Class::MOP::Mixin::HasMethods - Methods for metaclasses which have methods
240              
241             =head1 VERSION
242              
243             version 2.2206
244              
245             =head1 DESCRIPTION
246              
247             This class implements methods for metaclasses which have methods
248             (L<Class::MOP::Class> and L<Moose::Meta::Role>). See L<Class::MOP::Class> for
249             API details.
250              
251             =head1 AUTHORS
252              
253             =over 4
254              
255             =item *
256              
257             Stevan Little <stevan@cpan.org>
258              
259             =item *
260              
261             Dave Rolsky <autarch@urth.org>
262              
263             =item *
264              
265             Jesse Luehrs <doy@cpan.org>
266              
267             =item *
268              
269             Shawn M Moore <sartak@cpan.org>
270              
271             =item *
272              
273             יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
274              
275             =item *
276              
277             Karen Etheridge <ether@cpan.org>
278              
279             =item *
280              
281             Florian Ragwitz <rafl@debian.org>
282              
283             =item *
284              
285             Hans Dieter Pearcey <hdp@cpan.org>
286              
287             =item *
288              
289             Chris Prather <chris@prather.org>
290              
291             =item *
292              
293             Matt S Trout <mstrout@cpan.org>
294              
295             =back
296              
297             =head1 COPYRIGHT AND LICENSE
298              
299             This software is copyright (c) 2006 by Infinity Interactive, Inc.
300              
301             This is free software; you can redistribute it and/or modify it under
302             the same terms as the Perl 5 programming language system itself.
303              
304             =cut