7 package My::Meta::Instance;
10 # This needs to be in a BEGIN block so to avoid a metaclass
11 # incompatibility error from Moose. In normal usage,
12 # My::Meta::Instance would be in a separate file from MyApp::User,
13 # and this would be a non-issue.
14 BEGIN { extends 'Moose::Meta::Instance' }
21 Moose::Cookbook::Meta::Recipe7 - Creating an array reference meta-instance class
25 package My::Meta::Instance;
27 use List::Util qw( max );
30 extends 'Moose::Meta::Instance';
34 bless [], $self->_class_name;
38 my ( $self, $instance ) = @_;
39 bless [@$instance], $self->_class_name;
43 my ( $self, $instance, $slot_name ) = @_;
44 $instance->[ $self->_index_for_slot_name($slot_name) ];
48 my ( $self, $instance, $slot_name, $value ) = @_;
49 $instance->[ $self->_index_for_slot_name($slot_name) ] = $value;
52 sub deinitialize_slot {
53 my ( $self, $instance, $slot_name ) = @_;
54 delete $instance->[ $self->_index_for_slot_name($slot_name) ];
57 sub is_slot_initialized {
58 my ( $self, $instance, $slot_name, $value ) = @_;
59 exists $instance->[ $self->_index_for_slot_name($slot_name) ];
62 sub weaken_slot_value {
63 my ( $self, $instance, $slot_name ) = @_;
64 weaken $instance->[ $self->_index_for_slot_name($slot_name) ];
67 sub inline_create_instance {
68 my ( $self, $class_variable ) = @_;
69 'bless [] => ' . $class_variable;
72 sub inline_slot_access {
73 my ( $self, $instance, $slot_name ) = @_;
74 $slot_name =~ s/^\'|\'$//g;
75 sprintf "%s->[%s]", $instance, $self->_index_for_slot_name($slot_name);
79 sub _index_for_slot_name {
81 my $slot_name = shift;
83 my $indexes = $Indexes{ $self->associated_metaclass->name } ||= {};
85 return $indexes->{$slot_name}
86 if exists $indexes->{$slot_name};
88 my $max = max values %{$indexes};
90 return $indexes->{$slot_name} = ( $max || 0 ) + 1;
95 use metaclass 'Moose::Meta::Class' =>
96 ( instance_metaclass => 'My::Meta::Instance' );
112 This recipe shows how to build your own meta-instance. The meta
113 instance is the metaclass that creates object instances and helps
114 manages access to attribute slots.
116 In this example, we're creating a meta-instance that is an array
117 reference rather than a hash reference. In theory, this might be a bit
118 faster than using a hash, though in practice the difference may be
119 negligible. Nonetheless, it makes for a simple example here.
121 Our class is a subclass of L<Moose::Meta::Instance>, which creates
122 hash reference based objects. We need to override all the methods
123 which make assumptions about the object's data structure.
125 The first method we override is C<create_instance>:
127 sub create_instance {
129 bless [], $self->_class_name;
132 This returns an array reference which has been blessed into our
133 meta-instance's associated class.
135 We also override C<clone_instance> to create a new array reference:
138 my ( $self, $instance ) = @_;
139 bless [@$instance], $self->_class_name;
142 After that, we have a series of methods which mediate access to the
143 object's slots (attributes are stored in "slots"). In the default
144 instance class, these look up the slot by name. We need to translate
145 the name to a numeric index instead:
148 my ( $self, $instance, $slot_name ) = @_;
149 $instance->[ $self->_index_for_slot_name($slot_name) ];
152 This level of indirection probably makes our instance class I<slower>
153 than the default. However, when attribute access is inlined, this
154 lookup will be cached:
156 sub inline_slot_access {
157 my ( $self, $instance, $slot_name ) = @_;
158 $slot_name =~ s/^\'|\'$//g;
159 sprintf "%s->[%s]", $instance, $self->_index_for_slot_name($slot_name);
162 The code snippet that the C<inline_slot_access> method returns will
163 get C<eval>'d once per attribute.
165 Finally, we use this meta-instance in our C<MyApp::User> class:
167 use metaclass 'Moose::Meta::Class' =>
168 ( instance_metaclass => 'My::Meta::Instance' );
170 We actually don't recommend the use of L<metaclass> in most
171 cases. However, the other ways of using alternate metaclasses are more
172 complex, and would complicate our example code unnecessarily.
176 This recipe shows how to create your own meta-instance class. It's
177 unlikely that you'll need to do this yourself, but it's interesting to
178 take a peek at how Moose works under the hood.
182 There are a few meta-instance class extensions on CPAN:
186 =item * L<MooseX::Singleton>
188 This module extends the instance class in order to ensure that the
189 object is a singleton. The instance it uses is still a blessed hash
192 =item * L<MooseX::GlobRef>
194 This module makes the instance a blessed glob reference. This lets you
195 use a handle as an object instance.
201 Dave Rolsky E<lt>autarch@urth.orgE<gt>
203 =head1 COPYRIGHT AND LICENSE
205 Copyright 2006-2009 by Infinity Interactive, Inc.
207 L<http://www.iinteractive.com>
209 This library is free software; you can redistribute it and/or modify
210 it under the same terms as Perl itself.
216 MyApp::User->meta->make_immutable if $x;
218 my $user = MyApp::User->new( name => 'Faye', email => 'faye@example.com' );
220 ok( eval { @{$user} }, 'user object is an arrayref with some values' );
222 is( $user->name, 'Faye', 'check name' );
223 is( $user->email, 'faye@example.com', 'check email' );
225 $user->name('Ralph');
226 is( $user->name, 'Ralph', 'check name after changing it' );
228 $user->email('ralph@example.com');
229 is( $user->email, 'ralph@example.com', 'check email after changing it' );