1 package Class::MOP::HasMethods;
6 use Scalar::Util 'blessed';
8 use Sub::Name 'subname';
10 use base 'Class::MOP::Object';
12 sub method_metaclass { $_[0]->{'method_metaclass'} }
13 sub wrapped_method_metaclass { $_[0]->{'wrapped_method_metaclass'} }
15 # This doesn't always get initialized in a constructor because there is a
16 # weird object construction path for subclasses of Class::MOP::Class. At one
17 # point, this always got initialized by calling into the XS code first, but
18 # that is no longer guaranteed to happen.
19 sub _method_map { $_[0]->{'methods'} ||= {} }
21 sub wrap_method_body {
22 my ( $self, %args ) = @_;
24 ( 'CODE' eq ref $args{body} )
25 || confess "Your code block must be a CODE reference";
27 $self->method_metaclass->wrap(
28 package_name => $self->name,
34 my ( $self, $method_name, $method ) = @_;
35 ( defined $method_name && length $method_name )
36 || confess "You must define a method name";
39 if ( blessed($method) ) {
40 $body = $method->body;
41 if ( $method->package_name ne $self->name ) {
42 $method = $method->clone(
43 package_name => $self->name,
45 ) if $method->can('clone');
48 $method->attach_to_class($self);
51 # If a raw code reference is supplied, its method object is not created.
52 # The method object won't be created until required.
56 $self->_method_map->{$method_name} = $method;
58 my ( $current_package, $current_name ) = Class::MOP::get_code_info($body);
60 if ( !defined $current_name || $current_name =~ /^__ANON__/ ) {
61 my $full_method_name = ( $self->name . '::' . $method_name );
62 subname( $full_method_name => $body );
65 $self->add_package_symbol(
66 { sigil => '&', type => 'CODE', name => $method_name },
72 my ( $self, $code ) = @_;
74 my ( $code_package, $code_name ) = Class::MOP::get_code_info($code);
76 return $code_package && $code_package eq $self->name
77 || ( $code_package eq 'constant' && $code_name eq '__ANON__' );
81 my ( $self, $method_name ) = @_;
83 ( defined $method_name && length $method_name )
84 || confess "You must define a method name";
86 return defined( $self->get_method($method_name) );
90 my ( $self, $method_name ) = @_;
92 ( defined $method_name && length $method_name )
93 || confess "You must define a method name";
95 my $method_map = $self->_method_map;
96 my $map_entry = $method_map->{$method_name};
97 my $code = $self->get_package_symbol(
105 # This seems to happen in some weird cases where methods modifiers are
106 # added via roles or some other such bizareness. Honestly, I don't totally
107 # understand this, but returning the entry works, and keeps various MX
108 # modules from blowing up. - DR
109 return $map_entry if blessed $map_entry && !$code;
111 return $map_entry if blessed $map_entry && $map_entry->body == $code;
113 unless ($map_entry) {
114 return unless $code && $self->_code_is_mine($code);
117 $code ||= $map_entry;
119 return $method_map->{$method_name} = $self->wrap_method_body(
121 name => $method_name,
122 associated_metaclass => $self,
127 my ( $self, $method_name ) = @_;
128 ( defined $method_name && length $method_name )
129 || confess "You must define a method name";
131 my $removed_method = delete $self->_full_method_map->{$method_name};
133 $self->remove_package_symbol(
134 { sigil => '&', type => 'CODE', name => $method_name } );
136 $removed_method->detach_from_class
137 if $removed_method && blessed $removed_method;
139 # still valid, since we just removed the method from the map
140 $self->update_package_cache_flag;
142 return $removed_method;
145 sub get_method_list {
147 return grep { $self->has_method($_) } keys %{ $self->namespace };