0.39
[gitmo/Moose.git] / lib / Moose / Meta / Class.pm
CommitLineData
c0e30cf5 1
2package Moose::Meta::Class;
3
4use strict;
5use warnings;
6
648e79ae 7use Class::MOP;
8
6ba6d68c 9use Carp 'confess';
54b1cdf0 10use Scalar::Util 'weaken', 'blessed', 'reftype';
a15dff8d 11
48045612 12our $VERSION = '0.21';
d44714be 13our $AUTHORITY = 'cpan:STEVAN';
bc1e29b5 14
8ee73eeb 15use Moose::Meta::Method::Overriden;
16
c0e30cf5 17use base 'Class::MOP::Class';
18
598340d5 19__PACKAGE__->meta->add_attribute('roles' => (
ef333f17 20 reader => 'roles',
21 default => sub { [] }
22));
23
590868a3 24sub initialize {
25 my $class = shift;
26 my $pkg = shift;
27 $class->SUPER::initialize($pkg,
ac2dc464 28 'attribute_metaclass' => 'Moose::Meta::Attribute',
5cf3dbcf 29 'method_metaclass' => 'Moose::Meta::Method',
ac2dc464 30 'instance_metaclass' => 'Moose::Meta::Instance',
590868a3 31 @_);
ac2dc464 32}
590868a3 33
61bdd94f 34sub create {
35 my ($self, $package_name, %options) = @_;
36
37 (ref $options{roles} eq 'ARRAY')
38 || confess "You must pass an ARRAY ref of roles"
39 if exists $options{roles};
40
41 my $class = $self->SUPER::create($package_name, %options);
42
48045612 43 if (exists $options{roles}) {
61bdd94f 44 Moose::Util::apply_all_roles($class, @{$options{roles}});
45 }
46
47 return $class;
48}
49
17594769 50my %ANON_CLASSES;
51
52sub create_anon_class {
53 my ($self, %options) = @_;
54
55 my $cache_ok = delete $options{cache};
17594769 56
57 # something like Super::Class|Super::Class::2=Role|Role::1
58 my $cache_key = join '=' => (
6d5cbd2b 59 join('|', sort @{$options{superclasses} || []}),
60 join('|', sort @{$options{roles} || []}),
17594769 61 );
62
6d5cbd2b 63 if ($cache_ok && defined $ANON_CLASSES{$cache_key}) {
17594769 64 return $ANON_CLASSES{$cache_key};
65 }
66
67 my $new_class = $self->SUPER::create_anon_class(%options);
68
6d5cbd2b 69 $ANON_CLASSES{$cache_key} = $new_class
70 if $cache_ok;
17594769 71
72 return $new_class;
73}
74
ef333f17 75sub add_role {
76 my ($self, $role) = @_;
77 (blessed($role) && $role->isa('Moose::Meta::Role'))
78 || confess "Roles must be instances of Moose::Meta::Role";
79 push @{$self->roles} => $role;
80}
81
b8aeb4dc 82sub calculate_all_roles {
83 my $self = shift;
84 my %seen;
85 grep { !$seen{$_->name}++ } map { $_->calculate_all_roles } @{ $self->roles };
86}
87
ef333f17 88sub does_role {
89 my ($self, $role_name) = @_;
90 (defined $role_name)
91 || confess "You must supply a role name to look for";
9c429218 92 foreach my $class ($self->class_precedence_list) {
ac2dc464 93 next unless $class->can('meta');
9c429218 94 foreach my $role (@{$class->meta->roles}) {
95 return 1 if $role->does_role($role_name);
96 }
ef333f17 97 }
98 return 0;
99}
100
d79e62fd 101sub excludes_role {
102 my ($self, $role_name) = @_;
103 (defined $role_name)
104 || confess "You must supply a role name to look for";
ac2dc464 105 foreach my $class ($self->class_precedence_list) {
106 next unless $class->can('meta');
5cb193ed 107 # NOTE:
108 # in the pretty rare instance when a Moose metaclass
ac2dc464 109 # is itself extended with a role, this check needs to
5cb193ed 110 # be done since some items in the class_precedence_list
ac2dc464 111 # might in fact be Class::MOP based still.
112 next unless $class->meta->can('roles');
9c429218 113 foreach my $role (@{$class->meta->roles}) {
114 return 1 if $role->excludes_role($role_name);
115 }
d79e62fd 116 }
117 return 0;
118}
119
8c9d74e7 120sub new_object {
121 my ($class, %params) = @_;
122 my $self = $class->SUPER::new_object(%params);
123 foreach my $attr ($class->compute_all_applicable_attributes()) {
625d571f 124 if ( defined( my $init_arg = $attr->init_arg ) ) {
125 if ( exists($params{$init_arg}) && $attr->can('has_trigger') && $attr->has_trigger ) {
126 $attr->trigger->($self, $params{$init_arg}, $attr);
127 }
128 }
8c9d74e7 129 }
ac2dc464 130 return $self;
8c9d74e7 131}
132
a15dff8d 133sub construct_instance {
134 my ($class, %params) = @_;
ddd0ec20 135 my $meta_instance = $class->get_meta_instance;
575db57d 136 # FIXME:
137 # the code below is almost certainly incorrect
138 # but this is foreign inheritence, so we might
ac2dc464 139 # have to kludge it in the end.
ddd0ec20 140 my $instance = $params{'__INSTANCE__'} || $meta_instance->create_instance();
ac2dc464 141 foreach my $attr ($class->compute_all_applicable_attributes()) {
ddd0ec20 142 $attr->initialize_instance_slot($meta_instance, $instance, \%params)
a15dff8d 143 }
144 return $instance;
145}
146
093b12c2 147# FIXME:
148# This is ugly
ac2dc464 149sub get_method_map {
093b12c2 150 my $self = shift;
53dd42d8 151
152 if (defined $self->{'$!_package_cache_flag'} &&
66e08a8a 153 $self->{'$!_package_cache_flag'} == Class::MOP::check_package_cache_flag($self->meta->name)) {
53dd42d8 154 return $self->{'%!methods'};
155 }
156
ac2dc464 157 my $map = $self->{'%!methods'};
158
093b12c2 159 my $class_name = $self->name;
160 my $method_metaclass = $self->method_metaclass;
ac2dc464 161
093b12c2 162 foreach my $symbol ($self->list_all_package_symbols('CODE')) {
ac2dc464 163
093b12c2 164 my $code = $self->get_package_symbol('&' . $symbol);
ac2dc464 165
166 next if exists $map->{$symbol} &&
167 defined $map->{$symbol} &&
168 $map->{$symbol}->body == $code;
169
53dd42d8 170 my ($pkg, $name) = Class::MOP::get_code_info($code);
ac2dc464 171
53dd42d8 172 if ($pkg->can('meta')
4f8f3aab 173 # NOTE:
174 # we don't know what ->meta we are calling
53dd42d8 175 # here, so we need to be careful cause it
176 # just might blow up at us, or just complain
177 # loudly (in the case of Curses.pm) so we
4f8f3aab 178 # just be a little overly cautious here.
179 # - SL
180 && eval { no warnings; blessed($pkg->meta) }
181 && $pkg->meta->isa('Moose::Meta::Role')) {
093b12c2 182 #my $role = $pkg->meta->name;
183 #next unless $self->does_role($role);
184 }
185 else {
53dd42d8 186 next if ($pkg || '') ne $class_name &&
187 ($name || '') ne '__ANON__';
188
093b12c2 189 }
ac2dc464 190
093b12c2 191 $map->{$symbol} = $method_metaclass->wrap($code);
192 }
ac2dc464 193
093b12c2 194 return $map;
a7d0cd00 195}
196
093b12c2 197### ---------------------------------------------
198
a2eec5e7 199sub add_attribute {
200 my $self = shift;
e472c9a5 201 $self->SUPER::add_attribute(
202 (blessed $_[0] && $_[0]->isa('Class::MOP::Attribute')
203 ? $_[0]
204 : $self->_process_attribute(@_))
205 );
a2eec5e7 206}
207
78cd1d3b 208sub add_override_method_modifier {
209 my ($self, $name, $method, $_super_package) = @_;
d05cd563 210 (!$self->has_method($name))
211 || confess "Cannot add an override method if a local method is already present";
78cd1d3b 212 # need this for roles ...
213 $_super_package ||= $self->name;
214 my $super = $self->find_next_method_by_name($name);
215 (defined $super)
ac2dc464 216 || confess "You cannot override '$name' because it has no super method";
093b12c2 217 $self->add_method($name => Moose::Meta::Method::Overriden->wrap(sub {
78cd1d3b 218 my @args = @_;
78cd1d3b 219 no warnings 'redefine';
52c7c330 220 if ($Moose::SUPER_SLOT{$_super_package}) {
b644e331 221 local *{$Moose::SUPER_SLOT{$_super_package}} = sub { $super->body->(@args) };
b468a3d3 222 return $method->(@args);
52c7c330 223 } else {
b468a3d3 224 confess "Trying to call override modifier'd method without super()";
52c7c330 225 }
093b12c2 226 }));
78cd1d3b 227}
228
229sub add_augment_method_modifier {
ac2dc464 230 my ($self, $name, $method) = @_;
d05cd563 231 (!$self->has_method($name))
ac2dc464 232 || confess "Cannot add an augment method if a local method is already present";
78cd1d3b 233 my $super = $self->find_next_method_by_name($name);
234 (defined $super)
ac2dc464 235 || confess "You cannot augment '$name' because it has no super method";
236 my $_super_package = $super->package_name;
237 # BUT!,... if this is an overriden method ....
05d9eaf6 238 if ($super->isa('Moose::Meta::Method::Overriden')) {
ac2dc464 239 # we need to be sure that we actually
240 # find the next method, which is not
05d9eaf6 241 # an 'override' method, the reason is
ac2dc464 242 # that an 'override' method will not
05d9eaf6 243 # be the one calling inner()
ac2dc464 244 my $real_super = $self->_find_next_method_by_name_which_is_not_overridden($name);
05d9eaf6 245 $_super_package = $real_super->package_name;
ac2dc464 246 }
78cd1d3b 247 $self->add_method($name => sub {
248 my @args = @_;
78cd1d3b 249 no warnings 'redefine';
52c7c330 250 if ($Moose::INNER_SLOT{$_super_package}) {
53dd42d8 251 local *{$Moose::INNER_SLOT{$_super_package}} = sub {
252 local *{$Moose::INNER_SLOT{$_super_package}} = sub {};
b468a3d3 253 $method->(@args);
254 };
b644e331 255 return $super->body->(@args);
53dd42d8 256 }
257 else {
b644e331 258 return $super->body->(@args);
52c7c330 259 }
ac2dc464 260 });
78cd1d3b 261}
262
1341f10c 263## Private Utility methods ...
264
05d9eaf6 265sub _find_next_method_by_name_which_is_not_overridden {
266 my ($self, $name) = @_;
68efb014 267 foreach my $method ($self->find_all_methods_by_name($name)) {
ac2dc464 268 return $method->{code}
05d9eaf6 269 if blessed($method->{code}) && !$method->{code}->isa('Moose::Meta::Method::Overriden');
270 }
271 return undef;
272}
273
1341f10c 274sub _fix_metaclass_incompatability {
275 my ($self, @superclasses) = @_;
276 foreach my $super (@superclasses) {
277 # don't bother if it does not have a meta.
278 next unless $super->can('meta');
ac2dc464 279 # get the name, make sure we take
8ecb1fa0 280 # immutable classes into account
ac2dc464 281 my $super_meta_name = ($super->meta->is_immutable
8ecb1fa0 282 ? $super->meta->get_mutable_metaclass_name
283 : blessed($super->meta));
ac2dc464 284 # if it's meta is a vanilla Moose,
285 # then we can safely ignore it.
8ecb1fa0 286 next if $super_meta_name eq 'Moose::Meta::Class';
ac2dc464 287 # but if we have anything else,
1341f10c 288 # we need to check it out ...
289 unless (# see if of our metaclass is incompatible
8ecb1fa0 290 ($self->isa($super_meta_name) &&
1341f10c 291 # and see if our instance metaclass is incompatible
292 $self->instance_metaclass->isa($super->meta->instance_metaclass)) &&
293 # ... and if we are just a vanilla Moose
294 $self->isa('Moose::Meta::Class')) {
295 # re-initialize the meta ...
296 my $super_meta = $super->meta;
297 # NOTE:
ac2dc464 298 # We might want to consider actually
299 # transfering any attributes from the
300 # original meta into this one, but in
1341f10c 301 # general you should not have any there
ac2dc464 302 # at this point anyway, so it's very
1341f10c 303 # much an obscure edge case anyway
304 $self = $super_meta->reinitialize($self->name => (
ac2dc464 305 'attribute_metaclass' => $super_meta->attribute_metaclass,
5cf3dbcf 306 'method_metaclass' => $super_meta->method_metaclass,
307 'instance_metaclass' => $super_meta->instance_metaclass,
1341f10c 308 ));
309 }
310 }
ac2dc464 311 return $self;
1341f10c 312}
313
d7d8a8c7 314# NOTE:
d9bb6c63 315# this was crap anyway, see
316# Moose::Util::apply_all_roles
d7d8a8c7 317# instead
4498537c 318sub _apply_all_roles {
319 die 'DEPRECATED: use Moose::Util::apply_all_roles($meta, @roles) instead'
320}
1341f10c 321
322sub _process_attribute {
e472c9a5 323 my $self = shift;
d9bb6c63 324 my $name = shift;
325 my %options = ((scalar @_ == 1 && ref($_[0]) eq 'HASH') ? %{$_[0]} : @_);
326
1341f10c 327 if ($name =~ /^\+(.*)/) {
d7d8a8c7 328 return $self->_process_inherited_attribute($1, %options);
1341f10c 329 }
330 else {
d9bb6c63 331 my $attr_metaclass_name;
1341f10c 332 if ($options{metaclass}) {
c1935ade 333 my $metaclass_name = $options{metaclass};
334 eval {
335 my $possible_full_name = 'Moose::Meta::Attribute::Custom::' . $metaclass_name;
ac2dc464 336 Class::MOP::load_class($possible_full_name);
337 $metaclass_name = $possible_full_name->can('register_implementation')
c1935ade 338 ? $possible_full_name->register_implementation
339 : $possible_full_name;
340 };
341 if ($@) {
342 Class::MOP::load_class($metaclass_name);
343 }
d9bb6c63 344 $attr_metaclass_name = $metaclass_name;
1341f10c 345 }
346 else {
d9bb6c63 347 $attr_metaclass_name = $self->attribute_metaclass;
1341f10c 348 }
d9bb6c63 349
350 if ($options{traits}) {
17594769 351 my @traits;
352 foreach my $trait (@{$options{traits}}) {
353 eval {
354 my $possible_full_name = 'Moose::Meta::Attribute::Custom::Trait::' . $trait;
355 Class::MOP::load_class($possible_full_name);
356 push @traits => $possible_full_name->can('register_implementation')
357 ? $possible_full_name->register_implementation
358 : $possible_full_name;
359 };
360 if ($@) {
361 push @traits => $trait;
3bb22459 362 }
d9bb6c63 363 }
364
17594769 365 my $class = Moose::Meta::Class->create_anon_class(
366 superclasses => [ $attr_metaclass_name ],
367 roles => [ @traits ],
368 cache => 1,
369 );
370
d9bb6c63 371 $attr_metaclass_name = $class->name;
372 }
17594769 373
d9bb6c63 374 return $attr_metaclass_name->new($name, %options);
ac2dc464 375 }
1341f10c 376}
377
378sub _process_inherited_attribute {
379 my ($self, $attr_name, %options) = @_;
380 my $inherited_attr = $self->find_attribute_by_name($attr_name);
381 (defined $inherited_attr)
382 || confess "Could not find an attribute by the name of '$attr_name' to inherit from";
1341f10c 383 if ($inherited_attr->isa('Moose::Meta::Attribute')) {
d7d8a8c7 384 return $inherited_attr->clone_and_inherit_options(%options);
1341f10c 385 }
386 else {
387 # NOTE:
388 # kind of a kludge to handle Class::MOP::Attributes
d7d8a8c7 389 return $inherited_attr->Moose::Meta::Attribute::clone_and_inherit_options(%options);
ac2dc464 390 }
1341f10c 391}
392
5cf3dbcf 393## -------------------------------------------------
394
395use Moose::Meta::Method::Constructor;
1f779926 396use Moose::Meta::Method::Destructor;
5cf3dbcf 397
ac2dc464 398# This could be done by using SUPER and altering ->options
399# I am keeping it this way to make it more explicit.
400sub create_immutable_transformer {
401 my $self = shift;
402 my $class = Class::MOP::Immutable->new($self, {
403 read_only => [qw/superclasses/],
404 cannot_call => [qw/
405 add_method
406 alias_method
407 remove_method
408 add_attribute
409 remove_attribute
410 add_package_symbol
411 remove_package_symbol
412 add_role
413 /],
414 memoize => {
415 class_precedence_list => 'ARRAY',
416 compute_all_applicable_attributes => 'ARRAY',
417 get_meta_instance => 'SCALAR',
418 get_method_map => 'SCALAR',
419 # maybe ....
420 calculate_all_roles => 'ARRAY',
421 }
422 });
423 return $class;
424}
425
426sub make_immutable {
427 my $self = shift;
428 $self->SUPER::make_immutable
429 (
430 constructor_class => 'Moose::Meta::Method::Constructor',
431 destructor_class => 'Moose::Meta::Method::Destructor',
432 inline_destructor => 1,
433 # NOTE:
434 # no need to do this,
435 # Moose always does it
436 inline_accessors => 0,
437 @_,
438 );
5cf3dbcf 439}
440
c0e30cf5 4411;
442
443__END__
444
445=pod
446
447=head1 NAME
448
e522431d 449Moose::Meta::Class - The Moose metaclass
c0e30cf5 450
c0e30cf5 451=head1 DESCRIPTION
452
ac2dc464 453This is a subclass of L<Class::MOP::Class> with Moose specific
e522431d 454extensions.
455
ac2dc464 456For the most part, the only time you will ever encounter an
457instance of this class is if you are doing some serious deep
458introspection. To really understand this class, you need to refer
6ba6d68c 459to the L<Class::MOP::Class> documentation.
460
c0e30cf5 461=head1 METHODS
462
463=over 4
464
590868a3 465=item B<initialize>
466
61bdd94f 467=item B<create>
468
17594769 469Overrides original to accept a list of roles to apply to
61bdd94f 470the created class.
471
17594769 472 my $metaclass = Moose::Meta::Class->create( 'New::Class', roles => [...] );
473
474=item B<create_anon_class>
475
476Overrides original to support roles and caching.
477
478 my $metaclass = Moose::Meta::Class->create_anon_class(
479 superclasses => ['Foo'],
480 roles => [qw/Some Roles Go Here/],
481 cache => 1,
482 );
483
5cf3dbcf 484=item B<make_immutable>
485
ac2dc464 486Override original to add default options for inlining destructor
487and altering the Constructor metaclass.
488
489=item B<create_immutable_transformer>
490
491Override original to lock C<add_role> and memoize C<calculate_all_roles>
492
8c9d74e7 493=item B<new_object>
494
02a0fb52 495We override this method to support the C<trigger> attribute option.
496
a15dff8d 497=item B<construct_instance>
498
ac2dc464 499This provides some Moose specific extensions to this method, you
500almost never call this method directly unless you really know what
501you are doing.
6ba6d68c 502
503This method makes sure to handle the moose weak-ref, type-constraint
ac2dc464 504and type coercion features.
ef1d5f4b 505
093b12c2 506=item B<get_method_map>
e9ec68d6 507
ac2dc464 508This accommodates Moose::Meta::Role::Method instances, which are
509aliased, instead of added, but still need to be counted as valid
e9ec68d6 510methods.
511
78cd1d3b 512=item B<add_override_method_modifier ($name, $method)>
513
ac2dc464 514This will create an C<override> method modifier for you, and install
02a0fb52 515it in the package.
516
78cd1d3b 517=item B<add_augment_method_modifier ($name, $method)>
518
ac2dc464 519This will create an C<augment> method modifier for you, and install
02a0fb52 520it in the package.
521
2b14ac61 522=item B<calculate_all_roles>
523
ef333f17 524=item B<roles>
525
ac2dc464 526This will return an array of C<Moose::Meta::Role> instances which are
02a0fb52 527attached to this class.
528
ef333f17 529=item B<add_role ($role)>
530
ac2dc464 531This takes an instance of C<Moose::Meta::Role> in C<$role>, and adds it
02a0fb52 532to the list of associated roles.
533
ef333f17 534=item B<does_role ($role_name)>
535
ac2dc464 536This will test if this class C<does> a given C<$role_name>. It will
537not only check it's local roles, but ask them as well in order to
02a0fb52 538cascade down the role hierarchy.
539
d79e62fd 540=item B<excludes_role ($role_name)>
541
ac2dc464 542This will test if this class C<excludes> a given C<$role_name>. It will
543not only check it's local roles, but ask them as well in order to
d79e62fd 544cascade down the role hierarchy.
545
9e93dd19 546=item B<add_attribute ($attr_name, %params|$params)>
4e848edb 547
9e93dd19 548This method does the same thing as L<Class::MOP::Class::add_attribute>, but adds
549support for taking the C<$params> as a HASH ref.
ac1ef2f9 550
c0e30cf5 551=back
552
553=head1 BUGS
554
ac2dc464 555All complex software has bugs lurking in it, and this module is no
c0e30cf5 556exception. If you find a bug please either email me, or add the bug
557to cpan-RT.
558
c0e30cf5 559=head1 AUTHOR
560
561Stevan Little E<lt>stevan@iinteractive.comE<gt>
562
563=head1 COPYRIGHT AND LICENSE
564
778db3ac 565Copyright 2006-2008 by Infinity Interactive, Inc.
c0e30cf5 566
567L<http://www.iinteractive.com>
568
569This library is free software; you can redistribute it and/or modify
ac2dc464 570it under the same terms as Perl itself.
c0e30cf5 571
8a7a9c53 572=cut
1a563243 573