throw_error in Attribute
[gitmo/Moose.git] / lib / Moose / Meta / Class.pm
CommitLineData
c0e30cf5 1
2package Moose::Meta::Class;
3
4use strict;
5use warnings;
6
0addec44 7use Class::MOP;
648e79ae 8
11c86f15 9use Carp ();
21f1e231 10use Scalar::Util 'weaken', 'blessed';
a15dff8d 11
eaa35e6e 12our $VERSION = '0.50';
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
11c86f15 25__PACKAGE__->meta->add_attribute('error_builder' => (
26 reader => 'error_builder',
27 default => 'confess',
28));
29
30__PACKAGE__->meta->add_attribute('error_class' => (
31 reader => 'error_class',
32));
33
34
590868a3 35sub initialize {
36 my $class = shift;
37 my $pkg = shift;
685f7e44 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',
43 @_
44 );
ac2dc464 45}
590868a3 46
61bdd94f 47sub create {
48 my ($self, $package_name, %options) = @_;
49
50 (ref $options{roles} eq 'ARRAY')
11c86f15 51 || $self->throw_error("You must pass an ARRAY ref of roles", data => $options{roles})
61bdd94f 52 if exists $options{roles};
53
54 my $class = $self->SUPER::create($package_name, %options);
55
48045612 56 if (exists $options{roles}) {
61bdd94f 57 Moose::Util::apply_all_roles($class, @{$options{roles}});
58 }
59
60 return $class;
61}
62
17594769 63my %ANON_CLASSES;
64
65sub create_anon_class {
66 my ($self, %options) = @_;
67
68 my $cache_ok = delete $options{cache};
17594769 69
70 # something like Super::Class|Super::Class::2=Role|Role::1
71 my $cache_key = join '=' => (
6d5cbd2b 72 join('|', sort @{$options{superclasses} || []}),
73 join('|', sort @{$options{roles} || []}),
17594769 74 );
75
6d5cbd2b 76 if ($cache_ok && defined $ANON_CLASSES{$cache_key}) {
17594769 77 return $ANON_CLASSES{$cache_key};
78 }
79
80 my $new_class = $self->SUPER::create_anon_class(%options);
81
6d5cbd2b 82 $ANON_CLASSES{$cache_key} = $new_class
83 if $cache_ok;
17594769 84
85 return $new_class;
86}
87
ef333f17 88sub add_role {
89 my ($self, $role) = @_;
90 (blessed($role) && $role->isa('Moose::Meta::Role'))
11c86f15 91 || $self->throw_error("Roles must be instances of Moose::Meta::Role", data => $role);
ef333f17 92 push @{$self->roles} => $role;
93}
94
b8aeb4dc 95sub calculate_all_roles {
96 my $self = shift;
97 my %seen;
98 grep { !$seen{$_->name}++ } map { $_->calculate_all_roles } @{ $self->roles };
99}
100
ef333f17 101sub does_role {
102 my ($self, $role_name) = @_;
103 (defined $role_name)
11c86f15 104 || $self->throw_error("You must supply a role name to look for");
9c429218 105 foreach my $class ($self->class_precedence_list) {
81c3738f 106 next unless $class->can('meta') && $class->meta->can('roles');
9c429218 107 foreach my $role (@{$class->meta->roles}) {
108 return 1 if $role->does_role($role_name);
109 }
ef333f17 110 }
111 return 0;
112}
113
d79e62fd 114sub excludes_role {
115 my ($self, $role_name) = @_;
116 (defined $role_name)
11c86f15 117 || $self->throw_error("You must supply a role name to look for");
ac2dc464 118 foreach my $class ($self->class_precedence_list) {
119 next unless $class->can('meta');
5cb193ed 120 # NOTE:
121 # in the pretty rare instance when a Moose metaclass
ac2dc464 122 # is itself extended with a role, this check needs to
5cb193ed 123 # be done since some items in the class_precedence_list
ac2dc464 124 # might in fact be Class::MOP based still.
125 next unless $class->meta->can('roles');
9c429218 126 foreach my $role (@{$class->meta->roles}) {
127 return 1 if $role->excludes_role($role_name);
128 }
d79e62fd 129 }
130 return 0;
131}
132
8c9d74e7 133sub new_object {
134 my ($class, %params) = @_;
135 my $self = $class->SUPER::new_object(%params);
136 foreach my $attr ($class->compute_all_applicable_attributes()) {
4078709c 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
144 $attr->trigger->(
145 $self,
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}),
154 $attr
155 );
156 }
157 }
625d571f 158 }
8c9d74e7 159 }
ac2dc464 160 return $self;
8c9d74e7 161}
162
a15dff8d 163sub construct_instance {
164 my ($class, %params) = @_;
ddd0ec20 165 my $meta_instance = $class->get_meta_instance;
575db57d 166 # FIXME:
167 # the code below is almost certainly incorrect
168 # but this is foreign inheritence, so we might
ac2dc464 169 # have to kludge it in the end.
ddd0ec20 170 my $instance = $params{'__INSTANCE__'} || $meta_instance->create_instance();
ac2dc464 171 foreach my $attr ($class->compute_all_applicable_attributes()) {
c32c2c61 172 $attr->initialize_instance_slot($meta_instance, $instance, \%params);
a15dff8d 173 }
174 return $instance;
175}
176
093b12c2 177# FIXME:
178# This is ugly
ac2dc464 179sub get_method_map {
093b12c2 180 my $self = shift;
53dd42d8 181
182 if (defined $self->{'$!_package_cache_flag'} &&
66e08a8a 183 $self->{'$!_package_cache_flag'} == Class::MOP::check_package_cache_flag($self->meta->name)) {
53dd42d8 184 return $self->{'%!methods'};
185 }
186
ac2dc464 187 my $map = $self->{'%!methods'};
188
093b12c2 189 my $class_name = $self->name;
190 my $method_metaclass = $self->method_metaclass;
ac2dc464 191
0addec44 192 my %all_code = $self->get_all_package_symbols('CODE');
ac2dc464 193
0addec44 194 foreach my $symbol (keys %all_code) {
195 my $code = $all_code{$symbol};
ac2dc464 196
197 next if exists $map->{$symbol} &&
198 defined $map->{$symbol} &&
199 $map->{$symbol}->body == $code;
200
53dd42d8 201 my ($pkg, $name) = Class::MOP::get_code_info($code);
ac2dc464 202
53dd42d8 203 if ($pkg->can('meta')
4f8f3aab 204 # NOTE:
205 # we don't know what ->meta we are calling
53dd42d8 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
4f8f3aab 209 # just be a little overly cautious here.
210 # - SL
211 && eval { no warnings; blessed($pkg->meta) }
212 && $pkg->meta->isa('Moose::Meta::Role')) {
093b12c2 213 #my $role = $pkg->meta->name;
214 #next unless $self->does_role($role);
215 }
216 else {
2887c827 217
218 # NOTE:
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.
224 # - SL
225 unless ($pkg eq 'constant' && $name eq '__ANON__') {
226 next if ($pkg || '') ne $class_name ||
227 (($name || '') ne '__ANON__' && ($pkg || '') ne $class_name);
228 }
53dd42d8 229
093b12c2 230 }
ac2dc464 231
1b2aea39 232 $map->{$symbol} = $method_metaclass->wrap(
233 $code,
234 package_name => $class_name,
235 name => $symbol
236 );
093b12c2 237 }
ac2dc464 238
093b12c2 239 return $map;
a7d0cd00 240}
241
093b12c2 242### ---------------------------------------------
243
a2eec5e7 244sub add_attribute {
245 my $self = shift;
e472c9a5 246 $self->SUPER::add_attribute(
247 (blessed $_[0] && $_[0]->isa('Class::MOP::Attribute')
248 ? $_[0]
249 : $self->_process_attribute(@_))
250 );
a2eec5e7 251}
252
78cd1d3b 253sub add_override_method_modifier {
254 my ($self, $name, $method, $_super_package) = @_;
18c2ec0e 255
d05cd563 256 (!$self->has_method($name))
11c86f15 257 || $self->throw_error("Cannot add an override method if a local method is already present");
18c2ec0e 258
259 $self->add_method($name => Moose::Meta::Method::Overriden->new(
3f9e4b0a 260 method => $method,
261 class => $self,
262 package => $_super_package, # need this for roles
263 name => $name,
18c2ec0e 264 ));
78cd1d3b 265}
266
267sub add_augment_method_modifier {
ac2dc464 268 my ($self, $name, $method) = @_;
d05cd563 269 (!$self->has_method($name))
11c86f15 270 || $self->throw_error("Cannot add an augment method if a local method is already present");
3f9e4b0a 271
272 $self->add_method($name => Moose::Meta::Method::Augmented->new(
273 method => $method,
274 class => $self,
275 name => $name,
276 ));
78cd1d3b 277}
278
1341f10c 279## Private Utility methods ...
280
05d9eaf6 281sub _find_next_method_by_name_which_is_not_overridden {
282 my ($self, $name) = @_;
68efb014 283 foreach my $method ($self->find_all_methods_by_name($name)) {
ac2dc464 284 return $method->{code}
05d9eaf6 285 if blessed($method->{code}) && !$method->{code}->isa('Moose::Meta::Method::Overriden');
286 }
287 return undef;
288}
289
1341f10c 290sub _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');
ac2dc464 295 # get the name, make sure we take
8ecb1fa0 296 # immutable classes into account
ac2dc464 297 my $super_meta_name = ($super->meta->is_immutable
8ecb1fa0 298 ? $super->meta->get_mutable_metaclass_name
299 : blessed($super->meta));
ac2dc464 300 # if it's meta is a vanilla Moose,
301 # then we can safely ignore it.
8ecb1fa0 302 next if $super_meta_name eq 'Moose::Meta::Class';
ac2dc464 303 # but if we have anything else,
1341f10c 304 # we need to check it out ...
305 unless (# see if of our metaclass is incompatible
8ecb1fa0 306 ($self->isa($super_meta_name) &&
1341f10c 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;
313 # NOTE:
ac2dc464 314 # We might want to consider actually
315 # transfering any attributes from the
316 # original meta into this one, but in
1341f10c 317 # general you should not have any there
ac2dc464 318 # at this point anyway, so it's very
1341f10c 319 # much an obscure edge case anyway
320 $self = $super_meta->reinitialize($self->name => (
ac2dc464 321 'attribute_metaclass' => $super_meta->attribute_metaclass,
5cf3dbcf 322 'method_metaclass' => $super_meta->method_metaclass,
323 'instance_metaclass' => $super_meta->instance_metaclass,
1341f10c 324 ));
325 }
326 }
ac2dc464 327 return $self;
1341f10c 328}
329
d7d8a8c7 330# NOTE:
d9bb6c63 331# this was crap anyway, see
332# Moose::Util::apply_all_roles
d7d8a8c7 333# instead
4498537c 334sub _apply_all_roles {
547dda77 335 Carp::croak 'DEPRECATED: use Moose::Util::apply_all_roles($meta, @roles) instead'
4498537c 336}
1341f10c 337
338sub _process_attribute {
a3738e5b 339 my ( $self, $name, @args ) = @_;
7e59b803 340
341 @args = %{$args[0]} if scalar @args == 1 && ref($args[0]) eq 'HASH';
d9bb6c63 342
1341f10c 343 if ($name =~ /^\+(.*)/) {
7e59b803 344 return $self->_process_inherited_attribute($1, @args);
1341f10c 345 }
346 else {
7e59b803 347 return $self->_process_new_attribute($name, @args);
348 }
349}
350
351sub _process_new_attribute {
352 my ( $self, $name, @args ) = @_;
7e59b803 353
d5c30e52 354 $self->attribute_metaclass->interpolate_class_and_new($name, @args);
1341f10c 355}
356
357sub _process_inherited_attribute {
358 my ($self, $attr_name, %options) = @_;
359 my $inherited_attr = $self->find_attribute_by_name($attr_name);
360 (defined $inherited_attr)
11c86f15 361 || $self->throw_error("Could not find an attribute by the name of '$attr_name' to inherit from", data => $attr_name);
1341f10c 362 if ($inherited_attr->isa('Moose::Meta::Attribute')) {
d7d8a8c7 363 return $inherited_attr->clone_and_inherit_options(%options);
1341f10c 364 }
365 else {
366 # NOTE:
367 # kind of a kludge to handle Class::MOP::Attributes
d7d8a8c7 368 return $inherited_attr->Moose::Meta::Attribute::clone_and_inherit_options(%options);
ac2dc464 369 }
1341f10c 370}
371
5cf3dbcf 372## -------------------------------------------------
373
374use Moose::Meta::Method::Constructor;
1f779926 375use Moose::Meta::Method::Destructor;
5cf3dbcf 376
ac2dc464 377# This could be done by using SUPER and altering ->options
378# I am keeping it this way to make it more explicit.
379sub create_immutable_transformer {
380 my $self = shift;
381 my $class = Class::MOP::Immutable->new($self, {
87567f12 382 read_only => [qw/
383 superclasses
384 roles
385 error_class
386 error_builder
387 /],
388 cannot_call => [qw/
389 add_method
390 alias_method
391 remove_method
392 add_attribute
393 remove_attribute
394 remove_package_symbol
395 add_role
396 /],
397 memoize => {
398 class_precedence_list => 'ARRAY',
399 compute_all_applicable_attributes => 'ARRAY',
400 get_meta_instance => 'SCALAR',
401 get_method_map => 'SCALAR',
402 # maybe ....
403 calculate_all_roles => 'ARRAY',
404 },
405 # NOTE:
406 # this is ugly, but so are typeglobs,
407 # so whattayahgonnadoboutit
408 # - SL
409 wrapped => {
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;
415 },
416 },
ac2dc464 417 });
418 return $class;
419}
420
421sub make_immutable {
422 my $self = shift;
423 $self->SUPER::make_immutable
424 (
425 constructor_class => 'Moose::Meta::Method::Constructor',
426 destructor_class => 'Moose::Meta::Method::Destructor',
427 inline_destructor => 1,
428 # NOTE:
429 # no need to do this,
430 # Moose always does it
431 inline_accessors => 0,
432 @_,
433 );
5cf3dbcf 434}
435
11c86f15 436#{ package Moose::Meta::Class::ErrorRoutines; %Carp::Internal?
437
438our $level;
439
440sub throw_error {
441 my ( $self, @args ) = @_;
442 local $level = 1;
443 $self->raise_error($self->create_error(@args));
444}
445
446sub raise_error {
447 my ( $self, @args ) = @_;
448 die @args;
449}
450
451sub create_error {
452 my ( $self, @args ) = @_;
453
454 if ( @args % 2 == 1 ) {
455 unshift @args, "message";
456 }
457
be05faea 458 my %args = ( meta => $self, error => $@, @args );
11c86f15 459
460 local $level = $level + 1;
461
462 if ( my $class = $args{class} || ( ref $self && $self->error_class ) ) {
463 return $self->create_error_object( %args, class => $class );
464 } else {
465 my $builder = $args{builder} || ( ref($self) ? $self->error_builder : "confess" );
466
467 my $builder_method = ( ( ref($builder) && ref($builder) eq 'CODE' )
468 ? $builder
469 : ( $self->can("create_error_$builder") || "create_error_confess" ));
470
471 return $self->$builder_method(%args);
472 }
473}
474
475sub create_error_object {
476 my ( $self, %args ) = @_;
477
478 my $class = delete $args{class};
479
480 $class->new(
11c86f15 481 %args,
482 depth => ( ($args{depth} || 1) + ( $level + 1 ) ),
483 );
484}
485
486sub create_error_croak {
487 my ( $self, @args ) = @_;
488 $self->_create_error_carpmess( @args );
489}
490
491sub create_error_confess {
492 my ( $self, @args ) = @_;
493 $self->_create_error_carpmess( @args, longmess => 1 );
494}
495
496sub _create_error_carpmess {
497 my ( $self, %args ) = @_;
498
499 my $carp_level = $level + 1 + ( $args{depth} || 1 );
500
501 local $Carp::CarpLevel = $carp_level; # $Carp::CarpLevel + $carp_level ?
502 local $Carp::MaxArgNums = 20; # default is 8, usually we use named args which gets messier though
503
504 my @args = exists $args{message} ? $args{message} : ();
505
506 if ( $args{longmess} ) {
507 return Carp::longmess(@args);
508 } else {
509 return Carp::shortmess(@args);
510 }
511}
512
c0e30cf5 5131;
514
515__END__
516
517=pod
518
519=head1 NAME
520
e522431d 521Moose::Meta::Class - The Moose metaclass
c0e30cf5 522
c0e30cf5 523=head1 DESCRIPTION
524
ac2dc464 525This is a subclass of L<Class::MOP::Class> with Moose specific
e522431d 526extensions.
527
ac2dc464 528For the most part, the only time you will ever encounter an
529instance of this class is if you are doing some serious deep
530introspection. To really understand this class, you need to refer
6ba6d68c 531to the L<Class::MOP::Class> documentation.
532
c0e30cf5 533=head1 METHODS
534
535=over 4
536
590868a3 537=item B<initialize>
538
61bdd94f 539=item B<create>
540
17594769 541Overrides original to accept a list of roles to apply to
61bdd94f 542the created class.
543
17594769 544 my $metaclass = Moose::Meta::Class->create( 'New::Class', roles => [...] );
545
546=item B<create_anon_class>
547
548Overrides original to support roles and caching.
549
550 my $metaclass = Moose::Meta::Class->create_anon_class(
551 superclasses => ['Foo'],
552 roles => [qw/Some Roles Go Here/],
553 cache => 1,
554 );
555
5cf3dbcf 556=item B<make_immutable>
557
ac2dc464 558Override original to add default options for inlining destructor
559and altering the Constructor metaclass.
560
561=item B<create_immutable_transformer>
562
563Override original to lock C<add_role> and memoize C<calculate_all_roles>
564
8c9d74e7 565=item B<new_object>
566
02a0fb52 567We override this method to support the C<trigger> attribute option.
568
a15dff8d 569=item B<construct_instance>
570
ac2dc464 571This provides some Moose specific extensions to this method, you
572almost never call this method directly unless you really know what
573you are doing.
6ba6d68c 574
575This method makes sure to handle the moose weak-ref, type-constraint
ac2dc464 576and type coercion features.
ef1d5f4b 577
093b12c2 578=item B<get_method_map>
e9ec68d6 579
ac2dc464 580This accommodates Moose::Meta::Role::Method instances, which are
581aliased, instead of added, but still need to be counted as valid
e9ec68d6 582methods.
583
78cd1d3b 584=item B<add_override_method_modifier ($name, $method)>
585
ac2dc464 586This will create an C<override> method modifier for you, and install
02a0fb52 587it in the package.
588
78cd1d3b 589=item B<add_augment_method_modifier ($name, $method)>
590
ac2dc464 591This will create an C<augment> method modifier for you, and install
02a0fb52 592it in the package.
593
2b14ac61 594=item B<calculate_all_roles>
595
ef333f17 596=item B<roles>
597
ac2dc464 598This will return an array of C<Moose::Meta::Role> instances which are
02a0fb52 599attached to this class.
600
ef333f17 601=item B<add_role ($role)>
602
ac2dc464 603This takes an instance of C<Moose::Meta::Role> in C<$role>, and adds it
02a0fb52 604to the list of associated roles.
605
ef333f17 606=item B<does_role ($role_name)>
607
ac2dc464 608This will test if this class C<does> a given C<$role_name>. It will
609not only check it's local roles, but ask them as well in order to
02a0fb52 610cascade down the role hierarchy.
611
d79e62fd 612=item B<excludes_role ($role_name)>
613
ac2dc464 614This will test if this class C<excludes> a given C<$role_name>. It will
615not only check it's local roles, but ask them as well in order to
d79e62fd 616cascade down the role hierarchy.
617
9e93dd19 618=item B<add_attribute ($attr_name, %params|$params)>
4e848edb 619
9e93dd19 620This method does the same thing as L<Class::MOP::Class::add_attribute>, but adds
621support for taking the C<$params> as a HASH ref.
ac1ef2f9 622
11c86f15 623=item B<throw_error $message, %extra>
624
625Throws the error created by C<create_error> using C<raise_error>
626
627=item B<create_error $message, %extra>
628
629Creates an error message or object.
630
631The default behavior is C<create_error_confess>.
632
633If C<error_class> is set uses C<create_error_object>. Otherwise uses
634C<error_builder> (a code reference or variant name), and calls the appropriate
635C<create_error_$builder> method.
636
637=item B<error_builder $builder_name>
638
639Get or set the error builder. Defaults to C<confess>.
640
641=item B<error_class $class_name>
642
643Get or set the error class. Has no default.
644
645=item B<create_error_confess %args>
646
647Creates an error using L<Carp/longmess>
648
649=item B<create_error_croak %args>
650
651Creates an error using L<Carp/shortmess>
652
653=item B<create_error_object %args>
654
655Calls C<new> on the C<class> parameter in C<%args>. Usable with C<error_class>
656to support custom error objects for your meta class.
657
658=item B<raise_error $error>
659
660Dies with an error object or string.
661
c0e30cf5 662=back
663
664=head1 BUGS
665
ac2dc464 666All complex software has bugs lurking in it, and this module is no
c0e30cf5 667exception. If you find a bug please either email me, or add the bug
668to cpan-RT.
669
c0e30cf5 670=head1 AUTHOR
671
672Stevan Little E<lt>stevan@iinteractive.comE<gt>
673
674=head1 COPYRIGHT AND LICENSE
675
778db3ac 676Copyright 2006-2008 by Infinity Interactive, Inc.
c0e30cf5 677
678L<http://www.iinteractive.com>
679
680This library is free software; you can redistribute it and/or modify
ac2dc464 681it under the same terms as Perl itself.
c0e30cf5 682
8a7a9c53 683=cut
1a563243 684