triggers
[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';
a7d0cd00 10use Scalar::Util 'weaken', 'blessed';
a15dff8d 11
78cd1d3b 12our $VERSION = '0.04';
bc1e29b5 13
c0e30cf5 14use base 'Class::MOP::Class';
15
598340d5 16__PACKAGE__->meta->add_attribute('roles' => (
ef333f17 17 reader => 'roles',
18 default => sub { [] }
19));
20
21sub add_role {
22 my ($self, $role) = @_;
23 (blessed($role) && $role->isa('Moose::Meta::Role'))
24 || confess "Roles must be instances of Moose::Meta::Role";
25 push @{$self->roles} => $role;
26}
27
28sub does_role {
29 my ($self, $role_name) = @_;
30 (defined $role_name)
31 || confess "You must supply a role name to look for";
32 foreach my $role (@{$self->roles}) {
bdabd620 33 return 1 if $role->does_role($role_name);
ef333f17 34 }
35 return 0;
36}
37
8c9d74e7 38sub new_object {
39 my ($class, %params) = @_;
40 my $self = $class->SUPER::new_object(%params);
41 foreach my $attr ($class->compute_all_applicable_attributes()) {
42 next unless $params{$attr->name} && $attr->has_trigger;
43 $attr->trigger->($self, $params{$attr->name});
44 }
45 return $self;
46}
47
a15dff8d 48sub construct_instance {
49 my ($class, %params) = @_;
e522431d 50 my $instance = $params{'__INSTANCE__'} || {};
a15dff8d 51 foreach my $attr ($class->compute_all_applicable_attributes()) {
52 my $init_arg = $attr->init_arg();
53 # try to fetch the init arg from the %params ...
54 my $val;
ca01a97b 55 if (exists $params{$init_arg}) {
56 $val = $params{$init_arg};
57 }
58 else {
59 # skip it if it's lazy
60 next if $attr->is_lazy;
61 # and die if it is required
62 confess "Attribute (" . $attr->name . ") is required"
63 if $attr->is_required
64 }
a15dff8d 65 # if nothing was in the %params, we can use the
66 # attribute's default value (if it has one)
8339fae2 67 if (!defined $val && $attr->has_default) {
68 $val = $attr->default($instance);
69 }
00867c44 70 if (defined $val) {
00867c44 71 if ($attr->has_type_constraint) {
34a66aa3 72 if ($attr->should_coerce && $attr->type_constraint->has_coercion) {
a27aa600 73 $val = $attr->type_constraint->coercion->coerce($val);
7415b2cb 74 }
a27aa600 75 (defined($attr->type_constraint->check($val)))
66811d63 76 || confess "Attribute (" . $attr->name . ") does not pass the type contraint with '$val'";
00867c44 77 }
a15dff8d 78 }
79 $instance->{$attr->name} = $val;
6ba6d68c 80 if (defined $val && $attr->is_weak_ref) {
81 weaken($instance->{$attr->name});
82 }
a15dff8d 83 }
84 return $instance;
85}
86
a7d0cd00 87sub has_method {
88 my ($self, $method_name) = @_;
89 (defined $method_name && $method_name)
90 || confess "You must define a method name";
91
92 my $sub_name = ($self->name . '::' . $method_name);
93
94 no strict 'refs';
95 return 0 if !defined(&{$sub_name});
96 my $method = \&{$sub_name};
97
98 return 1 if blessed($method) && $method->isa('Moose::Meta::Role::Method');
99 return $self->SUPER::has_method($method_name);
100}
101
102
78cd1d3b 103sub add_override_method_modifier {
104 my ($self, $name, $method, $_super_package) = @_;
105 # need this for roles ...
106 $_super_package ||= $self->name;
107 my $super = $self->find_next_method_by_name($name);
108 (defined $super)
109 || confess "You cannot override '$name' because it has no super method";
05d9eaf6 110 $self->add_method($name => bless sub {
78cd1d3b 111 my @args = @_;
112 no strict 'refs';
113 no warnings 'redefine';
114 local *{$_super_package . '::super'} = sub { $super->(@args) };
115 return $method->(@args);
05d9eaf6 116 } => 'Moose::Meta::Method::Overriden');
78cd1d3b 117}
118
119sub add_augment_method_modifier {
05d9eaf6 120 my ($self, $name, $method) = @_;
78cd1d3b 121 my $super = $self->find_next_method_by_name($name);
122 (defined $super)
05d9eaf6 123 || confess "You cannot augment '$name' because it has no super method";
124 my $_super_package = $super->package_name;
125 # BUT!,... if this is an overriden method ....
126 if ($super->isa('Moose::Meta::Method::Overriden')) {
127 # we need to be sure that we actually
128 # find the next method, which is not
129 # an 'override' method, the reason is
130 # that an 'override' method will not
131 # be the one calling inner()
132 my $real_super = $self->_find_next_method_by_name_which_is_not_overridden($name);
133 $_super_package = $real_super->package_name;
134 }
78cd1d3b 135 $self->add_method($name => sub {
136 my @args = @_;
137 no strict 'refs';
138 no warnings 'redefine';
05d9eaf6 139 local *{$_super_package . '::inner'} = sub { $method->(@args) };
78cd1d3b 140 return $super->(@args);
141 });
142}
143
05d9eaf6 144sub _find_next_method_by_name_which_is_not_overridden {
145 my ($self, $name) = @_;
146 my @methods = $self->find_all_methods_by_name($name);
147 foreach my $method (@methods) {
148 return $method->{code}
149 if blessed($method->{code}) && !$method->{code}->isa('Moose::Meta::Method::Overriden');
150 }
151 return undef;
152}
153
154package Moose::Meta::Method::Overriden;
155
156use strict;
157use warnings;
158
159our $VERSION = '0.01';
160
161use base 'Class::MOP::Method';
162
c0e30cf5 1631;
164
165__END__
166
167=pod
168
169=head1 NAME
170
e522431d 171Moose::Meta::Class - The Moose metaclass
c0e30cf5 172
c0e30cf5 173=head1 DESCRIPTION
174
e522431d 175This is a subclass of L<Class::MOP::Class> with Moose specific
176extensions.
177
6ba6d68c 178For the most part, the only time you will ever encounter an
179instance of this class is if you are doing some serious deep
180introspection. To really understand this class, you need to refer
181to the L<Class::MOP::Class> documentation.
182
c0e30cf5 183=head1 METHODS
184
185=over 4
186
8c9d74e7 187=item B<new_object>
188
a15dff8d 189=item B<construct_instance>
190
6ba6d68c 191This provides some Moose specific extensions to this method, you
192almost never call this method directly unless you really know what
193you are doing.
194
195This method makes sure to handle the moose weak-ref, type-constraint
196and type coercion features.
ef1d5f4b 197
e9ec68d6 198=item B<has_method ($name)>
199
200This accomidates Moose::Meta::Role::Method instances, which are
201aliased, instead of added, but still need to be counted as valid
202methods.
203
78cd1d3b 204=item B<add_override_method_modifier ($name, $method)>
205
206=item B<add_augment_method_modifier ($name, $method)>
207
ef333f17 208=item B<roles>
209
210=item B<add_role ($role)>
211
212=item B<does_role ($role_name)>
213
c0e30cf5 214=back
215
216=head1 BUGS
217
218All complex software has bugs lurking in it, and this module is no
219exception. If you find a bug please either email me, or add the bug
220to cpan-RT.
221
c0e30cf5 222=head1 AUTHOR
223
224Stevan Little E<lt>stevan@iinteractive.comE<gt>
225
226=head1 COPYRIGHT AND LICENSE
227
228Copyright 2006 by Infinity Interactive, Inc.
229
230L<http://www.iinteractive.com>
231
232This library is free software; you can redistribute it and/or modify
233it under the same terms as Perl itself.
234
235=cut