Add VERSION section to pods
[gitmo/Mouse.git] / lib / Mouse / Meta / Method / Constructor.pm
1 package Mouse::Meta::Method::Constructor;
2 use Mouse::Util; # enables strict and warnings
3
4 sub _generate_constructor {
5     my ($class, $metaclass, $args) = @_;
6
7     my $associated_metaclass_name = $metaclass->name;
8
9     my @attrs         = $metaclass->get_all_attributes;
10
11     my $buildall      = $class->_generate_BUILDALL($metaclass);
12     my $buildargs     = $class->_generate_BUILDARGS($metaclass);
13     my $processattrs  = $class->_generate_processattrs($metaclass, \@attrs);
14
15     my @checks = map { $_ && $_->_compiled_type_constraint }
16                  map { $_->type_constraint } @attrs;
17
18     my $source = sprintf("#line %d %s\n", __LINE__, __FILE__).<<"...";
19         sub \{
20             my \$class = shift;
21             return \$class->Mouse::Object::new(\@_)
22                 if \$class ne q{$associated_metaclass_name};
23             # BUILDARGS
24             $buildargs;
25             my \$instance = bless {}, \$class;
26             # process attributes
27             $processattrs;
28             # BUILDALL
29             $buildall;
30             return \$instance;
31         }
32 ...
33     #warn $source;
34     my $code;
35     my $e = do{
36         local $@;
37         $code = eval $source;
38         $@;
39     };
40     die $e if $e;
41     return $code;
42 }
43
44 sub _generate_processattrs {
45     my ($class, $metaclass, $attrs) = @_;
46     my @res;
47
48     my $has_triggers;
49
50     for my $index (0 .. @$attrs - 1) {
51         my $code = '';
52
53         my $attr = $attrs->[$index];
54         my $key  = $attr->name;
55
56         my $init_arg        = $attr->init_arg;
57         my $type_constraint = $attr->type_constraint;
58         my $need_coercion;
59
60         my $instance_slot  = "\$instance->{q{$key}}";
61         my $attr_var       = "\$attrs[$index]";
62         my $constraint_var;
63
64         if(defined $type_constraint){
65              $constraint_var = "$attr_var\->{type_constraint}";
66              $need_coercion  = ($attr->should_coerce && $type_constraint->has_coercion);
67         }
68
69         $code .= "# initialize $key\n";
70
71         my $post_process = '';
72         if(defined $type_constraint){
73             $post_process .= "\$checks[$index]->($instance_slot)";
74             $post_process .= "  or $attr_var->verify_type_constraint_error(q{$key}, $instance_slot, $constraint_var);\n";
75         }
76         if($attr->is_weak_ref){
77             $post_process .= "Scalar::Util::weaken($instance_slot) if ref $instance_slot;\n";
78         }
79
80         if (defined $init_arg) {
81             my $value = "\$args->{q{$init_arg}}";
82
83             $code .= "if (exists $value) {\n";
84
85             if($need_coercion){
86                 $value = "$constraint_var->coerce($value)";
87             }
88
89             $code .= "$instance_slot = $value;\n";
90             $code .= $post_process;
91
92             if ($attr->has_trigger) {
93                 $has_triggers++;
94                 $code .= "push \@triggers, [$attr_var\->{trigger}, $instance_slot];\n";
95             }
96
97             $code .= "\n} else {\n";
98         }
99
100         if ($attr->has_default || $attr->has_builder) {
101             unless ($attr->is_lazy) {
102                 my $default = $attr->default;
103                 my $builder = $attr->builder;
104
105                 my $value;
106                 if (defined($builder)) {
107                     $value = "\$instance->$builder()";
108                 }
109                 elsif (ref($default) eq 'CODE') {
110                     $value = "$attr_var\->{default}->(\$instance)";
111                 }
112                 elsif (defined($default)) {
113                     $value = "$attr_var\->{default}";
114                 }
115                 else {
116                     $value = 'undef';
117                 }
118
119                 if($need_coercion){
120                     $value = "$constraint_var->coerce($value)";
121                 }
122
123                 $code .= "$instance_slot = $value;\n";
124             }
125         }
126         elsif ($attr->is_required) {
127             $code .= "Carp::confess('Attribute ($key) is required');";
128         }
129
130         $code .= "}\n" if defined $init_arg;
131
132         push @res, $code;
133     }
134
135     if($metaclass->is_anon_class){
136         push @res, q{$instance->{__METACLASS__} = $metaclass;};
137     }
138
139     if($has_triggers){
140         unshift @res, q{my @triggers;};
141         push    @res,  q{$_->[0]->($instance, $_->[1]) for @triggers;};
142     }
143
144     return join "\n", @res;
145 }
146
147 sub _generate_BUILDARGS {
148     my(undef, $metaclass) = @_;
149
150     my $class = $metaclass->name;
151     if ( $class->can('BUILDARGS') && $class->can('BUILDARGS') != \&Mouse::Object::BUILDARGS ) {
152         return 'my $args = $class->BUILDARGS(@_)';
153     }
154
155     return <<'...';
156         my $args;
157         if ( scalar @_ == 1 ) {
158             ( ref( $_[0] ) eq 'HASH' )
159                 || Carp::confess "Single parameters to new() must be a HASH ref";
160             $args = +{ %{ $_[0] } };
161         }
162         else {
163             $args = +{@_};
164         }
165 ...
166 }
167
168 sub _generate_BUILDALL {
169     my (undef, $metaclass) = @_;
170
171     return '' unless $metaclass->name->can('BUILD');
172
173     my @code;
174     for my $class ($metaclass->linearized_isa) {
175         no strict 'refs';
176         no warnings 'once';
177
178         if (*{ $class . '::BUILD' }{CODE}) {
179             unshift  @code, qq{${class}::BUILD(\$instance, \$args);};
180         }
181     }
182     return join "\n", @code;
183 }
184
185 1;
186 __END__
187
188 =head1 NAME
189
190 Mouse::Meta::Method::Constructor - A Mouse method generator for constructors
191
192 =head1 VERSION
193
194 This document describes Mouse version 0.37_06
195
196 =head1 SEE ALSO
197
198 L<Moose::Meta::Method::Constructor>
199
200 =cut