renames
[gitmo/Moose.git] / lib / Moose / Meta / Class.pm
1
2 package Moose::Meta::Class;
3
4 use strict;
5 use warnings;
6
7 use Class::MOP;
8
9 use Carp         'confess';
10 use Scalar::Util 'weaken', 'blessed', 'reftype';
11
12 our $VERSION = '0.05';
13
14 use base 'Class::MOP::Class';
15
16 __PACKAGE__->meta->add_attribute('roles' => (
17     reader  => 'roles',
18     default => sub { [] }
19 ));
20
21 sub initialize {
22     my $class = shift;
23     my $pkg   = shift;
24     $class->SUPER::initialize($pkg,
25         ':attribute_metaclass' => 'Moose::Meta::Attribute', 
26         ':instance_metaclass'  => 'Moose::Meta::Instance', 
27         @_);
28 }
29
30 sub 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
37 sub 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}) {
42         return 1 if $role->does_role($role_name);
43     }
44     return 0;
45 }
46
47 sub new_object {
48     my ($class, %params) = @_;
49     my $self = $class->SUPER::new_object(%params);
50     foreach my $attr ($class->compute_all_applicable_attributes()) {
51         next unless $params{$attr->init_arg} && $attr->can('has_trigger') && $attr->has_trigger;
52         $attr->trigger->($self, $params{$attr->init_arg}, $attr);
53     }
54     return $self;    
55 }
56
57 sub construct_instance {
58     my ($class, %params) = @_;
59     my $meta_instance = $class->get_meta_instance;
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. 
64     my $instance = $params{'__INSTANCE__'} || $meta_instance->create_instance();
65     foreach my $attr ($class->compute_all_applicable_attributes()) {
66         $attr->initialize_instance_slot($meta_instance, $instance, \%params)
67     }
68     return $instance;
69 }
70
71 sub 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
86 sub 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";    
93     $self->add_method($name => bless sub {
94         my @args = @_;
95         no strict   'refs';
96         no warnings 'redefine';
97         local *{$_super_package . '::super'} = sub { $super->(@args) };
98         return $method->(@args);
99     } => 'Moose::Meta::Method::Overriden');
100 }
101
102 sub add_augment_method_modifier {
103     my ($self, $name, $method) = @_;  
104     my $super = $self->find_next_method_by_name($name);
105     (defined $super)
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     }      
118     $self->add_method($name => sub {
119         my @args = @_;
120         no strict   'refs';
121         no warnings 'redefine';
122         local *{$_super_package . '::inner'} = sub { $method->(@args) };
123         return $super->(@args);
124     });    
125 }
126
127 sub _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
137 package Moose::Meta::Method::Overriden;
138
139 use strict;
140 use warnings;
141
142 our $VERSION = '0.01';
143
144 use base 'Class::MOP::Method';
145
146 1;
147
148 __END__
149
150 =pod
151
152 =head1 NAME
153
154 Moose::Meta::Class - The Moose metaclass
155
156 =head1 DESCRIPTION
157
158 This is a subclass of L<Class::MOP::Class> with Moose specific 
159 extensions.
160
161 For the most part, the only time you will ever encounter an 
162 instance of this class is if you are doing some serious deep 
163 introspection. To really understand this class, you need to refer 
164 to the L<Class::MOP::Class> documentation.
165
166 =head1 METHODS
167
168 =over 4
169
170 =item B<initialize>
171
172 =item B<new_object>
173
174 We override this method to support the C<trigger> attribute option.
175
176 =item B<construct_instance>
177
178 This provides some Moose specific extensions to this method, you 
179 almost never call this method directly unless you really know what 
180 you are doing. 
181
182 This method makes sure to handle the moose weak-ref, type-constraint
183 and type coercion features. 
184
185 =item B<has_method ($name)>
186
187 This accomidates Moose::Meta::Role::Method instances, which are 
188 aliased, instead of added, but still need to be counted as valid 
189 methods.
190
191 =item B<add_override_method_modifier ($name, $method)>
192
193 This will create an C<override> method modifier for you, and install 
194 it in the package.
195
196 =item B<add_augment_method_modifier ($name, $method)>
197
198 This will create an C<augment> method modifier for you, and install 
199 it in the package.
200
201 =item B<roles>
202
203 This will return an array of C<Moose::Meta::Role> instances which are 
204 attached to this class.
205
206 =item B<add_role ($role)>
207
208 This takes an instance of C<Moose::Meta::Role> in C<$role>, and adds it 
209 to the list of associated roles.
210
211 =item B<does_role ($role_name)>
212
213 This will test if this class C<does> a given C<$role_name>. It will 
214 not only check it's local roles, but ask them as well in order to 
215 cascade down the role hierarchy.
216
217 =item B<add_attribute $attr_name, %params>
218
219 This method does the same thing as L<Class::MOP::Class/add_attribute>, but adds
220 suport 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
236 =item filter_delegations
237
238 =back
239
240 =head1 BUGS
241
242 All complex software has bugs lurking in it, and this module is no 
243 exception. If you find a bug please either email me, or add the bug
244 to cpan-RT.
245
246 =head1 AUTHOR
247
248 Stevan Little E<lt>stevan@iinteractive.comE<gt>
249
250 =head1 COPYRIGHT AND LICENSE
251
252 Copyright 2006 by Infinity Interactive, Inc.
253
254 L<http://www.iinteractive.com>
255
256 This library is free software; you can redistribute it and/or modify
257 it under the same terms as Perl itself. 
258
259 =cut
260