deferred constructor construction
[gitmo/Role-Tiny.git] / lib / Method / Generate / Constructor.pm
CommitLineData
6f68f022 1package Method::Generate::Constructor;
2
3use strictures 1;
4use Sub::Quote;
5use base qw(Class::Tiny::Object);
14f32032 6use Sub::Defer;
6f68f022 7
14f32032 8sub register_attribute_spec {
9 my ($self, $name, $spec) = @_;
10 $self->{attribute_specs}{$name} = $spec;
11}
12
13sub install_delayed {
14 my ($self) = @_;
15 my $package = $self->{package};
16 defer_sub "${package}::new" => sub {
17 unquote_sub $self->generate_method(
18 $package, 'new', $self->{attribute_specs}, { no_install => 1 }
19 )
20 };
21 $self;
22}
6f68f022 23
24sub generate_method {
25 my ($self, $into, $name, $spec, $quote_opts) = @_;
26 foreach my $no_init (grep !exists($spec->{$_}{init_arg}), keys %$spec) {
27 $spec->{$no_init}{init_arg} = $no_init;
28 }
29 my $body = ' my $class = shift;'."\n";
30 $body .= $self->_generate_args;
31 $body .= $self->_check_required($spec);
32 $body .= ' my $new = bless({}, $class);'."\n";
33 $body .= $self->_assign_new($spec);
4053679e 34 $body .= ' return $new;'."\n";
6f68f022 35 quote_sub
4053679e 36 "${into}::${name}" => $body,
6f68f022 37 (ref($quote_opts) ? ({}, $quote_opts) : ())
38 ;
39}
40
41sub _generate_args {
42 my ($self) = @_;
43 q{ my $args = ref($_[0]) eq 'HASH' ? $_[0] : { @_ };}."\n";
44}
45
46sub _assign_new {
47 my ($self, $spec) = @_;
48 my (@init, @slots);
49 NAME: foreach my $name (keys %$spec) {
50 my $attr_spec = $spec->{$name};
51 push @init, do {
52 next NAME unless defined(my $i = $attr_spec->{init_arg});
53 $i;
54 };
55 push @slots, $name;
56 }
14f32032 57 return '' unless @init;
6f68f022 58 ' @{$new}{qw('.join(' ',@slots).')} = @{$args}{qw('.join(' ',@init).')};'
59 ."\n";
60}
61
62sub _check_required {
63 my ($self, $spec) = @_;
64 my @required_init =
65 map $spec->{$_}{init_arg},
66 grep $spec->{$_}{required},
f0d79ee0 67 keys %$spec;
6f68f022 68 return '' unless @required_init;
69 ' if (my @missing = grep !exists $args->{$_}, qw('
70 .join(' ',@required_init).')) {'."\n"
71 .q{ die "Missing required arguments: ".join(', ', sort @missing);}."\n"
72 ." }\n";
73}
74
751;