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