Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

custom accessor_metaclass override of _inline_store (Moose 1 to 2)

5 views
Skip to first unread message

Toby Blake

unread,
Mar 15, 2016, 12:15:02 PM3/15/16
to mo...@perl.org
Hello,

I'm trying to convert an existing project to Moose 2 (from Moose 1.15).
I've run into a tricky issue where the original author of the project (not
me!) has overridden part of Moose's private API - this part has now
changed. I'll try and explain the situation briefly, in the hope that
somebody can advise:

We have an attribute trait which uses a custom accessor_metaclass.

This accessor metaclass extends 'Moose::Meta::Method::Accessor' and
overrides _inline_store, like this:

override _inline_store => sub {
my ($self, $instance, $value) = @_;
my $attr = $self->associated_attribute;
if ($attr->has_logger) {
return sprintf('$attr->logger->($attr, %s, %s);', $instance, $value) . super;
}
return super;
};

So, essentially, it puts a call to the attribute trait's $attr->logger
subroutine in the chain when setting a value (this is needed because we
have code here which needs to know when an object's attribute values have
changed - this is the function of the "logger"). And of course this code
doesn't work with Moose 2, as there is no longer an _inline_store method in
Moose::Meta::Method::Accessor.

The lesson here is that we shouldn't be using parts of the private api, as
they may change. However, I would like to get this working without
rewriting large chunks of it. I naively tried changing _inline_store to
_inline_store_value for Moose 2, but this doesn't appear to be called in
the same way.

I'd be grateful for any advice on how I can get this code working again,
without substantial changes.

Thanks
Toby Blake
School of Informatics
University of Edinburgh


--
The University of Edinburgh is a charitable body, registered in
Scotland, with registration number SC005336.

Dave Rolsky

unread,
Mar 15, 2016, 12:30:02 PM3/15/16
to Toby Blake, mo...@perl.org
I think you can override Moose::Meta::Attribute->_inline_instance_set.
This will work for any attribute that doesn't have an initializer (but no
one uses that Moose feature).


Cheers,

-dave

/*============================================================
http://VegGuide.org http://blog.urth.org
Your guide to all that's veg House Absolute(ly Pointless)
============================================================*/

Toby Blake

unread,
Mar 15, 2016, 12:30:02 PM3/15/16
to Dave Rolsky, mo...@perl.org
[...]
On 15 Mar 2016, at 16:13, Dave Rolsky <aut...@urth.org> wrote:
>
> I think you can override Moose::Meta::Attribute->_inline_instance_set. This will work for any attribute that doesn't have an initializer (but no one uses that Moose feature).

Thanks for the quick reply, Dave. I'll give it a try...

Cheers
Toby

Toby Blake

unread,
Mar 22, 2016, 9:00:02 AM3/22/16
to mo...@perl.org
> On 15 Mar 2016, at 16:13, Dave Rolsky <aut...@urth.org> wrote:
>
> On Tue, 15 Mar 2016, Toby Blake wrote:

[...]

>> override _inline_store => sub {
>> my ($self, $instance, $value) = @_;
>> my $attr = $self->associated_attribute;
>> if ($attr->has_logger) {
>> return sprintf('$attr->logger->($attr, %s, %s);', $instance, $value) . super;
>> }
>> return super;
>> };
>>
>> So, essentially, it puts a call to the attribute trait's $attr->logger
>> subroutine in the chain when setting a value (this is needed because we
>> have code here which needs to know when an object's attribute values have
>> changed - this is the function of the "logger"). And of course this code
>> doesn't work with Moose 2, as there is no longer an _inline_store method in
>> Moose::Meta::Method::Accessor.

[...]

> I think you can override Moose::Meta::Attribute->_inline_instance_set. This will work for any attribute that doesn't have an initializer (but no one uses that Moose feature).

I wasn't able to get this working using
Moose::Meta::Attribute->_inline_instance_set, and the more time I spent
grubbing about in Moose and Class::MOP's internals the more I became convinced
that it was the wrong way to do it.

I _think_ I can achieve what I want by using trigger methods (it seems that
when the project was originally written, triggers didn't have access to the
old value, which I'm presuming is why the original author went with the
approach he did). However, this leads to the following question...

All these attributes to which I want to apply this trigger share the same
trait, so there's a logical association between the two. Is there a way I
can utilise this, so I don't have to define 'trigger => ....' for every
attribute which uses this trait, i.e. have a trigger built into an
attribute trait, if that makes sense?

Cheers
Toby

Toby Blake

unread,
Mar 23, 2016, 7:45:02 AM3/23/16
to Buddy Burden, mo...@perl.org
> On 23 Mar 2016, at 10:46, Buddy Burden <barefo...@gmail.com> wrote:
>
> Toby,
>
>> All these attributes to which I want to apply this trigger share the same
>> trait, so there's a logical association between the two. Is there a way I
>> can utilise this, so I don't have to define 'trigger => ....' for every
>> attribute which uses this trait, i.e. have a trigger built into an
>> attribute trait, if that makes sense?
>
> Well, I once put together an attribute trait that creates default subs (the discussion of which took place on this very list[1]), so I don't see any reason you couldn't do the same with triggers. Of course, then the trick is, is adding a trait to every attribute any better than adding a trigger to every attribute? Perhaps you could get around that by doing something to the metaclass, or perhaps your attributes _already_ all have a trait that you can piggyback on (I wasn't quite clear on that part).
>
> Anyway, I hope that discussion has something useful in it, particularly what I ended up with for my final solution.[2] I've used that pattern a few times over the past few years.

Thanks Buddy, I'll take a look a proper read-through of the thread and see
what I can do. It certainly sounds useful.

As to your question, yes the attributes in question already consume the
trait(s) I want to expand.
0 new messages