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