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