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