Only inline BUILDARGS if the class has one that isn't Mouse::Object's
[gitmo/Mouse.git] / lib / Mouse / Meta / Method / Constructor.pm
CommitLineData
fc1d8369 1package Mouse::Meta::Method::Constructor;
2use strict;
3use warnings;
4
5sub generate_constructor_method_inline {
41cdacce 6 my ($class, $meta) = @_;
24ad3f66 7
a4d5249c 8 my @attrs = $meta->compute_all_applicable_attributes;
fc1d8369 9 my $buildall = $class->_generate_BUILDALL($meta);
9dcd7d23 10 my $buildargs = $class->_generate_BUILDARGS($meta);
c12edd9a 11 my $processattrs = $class->_generate_processattrs($meta, \@attrs);
fc1d8369 12
24ad3f66 13 my $code = <<"...";
fc1d8369 14 sub {
15 my \$class = shift;
16 my \$args = $buildargs;
24ad3f66 17 my \$instance = bless {}, \$class;
fc1d8369 18 $processattrs;
19 $buildall;
20 return \$instance;
21 }
22...
24ad3f66 23
24ad3f66 24 local $@;
25 my $res = eval $code;
26 die $@ if $@;
27 $res;
fc1d8369 28}
29
30sub _generate_processattrs {
c12edd9a 31 my ($class, $meta, $attrs) = @_;
fc1d8369 32 my @res;
9df6f0cd 33
34 for my $index (0 .. @$attrs - 1) {
c12edd9a 35 my $attr = $attrs->[$index];
fc1d8369 36 my $key = $attr->name;
9df6f0cd 37 my $code = '';
38
39 if (defined $attr->init_arg) {
40 my $from = $attr->init_arg;
c91862e8 41
9df6f0cd 42 $code .= "if (exists \$args->{'$from'}) {\n";
c91862e8 43
b3b74cc6 44 if ($attr->should_coerce && $attr->type_constraint) {
9df6f0cd 45 $code .= "my \$value = Mouse::TypeRegistry->typecast_constraints('".$attr->associated_class->name."', \$attrs[$index]->{find_type_constraint}, \$attrs[$index]->{type_constraint}, \$args->{'$from'});";
7bf66a9b 46 }
47 else {
9df6f0cd 48 $code .= "my \$value = \$args->{'$from'};";
fc1d8369 49 }
c91862e8 50
fc1d8369 51 if ($attr->has_type_constraint) {
9df6f0cd 52 $code .= "{local \$_ = \$value; unless (\$attrs[$index]->{find_type_constraint}->(\$_)) {";
53 $code .= "\$attrs[$index]->verify_type_constraint_error('$key', \$_, \$attrs[$index]->type_constraint)}}";
fc1d8369 54 }
c91862e8 55
9df6f0cd 56 $code .= "\$instance->{'$key'} = \$value;";
c91862e8 57
41cdacce 58 if ($attr->is_weak_ref) {
9df6f0cd 59 $code .= "Scalar::Util::weaken( \$instance->{'$key'} ) if ref( \$value );";
41cdacce 60 }
c91862e8 61
9df6f0cd 62 if ($attr->has_trigger) {
63 $code .= "\$attrs[$index]->{trigger}->( \$instance, \$value, \$attrs[$index] );";
fc1d8369 64 }
c91862e8 65
9df6f0cd 66 $code .= "} else {";
67 }
c91862e8 68
9df6f0cd 69 if ($attr->has_default || $attr->has_builder) {
70 unless ($attr->is_lazy) {
71 my $default = $attr->default;
72 my $builder = $attr->builder;
e8ba7b26 73
9df6f0cd 74 $code .= "my \$value = ";
e8ba7b26 75
9df6f0cd 76 if ($attr->should_coerce && $attr->type_constraint) {
77 $code .= "Mouse::TypeRegistry->typecast_constraints('".$attr->associated_class->name."', \$attrs[$index]->{find_type_constraint}, \$attrs[$index]->{type_constraint}, ";
78 }
e8ba7b26 79
9df6f0cd 80 if ($attr->has_builder) {
81 $code .= "\$instance->$builder";
fc1d8369 82 }
9df6f0cd 83 elsif (ref($default) eq 'CODE') {
84 $code .= "\$attrs[$index]->{default}->(\$instance)";
e8ba7b26 85 }
9df6f0cd 86 elsif (!defined($default)) {
87 $code .= 'undef';
fc1d8369 88 }
9df6f0cd 89 elsif ($default =~ /^\-?[0-9]+(?:\.[0-9]+)$/) {
90 $code .= $default;
91 }
92 else {
93 $code .= "'$default'";
fc1d8369 94 }
e8ba7b26 95
9df6f0cd 96 if ($attr->should_coerce) {
97 $code .= ");";
98 }
99 else {
100 $code .= ";";
101 }
e8ba7b26 102
9df6f0cd 103 if ($attr->has_type_constraint) {
104 $code .= "{local \$_ = \$value; unless (\$attrs[$index]->{find_type_constraint}->(\$_)) {";
105 $code .= "\$attrs[$index]->verify_type_constraint_error('$key', \$_, \$attrs[$index]->type_constraint)}}";
fc1d8369 106 }
9df6f0cd 107
108 $code .= "\$instance->{'$key'} = \$value;";
109
110 if ($attr->is_weak_ref) {
111 $code .= "Scalar::Util::weaken( \$instance->{'$key'} ) if ref( \$value );";
fc1d8369 112 }
113 }
713a2a05 114 }
9df6f0cd 115 elsif ($attr->is_required) {
116 $code .= qq{Carp::confess("Attribute ($key) is required");};
117 }
118
119 $code .= "}" if defined $attr->init_arg;
120
fc1d8369 121 push @res, $code;
122 }
9df6f0cd 123
fc1d8369 124 return join "\n", @res;
125}
126
127sub _generate_BUILDARGS {
9dcd7d23 128 my $self = shift;
129 my $meta = shift;
130
131 if ($meta->name->can('BUILDARGS') != Mouse::Object->can('BUILDARGS')) {
132 return '$class->BUILDARGS(@_)';
133 }
134
135 return <<'...';
fc1d8369 136 do {
137 if ( scalar @_ == 1 ) {
138 if ( defined $_[0] ) {
139 ( ref( $_[0] ) eq 'HASH' )
140 || Carp::confess "Single parameters to new() must be a HASH ref";
141 +{ %{ $_[0] } };
142 }
143 else {
144 +{};
145 }
146 }
147 else {
148 +{@_};
149 }
150 };
151...
152}
153
154sub _generate_BUILDALL {
155 my ($class, $meta) = @_;
156 return '' unless $meta->name->can('BUILD');
157
158 my @code = ();
159 push @code, q{no strict 'refs';};
160 push @code, q{no warnings 'once';};
161 no strict 'refs';
ca3bebbd 162 for my $klass ($meta->linearized_isa) {
163 if (*{ $klass . '::BUILD' }{CODE}) {
63d74d7a 164 push @code, qq{${klass}::BUILD(\$instance, \$args);};
fc1d8369 165 }
166 }
167 return join "\n", @code;
168}
169
1701;