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
78cd1d3b 100sub add_override_method_modifier {
101 my ($self, $name, $method, $_super_package) = @_;
d05cd563 102 (!$self->has_method($name))
103 || confess "Cannot add an override method if a local method is already present";
78cd1d3b 104 # need this for roles ...
105 $_super_package ||= $self->name;
106 my $super = $self->find_next_method_by_name($name);
107 (defined $super)
108 || confess "You cannot override '$name' because it has no super method";
05d9eaf6 109 $self->add_method($name => bless sub {
78cd1d3b 110 my @args = @_;
111 no strict 'refs';
112 no warnings 'redefine';
113 local *{$_super_package . '::super'} = sub { $super->(@args) };
114 return $method->(@args);
05d9eaf6 115 } => 'Moose::Meta::Method::Overriden');
78cd1d3b 116}
117
118sub add_augment_method_modifier {
05d9eaf6 119 my ($self, $name, $method) = @_;
d05cd563 120 (!$self->has_method($name))
121 || confess "Cannot add an augment method if a local method is already present";
78cd1d3b 122 my $super = $self->find_next_method_by_name($name);
123 (defined $super)
05d9eaf6 124 || confess "You cannot augment '$name' because it has no super method";
125 my $_super_package = $super->package_name;
126 # BUT!,... if this is an overriden method ....
127 if ($super->isa('Moose::Meta::Method::Overriden')) {
128 # we need to be sure that we actually
129 # find the next method, which is not
130 # an 'override' method, the reason is
131 # that an 'override' method will not
132 # be the one calling inner()
133 my $real_super = $self->_find_next_method_by_name_which_is_not_overridden($name);
134 $_super_package = $real_super->package_name;
135 }
78cd1d3b 136 $self->add_method($name => sub {
137 my @args = @_;
138 no strict 'refs';
139 no warnings 'redefine';
05d9eaf6 140 local *{$_super_package . '::inner'} = sub { $method->(@args) };
78cd1d3b 141 return $super->(@args);
142 });
143}
144
05d9eaf6 145sub _find_next_method_by_name_which_is_not_overridden {
146 my ($self, $name) = @_;
147 my @methods = $self->find_all_methods_by_name($name);
148 foreach my $method (@methods) {
149 return $method->{code}
150 if blessed($method->{code}) && !$method->{code}->isa('Moose::Meta::Method::Overriden');
151 }
152 return undef;
153}
154
155package Moose::Meta::Method::Overriden;
156
157use strict;
158use warnings;
159
160our $VERSION = '0.01';
161
162use base 'Class::MOP::Method';
163
c0e30cf5 1641;
165
166__END__
167
168=pod
169
170=head1 NAME
171
e522431d 172Moose::Meta::Class - The Moose metaclass
c0e30cf5 173
c0e30cf5 174=head1 DESCRIPTION
175
e522431d 176This is a subclass of L<Class::MOP::Class> with Moose specific
177extensions.
178
6ba6d68c 179For the most part, the only time you will ever encounter an
180instance of this class is if you are doing some serious deep
181introspection. To really understand this class, you need to refer
182to the L<Class::MOP::Class> documentation.
183
c0e30cf5 184=head1 METHODS
185
186=over 4
187
590868a3 188=item B<initialize>
189
8c9d74e7 190=item B<new_object>
191
02a0fb52 192We override this method to support the C<trigger> attribute option.
193
a15dff8d 194=item B<construct_instance>
195
6ba6d68c 196This provides some Moose specific extensions to this method, you
197almost never call this method directly unless you really know what
198you are doing.
199
200This method makes sure to handle the moose weak-ref, type-constraint
201and type coercion features.
ef1d5f4b 202
e9ec68d6 203=item B<has_method ($name)>
204
205This accomidates Moose::Meta::Role::Method instances, which are
206aliased, instead of added, but still need to be counted as valid
207methods.
208
78cd1d3b 209=item B<add_override_method_modifier ($name, $method)>
210
02a0fb52 211This will create an C<override> method modifier for you, and install
212it in the package.
213
78cd1d3b 214=item B<add_augment_method_modifier ($name, $method)>
215
02a0fb52 216This will create an C<augment> method modifier for you, and install
217it in the package.
218
ef333f17 219=item B<roles>
220
02a0fb52 221This will return an array of C<Moose::Meta::Role> instances which are
222attached to this class.
223
ef333f17 224=item B<add_role ($role)>
225
02a0fb52 226This takes an instance of C<Moose::Meta::Role> in C<$role>, and adds it
227to the list of associated roles.
228
ef333f17 229=item B<does_role ($role_name)>
230
02a0fb52 231This will test if this class C<does> a given C<$role_name>. It will
232not only check it's local roles, but ask them as well in order to
233cascade down the role hierarchy.
234
d79e62fd 235=item B<excludes_role ($role_name)>
236
237This will test if this class C<excludes> a given C<$role_name>. It will
238not only check it's local roles, but ask them as well in order to
239cascade down the role hierarchy.
240
4e848edb 241=item B<add_attribute $attr_name, %params>
242
243This method does the same thing as L<Class::MOP::Class/add_attribute>, but adds
244suport for delegation.
245
246=back
247
248=head1 INTERNAL METHODS
249
250=over 4
251
252=item compute_delegation
253
254=item generate_delegation_list
255
256=item generate_delgate_method
257
258=item get_delegatable_methods
259
ac1ef2f9 260=item filter_delegations
261
c0e30cf5 262=back
263
264=head1 BUGS
265
266All complex software has bugs lurking in it, and this module is no
267exception. If you find a bug please either email me, or add the bug
268to cpan-RT.
269
c0e30cf5 270=head1 AUTHOR
271
272Stevan Little E<lt>stevan@iinteractive.comE<gt>
273
274=head1 COPYRIGHT AND LICENSE
275
276Copyright 2006 by Infinity Interactive, Inc.
277
278L<http://www.iinteractive.com>
279
280This library is free software; you can redistribute it and/or modify
281it under the same terms as Perl itself.
282
8a7a9c53 283=cut
1a563243 284