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