No need to pass an index to an array when we can pass the array member
[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)
64adcd8d 105 } @{$self->attributes});
d90b42a6 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;
64adcd8d 121 my $attr = shift;
82cff1ae 122 my $close = shift;
8d2d4c67 123
d90b42a6 124 my $default;
125 if ($attr->has_default) {
126 # NOTE:
127 # default values can either be CODE refs
8d2d4c67 128 # in which case we need to call them. Or
d90b42a6 129 # they can be scalars (strings/numbers)
130 # in which case we can just deal with them
131 # in the code we eval.
132 if ($attr->is_default_a_coderef) {
82cff1ae 133 my $idx = @{$close->{'@defaults'}||=[]};
134 push(@{$close->{'@defaults'}}, $attr->default);
135 $default = '$defaults[' . $idx . ']->($instance)';
d90b42a6 136 }
137 else {
138 $default = $attr->default;
139 # make sure to quote strings ...
140 unless (looks_like_number($default)) {
141 $default = "'$default'";
142 }
143 }
8d2d4c67 144 } elsif( $attr->has_builder ) {
145 $default = '$instance->'.$attr->builder;
d90b42a6 146 }
8d2d4c67 147
c16c9c1b 148 if ( defined $attr->init_arg ) {
149 return (
26ffbb36 150 'if(exists $params->{\'' . $attr->init_arg . '\'}){' . "\n" .
c16c9c1b 151 $self->meta_instance->inline_set_slot_value(
152 '$instance',
e9a19694 153 $attr->name,
26ffbb36 154 '$params->{\'' . $attr->init_arg . '\'}' ) . "\n" .
c16c9c1b 155 '} ' . (!defined $default ? '' : 'else {' . "\n" .
156 $self->meta_instance->inline_set_slot_value(
157 '$instance',
e9a19694 158 $attr->name,
c16c9c1b 159 $default ) . "\n" .
160 '}')
161 );
162 } elsif ( defined $default ) {
163 return (
164 $self->meta_instance->inline_set_slot_value(
165 '$instance',
e9a19694 166 $attr->name,
c16c9c1b 167 $default ) . "\n"
168 );
169 } else { return '' }
d90b42a6 170}
171
1721;
173
d90b42a6 174__END__
175
176=pod
177
8d2d4c67 178=head1 NAME
d90b42a6 179
180Class::MOP::Method::Constructor - Method Meta Object for constructors
181
182=head1 SYNOPSIS
183
96e38ba6 184 use Class::MOP::Method::Constructor;
8d2d4c67 185
96e38ba6 186 my $constructor = Class::MOP::Method::Constructor->new(
8d2d4c67 187 metaclass => $metaclass,
96e38ba6 188 options => {
189 debug => 1, # this is all for now
8d2d4c67 190 },
96e38ba6 191 );
8d2d4c67 192
96e38ba6 193 # calling the constructor ...
b7045e66 194 $constructor->body->execute($metaclass->name, %params);
8d2d4c67 195
d90b42a6 196=head1 DESCRIPTION
197
3fd960d9 198This is a subclass of C<Class::MOP::Method> which generates
199constructor methods.
96e38ba6 200
d90b42a6 201=head1 METHODS
202
203=over 4
204
3fd960d9 205=item B<< Class::MOP::Method::Constructor->new(%options) >>
d90b42a6 206
3fd960d9 207This creates a new constructor object. It accepts a hash reference of
208options.
96e38ba6 209
3fd960d9 210=over 8
96e38ba6 211
3fd960d9 212=item * metaclass
96e38ba6 213
3fd960d9 214This should be a L<Class::MOP::Class> object. It is required.
c23184fc 215
3fd960d9 216=item * name
d90b42a6 217
3fd960d9 218The method name (without a package name). This is required.
96e38ba6 219
3fd960d9 220=item * package_name
d90b42a6 221
3fd960d9 222The package name for the method. This is required.
c23184fc 223
3fd960d9 224=item * is_inline
96e38ba6 225
3fd960d9 226This indicates whether or not the constructor should be inlined. This
227defaults to false.
d90b42a6 228
3fd960d9 229=back
f0de47d9 230
3fd960d9 231=item B<< $metamethod->is_inline >>
f0de47d9 232
3fd960d9 233Returns a boolean indicating whether or not the constructor is
234inlined.
d90b42a6 235
3fd960d9 236=item B<< $metamethod->associated_metaclass >>
96e38ba6 237
3fd960d9 238This returns the L<Class::MOP::Class> object for the method.
d90b42a6 239
3fd960d9 240=item B<< $metamethod->is_inline >>
565f0cbb 241
3fd960d9 242Returns a boolean indicating whether or not the constructor is
243inlined.
565f0cbb 244
3fd960d9 245=item B<< $metamethod->can_be_inlined >>
565f0cbb 246
3fd960d9 247This method always returns true in this class. It exists so that
248subclasses (as in Moose) can do some sort of checking to determine
249whether or not inlining the constructor is safe.
565f0cbb 250
251=back
252
d90b42a6 253=head1 AUTHORS
254
255Stevan Little E<lt>stevan@iinteractive.comE<gt>
256
257=head1 COPYRIGHT AND LICENSE
258
070bb6c9 259Copyright 2006-2009 by Infinity Interactive, Inc.
d90b42a6 260
261L<http://www.iinteractive.com>
262
263This library is free software; you can redistribute it and/or modify
8d2d4c67 264it under the same terms as Perl itself.
d90b42a6 265
266=cut
267