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