On Github kablamo / slides-intro-to-moo
use Moo;
          
          is equivalent to
use strict;                   # strict vars, refs, subs
use warnings;                 # in Moo v2+
no indirect;                  # can't do `my $alien = new Alien;`
no multidimensional;          # can't do `$hash{1,2}`
no bareword::filehandles;     # can't do `open FH, $filename`
use base 'Moo::Object';       # provides new(), etc
          
          also use Moo imports some methods:
extends(), with(), has(), before(), around(), and after()
It inflates your Moo class to a Moose class
my $alien = Alien->new(@args)
new() calls Alien->BUILDARGS(@args) new() instantiates object, creating $self new() calls BUILD($self) new() returns $self
is called before instantiation
package Alien;
use Moo;
sub BUILDARGS {
    my ($class, @args) = @_;
   
    # -- modify @args here --
   
    return { @args };
}
          
          In Moose you need to call SUPER at the end
is called after instantiation
package Alien;
use Moo;
sub BUILD {
    my ($self, $args) = @_;
   
    # -- additional validation or logging here --
}
          
          The return value is ignored
is called when the object is destroyed
package Alien;
use Moo;
sub DEMOLISH {
    my ($self, $in_global_destruction) = @_;
   
    $self->dbh->disconnect;
}
          
        
package Alien;
use Moo;
has eyes      => (is => 'rw');
has nostrils  => (is => 'ro');
          
          
my $alien = Alien->new( nostrils => 20 );
$alien->eyes(10);     # succeeds
$alien->nostrils(10); # dies
          
        
package Alien;
use Moo;
has eyes     => (is => 'ro', default => sub { 5 });
has nostrils => (is => 'ro', builder => '_build_nostrils');
# Perlism: methods that start with _ are private
sub _build_nostrils { 5 }
          
        
has tentacles => (is => 'lazy');
          
          is equivalent to
has tentacles => (is => 'ro', lazy => 1, builder => '_build_tentacles');
          
        Use MooseX::AttributeShortcuts to get support for is => 'lazy' in Moose
is unpredictable
package Alien;
use Moo;
use Tentacle;
has tentacle_count => (is => 'ro', default => sub { 5 });
has tentacles      => (is => 'ro', builder => '_build_tentacles');
sub _build_tentacles { 
  my $self = shift;
  my @tentacles;
  push @tentacles, Tentacle->new() for (1..$self->tentacle_count);
  return \@tentacles;
}
          
        
package Alien;
use Moo;
use Tentacle;
has tentacles      => (is => 'lazy');
has tentacle_count => (is => 'ro', default => sub { 5 });
sub _build_tentacles { 
  my $self = shift;
  my @tentacles;
  push @tentacles, Tentacle->new() for (1..$self->tentacle_count);
  return \@tentacles;
}
          
        
use Types::URI -all;
has uri => (is => 'ro', isa => Uri);
use Types::Standard -all;
has is_from_mars => (is => 'ro', isa => Bool);
has tentacles    => (is => 'ro', isa => ArrayRef[InstanceOf["Tentacle"]]);
          
        
package MyCompany::Types;
use Type::Library -base;
use Type::Utils -all;
BEGIN { extends "Types::Standard" };
 
declare "PurpleTentacles",
     as ArrayRef[InstanceOf["Tentacles"]],
  where {
            my $tentacles = $_;
            for my $tentacle (@$tentacles) {
                return 0 if $tentacle->color ne "purple";
            }
            return 1;
        };
          
        
use MyCompany::Types -all;
has tentacles => (is => 'ro', isa => PurpleTentacles);
          
        Unlike Moose, coercions are separate from type checking
No solution that worked with both Moose and Moo until recently
package Client;
use Moo;
use URI;
has uri => (is => 'ro', coerce => \&string_to_uri );
sub string_to_uri {
  my $value = shift;
  return $value if ref $value eq 'URI'
  return URI->new($value);
}
          
          
my $client = Client->new( uri => 'http://example.com' );
$client->uri->host;  # returns example.com
          
        Type::Tiny coercions come packaged with types (like in Moose)
package Client;
use Moo;
use Types::URI -all;
has uri => (is => 'ro', isa => URI, coerce => 1);
          
          
my $client = Client->new( uri => 'http://example.com' );
$client->uri->host;  # returns example.com
          
        
package MyCompany::Types;
use Type::Library -base;
use Type::Utils -all;
BEGIN { extends "Types::Standard" };
 
declare "Greeting",
     as "Str",
  where { $_ =~ /Take me to your leader.$/ };
coerce "Greeting",
  from "Str",
   via { $_ .= '  Take me to your leader.' };
          
        Too many for me to cover here. See also:
package ConfigFile;
use Moo;
use Path::Class;
has _file => (
  is      => 'ro', 
  handles => [qw/spew slurp/],
  default => sub { Path::Class::file('.configuration') },
);
          
          
my $config_file = ConfigFile->new();
$config_file->slurp(); # read in file contents
          
        
package ConfigFile;
use Moo;
use Path::Class;
has _file => (
  is      => 'ro', 
  handles => { write => 'spew', read => 'slurp'},
  default => sub { Path::Class::file('.configuration') },
);
          
          
my $config_file = ConfigFile->new();
$config_file->read(); # slurp in file contents
          
        A code reference run after an attribute is set
has cowboy => (
  is      => 'ro', 
  trigger => sub { warn "cowboy attr set"; }
);
          
        
package Brontosaurus;
use Moo;
extends 'Dinosaur';
before eat => sub {
  my ($self, $food) = @_;
  die "bad params" if $food eq 'meat';
};
          
          Receives same params as the original method
Return value is ignored
Good for adding extra validation
package Brontosaurus;
use Moo;
extends 'Dinosaur';
after eat => sub {
  my ($self, $food) = @_;
  $self->log->warning("Brontosaurus does not like to eat $food")
    if $food eq 'meat';
};
          
          Receives same params as the original method
Return value is ignored
Good for logging/debugging
package Brontosaurus;
extends 'Dinosaur';
around eat => sub {
  my ($orig, $self, $food) = @_;
  uc $orig->($self, $food);
};
          
          Called instead of the original method
package Searchable;
use Moo::Role;
# state
has 'number_of_results' => (is => 'ro', default => sub { 5 }); 
# behavior
sub search { ... }
          
          
package Thing;
use Moo;
with qw/Searchable/;
          
          
my $thing = Thing->new();
$thing->search();
          
        
package Searchable;
use Moo::Role;
requires 'search_engine';
sub search { 
  my ($self, $query) = @_;
  my $json = $self->search_engine->search($query);
  return JSON->new->utf8->decode($json);
}
          
          
package Thing;
use Moo;
with qw/Searchable/;
sub search_engine {
  return Bing->new();
}
          
        
print "hi" if Thing->does('Searchable');