IT WORKS NOWrun_testsrun_testsrun_testsrun_tests
[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.03';
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} ? 1 : 0;
67 }
68
69 # operations on created instances
70
71 sub get_slot_value {
72     my ($self, $instance, $slot_name) = @_;
73     return $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} ? 1 : 0;
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 # inlinable operation snippets
121
122 sub is_inlinable { 1 }
123
124 sub inline_create_instance {
125     my ($self, $class_variable) = @_;
126     'bless {} => ' . $class_variable;
127 }
128
129 sub inline_slot_access {
130     my ($self, $instance, $slot_name) = @_;
131     sprintf "%s->{%s}", $instance, $slot_name;
132 }
133
134 sub inline_get_slot_value {
135     my ($self, $instance, $slot_name) = @_;
136     $self->inline_slot_access($instance, $slot_name);
137 }
138
139 sub inline_set_slot_value {
140     my ($self, $instance, $slot_name, $value) = @_;
141     $self->inline_slot_access($instance, $slot_name) . " = $value", 
142 }
143
144 sub inline_initialize_slot {
145     my ($self, $instance, $slot_name) = @_;
146     $self->inline_set_slot_value($instance, $slot_name, 'undef'),
147 }
148
149 sub inline_deinitialize_slot {
150     my ($self, $instance, $slot_name) = @_;
151     "delete " . $self->inline_slot_access($instance, $slot_name);
152 }
153 sub inline_is_slot_initialized {
154     my ($self, $instance, $slot_name) = @_;
155     "exists " . $self->inline_slot_access($instance, $slot_name) . " ? 1 : 0";
156 }
157
158 sub inline_weaken_slot_value {
159     my ($self, $instance, $slot_name) = @_;
160     sprintf "Scalar::Util::weaken( %s )", $self->inline_slot_access($instance, $slot_name);
161 }
162
163 sub inline_strengthen_slot_value {
164     my ($self, $instance, $slot_name) = @_;
165     $self->inline_set_slot_value($instance, $slot_name, $self->inline_slot_access($instance, $slot_name));
166 }
167
168 1;
169
170 __END__
171
172 =pod
173
174 =head1 NAME 
175
176 Class::MOP::Instance - Instance Meta Object
177
178 =head1 SYNOPSIS
179
180   # for the most part, this protocol is internal 
181   # and not for public usage, but this how one 
182   # might use it
183   
184   package Foo;
185   
186   use strict;
187   use warnings;
188   use metaclass (
189       ':instance_metaclass'  => 'ArrayBasedStorage::Instance',
190   );
191   
192   # now Foo->new produces blessed ARRAY ref based objects
193
194 =head1 DESCRIPTION
195
196 This is a sub-protocol which governs instance creation 
197 and access to the slots of the instance structure.
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 =back
286
287 =head2 Inlineable Instance Operations
288
289 This part of the API is currently un-used. It is there for use 
290 in future experiments in class finailization mostly. Best to 
291 ignore this for now.
292
293 =over 4
294
295 =item B<is_inlinable>
296
297 Each meta-instance should override this method to tell Class::MOP if it's 
298 possible to inline the slot access. 
299
300 This is currently only used by Class::MOP::Class::Immutable when performing 
301 optimizations.
302
303 =item B<inline_create_instance>
304
305 =item B<inline_slot_access ($instance_structure, $slot_name)>
306
307 =item B<inline_get_slot_value ($instance_structure, $slot_name)>
308
309 =item B<inline_set_slot_value ($instance_structure, $slot_name, $value)>
310
311 =item B<inline_initialize_slot ($instance_structure, $slot_name)>
312
313 =item B<inline_deinitialize_slot ($instance_structure, $slot_name)>
314
315 =item B<inline_is_slot_initialized ($instance_structure, $slot_name)>
316
317 =item B<inline_weaken_slot_value ($instance_structure, $slot_name)>
318
319 =item B<inline_strengthen_slot_value ($instance_structure, $slot_name)>
320
321 =back
322
323 =head1 AUTHORS
324
325 Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
326
327 Stevan Little E<lt>stevan@iinteractive.comE<gt>
328
329 =head1 COPYRIGHT AND LICENSE
330
331 Copyright 2006 by Infinity Interactive, Inc.
332
333 L<http://www.iinteractive.com>
334
335 This library is free software; you can redistribute it and/or modify
336 it under the same terms as Perl itself. 
337
338 =cut
339