bump copyright year to 2009
[gitmo/Class-MOP.git] / lib / Class / MOP / Method / Constructor.pm
CommitLineData
d90b42a6 1
2package Class::MOP::Method::Constructor;
3
4use strict;
5use warnings;
6
7use Carp 'confess';
8use Scalar::Util 'blessed', 'weaken', 'looks_like_number';
9
eca95e04 10our $VERSION = '0.78';
d519662a 11$VERSION = eval $VERSION;
d90b42a6 12our $AUTHORITY = 'cpan:STEVAN';
13
565f0cbb 14use base 'Class::MOP::Method::Generated';
d90b42a6 15
16sub new {
17 my $class = shift;
18 my %options = @_;
8d2d4c67 19
ad315b75 20 (blessed $options{metaclass} && $options{metaclass}->isa('Class::MOP::Class'))
21 || confess "You must pass a metaclass instance if you want to inline"
8d2d4c67 22 if $options{is_inline};
23
b38f3848 24 ($options{package_name} && $options{name})
32202ce2 25 || confess "You must supply the package_name and name parameters $Class::MOP::Method::UPGRADE_ERROR_TEXT";
b38f3848 26
0bfc85b8 27 my $self = $class->_new(\%options);
d90b42a6 28
8d2d4c67 29 # we don't want this creating
30 # a cycle in the code, if not
d90b42a6 31 # needed
8683db0e 32 weaken($self->{'associated_metaclass'});
d90b42a6 33
565f0cbb 34 $self->initialize_body;
d90b42a6 35
8d2d4c67 36 return $self;
d90b42a6 37}
38
28b97bef 39sub _new {
0bfc85b8 40 my $class = shift;
41 my $options = @_ == 1 ? $_[0] : {@_};
28b97bef 42
43 bless {
44 # from our superclass
45 'body' => undef,
0bfc85b8 46 'package_name' => $options->{package_name},
47 'name' => $options->{name},
28b97bef 48 # specific to this subclass
0bfc85b8 49 'options' => $options->{options} || {},
50 'associated_metaclass' => $options->{metaclass},
51 'is_inline' => ($options->{is_inline} || 0),
28b97bef 52 }, $class;
53}
54
f0de47d9 55sub can_be_inlined { 1 }
56
8d2d4c67 57## accessors
c23184fc 58
8683db0e 59sub options { (shift)->{'options'} }
60sub associated_metaclass { (shift)->{'associated_metaclass'} }
c23184fc 61
565f0cbb 62## cached values ...
d90b42a6 63
8d2d4c67 64sub meta_instance {
565f0cbb 65 my $self = shift;
8683db0e 66 $self->{'meta_instance'} ||= $self->associated_metaclass->get_meta_instance;
565f0cbb 67}
c23184fc 68
8d2d4c67 69sub attributes {
565f0cbb 70 my $self = shift;
8683db0e 71 $self->{'attributes'} ||= [ $self->associated_metaclass->compute_all_applicable_attributes ]
565f0cbb 72}
d90b42a6 73
74## method
75
565f0cbb 76sub initialize_body {
77 my $self = shift;
78 my $method_name = 'generate_constructor_method';
8d2d4c67 79
565f0cbb 80 $method_name .= '_inline' if $self->is_inline;
8d2d4c67 81
8683db0e 82 $self->{'body'} = $self->$method_name;
565f0cbb 83}
84
85sub generate_constructor_method {
2a2b8458 86 return sub { Class::MOP::Class->initialize(shift)->new_object(@_) }
565f0cbb 87}
88
89sub generate_constructor_method_inline {
d90b42a6 90 my $self = shift;
565f0cbb 91
0c6f3280 92 my $close_over = {};
93
d90b42a6 94 my $source = 'sub {';
26ffbb36 95 $source .= "\n" . 'my $class = shift;';
8d2d4c67 96
26ffbb36 97 $source .= "\n" . 'return Class::MOP::Class->initialize($class)->new_object(@_)';
8d2d4c67 98 $source .= "\n" . ' if $class ne \'' . $self->associated_metaclass->name . '\';';
99
26ffbb36 100 $source .= "\n" . 'my $params = @_ == 1 ? $_[0] : {@_};';
101
d90b42a6 102 $source .= "\n" . 'my $instance = ' . $self->meta_instance->inline_create_instance('$class');
8d2d4c67 103 $source .= ";\n" . (join ";\n" => map {
82cff1ae 104 $self->_generate_slot_initializer($_, $close_over)
d90b42a6 105 } 0 .. (@{$self->attributes} - 1));
106 $source .= ";\n" . 'return $instance';
8d2d4c67 107 $source .= ";\n" . '}';
108 warn $source if $self->options->{debug};
109
a6eef5a3 110 my $code = $self->_eval_closure(
ffe92c8b 111 $close_over,
112 $source
113 );
a6eef5a3 114 confess "Could not eval the constructor :\n\n$source\n\nbecause :\n\n$@" if $@;
115
116 return $code;
d90b42a6 117}
118
119sub _generate_slot_initializer {
120 my $self = shift;
121 my $index = shift;
82cff1ae 122 my $close = shift;
8d2d4c67 123
d90b42a6 124 my $attr = $self->attributes->[$index];
8d2d4c67 125
d90b42a6 126 my $default;
127 if ($attr->has_default) {
128 # NOTE:
129 # default values can either be CODE refs
8d2d4c67 130 # in which case we need to call them. Or
d90b42a6 131 # they can be scalars (strings/numbers)
132 # in which case we can just deal with them
133 # in the code we eval.
134 if ($attr->is_default_a_coderef) {
82cff1ae 135 my $idx = @{$close->{'@defaults'}||=[]};
136 push(@{$close->{'@defaults'}}, $attr->default);
137 $default = '$defaults[' . $idx . ']->($instance)';
d90b42a6 138 }
139 else {
140 $default = $attr->default;
141 # make sure to quote strings ...
142 unless (looks_like_number($default)) {
143 $default = "'$default'";
144 }
145 }
8d2d4c67 146 } elsif( $attr->has_builder ) {
147 $default = '$instance->'.$attr->builder;
d90b42a6 148 }
8d2d4c67 149
c16c9c1b 150 if ( defined $attr->init_arg ) {
151 return (
26ffbb36 152 'if(exists $params->{\'' . $attr->init_arg . '\'}){' . "\n" .
c16c9c1b 153 $self->meta_instance->inline_set_slot_value(
154 '$instance',
e9a19694 155 $attr->name,
26ffbb36 156 '$params->{\'' . $attr->init_arg . '\'}' ) . "\n" .
c16c9c1b 157 '} ' . (!defined $default ? '' : 'else {' . "\n" .
158 $self->meta_instance->inline_set_slot_value(
159 '$instance',
e9a19694 160 $attr->name,
c16c9c1b 161 $default ) . "\n" .
162 '}')
163 );
164 } elsif ( defined $default ) {
165 return (
166 $self->meta_instance->inline_set_slot_value(
167 '$instance',
e9a19694 168 $attr->name,
c16c9c1b 169 $default ) . "\n"
170 );
171 } else { return '' }
d90b42a6 172}
173
1741;
175
d90b42a6 176__END__
177
178=pod
179
8d2d4c67 180=head1 NAME
d90b42a6 181
182Class::MOP::Method::Constructor - Method Meta Object for constructors
183
184=head1 SYNOPSIS
185
96e38ba6 186 use Class::MOP::Method::Constructor;
8d2d4c67 187
96e38ba6 188 my $constructor = Class::MOP::Method::Constructor->new(
8d2d4c67 189 metaclass => $metaclass,
96e38ba6 190 options => {
191 debug => 1, # this is all for now
8d2d4c67 192 },
96e38ba6 193 );
8d2d4c67 194
96e38ba6 195 # calling the constructor ...
b7045e66 196 $constructor->body->execute($metaclass->name, %params);
8d2d4c67 197
d90b42a6 198=head1 DESCRIPTION
199
8d2d4c67 200This is a subclass of C<Class::MOP::Method> which deals with
127d39a7 201class constructors. This is used when making a class immutable
202to generate an optimized constructor.
96e38ba6 203
d90b42a6 204=head1 METHODS
205
206=over 4
207
96e38ba6 208=item B<new (metaclass => $meta, options => \%options)>
d90b42a6 209
96e38ba6 210=item B<options>
211
212This returns the options HASH which is passed into C<new>.
213
214=item B<associated_metaclass>
215
216This returns the metaclass which is passed into C<new>.
c23184fc 217
d90b42a6 218=item B<attributes>
219
8d2d4c67 220This returns the list of attributes which are associated with the
96e38ba6 221metaclass which is passed into C<new>.
222
d90b42a6 223=item B<meta_instance>
224
8d2d4c67 225This returns the meta instance which is associated with the
96e38ba6 226metaclass which is passed into C<new>.
c23184fc 227
96e38ba6 228=item B<is_inline>
229
8d2d4c67 230This returns a boolean, but since constructors are very rarely
96e38ba6 231not inlined, this always returns true for now.
d90b42a6 232
f0de47d9 233=item B<can_be_inlined>
234
235This method always returns true in this class. It exists so that
236subclasses (like in Moose) can override and do some sort of checking
237to determine whether or not inlining the constructor is safe.
238
565f0cbb 239=item B<initialize_body>
d90b42a6 240
8d2d4c67 241This creates the code reference for the constructor itself.
96e38ba6 242
d90b42a6 243=back
244
127d39a7 245=head2 Method Generators
565f0cbb 246
247=over 4
248
249=item B<generate_constructor_method>
250
251=item B<generate_constructor_method_inline>
252
253=back
254
d90b42a6 255=head1 AUTHORS
256
257Stevan Little E<lt>stevan@iinteractive.comE<gt>
258
259=head1 COPYRIGHT AND LICENSE
260
070bb6c9 261Copyright 2006-2009 by Infinity Interactive, Inc.
d90b42a6 262
263L<http://www.iinteractive.com>
264
265This library is free software; you can redistribute it and/or modify
8d2d4c67 266it under the same terms as Perl itself.
d90b42a6 267
268=cut
269