| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package MOP::Role; | 
| 2 |  |  |  |  |  |  | # ABSTRACT: A representation of a role | 
| 3 |  |  |  |  |  |  |  | 
| 4 | 28 |  |  | 28 |  | 861365 | use strict; | 
|  | 28 |  |  |  |  | 199 |  | 
|  | 28 |  |  |  |  | 707 |  | 
| 5 | 28 |  |  | 28 |  | 124 | use warnings; | 
|  | 28 |  |  |  |  | 52 |  | 
|  | 28 |  |  |  |  | 599 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 28 |  |  | 28 |  | 117 | use Carp (); | 
|  | 28 |  |  |  |  | 56 |  | 
|  | 28 |  |  |  |  | 426 |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 28 |  |  | 28 |  | 6177 | use UNIVERSAL::Object::Immutable; | 
|  | 28 |  |  |  |  | 35163 |  | 
|  | 28 |  |  |  |  | 704 |  | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 28 |  |  | 28 |  | 6923 | use MOP::Method; | 
|  | 28 |  |  |  |  | 73 |  | 
|  | 28 |  |  |  |  | 837 |  | 
| 12 | 28 |  |  | 28 |  | 7461 | use MOP::Slot; | 
|  | 28 |  |  |  |  | 61 |  | 
|  | 28 |  |  |  |  | 678 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 | 28 |  |  | 28 |  | 145 | use MOP::Internal::Util; | 
|  | 28 |  |  |  |  | 40 |  | 
|  | 28 |  |  |  |  | 1156 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | our $VERSION   = '0.11'; | 
| 17 |  |  |  |  |  |  | our $AUTHORITY = 'cpan:STEVAN'; | 
| 18 |  |  |  |  |  |  |  | 
| 19 | 28 |  |  | 28 |  | 4903 | our @ISA; BEGIN { @ISA = 'UNIVERSAL::Object::Immutable' }; | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | sub BUILDARGS { | 
| 22 | 110 |  |  | 110 | 1 | 139113 | my $class = shift; | 
| 23 | 110 |  |  |  |  | 175 | my %args; | 
| 24 |  |  |  |  |  |  |  | 
| 25 | 110 | 100 |  |  |  | 276 | if ( scalar( @_ ) == 1 ) { | 
| 26 | 16 | 100 |  |  |  | 41 | if ( ref $_[0] ) { | 
| 27 | 4 | 50 |  |  |  | 13 | if ( ref $_[0] eq 'HASH' ) { | 
| 28 | 4 | 100 |  |  |  | 16 | if ( MOP::Internal::Util::IS_STASH_REF( $_[0] ) ) { | 
| 29 |  |  |  |  |  |  | # if it is a stash, grab the name | 
| 30 | 2 |  |  |  |  | 8 | %args = ( | 
| 31 |  |  |  |  |  |  | name  => MOP::Internal::Util::GET_NAME( $_[0] ), | 
| 32 |  |  |  |  |  |  | stash => $_[0] | 
| 33 |  |  |  |  |  |  | ); | 
| 34 |  |  |  |  |  |  | } | 
| 35 |  |  |  |  |  |  | else { | 
| 36 |  |  |  |  |  |  | # just plain old HASH ref ... | 
| 37 | 2 |  |  |  |  | 5 | %args = %{ $_[0] }; | 
|  | 2 |  |  |  |  | 8 |  | 
| 38 |  |  |  |  |  |  | } | 
| 39 |  |  |  |  |  |  | } | 
| 40 |  |  |  |  |  |  | } | 
| 41 |  |  |  |  |  |  | else { | 
| 42 |  |  |  |  |  |  | # assume it is a single package name ... | 
| 43 | 12 |  |  |  |  | 32 | %args = ( name => $_[0] ); | 
| 44 |  |  |  |  |  |  | } | 
| 45 |  |  |  |  |  |  | } | 
| 46 |  |  |  |  |  |  | else { | 
| 47 |  |  |  |  |  |  | # assume we got key/value pairs ... | 
| 48 | 94 |  |  |  |  | 260 | %args = @_; | 
| 49 |  |  |  |  |  |  | } | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | Carp::croak('[ARGS] You must specify a package name') | 
| 52 | 110 | 50 |  |  |  | 317 | unless $args{name}; | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  | Carp::croak('[ARGS] You must specify a valid package name, not `'.$_[0].'`') | 
| 55 | 110 | 50 |  |  |  | 359 | unless MOP::Internal::Util::IS_VALID_MODULE_NAME( $args{name} ); | 
| 56 |  |  |  |  |  |  |  | 
| 57 | 110 |  |  |  |  | 472 | return \%args; | 
| 58 |  |  |  |  |  |  | } | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | sub CREATE { | 
| 61 | 110 |  |  | 110 | 1 | 1309 | my ($class, $args) = @_; | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | # intiialize the stash ... | 
| 64 | 110 |  |  |  |  | 184 | my $stash = $args->{stash}; | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | # if we have it, otherwise get it ... | 
| 67 | 110 | 100 |  |  |  | 250 | unless ( $stash ) { | 
| 68 |  |  |  |  |  |  | # get a ref to to the stash itself ... | 
| 69 | 28 |  |  | 28 |  | 166 | no strict 'refs'; | 
|  | 28 |  |  |  |  | 54 |  | 
|  | 28 |  |  |  |  | 70615 |  | 
| 70 | 108 |  |  |  |  | 143 | $stash = \%{ $args->{name} . '::' }; | 
|  | 108 |  |  |  |  | 331 |  | 
| 71 |  |  |  |  |  |  | } | 
| 72 |  |  |  |  |  |  | # and then a ref to that, because we | 
| 73 |  |  |  |  |  |  | # eventually will need to bless it and | 
| 74 |  |  |  |  |  |  | # we do not want to bless the actual | 
| 75 |  |  |  |  |  |  | # stash because that persists beyond | 
| 76 |  |  |  |  |  |  | # the lifetime of this object, so we | 
| 77 |  |  |  |  |  |  | # bless a ref of a ref then ... | 
| 78 | 110 |  |  |  |  | 313 | return \$stash; | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | # stash | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | sub stash { | 
| 84 | 2058 |  |  | 2058 | 1 | 2558 | my ($self) = @_; | 
| 85 | 2058 |  |  |  |  | 4172 | return $$self; # returns the direct HASH ref of the stash | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | # identity | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | sub name { | 
| 91 | 1115 |  |  | 1115 | 1 | 39169 | my ($self) = @_; | 
| 92 | 1115 |  |  |  |  | 1536 | return MOP::Internal::Util::GET_NAME( $self->stash ); | 
| 93 |  |  |  |  |  |  | } | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | sub version { | 
| 96 | 8 |  |  | 8 | 1 | 22 | my ($self) = @_; | 
| 97 | 8 |  |  |  |  | 27 | my $version = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'VERSION', 'SCALAR' ); | 
| 98 | 8 | 50 |  |  |  | 32 | return unless $version; | 
| 99 | 8 |  |  |  |  | 37 | return $$version; | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | sub authority { | 
| 103 | 8 |  |  | 8 | 1 | 26 | my ($self) = @_; | 
| 104 | 8 |  |  |  |  | 23 | my $authority = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'AUTHORITY', 'SCALAR' ); | 
| 105 | 8 | 50 |  |  |  | 29 | return unless $authority; | 
| 106 | 8 |  |  |  |  | 36 | return $$authority; | 
| 107 |  |  |  |  |  |  | } | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | # other roles | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | sub roles { | 
| 112 | 155 |  |  | 155 | 1 | 673 | my ($self) = @_; | 
| 113 | 155 |  |  |  |  | 293 | my $does = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'DOES', 'ARRAY' ); | 
| 114 | 155 | 100 |  |  |  | 420 | return unless $does; | 
| 115 | 52 |  |  |  |  | 167 | return @$does; | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | sub set_roles { | 
| 119 | 1 |  |  | 1 | 1 | 97 | my ($self, @roles) = @_; | 
| 120 | 1 | 50 |  |  |  | 4 | Carp::croak('[ARGS] You must specify at least one role') | 
| 121 |  |  |  |  |  |  | if scalar( @roles ) == 0; | 
| 122 | 1 |  |  |  |  | 4 | MOP::Internal::Util::SET_GLOB_SLOT( $self->stash, 'DOES', \@roles ); | 
| 123 | 1 |  |  |  |  | 4 | return; | 
| 124 |  |  |  |  |  |  | } | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | sub does_role { | 
| 127 | 23 |  |  | 23 | 1 | 2439 | my ($self, $to_test) = @_; | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 23 | 50 |  |  |  | 68 | Carp::croak('[ARGS] You must specify a role') | 
| 130 |  |  |  |  |  |  | unless $to_test; | 
| 131 |  |  |  |  |  |  |  | 
| 132 | 23 |  |  |  |  | 58 | my @roles = $self->roles; | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | # no roles, will never match ... | 
| 135 | 23 | 100 |  |  |  | 79 | return 0 unless @roles; | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | # try the simple way first ... | 
| 138 | 17 |  |  |  |  | 38 | foreach my $role ( @roles ) { | 
| 139 | 20 | 100 |  |  |  | 106 | return 1 if $role eq $to_test; | 
| 140 |  |  |  |  |  |  | } | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | # then try the harder way next ... | 
| 143 | 4 |  |  |  |  | 13 | foreach my $role ( @roles ) { | 
| 144 | 4 | 100 |  |  |  | 19 | return 1 | 
| 145 |  |  |  |  |  |  | if MOP::Role->new( name => $role ) | 
| 146 |  |  |  |  |  |  | ->does_role( $to_test ); | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | # oh well ... | 
| 150 | 1 |  |  |  |  | 16 | return 0; | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | ## Methods | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | # get them all; regular, aliased & required | 
| 156 |  |  |  |  |  |  | sub all_methods { | 
| 157 | 46 |  |  | 46 | 1 | 87 | my $stash = $_[0]->stash; | 
| 158 | 46 |  |  |  |  | 85 | my @methods; | 
| 159 | 46 |  |  |  |  | 246 | foreach my $candidate ( keys %$stash ) { | 
| 160 | 1211 | 100 |  |  |  | 12145 | if ( my $code = MOP::Internal::Util::GET_GLOB_SLOT( $stash, $candidate, 'CODE' ) ) { | 
| 161 | 941 |  |  |  |  | 2055 | push @methods => MOP::Method->new( body => $code ); | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  | } | 
| 164 | 46 |  |  |  |  | 577 | return @methods; | 
| 165 |  |  |  |  |  |  | } | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | # just the local non-required methods | 
| 168 |  |  |  |  |  |  | sub methods { | 
| 169 | 21 |  |  | 21 | 1 | 1271 | my $self  = shift; | 
| 170 | 21 |  |  |  |  | 45 | my $class = $self->name; | 
| 171 | 21 |  |  |  |  | 55 | my @roles = $self->roles; | 
| 172 |  |  |  |  |  |  |  | 
| 173 | 21 |  |  |  |  | 35 | my @methods; | 
| 174 | 21 |  |  |  |  | 45 | foreach my $method ( $self->all_methods ) { | 
| 175 |  |  |  |  |  |  | # if the method is required, we don't want it | 
| 176 | 464 | 100 |  |  |  | 782 | next if $method->is_required; | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | # if the method is not originally from the | 
| 179 |  |  |  |  |  |  | # class, then we probably don't want it ... | 
| 180 | 459 | 100 |  |  |  | 865 | if ( $method->origin_stash ne $class ) { | 
| 181 |  |  |  |  |  |  | # if our class has roles, then non-local | 
| 182 |  |  |  |  |  |  | # methods *might* be valid, so ... | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | # if we don't have roles, then | 
| 185 |  |  |  |  |  |  | # it can't be valid, so we don't | 
| 186 |  |  |  |  |  |  | # want it | 
| 187 | 3 | 50 |  |  |  | 16 | next unless @roles; | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | # if we do have roles, but our | 
| 190 |  |  |  |  |  |  | # method was not aliased from one | 
| 191 |  |  |  |  |  |  | # of them, then we don't want it. | 
| 192 | 3 | 50 |  |  |  | 10 | next unless $method->was_aliased_from( @roles ); | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | # if we are here then we have | 
| 195 |  |  |  |  |  |  | # a non-required method that is | 
| 196 |  |  |  |  |  |  | # not from the local class, it | 
| 197 |  |  |  |  |  |  | # has roles and was aliased from | 
| 198 |  |  |  |  |  |  | # one of them, which means we want | 
| 199 |  |  |  |  |  |  | # to keep it, so we let it fall through | 
| 200 |  |  |  |  |  |  | } | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | # if we are here then we have | 
| 203 |  |  |  |  |  |  | # a non-required method that is | 
| 204 |  |  |  |  |  |  | # either from the local class, | 
| 205 |  |  |  |  |  |  | # or is not from a local class, | 
| 206 |  |  |  |  |  |  | # but has fallen through our | 
| 207 |  |  |  |  |  |  | # conditional above. | 
| 208 |  |  |  |  |  |  |  | 
| 209 | 459 |  |  |  |  | 845 | push @methods => $method; | 
| 210 |  |  |  |  |  |  | } | 
| 211 |  |  |  |  |  |  |  | 
| 212 | 21 |  |  |  |  | 78 | return @methods; | 
| 213 |  |  |  |  |  |  | } | 
| 214 |  |  |  |  |  |  |  | 
| 215 |  |  |  |  |  |  | # just the non-local non-required methods | 
| 216 |  |  |  |  |  |  | sub aliased_methods { | 
| 217 | 2 |  |  | 2 | 1 | 18 | my $self  = shift; | 
| 218 | 2 |  |  |  |  | 3 | my $class = $self->name; | 
| 219 | 2 | 100 |  |  |  | 5 | return grep { (!$_->is_required) && $_->origin_stash ne $class } $self->all_methods | 
|  | 5 |  |  |  |  | 10 |  | 
| 220 |  |  |  |  |  |  | } | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | # just the required methods (locality be damned) | 
| 223 |  |  |  |  |  |  | # NOTE: | 
| 224 |  |  |  |  |  |  | # We don't care where are required method comes from | 
| 225 |  |  |  |  |  |  | # just that one exists, so aliasing is not part of the | 
| 226 |  |  |  |  |  |  | # criteria here. | 
| 227 |  |  |  |  |  |  | # - SL | 
| 228 |  |  |  |  |  |  | sub required_methods { | 
| 229 | 20 |  |  | 20 | 1 | 50 | my $self = shift; | 
| 230 | 20 |  |  |  |  | 37 | return grep { $_->is_required } $self->all_methods | 
|  | 427 |  |  |  |  | 717 |  | 
| 231 |  |  |  |  |  |  | } | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | # required methods | 
| 234 |  |  |  |  |  |  |  | 
| 235 |  |  |  |  |  |  | # NOTE: | 
| 236 |  |  |  |  |  |  | # there is no real heavy need to use the MOP::Method API | 
| 237 |  |  |  |  |  |  | # below because 1) it is not needed, and 2) the MOP::Method | 
| 238 |  |  |  |  |  |  | # API is really just an information shim, it does not perform | 
| 239 |  |  |  |  |  |  | # much in the way of actions. From my point of view, the below | 
| 240 |  |  |  |  |  |  | # operations are mostly stash manipulation functions and so | 
| 241 |  |  |  |  |  |  | # therefore belong here in the continuim of responsibility/ | 
| 242 |  |  |  |  |  |  | # ownership. | 
| 243 |  |  |  |  |  |  | # | 
| 244 |  |  |  |  |  |  | ## The only argument that could likely be made is for the | 
| 245 |  |  |  |  |  |  | ## MOP::Method API to handle creating the NULL CV for the | 
| 246 |  |  |  |  |  |  | ## add_required_method, but that would require us to pass in | 
| 247 |  |  |  |  |  |  | ## a MOP::Method instance, which would be silly since we never | 
| 248 |  |  |  |  |  |  | ## need it anyway. | 
| 249 |  |  |  |  |  |  | # | 
| 250 |  |  |  |  |  |  | # - SL | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | sub has_required_method { | 
| 253 | 37 |  |  | 37 | 1 | 100 | my $stash = $_[0]->stash; | 
| 254 | 37 |  |  |  |  | 65 | my $name  = $_[1]; | 
| 255 |  |  |  |  |  |  |  | 
| 256 | 37 | 50 |  |  |  | 119 | Carp::croak('[ARGS] You must specify the name of the required method to look for') | 
| 257 |  |  |  |  |  |  | unless $name; | 
| 258 |  |  |  |  |  |  |  | 
| 259 | 37 | 100 |  |  |  | 92 | return 0 unless exists $stash->{ $name }; | 
| 260 | 34 |  |  |  |  | 102 | return MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $stash->{ $name } ); | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  |  | 
| 263 |  |  |  |  |  |  | # consistency is a good thing ... | 
| 264 | 36 |  |  | 36 | 1 | 10744 | sub requires_method { goto &has_required_method } | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | sub get_required_method { | 
| 267 | 20 |  |  | 20 | 1 | 8353 | my $class = $_[0]->name; | 
| 268 | 20 |  |  |  |  | 48 | my $stash = $_[0]->stash; | 
| 269 | 20 |  |  |  |  | 32 | my $name  = $_[1]; | 
| 270 |  |  |  |  |  |  |  | 
| 271 | 20 | 50 |  |  |  | 54 | Carp::croak('[ARGS] You must specify the name of the required method to get') | 
| 272 |  |  |  |  |  |  | unless $name; | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | # check these two easy cases first ... | 
| 275 | 20 | 100 |  |  |  | 51 | return unless exists $stash->{ $name }; | 
| 276 | 17 | 100 |  |  |  | 45 | return unless MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $stash->{ $name } ); | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | # now we grab the CV ... | 
| 279 | 6 |  |  |  |  | 20 | my $method = MOP::Method->new( | 
| 280 |  |  |  |  |  |  | body => MOP::Internal::Util::GET_GLOB_SLOT( $stash, $name, 'CODE' ) | 
| 281 |  |  |  |  |  |  | ); | 
| 282 |  |  |  |  |  |  | # and make sure it is local, and | 
| 283 |  |  |  |  |  |  | # then return the method ... | 
| 284 | 6 | 100 |  |  |  | 111 | return $method if $method->origin_stash eq $class; | 
| 285 |  |  |  |  |  |  | # or return nothing ... | 
| 286 | 1 |  |  |  |  | 4 | return; | 
| 287 |  |  |  |  |  |  | } | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | sub add_required_method { | 
| 290 | 5 |  |  | 5 | 1 | 3886 | my ($self, $name) = @_; | 
| 291 |  |  |  |  |  |  |  | 
| 292 | 5 | 50 |  |  |  | 11 | Carp::croak('[ARGS] You must specify the name of the required method to add') | 
| 293 |  |  |  |  |  |  | unless $name; | 
| 294 |  |  |  |  |  |  |  | 
| 295 |  |  |  |  |  |  | # if we already have a glob there ... | 
| 296 | 5 | 100 |  |  |  | 10 | if ( my $glob = $self->stash->{ $name } ) { | 
| 297 |  |  |  |  |  |  | # and if we have a NULL CV in it, just return | 
| 298 | 3 | 100 |  |  |  | 8 | return if MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $glob ); | 
| 299 |  |  |  |  |  |  | # and if we don't and we have a CODE slot, we | 
| 300 |  |  |  |  |  |  | # need to die because this doesn't make sense | 
| 301 |  |  |  |  |  |  | Carp::croak("[CONFLICT] Cannot add a required method ($name) when there is a regular method already there") | 
| 302 | 2 | 100 |  |  |  | 4 | if defined *{ $glob }{CODE}; | 
|  | 2 |  |  |  |  | 146 |  | 
| 303 |  |  |  |  |  |  | } | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | # if we get here, then we | 
| 306 |  |  |  |  |  |  | # just create a null CV | 
| 307 | 3 |  |  |  |  | 7 | MOP::Internal::Util::CREATE_NULL_CV( $self->name, $name ); | 
| 308 |  |  |  |  |  |  |  | 
| 309 | 2 |  |  |  |  | 6 | return; | 
| 310 |  |  |  |  |  |  | } | 
| 311 |  |  |  |  |  |  |  | 
| 312 |  |  |  |  |  |  | sub delete_required_method { | 
| 313 | 4 |  |  | 4 | 1 | 1834 | my ($self, $name) = @_; | 
| 314 |  |  |  |  |  |  |  | 
| 315 | 4 | 50 |  |  |  | 9 | Carp::croak('[ARGS] You must specify the name of the required method to delete') | 
| 316 |  |  |  |  |  |  | unless $name; | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | # check if we have a stash entry for $name ... | 
| 319 | 4 | 100 |  |  |  | 9 | if ( my $glob = $self->stash->{ $name } ) { | 
| 320 |  |  |  |  |  |  | # and if we have a NULL CV in it, ... | 
| 321 | 3 | 100 |  |  |  | 7 | if ( MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $glob ) ) { | 
| 322 |  |  |  |  |  |  | # then we must delete it | 
| 323 | 1 |  |  |  |  | 3 | MOP::Internal::Util::REMOVE_CV_FROM_GLOB( $self->stash, $name ); | 
| 324 | 1 |  |  |  |  | 3 | return; | 
| 325 |  |  |  |  |  |  | } | 
| 326 |  |  |  |  |  |  | else { | 
| 327 |  |  |  |  |  |  | # and if we have a CV slot, but it doesn't have | 
| 328 |  |  |  |  |  |  | # a NULL CV in it, then we need to die because | 
| 329 |  |  |  |  |  |  | # this doesn't make sense | 
| 330 |  |  |  |  |  |  | Carp::croak("[CONFLICT] Cannot delete a required method ($name) when there is a regular method already there") | 
| 331 | 2 | 100 |  |  |  | 3 | if defined *{ $glob }{CODE}; | 
|  | 2 |  |  |  |  | 145 |  | 
| 332 |  |  |  |  |  |  |  | 
| 333 |  |  |  |  |  |  | # if we have the glob, but no CV slot (NULL or otherwise) | 
| 334 |  |  |  |  |  |  | # we do nothing ... | 
| 335 | 1 |  |  |  |  | 3 | return; | 
| 336 |  |  |  |  |  |  | } | 
| 337 |  |  |  |  |  |  | } | 
| 338 |  |  |  |  |  |  | # if there is no stash entry for $name, we do nothing | 
| 339 | 1 |  |  |  |  | 3 | return; | 
| 340 |  |  |  |  |  |  | } | 
| 341 |  |  |  |  |  |  |  | 
| 342 |  |  |  |  |  |  | # methods | 
| 343 |  |  |  |  |  |  |  | 
| 344 |  |  |  |  |  |  | sub has_method { | 
| 345 | 460 |  |  | 460 | 1 | 17157 | my $self  = $_[0]; | 
| 346 | 460 |  |  |  |  | 654 | my $class = $self->name; | 
| 347 | 460 |  |  |  |  | 770 | my $stash = $self->stash; | 
| 348 | 460 |  |  |  |  | 593 | my $name  = $_[1]; | 
| 349 |  |  |  |  |  |  |  | 
| 350 | 460 | 50 |  |  |  | 738 | Carp::croak('[ARGS] You must specify the name of the method to look for') | 
| 351 |  |  |  |  |  |  | unless $name; | 
| 352 |  |  |  |  |  |  |  | 
| 353 |  |  |  |  |  |  | # check these two easy cases first ... | 
| 354 | 460 | 100 |  |  |  | 1271 | return 0 unless exists $stash->{ $name }; | 
| 355 | 35 | 100 |  |  |  | 161 | return 0 if MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $stash->{ $name } ); | 
| 356 |  |  |  |  |  |  |  | 
| 357 |  |  |  |  |  |  | # now we grab the CV and make sure it is | 
| 358 |  |  |  |  |  |  | # local, and return accordingly | 
| 359 | 30 | 100 |  |  |  | 189 | if ( my $code = MOP::Internal::Util::GET_GLOB_SLOT( $stash, $name, 'CODE' ) ) { | 
| 360 | 27 |  |  |  |  | 136 | my $method = MOP::Method->new( body => $code ); | 
| 361 | 27 |  |  |  |  | 547 | my @roles  = $self->roles; | 
| 362 |  |  |  |  |  |  | # and make sure it is local, and | 
| 363 |  |  |  |  |  |  | # then return accordingly | 
| 364 | 27 |  | 100 |  |  | 96 | return $method->origin_stash eq $class | 
| 365 |  |  |  |  |  |  | || (@roles && $method->was_aliased_from( @roles )); | 
| 366 |  |  |  |  |  |  | } | 
| 367 |  |  |  |  |  |  |  | 
| 368 |  |  |  |  |  |  | # if there was no CV, return false. | 
| 369 | 3 |  |  |  |  | 11 | return 0; | 
| 370 |  |  |  |  |  |  | } | 
| 371 |  |  |  |  |  |  |  | 
| 372 |  |  |  |  |  |  | sub get_method { | 
| 373 | 22 |  |  | 22 | 1 | 22951 | my $self  = $_[0]; | 
| 374 | 22 |  |  |  |  | 61 | my $class = $self->name; | 
| 375 | 22 |  |  |  |  | 66 | my $stash = $self->stash; | 
| 376 | 22 |  |  |  |  | 47 | my $name  = $_[1]; | 
| 377 |  |  |  |  |  |  |  | 
| 378 | 22 | 50 |  |  |  | 64 | Carp::croak('[ARGS] You must specify the name of the method to get') | 
| 379 |  |  |  |  |  |  | unless $name; | 
| 380 |  |  |  |  |  |  |  | 
| 381 |  |  |  |  |  |  | # check the easy cases first ... | 
| 382 | 22 | 100 |  |  |  | 73 | return unless exists $stash->{ $name }; | 
| 383 | 20 | 100 |  |  |  | 75 | return if MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $stash->{ $name } ); | 
| 384 |  |  |  |  |  |  |  | 
| 385 |  |  |  |  |  |  | # now we grab the CV ... | 
| 386 | 17 | 100 |  |  |  | 72 | if ( my $code = MOP::Internal::Util::GET_GLOB_SLOT( $stash, $name, 'CODE' ) ) { | 
| 387 | 14 |  |  |  |  | 68 | my $method = MOP::Method->new( body => $code ); | 
| 388 | 14 |  |  |  |  | 290 | my @roles  = $self->roles; | 
| 389 |  |  |  |  |  |  | # and make sure it is local, and | 
| 390 |  |  |  |  |  |  | # then return accordingly | 
| 391 | 14 | 100 | 66 |  |  | 52 | return $method | 
|  |  |  | 100 |  |  |  |  | 
| 392 |  |  |  |  |  |  | if $method->origin_stash eq $class | 
| 393 |  |  |  |  |  |  | || (@roles && $method->was_aliased_from( @roles )); | 
| 394 |  |  |  |  |  |  | } | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | # if there was no CV, return false. | 
| 397 | 4 |  |  |  |  | 20 | return; | 
| 398 |  |  |  |  |  |  | } | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | sub add_method { | 
| 401 | 1 |  |  | 1 | 1 | 3 | my ($self, $name, $code) = @_; | 
| 402 |  |  |  |  |  |  |  | 
| 403 | 1 | 50 |  |  |  | 3 | Carp::croak('[ARGS] You must specify the name of the method to add') | 
| 404 |  |  |  |  |  |  | unless $name; | 
| 405 |  |  |  |  |  |  |  | 
| 406 | 1 | 50 | 33 |  |  | 7 | Carp::croak('[ARGS] You must specify a CODE reference to add as a method') | 
| 407 |  |  |  |  |  |  | unless $code && ref $code eq 'CODE'; | 
| 408 |  |  |  |  |  |  |  | 
| 409 | 1 |  |  |  |  | 2 | MOP::Internal::Util::INSTALL_CV( $self->name, $name, $code, set_subname => 1 ); | 
| 410 | 1 |  |  |  |  | 2 | return; | 
| 411 |  |  |  |  |  |  | } | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | sub delete_method { | 
| 414 | 5 |  |  | 5 | 1 | 2690 | my ($self, $name) = @_; | 
| 415 |  |  |  |  |  |  |  | 
| 416 | 5 | 50 |  |  |  | 12 | Carp::croak('[ARGS] You must specify the name of the method to delete') | 
| 417 |  |  |  |  |  |  | unless $name; | 
| 418 |  |  |  |  |  |  |  | 
| 419 |  |  |  |  |  |  | # check if we have a stash entry for $name ... | 
| 420 | 5 | 100 |  |  |  | 9 | if ( my $glob = $self->stash->{ $name } ) { | 
| 421 |  |  |  |  |  |  | # and if we have a NULL CV in it, ... | 
| 422 | 4 | 100 |  |  |  | 9 | if ( MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $glob ) ) { | 
| 423 |  |  |  |  |  |  | # then we need to die because this | 
| 424 |  |  |  |  |  |  | # shouldn't happen, we should only | 
| 425 |  |  |  |  |  |  | # delete regular methods. | 
| 426 | 1 |  |  |  |  | 146 | Carp::croak("[CONFLICT] Cannot delete a regular method ($name) when there is a required method already there"); | 
| 427 |  |  |  |  |  |  | } | 
| 428 |  |  |  |  |  |  | else { | 
| 429 |  |  |  |  |  |  | # if we don't have a code slot ... | 
| 430 | 3 | 100 |  |  |  | 5 | return unless defined *{ $glob }{CODE}; | 
|  | 3 |  |  |  |  | 9 |  | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | # we need to make sure it is local, and | 
| 433 |  |  |  |  |  |  | # otherwise, error accordingly | 
| 434 | 2 |  |  |  |  | 3 | my $method = MOP::Method->new( body => *{ $glob }{CODE} ); | 
|  | 2 |  |  |  |  | 6 |  | 
| 435 | 2 |  |  |  |  | 30 | my @roles  = $self->roles; | 
| 436 |  |  |  |  |  |  |  | 
| 437 |  |  |  |  |  |  | # if the method has not come from | 
| 438 |  |  |  |  |  |  | # the local class, we need to see | 
| 439 |  |  |  |  |  |  | # if it was added from a role | 
| 440 | 2 | 100 |  |  |  | 8 | if ($method->origin_stash ne $self->name) { | 
| 441 |  |  |  |  |  |  |  | 
| 442 |  |  |  |  |  |  | # if it came from a role, then it is | 
| 443 |  |  |  |  |  |  | # okay to be deleted, but if it didn't | 
| 444 |  |  |  |  |  |  | # then we have an error cause they are | 
| 445 |  |  |  |  |  |  | # trying to delete an alias using the | 
| 446 |  |  |  |  |  |  | # regular method method | 
| 447 | 1 | 50 | 33 |  |  | 9 | unless ( @roles && $method->was_aliased_from( @roles ) ) { | 
| 448 | 1 |  |  |  |  | 81 | Carp::croak("[CONFLICT] Cannot delete a regular method ($name) when there is an aliased method already there") | 
| 449 |  |  |  |  |  |  | } | 
| 450 |  |  |  |  |  |  | } | 
| 451 |  |  |  |  |  |  |  | 
| 452 |  |  |  |  |  |  | # but if we have a regular method, then we | 
| 453 |  |  |  |  |  |  | # can just delete the CV from the glob | 
| 454 | 1 |  |  |  |  | 3 | MOP::Internal::Util::REMOVE_CV_FROM_GLOB( $self->stash, $name ); | 
| 455 |  |  |  |  |  |  | } | 
| 456 |  |  |  |  |  |  | } | 
| 457 |  |  |  |  |  |  | # if there is no stash entry for $name, we do nothing | 
| 458 | 2 |  |  |  |  | 22 | return; | 
| 459 |  |  |  |  |  |  | } | 
| 460 |  |  |  |  |  |  |  | 
| 461 |  |  |  |  |  |  | # aliased methods | 
| 462 |  |  |  |  |  |  |  | 
| 463 |  |  |  |  |  |  | sub get_method_alias { | 
| 464 | 14 |  |  | 14 | 1 | 1668 | my $class = $_[0]->name; | 
| 465 | 14 |  |  |  |  | 30 | my $stash = $_[0]->stash; | 
| 466 | 14 |  |  |  |  | 23 | my $name  = $_[1]; | 
| 467 |  |  |  |  |  |  |  | 
| 468 | 14 | 50 |  |  |  | 42 | Carp::croak('[ARGS] You must specify the name of the method alias to look for') | 
| 469 |  |  |  |  |  |  | unless $name; | 
| 470 |  |  |  |  |  |  |  | 
| 471 |  |  |  |  |  |  | # check the easy cases first ... | 
| 472 | 14 | 100 |  |  |  | 43 | return unless exists $stash->{ $name }; | 
| 473 | 12 | 100 |  |  |  | 35 | return if MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $stash->{ $name } ); | 
| 474 |  |  |  |  |  |  |  | 
| 475 |  |  |  |  |  |  | # now we grab the CV ... | 
| 476 | 11 | 100 |  |  |  | 31 | if ( my $code = MOP::Internal::Util::GET_GLOB_SLOT( $stash, $name, 'CODE' ) ) { | 
| 477 | 8 |  |  |  |  | 36 | my $method = MOP::Method->new( body => $code ); | 
| 478 |  |  |  |  |  |  | # and make sure it is not local, and | 
| 479 |  |  |  |  |  |  | # then return accordingly | 
| 480 | 8 | 100 |  |  |  | 114 | return $method | 
| 481 |  |  |  |  |  |  | if $method->origin_stash ne $class; | 
| 482 |  |  |  |  |  |  | } | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | # if there was no CV, return false. | 
| 485 | 5 |  |  |  |  | 28 | return; | 
| 486 |  |  |  |  |  |  | } | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | # NOTE: | 
| 489 |  |  |  |  |  |  | # Should aliasing be aloud even after a class is closed? | 
| 490 |  |  |  |  |  |  | # Probably not, but it might not be a bad idea to at | 
| 491 |  |  |  |  |  |  | # least discuss in more detail what happens when a class | 
| 492 |  |  |  |  |  |  | # is actually closed. | 
| 493 |  |  |  |  |  |  | # - SL | 
| 494 |  |  |  |  |  |  |  | 
| 495 |  |  |  |  |  |  | sub alias_method { | 
| 496 | 420 |  |  | 420 | 1 | 625 | my ($self, $name, $code) = @_; | 
| 497 |  |  |  |  |  |  |  | 
| 498 | 420 | 50 |  |  |  | 647 | Carp::croak('[ARGS] You must specify the name of the method alias to add') | 
| 499 |  |  |  |  |  |  | unless $name; | 
| 500 |  |  |  |  |  |  |  | 
| 501 | 420 | 50 | 33 |  |  | 1156 | Carp::croak('[ARGS] You must specify a CODE reference to add as a method alias') | 
| 502 |  |  |  |  |  |  | unless $code && ref $code eq 'CODE'; | 
| 503 |  |  |  |  |  |  |  | 
| 504 | 420 |  |  |  |  | 604 | MOP::Internal::Util::INSTALL_CV( $self->name, $name, $code, set_subname => 0 ); | 
| 505 | 420 |  |  |  |  | 759 | return; | 
| 506 |  |  |  |  |  |  | } | 
| 507 |  |  |  |  |  |  |  | 
| 508 |  |  |  |  |  |  | sub delete_method_alias { | 
| 509 | 5 |  |  | 5 | 1 | 2292 | my ($self, $name) = @_; | 
| 510 |  |  |  |  |  |  |  | 
| 511 | 5 | 50 |  |  |  | 11 | Carp::croak('[ARGS] You must specify the name of the method alias to remove') | 
| 512 |  |  |  |  |  |  | unless $name; | 
| 513 |  |  |  |  |  |  |  | 
| 514 |  |  |  |  |  |  | # check if we have a stash entry for $name ... | 
| 515 | 5 | 100 |  |  |  | 10 | if ( my $glob = $self->stash->{ $name } ) { | 
| 516 |  |  |  |  |  |  | # and if we have a NULL CV in it, ... | 
| 517 | 4 | 100 |  |  |  | 9 | if ( MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $glob ) ) { | 
| 518 |  |  |  |  |  |  | # then we need to die because this | 
| 519 |  |  |  |  |  |  | # shouldn't happen, we should only | 
| 520 |  |  |  |  |  |  | # delete regular methods. | 
| 521 | 1 |  |  |  |  | 83 | Carp::croak("[CONFLICT] Cannot delete an aliased method ($name) when there is a required method already there"); | 
| 522 |  |  |  |  |  |  | } | 
| 523 |  |  |  |  |  |  | else { | 
| 524 |  |  |  |  |  |  | # if we don't have a code slot ... | 
| 525 | 3 | 100 |  |  |  | 5 | return unless defined *{ $glob }{CODE}; | 
|  | 3 |  |  |  |  | 10 |  | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  | # we need to make sure it is local, and | 
| 528 |  |  |  |  |  |  | # otherwise, error accordingly | 
| 529 | 2 |  |  |  |  | 5 | my $method = MOP::Method->new( body => *{ $glob }{CODE} ); | 
|  | 2 |  |  |  |  | 7 |  | 
| 530 |  |  |  |  |  |  |  | 
| 531 | 2 | 100 |  |  |  | 30 | Carp::croak("[CONFLICT] Cannot delete an aliased method ($name) when there is a regular method already there") | 
| 532 |  |  |  |  |  |  | if $method->origin_stash eq $self->name; | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  | # but if we have a regular method, then we | 
| 535 |  |  |  |  |  |  | # can just delete the CV from the glob | 
| 536 | 1 |  |  |  |  | 3 | MOP::Internal::Util::REMOVE_CV_FROM_GLOB( $self->stash, $name ); | 
| 537 |  |  |  |  |  |  | } | 
| 538 |  |  |  |  |  |  | } | 
| 539 |  |  |  |  |  |  | # if there is no stash entry for $name, we do nothing | 
| 540 | 2 |  |  |  |  | 12 | return; | 
| 541 |  |  |  |  |  |  | } | 
| 542 |  |  |  |  |  |  |  | 
| 543 |  |  |  |  |  |  | sub has_method_alias { | 
| 544 | 30 |  |  | 30 | 1 | 4197 | my $class = $_[0]->name; | 
| 545 | 30 |  |  |  |  | 70 | my $stash = $_[0]->stash; | 
| 546 | 30 |  |  |  |  | 45 | my $name  = $_[1]; | 
| 547 |  |  |  |  |  |  |  | 
| 548 | 30 | 50 |  |  |  | 59 | Carp::croak('[ARGS] You must specify the name of the method alias to look for') | 
| 549 |  |  |  |  |  |  | unless $name; | 
| 550 |  |  |  |  |  |  |  | 
| 551 |  |  |  |  |  |  | # check these two easy cases first ... | 
| 552 | 30 | 100 |  |  |  | 81 | return 0 unless exists $stash->{ $name }; | 
| 553 | 28 | 100 |  |  |  | 68 | return 0 if MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $stash->{ $name } ); | 
| 554 |  |  |  |  |  |  |  | 
| 555 |  |  |  |  |  |  | # now we grab the CV and make sure it is | 
| 556 |  |  |  |  |  |  | # local, and return accordingly | 
| 557 | 23 | 100 |  |  |  | 70 | if ( my $code = MOP::Internal::Util::GET_GLOB_SLOT( $stash, $name, 'CODE' ) ) { | 
| 558 | 20 |  |  |  |  | 66 | return MOP::Method->new( body => $code )->origin_stash ne $class; | 
| 559 |  |  |  |  |  |  | } | 
| 560 |  |  |  |  |  |  |  | 
| 561 |  |  |  |  |  |  | # if there was no CV, return false. | 
| 562 | 3 |  |  |  |  | 11 | return 0; | 
| 563 |  |  |  |  |  |  | } | 
| 564 |  |  |  |  |  |  |  | 
| 565 |  |  |  |  |  |  | ## Slots | 
| 566 |  |  |  |  |  |  |  | 
| 567 |  |  |  |  |  |  | ## FIXME: | 
| 568 |  |  |  |  |  |  | ## The same problem we had methods needs to be fixed with | 
| 569 |  |  |  |  |  |  | ## slots, just checking the origin_stash v. class is | 
| 570 |  |  |  |  |  |  | ## not enough, we need to check aliasing as well. | 
| 571 |  |  |  |  |  |  | ## - SL | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  | # get them all; regular & aliased | 
| 574 |  |  |  |  |  |  | sub all_slots { | 
| 575 | 43 |  |  | 43 | 1 | 3489 | my $self = shift; | 
| 576 | 43 |  |  |  |  | 82 | my $has = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'HAS', 'HASH' ); | 
| 577 | 43 | 100 |  |  |  | 137 | return unless $has; | 
| 578 |  |  |  |  |  |  | return map { | 
| 579 | 18 |  |  |  |  | 47 | MOP::Slot->new( | 
| 580 |  |  |  |  |  |  | name        => $_, | 
| 581 | 18 |  |  |  |  | 117 | initializer => $has->{ $_ } | 
| 582 |  |  |  |  |  |  | ) | 
| 583 |  |  |  |  |  |  | } keys %$has; | 
| 584 |  |  |  |  |  |  | } | 
| 585 |  |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | # just the local slots | 
| 587 |  |  |  |  |  |  | sub slots { | 
| 588 | 26 |  |  | 26 | 1 | 158 | my $self  = shift; | 
| 589 | 26 |  |  |  |  | 68 | my $class = $self->name; | 
| 590 | 26 |  |  |  |  | 69 | my @roles = $self->roles; | 
| 591 |  |  |  |  |  |  | return grep { | 
| 592 | 26 | 100 | 33 |  |  | 65 | $_->origin_stash eq $class | 
|  | 6 |  |  |  |  | 57 |  | 
| 593 |  |  |  |  |  |  | || | 
| 594 |  |  |  |  |  |  | (@roles && $_->was_aliased_from( @roles )) | 
| 595 |  |  |  |  |  |  | } $self->all_slots | 
| 596 |  |  |  |  |  |  | } | 
| 597 |  |  |  |  |  |  |  | 
| 598 |  |  |  |  |  |  | # just the non-local slots | 
| 599 |  |  |  |  |  |  | sub aliased_slots { | 
| 600 | 8 |  |  | 8 | 1 | 47 | my $self  = shift; | 
| 601 | 8 |  |  |  |  | 25 | my $class = $self->name; | 
| 602 | 8 |  |  |  |  | 20 | return grep { $_->origin_stash ne $class } $self->all_slots | 
|  | 6 |  |  |  |  | 51 |  | 
| 603 |  |  |  |  |  |  | } | 
| 604 |  |  |  |  |  |  |  | 
| 605 |  |  |  |  |  |  | ## regular ... | 
| 606 |  |  |  |  |  |  |  | 
| 607 |  |  |  |  |  |  | sub has_slot { | 
| 608 | 11 |  |  | 11 | 1 | 10210 | my $self  = $_[0]; | 
| 609 | 11 |  |  |  |  | 22 | my $name  = $_[1]; | 
| 610 | 11 |  |  |  |  | 21 | my $class = $self->name; | 
| 611 | 11 |  |  |  |  | 25 | my $has   = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'HAS', 'HASH' ); | 
| 612 |  |  |  |  |  |  |  | 
| 613 | 11 | 50 |  |  |  | 28 | Carp::croak('[ARGS] You must specify the name of the slot to look for') | 
| 614 |  |  |  |  |  |  | unless $name; | 
| 615 |  |  |  |  |  |  |  | 
| 616 | 11 | 100 |  |  |  | 34 | return unless $has; | 
| 617 | 8 | 100 |  |  |  | 28 | return unless exists $has->{ $name }; | 
| 618 |  |  |  |  |  |  |  | 
| 619 | 4 |  |  |  |  | 9 | my @roles = $self->roles; | 
| 620 |  |  |  |  |  |  | my $slot  = MOP::Slot->new( | 
| 621 |  |  |  |  |  |  | name        => $name, | 
| 622 | 4 |  |  |  |  | 16 | initializer => $has->{ $name } | 
| 623 |  |  |  |  |  |  | ); | 
| 624 |  |  |  |  |  |  |  | 
| 625 | 4 |  | 66 |  |  | 52 | return $slot->origin_stash eq $class | 
| 626 |  |  |  |  |  |  | || (@roles && $slot->was_aliased_from( @roles )); | 
| 627 |  |  |  |  |  |  | } | 
| 628 |  |  |  |  |  |  |  | 
| 629 |  |  |  |  |  |  | sub get_slot { | 
| 630 | 16 |  |  | 16 | 1 | 2053 | my $self  = $_[0]; | 
| 631 | 16 |  |  |  |  | 22 | my $name  = $_[1]; | 
| 632 | 16 |  |  |  |  | 31 | my $class = $self->name; | 
| 633 | 16 |  |  |  |  | 30 | my $has   = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'HAS', 'HASH' ); | 
| 634 |  |  |  |  |  |  |  | 
| 635 | 16 | 50 |  |  |  | 41 | Carp::croak('[ARGS] You must specify the name of the slot to get') | 
| 636 |  |  |  |  |  |  | unless $name; | 
| 637 |  |  |  |  |  |  |  | 
| 638 | 16 | 100 |  |  |  | 42 | return unless $has; | 
| 639 | 13 | 100 |  |  |  | 35 | return unless exists $has->{ $name }; | 
| 640 |  |  |  |  |  |  |  | 
| 641 | 9 |  |  |  |  | 25 | my @roles = $self->roles; | 
| 642 |  |  |  |  |  |  | my $slot  = MOP::Slot->new( | 
| 643 |  |  |  |  |  |  | name        => $name, | 
| 644 | 9 |  |  |  |  | 34 | initializer => $has->{ $name } | 
| 645 |  |  |  |  |  |  | ); | 
| 646 |  |  |  |  |  |  |  | 
| 647 | 9 | 100 | 33 |  |  | 142 | return $slot | 
|  |  |  | 66 |  |  |  |  | 
| 648 |  |  |  |  |  |  | if $slot->origin_stash eq $class | 
| 649 |  |  |  |  |  |  | || (@roles && $slot->was_aliased_from( @roles )); | 
| 650 |  |  |  |  |  |  |  | 
| 651 | 1 |  |  |  |  | 3 | return; | 
| 652 |  |  |  |  |  |  | } | 
| 653 |  |  |  |  |  |  |  | 
| 654 |  |  |  |  |  |  | sub add_slot { | 
| 655 | 3 |  |  | 3 | 1 | 1036 | my $self        = $_[0]; | 
| 656 | 3 |  |  |  |  | 5 | my $name        = $_[1]; | 
| 657 | 3 |  |  |  |  | 3 | my $initializer = $_[2]; | 
| 658 |  |  |  |  |  |  |  | 
| 659 | 3 | 50 |  |  |  | 7 | Carp::croak('[ARGS] You must specify the name of the slot to add') | 
| 660 |  |  |  |  |  |  | unless $name; | 
| 661 |  |  |  |  |  |  |  | 
| 662 | 3 | 50 | 33 |  |  | 12 | Carp::croak('[ARGS] You must specify an initializer CODE reference to associate with the slot') | 
|  |  |  | 33 |  |  |  |  | 
| 663 |  |  |  |  |  |  | unless $initializer && (ref $initializer eq 'CODE' || MOP::Internal::Util::CAN_COERCE_TO_CODE_REF( $initializer )); | 
| 664 |  |  |  |  |  |  |  | 
| 665 | 3 |  |  |  |  | 6 | my $stash = $self->stash; | 
| 666 | 3 |  |  |  |  | 5 | my $class = $self->name; | 
| 667 | 3 |  |  |  |  | 15 | my $slot  = MOP::Slot->new( name => $name, initializer => $initializer ); | 
| 668 |  |  |  |  |  |  |  | 
| 669 |  |  |  |  |  |  | # just as with add_method, we take ownership | 
| 670 |  |  |  |  |  |  | # of the initializer and set the COMP STASH | 
| 671 |  |  |  |  |  |  | # field so that we know it is ours. | 
| 672 | 3 | 100 |  |  |  | 52 | MOP::Internal::Util::SET_COMP_STASH_FOR_CV( $slot->initializer, $class ) | 
| 673 |  |  |  |  |  |  | if $slot->origin_stash ne $class; | 
| 674 |  |  |  |  |  |  |  | 
| 675 | 3 |  |  |  |  | 8 | my $has = MOP::Internal::Util::GET_GLOB_SLOT( $stash, 'HAS', 'HASH' ); | 
| 676 | 3 | 100 |  |  |  | 10 | MOP::Internal::Util::SET_GLOB_SLOT( $stash, 'HAS', $has = {} ) | 
| 677 |  |  |  |  |  |  | unless $has; | 
| 678 |  |  |  |  |  |  |  | 
| 679 | 3 |  |  |  |  | 6 | $has->{ $name } = $initializer; | 
| 680 | 3 |  |  |  |  | 11 | return; | 
| 681 |  |  |  |  |  |  | } | 
| 682 |  |  |  |  |  |  |  | 
| 683 |  |  |  |  |  |  | sub delete_slot { | 
| 684 | 4 |  |  | 4 | 1 | 1812 | my $self  = $_[0]; | 
| 685 | 4 |  |  |  |  | 5 | my $name  = $_[1]; | 
| 686 | 4 |  |  |  |  | 8 | my $stash = $self->stash; | 
| 687 | 4 |  |  |  |  | 5 | my $class = $self->name; | 
| 688 |  |  |  |  |  |  |  | 
| 689 | 4 | 50 |  |  |  | 9 | Carp::croak('[ARGS] You must specify the name of the slot to delete') | 
| 690 |  |  |  |  |  |  | unless $name; | 
| 691 |  |  |  |  |  |  |  | 
| 692 | 4 |  |  |  |  | 9 | my $has = MOP::Internal::Util::GET_GLOB_SLOT( $stash, 'HAS', 'HASH' ); | 
| 693 |  |  |  |  |  |  |  | 
| 694 | 4 | 100 |  |  |  | 8 | return unless $has; | 
| 695 | 3 | 100 |  |  |  | 7 | return unless exists $has->{ $name }; | 
| 696 |  |  |  |  |  |  |  | 
| 697 |  |  |  |  |  |  | Carp::croak("[CONFLICT] Cannot delete a regular slot ($name) when there is an aliased slot already there") | 
| 698 |  |  |  |  |  |  | if MOP::Slot->new( | 
| 699 |  |  |  |  |  |  | name        => $name, | 
| 700 | 2 | 100 |  |  |  | 6 | initializer => $has->{ $name } | 
| 701 |  |  |  |  |  |  | )->origin_stash ne $class; | 
| 702 |  |  |  |  |  |  |  | 
| 703 | 1 |  |  |  |  | 3 | delete $has->{ $name }; | 
| 704 |  |  |  |  |  |  |  | 
| 705 | 1 |  |  |  |  | 8 | return; | 
| 706 |  |  |  |  |  |  | } | 
| 707 |  |  |  |  |  |  |  | 
| 708 |  |  |  |  |  |  | sub has_slot_alias { | 
| 709 | 8 |  |  | 8 | 1 | 4048 | my $self  = $_[0]; | 
| 710 | 8 |  |  |  |  | 12 | my $name  = $_[1]; | 
| 711 | 8 |  |  |  |  | 15 | my $class = $self->name; | 
| 712 | 8 |  |  |  |  | 19 | my $has   = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'HAS', 'HASH' ); | 
| 713 |  |  |  |  |  |  |  | 
| 714 | 8 | 50 |  |  |  | 21 | Carp::croak('[ARGS] You must specify the name of the slot alias to look for') | 
| 715 |  |  |  |  |  |  | unless $name; | 
| 716 |  |  |  |  |  |  |  | 
| 717 | 8 | 100 |  |  |  | 20 | return unless $has; | 
| 718 | 7 | 100 |  |  |  | 21 | return unless exists $has->{ $name }; | 
| 719 |  |  |  |  |  |  |  | 
| 720 |  |  |  |  |  |  | return MOP::Slot->new( | 
| 721 |  |  |  |  |  |  | name        => $name, | 
| 722 | 5 |  |  |  |  | 22 | initializer => $has->{ $name } | 
| 723 |  |  |  |  |  |  | )->origin_stash ne $class; | 
| 724 |  |  |  |  |  |  | } | 
| 725 |  |  |  |  |  |  |  | 
| 726 |  |  |  |  |  |  | sub get_slot_alias { | 
| 727 | 8 |  |  | 8 | 1 | 1406 | my $self  = $_[0]; | 
| 728 | 8 |  |  |  |  | 14 | my $name  = $_[1]; | 
| 729 | 8 |  |  |  |  | 16 | my $class = $self->name; | 
| 730 | 8 |  |  |  |  | 18 | my $has   = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'HAS', 'HASH' ); | 
| 731 |  |  |  |  |  |  |  | 
| 732 | 8 | 50 |  |  |  | 18 | Carp::croak('[ARGS] You must specify the name of the slot alias to get') | 
| 733 |  |  |  |  |  |  | unless $name; | 
| 734 |  |  |  |  |  |  |  | 
| 735 | 8 | 100 |  |  |  | 25 | return unless $has; | 
| 736 | 7 | 100 |  |  |  | 26 | return unless exists $has->{ $name }; | 
| 737 |  |  |  |  |  |  |  | 
| 738 |  |  |  |  |  |  | my $slot = MOP::Slot->new( | 
| 739 |  |  |  |  |  |  | name        => $name, | 
| 740 | 6 |  |  |  |  | 20 | initializer => $has->{ $name } | 
| 741 |  |  |  |  |  |  | ); | 
| 742 |  |  |  |  |  |  |  | 
| 743 | 6 | 100 |  |  |  | 79 | return $slot | 
| 744 |  |  |  |  |  |  | if $slot->origin_stash ne $class; | 
| 745 |  |  |  |  |  |  |  | 
| 746 | 2 |  |  |  |  | 6 | return; | 
| 747 |  |  |  |  |  |  | } | 
| 748 |  |  |  |  |  |  |  | 
| 749 |  |  |  |  |  |  | sub alias_slot { | 
| 750 | 3 |  |  | 3 | 1 | 994 | my $self        = $_[0]; | 
| 751 | 3 |  |  |  |  | 4 | my $name        = $_[1]; | 
| 752 | 3 |  |  |  |  | 4 | my $initializer = $_[2]; | 
| 753 |  |  |  |  |  |  |  | 
| 754 | 3 | 50 |  |  |  | 6 | Carp::croak('[ARGS] You must specify the name of the slot alias to add') | 
| 755 |  |  |  |  |  |  | unless $name; | 
| 756 |  |  |  |  |  |  |  | 
| 757 | 3 | 50 | 33 |  |  | 11 | Carp::croak('[ARGS] You must specify an initializer CODE reference to associate with the slot alias') | 
|  |  |  | 33 |  |  |  |  | 
| 758 |  |  |  |  |  |  | unless $initializer && (ref $initializer eq 'CODE' || MOP::Internal::Util::CAN_COERCE_TO_CODE_REF( $initializer )); | 
| 759 |  |  |  |  |  |  |  | 
| 760 | 3 |  |  |  |  | 6 | my $stash = $self->stash; | 
| 761 | 3 |  |  |  |  | 5 | my $class = $self->name; | 
| 762 | 3 |  |  |  |  | 13 | my $slot  = MOP::Slot->new( name => $name, initializer => $initializer ); | 
| 763 |  |  |  |  |  |  |  | 
| 764 | 3 | 100 |  |  |  | 52 | Carp::croak('[CONFLICT] Slot is from the local class (' . $class . '), it should be from a different class') | 
| 765 |  |  |  |  |  |  | if $slot->origin_stash eq $class; | 
| 766 |  |  |  |  |  |  |  | 
| 767 | 2 |  |  |  |  | 5 | my $has = MOP::Internal::Util::GET_GLOB_SLOT( $stash, 'HAS', 'HASH' ); | 
| 768 | 2 | 100 |  |  |  | 7 | MOP::Internal::Util::SET_GLOB_SLOT( $stash, 'HAS', $has = {} ) | 
| 769 |  |  |  |  |  |  | unless $has; | 
| 770 |  |  |  |  |  |  |  | 
| 771 | 2 |  |  |  |  | 3 | $has->{ $name } = $initializer; | 
| 772 | 2 |  |  |  |  | 11 | return; | 
| 773 |  |  |  |  |  |  | } | 
| 774 |  |  |  |  |  |  |  | 
| 775 |  |  |  |  |  |  | sub delete_slot_alias { | 
| 776 | 4 |  |  | 4 | 1 | 1160 | my $self  = $_[0]; | 
| 777 | 4 |  |  |  |  | 7 | my $name  = $_[1]; | 
| 778 | 4 |  |  |  |  | 6 | my $stash = $self->stash; | 
| 779 | 4 |  |  |  |  | 9 | my $class = $self->name; | 
| 780 |  |  |  |  |  |  |  | 
| 781 | 4 | 50 |  |  |  | 10 | Carp::croak('[ARGS] You must specify the name of the slot alias to delete') | 
| 782 |  |  |  |  |  |  | unless $name; | 
| 783 |  |  |  |  |  |  |  | 
| 784 | 4 |  |  |  |  | 8 | my $has = MOP::Internal::Util::GET_GLOB_SLOT( $stash, 'HAS', 'HASH' ); | 
| 785 |  |  |  |  |  |  |  | 
| 786 | 4 | 100 |  |  |  | 9 | return unless $has; | 
| 787 | 3 | 100 |  |  |  | 7 | return unless exists $has->{ $name }; | 
| 788 |  |  |  |  |  |  |  | 
| 789 |  |  |  |  |  |  | Carp::croak("[CONFLICT] Cannot delete an slot alias ($name) when there is an regular slot already there") | 
| 790 |  |  |  |  |  |  | if MOP::Slot->new( | 
| 791 |  |  |  |  |  |  | name        => $name, | 
| 792 | 2 | 100 |  |  |  | 5 | initializer => $has->{ $name } | 
| 793 |  |  |  |  |  |  | )->origin_stash eq $class; | 
| 794 |  |  |  |  |  |  |  | 
| 795 | 1 |  |  |  |  | 3 | delete $has->{ $name }; | 
| 796 |  |  |  |  |  |  |  | 
| 797 | 1 |  |  |  |  | 7 | return; | 
| 798 |  |  |  |  |  |  | } | 
| 799 |  |  |  |  |  |  |  | 
| 800 |  |  |  |  |  |  | 1; | 
| 801 |  |  |  |  |  |  |  | 
| 802 |  |  |  |  |  |  | __END__ |