Re: chained accessors
[email protected] (Stevan Little)
| Newsgroups | perl.moose |
|---|---|
| Message-ID | <[email protected]> |
Carl,
On Nov 21, 2006, at 4:27 AM, Carl Franks wrote:
> Can anyone give me any pointers to how I might create "chained"
> accessors which return $self when called as a setter.
> If I do:
> has( foo => ( is => 'rw' ) );
> I've found using the debugger, that $x->foo('y') calls
> Moose::Meta::Method::Accessor::generate_accessor_method()
> But I can't figure out how to wrap that (and whether that's the
> right approach).
Wrapping is not the right approach, subclassing is. This is pretty
much what you will need to do (this code is untested though).
package Foo::Chained::Attribute;
use Moose;
extends 'Moose::Meta::Attribute';
sub accessor_metaclass { 'Foo::Meta::Method::Accessor::Chained' }
package Foo::Meta::Method::Accessor::Chained;
use Moose;
extends 'Moose::Meta::Method::Accessor';
sub generate_writer_method {
my $self = shift;
my $attr = $self->associated_attribute;
return sub {
my ($instance, $value) = @_;
$attr->set_value($instance, $value);
$instance;
}
}
sub generate_accessor_method {
my $self = shift;
my $attr = $self->associated_attribute;
return sub {
my $instance = shift;
if (@_) {
$attr->set_value($instance, $value);
$instance;
}
$attr->get_value($instance, $value);
}
}
Then at this point, you should be able to do this:
> package Foo;
> use Moose;
> has 'foo' => (is => 'rw', 'metaclass' => 'Foo::Chained::Attribute');
The only issue here is going to be performance. The set_value and
get_value methods on the attribute metaclass are not very fast (they
do too much runtime calculation), and normally we inline and eval the
accessor methods. However the inlining code is not currently suited
to wrapping/altering in this way. If you are so inclined, I would be
happy to give you a commit-bit and you can refactor the inlining code
to your needs.
- Stevan