fixed documentation for predicate to match behaviour changed in 0.43
[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
565f0cbb 10our $VERSION = '0.02';
d90b42a6 11our $AUTHORITY = 'cpan:STEVAN';
12
565f0cbb 13use base 'Class::MOP::Method::Generated';
d90b42a6 14
15sub new {
16 my $class = shift;
17 my %options = @_;
8d2d4c67 18
ad315b75 19 (blessed $options{metaclass} && $options{metaclass}->isa('Class::MOP::Class'))
20 || confess "You must pass a metaclass instance if you want to inline"
8d2d4c67 21 if $options{is_inline};
22
d90b42a6 23 my $self = bless {
24 # from our superclass
c23184fc 25 '&!body' => undef,
d90b42a6 26 # specific to this subclass
ad315b75 27 '%!options' => $options{options} || {},
c23184fc 28 '$!associated_metaclass' => $options{metaclass},
8d2d4c67 29 '$!is_inline' => ($options{is_inline} || 0),
d90b42a6 30 } => $class;
31
8d2d4c67 32 # we don't want this creating
33 # a cycle in the code, if not
d90b42a6 34 # needed
8d2d4c67 35 weaken($self->{'$!associated_metaclass'});
d90b42a6 36
565f0cbb 37 $self->initialize_body;
d90b42a6 38
8d2d4c67 39 return $self;
d90b42a6 40}
41
8d2d4c67 42## accessors
c23184fc 43
565f0cbb 44sub options { (shift)->{'%!options'} }
45sub associated_metaclass { (shift)->{'$!associated_metaclass'} }
c23184fc 46
565f0cbb 47## cached values ...
d90b42a6 48
8d2d4c67 49sub meta_instance {
565f0cbb 50 my $self = shift;
51 $self->{'$!meta_instance'} ||= $self->associated_metaclass->get_meta_instance;
52}
c23184fc 53
8d2d4c67 54sub attributes {
565f0cbb 55 my $self = shift;
56 $self->{'@!attributes'} ||= [ $self->associated_metaclass->compute_all_applicable_attributes ]
57}
d90b42a6 58
59## method
60
565f0cbb 61sub initialize_body {
62 my $self = shift;
63 my $method_name = 'generate_constructor_method';
8d2d4c67 64
565f0cbb 65 $method_name .= '_inline' if $self->is_inline;
8d2d4c67 66
565f0cbb 67 $self->{'&!body'} = $self->$method_name;
68}
69
70sub generate_constructor_method {
71 return sub { (shift)->meta->new_object(@_) }
72}
73
74sub generate_constructor_method_inline {
d90b42a6 75 my $self = shift;
565f0cbb 76
d90b42a6 77 my $source = 'sub {';
78 $source .= "\n" . 'my ($class, %params) = @_;';
8d2d4c67 79
565f0cbb 80 $source .= "\n" . 'return $class->meta->new_object(%params)';
8d2d4c67 81 $source .= "\n" . ' if $class ne \'' . $self->associated_metaclass->name . '\';';
82
d90b42a6 83 $source .= "\n" . 'my $instance = ' . $self->meta_instance->inline_create_instance('$class');
8d2d4c67 84 $source .= ";\n" . (join ";\n" => map {
85 $self->_generate_slot_initializer($_)
d90b42a6 86 } 0 .. (@{$self->attributes} - 1));
87 $source .= ";\n" . 'return $instance';
8d2d4c67 88 $source .= ";\n" . '}';
89 warn $source if $self->options->{debug};
90
d90b42a6 91 my $code;
92 {
93 # NOTE:
94 # create the nessecary lexicals
8d2d4c67 95 # to be picked up in the eval
d90b42a6 96 my $attrs = $self->attributes;
8d2d4c67 97
d90b42a6 98 $code = eval $source;
99 confess "Could not eval the constructor :\n\n$source\n\nbecause :\n\n$@" if $@;
100 }
565f0cbb 101 return $code;
d90b42a6 102}
103
104sub _generate_slot_initializer {
105 my $self = shift;
106 my $index = shift;
8d2d4c67 107
d90b42a6 108 my $attr = $self->attributes->[$index];
8d2d4c67 109
d90b42a6 110 my $default;
111 if ($attr->has_default) {
112 # NOTE:
113 # default values can either be CODE refs
8d2d4c67 114 # in which case we need to call them. Or
d90b42a6 115 # they can be scalars (strings/numbers)
116 # in which case we can just deal with them
117 # in the code we eval.
118 if ($attr->is_default_a_coderef) {
119 $default = '$attrs->[' . $index . ']->default($instance)';
120 }
121 else {
122 $default = $attr->default;
123 # make sure to quote strings ...
124 unless (looks_like_number($default)) {
125 $default = "'$default'";
126 }
127 }
8d2d4c67 128 } elsif( $attr->has_builder ) {
129 $default = '$instance->'.$attr->builder;
d90b42a6 130 }
8d2d4c67 131
132 'if(exists $params{\'' . $attr->init_arg . '\'}){' . "\n" .
133 $self->meta_instance->inline_set_slot_value(
134 '$instance',
135 ("'" . $attr->name . "'"),
136 '$params{\'' . $attr->init_arg . '\'}' ) . "\n" .
137 '} ' . (!defined $default ? '' : 'else {' . "\n" .
138 $self->meta_instance->inline_set_slot_value(
139 '$instance',
140 ("'" . $attr->name . "'"),
141 $default ) . "\n" .
142 '}');
d90b42a6 143}
144
1451;
146
1471;
148
149__END__
150
151=pod
152
8d2d4c67 153=head1 NAME
d90b42a6 154
155Class::MOP::Method::Constructor - Method Meta Object for constructors
156
157=head1 SYNOPSIS
158
96e38ba6 159 use Class::MOP::Method::Constructor;
8d2d4c67 160
96e38ba6 161 my $constructor = Class::MOP::Method::Constructor->new(
8d2d4c67 162 metaclass => $metaclass,
96e38ba6 163 options => {
164 debug => 1, # this is all for now
8d2d4c67 165 },
96e38ba6 166 );
8d2d4c67 167
96e38ba6 168 # calling the constructor ...
169 $constructor->body->($metaclass->name, %params);
8d2d4c67 170
d90b42a6 171=head1 DESCRIPTION
172
8d2d4c67 173This is a subclass of C<Class::MOP::Method> which deals with
174class constructors.
96e38ba6 175
d90b42a6 176=head1 METHODS
177
178=over 4
179
96e38ba6 180=item B<new (metaclass => $meta, options => \%options)>
d90b42a6 181
96e38ba6 182=item B<options>
183
184This returns the options HASH which is passed into C<new>.
185
186=item B<associated_metaclass>
187
188This returns the metaclass which is passed into C<new>.
c23184fc 189
d90b42a6 190=item B<attributes>
191
8d2d4c67 192This returns the list of attributes which are associated with the
96e38ba6 193metaclass which is passed into C<new>.
194
d90b42a6 195=item B<meta_instance>
196
8d2d4c67 197This returns the meta instance which is associated with the
96e38ba6 198metaclass which is passed into C<new>.
c23184fc 199
96e38ba6 200=item B<is_inline>
201
8d2d4c67 202This returns a boolean, but since constructors are very rarely
96e38ba6 203not inlined, this always returns true for now.
d90b42a6 204
565f0cbb 205=item B<initialize_body>
d90b42a6 206
8d2d4c67 207This creates the code reference for the constructor itself.
96e38ba6 208
d90b42a6 209=back
210
565f0cbb 211=head2 Method Generators
212
213=over 4
214
215=item B<generate_constructor_method>
216
217=item B<generate_constructor_method_inline>
218
219=back
220
d90b42a6 221=head1 AUTHORS
222
223Stevan Little E<lt>stevan@iinteractive.comE<gt>
224
225=head1 COPYRIGHT AND LICENSE
226
2367814a 227Copyright 2006, 2007 by Infinity Interactive, Inc.
d90b42a6 228
229L<http://www.iinteractive.com>
230
231This library is free software; you can redistribute it and/or modify
8d2d4c67 232it under the same terms as Perl itself.
d90b42a6 233
234=cut
235