tweaking the attribute initializer stuff a little
[gitmo/Class-MOP.git] / lib / Class / MOP / Instance.pm
1
2 package Class::MOP::Instance;
3
4 use strict;
5 use warnings;
6
7 use Scalar::Util 'weaken', 'blessed';
8
9 our $VERSION   = '0.04';
10 our $AUTHORITY = 'cpan:STEVAN';
11
12 sub meta {
13     require Class::MOP::Class;
14     Class::MOP::Class->initialize(blessed($_[0]) || $_[0]);
15 }
16
17 sub new {
18     my ($class, $meta, @attrs) = @_;
19     my @slots = map { $_->slots } @attrs;
20     my $instance = bless {
21         # NOTE:
22         # I am not sure that it makes
23         # sense to pass in the meta
24         # The ideal would be to just
25         # pass in the class name, but
26         # that is placing too much of
27         # an assumption on bless(),
28         # which is *probably* a safe
29         # assumption,.. but you can
30         # never tell <:)
31         '$!meta'  => $meta,
32         '@!slots' => { map { $_ => undef } @slots },
33     } => $class;
34
35     weaken($instance->{'$!meta'});
36
37     return $instance;
38 }
39
40 sub associated_metaclass { (shift)->{'$!meta'} }
41
42 sub create_instance {
43     my $self = shift;
44     $self->bless_instance_structure({});
45 }
46
47 sub bless_instance_structure {
48     my ($self, $instance_structure) = @_;
49     bless $instance_structure, $self->associated_metaclass->name;
50 }
51
52 sub clone_instance {
53     my ($self, $instance) = @_;
54     $self->bless_instance_structure({ %$instance });
55 }
56
57 # operations on meta instance
58
59 sub get_all_slots {
60     my $self = shift;
61     return keys %{$self->{'@!slots'}};
62 }
63
64 sub is_valid_slot {
65     my ($self, $slot_name) = @_;
66     exists $self->{'@!slots'}->{$slot_name};
67 }
68
69 # operations on created instances
70
71 sub get_slot_value {
72     my ($self, $instance, $slot_name) = @_;
73     $instance->{$slot_name};
74 }
75
76 sub set_slot_value {
77     my ($self, $instance, $slot_name, $value) = @_;
78     $instance->{$slot_name} = $value;
79 }
80
81 sub initialize_slot {
82     my ($self, $instance, $slot_name) = @_;
83     #$self->set_slot_value($instance, $slot_name, undef);
84 }
85
86 sub deinitialize_slot {
87     my ( $self, $instance, $slot_name ) = @_;
88     delete $instance->{$slot_name};
89 }
90
91 sub initialize_all_slots {
92     my ($self, $instance) = @_;
93     foreach my $slot_name ($self->get_all_slots) {
94         $self->initialize_slot($instance, $slot_name);
95     }
96 }
97
98 sub deinitialize_all_slots {
99     my ($self, $instance) = @_;
100     foreach my $slot_name ($self->get_all_slots) {
101         $self->deinitialize_slot($instance, $slot_name);
102     }
103 }
104
105 sub is_slot_initialized {
106     my ($self, $instance, $slot_name, $value) = @_;
107     exists $instance->{$slot_name};
108 }
109
110 sub weaken_slot_value {
111     my ($self, $instance, $slot_name) = @_;
112     weaken $instance->{$slot_name};
113 }
114
115 sub strengthen_slot_value {
116     my ($self, $instance, $slot_name) = @_;
117     $self->set_slot_value($instance, $slot_name, $self->get_slot_value($instance, $slot_name));
118 }
119
120 sub rebless_instance_structure {
121     my ($self, $instance, $metaclass) = @_;
122     bless $instance, $metaclass->name;
123 }
124
125 # inlinable operation snippets
126
127 sub is_inlinable { 1 }
128
129 sub inline_create_instance {
130     my ($self, $class_variable) = @_;
131     'bless {} => ' . $class_variable;
132 }
133
134 sub inline_slot_access {
135     my ($self, $instance, $slot_name) = @_;
136     sprintf "%s->{%s}", $instance, $slot_name;
137 }
138
139 sub inline_get_slot_value {
140     my ($self, $instance, $slot_name) = @_;
141     $self->inline_slot_access($instance, $slot_name);
142 }
143
144 sub inline_set_slot_value {
145     my ($self, $instance, $slot_name, $value) = @_;
146     $self->inline_slot_access($instance, $slot_name) . " = $value",
147 }
148
149 sub inline_initialize_slot {
150     my ($self, $instance, $slot_name) = @_;
151     $self->inline_set_slot_value($instance, $slot_name, 'undef'),
152 }
153
154 sub inline_deinitialize_slot {
155     my ($self, $instance, $slot_name) = @_;
156     "delete " . $self->inline_slot_access($instance, $slot_name);
157 }
158 sub inline_is_slot_initialized {
159     my ($self, $instance, $slot_name) = @_;
160     "exists " . $self->inline_slot_access($instance, $slot_name);
161 }
162
163 sub inline_weaken_slot_value {
164     my ($self, $instance, $slot_name) = @_;
165     sprintf "Scalar::Util::weaken( %s )", $self->inline_slot_access($instance, $slot_name);
166 }
167
168 sub inline_strengthen_slot_value {
169     my ($self, $instance, $slot_name) = @_;
170     $self->inline_set_slot_value($instance, $slot_name, $self->inline_slot_access($instance, $slot_name));
171 }
172
173 1;
174
175 __END__
176
177 =pod
178
179 =head1 NAME
180
181 Class::MOP::Instance - Instance Meta Object
182
183 =head1 SYNOPSIS
184
185     # This API is largely internal
186     # you shouldn't need it unless you are writing meta attributes or meta
187     # instances
188
189 =head1 DESCRIPTION
190
191 The meta instance is used by attributes for low level storage.
192
193 Using this API generally violates attribute encapsulation and is not
194 reccomended, instead look at L<Class::MOP::Attribute/get_value>,
195 L<Class::MOP::Attribute/set_value> for the reccomended way to fiddle with
196 attribute values in a generic way, independant of how/whether accessors have
197 been defined. Accessors can be found using L<Class::MOP::Class/get_attribute>.
198
199 This may seem like over-abstraction, but by abstracting
200 this process into a sub-protocol we make it possible to
201 easily switch the details of how an object's instance is
202 stored with minimal impact. In most cases just subclassing
203 this class will be all you need to do (see the examples;
204 F<examples/ArrayBasedStorage.pod> and
205 F<examples/InsideOutClass.pod> for details).
206
207 =head1 METHODS
208
209 =over 4
210
211 =item B<new ($meta, @attrs)>
212
213 Creates a new instance meta-object and gathers all the slots from
214 the list of C<@attrs> given.
215
216 =item B<meta>
217
218 This will return a B<Class::MOP::Class> instance which is related
219 to this class.
220
221 =back
222
223 =head2 Creation of Instances
224
225 =over 4
226
227 =item B<create_instance>
228
229 This creates the appropriate structure needed for the instance and
230 then calls C<bless_instance_structure> to bless it into the class.
231
232 =item B<bless_instance_structure ($instance_structure)>
233
234 This does just exactly what it says it does.
235
236 =item B<clone_instance ($instance_structure)>
237
238 =back
239
240 =head2 Instrospection
241
242 NOTE: There might be more methods added to this part of the API,
243 we will add then when we need them basically.
244
245 =over 4
246
247 =item B<associated_metaclass>
248
249 =item B<get_all_slots>
250
251 This will return the current list of slots based on what was
252 given to this object in C<new>.
253
254 =item B<is_valid_slot ($slot_name)>
255
256 =back
257
258 =head2 Operations on Instance Structures
259
260 An important distinction of this sub-protocol is that the
261 instance meta-object is a different entity from the actual
262 instance it creates. For this reason, any actions on slots
263 require that the C<$instance_structure> is passed into them.
264
265 =over 4
266
267 =item B<get_slot_value ($instance_structure, $slot_name)>
268
269 =item B<set_slot_value ($instance_structure, $slot_name, $value)>
270
271 =item B<initialize_slot ($instance_structure, $slot_name)>
272
273 =item B<deinitialize_slot ($instance_structure, $slot_name)>
274
275 =item B<initialize_all_slots ($instance_structure)>
276
277 =item B<deinitialize_all_slots ($instance_structure)>
278
279 =item B<is_slot_initialized ($instance_structure, $slot_name)>
280
281 =item B<weaken_slot_value ($instance_structure, $slot_name)>
282
283 =item B<strengthen_slot_value ($instance_structure, $slot_name)>
284
285 =item B<rebless_instance_structure ($instance_structure, $new_metaclass)>
286
287 =back
288
289 =head2 Inlineable Instance Operations
290
291 This part of the API is currently un-used. It is there for use
292 in future experiments in class finailization mostly. Best to
293 ignore this for now.
294
295 =over 4
296
297 =item B<is_inlinable>
298
299 Each meta-instance should override this method to tell Class::MOP if it's
300 possible to inline the slot access.
301
302 This is currently only used by Class::MOP::Class::Immutable when performing
303 optimizations.
304
305 =item B<inline_create_instance>
306
307 =item B<inline_slot_access ($instance_structure, $slot_name)>
308
309 =item B<inline_get_slot_value ($instance_structure, $slot_name)>
310
311 =item B<inline_set_slot_value ($instance_structure, $slot_name, $value)>
312
313 =item B<inline_initialize_slot ($instance_structure, $slot_name)>
314
315 =item B<inline_deinitialize_slot ($instance_structure, $slot_name)>
316
317 =item B<inline_is_slot_initialized ($instance_structure, $slot_name)>
318
319 =item B<inline_weaken_slot_value ($instance_structure, $slot_name)>
320
321 =item B<inline_strengthen_slot_value ($instance_structure, $slot_name)>
322
323 =back
324
325 =head1 AUTHORS
326
327 Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
328
329 Stevan Little E<lt>stevan@iinteractive.comE<gt>
330
331 =head1 COPYRIGHT AND LICENSE
332
333 Copyright 2006-2008 by Infinity Interactive, Inc.
334
335 L<http://www.iinteractive.com>
336
337 This library is free software; you can redistribute it and/or modify
338 it under the same terms as Perl itself.
339
340 =cut
341