NAME
Moose::Cookbook::Meta::Recipe7 - Creating a glob reference meta-instance class
SYNOPSIS
package
My::Meta::Instance;
use
Moose;
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
,
$value
) =
@_
;
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;
(
instance_metaclass
=>
'My::Meta::Instance'
);
use
Moose;
has
'name'
=> (
is
=>
'rw'
,
isa
=>
'Str'
,
);
has
'email'
=> (
is
=>
'rw'
,
isa
=>
'Str'
,
);
DESCRIPTION
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 MooseX::GlobRef module.
Our class is a subclass of Moose::Meta::Instance, 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_create_instance {
my
(
$self
,
$class_variable
) =
@_
;
return
'do { my $sym = Symbol::gensym(); bless $sym, '
.
$class_variable
.
' }'
;
}
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:
(
instance_metaclass
=>
'My::Meta::Instance'
);
We actually don't recommend the use of metaclass in most cases. However, the other ways of using alternate metaclasses are more complex, and would complicate our example code unnecessarily.
CONCLUSION
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.
SEE ALSO
There are a few meta-instance class extensions on CPAN:
-
This module extends the instance class in order to ensure that the object is a singleton. The instance it uses is still a blessed hash reference.
-
This module makes the instance a blessed glob reference. This lets you use a handle as an object instance.
AUTHOR
Dave Rolsky <autarch@urth.org>
COPYRIGHT AND LICENSE
Copyright 2006-2009 by Infinity Interactive, Inc.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.