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