Name

Class::Plain::Document::Cookbook - Cookbook of Class::Plain

Description

This is the cookbook of the Class::Plain.

Use Class::Plain with Existing Classes

Use Class::Plain with existing classes.

Before:

package Point;

sub new {
  my $class = shift;
  
  my $self = {@_};
  
  return bless $self, ref $class || $class;
}

sub x {
  my $self = shift;
  
  if (@_) {
    $self->{x} = shift;
    return $self;
  }
  
  return $self->{x};
}

sub y {
  my $self = shift;
  
  if (@_) {
    $self->{y} = shift;
    return $self;
  }
  
  return $self->{y};
}

my $point = Point->new(x => 1, y => 2);
$point->x(3);
$point->y(4);

print $point->x . "\n";
print $point->y . "\n";

After

Use class, field, method keywords.

use Class::Plain;

class Point {
  field x;
  field y;
  
  method new : common {
    my $self = {@_};
    
    return bless $self, ref $class || $class;
  }
  
  method x {
    if (@_) {
      $self->{x} = shift;
      return $self;
    }
    
    return $self->{x};
  }

  method y {
    if (@_) {
      $self->{y} = shift;
      return $self;
    }
    
    return $self->{y};
  }
}

my $point = Point->new(x => 1, y => 2);
$point->x(3);
$point->y(4);

print $point->x . "\n";
print $point->y . "\n";

Rewite Existing Classes using Class::Plain

If you don't need to take care of the fll backword compatilibity, you can rewrite above code to the following code.

use Class::Plain;

class Point {
  field x : rw;
  field y : rw;
}

my $point = Point->new(x => 1, y => 2);
$point->x(3);
$point->y(4);

print $point->x . "\n";
print $point->y . "\n";

Customizing Object Initialization

A class created by Class::Plain inherits Class::Plain::Base. Class::Plain::Base has the new method.

use Class::Plain;

# Inherit Class::Plain::Base
class Point {
  field x;
  field y;
}

# (x => 1)
my $point = Point->new(x => 1);

This can be customize by overriding the new method.

use Class::Plain;

class Point {
  field x;
  field y;
  
  # Override the new method
  method new : common {
    my $self = $class->SUPER::new(@_);
    
    $self->{x} //= 0;
    $self->{y} //= 0;
    
    return $self;
  }
}

# (x => 1, y => 0)
my $point = Point->new(x => 1);

Using Other Data Structures

Array Based Object

An example of the array based object.

use Class::Plain;

class ArrayBased {
  method new : common {
    return bless [@_], ref $class || $class;
  }
  
  method push {
    my ($value) = @_;
    
    push @$self, $value;
  }
  
  method get {
    my ($index) = @_;
    
    return $self->[$index];
  }
  
  method to_array {
    return [@$self];
  }
}

my $object = ArrayBased->new(1, 2);

$object->to_array; # [1, 2]

$object->push(3);
$object->push(5);

$object->get(0); # 1
$object->get(1); # 2
$object->get(2); # 3
$object->get(3); # 5
$object->to_array; # [1, 2, 3, 5]

Scalar Based Object

An example of the scalar based object.

use Class::Plain;

class ScalarBased {
  method new : common {
    
    my $value = shift;
    
    return bless \$value, ref $class || $class;
  }
  
  method to_value {
    return $$self;
  }
}

my $object = ScalarBased->new(3);

$object->to_value; # 3;

Inheritance

Single Inheritance

An example of single inheritance.

use Class::Plain;

class Point {
  field x;
  field y;
  
  method new : common {
    my $self = $class->SUPER::new(@_);
    
    $self->{x} //= 0;
    $self->{y} //= 0;
    
    return $self;
  }
  
  method move {
    my ($x, $y) = @_;
    
    $self->{x} += $x;
    $self->{y} += $y;
  }
  
  method describe {
    print "A point at ($self->{x}, $self->{y})\n";
  }
}

my $point = Point->new(x => 5, y => 10);
$point->describe;

class Point3D : isa(Point) {
  field z;
  
  method new : common {
    my $self = $class->SUPER::new(@_);
    
    $self->{z} //= 0;
    
    return $self;
  }
  
  method move {
    my ($x, $y, $z) = @_;
    
    $self->SUPER::move($x, $y);
    $self->{z} += $z;
  }
  
  method describe {
    print "A point at ($self->{x}, $self->{y}, $self->{z})\n";
  }
}

my $point3d = Point3D->new(x => 5, y => 10, z => 15);
$point3d->describe;

Multiple Inheritance

An example of multiple inheritance. It is used for modules using multiple inheritance such as DBIx::Class.

use Class::Plain;

# The multiple inheritance
class MultiBase1 {
  field b1 : rw;
  
  method ps;
  
  method b1_init {

    push @{$self->ps}, 2;
    $self->{b1} = 3;
  }
}

class MultiBase2 {
  field b2 : rw;

  method ps;
  
  method b1_init {

    push @{$self->ps}, 7;
    $self->{b1} = 8;
  }
  
  method b2_init {
    
    push @{$self->ps}, 3;
    $self->{b2} = 4;
  }
}

class MultiClass : isa(MultiBase1) isa(MultiBase2) {
  field ps : rw;
  
  method new : common {
    my $self = $class->SUPER::new(@_);
    
    $self->{ps} //= [];
    
    $self->init;
    
    return $self;
  }
  
  method init {
    push @{$self->{ps}}, 1;
    
    $self->b1_init;
    $self->b2_init;
  }
  
  method b1_init {
    $self->next::method;
  }
  
  method b2_init {
    $self->next::method;
  }
}

my $object = MultiClass->new;

$object->b1; # 3

$object->b2; # 4

$object->ps; # [1, 2, 3]

Embeding Class

An example of embeding classes. Embeding class is similar to Corinna Role although the methods are embeded manually in the case of using Class::Plain.

use Class::Plain;

class EmbedBase1 {
  field b1 : rw;
  
  method ps;
  
  method init {

    push @{$self->ps}, 2;
    $self->{b1} = 3;
  }
}

class EmbedBase2 {
  field b2 : rw;

  method ps;
  
  method init {
    
    push @{$self->ps}, 3;
    $self->{b2} = 4;
  }
}

class EmbedClass {
  field ps : rw;
  
  method new : common {
    my $self = $class->SUPER::new(@_);
    
    $self->{ps} //= [];
    
    $self->init;
    
    return $self;
  }
  
  method init {
    push @{$self->{ps}}, 1;
    
    $self->EmbedBase1::init;
    $self->EmbedBase2::init;
  }
  
  method b1 { $self->EmbedBase1::b1(@_) }
  
  method b2 { $self->EmbedBase2::b2(@_) }
}

my $object = EmbedClass->new;

$object->b1; # 3
$object->b2; # 4
$object->ps; # [1, 2, 3]

Role

An example of the role. The above example is rewritten by "role" in Class::Plain.

use Class::Plain;

role EmbedBase1 {
  field b1 : rw;
  
  method ps;
  
  method init {

    push @{$self->ps}, 2;
    $self->{b1} = 3;
  }
}

role EmbedBase2 {
  field b2 : rw;

  method ps;
  
  method init {
    
    push @{$self->ps}, 3;
    $self->{b2} = 4;
  }
}

class EmbedClass : does(EmbedBase1) does(EmbedBase2) {
  field ps : rw;
  
  method new : common {
    my $self = $class->SUPER::new(@_);
    
    $self->{ps} //= [];
    
    $self->init;
    
    return $self;
  }
  
  method init {
    push @{$self->{ps}}, 1;
    
    $self->EmbedBase1::init;
    $self->EmbedBase2::init;
  }
}

my $object = EmbedClass->new;

print $object->b1 . "\n"; # 3
print $object->b2 . "\n"; # 4
print "@{$object->ps}" . "\n"; # [1, 2, 3]

Use Other OO Module With Class::Plain

Class::Plain can be used with other OO modules.

Moo

Use Moo with Class::Plain.

use Class::Plain;

class Foo : isa() {
  field x;
  
  use Moo;
  has "x" => (is => 'rw');
  
  method to_string { "String:" . $self->x }
}

my $object = Foo->new(x => 1);
print $object->x . " " . $object->to_string;

Class::Accessor::Fast

Use Class::Accessor::Fast with Class::Plain.

use Class::Plain;

class Foo {
  field x;
  
  use base 'Class::Accessor::Fast';
  __PACKAGE__->mk_accessors('x');
  method to_string { "String:" . $self->x }
}

my $object = Foo->new(x => 1);
print $object->x . " " . $object->to_string;

Class::Accessor

Use Class::Accessor with Class::Plain.

use Class::Plain;

class Foo {
  field x;
  
  use base 'Class::Accessor::Fast';
  __PACKAGE__->mk_accessors('x');
  method to_string { "String:" . $self->x }
}

my $object = Foo->new(x => 1);
print $object->x . " " . $object->to_string;

Mojo::Base

Use Mojo::Base with Class::Plain.

use Class::Plain;

class Foo : isa() {
  field x;
  
  use Mojo::Base -base;
  has "x";
  
  method to_string { "String:" . $self->x }
}

my $object = Foo->new(x => 1);
print $object->x . " " . $object->to_string;

Weakening Field

Weaken a field.

use Scalar::Util 'weaken';

use Class::Plain;

class Foo {
  field x;
  
  method weaken_x {
    weaken $self->{x};
  }
}

Class Variable

A class variable is represented using a package variable or a lexical variable.

use Class::Plain;

class ClassVariable {
  # Public
  our $FOO;
  
  # Private
  my $BAR;
  
  BEGIN {
    $FOO = 1;
    $BAR = 2;
  }
  
  method FOO : common { $FOO }
  method BAR : common { $BAR }
}

ClassVariable->FOO: # 1
ClassVariable->BAR; # 2

Signatures

Use Class::Plain with subroutine signatures from Perl 5.26+.

use v5.36; # Enable signatures and other features.

use Class::Plain;

class Point {
  field x;
  field y;
  
  method new : common {
    my $self = $class->SUPER::new(@_);
    
    $self->{x} //= 0;
    $self->{y} //= 0;
    
    return $self;
  }
  
  # Subroutine signatures
  method move ($x = 0, $y = 0) {
    
    $self->{x} += $x;
    $self->{y} += $y;
  }
  
  method describe {
    print "A point at ($self->{x}, $self->{y})\n";
  }
}

my $point = Point->new(x => 5, y => 10);
$point->describe;