Version 1.12
[gitmo/Class-MOP.git] / lib / Class / MOP / Instance.pm
CommitLineData
24869f62 1
2package Class::MOP::Instance;
3
4use strict;
5use warnings;
6
fa16e528 7use Scalar::Util 'weaken', 'blessed';
24869f62 8
bd2550f8 9our $VERSION = '1.12';
d519662a 10$VERSION = eval $VERSION;
f0480c45 11our $AUTHORITY = 'cpan:STEVAN';
24869f62 12
d7b2249e 13use base 'Class::MOP::Object';
24869f62 14
301d65f2 15# make this not a valid method name, to avoid (most) attribute conflicts
16my $RESERVED_MOP_SLOT = '<<MOP>>';
17
63d08a9e 18sub BUILDARGS {
d43737b3 19 my ($class, @args) = @_;
20
21 if ( @args == 1 ) {
63d08a9e 22 unshift @args, "associated_metaclass";
d43737b3 23 } elsif ( @args >= 2 && blessed($args[0]) && $args[0]->isa("Class::MOP::Class") ) {
24 # compat mode
25 my ( $meta, @attrs ) = @args;
63d08a9e 26 @args = ( associated_metaclass => $meta, attributes => \@attrs );
d43737b3 27 }
28
29 my %options = @args;
7c7fd869 30 # FIXME lazy_build
d43737b3 31 $options{slots} ||= [ map { $_->slots } @{ $options{attributes} || [] } ];
63d08a9e 32 $options{slot_hash} = { map { $_ => undef } @{ $options{slots} } }; # FIXME lazy_build
33
34 return \%options;
35}
36
37sub new {
38 my $class = shift;
39 my $options = $class->BUILDARGS(@_);
d43737b3 40
41 # FIXME replace with a proper constructor
b4b5d65a 42 my $instance = $class->_new(%$options);
43
44 # FIXME weak_ref => 1,
45 weaken($instance->{'associated_metaclass'});
46
47 return $instance;
48}
49
50sub _new {
ec9e38e5 51 my $class = shift;
52 return Class::MOP::Class->initialize($class)->new_object(@_)
53 if $class ne __PACKAGE__;
54
55 my $params = @_ == 1 ? $_[0] : {@_};
56 return bless {
fc3ddd1d 57 # NOTE:
58 # I am not sure that it makes
59 # sense to pass in the meta
8d2d4c67 60 # The ideal would be to just
61 # pass in the class name, but
62 # that is placing too much of
63 # an assumption on bless(),
fc3ddd1d 64 # which is *probably* a safe
8d2d4c67 65 # assumption,.. but you can
fc3ddd1d 66 # never tell <:)
ec9e38e5 67 'associated_metaclass' => $params->{associated_metaclass},
68 'attributes' => $params->{attributes},
69 'slots' => $params->{slots},
70 'slot_hash' => $params->{slot_hash},
8d2d4c67 71 } => $class;
24869f62 72}
73
74890687 74sub _class_name { $_[0]->{_class_name} ||= $_[0]->associated_metaclass->name }
75
76sub associated_metaclass { $_[0]{'associated_metaclass'} }
c23184fc 77
49c93440 78sub create_instance {
79 my $self = shift;
becd03c6 80 bless {}, $self->_class_name;
2d711cc8 81}
82
f7259199 83sub clone_instance {
84 my ($self, $instance) = @_;
becd03c6 85 bless { %$instance }, $self->_class_name;
f7259199 86}
87
2d711cc8 88# operations on meta instance
89
eb49acde 90sub get_all_slots {
91 my $self = shift;
7c7fd869 92 return @{$self->{'slots'}};
f7259199 93}
94
0b5d46da 95sub get_all_attributes {
96 my $self = shift;
97 return @{$self->{attributes}};
98}
99
f7259199 100sub is_valid_slot {
101 my ($self, $slot_name) = @_;
7c7fd869 102 exists $self->{'slot_hash'}->{$slot_name};
839ea973 103}
104
2d711cc8 105# operations on created instances
106
839ea973 107sub get_slot_value {
2bab2be6 108 my ($self, $instance, $slot_name) = @_;
230472a7 109 $instance->{$slot_name};
839ea973 110}
111
2bab2be6 112sub set_slot_value {
113 my ($self, $instance, $slot_name, $value) = @_;
114 $instance->{$slot_name} = $value;
115}
116
2d711cc8 117sub initialize_slot {
49c93440 118 my ($self, $instance, $slot_name) = @_;
a007159d 119 return;
2d711cc8 120}
121
7d28758b 122sub deinitialize_slot {
123 my ( $self, $instance, $slot_name ) = @_;
124 delete $instance->{$slot_name};
125}
126
c174112e 127sub initialize_all_slots {
128 my ($self, $instance) = @_;
129 foreach my $slot_name ($self->get_all_slots) {
130 $self->initialize_slot($instance, $slot_name);
131 }
132}
133
7d28758b 134sub deinitialize_all_slots {
135 my ($self, $instance) = @_;
136 foreach my $slot_name ($self->get_all_slots) {
137 $self->deinitialize_slot($instance, $slot_name);
138 }
139}
140
49c93440 141sub is_slot_initialized {
142 my ($self, $instance, $slot_name, $value) = @_;
230472a7 143 exists $instance->{$slot_name};
2bab2be6 144}
839ea973 145
5582521c 146sub weaken_slot_value {
69e3ab0a 147 my ($self, $instance, $slot_name) = @_;
148 weaken $instance->{$slot_name};
5582521c 149}
150
151sub strengthen_slot_value {
69e3ab0a 152 my ($self, $instance, $slot_name) = @_;
153 $self->set_slot_value($instance, $slot_name, $self->get_slot_value($instance, $slot_name));
5582521c 154}
155
3d9e4646 156sub rebless_instance_structure {
157 my ($self, $instance, $metaclass) = @_;
feb93c85 158
159 # we use $_[1] here because of t/306_rebless_overload.t regressions on 5.8.8
160 bless $_[1], $metaclass->name;
3d9e4646 161}
162
da5680be 163sub is_dependent_on_superclasses {
164 return; # for meta instances that require updates on inherited slot changes
165}
166
301d65f2 167sub _get_mop_slot {
168 my ($self, $instance) = @_;
169 $self->get_slot_value($instance, $RESERVED_MOP_SLOT);
170}
171
172sub _set_mop_slot {
173 my ($self, $instance, $value) = @_;
174 $self->set_slot_value($instance, $RESERVED_MOP_SLOT, $value);
175}
176
177sub _clear_mop_slot {
178 my ($self, $instance) = @_;
179 $self->deinitialize_slot($instance, $RESERVED_MOP_SLOT);
180}
181
ee7c0467 182# inlinable operation snippets
183
c0cbf4d9 184sub is_inlinable { 1 }
185
186sub inline_create_instance {
187 my ($self, $class_variable) = @_;
188 'bless {} => ' . $class_variable;
189}
190
ee7c0467 191sub inline_slot_access {
192 my ($self, $instance, $slot_name) = @_;
5143ee94 193 sprintf q[%s->{"%s"}], $instance, quotemeta($slot_name);
ee7c0467 194}
195
4dcd4272 196sub inline_get_is_lvalue { 1 }
197
ee7c0467 198sub inline_get_slot_value {
199 my ($self, $instance, $slot_name) = @_;
230472a7 200 $self->inline_slot_access($instance, $slot_name);
ee7c0467 201}
202
203sub inline_set_slot_value {
204 my ($self, $instance, $slot_name, $value) = @_;
8d2d4c67 205 $self->inline_slot_access($instance, $slot_name) . " = $value",
ee7c0467 206}
207
208sub inline_initialize_slot {
209 my ($self, $instance, $slot_name) = @_;
a007159d 210 return '';
ee7c0467 211}
212
7d28758b 213sub inline_deinitialize_slot {
214 my ($self, $instance, $slot_name) = @_;
215 "delete " . $self->inline_slot_access($instance, $slot_name);
216}
ee7c0467 217sub inline_is_slot_initialized {
218 my ($self, $instance, $slot_name) = @_;
230472a7 219 "exists " . $self->inline_slot_access($instance, $slot_name);
ee7c0467 220}
221
222sub inline_weaken_slot_value {
223 my ($self, $instance, $slot_name) = @_;
224 sprintf "Scalar::Util::weaken( %s )", $self->inline_slot_access($instance, $slot_name);
225}
226
227sub inline_strengthen_slot_value {
228 my ($self, $instance, $slot_name) = @_;
229 $self->inline_set_slot_value($instance, $slot_name, $self->inline_slot_access($instance, $slot_name));
230}
231
bc3c58a0 232sub inline_rebless_instance_structure {
233 my ($self, $instance, $class_variable) = @_;
234 "bless $instance => $class_variable";
235}
236
7931f7db 237sub _inline_get_mop_slot {
238 my ($self, $instance) = @_;
239 $self->inline_get_slot_value($instance, $RESERVED_MOP_SLOT);
240}
241
242sub _inline_set_mop_slot {
243 my ($self, $instance, $value) = @_;
244 $self->inline_set_slot_value($instance, $RESERVED_MOP_SLOT, $value);
245}
246
247sub _inline_clear_mop_slot {
248 my ($self, $instance) = @_;
249 $self->inline_deinitialize_slot($instance, $RESERVED_MOP_SLOT);
250}
251
24869f62 2521;
253
254__END__
255
256=pod
257
8d2d4c67 258=head1 NAME
24869f62 259
260Class::MOP::Instance - Instance Meta Object
261
24869f62 262=head1 DESCRIPTION
263
1cbf42df 264The Instance Protocol controls the creation of object instances, and
88bb3cf1 265the storage of attribute values in those instances.
266
267Using this API directly in your own code violates encapsulation, and
268we recommend that you use the appropriate APIs in L<Class::MOP::Class>
269and L<Class::MOP::Attribute> instead. Those APIs in turn call the
270methods in this class as appropriate.
271
272This class also participates in generating inlined code by providing
273snippets of code to access an object instance.
9fa4d0b4 274
24869f62 275=head1 METHODS
276
88bb3cf1 277=head2 Object construction
278
24869f62 279=over 4
280
88bb3cf1 281=item B<< Class::MOP::Instance->new(%options) >>
9fa4d0b4 282
88bb3cf1 283This method creates a new meta-instance object.
9fa4d0b4 284
88bb3cf1 285It accepts the following keys in C<%options>:
63d08a9e 286
88bb3cf1 287=over 8
63d08a9e 288
88bb3cf1 289=item * associated_metaclass
9fa4d0b4 290
88bb3cf1 291The L<Class::MOP::Class> object for which instances will be created.
9fa4d0b4 292
88bb3cf1 293=item * attributes
9fa4d0b4 294
88bb3cf1 295An array reference of L<Class::MOP::Attribute> objects. These are the
296attributes which can be stored in each instance.
9fa4d0b4 297
88bb3cf1 298=back
24869f62 299
88bb3cf1 300=back
58287a97 301
88bb3cf1 302=head2 Creating and altering instances
0e76a376 303
88bb3cf1 304=over 4
839ea973 305
88bb3cf1 306=item B<< $metainstance->create_instance >>
0e76a376 307
88bb3cf1 308This method returns a reference blessed into the associated
309metaclass's class.
becd03c6 310
88bb3cf1 311The default is to use a hash reference. Subclasses can override this.
f7259199 312
88bb3cf1 313=item B<< $metainstance->clone_instance($instance) >>
314
315Given an instance, this method creates a new object by making
316I<shallow> clone of the original.
127d39a7 317
9fa4d0b4 318=back
839ea973 319
98bf345b 320=head2 Introspection
58287a97 321
9fa4d0b4 322=over 4
323
88bb3cf1 324=item B<< $metainstance->associated_metaclass >>
c23184fc 325
88bb3cf1 326This returns the L<Class::MOP::Class> object associated with the
327meta-instance object.
127d39a7 328
88bb3cf1 329=item B<< $metainstance->get_all_slots >>
9fa4d0b4 330
88bb3cf1 331This returns a list of slot names stored in object instances. In
332almost all cases, slot names correspond directly attribute names.
58287a97 333
88bb3cf1 334=item B<< $metainstance->is_valid_slot($slot_name) >>
f7259199 335
127d39a7 336This will return true if C<$slot_name> is a valid slot name.
337
88bb3cf1 338=item B<< $metainstance->get_all_attributes >>
da5680be 339
88bb3cf1 340This returns a list of attributes corresponding to the attributes
341passed to the constructor.
0202ee96 342
24869f62 343=back
344
9fa4d0b4 345=head2 Operations on Instance Structures
346
88bb3cf1 347It's important to understand that the meta-instance object is a
348different entity from the actual instances it creates. For this
349reason, any operations on the C<$instance_structure> always require
350that the object instance be passed to the method.
127d39a7 351
24869f62 352=over 4
353
88bb3cf1 354=item B<< $metainstance->get_slot_value($instance_structure, $slot_name) >>
355
356=item B<< $metainstance->set_slot_value($instance_structure, $slot_name, $value) >>
24869f62 357
88bb3cf1 358=item B<< $metainstance->initialize_slot($instance_structure, $slot_name) >>
9fa4d0b4 359
88bb3cf1 360=item B<< $metainstance->deinitialize_slot($instance_structure, $slot_name) >>
9fa4d0b4 361
88bb3cf1 362=item B<< $metainstance->initialize_all_slots($instance_structure) >>
7d28758b 363
88bb3cf1 364=item B<< $metainstance->deinitialize_all_slots($instance_structure) >>
9fa4d0b4 365
88bb3cf1 366=item B<< $metainstance->is_slot_initialized($instance_structure, $slot_name) >>
7d28758b 367
88bb3cf1 368=item B<< $metainstance->weaken_slot_value($instance_structure, $slot_name) >>
24869f62 369
88bb3cf1 370=item B<< $metainstance->strengthen_slot_value($instance_structure, $slot_name) >>
ee7c0467 371
88bb3cf1 372=item B<< $metainstance->rebless_instance_structure($instance_structure, $new_metaclass) >>
ee7c0467 373
88bb3cf1 374The exact details of what each method does should be fairly obvious
375from the method name.
5fdf066d 376
ee7c0467 377=back
378
88bb3cf1 379=head2 Inlinable Instance Operations
ee7c0467 380
381=over 4
382
88bb3cf1 383=item B<< $metainstance->is_inlinable >>
c0cbf4d9 384
88bb3cf1 385This is a boolean that indicates whether or not slot access operations
386can be inlined. By default it is true, but subclasses can override
387this.
c0cbf4d9 388
88bb3cf1 389=item B<< $metainstance->inline_create_instance($class_variable) >>
495af518 390
88bb3cf1 391This method expects a string that, I<when inlined>, will become a
392class name. This would literally be something like C<'$class'>, not an
393actual class name.
ee7c0467 394
88bb3cf1 395It returns a snippet of code that creates a new object for the
396class. This is something like C< bless {}, $class_name >.
ee7c0467 397
4dcd4272 398=item B<< $metainstance->inline_get_is_lvalue >>
399
400Returns whether or not C<inline_get_slot_value> is a valid lvalue. This can be
401used to do extra optimizations when generating inlined methods.
402
88bb3cf1 403=item B<< $metainstance->inline_slot_access($instance_variable, $slot_name) >>
ee7c0467 404
88bb3cf1 405=item B<< $metainstance->inline_get_slot_value($instance_variable, $slot_name) >>
ee7c0467 406
88bb3cf1 407=item B<< $metainstance->inline_set_slot_value($instance_variable, $slot_name, $value) >>
408
409=item B<< $metainstance->inline_initialize_slot($instance_variable, $slot_name) >>
410
411=item B<< $metainstance->inline_deinitialize_slot($instance_variable, $slot_name) >>
412
413=item B<< $metainstance->inline_is_slot_initialized($instance_variable, $slot_name) >>
414
415=item B<< $metainstance->inline_weaken_slot_value($instance_variable, $slot_name) >>
416
417=item B<< $metainstance->inline_strengthen_slot_value($instance_variable, $slot_name) >>
418
419These methods all expect two arguments. The first is the name of a
420variable, than when inlined, will represent the object
421instance. Typically this will be a literal string like C<'$_[0]'>.
422
423The second argument is a slot name.
424
425The method returns a snippet of code that, when inlined, performs some
426operation on the instance.
427
0fab42eb 428=item B<< $metainstance->inline_rebless_instance_structure($instance_variable, $class_variable) >>
429
430This takes the name of a variable that will, when inlined, represent the object
431instance, and the name of a variable that will represent the class to rebless
432into, and returns code to rebless an instance into a class.
433
88bb3cf1 434=back
435
436=head2 Introspection
437
438=over 4
7d28758b 439
88bb3cf1 440=item B<< Class::MOP::Instance->meta >>
5582521c 441
88bb3cf1 442This will return a L<Class::MOP::Class> instance for this class.
5582521c 443
88bb3cf1 444It should also be noted that L<Class::MOP> will actually bootstrap
445this module by installing a number of attribute meta-objects into its
446metaclass.
5582521c 447
24869f62 448=back
449
1a09d9cc 450=head1 AUTHORS
24869f62 451
9fa4d0b4 452Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
453
24869f62 454Stevan Little E<lt>stevan@iinteractive.comE<gt>
455
456=head1 COPYRIGHT AND LICENSE
457
3e2c8600 458Copyright 2006-2010 by Infinity Interactive, Inc.
24869f62 459
460L<http://www.iinteractive.com>
461
462This library is free software; you can redistribute it and/or modify
8d2d4c67 463it under the same terms as Perl itself.
24869f62 464
84ef30d1 465=cut
5582521c 466