Tidy for release
[gitmo/Mouse.git] / lib / Mouse / Meta / Method / Constructor.pm
CommitLineData
fc1d8369 1package Mouse::Meta::Method::Constructor;
bc69ee88 2use Mouse::Util; # enables strict and warnings
fc1d8369 3
380e1cd7 4sub _generate_constructor {
2a464664 5 my ($class, $metaclass, $args) = @_;
24ad3f66 6
2efc0af1 7 my $associated_metaclass_name = $metaclass->name;
0bfc7290 8
7ca5c5fb 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
0bfc7290 15 my @checks = map { $_ && $_->_compiled_type_constraint }
16 map { $_->type_constraint } @attrs;
ad087d11 17
18 my $source = sprintf("#line %d %s\n", __LINE__, __FILE__).<<"...";
19 sub \{
2a464664 20 my \$class = shift;
21 return \$class->Mouse::Object::new(\@_)
22 if \$class ne q{$associated_metaclass_name};
0bfc7290 23 # BUILDARGS
2a464664 24 $buildargs;
25 my \$instance = bless {}, \$class;
0bfc7290 26 # process attributes
2a464664 27 $processattrs;
0bfc7290 28 # BUILDALL
2a464664 29 $buildall;
30 return \$instance;
31 }
fc1d8369 32...
0bfc7290 33 #warn $source;
ad087d11 34 my $code;
35 my $e = do{
36 local $@;
37 $code = eval $source;
38 $@;
39 };
40 die $e if $e;
380e1cd7 41 return $code;
fc1d8369 42}
43
44sub _generate_processattrs {
2efc0af1 45 my ($class, $metaclass, $attrs) = @_;
fc1d8369 46 my @res;
9df6f0cd 47
2efc0af1 48 my $has_triggers;
49
9df6f0cd 50 for my $index (0 .. @$attrs - 1) {
0bfc7290 51 my $code = '';
52
c12edd9a 53 my $attr = $attrs->[$index];
fc1d8369 54 my $key = $attr->name;
9df6f0cd 55
0bfc7290 56 my $init_arg = $attr->init_arg;
57 my $type_constraint = $attr->type_constraint;
58 my $need_coercion;
c91862e8 59
0bfc7290 60 my $instance_slot = "\$instance->{q{$key}}";
61 my $attr_var = "\$attrs[$index]";
62 my $constraint_var;
c91862e8 63
0bfc7290 64 if(defined $type_constraint){
65 $constraint_var = "$attr_var\->{type_constraint}";
66 $need_coercion = ($attr->should_coerce && $type_constraint->has_coercion);
67 }
c91862e8 68
0bfc7290 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 }
c91862e8 79
0bfc7290 80 if (defined $init_arg) {
81 my $value = "\$args->{q{$init_arg}}";
c91862e8 82
0bfc7290 83 $code .= "if (exists $value) {\n";
84
85 if($need_coercion){
620c3203 86 $value = "$constraint_var->coerce($value)";
41cdacce 87 }
c91862e8 88
0bfc7290 89 $code .= "$instance_slot = $value;\n";
90 $code .= $post_process;
91
9df6f0cd 92 if ($attr->has_trigger) {
2efc0af1 93 $has_triggers++;
620c3203 94 $code .= "push \@triggers, [$attr_var\->{trigger}, $instance_slot];\n";
fc1d8369 95 }
c91862e8 96
7756897f 97 $code .= "\n} else {\n";
9df6f0cd 98 }
c91862e8 99
9df6f0cd 100 if ($attr->has_default || $attr->has_builder) {
101 unless ($attr->is_lazy) {
102 my $default = $attr->default;
103 my $builder = $attr->builder;
e8ba7b26 104
0bfc7290 105 my $value;
106 if (defined($builder)) {
107 $value = "\$instance->$builder()";
ffbbf459 108 }
109 elsif (ref($default) eq 'CODE') {
0bfc7290 110 $value = "$attr_var\->{default}->(\$instance)";
ffbbf459 111 }
0bfc7290 112 elsif (defined($default)) {
113 $value = "$attr_var\->{default}";
ffbbf459 114 }
115 else {
0bfc7290 116 $value = 'undef';
ffbbf459 117 }
e8ba7b26 118
0bfc7290 119 if($need_coercion){
120 $value = "$constraint_var->coerce($value)";
9df6f0cd 121 }
9df6f0cd 122
0bfc7290 123 $code .= "$instance_slot = $value;\n";
fc1d8369 124 }
713a2a05 125 }
9df6f0cd 126 elsif ($attr->is_required) {
7756897f 127 $code .= "Carp::confess('Attribute ($key) is required');";
9df6f0cd 128 }
129
0bfc7290 130 $code .= "}\n" if defined $init_arg;
9df6f0cd 131
fc1d8369 132 push @res, $code;
133 }
9df6f0cd 134
2efc0af1 135 if($metaclass->is_anon_class){
136 push @res, q{$instnace->{__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;
fc1d8369 145}
146
147sub _generate_BUILDARGS {
0bfc7290 148 my(undef, $metaclass) = @_;
9dcd7d23 149
0bfc7290 150 my $class = $metaclass->name;
151 if ( $class->can('BUILDARGS') && $class->can('BUILDARGS') != \&Mouse::Object::BUILDARGS ) {
53d4053e 152 return 'my $args = $class->BUILDARGS(@_)';
9dcd7d23 153 }
154
155 return <<'...';
53d4053e 156 my $args;
fc1d8369 157 if ( scalar @_ == 1 ) {
c9aefe26 158 ( ref( $_[0] ) eq 'HASH' )
fc1d8369 159 || Carp::confess "Single parameters to new() must be a HASH ref";
53d4053e 160 $args = +{ %{ $_[0] } };
fc1d8369 161 }
162 else {
53d4053e 163 $args = +{@_};
fc1d8369 164 }
fc1d8369 165...
166}
167
168sub _generate_BUILDALL {
0bfc7290 169 my (undef, $metaclass) = @_;
7ca5c5fb 170
2efc0af1 171 return '' unless $metaclass->name->can('BUILD');
fc1d8369 172
7ca5c5fb 173 my @code;
174 for my $class ($metaclass->linearized_isa) {
175 no strict 'refs';
b898bac8 176 no warnings 'once';
7ca5c5fb 177
178 if (*{ $class . '::BUILD' }{CODE}) {
179 unshift @code, qq{${class}::BUILD(\$instance, \$args);};
fc1d8369 180 }
181 }
182 return join "\n", @code;
183}
184
1851;
0126c27c 186__END__