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, {
382 read_only => [qw/superclasses/],
389 remove_package_symbol
393 class_precedence_list => 'ARRAY',
394 compute_all_applicable_attributes => 'ARRAY',
395 get_meta_instance => 'SCALAR',
396 get_method_map => 'SCALAR',
398 calculate_all_roles => 'ARRAY',
401 # this is ugly, but so are typeglobs,
402 # so whattayahgonnadoboutit
405 add_package_symbol => sub {
406 my $original = shift;
407 $self->throw_error("Cannot add package symbols to an immutable metaclass")
408 unless (caller(2))[3] eq 'Class::MOP::Package::get_package_symbol';
409 goto $original->body;
418 $self->SUPER::make_immutable
420 constructor_class => 'Moose::Meta::Method::Constructor',
421 destructor_class => 'Moose::Meta::Method::Destructor',
422 inline_destructor => 1,
424 # no need to do this,
425 # Moose always does it
426 inline_accessors => 0,
431 #{ package Moose::Meta::Class::ErrorRoutines; %Carp::Internal?
436 my ( $self, @args ) = @_;
438 $self->raise_error($self->create_error(@args));
442 my ( $self, @args ) = @_;
447 my ( $self, @args ) = @_;
449 if ( @args % 2 == 1 ) {
450 unshift @args, "message";
455 local $level = $level + 1;
457 if ( my $class = $args{class} || ( ref $self && $self->error_class ) ) {
458 return $self->create_error_object( %args, class => $class );
460 my $builder = $args{builder} || ( ref($self) ? $self->error_builder : "confess" );
462 my $builder_method = ( ( ref($builder) && ref($builder) eq 'CODE' )
464 : ( $self->can("create_error_$builder") || "create_error_confess" ));
466 return $self->$builder_method(%args);
470 sub create_error_object {
471 my ( $self, %args ) = @_;
473 my $class = delete $args{class};
478 depth => ( ($args{depth} || 1) + ( $level + 1 ) ),
482 sub create_error_croak {
483 my ( $self, @args ) = @_;
484 $self->_create_error_carpmess( @args );
487 sub create_error_confess {
488 my ( $self, @args ) = @_;
489 $self->_create_error_carpmess( @args, longmess => 1 );
492 sub _create_error_carpmess {
493 my ( $self, %args ) = @_;
495 my $carp_level = $level + 1 + ( $args{depth} || 1 );
497 local $Carp::CarpLevel = $carp_level; # $Carp::CarpLevel + $carp_level ?
498 local $Carp::MaxArgNums = 20; # default is 8, usually we use named args which gets messier though
500 my @args = exists $args{message} ? $args{message} : ();
502 if ( $args{longmess} ) {
503 return Carp::longmess(@args);
505 return Carp::shortmess(@args);
517 Moose::Meta::Class - The Moose metaclass
521 This is a subclass of L<Class::MOP::Class> with Moose specific
524 For the most part, the only time you will ever encounter an
525 instance of this class is if you are doing some serious deep
526 introspection. To really understand this class, you need to refer
527 to the L<Class::MOP::Class> documentation.
537 Overrides original to accept a list of roles to apply to
540 my $metaclass = Moose::Meta::Class->create( 'New::Class', roles => [...] );
542 =item B<create_anon_class>
544 Overrides original to support roles and caching.
546 my $metaclass = Moose::Meta::Class->create_anon_class(
547 superclasses => ['Foo'],
548 roles => [qw/Some Roles Go Here/],
552 =item B<make_immutable>
554 Override original to add default options for inlining destructor
555 and altering the Constructor metaclass.
557 =item B<create_immutable_transformer>
559 Override original to lock C<add_role> and memoize C<calculate_all_roles>
563 We override this method to support the C<trigger> attribute option.
565 =item B<construct_instance>
567 This provides some Moose specific extensions to this method, you
568 almost never call this method directly unless you really know what
571 This method makes sure to handle the moose weak-ref, type-constraint
572 and type coercion features.
574 =item B<get_method_map>
576 This accommodates Moose::Meta::Role::Method instances, which are
577 aliased, instead of added, but still need to be counted as valid
580 =item B<add_override_method_modifier ($name, $method)>
582 This will create an C<override> method modifier for you, and install
585 =item B<add_augment_method_modifier ($name, $method)>
587 This will create an C<augment> method modifier for you, and install
590 =item B<calculate_all_roles>
594 This will return an array of C<Moose::Meta::Role> instances which are
595 attached to this class.
597 =item B<add_role ($role)>
599 This takes an instance of C<Moose::Meta::Role> in C<$role>, and adds it
600 to the list of associated roles.
602 =item B<does_role ($role_name)>
604 This will test if this class C<does> a given C<$role_name>. It will
605 not only check it's local roles, but ask them as well in order to
606 cascade down the role hierarchy.
608 =item B<excludes_role ($role_name)>
610 This will test if this class C<excludes> a given C<$role_name>. It will
611 not only check it's local roles, but ask them as well in order to
612 cascade down the role hierarchy.
614 =item B<add_attribute ($attr_name, %params|$params)>
616 This method does the same thing as L<Class::MOP::Class::add_attribute>, but adds
617 support for taking the C<$params> as a HASH ref.
619 =item B<throw_error $message, %extra>
621 Throws the error created by C<create_error> using C<raise_error>
623 =item B<create_error $message, %extra>
625 Creates an error message or object.
627 The default behavior is C<create_error_confess>.
629 If C<error_class> is set uses C<create_error_object>. Otherwise uses
630 C<error_builder> (a code reference or variant name), and calls the appropriate
631 C<create_error_$builder> method.
633 =item B<error_builder $builder_name>
635 Get or set the error builder. Defaults to C<confess>.
637 =item B<error_class $class_name>
639 Get or set the error class. Has no default.
641 =item B<create_error_confess %args>
643 Creates an error using L<Carp/longmess>
645 =item B<create_error_croak %args>
647 Creates an error using L<Carp/shortmess>
649 =item B<create_error_object %args>
651 Calls C<new> on the C<class> parameter in C<%args>. Usable with C<error_class>
652 to support custom error objects for your meta class.
654 =item B<raise_error $error>
656 Dies with an error object or string.
662 All complex software has bugs lurking in it, and this module is no
663 exception. If you find a bug please either email me, or add the bug
668 Stevan Little E<lt>stevan@iinteractive.comE<gt>
670 =head1 COPYRIGHT AND LICENSE
672 Copyright 2006-2008 by Infinity Interactive, Inc.
674 L<http://www.iinteractive.com>
676 This library is free software; you can redistribute it and/or modify
677 it under the same terms as Perl itself.