BUGS
[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.04';
13
14 use base 'Class::MOP::Class';
15
16 __PACKAGE__->meta->add_attribute('roles' => (
17     reader  => 'roles',
18     default => sub { [] }
19 ));
20
21 sub add_role {
22     my ($self, $role) = @_;
23     (blessed($role) && $role->isa('Moose::Meta::Role'))
24         || confess "Roles must be instances of Moose::Meta::Role";
25     push @{$self->roles} => $role;
26 }
27
28 sub does_role {
29     my ($self, $role_name) = @_;
30     (defined $role_name)
31         || confess "You must supply a role name to look for";
32     foreach my $role (@{$self->roles}) {
33         return 1 if $role->does_role($role_name);
34     }
35     return 0;
36 }
37
38 sub construct_instance {
39     my ($class, %params) = @_;
40     my $instance = $params{'__INSTANCE__'} || {};
41     foreach my $attr ($class->compute_all_applicable_attributes()) {
42         my $init_arg = $attr->init_arg();
43         # try to fetch the init arg from the %params ...
44         my $val;        
45         if (exists $params{$init_arg}) {
46             $val = $params{$init_arg};
47         }
48         else {
49             # skip it if it's lazy
50             next if $attr->is_lazy;
51             # and die if it is required            
52             confess "Attribute (" . $attr->name . ") is required" 
53                 if $attr->is_required
54         }
55         # if nothing was in the %params, we can use the 
56         # attribute's default value (if it has one)
57         if (!defined $val && $attr->has_default) {
58             $val = $attr->default($instance); 
59         }
60                 if (defined $val) {
61                     if ($attr->has_type_constraint) {
62                     if ($attr->should_coerce && $attr->type_constraint->has_coercion) {
63                         $val = $attr->type_constraint->coercion->coerce($val);
64                     }   
65                 (defined($attr->type_constraint->check($val))) 
66                     || confess "Attribute (" . $attr->name . ") does not pass the type contraint with '$val'";                  
67             }
68                 }
69         $instance->{$attr->name} = $val;
70         if (defined $val && $attr->is_weak_ref) {
71             weaken($instance->{$attr->name});
72         }
73     }
74     return $instance;
75 }
76
77 sub has_method {
78     my ($self, $method_name) = @_;
79     (defined $method_name && $method_name)
80         || confess "You must define a method name";    
81
82     my $sub_name = ($self->name . '::' . $method_name);   
83     
84     no strict 'refs';
85     return 0 if !defined(&{$sub_name});        
86         my $method = \&{$sub_name};
87         
88         return 1 if blessed($method) && $method->isa('Moose::Meta::Role::Method');
89     return $self->SUPER::has_method($method_name);    
90 }
91
92
93 sub add_override_method_modifier {
94     my ($self, $name, $method, $_super_package) = @_;
95     # need this for roles ...
96     $_super_package ||= $self->name;
97     my $super = $self->find_next_method_by_name($name);
98     (defined $super)
99         || confess "You cannot override '$name' because it has no super method";    
100     $self->add_method($name => bless sub {
101         my @args = @_;
102         no strict   'refs';
103         no warnings 'redefine';
104         local *{$_super_package . '::super'} = sub { $super->(@args) };
105         return $method->(@args);
106     } => 'Moose::Meta::Method::Overriden');
107 }
108
109 sub add_augment_method_modifier {
110     my ($self, $name, $method) = @_;  
111     my $super = $self->find_next_method_by_name($name);
112     (defined $super)
113         || confess "You cannot augment '$name' because it has no super method";    
114     my $_super_package = $super->package_name;   
115     # BUT!,... if this is an overriden method ....     
116     if ($super->isa('Moose::Meta::Method::Overriden')) {
117         # we need to be sure that we actually 
118         # find the next method, which is not 
119         # an 'override' method, the reason is
120         # that an 'override' method will not 
121         # be the one calling inner()
122         my $real_super = $self->_find_next_method_by_name_which_is_not_overridden($name);        
123         $_super_package = $real_super->package_name;
124     }      
125     $self->add_method($name => sub {
126         my @args = @_;
127         no strict   'refs';
128         no warnings 'redefine';
129         local *{$_super_package . '::inner'} = sub { $method->(@args) };
130         return $super->(@args);
131     });    
132 }
133
134 sub _find_next_method_by_name_which_is_not_overridden {
135     my ($self, $name) = @_;
136     my @methods = $self->find_all_methods_by_name($name);
137     foreach my $method (@methods) {
138         return $method->{code} 
139             if blessed($method->{code}) && !$method->{code}->isa('Moose::Meta::Method::Overriden');
140     }
141     return undef;
142 }
143
144 package Moose::Meta::Method::Overriden;
145
146 use strict;
147 use warnings;
148
149 our $VERSION = '0.01';
150
151 use base 'Class::MOP::Method';
152
153 1;
154
155 __END__
156
157 =pod
158
159 =head1 NAME
160
161 Moose::Meta::Class - The Moose metaclass
162
163 =head1 DESCRIPTION
164
165 This is a subclass of L<Class::MOP::Class> with Moose specific 
166 extensions.
167
168 For the most part, the only time you will ever encounter an 
169 instance of this class is if you are doing some serious deep 
170 introspection. To really understand this class, you need to refer 
171 to the L<Class::MOP::Class> documentation.
172
173 =head1 METHODS
174
175 =over 4
176
177 =item B<construct_instance>
178
179 This provides some Moose specific extensions to this method, you 
180 almost never call this method directly unless you really know what 
181 you are doing. 
182
183 This method makes sure to handle the moose weak-ref, type-constraint
184 and type coercion features. 
185
186 =item B<has_method ($name)>
187
188 This accomidates Moose::Meta::Role::Method instances, which are 
189 aliased, instead of added, but still need to be counted as valid 
190 methods.
191
192 =item B<add_override_method_modifier ($name, $method)>
193
194 =item B<add_augment_method_modifier ($name, $method)>
195
196 =item B<roles>
197
198 =item B<add_role ($role)>
199
200 =item B<does_role ($role_name)>
201
202 =back
203
204 =head1 BUGS
205
206 All complex software has bugs lurking in it, and this module is no 
207 exception. If you find a bug please either email me, or add the bug
208 to cpan-RT.
209
210 =head1 AUTHOR
211
212 Stevan Little E<lt>stevan@iinteractive.comE<gt>
213
214 =head1 COPYRIGHT AND LICENSE
215
216 Copyright 2006 by Infinity Interactive, Inc.
217
218 L<http://www.iinteractive.com>
219
220 This library is free software; you can redistribute it and/or modify
221 it under the same terms as Perl itself. 
222
223 =cut