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.2203';
3              
4 462     462   94084 use strict;
  462         910  
  462         12264  
5 462     462   2033 use warnings;
  462         804  
  462         9979  
6              
7 462     462   179945 use Class::MOP::Method::Meta;
  462         1074  
  462         14003  
8              
9 462     462   2746 use Scalar::Util 'blessed', 'reftype';
  462         914  
  462         21003  
10 462     462   2366 use Sub::Util 1.40 'set_subname';
  462         8492  
  462         21575  
11              
12 462     462   2599 use parent 'Class::MOP::Mixin';
  462         855  
  462         1975  
13              
14 10296     10296   59660 sub _meta_method_class { 'Class::MOP::Method::Meta' }
15              
16             sub _add_meta_method {
17 13363     13363   23640 my $self = shift;
18 13363         25107 my ($name) = @_;
19 13363 50       71368 my $existing_method = $self->can('find_method_by_name')
20             ? $self->find_method_by_name($name)
21             : $self->get_method($name);
22 13363 100 100     35494 return if $existing_method
23             && $existing_method->isa($self->_meta_method_class);
24 13256         37002 $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 29959     29959 0 80273 my ( $self, %args ) = @_;
35              
36             ( $args{body} && 'CODE' eq reftype $args{body} )
37 29959 100 66     116742 || $self->_throw_exception( CodeBlockMustBeACodeRef => instance => $self,
38             params => \%args
39             );
40 29958         205542 $self->method_metaclass->wrap(
41             package_name => $self->name,
42             %args,
43             );
44             }
45              
46             sub add_method {
47 183632     183632 0 335902 my ( $self, $method_name, $method ) = @_;
48 183632 100 100     618150 ( defined $method_name && length $method_name )
49             || $self->_throw_exception( MustDefineAMethodName => instance => $self );
50              
51 183629         426969 my $package_name = $self->name;
52              
53 183627         236095 my $body;
54 183627 100 100     878179 if ( blessed($method) && $method->isa('Class::MOP::Method') ) {
55 174533         367362 $body = $method->body;
56 174533 100       421362 if ( $method->package_name ne $package_name ) {
57 18541         44941 $method = $method->clone(
58             package_name => $package_name,
59             name => $method_name,
60             );
61             }
62              
63 174533         392477 $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 9094         12959 $body = $method;
69             }
70              
71 183627         927541 $self->_method_map->{$method_name} = $method;
72              
73 183627         653283 my ($current_package, $current_name) = Class::MOP::get_code_info($body);
74              
75 183627 100 66     1528631 set_subname($package_name . '::' . $method_name, $body)
76             unless defined $current_name && $current_name !~ /^__ANON__/;
77              
78 183627         700858 $self->add_package_symbol("&$method_name", $body);
79              
80             # we added the method to the method map too, so it's still valid
81 183627         480032 $self->update_package_cache_flag;
82             }
83              
84             sub _code_is_mine {
85 54134     54134   87397 my ( $self, $code ) = @_;
86              
87 54134         161074 my ( $code_package, $code_name ) = Class::MOP::get_code_info($code);
88              
89 54134   66     311299 return ( $code_package && $code_package eq $self->name )
90             || ( $code_package eq 'constant' && $code_name eq '__ANON__' );
91             }
92              
93             sub has_method {
94 26229     26229 0 174566 my ( $self, $method_name ) = @_;
95              
96 26229 100 100     90547 ( defined $method_name && length $method_name )
97             || $self->_throw_exception( MustDefineAMethodName => instance => $self );
98              
99 26225         53381 my $method = $self->_get_maybe_raw_method($method_name);
100 26225 100       100841 return if not $method;
101              
102 1470         8197 return defined($self->_method_map->{$method_name} = $method);
103             }
104              
105             sub get_method {
106 275521     275521 0 465476 my ( $self, $method_name ) = @_;
107              
108 275521 100 100     725330 ( defined $method_name && length $method_name )
109             || $self->_throw_exception( MustDefineAMethodName => instance => $self );
110              
111 275518         458969 my $method = $self->_get_maybe_raw_method($method_name);
112 275518 100       645219 return if not $method;
113              
114 83110 100 100     392693 return $method if blessed($method) && $method->isa('Class::MOP::Method');
115              
116 29958         64448 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 301743     301743   420549 my ( $self, $method_name ) = @_;
125              
126 301743         953152 my $map_entry = $self->_method_map->{$method_name};
127 301743 100       570083 return $map_entry if defined $map_entry;
128              
129 247107         627025 my $code = $self->get_package_symbol("&$method_name");
130              
131 247107 100 100     642245 return unless $code && $self->_code_is_mine($code);
132              
133 29944         53690 return $code;
134             }
135              
136             sub remove_method {
137 86     86 0 1274 my ( $self, $method_name ) = @_;
138              
139 86 100 100     416 ( defined $method_name && length $method_name )
140             || $self->_throw_exception( MustDefineAMethodName => instance => $self );
141              
142 83         610 my $removed_method = delete $self->_method_map->{$method_name};
143              
144 83         444 $self->remove_package_symbol("&$method_name");
145              
146 83 100 66     880 $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 83         246 $self->update_package_cache_flag;
151              
152 83         232 return $removed_method;
153             }
154              
155             sub get_method_list {
156 215     215 0 5426 my $self = shift;
157              
158 215         303 return keys %{ $self->_full_method_map };
  215         571  
159             }
160              
161             sub _get_local_methods {
162 7857     7857   12425 my $self = shift;
163              
164 7857         10456 return values %{ $self->_full_method_map };
  7857         18089  
165             }
166              
167             sub _restore_metamethods_from {
168 134     134   1555 my $self = shift;
169 134         270 my ($old_meta) = @_;
170              
171 134         907 my $package_name = $self->name;
172              
173             # Check if Perl debugger is enabled
174 134         1153 my $debugger_enabled = ($^P & 0x10);
175 134         465 my $debug_method_info;
176              
177 134         474 for my $method ($old_meta->_get_local_methods) {
178 167         594 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 167         549 $debug_method_info = '';
183 167 100       917 if ($debugger_enabled) {
184 8         22 $debug_method_info = $DB::sub{$package_name . "::" . $method_name}
185             }
186              
187 167         1851 $method->_make_compatible_with($self->method_metaclass);
188 164         862 $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 164 100 66     708 if ($debugger_enabled && $debug_method_info) {
195 8         25 $DB::sub{$package_name . "::" . $method_name} = $debug_method_info;
196             }
197             }
198             }
199              
200 1593     1593 0 7483 sub reset_package_cache_flag { (shift)->{'_package_cache_flag'} = undef }
201             sub update_package_cache_flag {
202 183710     183710 0 260003 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 183710         1201270 $self->{'_package_cache_flag'} = Class::MOP::check_package_cache_flag($self->name);
210             }
211              
212             sub _full_method_map {
213 8072     8072   11294 my $self = shift;
214              
215 8072         26545 my $pkg_gen = Class::MOP::check_package_cache_flag($self->name);
216              
217 8072 100 100     31257 if (($self->{_package_cache_flag_full} || -1) != $pkg_gen) {
218             # forcibly reify all method map entries
219             $self->get_method($_)
220 3483         13035 for $self->list_all_package_symbols('CODE');
221 3483         11058 $self->{_package_cache_flag_full} = $pkg_gen;
222             }
223              
224 8072         77690 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.2203
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