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