one more spot still referring to compute_all_applicable_attributes
[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
f3ddcd1a 10our $VERSION = '0.80';
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
8f7852d8 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 {
5a49fb79 65 warn 'The meta_instance method has been made private.'
66 . " The public version is deprecated and will be removed in a future release.\n";
d5c7f638 67 shift->_meta_instance;
5a49fb79 68}
69
70sub _meta_instance {
565f0cbb 71 my $self = shift;
8683db0e 72 $self->{'meta_instance'} ||= $self->associated_metaclass->get_meta_instance;
565f0cbb 73}
c23184fc 74
8d2d4c67 75sub attributes {
6e2f5a81 76 warn 'The attributes method is deprecated.'
2620be77 77 . " Use ->associated_metaclass->get_all_attributes instead.\n";
6e2f5a81 78
565f0cbb 79 my $self = shift;
2620be77 80 $self->{'attributes'} ||= [ $self->associated_metaclass->get_all_attributes ]
565f0cbb 81}
d90b42a6 82
83## method
84
565f0cbb 85sub initialize_body {
8f7852d8 86 warn 'The initialize_body method has been made private.'
87 . " The public version is deprecated and will be removed in a future release.\n";
d5c7f638 88 shift->_initialize_body;
8f7852d8 89}
90
91sub _initialize_body {
565f0cbb 92 my $self = shift;
ecb874a0 93 my $method_name = '_generate_constructor_method';
8d2d4c67 94
565f0cbb 95 $method_name .= '_inline' if $self->is_inline;
8d2d4c67 96
8683db0e 97 $self->{'body'} = $self->$method_name;
565f0cbb 98}
99
100sub generate_constructor_method {
ecb874a0 101 warn 'The generate_constructor_method method has been made private.'
102 . " The public version is deprecated and will be removed in a future release.\n";
d5c7f638 103 shift->_generate_constructor_method;
ecb874a0 104}
105
106sub _generate_constructor_method {
2a2b8458 107 return sub { Class::MOP::Class->initialize(shift)->new_object(@_) }
565f0cbb 108}
109
110sub generate_constructor_method_inline {
ecb874a0 111 warn 'The generate_constructor_method_inline method has been made private.'
112 . " The public version is deprecated and will be removed in a future release.\n";
d5c7f638 113 shift->_generate_constructor_method_inline;
ecb874a0 114}
115
116sub _generate_constructor_method_inline {
d90b42a6 117 my $self = shift;
565f0cbb 118
0c6f3280 119 my $close_over = {};
120
d90b42a6 121 my $source = 'sub {';
26ffbb36 122 $source .= "\n" . 'my $class = shift;';
8d2d4c67 123
26ffbb36 124 $source .= "\n" . 'return Class::MOP::Class->initialize($class)->new_object(@_)';
8d2d4c67 125 $source .= "\n" . ' if $class ne \'' . $self->associated_metaclass->name . '\';';
126
26ffbb36 127 $source .= "\n" . 'my $params = @_ == 1 ? $_[0] : {@_};';
128
5a49fb79 129 $source .= "\n" . 'my $instance = ' . $self->_meta_instance->inline_create_instance('$class');
8d2d4c67 130 $source .= ";\n" . (join ";\n" => map {
82cff1ae 131 $self->_generate_slot_initializer($_, $close_over)
2620be77 132 } $self->associated_metaclass->get_all_attributes);
d90b42a6 133 $source .= ";\n" . 'return $instance';
8d2d4c67 134 $source .= ";\n" . '}';
135 warn $source if $self->options->{debug};
136
a6eef5a3 137 my $code = $self->_eval_closure(
ffe92c8b 138 $close_over,
139 $source
140 );
a6eef5a3 141 confess "Could not eval the constructor :\n\n$source\n\nbecause :\n\n$@" if $@;
142
143 return $code;
d90b42a6 144}
145
146sub _generate_slot_initializer {
147 my $self = shift;
64adcd8d 148 my $attr = shift;
82cff1ae 149 my $close = shift;
8d2d4c67 150
d90b42a6 151 my $default;
152 if ($attr->has_default) {
153 # NOTE:
154 # default values can either be CODE refs
8d2d4c67 155 # in which case we need to call them. Or
d90b42a6 156 # they can be scalars (strings/numbers)
157 # in which case we can just deal with them
158 # in the code we eval.
159 if ($attr->is_default_a_coderef) {
82cff1ae 160 my $idx = @{$close->{'@defaults'}||=[]};
161 push(@{$close->{'@defaults'}}, $attr->default);
162 $default = '$defaults[' . $idx . ']->($instance)';
d90b42a6 163 }
164 else {
165 $default = $attr->default;
166 # make sure to quote strings ...
167 unless (looks_like_number($default)) {
168 $default = "'$default'";
169 }
170 }
8d2d4c67 171 } elsif( $attr->has_builder ) {
172 $default = '$instance->'.$attr->builder;
d90b42a6 173 }
8d2d4c67 174
c16c9c1b 175 if ( defined $attr->init_arg ) {
176 return (
26ffbb36 177 'if(exists $params->{\'' . $attr->init_arg . '\'}){' . "\n" .
5a49fb79 178 $self->_meta_instance->inline_set_slot_value(
c16c9c1b 179 '$instance',
e9a19694 180 $attr->name,
26ffbb36 181 '$params->{\'' . $attr->init_arg . '\'}' ) . "\n" .
c16c9c1b 182 '} ' . (!defined $default ? '' : 'else {' . "\n" .
5a49fb79 183 $self->_meta_instance->inline_set_slot_value(
c16c9c1b 184 '$instance',
e9a19694 185 $attr->name,
c16c9c1b 186 $default ) . "\n" .
187 '}')
188 );
189 } elsif ( defined $default ) {
190 return (
5a49fb79 191 $self->_meta_instance->inline_set_slot_value(
c16c9c1b 192 '$instance',
e9a19694 193 $attr->name,
c16c9c1b 194 $default ) . "\n"
195 );
196 } else { return '' }
d90b42a6 197}
198
1991;
200
d90b42a6 201__END__
202
203=pod
204
8d2d4c67 205=head1 NAME
d90b42a6 206
207Class::MOP::Method::Constructor - Method Meta Object for constructors
208
209=head1 SYNOPSIS
210
96e38ba6 211 use Class::MOP::Method::Constructor;
8d2d4c67 212
96e38ba6 213 my $constructor = Class::MOP::Method::Constructor->new(
8d2d4c67 214 metaclass => $metaclass,
96e38ba6 215 options => {
216 debug => 1, # this is all for now
8d2d4c67 217 },
96e38ba6 218 );
8d2d4c67 219
96e38ba6 220 # calling the constructor ...
b7045e66 221 $constructor->body->execute($metaclass->name, %params);
8d2d4c67 222
d90b42a6 223=head1 DESCRIPTION
224
3fd960d9 225This is a subclass of C<Class::MOP::Method> which generates
226constructor methods.
96e38ba6 227
d90b42a6 228=head1 METHODS
229
230=over 4
231
3fd960d9 232=item B<< Class::MOP::Method::Constructor->new(%options) >>
d90b42a6 233
3fd960d9 234This creates a new constructor object. It accepts a hash reference of
235options.
96e38ba6 236
3fd960d9 237=over 8
96e38ba6 238
3fd960d9 239=item * metaclass
96e38ba6 240
3fd960d9 241This should be a L<Class::MOP::Class> object. It is required.
c23184fc 242
3fd960d9 243=item * name
d90b42a6 244
3fd960d9 245The method name (without a package name). This is required.
96e38ba6 246
3fd960d9 247=item * package_name
d90b42a6 248
3fd960d9 249The package name for the method. This is required.
c23184fc 250
3fd960d9 251=item * is_inline
96e38ba6 252
3fd960d9 253This indicates whether or not the constructor should be inlined. This
254defaults to false.
d90b42a6 255
3fd960d9 256=back
f0de47d9 257
3fd960d9 258=item B<< $metamethod->is_inline >>
f0de47d9 259
3fd960d9 260Returns a boolean indicating whether or not the constructor is
261inlined.
d90b42a6 262
3fd960d9 263=item B<< $metamethod->associated_metaclass >>
96e38ba6 264
3fd960d9 265This returns the L<Class::MOP::Class> object for the method.
d90b42a6 266
3fd960d9 267=item B<< $metamethod->can_be_inlined >>
565f0cbb 268
3fd960d9 269This method always returns true in this class. It exists so that
270subclasses (as in Moose) can do some sort of checking to determine
271whether or not inlining the constructor is safe.
565f0cbb 272
273=back
274
d90b42a6 275=head1 AUTHORS
276
277Stevan Little E<lt>stevan@iinteractive.comE<gt>
278
279=head1 COPYRIGHT AND LICENSE
280
070bb6c9 281Copyright 2006-2009 by Infinity Interactive, Inc.
d90b42a6 282
283L<http://www.iinteractive.com>
284
285This library is free software; you can redistribute it and/or modify
8d2d4c67 286it under the same terms as Perl itself.
d90b42a6 287
288=cut
289