Re: chained accessors
[email protected] ("Carl Franks")
| Newsgroups | perl.moose |
|---|---|
| Message-ID | <[email protected]> |
Stevan, On 21/11/06, Stevan Little <[email protected]> wrote: > 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); > } > } That's great. It just needed a tiny tweak. For the record, the working code is: { 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, @_); return $instance; } $attr->get_value($instance); } } } > 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. Thanks, but I'll defer on that for now. I'm only just starting to learn Moose, and I've a long way to go. Cheers, Carl