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