The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Momo,a simple oop module inspired from Mojo::Base and Moo.

SYNOPSIS

    package Person;

    use Momo;
    
    has name => 'james'; # if not set,default set james
    has [qw(age sex)];

    sub new{
        say "I'm a Person";
    }

    1;

DESCRIPTION

Why I want to write this module? If you heard about Moose or Moo,you know they are pretty module for perl object-oriented program. Compare with old style of perl5 object-oriented program:

    package Foo;

    BEGIN{
        push @ISA,"Some::SuperClass";
    } # or 
    use base 'Some::SuperClass';

    sub new{
        my $self = bless {} shift;
        $self->{name} = shift;
        $self->{age} = shift;
        return $self;
    }

    sub some_method{
        say "I'm some method";
    }

    1;

    # invoke method as oop style
    my $obj = Foo->new;
    $obj->some_method;

In moose or moo,write like this:

    package Foo;

    use Moose; # or use Moo
    
    extends 'SomeBaseClass' with 'role1','role2';

    has x => ( is => 'rw',default => sub { {} },lazy => 1);
    has y => ( is => 'ro',default => ref {} );
    has z => ( is => 'rw',default => sub { { xx => 'yy'} },required => 1);

    before method1 => sub {
        .....
    };

    after method1 => sub {
    };

    around method1 => sub {
    };

    1;

It looks so amazing,everything works fine,Moose can give you vast powerful feature of perl Object-Oriented,the syntax sugars like 'extends','has','with'...etc are magic. On the other hand,you can override the attribute with has +x,and also,with the role make it more inconceivable.

But,I still find some problem:

the cumbersome syntax in has defined

Every time when I type the has blabla,does this below is really I want?

    has ua=> ( is => 'rw',isa => 'LWP::UserAgent',
        default => sub { LWP::UserAgent->new },lazy => 1);
    # is => 'rw', over and over,lazy => 1, over and over,default,over and
    # over....
    # It makes me creazy!

You know perl is a dynamically typed language,not like java ,c++,I think I don't need the feature,even I almost do not used this feature,I also write ruby and python,but I never see this.

inherit some class of non Moose modules

In Moose or Moo,if you want to inherit a calss of non Moose style,all I know is to use MooseX::NonMoose;

      package Term::VT102::NBased;
      use Moose;
      use MooseX::NonMoose;
      extends 'Term::VT102';

      has [qw/x_base y_base/] => (
          is      => 'ro',
          isa     => 'Int',
          default => 1,
      );

      around x => sub {
          my $orig = shift;
          my $self = shift;
          $self->$orig(@_) + $self->x_base - 1;
      };

      # ... (wrap other methods)

      no Moose;
      # no need to fiddle with inline_constructor here
      __PACKAGE__->meta->make_immutable;

      my $vt = Term::VT102::NBased->new(x_base => 0, y_base => 0);

or:

    package Crawler::Event;

    use Moo;

    extends 'Object::Event','Moo::Object';

    # explicit constructor
    sub new {
        my $class = shift;

        # call Mojo::UserAgent's constructor
        my $obj = $class->SUPER::new(@_);
        return $class->meta->new_object(
            # pass in the constructed object
            # using the special key __INSTANCE__
            __INSTANCE__ => $obj,
            @_,    # pass in the normal args
        );
    }

    1;

It looks so weird,this is just a simple object inherit,why I need to type so many code and install a Moosex module. Also,there is another way to fix this,use deligation

    package Website;

    use Moose;

    has 'uri' => (
      is      => 'ro',
      isa     => 'URI',
      handles => {
          hostname => 'host',
          path     => 'path',
      },
    );

But I think this is more complex,if you lost some method of handles,when you run your code which just need to inherit LWP,then throw a error like:

    Can't find this method

Oh my god,why I must do this?

speed of runtime slowly

Although,Moo have make moose looks tidy and simple,at runtime,it still cost more time than old style of perl Object-Oriented program.

Here is the benchmark of Momo,Moose,Moo,hashref,bless hashref,each test create a object and access the attr,set the attr:

    Benchmark: timing 1000000 iterations of blessed_hashref, hashref, momo, moo, moose...
    blessed_hashref: 1.60316 wallclock secs ( 1.60 usr +  0.00 sys =  1.60 CPU) @ 625000.00/s (n=1000000)
       hashref: 1.34393 wallclock secs ( 1.35 usr +  0.00 sys =  1.35 CPU) @ 740740.74/s (n=1000000)
          momo: 3.97532 wallclock secs ( 3.97 usr +  0.00 sys =  3.97 CPU) @ 251889.17/s (n=1000000)
           moo: 5.36459 wallclock secs ( 5.37 usr +  0.00 sys =  5.37 CPU) @ 186219.74/s (n=1000000)
         moose: 7.81556 wallclock secs ( 7.81 usr +  0.00 sys =  7.81 CPU) @ 128040.97/s (n=1000000)
                        Rate     moose       moo      momo blessed_hashref   hashref
    moose           128041/s        --      -31%      -49%            -80%      -83%
    moo             186220/s       45%        --      -26%            -70%      -75%
    momo            251889/s       97%       35%        --            -60%      -66%
    blessed_hashref 625000/s      388%      236%      148%              --      -16%
    hashref         740741/s      479%      298%      194%             19%        --

The result shows that Momo is faster than Moo,Moose.

When I develop mojo app,I found Mojo::Base is so simple and light,fast speed, and I add some features like : role,method modifiers,everything works fine for me.

Anyway,if you hate all of these,try Momo,or you can keep working on Moose or Moo.

It's so simple:

    package MomoStyle;

    use Momo;
    extends 'LWP::UserAgent'; #inherit LWP::UserAgent so easy
    with 'Logger'; # does a logging role,same as moose's role

    has name => 'momo';
    has city => 'beijing';
    has check => sub {
        my $self = shift;
        if( $name eq 'momo' ){
            # do some stuff here
        }
    };
    # if you need do some other thing,you can override new 
    sub new{
        my $self = shift->SUPER::new(@_);
        $self->agent("momo");
        $self;
    }

    1;

FUNCTIONS

Momo exports the following functions

has

  has 'name';
  has [qw(name1 name2 name3)];
  has name => 'foo';
  has name => sub {...};
  has [qw(name1 name2 name3)] => 'foo';
  has [qw(name1 name2 name3)] => sub {...};

Create attributes for hash-based objects, just like the Moose has or Moo, but ignore the option of is,isa...

METHODS

Momo implements the following methods.

new

  my $object = BaseSubClass->new;
  my $object = BaseSubClass->new(name => 'value');
  my $object = BaseSubClass->new({name => 'value'});

This base class provides a basic constructor for hash-based objects. You can pass it either a hash or a hash reference with attribute values.

attr

  $object->attr('name');
  BaseSubClass->attr('name');
  BaseSubClass->attr([qw(name1 name2 name3)]);
  BaseSubClass->attr(name => 'foo');
  BaseSubClass->attr(name => sub {...});
  BaseSubClass->attr([qw(name1 name2 name3)] => 'foo');
  BaseSubClass->attr([qw(name1 name2 name3)] => sub {...});

Create attribute accessor for hash-based objects, an array reference can be used to create more than one at a time. Pass an optional second argument to set a default value, it should be a constant or a callback. The callback will be executed at accessor read time if there's no set value. Accessors can be chained, that means they return their invocant when they are called with an argument.

extends

use this to inherit a class,different with Moose's extends,you can extends any other module,what if they are blessed style module,

    extends 'LWP::UserAgent';
    extends 'BaseClass1','BaseClass2';

with

use this to does a role,about role you can check Moose::Role

    extends 'Mojo::Lite';
    with 'Some::Role';

    1;

method_modifiers

Same as Moo and Moose,Momo support method modifiers in Class or Role:

    package Role1;

    use Momo::Role;

    before some_method => sub { print "i'm before method" };
    after some_method => sub { print "i'm after method" };
    around some_method => sub { $_[1]->$_[0](@_) };

in class package:

    package Cat;

    use Momo;

    before feed => sub { print "I want to eat some water" };
    after feed => sub { print "after feed,I'm full" };
    around feed => sub { print "I should eat what" };
    sub feed { print "I want to feed ..." };

tap

  $object = $object->tap(sub {...});

K combinator, tap into a method chain to perform operations on an object within the chain. The object will be the first argument passed to the callback and is also available as $_.

DEBUGGING

You can set the MOMO_DEBUG environment variable to get some advanced diagnostics information printed to STDERR.

  MOMO_DEBUG=1

SEE ALSO

Mojo::Base,Moo,Moose,Role::Tiny

TODO

support MOP
write attr with XS

BUGS

Any bugs just email yiming.jin@live.com,or commit a issue on github: https://github.com/niumang/momo/issues

AUTHOR

舌尖上的牛氓 yiming.jin@live.com

QQ: 492003149

QQ-Group: 211685345

Site: http://perl-china.com

Copyright

Copyright (C) <2013>, <舌尖上的牛氓>.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES.

This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.