File Coverage

blib/lib/MOP/Role.pm
Criterion Covered Total %
statement 311 311 100.0
branch 167 202 82.6
condition 21 42 50.0
subroutine 45 45 100.0
pod 37 37 100.0
total 581 637 91.2


line stmt bran cond sub pod time code
1             package MOP::Role;
2             # ABSTRACT: A representation of a role
3              
4 28     28   940637 use strict;
  28         172  
  28         613  
5 28     28   154 use warnings;
  28         37  
  28         501  
6              
7 28     28   100 use Carp ();
  28         46  
  28         364  
8              
9 28     28   8716 use MOP::Method;
  28         59  
  28         722  
10 28     28   9158 use MOP::Slot;
  28         55  
  28         653  
11              
12 28     28   131 use MOP::Internal::Util;
  28         46  
  28         798  
13              
14             our $VERSION = '0.14';
15             our $AUTHORITY = 'cpan:STEVAN';
16              
17 28     28   106 use parent 'UNIVERSAL::Object::Immutable';
  28         37  
  28         77  
18              
19             sub BUILDARGS {
20 115     115 1 117224 my $class = shift;
21 115         151 my %args;
22              
23 115 100       264 if ( scalar( @_ ) == 1 ) {
24 16 100       31 if ( ref $_[0] ) {
25 4 50       11 if ( ref $_[0] eq 'HASH' ) {
26 4 100       11 if ( MOP::Internal::Util::IS_STASH_REF( $_[0] ) ) {
27             # if it is a stash, grab the name
28 2         7 %args = (
29             name => MOP::Internal::Util::GET_NAME( $_[0] ),
30             stash => $_[0]
31             );
32             }
33             else {
34             # just plain old HASH ref ...
35 2         3 %args = %{ $_[0] };
  2         7  
36             }
37             }
38             }
39             else {
40             # assume it is a single package name ...
41 12         27 %args = ( name => $_[0] );
42             }
43             }
44             else {
45             # assume we got key/value pairs ...
46 99         246 %args = @_;
47             }
48              
49             Carp::confess('[ARGS] You must specify a package name')
50 115 50       267 unless $args{name};
51              
52             Carp::confess('[ARGS] You must specify a valid package name, not `'.$_[0].'`')
53 115 50       345 unless MOP::Internal::Util::IS_VALID_MODULE_NAME( $args{name} );
54              
55 115         286 return \%args;
56             }
57              
58             sub CREATE {
59 115     115 1 1178 my ($class, $args) = @_;
60              
61             # intiialize the stash ...
62 115         195 my $stash = $args->{stash};
63              
64             # if we have it, otherwise get it ...
65 115 100       214 unless ( $stash ) {
66             # get a ref to to the stash itself ...
67 28     28   5674 no strict 'refs';
  28         42  
  28         76411  
68 113         142 $stash = \%{ $args->{name} . '::' };
  113         322  
69             }
70             # and then a ref to that, because we
71             # eventually will need to bless it and
72             # we do not want to bless the actual
73             # stash because that persists beyond
74             # the lifetime of this object, so we
75             # bless a ref of a ref then ...
76 115         297 return \$stash;
77             }
78              
79             # stash
80              
81             sub stash {
82 2104     2104 1 2262 my ($self) = @_;
83 2104         3525 return $$self; # returns the direct HASH ref of the stash
84             }
85              
86             # identity
87              
88             sub name {
89 1133     1133 1 26218 my ($self) = @_;
90 1133         1382 return MOP::Internal::Util::GET_NAME( $self->stash );
91             }
92              
93             sub version {
94 8     8 1 17 my ($self) = @_;
95 8         14 my $version = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'VERSION', 'SCALAR' );
96 8 50       20 return unless $version;
97 8         27 return $$version;
98             }
99              
100             sub authority {
101 8     8 1 13 my ($self) = @_;
102 8         18 my $authority = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'AUTHORITY', 'SCALAR' );
103 8 50       21 return unless $authority;
104 8         27 return $$authority;
105             }
106              
107             # other roles
108              
109             sub roles {
110 161     161 1 624 my ($self) = @_;
111 161         238 my $does = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'DOES', 'ARRAY' );
112 161 100       372 return unless $does;
113 52         132 return @$does;
114             }
115              
116             sub set_roles {
117 1     1 1 65 my ($self, @roles) = @_;
118 1 50       4 Carp::confess('[ARGS] You must specify at least one role')
119             if scalar( @roles ) == 0;
120 1         3 MOP::Internal::Util::SET_GLOB_SLOT( $self->stash, 'DOES', \@roles );
121 1         2 return;
122             }
123              
124             sub does_role {
125 23     23 1 2195 my ($self, $to_test) = @_;
126              
127 23 50       45 Carp::confess('[ARGS] You must specify a role')
128             unless $to_test;
129              
130 23         43 my @roles = $self->roles;
131              
132             # no roles, will never match ...
133 23 100       53 return 0 unless @roles;
134              
135             # try the simple way first ...
136 17         30 foreach my $role ( @roles ) {
137 20 100       76 return 1 if $role eq $to_test;
138             }
139              
140             # then try the harder way next ...
141 4         9 foreach my $role ( @roles ) {
142 4 100       83 return 1
143             if MOP::Role->new( name => $role )
144             ->does_role( $to_test );
145             }
146              
147             # oh well ...
148 1         7 return 0;
149             }
150              
151             ## Methods
152              
153             # get them all; regular, aliased & required
154             sub all_methods {
155 48     48 1 95 my $stash = $_[0]->stash;
156 48         58 my @methods;
157 48         253 foreach my $candidate ( keys %$stash ) {
158 1230 100       10699 if ( my $code = MOP::Internal::Util::GET_GLOB_SLOT( $stash, $candidate, 'CODE' ) ) {
159 944         1717 push @methods => MOP::Method->new( body => $code );
160             }
161             }
162 48         358 return @methods;
163             }
164              
165             # just the local non-required methods
166             sub methods {
167 21     21 1 998 my $self = shift;
168 21         39 my $class = $self->name;
169 21         55 my @roles = $self->roles;
170              
171 21         27 my @methods;
172 21         37 foreach my $method ( $self->all_methods ) {
173             # if the method is required, we don't want it
174 464 100       690 next if $method->is_required;
175              
176             # if the method is not originally from the
177             # class, then we probably don't want it ...
178 459 100       743 if ( $method->origin_stash ne $class ) {
179             # if our class has roles, then non-local
180             # methods *might* be valid, so ...
181              
182             # if we don't have roles, then
183             # it can't be valid, so we don't
184             # want it
185 3 50       13 next unless @roles;
186              
187             # if we do have roles, but our
188             # method was not aliased from one
189             # of them, then we don't want it.
190 3 50       10 next unless $method->was_aliased_from( @roles );
191              
192             # if we are here then we have
193             # a non-required method that is
194             # not from the local class, it
195             # has roles and was aliased from
196             # one of them, which means we want
197             # to keep it, so we let it fall through
198             }
199              
200             # if we are here then we have
201             # a non-required method that is
202             # either from the local class,
203             # or is not from a local class,
204             # but has fallen through our
205             # conditional above.
206              
207 459         777 push @methods => $method;
208             }
209              
210 21         80 return @methods;
211             }
212              
213             # just the non-local non-required methods
214             sub aliased_methods {
215 4     4 1 27 my $self = shift;
216 4         7 my $class = $self->name;
217 4 100       8 return grep { (!$_->is_required) && $_->origin_stash ne $class } $self->all_methods
  8         17  
218             }
219              
220             # just the required methods (locality be damned)
221             # NOTE:
222             # We don't care where are required method comes from
223             # just that one exists, so aliasing is not part of the
224             # criteria here.
225             # - SL
226             sub required_methods {
227 20     20 1 51 my $self = shift;
228 20         30 return grep { $_->is_required } $self->all_methods
  427         609  
229             }
230              
231             # required methods
232              
233             # NOTE:
234             # there is no real heavy need to use the MOP::Method API
235             # below because 1) it is not needed, and 2) the MOP::Method
236             # API is really just an information shim, it does not perform
237             # much in the way of actions. From my point of view, the below
238             # operations are mostly stash manipulation functions and so
239             # therefore belong here in the continuim of responsibility/
240             # ownership.
241             #
242             ## The only argument that could likely be made is for the
243             ## MOP::Method API to handle creating the NULL CV for the
244             ## add_required_method, but that would require us to pass in
245             ## a MOP::Method instance, which would be silly since we never
246             ## need it anyway.
247             #
248             # - SL
249              
250             sub has_required_method {
251 39     39 1 94 my $stash = $_[0]->stash;
252 39         58 my $name = $_[1];
253              
254 39 50       74 Carp::confess('[ARGS] You must specify the name of the required method to look for')
255             unless $name;
256              
257 39 100       129 return 0 unless exists $stash->{ $name };
258 36         111 return MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $stash->{ $name } );
259             }
260              
261             # consistency is a good thing ...
262 38     38 1 11256 sub requires_method { goto &has_required_method }
263              
264             sub get_required_method {
265 20     20 1 7420 my $class = $_[0]->name;
266 20         52 my $stash = $_[0]->stash;
267 20         39 my $name = $_[1];
268              
269 20 50       51 Carp::confess('[ARGS] You must specify the name of the required method to get')
270             unless $name;
271              
272             # check these two easy cases first ...
273 20 100       48 return unless exists $stash->{ $name };
274 17 100       41 return unless MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $stash->{ $name } );
275              
276             # now we grab the CV ...
277 6         21 my $method = MOP::Method->new(
278             body => MOP::Internal::Util::GET_GLOB_SLOT( $stash, $name, 'CODE' )
279             );
280             # and make sure it is local, and
281             # then return the method ...
282 6 100       107 return $method if $method->origin_stash eq $class;
283             # or return nothing ...
284 1         4 return;
285             }
286              
287             sub add_required_method {
288 5     5 1 3931 my ($self, $name) = @_;
289              
290 5 50       12 Carp::confess('[ARGS] You must specify the name of the required method to add')
291             unless $name;
292              
293             # if we already have a glob there ...
294 5 100       9 if ( my $glob = $self->stash->{ $name } ) {
295             # and if we have a NULL CV in it, just return
296 3 100       9 return if MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $glob );
297             # and if we don't and we have a CODE slot, we
298             # need to die because this doesn't make sense
299             Carp::confess("[CONFLICT] Cannot add a required method ($name) when there is a regular method already there")
300             if ref \$glob eq 'GLOB'
301 2         182 ? defined *{ $glob }{CODE}
302 2 50       6 : defined $glob;
    100          
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         5 return;
310             }
311              
312             sub delete_required_method {
313 4     4 1 1504 my ($self, $name) = @_;
314              
315 4 50       9 Carp::confess('[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       8 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::confess("[CONFLICT] Cannot delete a required method ($name) when there is a regular method already there")
331 2 100       3 if defined *{ $glob }{CODE};
  2         168  
332              
333             # if we have the glob, but no CV slot (NULL or otherwise)
334             # we do nothing ...
335 1         2 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 13512 my $self = $_[0];
346 460         577 my $class = $self->name;
347 460         641 my $stash = $self->stash;
348 460         1017 my $name = $_[1];
349              
350 460 50       612 Carp::confess('[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       998 return 0 unless exists $stash->{ $name };
355 35 100       184 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       74 if ( my $code = MOP::Internal::Util::GET_GLOB_SLOT( $stash, $name, 'CODE' ) ) {
360 27         99 my $method = MOP::Method->new( body => $code );
361 27         406 my @roles = $self->roles;
362             # and make sure it is local, and
363             # then return accordingly
364 27   100     145 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         10 return 0;
370             }
371              
372             sub get_method {
373 22     22 1 6255 my $self = $_[0];
374 22         81 my $class = $self->name;
375 22         50 my $stash = $self->stash;
376 22         47 my $name = $_[1];
377              
378 22 50       45 Carp::confess('[ARGS] You must specify the name of the method to get')
379             unless $name;
380              
381             # check the easy cases first ...
382 22 100       74 return unless exists $stash->{ $name };
383 20 100       118 return if MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $stash->{ $name } );
384              
385             # now we grab the CV ...
386 17 100       45 if ( my $code = MOP::Internal::Util::GET_GLOB_SLOT( $stash, $name, 'CODE' ) ) {
387 14         47 my $method = MOP::Method->new( body => $code );
388 14         188 my @roles = $self->roles;
389             # and make sure it is local, and
390             # then return accordingly
391 14 100 66     48 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         19 return;
398             }
399              
400             sub add_method {
401 1     1 1 2 my ($self, $name, $code) = @_;
402              
403 1 50       2 Carp::confess('[ARGS] You must specify the name of the method to add')
404             unless $name;
405              
406 1 50 33     6 Carp::confess('[ARGS] You must specify a CODE reference to add as a method')
407             unless $code && ref $code eq 'CODE';
408              
409 1         3 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 2179 my ($self, $name) = @_;
415              
416 5 50       10 Carp::confess('[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       16 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         164 Carp::confess("[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       4 return unless defined *{ $glob }{CODE};
  3         8  
431              
432             # we need to make sure it is local, and
433             # otherwise, error accordingly
434 2         16 my $method = MOP::Method->new( body => *{ $glob }{CODE} );
  2         6  
435 2         27 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       3 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     5 unless ( @roles && $method->was_aliased_from( @roles ) ) {
448 1         78 Carp::confess("[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 15     15 1 1531 my $class = $_[0]->name;
465 15         32 my $stash = $_[0]->stash;
466 15         25 my $name = $_[1];
467              
468 15 50       32 Carp::confess('[ARGS] You must specify the name of the method alias to look for')
469             unless $name;
470              
471             # check the easy cases first ...
472 15 100       40 return unless exists $stash->{ $name };
473 13 100       34 return if MOP::Internal::Util::DOES_GLOB_HAVE_NULL_CV( $stash->{ $name } );
474              
475             # now we grab the CV ...
476 12 100       49 if ( my $code = MOP::Internal::Util::GET_GLOB_SLOT( $stash, $name, 'CODE' ) ) {
477 9         32 my $method = MOP::Method->new( body => $code );
478             # and make sure it is not local, and
479             # then return accordingly
480 9 100       126 return $method
481             if $method->origin_stash ne $class;
482             }
483              
484             # if there was no CV, return false.
485 5         29 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 421     421 1 511 my ($self, $name, $code) = @_;
497              
498 421 50       548 Carp::confess('[ARGS] You must specify the name of the method alias to add')
499             unless $name;
500              
501 421 50 33     1014 Carp::confess('[ARGS] You must specify a CODE reference to add as a method alias')
502             unless $code && ref $code eq 'CODE';
503              
504 421         502 MOP::Internal::Util::INSTALL_CV( $self->name, $name, $code, set_subname => 0 );
505 421         629 return;
506             }
507              
508             sub delete_method_alias {
509 6     6 1 2180 my ($self, $name) = @_;
510              
511 6 50       14 Carp::confess('[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 6 100       12 if ( my $glob = $self->stash->{ $name } ) {
516             # and if we have a NULL CV in it, ...
517 5 100       12 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         77 Carp::confess("[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 4 100       6 return unless defined *{ $glob }{CODE};
  4         13  
526              
527             # we need to make sure it is local, and
528             # otherwise, error accordingly
529 3         6 my $method = MOP::Method->new( body => *{ $glob }{CODE} );
  3         11  
530              
531 3 100       40 Carp::confess("[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 2         6 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 3         18 return;
541             }
542              
543             sub has_method_alias {
544 33     33 1 4531 my $class = $_[0]->name;
545 33         59 my $stash = $_[0]->stash;
546 33         41 my $name = $_[1];
547              
548 33 50       72 Carp::confess('[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 33 100       77 return 0 unless exists $stash->{ $name };
553 30 100       62 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 25 100       72 if ( my $code = MOP::Internal::Util::GET_GLOB_SLOT( $stash, $name, 'CODE' ) ) {
558 21         73 return MOP::Method->new( body => $code )->origin_stash ne $class;
559             }
560              
561             # if there was no CV, return false.
562 4         13 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 49     49 1 3826 my $self = shift;
576 49         94 my $has = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'HAS', 'HASH' );
577 49 100       233 return unless $has;
578             return map {
579 24         61 MOP::Slot->new(
580             name => $_,
581 24         137 initializer => $has->{ $_ }
582             )
583             } keys %$has;
584             }
585              
586             # just the local slots
587             sub slots {
588 28     28 1 1091 my $self = shift;
589 28         64 my $class = $self->name;
590 28         85 my @roles = $self->roles;
591             return grep {
592 28 100 33     69 $_->origin_stash eq $class
  8         80  
593             ||
594             (@roles && $_->was_aliased_from( @roles ))
595             } $self->all_slots
596             }
597              
598             # just the non-local slots
599             sub aliased_slots {
600 10     10 1 59 my $self = shift;
601 10         24 my $class = $self->name;
602 10         24 return grep { $_->origin_stash ne $class } $self->all_slots
  8         75  
603             }
604              
605             ## regular ...
606              
607             sub has_slot {
608 13     13 1 11433 my $self = $_[0];
609 13         21 my $name = $_[1];
610 13         24 my $class = $self->name;
611 13         30 my $has = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'HAS', 'HASH' );
612              
613 13 50       31 Carp::confess('[ARGS] You must specify the name of the slot to look for')
614             unless $name;
615              
616 13 100       35 return unless $has;
617 10 100       39 return unless exists $has->{ $name };
618              
619 6         14 my @roles = $self->roles;
620             my $slot = MOP::Slot->new(
621             name => $name,
622 6         20 initializer => $has->{ $name }
623             );
624              
625 6   66     77 return $slot->origin_stash eq $class
626             || (@roles && $slot->was_aliased_from( @roles ));
627             }
628              
629             sub get_slot {
630 18     18 1 3309 my $self = $_[0];
631 18         31 my $name = $_[1];
632 18         37 my $class = $self->name;
633 18         39 my $has = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'HAS', 'HASH' );
634              
635 18 50       42 Carp::confess('[ARGS] You must specify the name of the slot to get')
636             unless $name;
637              
638 18 100       36 return unless $has;
639 15 100       41 return unless exists $has->{ $name };
640              
641 11         28 my @roles = $self->roles;
642             my $slot = MOP::Slot->new(
643             name => $name,
644 11         39 initializer => $has->{ $name }
645             );
646              
647 11 100 33     155 return $slot
      66        
648             if $slot->origin_stash eq $class
649             || (@roles && $slot->was_aliased_from( @roles ));
650              
651 2         5 return;
652             }
653              
654             sub add_slot {
655 3     3 1 3390 my $self = $_[0];
656 3         8 my $name = $_[1];
657 3         4 my $initializer = $_[2];
658              
659 3 50       10 Carp::confess('[ARGS] You must specify the name of the slot to add')
660             unless $name;
661              
662 3 50 33     16 Carp::confess('[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         10 my $stash = $self->stash;
666 3         9 my $class = $self->name;
667 3         18 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       60 MOP::Internal::Util::SET_COMP_STASH_FOR_CV( $slot->initializer, $class )
673             if $slot->origin_stash ne $class;
674              
675 3         11 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         8 $has->{ $name } = $initializer;
680 3         14 return;
681             }
682              
683             sub delete_slot {
684 4     4 1 1802 my $self = $_[0];
685 4         5 my $name = $_[1];
686 4         9 my $stash = $self->stash;
687 4         5 my $class = $self->name;
688              
689 4 50       8 Carp::confess('[ARGS] You must specify the name of the slot to delete')
690             unless $name;
691              
692 4         14 my $has = MOP::Internal::Util::GET_GLOB_SLOT( $stash, 'HAS', 'HASH' );
693              
694 4 100       9 return unless $has;
695 3 100       6 return unless exists $has->{ $name };
696              
697             Carp::confess("[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       8 initializer => $has->{ $name }
701             )->origin_stash ne $class;
702              
703 1         3 delete $has->{ $name };
704              
705 1         7 return;
706             }
707              
708             sub has_slot_alias {
709 9     9 1 4150 my $self = $_[0];
710 9         13 my $name = $_[1];
711 9         20 my $class = $self->name;
712 9         20 my $has = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'HAS', 'HASH' );
713              
714 9 50       19 Carp::confess('[ARGS] You must specify the name of the slot alias to look for')
715             unless $name;
716              
717 9 100       20 return unless $has;
718 8 100       30 return unless exists $has->{ $name };
719              
720             return MOP::Slot->new(
721             name => $name,
722 6         22 initializer => $has->{ $name }
723             )->origin_stash ne $class;
724             }
725              
726             sub get_slot_alias {
727 9     9 1 1068 my $self = $_[0];
728 9         14 my $name = $_[1];
729 9         16 my $class = $self->name;
730 9         21 my $has = MOP::Internal::Util::GET_GLOB_SLOT( $self->stash, 'HAS', 'HASH' );
731              
732 9 50       20 Carp::confess('[ARGS] You must specify the name of the slot alias to get')
733             unless $name;
734              
735 9 100       26 return unless $has;
736 8 100       19 return unless exists $has->{ $name };
737              
738             my $slot = MOP::Slot->new(
739             name => $name,
740 7         37 initializer => $has->{ $name }
741             );
742              
743 7 100       85 return $slot
744             if $slot->origin_stash ne $class;
745              
746 2         4 return;
747             }
748              
749             sub alias_slot {
750 3     3 1 976 my $self = $_[0];
751 3         4 my $name = $_[1];
752 3         3 my $initializer = $_[2];
753              
754 3 50       6 Carp::confess('[ARGS] You must specify the name of the slot alias to add')
755             unless $name;
756              
757 3 50 33     12 Carp::confess('[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         5 my $stash = $self->stash;
761 3         4 my $class = $self->name;
762 3         13 my $slot = MOP::Slot->new( name => $name, initializer => $initializer );
763              
764 3 100       39 Carp::confess('[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       6 MOP::Internal::Util::SET_GLOB_SLOT( $stash, 'HAS', $has = {} )
769             unless $has;
770              
771 2         3 $has->{ $name } = $initializer;
772 2         7 return;
773             }
774              
775             sub delete_slot_alias {
776 4     4 1 1117 my $self = $_[0];
777 4         4 my $name = $_[1];
778 4         9 my $stash = $self->stash;
779 4         7 my $class = $self->name;
780              
781 4 50       8 Carp::confess('[ARGS] You must specify the name of the slot alias to delete')
782             unless $name;
783              
784 4         6 my $has = MOP::Internal::Util::GET_GLOB_SLOT( $stash, 'HAS', 'HASH' );
785              
786 4 100       7 return unless $has;
787 3 100       7 return unless exists $has->{ $name };
788              
789             Carp::confess("[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       7 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__