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