File Coverage

blib/lib/MOP/Role.pm
Criterion Covered Total %
statement 312 312 100.0
branch 166 200 83.0
condition 21 42 50.0
subroutine 46 46 100.0
pod 37 37 100.0
total 582 637 91.3


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__