Moose: OOP in Perl

    Moose is an extension to Perl 5 that makes it easy to implement OOP.

    Creating a class is very easy:
    package MyClass;
    use Moose;
    


    everything, an empty class is created. It can have an arbitrary number of attributes, methods, superclasses, method modifiers, constructor (1pc), destructor (1pc) and meta-class (1pc) that contains all the meta-information about this class.

    Now more about these components:


    Class


    Each class is a subclass of Moose :: Object. By default, it creates a bunch of all sorts of useful objects, in the form of meta-classes and other objects inherent in the superclass, which can be accessed after creation.

    Subclass

    Inheritance occurs using the extends keyword
    package User; 
    use Moose; 
    extends 'Person'; 
    has 'username' => ( is =>'rw' ); 
    

    multiple inheritance, specify classes separated by commas: extends 'Foo', 'Bar';

    Attributes


    The attribute must have a name, it can have a different number of properties: read / write flag, type, accessor method, delegations, default value, etc.
    By default, Moose stores the attributes in the class instance as a hash. Access to them can be obtained through accessors.
    has - declare the attribute
    has 'first_name' => ( is =>'rw' );
    

    the is option can have the values ​​[ro | rw | bare] read-only or read-write or bare - without accessors to this attribute.

    Getters and setters can be set like this:

    has 'weight' => ( 
        is     =>'rw', 
        reader =>'get_weight', 
        writer =>'set_weight', 
    ); 
    


    predicate - if the attribute is “undef” or another false value, it will return true.
    clearer - resets the attribute

    clearer - resets the attribute
    has 'ssn' => ( 
        is        =>'rw', 
        clearer   =>'clear_ssn', 
        predicate =>'has_ssn', 
    ); 
    


    $person->has_ssn; # false 
    $person->ssn(undef); 
    $person->ssn; # returns undef 
    $person->has_ssn; # true 
    $person->clear_ssn; 
    $person->ssn; # returns undef 
    $person->has_ssn; # false 
    $person->ssn('123-45-6789'); 
    $person->ssn; # returns '123-45-6789' 
    $person->has_ssn; # true 


    The need to install the attribute

    can be set using the property: required => 1
    by default, all attributes are optional.

    Attributes can be set by default in two ways.

    has 'size' => (
        is        =>'ro',
        default   =>'medium',
        predicate =>'has_size',
    );
    

    and if not set in the constructor, then:
    my $person = Person->new();
    $person->size; # medium
    $person->has_size; # true


    And you can set a link to the method:
    has 'size' => (
        is =>'ro',
        default =>sub{ ( 'small', 'medium', 'large' )[ int( rand3 ) ] },
                 predicate =>'has_size',
            );
    


    Alternative method:
    has 'size' => (
        is        =>'ro',
        builder   =>'_build_size',
        predicate =>'has_size',
    );
    sub _build_size{
         return ( 'small', 'medium', 'large' )[ int( rand3 ) ];
    }
    

    builder recommend using instead of default .

    We postpone the installation of the attribute last

    this can be achieved by setting the property: lazy => 1 is
    especially necessary when the initial value of the attribute depends on other factors.
    Another plus in using this property is that the attribute will be calculated only if it is required, and if it is not needed at all, we will save CPU time.

    Attribute Types

    can be the same type as any pearl structure: isa => 'Str'
    or can be an object: does => 'MyApp :: Object'

    Setting multiple attributes

    has [ 'x', 'y' ] => ( is =>'ro', isa =>'Int' );
    

    or so:
    formy $name ( qw( x y ) ) {
        my $builder = '_build_' . $name;
        has $name => ( is =>'ro', isa =>'Int', builder => $builder );
    }
    


    Methods


    Any function declared in a class is a class method.

    Method Modifiers

    called before (or "before, after, around, augment") a method call:
    before 'atribute' => sub{ 
        my $self = shift; 
        my $a   = shift; 
        print $a;
    }; 
    


    Role


    The behavior or state that this class should implement. An analogue of the interface in other OO languages.
    Created using use Moose :: Role;
    package Eq;
    use Moose::Role;
    requires 'equal_to';
    subnot_equal_to{
        my ( $self, $other ) = @_;
        not $self->equal_to($other);
    }
    

    although the role looks like a class, but it is not a class, you cannot instantiate a role. The word requires tells us that any class using this role must implement the 'equal_to' method.
    package Comparable;
    use Moose;
    with 'Eq';
    subequal_to{
        my ( $self, $other ) = @_;
        $self->compare($other) == 0;
    }
    subcompare{
        my ( $self, $other ) = @_;
        $self->amount <=> $other->amount;
    }
    


    Constructor / Destructor


    They never need to be explicitly redefined, but if such a need arises, you can use BUILD () and DEMOLISH () for the constructor and destructor, respectively.

    Metaclass


    The metaclass describes the class. With Moose, each class gives a "meta ()", which returns a Moose :: Meta :: Class object. He talks about what this class is.
    my $meta = User->meta(); 
    formy $attribute ( $meta->get_all_attributes ) { 
         print $attribute->name(), "\n"; 
         if ( $attribute->has_type_constraint ) { 
             print"  type: ", $attribute->type_constraint->name, "\n"; 
         } 
    } 
    formy $method ( $meta->get_all_methods ) { 
         print $method->name, "\n"; 
    } 
    


    Garbage cleaning


    happens if set at the beginning of the class: use namespace :: autoclean;
    or at the end of the class: no Moose;

    Class acceleration


    If the class does not change during the work, then its work can be accelerated as follows:
    __PACKAGE__->meta->make_immutable;
    


    That's all, this knowledge should be enough to successfully create OOP structures in Perl, but for a deeper understanding, of course it is better to delve into the documentation and ... yes yes in the source code of the modules (well, this is for special cases, although in this case, curiosity will not hurt anyone).

    Also popular now: