Slides for the talk moo at cluj-pm-2012
-
______
< Moo! >
~~~~~~
\ ^__^
\ (oo)\______
(__)\ )\/\
||~~~~w |
|| ||
-
Moose
-
<3
-
0.01 released
March 15, 2006
-
I started with
about ... 0.18
-
0.18 released
March 10, 2007
-
What is
Moose?
-
What is
Moose
to me?
-
The OO I
always knew
perl5 was
capable of
-
... but wasn't
good enough
to implement
-
Class::Accessor
-
Class::Accessor
Class::MakeMethods
Class::Base
-
Too many!
-
DBIx::Class::AccessorGroup
became
Class::Accessor::Grouped
-
Damian
wrote
Class::Std
-
... but
nobody
used it
-
One class
builder to
rule them all
-
Moose
-
Why did I
stop using
Moose?
-
I didn't.
-
Catalyst
is Moose
-
All Shadowcat's
clients are
using Moose
-
Moose
rocks
-
This is all
the Italians'
fault.
-
IPW
2009
-
Antiquated
Perl
-
Web::Simple
-
Targets:
usable as CGI
-
Targets:
usable as CGI
fast startup
no XS deps
-
Wrote my own
accessors
-
Wrote my own
constructor
-
Perling like
it's 1999
-
*GRUMBLE*
-
Multiple
projects
like this
-
Web::Simple
Data::Query
HTML::Zoom
-
Moose use
impedes
adoption
-
Mouse?
-
Can be
pure perl
-
Describes
itself as
"Moose minus
the antlers"
-
Well ...
-
It still
has a
metamodel
-
The antlers
are just
smaller
-
Mouse is
Moose--
-
Not what
I wanted
-
So I put
on the
hair shirt
-
Used no object
system at all
in my projects
for a year
-
IT
HURT
-
No method
modifiers
-
before foo => sub {
shift->do_before_foo;
};
-
sub foo {
my $self = shift;
$self->do_before_foo;
$self->next::method(@_);
}
-
after foo => sub {
shift->do_after_foo;
};
-
sub foo {
my $self = shift;
my @ret = wantarray
? $self->next::method(@_)
: scalar $self->next::method(@_)
$self->do_after_foo;
return wantarray
? @ret
: $ret[0];
}
-
(and that fails
for void context)
-
Intelligent
accessors
-
has foo => (
is => 'ro',
lazy => 1,
builder => '_build_foo'
);
-
sub foo {
my $self = shift;
die "Readonly" in @_;
unless (exists $self->{foo}) {
$self->{foo} = $self->_build_foo;
}
return $self->{foo}
}
-
Intelligent
constructors
-
has foo => (is => 'ro', required => 1);
has bar => (is => 'ro', default => sub { 0 });
-
sub new {
my $class = shift;
my %args = @_ == 1 ? %{$_[0]} : @_;
die "foo is required"
unless exists $args{foo};
$args{bar} = 0
unless $args{bar};
my %new;
@new{qw(foo bar)} = @args{qw(foo bar)};
bless (\%new, $class);
}
-
Subclassing
gets even
worse ...
-
Runtime
role
application
-
apply_all_roles($obj, @roles)
-
my $new_class = ref($obj).'::__ANON__'.++$i;
@{"${new_class}::ISA"} = ref($obj);
eval "package ${new_class}; use $_" for @roles;
bless($obj, $new_class);
-
ARGH
-
-
So ...
-
About one
year ago
-
Working on
site in
New York
-
Bored at the
weekend
-
(I am useless
at being
a tourist)
-
Coffee.
Subway.
-
I hacked.
ribasushi
and frew
tested.
-
So, what did
we produce?
-
-
Metaprotocol
only needed
for introspection
-
Accessor
generation
-
Method::Generate::Accessor
-
sub _generate_simple_get {
my ($self, $me, $name) = @_;
my $name_str = perlstring $name;
"${me}->{${name_str}}";
}
-
sub _generate_get {
my ($self, $name, $spec) = @_;
my $simple = $self->_generate_simple_get('$_[0]', $name);
if ($self->is_simple_get($name, $spec)) {
$simple;
} else {
'do { '.$self->_generate_use_default(
'$_[0]', $name, $spec,
$self->_generate_simple_has('$_[0]', $name),
).'; '.$simple.' }';
}
}
-
has foo => (
is => 'ro', lazy => 1,
default => sub { 0 }
);
-
sub Class::foo {
do {
$_[0]->{"foo"} = $default_for_foo->($_[0])
unless exists $_[0]->{"foo"}; $_[0]->{"foo"}
}
}
-
Hmm ...
-
Why call a sub
if you don't
need to?
-
Sub::Quote
-
has foo => (
is => 'ro', lazy => 1,
default => quote_sub(q{ 0 })
);
-
sub Class::foo {
do {
$_[0]->{"foo"} = do { @_ = ($_[0]); 0 }
unless exists $_[0]->{"foo"}; $_[0]->{"foo"}
}
}
-
Method::Generate::Constructor
-
sub Class::new {
my $class = shift;
my $args = @_ == 1 ? %{$_[0]} : {@_};
my $new = bless({}, $class);
if (exists $args->{"foo"}) {
$new->{"foo"} = $args->{"foo"};
}
return $new;
}
-
# generated by the *accessor*
# system to avoid repeating
$new->{"foo"} =
-
BUILDALL
-
$new->Super1::BUILD($args);
$new->Super2::BUILD($args);
return $new;
-
Not quite
that simple
-
Subclass may
need a new
constructor
-
package Something;
use base qw(MooThing);
sub BUILD { ... }
-
sub MooThing::new {
my $class = shift;
if ($class ne "MooThing") {
Moo->_constructor_maker_for($class,"Class");
return $class->new(@_);
}
-
Everything
eval()-ed
on demand
-
Simple
sugar
-
Moose has
lazy_build
-
has foo => (
is => 'ro',
lazy => 1,
builder => '_build_foo',
predicate => 'has_foo',
clearer => 'clear_foo'
);
-
Bit too
much.
-
has foo => (
is => 'ro',
lazy => 1,
builder => '_build_foo'
);
-
has foo => (
is => 'lazy'
);
-
Now available in Moose via
MooseX::AttributeShortcuts
-
Method
Modifiers
-
Class::Method::Modifiers
-
Moo::import
does -
-
foreach my $type (qw(before after around)) {
*{_getglob "${target}::${type}"} = sub {
require Class::Method::Modifiers;
_install_modifier($target, $type, @_);
};
}
-
# avoid upsetting strict
sub _getglob { \*{$_[0]} }
-
Moo::Role
-
foreach my $type (qw(before after around)) {
*{_getglob "${target}::${type}"} = sub {
require Class::Method::Modifiers;
push @{$INFO{$target}{modifiers}||=[]}, [ $type => @_ ];
};
}
-
Then during
application
-
foreach my $modifier (@{$modifiers||[]}) {
Class::Method::Modifiers::install_modifier(
$to, @$modifiers
);
}
-
Types?
-
No type
system
-
Lots of
arguing
about
Moose's
-
has foo => (
...
isa => sub {
<pass check>
or die "Not a valid thing"
}
);
-
MooX::Types::MooseLike
-
Other
differences?
-
Moose:
use strict;
use warnings;
-
Moo:
use strictures 1;
-
strictures?
-
use strict;
use warnings FATAL => 'all';
-
when run
from a
test ...
-
use strict;
use warnings FATAL => 'all';
no indirect;
no multidimensional;
no bareword::filehandles;
-
Defaults designed
to save newbies
from themselves
-
Runtime role
application
-
Moose creates
a new class,
applies each
role to it
-
Cachable only
per combination
of roles
-
Moo ... is
slightly
more clever
-
Moo ... is
slightly
more evil
-
Creates a
composable
form of
the class
-
before foo => sub {
$_[0]->do_before_foo
};
-
sub foo {
my $self = shift;
$self->do_before_foo;
$self->next::method(@_);
}
-
next::method
uses
Class::C3
(or C3 mro
on 5.10+)
-
@{"${new_class}::ISA"} = qw(
Composed::Role1
Composed::Role2
SuperClass
);
-
Done.
-
So, total
results?
-
use Moo;
use Moo::Role;
-
extends
has
with
before
after
around
-
Quite sufficient
for small projects
-
Web::Simple
now uses Moo
-
Data::Query
now uses Moo
-
DBIx::Class (!)
now uses Moo
-
DBIx::Class (!)
now uses Moo
(for the odd
thing it used
to use Moose for)
-
perl -Moo -e 'has ...'
# like perl -Moose
-
13 modules
-
~2000 lines
of code and
documentation
-
Needs only:
strictures
Class::Method::Modifiers
-
Needs only:
strictures
Class::Method::Modifiers
Test::More
Test::Fatal
-
Needs only:
strictures
Class::Method::Modifiers
Test::More
Test::Fatal
MRO::Compat
-
It works.
-
It works.
Try it.
-
It works.
Try it.
Complain on
#web-simple
-
'Moo' is
60% of
'Moose'
-
Moo: "almost
but not quite
two thirds
of Moose"
-
Questions?
-
Thank You
IRC:mst
mst@shadowcat.co.uk
@shadowcat_mst