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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.