Moose and Moo

29.1 Moo (Lightweight, Fast Startup)

package Point;
use Moo;
use Types::Standard qw(Num Str ArrayRef);
use namespace::clean;

has x => (is => 'ro', isa => Num, default => 0);
has y => (is => 'ro', isa => Num, default => 0);
has label => (is => 'rw', isa => Str, predicate => 1, clearer => 1);
has history => (is => 'lazy', isa => ArrayRef);
sub _build_history { [] }            # lazy builder

sub BUILD {                          # runs after construction
    my ($self, $args) = @_;
    die "x must be >= 0" if $self->x < 0;
}

sub to_string {
    my $self = shift;
    return sprintf '(%s, %s)', $self->x, $self->y;
}

package Point3D;
use Moo;
extends 'Point';
has z => (is => 'ro', default => 0);
around to_string => sub {            # method modifiers: before, after, around
    my ($orig, $self, @args) = @_;
    my $s = $self->$orig(@args);
    $s =~ s/\)$/, ${\ $self->z })/;
    return $s;
};

package main;
my $p = Point3D->new(x => 1, y => 2, z => 3);
say $p->to_string;                   # (1, 2, 3)
$p->label('origin-ish');
say $p->has_label ? 'labeled' : 'no label';

29.2 Moose (Full-Featured, Introspective)

Mouse / Object::Pad / Core class Minimal (upgrades to Moose if needed) Via Type::Tiny Role::Tiny / Moo::Role Role::Tiny / built in (Object::Pad) Large apps needing introspection Default choice for most CPAN/apps Object::Pad/core class for new code

Type::Tiny works with Moo, Moose, Mouse, and plain subs (Types::Standard, Types::Common::Numeric).

Other systems: Mojo::Base (minimal, used in Mojolicious), Class::Accessor, Class::Tiny, Object::Pad (the testbed for the core class feature).

package BankAccount;
use Moose;
use Moose::Util::TypeConstraints;
use namespace::autoclean;

subtype 'PositiveNum', as 'Num', where { $_ > 0 }, message { "Amount must be positive" };

has owner   => (is => 'ro', isa => 'Str', required => 1);
has balance => (is => 'ro', isa => 'Num', default => 0, writer => '_set_balance');
has transactions => (
    traits  => ['Array'],
    is      => 'ro',
    isa     => 'ArrayRef[HashRef]',
    default => sub { [] },
    handles => { add_transaction => 'push', transaction_count => 'count' },   # native traits
);

sub deposit {
    my ($self, $amount) = @_;
    find_type_constraint('PositiveNum')->assert_valid($amount);
    $self->_set_balance($self->balance + $amount);
    $self->add_transaction({ type => 'deposit', amount => $amount });
}

__PACKAGE__->meta->make_immutable;   # speed optimization
1;