2 package Moose::Meta::Class;
10 use Scalar::Util 'weaken', 'blessed';
12 our $VERSION = '0.50';
13 our $AUTHORITY = 'cpan:STEVAN';
15 use Moose::Meta::Method::Overriden;
16 use Moose::Meta::Method::Augmented;
18 use base 'Class::MOP::Class';
20 __PACKAGE__->meta->add_attribute('roles' => (
25 __PACKAGE__->meta->add_attribute('error_builder' => (
26 reader => 'error_builder',
30 __PACKAGE__->meta->add_attribute('error_class' => (
31 reader => 'error_class',
38 return Class::MOP::get_metaclass_by_name($pkg)
39 || $class->SUPER::initialize($pkg,
40 'attribute_metaclass' => 'Moose::Meta::Attribute',
41 'method_metaclass' => 'Moose::Meta::Method',
42 'instance_metaclass' => 'Moose::Meta::Instance',
48 my ($self, $package_name, %options) = @_;
50 (ref $options{roles} eq 'ARRAY')
51 || $self->throw_error("You must pass an ARRAY ref of roles", data => $options{roles})
52 if exists $options{roles};
54 my $class = $self->SUPER::create($package_name, %options);
56 if (exists $options{roles}) {
57 Moose::Util::apply_all_roles($class, @{$options{roles}});
65 sub create_anon_class {
66 my ($self, %options) = @_;
68 my $cache_ok = delete $options{cache};
70 # something like Super::Class|Super::Class::2=Role|Role::1
71 my $cache_key = join '=' => (
72 join('|', sort @{$options{superclasses} || []}),
73 join('|', sort @{$options{roles} || []}),
76 if ($cache_ok && defined $ANON_CLASSES{$cache_key}) {
77 return $ANON_CLASSES{$cache_key};
80 my $new_class = $self->SUPER::create_anon_class(%options);
82 $ANON_CLASSES{$cache_key} = $new_class
89 my ($self, $role) = @_;
90 (blessed($role) && $role->isa('Moose::Meta::Role'))
91 || $self->throw_error("Roles must be instances of Moose::Meta::Role", data => $role);
92 push @{$self->roles} => $role;
95 sub calculate_all_roles {
98 grep { !$seen{$_->name}++ } map { $_->calculate_all_roles } @{ $self->roles };
102 my ($self, $role_name) = @_;
104 || $self->throw_error("You must supply a role name to look for");
105 foreach my $class ($self->class_precedence_list) {
106 next unless $class->can('meta') && $class->meta->can('roles');
107 foreach my $role (@{$class->meta->roles}) {
108 return 1 if $role->does_role($role_name);
115 my ($self, $role_name) = @_;
117 || $self->throw_error("You must supply a role name to look for");
118 foreach my $class ($self->class_precedence_list) {
119 next unless $class->can('meta');
121 # in the pretty rare instance when a Moose metaclass
122 # is itself extended with a role, this check needs to
123 # be done since some items in the class_precedence_list
124 # might in fact be Class::MOP based still.
125 next unless $class->meta->can('roles');
126 foreach my $role (@{$class->meta->roles}) {
127 return 1 if $role->excludes_role($role_name);
134 my ($class, %params) = @_;
135 my $self = $class->SUPER::new_object(%params);
136 foreach my $attr ($class->compute_all_applicable_attributes()) {
137 # if we have a trigger, then ...
138 if ($attr->can('has_trigger') && $attr->has_trigger) {
139 # make sure we have an init-arg ...
140 if (defined(my $init_arg = $attr->init_arg)) {
141 # now make sure an init-arg was passes ...
142 if (exists $params{$init_arg}) {
143 # and if get here, fire the trigger
146 # check if there is a coercion
147 ($attr->should_coerce
148 # and if so, we need to grab the
149 # value that is actually been stored
150 ? $attr->get_read_method_ref->($self)
151 # otherwise, just get the value from
152 # the constructor params
153 : $params{$init_arg}),
163 sub construct_instance {
164 my ($class, %params) = @_;
165 my $meta_instance = $class->get_meta_instance;
167 # the code below is almost certainly incorrect
168 # but this is foreign inheritence, so we might
169 # have to kludge it in the end.
170 my $instance = $params{'__INSTANCE__'} || $meta_instance->create_instance();
171 foreach my $attr ($class->compute_all_applicable_attributes()) {
172 $attr->initialize_instance_slot($meta_instance, $instance, \%params);
182 if (defined $self->{'$!_package_cache_flag'} &&
183 $self->{'$!_package_cache_flag'} == Class::MOP::check_package_cache_flag($self->meta->name)) {
184 return $self->{'%!methods'};
187 my $map = $self->{'%!methods'};
189 my $class_name = $self->name;
190 my $method_metaclass = $self->method_metaclass;
192 my %all_code = $self->get_all_package_symbols('CODE');
194 foreach my $symbol (keys %all_code) {
195 my $code = $all_code{$symbol};
197 next if exists $map->{$symbol} &&
198 defined $map->{$symbol} &&
199 $map->{$symbol}->body == $code;
201 my ($pkg, $name) = Class::MOP::get_code_info($code);
203 if ($pkg->can('meta')
205 # we don't know what ->meta we are calling
206 # here, so we need to be careful cause it
207 # just might blow up at us, or just complain
208 # loudly (in the case of Curses.pm) so we
209 # just be a little overly cautious here.
211 && eval { no warnings; blessed($pkg->meta) }
212 && $pkg->meta->isa('Moose::Meta::Role')) {
213 #my $role = $pkg->meta->name;
214 #next unless $self->does_role($role);
219 # in 5.10 constant.pm the constants show up
220 # as being in the right package, but in pre-5.10
221 # they show up as constant::__ANON__ so we
222 # make an exception here to be sure that things
223 # work as expected in both.
225 unless ($pkg eq 'constant' && $name eq '__ANON__') {
226 next if ($pkg || '') ne $class_name ||
227 (($name || '') ne '__ANON__' && ($pkg || '') ne $class_name);
232 $map->{$symbol} = $method_metaclass->wrap(
234 package_name => $class_name,
242 ### ---------------------------------------------
246 $self->SUPER::add_attribute(
247 (blessed $_[0] && $_[0]->isa('Class::MOP::Attribute')
249 : $self->_process_attribute(@_))
253 sub add_override_method_modifier {
254 my ($self, $name, $method, $_super_package) = @_;
256 (!$self->has_method($name))
257 || $self->throw_error("Cannot add an override method if a local method is already present");
259 $self->add_method($name => Moose::Meta::Method::Overriden->new(
262 package => $_super_package, # need this for roles
267 sub add_augment_method_modifier {
268 my ($self, $name, $method) = @_;
269 (!$self->has_method($name))
270 || $self->throw_error("Cannot add an augment method if a local method is already present");
272 $self->add_method($name => Moose::Meta::Method::Augmented->new(
279 ## Private Utility methods ...
281 sub _find_next_method_by_name_which_is_not_overridden {
282 my ($self, $name) = @_;
283 foreach my $method ($self->find_all_methods_by_name($name)) {
284 return $method->{code}
285 if blessed($method->{code}) && !$method->{code}->isa('Moose::Meta::Method::Overriden');
290 sub _fix_metaclass_incompatability {
291 my ($self, @superclasses) = @_;
292 foreach my $super (@superclasses) {
293 # don't bother if it does not have a meta.
294 next unless $super->can('meta');
295 # get the name, make sure we take
296 # immutable classes into account
297 my $super_meta_name = ($super->meta->is_immutable
298 ? $super->meta->get_mutable_metaclass_name
299 : blessed($super->meta));
300 # if it's meta is a vanilla Moose,
301 # then we can safely ignore it.
302 next if $super_meta_name eq 'Moose::Meta::Class';
303 # but if we have anything else,
304 # we need to check it out ...
305 unless (# see if of our metaclass is incompatible
306 ($self->isa($super_meta_name) &&
307 # and see if our instance metaclass is incompatible
308 $self->instance_metaclass->isa($super->meta->instance_metaclass)) &&
309 # ... and if we are just a vanilla Moose
310 $self->isa('Moose::Meta::Class')) {
311 # re-initialize the meta ...
312 my $super_meta = $super->meta;
314 # We might want to consider actually
315 # transfering any attributes from the
316 # original meta into this one, but in
317 # general you should not have any there
318 # at this point anyway, so it's very
319 # much an obscure edge case anyway
320 $self = $super_meta->reinitialize($self->name => (
321 'attribute_metaclass' => $super_meta->attribute_metaclass,
322 'method_metaclass' => $super_meta->method_metaclass,
323 'instance_metaclass' => $super_meta->instance_metaclass,
331 # this was crap anyway, see
332 # Moose::Util::apply_all_roles
334 sub _apply_all_roles {
335 Carp::croak 'DEPRECATED: use Moose::Util::apply_all_roles($meta, @roles) instead'
338 sub _process_attribute {
339 my ( $self, $name, @args ) = @_;
341 @args = %{$args[0]} if scalar @args == 1 && ref($args[0]) eq 'HASH';
343 if ($name =~ /^\+(.*)/) {
344 return $self->_process_inherited_attribute($1, @args);
347 return $self->_process_new_attribute($name, @args);
351 sub _process_new_attribute {
352 my ( $self, $name, @args ) = @_;
354 $self->attribute_metaclass->interpolate_class_and_new($name, @args);
357 sub _process_inherited_attribute {
358 my ($self, $attr_name, %options) = @_;
359 my $inherited_attr = $self->find_attribute_by_name($attr_name);
360 (defined $inherited_attr)
361 || $self->throw_error("Could not find an attribute by the name of '$attr_name' to inherit from", data => $attr_name);
362 if ($inherited_attr->isa('Moose::Meta::Attribute')) {
363 return $inherited_attr->clone_and_inherit_options(%options);
367 # kind of a kludge to handle Class::MOP::Attributes
368 return $inherited_attr->Moose::Meta::Attribute::clone_and_inherit_options(%options);
372 ## -------------------------------------------------
374 use Moose::Meta::Method::Constructor;
375 use Moose::Meta::Method::Destructor;
377 # This could be done by using SUPER and altering ->options
378 # I am keeping it this way to make it more explicit.
379 sub create_immutable_transformer {
381 my $class = Class::MOP::Immutable->new($self, {
394 remove_package_symbol
398 class_precedence_list => 'ARRAY',
399 compute_all_applicable_attributes => 'ARRAY',
400 get_meta_instance => 'SCALAR',
401 get_method_map => 'SCALAR',
403 calculate_all_roles => 'ARRAY',
406 # this is ugly, but so are typeglobs,
407 # so whattayahgonnadoboutit
410 add_package_symbol => sub {
411 my $original = shift;
412 $self->throw_error("Cannot add package symbols to an immutable metaclass")
413 unless (caller(2))[3] eq 'Class::MOP::Package::get_package_symbol';
414 goto $original->body;
423 $self->SUPER::make_immutable
425 constructor_class => 'Moose::Meta::Method::Constructor',
426 destructor_class => 'Moose::Meta::Method::Destructor',
427 inline_destructor => 1,
429 # no need to do this,
430 # Moose always does it
431 inline_accessors => 0,
436 #{ package Moose::Meta::Class::ErrorRoutines; %Carp::Internal?
441 my ( $self, @args ) = @_;
443 $self->raise_error($self->create_error(@args));
447 my ( $self, @args ) = @_;
452 my ( $self, @args ) = @_;
454 if ( @args % 2 == 1 ) {
455 unshift @args, "message";
460 local $level = $level + 1;
462 if ( my $class = $args{class} || ( ref $self && $self->error_class ) ) {
463 return $self->create_error_object( %args, class => $class );
465 my $builder = $args{builder} || ( ref($self) ? $self->error_builder : "confess" );
467 my $builder_method = ( ( ref($builder) && ref($builder) eq 'CODE' )
469 : ( $self->can("create_error_$builder") || "create_error_confess" ));
471 return $self->$builder_method(%args);
475 sub create_error_object {
476 my ( $self, %args ) = @_;
478 my $class = delete $args{class};
483 depth => ( ($args{depth} || 1) + ( $level + 1 ) ),
487 sub create_error_croak {
488 my ( $self, @args ) = @_;
489 $self->_create_error_carpmess( @args );
492 sub create_error_confess {
493 my ( $self, @args ) = @_;
494 $self->_create_error_carpmess( @args, longmess => 1 );
497 sub _create_error_carpmess {
498 my ( $self, %args ) = @_;
500 my $carp_level = $level + 1 + ( $args{depth} || 1 );
502 local $Carp::CarpLevel = $carp_level; # $Carp::CarpLevel + $carp_level ?
503 local $Carp::MaxArgNums = 20; # default is 8, usually we use named args which gets messier though
505 my @args = exists $args{message} ? $args{message} : ();
507 if ( $args{longmess} ) {
508 return Carp::longmess(@args);
510 return Carp::shortmess(@args);
522 Moose::Meta::Class - The Moose metaclass
526 This is a subclass of L<Class::MOP::Class> with Moose specific
529 For the most part, the only time you will ever encounter an
530 instance of this class is if you are doing some serious deep
531 introspection. To really understand this class, you need to refer
532 to the L<Class::MOP::Class> documentation.
542 Overrides original to accept a list of roles to apply to
545 my $metaclass = Moose::Meta::Class->create( 'New::Class', roles => [...] );
547 =item B<create_anon_class>
549 Overrides original to support roles and caching.
551 my $metaclass = Moose::Meta::Class->create_anon_class(
552 superclasses => ['Foo'],
553 roles => [qw/Some Roles Go Here/],
557 =item B<make_immutable>
559 Override original to add default options for inlining destructor
560 and altering the Constructor metaclass.
562 =item B<create_immutable_transformer>
564 Override original to lock C<add_role> and memoize C<calculate_all_roles>
568 We override this method to support the C<trigger> attribute option.
570 =item B<construct_instance>
572 This provides some Moose specific extensions to this method, you
573 almost never call this method directly unless you really know what
576 This method makes sure to handle the moose weak-ref, type-constraint
577 and type coercion features.
579 =item B<get_method_map>
581 This accommodates Moose::Meta::Role::Method instances, which are
582 aliased, instead of added, but still need to be counted as valid
585 =item B<add_override_method_modifier ($name, $method)>
587 This will create an C<override> method modifier for you, and install
590 =item B<add_augment_method_modifier ($name, $method)>
592 This will create an C<augment> method modifier for you, and install
595 =item B<calculate_all_roles>
599 This will return an array of C<Moose::Meta::Role> instances which are
600 attached to this class.
602 =item B<add_role ($role)>
604 This takes an instance of C<Moose::Meta::Role> in C<$role>, and adds it
605 to the list of associated roles.
607 =item B<does_role ($role_name)>
609 This will test if this class C<does> a given C<$role_name>. It will
610 not only check it's local roles, but ask them as well in order to
611 cascade down the role hierarchy.
613 =item B<excludes_role ($role_name)>
615 This will test if this class C<excludes> a given C<$role_name>. It will
616 not only check it's local roles, but ask them as well in order to
617 cascade down the role hierarchy.
619 =item B<add_attribute ($attr_name, %params|$params)>
621 This method does the same thing as L<Class::MOP::Class::add_attribute>, but adds
622 support for taking the C<$params> as a HASH ref.
624 =item B<throw_error $message, %extra>
626 Throws the error created by C<create_error> using C<raise_error>
628 =item B<create_error $message, %extra>
630 Creates an error message or object.
632 The default behavior is C<create_error_confess>.
634 If C<error_class> is set uses C<create_error_object>. Otherwise uses
635 C<error_builder> (a code reference or variant name), and calls the appropriate
636 C<create_error_$builder> method.
638 =item B<error_builder $builder_name>
640 Get or set the error builder. Defaults to C<confess>.
642 =item B<error_class $class_name>
644 Get or set the error class. Has no default.
646 =item B<create_error_confess %args>
648 Creates an error using L<Carp/longmess>
650 =item B<create_error_croak %args>
652 Creates an error using L<Carp/shortmess>
654 =item B<create_error_object %args>
656 Calls C<new> on the C<class> parameter in C<%args>. Usable with C<error_class>
657 to support custom error objects for your meta class.
659 =item B<raise_error $error>
661 Dies with an error object or string.
667 All complex software has bugs lurking in it, and this module is no
668 exception. If you find a bug please either email me, or add the bug
673 Stevan Little E<lt>stevan@iinteractive.comE<gt>
675 =head1 COPYRIGHT AND LICENSE
677 Copyright 2006-2008 by Infinity Interactive, Inc.
679 L<http://www.iinteractive.com>
681 This library is free software; you can redistribute it and/or modify
682 it under the same terms as Perl itself.