Announcing MooX::Press

MooX::Press is a quick way of building a bunch of Moo roles and classes in one use statement.

The most basic example would be:

  package MyApp {
    use MooX::Press class => ['Foo', 'Bar'];
  }
  
  my $thing1 = MyApp::Foo->new();
  my $thing2 = MyApp->new_foo();   # alternative constructor

But do-nothing classes with a constructor and nothing else aren't very exciting. Let's define a class with some subclasses which have attributes and roles and methods and stuff.

  package MyApp::Zoo;
  use MooX::Press (
    role => [
      'Aquatic' => {
        can => [
          swim => sub { print "swimming\n" },
        ],
      },
      'Flight',
    ],
    class => [
      'Animal' => {
        has => [qw( $name $colour $age )],
        subclass => [
          'Fish' => {
            with => 'Aquatic',
            subclass => [qw( Shark Ray )],
          },
          'Bird' => { with => 'Flight' },
          'Mammal' => {
            subclass => [
              qw( Panda Goat ),
              'Kangaroo' => { can => [ jump => sub { ... } ] },
              'Dolphin'  => { with => 'Aquatic' },
              'Bat'      => { with => 'Flight' },
            ],
          },
        ],
      },
    ],
  );

The above code just defined the following roles:

  • MyApp::Zoo::Aquatic
  • MyApp::Zoo::Flight

And the following classes:

  • MyApp::Zoo::Animal
  • MyApp::Zoo::Fish
  • MyApp::Zoo::Shark
  • MyApp::Zoo::Ray
  • MyApp::Zoo::Bird
  • MyApp::Zoo::Mammal
  • MyApp::Zoo::Panda
  • MyApp::Zoo::Goat
  • MyApp::Zoo::Kangaroo
  • MyApp::Zoo::Dolphin
  • MyApp::Zoo::Bat

All with the appropriate attributes and roles applied to them.

Also, it defined a package called MyApp::Zoo::Types with class and role type constraints already set up.

So you can do:

  use Moo;
  use MyApp::Zoo::Types qw(Kangaroo);
  
  has mascot => (is => 'ro', isa => Kangaroo);

Or:

  use MyApp::Zoo::Types qw(is_Kangaroo);
  
  $thing->jump if is_Kangaroo($thing);

Here's some more code using our zoo classes...

  use MyApp::Zoo ();
  
  my $lenny = MyApp::Zoo->new_shark(name => 'Lenny');
  $lenny->isa('MyApp::Zoo::Shark');    # true
  $lenny->isa('MyApp::Zoo::Fish');     # true
  $lenny->isa('MyApp::Zoo::Animal');   # true
  $lenny->does('MyApp::Zoo::Aquatic'); # true
  $lenny->can('swim');                 # true
  
  package MyApp::Zoo::Enclosure::Tank {
    use Moo;
    use Types::Standard qw(ArrayRef);
    use MyApp::Zoo::Types qw(Aquatic);
    has animals => (
      is  => 'rw',
      isa => ArrayRef[Aquatic],
    );
  }
  
  my $tank = MyApp::Zoo::Enclosure::Tank->new(
    animals => [ $lenny ],
  );

MooX::Press is on CPAN.

2 Comments

Probably need something to import MooX modules like MooX::TO_JSON or MooX::HandlesVia per class/ role.

Leave a comment

About Toby Inkster

user-pic I'm tobyink on CPAN, IRC and PerlMonks.