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