Moose::Cookbook::Meta::GlobRef_InstanceMetaclass - Creating a glob reference meta-instance class |
Moose::Cookbook::Meta::GlobRef_InstanceMetaclass - Creating a glob reference meta-instance class
version 2.1605
package My::Meta::Instance;
use Scalar::Util qw( weaken ); use Symbol qw( gensym );
use Moose::Role;
sub create_instance { my $self = shift; my $sym = gensym(); bless $sym, $self->_class_name; }
sub clone_instance { my ( $self, $instance ) = @_;
my $new_sym = gensym(); %{*$new_sym} = %{*$instance};
bless $new_sym, $self->_class_name; }
sub get_slot_value { my ( $self, $instance, $slot_name ) = @_; return *$instance->{$slot_name}; }
sub set_slot_value { my ( $self, $instance, $slot_name, $value ) = @_; *$instance->{$slot_name} = $value; }
sub deinitialize_slot { my ( $self, $instance, $slot_name ) = @_; delete *$instance->{$slot_name}; }
sub is_slot_initialized { my ( $self, $instance, $slot_name ) = @_; exists *$instance->{$slot_name}; }
sub weaken_slot_value { my ( $self, $instance, $slot_name ) = @_; weaken *$instance->{$slot_name}; }
sub inline_create_instance { my ( $self, $class_variable ) = @_; return 'do { my $sym = Symbol::gensym(); bless $sym, ' . $class_variable . ' }'; }
sub inline_slot_access { my ( $self, $instance, $slot_name ) = @_; return '*{' . $instance . '}->{' . $slot_name . '}'; }
package MyApp::User;
use Moose; Moose::Util::MetaRole::apply_metaroles( for => __PACKAGE__, class_metaroles => { instance => ['My::Meta::Instance'], }, );
has 'name' => ( is => 'rw', isa => 'Str', );
has 'email' => ( is => 'rw', isa => 'Str', );
This recipe shows how to build your own meta-instance. The meta instance is the metaclass that creates object instances and helps manages access to attribute slots.
In this example, we're creating a meta-instance that is based on a glob reference rather than a hash reference. This example is largely based on the Piotr Roszatycki's the MooseX::GlobRef manpage module.
Our extension is a role which will be applied to the Moose::Meta::Instance manpage, which creates hash reference based objects. We need to override all the methods which make assumptions about the object's data structure.
The first method we override is create_instance
:
sub create_instance { my $self = shift; my $sym = gensym(); bless $sym, $self->_class_name; }
This returns an glob reference which has been blessed into our meta-instance's associated class.
We also override clone_instance
to create a new array reference:
sub clone_instance { my ( $self, $instance ) = @_;
my $new_sym = gensym(); %{*$new_sym} = %{*$instance};
bless $new_sym, $self->_class_name; }
After that, we have a series of methods which mediate access to the object's slots (attributes are stored in ``slots''). In the default instance class, these expect the object to be a hash reference, but we need to change this to expect a glob reference instead.
sub get_slot_value { my ( $self, $instance, $slot_name ) = @_; *$instance->{$slot_name}; }
This level of indirection probably makes our instance class slower than the default. However, when attribute access is inlined, this lookup will be cached:
sub inline_slot_access { my ( $self, $instance, $slot_name ) = @_; return '*{' . $instance . '}->{' . $slot_name . '}'; }
The code snippet that the inline_slot_access
method returns will
get eval
'd once per attribute.
Finally, we use this meta-instance in our MyApp::User
class:
Moose::Util::MetaRole::apply_metaroles( for => __PACKAGE__, class_metaroles => { instance => ['My::Meta::Instance'], }, );
We actually don't recommend the use of the Moose::Util::MetaRole manpage directly in your class in most cases. Typically, this would be provided by a the Moose::Exporter manpage-based module which handles applying the role for you.
This recipe shows how to create your own meta-instance class. It's unlikely that you'll need to do this yourself, but it's interesting to take a peek at how Moose works under the hood.
There are a few meta-instance class extensions on CPAN:
This software is copyright (c) 2006 by Infinity Interactive, Inc.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
Moose::Cookbook::Meta::GlobRef_InstanceMetaclass - Creating a glob reference meta-instance class |