2 package Class::MOP::Instance;
7 use Scalar::Util 'weaken', 'blessed';
10 $VERSION = eval $VERSION;
11 our $AUTHORITY = 'cpan:STEVAN';
13 use base 'Class::MOP::Object';
16 my ($class, @args) = @_;
19 unshift @args, "associated_metaclass";
20 } elsif ( @args >= 2 && blessed($args[0]) && $args[0]->isa("Class::MOP::Class") ) {
22 my ( $meta, @attrs ) = @args;
23 @args = ( associated_metaclass => $meta, attributes => \@attrs );
28 $options{slots} ||= [ map { $_->slots } @{ $options{attributes} || [] } ];
29 $options{slot_hash} = { map { $_ => undef } @{ $options{slots} } }; # FIXME lazy_build
36 my $options = $class->BUILDARGS(@_);
38 # FIXME replace with a proper constructor
39 my $instance = $class->_new(%$options);
41 # FIXME weak_ref => 1,
42 weaken($instance->{'associated_metaclass'});
49 return Class::MOP::Class->initialize($class)->new_object(@_)
50 if $class ne __PACKAGE__;
52 my $params = @_ == 1 ? $_[0] : {@_};
55 # I am not sure that it makes
56 # sense to pass in the meta
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(),
61 # which is *probably* a safe
62 # assumption,.. but you can
64 'associated_metaclass' => $params->{associated_metaclass},
65 'attributes' => $params->{attributes},
66 'slots' => $params->{slots},
67 'slot_hash' => $params->{slot_hash},
71 sub _class_name { $_[0]->{_class_name} ||= $_[0]->associated_metaclass->name }
75 bless {}, $self->_class_name;
79 my ($self, $instance) = @_;
80 bless { %$instance }, $self->_class_name;
83 # operations on meta instance
87 return @{$self->{'slots'}};
90 sub get_all_attributes {
92 return @{$self->{attributes}};
96 my ($self, $slot_name) = @_;
97 exists $self->{'slot_hash'}->{$slot_name};
100 # operations on created instances
103 my ($self, $instance, $slot_name) = @_;
104 $instance->{$slot_name};
108 my ($self, $instance, $slot_name, $value) = @_;
109 $instance->{$slot_name} = $value;
112 sub initialize_slot {
113 my ($self, $instance, $slot_name) = @_;
117 sub deinitialize_slot {
118 my ( $self, $instance, $slot_name ) = @_;
119 delete $instance->{$slot_name};
122 sub initialize_all_slots {
123 my ($self, $instance) = @_;
124 foreach my $slot_name ($self->get_all_slots) {
125 $self->initialize_slot($instance, $slot_name);
129 sub deinitialize_all_slots {
130 my ($self, $instance) = @_;
131 foreach my $slot_name ($self->get_all_slots) {
132 $self->deinitialize_slot($instance, $slot_name);
136 sub is_slot_initialized {
137 my ($self, $instance, $slot_name, $value) = @_;
138 exists $instance->{$slot_name};
141 sub weaken_slot_value {
142 my ($self, $instance, $slot_name) = @_;
143 weaken $instance->{$slot_name};
146 sub strengthen_slot_value {
147 my ($self, $instance, $slot_name) = @_;
148 $self->set_slot_value($instance, $slot_name, $self->get_slot_value($instance, $slot_name));
151 sub rebless_instance_structure {
152 my ($self, $instance, $metaclass) = @_;
154 # we use $_[1] here because of t/306_rebless_overload.t regressions on 5.8.8
155 bless $_[1], $metaclass->name;
158 sub is_dependent_on_superclasses {
159 return; # for meta instances that require updates on inherited slot changes
162 # inlinable operation snippets
164 sub is_inlinable { 1 }
166 sub inline_create_instance {
167 my ($self, $class_variable) = @_;
168 'bless {} => ' . $class_variable;
171 sub inline_slot_access {
172 my ($self, $instance, $slot_name) = @_;
173 sprintf q[%s->{"%s"}], $instance, quotemeta($slot_name);
176 sub inline_get_slot_value {
177 my ($self, $instance, $slot_name) = @_;
178 $self->inline_slot_access($instance, $slot_name);
181 sub inline_set_slot_value {
182 my ($self, $instance, $slot_name, $value) = @_;
183 $self->inline_slot_access($instance, $slot_name) . " = $value",
186 sub inline_initialize_slot {
187 my ($self, $instance, $slot_name) = @_;
191 sub inline_deinitialize_slot {
192 my ($self, $instance, $slot_name) = @_;
193 "delete " . $self->inline_slot_access($instance, $slot_name);
195 sub inline_is_slot_initialized {
196 my ($self, $instance, $slot_name) = @_;
197 "exists " . $self->inline_slot_access($instance, $slot_name);
200 sub inline_weaken_slot_value {
201 my ($self, $instance, $slot_name) = @_;
202 sprintf "Scalar::Util::weaken( %s )", $self->inline_slot_access($instance, $slot_name);
205 sub 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));
210 sub inline_rebless_instance_structure {
211 my ($self, $instance, $class_variable) = @_;
212 "bless $instance => $class_variable";
223 Class::MOP::Instance - Instance Meta Object
227 The Instance Protocol controls the creation of object instances, and
228 the storage of attribute values in those instances.
230 Using this API directly in your own code violates encapsulation, and
231 we recommend that you use the appropriate APIs in L<Class::MOP::Class>
232 and L<Class::MOP::Attribute> instead. Those APIs in turn call the
233 methods in this class as appropriate.
235 This class also participates in generating inlined code by providing
236 snippets of code to access an object instance.
240 =head2 Object construction
244 =item B<< Class::MOP::Instance->new(%options) >>
246 This method creates a new meta-instance object.
248 It accepts the following keys in C<%options>:
252 =item * associated_metaclass
254 The L<Class::MOP::Class> object for which instances will be created.
258 An array reference of L<Class::MOP::Attribute> objects. These are the
259 attributes which can be stored in each instance.
265 =head2 Creating and altering instances
269 =item B<< $metainstance->create_instance >>
271 This method returns a reference blessed into the associated
274 The default is to use a hash reference. Subclasses can override this.
276 =item B<< $metainstance->clone_instance($instance) >>
278 Given an instance, this method creates a new object by making
279 I<shallow> clone of the original.
287 =item B<< $metainstance->associated_metaclass >>
289 This returns the L<Class::MOP::Class> object associated with the
290 meta-instance object.
292 =item B<< $metainstance->get_all_slots >>
294 This returns a list of slot names stored in object instances. In
295 almost all cases, slot names correspond directly attribute names.
297 =item B<< $metainstance->is_valid_slot($slot_name) >>
299 This will return true if C<$slot_name> is a valid slot name.
301 =item B<< $metainstance->get_all_attributes >>
303 This returns a list of attributes corresponding to the attributes
304 passed to the constructor.
308 =head2 Operations on Instance Structures
310 It's important to understand that the meta-instance object is a
311 different entity from the actual instances it creates. For this
312 reason, any operations on the C<$instance_structure> always require
313 that the object instance be passed to the method.
317 =item B<< $metainstance->get_slot_value($instance_structure, $slot_name) >>
319 =item B<< $metainstance->set_slot_value($instance_structure, $slot_name, $value) >>
321 =item B<< $metainstance->initialize_slot($instance_structure, $slot_name) >>
323 =item B<< $metainstance->deinitialize_slot($instance_structure, $slot_name) >>
325 =item B<< $metainstance->initialize_all_slots($instance_structure) >>
327 =item B<< $metainstance->deinitialize_all_slots($instance_structure) >>
329 =item B<< $metainstance->is_slot_initialized($instance_structure, $slot_name) >>
331 =item B<< $metainstance->weaken_slot_value($instance_structure, $slot_name) >>
333 =item B<< $metainstance->strengthen_slot_value($instance_structure, $slot_name) >>
335 =item B<< $metainstance->rebless_instance_structure($instance_structure, $new_metaclass) >>
337 The exact details of what each method does should be fairly obvious
338 from the method name.
342 =head2 Inlinable Instance Operations
346 =item B<< $metainstance->is_inlinable >>
348 This is a boolean that indicates whether or not slot access operations
349 can be inlined. By default it is true, but subclasses can override
352 =item B<< $metainstance->inline_create_instance($class_variable) >>
354 This method expects a string that, I<when inlined>, will become a
355 class name. This would literally be something like C<'$class'>, not an
358 It returns a snippet of code that creates a new object for the
359 class. This is something like C< bless {}, $class_name >.
361 =item B<< $metainstance->inline_slot_access($instance_variable, $slot_name) >>
363 =item B<< $metainstance->inline_get_slot_value($instance_variable, $slot_name) >>
365 =item B<< $metainstance->inline_set_slot_value($instance_variable, $slot_name, $value) >>
367 =item B<< $metainstance->inline_initialize_slot($instance_variable, $slot_name) >>
369 =item B<< $metainstance->inline_deinitialize_slot($instance_variable, $slot_name) >>
371 =item B<< $metainstance->inline_is_slot_initialized($instance_variable, $slot_name) >>
373 =item B<< $metainstance->inline_weaken_slot_value($instance_variable, $slot_name) >>
375 =item B<< $metainstance->inline_strengthen_slot_value($instance_variable, $slot_name) >>
377 These methods all expect two arguments. The first is the name of a
378 variable, than when inlined, will represent the object
379 instance. Typically this will be a literal string like C<'$_[0]'>.
381 The second argument is a slot name.
383 The method returns a snippet of code that, when inlined, performs some
384 operation on the instance.
386 =item B<< $metainstance->inline_rebless_instance_structure($instance_variable, $class_variable) >>
388 This takes the name of a variable that will, when inlined, represent the object
389 instance, and the name of a variable that will represent the class to rebless
390 into, and returns code to rebless an instance into a class.
394 =head2 XS Instance Operations
398 =item B<< $metainstance->can_xs() >>
400 This is an integer that indicates the address of XS virtual table for slot accesses.
401 By default it returns a virtual table address to operate hash references, but subclasses
402 should override this.
410 =item B<< Class::MOP::Instance->meta >>
412 This will return a L<Class::MOP::Class> instance for this class.
414 It should also be noted that L<Class::MOP> will actually bootstrap
415 this module by installing a number of attribute meta-objects into its
422 Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
424 Stevan Little E<lt>stevan@iinteractive.comE<gt>
426 =head1 COPYRIGHT AND LICENSE
428 Copyright 2006-2009 by Infinity Interactive, Inc.
430 L<http://www.iinteractive.com>
432 This library is free software; you can redistribute it and/or modify
433 it under the same terms as Perl itself.