2 package Class::MOP::Instance;
7 use Scalar::Util 'weaken', 'blessed';
10 our $AUTHORITY = 'cpan:STEVAN';
12 use base 'Class::MOP::Object';
15 my ($class, @args) = @_;
18 unshift @args, "associated_metaclass";
19 } elsif ( @args >= 2 && blessed($args[0]) && $args[0]->isa("Class::MOP::Class") ) {
21 my ( $meta, @attrs ) = @args;
22 @args = ( associated_metaclass => $meta, attributes => \@attrs );
27 $options{slots} ||= [ map { $_->slots } @{ $options{attributes} || [] } ];
28 $options{slot_hash} = { map { $_ => undef } @{ $options{slots} } }; # FIXME lazy_build
35 my $options = $class->BUILDARGS(@_);
37 # FIXME replace with a proper constructor
38 my $instance = bless {
40 # I am not sure that it makes
41 # sense to pass in the meta
42 # The ideal would be to just
43 # pass in the class name, but
44 # that is placing too much of
45 # an assumption on bless(),
46 # which is *probably* a safe
47 # assumption,.. but you can
49 'associated_metaclass' => $options->{associated_metaclass},
50 'attributes' => $options->{attributes},
51 'slots' => $options->{slots},
52 'slot_hash' => $options->{slot_hash},
55 # FIXME weak_ref => 1,
56 weaken($instance->{'associated_metaclass'});
61 sub _class_name { $_[0]->{_class_name} ||= $_[0]->associated_metaclass->name }
63 sub associated_metaclass { $_[0]{'associated_metaclass'} }
67 $self->bless_instance_structure({});
70 sub bless_instance_structure {
71 my ($self, $instance_structure) = @_;
72 bless $instance_structure, $self->_class_name;
76 my ($self, $instance) = @_;
77 $self->bless_instance_structure({ %$instance });
80 # operations on meta instance
84 return @{$self->{'slots'}};
88 my ($self, $slot_name) = @_;
89 exists $self->{'slot_hash'}->{$slot_name};
92 # operations on created instances
95 my ($self, $instance, $slot_name) = @_;
96 $instance->{$slot_name};
100 my ($self, $instance, $slot_name, $value) = @_;
101 $instance->{$slot_name} = $value;
104 sub initialize_slot {
105 my ($self, $instance, $slot_name) = @_;
109 sub deinitialize_slot {
110 my ( $self, $instance, $slot_name ) = @_;
111 delete $instance->{$slot_name};
114 sub initialize_all_slots {
115 my ($self, $instance) = @_;
116 foreach my $slot_name ($self->get_all_slots) {
117 $self->initialize_slot($instance, $slot_name);
121 sub deinitialize_all_slots {
122 my ($self, $instance) = @_;
123 foreach my $slot_name ($self->get_all_slots) {
124 $self->deinitialize_slot($instance, $slot_name);
128 sub is_slot_initialized {
129 my ($self, $instance, $slot_name, $value) = @_;
130 exists $instance->{$slot_name};
133 sub weaken_slot_value {
134 my ($self, $instance, $slot_name) = @_;
135 weaken $instance->{$slot_name};
138 sub strengthen_slot_value {
139 my ($self, $instance, $slot_name) = @_;
140 $self->set_slot_value($instance, $slot_name, $self->get_slot_value($instance, $slot_name));
143 sub rebless_instance_structure {
144 my ($self, $instance, $metaclass) = @_;
145 bless $instance, $metaclass->name;
148 sub is_dependent_on_superclasses {
149 return; # for meta instances that require updates on inherited slot changes
152 # inlinable operation snippets
154 sub is_inlinable { 1 }
156 sub inline_create_instance {
157 my ($self, $class_variable) = @_;
158 'bless {} => ' . $class_variable;
161 sub inline_slot_access {
162 my ($self, $instance, $slot_name) = @_;
163 sprintf "%s->{%s}", $instance, $slot_name;
166 sub inline_get_slot_value {
167 my ($self, $instance, $slot_name) = @_;
168 $self->inline_slot_access($instance, $slot_name);
171 sub inline_set_slot_value {
172 my ($self, $instance, $slot_name, $value) = @_;
173 $self->inline_slot_access($instance, $slot_name) . " = $value",
176 sub inline_initialize_slot {
177 my ($self, $instance, $slot_name) = @_;
181 sub inline_deinitialize_slot {
182 my ($self, $instance, $slot_name) = @_;
183 "delete " . $self->inline_slot_access($instance, $slot_name);
185 sub inline_is_slot_initialized {
186 my ($self, $instance, $slot_name) = @_;
187 "exists " . $self->inline_slot_access($instance, $slot_name);
190 sub inline_weaken_slot_value {
191 my ($self, $instance, $slot_name) = @_;
192 sprintf "Scalar::Util::weaken( %s )", $self->inline_slot_access($instance, $slot_name);
195 sub inline_strengthen_slot_value {
196 my ($self, $instance, $slot_name) = @_;
197 $self->inline_set_slot_value($instance, $slot_name, $self->inline_slot_access($instance, $slot_name));
208 Class::MOP::Instance - Instance Meta Object
212 The meta instance is used by attributes for low level storage.
214 Using this API generally violates attribute encapsulation and is not
215 recommended, instead look at L<Class::MOP::Attribute/get_value>,
216 L<Class::MOP::Attribute/set_value> for the recommended way to fiddle with
217 attribute values in a generic way, independent of how/whether accessors have
218 been defined. Accessors can be found using L<Class::MOP::Class/get_attribute>.
220 This may seem like over-abstraction, but by abstracting
221 this process into a sub-protocol we make it possible to
222 easily switch the details of how an object's instance is
223 stored with minimal impact. In most cases just subclassing
224 this class will be all you need to do (see the examples;
225 F<examples/ArrayBasedStorage.pod> and
226 F<examples/InsideOutClass.pod> for details).
234 Creates a new instance meta-object and gathers all the slots from
235 the list of C<@attrs> given.
239 Processes arguments for compatibility.
243 Returns the metaclass of L<Class::MOP::Instance>.
247 =head2 Creation of Instances
251 =item B<create_instance>
253 This creates the appropriate structure needed for the instance and
254 then calls C<bless_instance_structure> to bless it into the class.
256 =item B<bless_instance_structure ($instance_structure)>
258 This does just exactly what it says it does.
260 =item B<clone_instance ($instance_structure)>
262 This too does just exactly what it says it does.
268 NOTE: There might be more methods added to this part of the API,
269 we will add then when we need them basically.
273 =item B<associated_metaclass>
275 This returns the metaclass associated with this instance.
277 =item B<get_all_slots>
279 This will return the current list of slots based on what was
280 given to this object in C<new>.
282 =item B<is_valid_slot ($slot_name)>
284 This will return true if C<$slot_name> is a valid slot name.
286 =item B<is_dependent_on_superclasses>
288 This method returns true when the meta instance must be recreated on any
295 =head2 Operations on Instance Structures
297 An important distinction of this sub-protocol is that the
298 instance meta-object is a different entity from the actual
299 instance it creates. For this reason, any actions on slots
300 require that the C<$instance_structure> is passed into them.
302 The names of these methods pretty much explain exactly
303 what they do, if that is not enough then I suggest reading
304 the source, it is very straightfoward.
308 =item B<get_slot_value ($instance_structure, $slot_name)>
310 =item B<set_slot_value ($instance_structure, $slot_name, $value)>
312 =item B<initialize_slot ($instance_structure, $slot_name)>
314 =item B<deinitialize_slot ($instance_structure, $slot_name)>
316 =item B<initialize_all_slots ($instance_structure)>
318 =item B<deinitialize_all_slots ($instance_structure)>
320 =item B<is_slot_initialized ($instance_structure, $slot_name)>
322 =item B<weaken_slot_value ($instance_structure, $slot_name)>
324 =item B<strengthen_slot_value ($instance_structure, $slot_name)>
326 =item B<rebless_instance_structure ($instance_structure, $new_metaclass)>
330 =head2 Inlineable Instance Operations
334 =item B<is_inlinable>
336 Each meta-instance should override this method to tell Class::MOP if it's
337 possible to inline the slot access. This is currently only used by
338 L<Class::MOP::Immutable> when performing optimizations.
340 =item B<inline_create_instance>
342 =item B<inline_slot_access ($instance_structure, $slot_name)>
344 =item B<inline_get_slot_value ($instance_structure, $slot_name)>
346 =item B<inline_set_slot_value ($instance_structure, $slot_name, $value)>
348 =item B<inline_initialize_slot ($instance_structure, $slot_name)>
350 =item B<inline_deinitialize_slot ($instance_structure, $slot_name)>
352 =item B<inline_is_slot_initialized ($instance_structure, $slot_name)>
354 =item B<inline_weaken_slot_value ($instance_structure, $slot_name)>
356 =item B<inline_strengthen_slot_value ($instance_structure, $slot_name)>
362 Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
364 Stevan Little E<lt>stevan@iinteractive.comE<gt>
366 =head1 COPYRIGHT AND LICENSE
368 Copyright 2006-2008 by Infinity Interactive, Inc.
370 L<http://www.iinteractive.com>
372 This library is free software; you can redistribute it and/or modify
373 it under the same terms as Perl itself.