JayBonci has asked for the wisdom of the Perl Monks concerning the following question:

Hello kind monks,

Over at E2 I'm working on rewriting the object model to use Moose. This is slowly trying to change the tires on the car while it's moving. I'm still trying to dig in there, but my problem is that I don't know quite the right question to ask, so I thought I'd start here. This is a simplified example

Let's say I had a Moose Class like:

package MyApp::Object; use strict; use Moose; has 'greeting' => ('isa' => 'Str', 'is' => 'ro', 'required' => 1); 1;

For instance, what I want to do is create have MyApp::Object automatically create a MyApp::Object::Collection object which will contain an array of MyApp::Objects and when I call a parameter against it, it will loop through and call each of the MyApp::Object parameters. Additionally, I want this to be subclassable, so if MyApp::ChildObject comes along, that automatically creates MyApp::ChildObject::Collection. I'm a bit lost in the documentation on Moose::Meta, and am not quite sure what to google to continue. Does anyone have any pointers?

Thanks!



    --jaybonci

Replies are listed 'Best First'.
Re: Moose::Meta programming and derivative classes
by choroba (Cardinal) on Apr 30, 2017 at 23:28 UTC
    I'm not sure I understand. Object should create Collection? What should it contain - the Object or all the objects? Also, what do you mean by "call a parameter"? One usually calls methods, not parameters.

    Also, with Moose, you don't need to specify use strict . Moose enables strict and warnings automatically.

    Do you mean something like this?

    #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; { package MyApp::Object; use Moose; has greeting => (isa => 'Str', is => 'ro', required => 1); sub collection { ref(shift) . '::Collection' } { my %collection; sub BUILD { my ($self) = @_; my $class = $self->collection; Moose::Meta::Class->create( $class, methods => { push => sub { push @{ $collection{ +shift } }, $s +elf }, greet => sub { say $_->greeting for @{ $collection{ +shift } +} }, }, ); $class->push($self); } } __PACKAGE__->meta->make_immutable; } { package MyApp::ChildObject; use Moose; extends 'MyApp::Object'; __PACKAGE__->meta->make_immutable; } my $o = 'MyApp::Object'->new(greeting => 'Hallo'); $o->collection->greet; my $c1 = 'MyApp::ChildObject'->new(greeting => 'Ciao'); my $c2 = 'MyApp::ChildObject'->new(greeting => 'Salut'); $c1->collection->greet;

    Instead of storing the collections in a lexical hash, you can create a singleton instance for each class.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      Hey there choroba, thanks for getting back to me.

      So to clear up a few things. First, thanks for the tip about strict and warnings. I also meant methods, as you implied.

      I guess what I'm considering is that I want to be able to create additional classes out of skeletons of other classes that are set at use() time if possible. So when I use MyApp::Object, I also want MyApp::Object::Collection to be available as an object that could get returned, and it is built via convention. It seems like I could create an on-the-fly class and store that to make instances of it when I return something that would be a collection, and maybe that is the right way to do it, but that feels strange to me when you could just store traditional stuff in the symbol table. I'm academically exploring how I can use meta programming to reduce having to generate a bunch of classes at use time and avoid potential errors of copy and paste boilerplate stuff.

      Thanks again!



          --jaybonci
        "I'm academically exploring how I can use meta programming to reduce having to generate a bunch of classes at use time ..."

        You simply ... don't. Classes are just containers, they don't actually do anything. It is their METHODS that do the work.