Introducing Moops

This is a very old article. It has been imported from older blogging software, and the formatting, images, etc may have been lost. Some links may be broken. Some of the information may no longer be correct. Opinions expressed in this article may no longer be held.

Moops is sugar for writing object-oriented Perl. It provides similar syntax to MooseX::Declare and Stevan Little’s p5-mop-redux. It’s some glue between Moo, Type::Tiny, Function::Parameters and Try::Tiny, but for those occasions when you want the backing of a meta object protocol, allows you to easily swap Moose (or even Mouse) in place of Moo with very minimal changes.

Here’s an example of a complete, usable class definition in Moops:

   use Moops;
   
   class Person :ro {
      has first_name => (isa => Str);
      has last_name  => (isa => Str);
   }

Note the :ro shortcut, to make attributes default to being read-only. Boilerplate code like use namespace::sweep and __PACKAGE__->meta->make_immutable can be omitted because Moops does that all for you.

Here’s a more extensive example, showing off some other Moops features.

   class User extends Person using Moose :ro {
      use DateTime ();
      
      has password    => (isa => Str);
      has last_login  => (
         is      => 'rwp',
         isa     => InstanceOf['DateTime'],
         handles => { 'date_of_last_login' => 'date' },
      );
      
      method login ( Str $pw ) {
         return 0 if $pw ne $self->password;
         $self->_set_last_login( DateTime->now );
         return 1;
      }
   }

Moops goes to great lengths to smooth over the differences between Moo and Moose. Type constraints are taken from Types::Standard, so the same types will be available for attribute declarations and method signatures, no matter whether you’re using Moo, Moose or Mouse. The Moo-specific is => 'rwp' is munged by MooseX::MungeHas into something Moose is capable of understanding.

Roles can be declared and used just as easily:

   role Breakable :rwp {
      has is_broken => (isa => Bool);
      after break () {
         $self->_set_is_broken(1);
      }
   }
   
   class Engine;
   
   class Car with Breakable {
      
      has engine    => (is => 'ro', isa => InstanceOf['Engine']);
      has is_moving => (is => 'rw', isa => Bool);
      
      method start () {
         return if $self->is_broken;
         say "Starting car";
         $self->is_moving(1);
      }
      
      method stop () {
         say "Stopping car";
         $self->is_moving(0);
      }
      
      method break () {
         say "Car broke";
         $self->stop if $self->is_moving;
      }
   }

Moops is still in an early stage of development, but loads and runs significantly faster than MooseX::Declare and doesn’t seem to suffer from as many parsing oddities. If you’ve got a few spare minutes, and a relatively up-to-date Perl installation (Perl 5.14 is required), please download it and give it a go, and let me know how it went for you.