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