docs
[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';
54b1cdf0 10use Scalar::Util 'weaken', 'blessed', 'reftype';
a15dff8d 11
db1ab48d 12our $VERSION = '0.06';
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',
ddd0ec20 26 ':instance_metaclass' => 'Moose::Meta::Instance',
590868a3 27 @_);
28}
29
ef333f17 30sub add_role {
31 my ($self, $role) = @_;
32 (blessed($role) && $role->isa('Moose::Meta::Role'))
33 || confess "Roles must be instances of Moose::Meta::Role";
34 push @{$self->roles} => $role;
35}
36
37sub does_role {
38 my ($self, $role_name) = @_;
39 (defined $role_name)
40 || confess "You must supply a role name to look for";
9c429218 41 foreach my $class ($self->class_precedence_list) {
74f6d830 42 next unless $class->can('meta');
9c429218 43 foreach my $role (@{$class->meta->roles}) {
44 return 1 if $role->does_role($role_name);
45 }
ef333f17 46 }
47 return 0;
48}
49
d79e62fd 50sub excludes_role {
51 my ($self, $role_name) = @_;
52 (defined $role_name)
53 || confess "You must supply a role name to look for";
74f6d830 54 foreach my $class ($self->class_precedence_list) {
55 next unless $class->can('meta');
9c429218 56 foreach my $role (@{$class->meta->roles}) {
57 return 1 if $role->excludes_role($role_name);
58 }
d79e62fd 59 }
60 return 0;
61}
62
8c9d74e7 63sub new_object {
64 my ($class, %params) = @_;
65 my $self = $class->SUPER::new_object(%params);
66 foreach my $attr ($class->compute_all_applicable_attributes()) {
5faf11bb 67 next unless $params{$attr->init_arg} && $attr->can('has_trigger') && $attr->has_trigger;
68 $attr->trigger->($self, $params{$attr->init_arg}, $attr);
8c9d74e7 69 }
70 return $self;
71}
72
a15dff8d 73sub construct_instance {
74 my ($class, %params) = @_;
ddd0ec20 75 my $meta_instance = $class->get_meta_instance;
575db57d 76 # FIXME:
77 # the code below is almost certainly incorrect
78 # but this is foreign inheritence, so we might
79 # have to kludge it in the end.
ddd0ec20 80 my $instance = $params{'__INSTANCE__'} || $meta_instance->create_instance();
74f6d830 81 foreach my $attr ($class->compute_all_applicable_attributes()) {
ddd0ec20 82 $attr->initialize_instance_slot($meta_instance, $instance, \%params)
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
a2eec5e7 102sub add_attribute {
103 my $self = shift;
104 my $name = shift;
105 if (scalar @_ == 1 && ref($_[0]) eq 'HASH') {
106 # NOTE:
107 # if it is a HASH ref, we de-ref it.
108 # this will usually mean that it is
109 # coming from a role
110 $self->SUPER::add_attribute($name => %{$_[0]});
111 }
112 else {
113 # otherwise we just pass the args
114 $self->SUPER::add_attribute($name => @_);
115 }
116}
117
78cd1d3b 118sub add_override_method_modifier {
119 my ($self, $name, $method, $_super_package) = @_;
d05cd563 120 (!$self->has_method($name))
121 || confess "Cannot add an override method if a local method is already present";
78cd1d3b 122 # need this for roles ...
123 $_super_package ||= $self->name;
124 my $super = $self->find_next_method_by_name($name);
125 (defined $super)
126 || confess "You cannot override '$name' because it has no super method";
05d9eaf6 127 $self->add_method($name => bless sub {
78cd1d3b 128 my @args = @_;
129 no strict 'refs';
130 no warnings 'redefine';
131 local *{$_super_package . '::super'} = sub { $super->(@args) };
132 return $method->(@args);
05d9eaf6 133 } => 'Moose::Meta::Method::Overriden');
78cd1d3b 134}
135
136sub add_augment_method_modifier {
05d9eaf6 137 my ($self, $name, $method) = @_;
d05cd563 138 (!$self->has_method($name))
139 || confess "Cannot add an augment method if a local method is already present";
78cd1d3b 140 my $super = $self->find_next_method_by_name($name);
141 (defined $super)
05d9eaf6 142 || confess "You cannot augment '$name' because it has no super method";
143 my $_super_package = $super->package_name;
144 # BUT!,... if this is an overriden method ....
145 if ($super->isa('Moose::Meta::Method::Overriden')) {
146 # we need to be sure that we actually
147 # find the next method, which is not
148 # an 'override' method, the reason is
149 # that an 'override' method will not
150 # be the one calling inner()
151 my $real_super = $self->_find_next_method_by_name_which_is_not_overridden($name);
152 $_super_package = $real_super->package_name;
153 }
78cd1d3b 154 $self->add_method($name => sub {
155 my @args = @_;
156 no strict 'refs';
157 no warnings 'redefine';
05d9eaf6 158 local *{$_super_package . '::inner'} = sub { $method->(@args) };
78cd1d3b 159 return $super->(@args);
160 });
161}
162
05d9eaf6 163sub _find_next_method_by_name_which_is_not_overridden {
164 my ($self, $name) = @_;
165 my @methods = $self->find_all_methods_by_name($name);
166 foreach my $method (@methods) {
167 return $method->{code}
168 if blessed($method->{code}) && !$method->{code}->isa('Moose::Meta::Method::Overriden');
169 }
170 return undef;
171}
172
173package Moose::Meta::Method::Overriden;
174
175use strict;
176use warnings;
177
178our $VERSION = '0.01';
179
180use base 'Class::MOP::Method';
181
c0e30cf5 1821;
183
184__END__
185
186=pod
187
188=head1 NAME
189
e522431d 190Moose::Meta::Class - The Moose metaclass
c0e30cf5 191
c0e30cf5 192=head1 DESCRIPTION
193
e522431d 194This is a subclass of L<Class::MOP::Class> with Moose specific
195extensions.
196
6ba6d68c 197For the most part, the only time you will ever encounter an
198instance of this class is if you are doing some serious deep
199introspection. To really understand this class, you need to refer
200to the L<Class::MOP::Class> documentation.
201
c0e30cf5 202=head1 METHODS
203
204=over 4
205
590868a3 206=item B<initialize>
207
8c9d74e7 208=item B<new_object>
209
02a0fb52 210We override this method to support the C<trigger> attribute option.
211
a15dff8d 212=item B<construct_instance>
213
6ba6d68c 214This provides some Moose specific extensions to this method, you
215almost never call this method directly unless you really know what
216you are doing.
217
218This method makes sure to handle the moose weak-ref, type-constraint
219and type coercion features.
ef1d5f4b 220
e9ec68d6 221=item B<has_method ($name)>
222
223This accomidates Moose::Meta::Role::Method instances, which are
224aliased, instead of added, but still need to be counted as valid
225methods.
226
78cd1d3b 227=item B<add_override_method_modifier ($name, $method)>
228
02a0fb52 229This will create an C<override> method modifier for you, and install
230it in the package.
231
78cd1d3b 232=item B<add_augment_method_modifier ($name, $method)>
233
02a0fb52 234This will create an C<augment> method modifier for you, and install
235it in the package.
236
ef333f17 237=item B<roles>
238
02a0fb52 239This will return an array of C<Moose::Meta::Role> instances which are
240attached to this class.
241
ef333f17 242=item B<add_role ($role)>
243
02a0fb52 244This takes an instance of C<Moose::Meta::Role> in C<$role>, and adds it
245to the list of associated roles.
246
ef333f17 247=item B<does_role ($role_name)>
248
02a0fb52 249This will test if this class C<does> a given C<$role_name>. It will
250not only check it's local roles, but ask them as well in order to
251cascade down the role hierarchy.
252
d79e62fd 253=item B<excludes_role ($role_name)>
254
255This will test if this class C<excludes> a given C<$role_name>. It will
256not only check it's local roles, but ask them as well in order to
257cascade down the role hierarchy.
258
4e848edb 259=item B<add_attribute $attr_name, %params>
260
261This method does the same thing as L<Class::MOP::Class/add_attribute>, but adds
262suport for delegation.
263
264=back
265
266=head1 INTERNAL METHODS
267
268=over 4
269
270=item compute_delegation
271
272=item generate_delegation_list
273
274=item generate_delgate_method
275
276=item get_delegatable_methods
277
ac1ef2f9 278=item filter_delegations
279
c0e30cf5 280=back
281
282=head1 BUGS
283
284All complex software has bugs lurking in it, and this module is no
285exception. If you find a bug please either email me, or add the bug
286to cpan-RT.
287
c0e30cf5 288=head1 AUTHOR
289
290Stevan Little E<lt>stevan@iinteractive.comE<gt>
291
292=head1 COPYRIGHT AND LICENSE
293
294Copyright 2006 by Infinity Interactive, Inc.
295
296L<http://www.iinteractive.com>
297
298This library is free software; you can redistribute it and/or modify
299it under the same terms as Perl itself.
300
8a7a9c53 301=cut
1a563243 302