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