Mailing List Archive

Plugin attributes and Moose
I wanted to note something (before the week gets started and time vanishes)
about how Catalyst is behaving, and see if it's expected.

I asked about this on the Moose list, so sorry if you already saw this.

A Catalyst app extends Catalyst::Component, which has a BUILDARGS sub to
merge in class configuration when creating instances of components.

This is how configuration can set initial values on attributes in Models,
Views, Controllers, and the application class itself.

If a (non-role) Moose-based plugin is loaded (which is common) it's added
to the app's inheritance like this:

$meta->superclasses($plugin, $meta->superclasses);


Which can be thought of like this:

@App::ISA = ( qw/ Catalyst::Plugin::Foo Catalyst / );


The result then is that BUILDARGS in Catalyst::Component is no longer
called, and then attributes in the App class are no longer populated from
the config.

So, the behavior changes depending on what plugins are brought in.


Another odd issue I came against is that MooseX::Emulate::Class::Accessor::Fast
causes odd behavior of Moose attributes. This role is widely used in
Catalyst.

In the code below note how the "foo" attribute has init_arg => undef to
prevent it from being initialized. With the the role not only is it
initialized, but with a value that isn't an "Int".


package Foo;
use Moose;

with 'MooseX::Emulate::Class::Accessor::Fast';

has foo => (
is => 'ro',
isa => 'Int', # for error
init_arg => undef,
);


package main;
use strict;
use warnings;

my $foo = Foo->new( { foo => 'bar' } );

use Data::Dumper;
print Dumper $foo->foo;


Generates 'bar', which is not an Int.

$VAR1 = 'bar';


Comment out "with 'MooseX::Emulate::Class::Accessor::Fast';" and it behaves
as expected. Also comment out "init_arg" and Moose will complain about
the string not begin an Int.


--
Bill Moseley
moseley@hank.org
Re: Plugin attributes and Moose [ In reply to ]
I'm not sure how to solve your problem, explanation wise, however I might wonder if we can find a way to use a role, either Moose or Moo, instead of a class for your plugin. I find its a more sane implementation. I know a lot of legacy stuff from pre Catamoose doesn't do that but I can't think of a good reason why we'd not wish for them to all be converted. Basically what I think of a plugin in Catalyst is just a role but we didn't have roles at the time Catalyst was first done so we were stuck rolling our own. There's a few other weird things like how plugins are applied at setup_plugin time rather than earlier (which again I personally find to be a real pain in the butt but maybe there's some actually good use for it, just I don't see it.)


Even the role interface is probably too much since its applied on top of the application (and then automatically on the context). Its a big hammer. Then number one thing that always stopped me from bigger Catalyst refactoring is that I have not idea what people did to Catalyst internals with plugins... Its hard to figure out what you are breaking, which is why I tended to encourage people to try and use other things when they could like custom models, middleware, etc. But you still need them from time to time I guess. If all you want is some application scoped attributes you could do that with a application model, for example. I personally consider 'MooseX::Emulate::Class::Accessor::Fast' something that was written as an expedient way to get get CataMoose off the ground. I definitely would not use it in my code, particularly if I could use Moose or Moo anyway. I wasn't around for most of CataMoose so I don't know the reasons why a lot of stuff was done in certain ways, but those shims I'd not use for new stuff. I always assumed it was 'until someone has time to fix this right' but then no body bothered.

Sorry this probably didn't help. snap


On Sunday, November 22, 2015 3:03 PM, Bill Moseley <moseley@hank.org> wrote:



I wanted to note something (before the week gets started and time vanishes) about how Catalyst is behaving, and see if it's expected.

I asked about this on the Moose list, so sorry if you already saw this.

A Catalyst app extends Catalyst::Component, which has a BUILDARGS sub to merge in class configuration when creating instances of components.

This is how configuration can set initial values on attributes in Models, Views, Controllers, and the application class itself.

If a (non-role) Moose-based plugin is loaded (which is common) it's added to the app's inheritance like this:

$meta->superclasses($plugin, $meta->superclasses);

Which can be thought of like this:

@App::ISA = ( qw/ Catalyst::Plugin::Foo Catalyst / );

The result then is that BUILDARGS in Catalyst::Component is no longer called, and then attributes in the App class are no longer populated from the config.

So, the behavior changes depending on what plugins are brought in.

Another odd issue I came against is that MooseX::Emulate::Class::Accessor::Fast causes odd behavior of Moose attributes. This role is widely used in Catalyst.

In the code below note how the "foo" attribute has init_arg => undef to prevent it from being initialized. With the the role not only is it initialized, but with a value that isn't an "Int".



package Foo;
>use Moose;
>
>
>with 'MooseX::Emulate::Class::Accessor::Fast';
>
>has foo => (
> is => 'ro',
> isa => 'Int', # for error
> init_arg => undef,
>);
>
>
>
>package main;
>use strict;
>use warnings;
>
>
>my $foo = Foo->new( { foo => 'bar' } );
>
>
>use Data::Dumper;
>print Dumper $foo->foo;


Generates 'bar', which is not an Int.

$VAR1 = 'bar';


Comment out "with 'MooseX::Emulate::Class::Accessor::Fast';" and it behaves as expected. Also comment out "init_arg" and Moose will complain about the string not begin an Int.

--

Bill Moseley
moseley@hank.org
_______________________________________________
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/

_______________________________________________
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/
Re: Plugin attributes and Moose [ In reply to ]
To speak to the issue with MooseX::Emulate::Class::Accessor::Fast I don't think this is supposed to mix and match with Moose 'has' style attributes as in your example, see the docs:

https://metacpan.org/pod/MooseX::Emulate::Class::Accessor::Fast

Basically this is meant to be the fast easy way to move an old CA based class to Moose. If you are going to define attributes via 'has' then I'd just say you should stop using it. You see this used in a bunch of older plugins to 'moosify' them. But IMHO those should be really Moose or Moo top to bottom. Just again no volunteers to do it and it mostly just works anyway.

Again, I would say if you are writing new code to just not use any of those compatibility shims. best of luck -jnap


On Sunday, November 22, 2015 3:03 PM, Bill Moseley <moseley@hank.org> wrote:



I wanted to note something (before the week gets started and time vanishes) about how Catalyst is behaving, and see if it's expected.

I asked about this on the Moose list, so sorry if you already saw this.

A Catalyst app extends Catalyst::Component, which has a BUILDARGS sub to merge in class configuration when creating instances of components.

This is how configuration can set initial values on attributes in Models, Views, Controllers, and the application class itself.

If a (non-role) Moose-based plugin is loaded (which is common) it's added to the app's inheritance like this:

$meta->superclasses($plugin, $meta->superclasses);

Which can be thought of like this:

@App::ISA = ( qw/ Catalyst::Plugin::Foo Catalyst / );

The result then is that BUILDARGS in Catalyst::Component is no longer called, and then attributes in the App class are no longer populated from the config.

So, the behavior changes depending on what plugins are brought in.

Another odd issue I came against is that MooseX::Emulate::Class::Accessor::Fast causes odd behavior of Moose attributes. This role is widely used in Catalyst.

In the code below note how the "foo" attribute has init_arg => undef to prevent it from being initialized. With the the role not only is it initialized, but with a value that isn't an "Int".



package Foo;
>use Moose;
>
>
>with 'MooseX::Emulate::Class::Accessor::Fast';
>
>has foo => (
> is => 'ro',
> isa => 'Int', # for error
> init_arg => undef,
>);
>
>
>
>package main;
>use strict;
>use warnings;
>
>
>my $foo = Foo->new( { foo => 'bar' } );
>
>
>use Data::Dumper;
>print Dumper $foo->foo;


Generates 'bar', which is not an Int.

$VAR1 = 'bar';


Comment out "with 'MooseX::Emulate::Class::Accessor::Fast';" and it behaves as expected. Also comment out "init_arg" and Moose will complain about the string not begin an Int.

--

Bill Moseley
moseley@hank.org
_______________________________________________
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/

_______________________________________________
List: Catalyst@lists.scsys.co.uk
Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
Dev site: http://dev.catalyst.perl.org/