X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMethod%2FGenerate%2FConstructor.pm;h=5d459b6c791d1531fccb41661432b1c276894ee0;hb=d02da2bc41a7f450a64ef79a571a889e73f690d6;hp=6d45aee6f711c032ca5f1e37ede974fe70fd6cdc;hpb=a16d301ee1659572170ed6baebb3f5e2451b35f5;p=gitmo%2FRole-Tiny.git diff --git a/lib/Method/Generate/Constructor.pm b/lib/Method/Generate/Constructor.pm index 6d45aee..5d459b6 100644 --- a/lib/Method/Generate/Constructor.pm +++ b/lib/Method/Generate/Constructor.pm @@ -2,7 +2,7 @@ package Method::Generate::Constructor; use strictures 1; use Sub::Quote; -use base qw(Class::Tiny::Object); +use base qw(Moo::Object); use Sub::Defer; use B 'perlstring'; @@ -20,6 +20,11 @@ sub accessor_generator { $_[0]->{accessor_generator} } +sub construction_string { + my ($self) = @_; + $self->{construction_string} or 'bless({}, $class);' +} + sub install_delayed { my ($self) = @_; my $package = $self->{package}; @@ -40,9 +45,14 @@ sub generate_method { my $body = ' my $class = shift;'."\n"; $body .= $self->_generate_args; $body .= $self->_check_required($spec); - $body .= ' my $new = bless({}, $class);'."\n"; + $body .= ' my $new = '.$self->construction_string.";\n"; $body .= $self->_assign_new($spec); - $body .= $self->_fire_triggers($spec); + if ($into->can('BUILD')) { + require Method::Generate::BuildAll; + $body .= Method::Generate::BuildAll->new->buildall_body_for( + $into, '$new', '$args' + ); + } $body .= ' return $new;'."\n"; quote_sub "${into}::${name}" => $body, @@ -50,6 +60,12 @@ sub generate_method { ; } +sub _cap_call { + my ($self, $code, $captures) = @_; + @{$self->{captures}}{keys %$captures} = values %$captures if $captures; + $code; +} + sub _generate_args { my ($self) = @_; q{ my $args = ref($_[0]) eq 'HASH' ? $_[0] : { @_ };}."\n"; @@ -57,18 +73,37 @@ sub _generate_args { sub _assign_new { my ($self, $spec) = @_; - my (@init, @slots); - NAME: foreach my $name (keys %$spec) { + my (@init, @slots, %test); + my $ag = $self->accessor_generator; + NAME: foreach my $name (sort keys %$spec) { my $attr_spec = $spec->{$name}; - push @init, do { - next NAME unless defined(my $i = $attr_spec->{init_arg}); - $i; - }; + unless ($ag->is_simple_attribute($name, $attr_spec)) { + next NAME unless defined($attr_spec->{init_arg}) + or (($attr_spec->{default} or $attr_spec->{builder}) + and not $attr_spec->{lazy}); + $test{$name} = $attr_spec->{init_arg}; + next NAME; + } + next NAME unless defined(my $i = $attr_spec->{init_arg}); + push @init, $i; push @slots, $name; } - return '' unless @init; - ' @{$new}{qw('.join(' ',@slots).')} = @{$args}{qw('.join(' ',@init).')};' - ."\n"; + return '' unless @init or %test; + join '', ( + @init + ? ' '.$self->_cap_call($ag->generate_multi_set( + '$new', [ @slots ], '@{$args}{qw('.join(' ',@init).')}' + )).";\n" + : '' + ), map { + my $arg_key = perlstring($test{$_}); + my $test = "exists \$args->{$arg_key}"; + my $source = "\$args->{$arg_key}"; + my $attr_spec = $spec->{$_}; + $self->_cap_call($ag->generate_populate_set( + '$new', $_, $attr_spec, $source, $test + )); + } sort keys %test; } sub _check_required { @@ -76,7 +111,7 @@ sub _check_required { my @required_init = map $spec->{$_}{init_arg}, grep $spec->{$_}{required}, - keys %$spec; + sort keys %$spec; return '' unless @required_init; ' if (my @missing = grep !exists $args->{$_}, qw(' .join(' ',@required_init).')) {'."\n" @@ -84,15 +119,35 @@ sub _check_required { ." }\n"; } +sub _check_isa { + my ($self, $spec) = @_; + my $acc = $self->accessor_generator; + my $captures = $self->{captures}; + my $check = ''; + foreach my $name (sort keys %$spec) { + my ($init, $isa) = @{$spec->{$name}}{qw(init_arg isa)}; + next unless $init and $isa; + my $init_str = perlstring($init); + my ($code, $add_captures) = $acc->generate_isa_check( + $name, "\$args->{${init_str}}", $isa + ); + @{$captures}{keys %$add_captures} = values %$add_captures; + $check .= " ${code}".( + (not($spec->{lazy}) and ($spec->{default} or $spec->{builder}) + ? ";\n" + : "if exists \$args->{${init_str}};\n" + ) + ); + } + return $check; +} + sub _fire_triggers { my ($self, $spec) = @_; - my @fire = map { - [ $_, $spec->{$_}{init_arg}, $spec->{$_}{trigger} ] - } grep { $spec->{$_}{init_arg} && $spec->{$_}{trigger} } keys %$spec; my $acc = $self->accessor_generator; my $captures = $self->{captures}; my $fire = ''; - foreach my $name (keys %$spec) { + foreach my $name (sort keys %$spec) { my ($init, $trigger) = @{$spec->{$name}}{qw(init_arg trigger)}; next unless $init && $trigger; my ($code, $add_captures) = $acc->generate_trigger(