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