NAME

Pony::Object is the object system.

OVERVIEW

Pony::Object is an object system, which provides simple way to use cute objects.

SYNOPSIS

# Class: MyArticle (Example)
#   Abstract class for articles.

package MyArticle;
use Pony::Object qw(-abstract :exceptions);
use MyArticle::Exception::IO; # Based on Pony::Object::Throwable class.
  
  protected date => undef;
  protected authors => [];
  public title => '';
  public text => '';
  
  
  # Function: init
  #   Constructor.
  #
  # Parameters:
  #   date - Int
  #   authors - ArrayRef
  
  sub init : Public
    {
      my $this = shift;
      ($this->date, $this->authors) = @_;
    }
  
  
  # Function: getDate
  #   Get formatted date.
  #
  # Returns:
  #   Str
  
  sub getDate : Public
    {
      my $this = shift;
      return $this->dateFormat($this->date);
    }
  
  
  # Function: dateFormat
  #   Convert Unix time to good looking string. Not implemented.
  #
  # Parameters:
  #   date - Int
  #
  # Returns:
  #   String
  
  sub dateFormat : Abstract;
  
  
  # Function: fromPdf
  #   Trying to create article from pdf file.
  #
  # Parameters:
  #   file - Str - pdf file.
  
  sub fromPdf : Public
    {
      my $this = shift;
      my $file = shift;
      
      try {
        open F, $file or
          throw MyArticle::Exception::IO(action => "read", file => $file);
        
        # do smth
        
        close F;
      } catch {
        my $e = shift; # get exception object
        
        if ($e->isa('MyArticle::Exception::IO')) {
          # handler for MyArticle::Exception::IO exceptions
        }
      };
    }
  
1;

DESCRIPTION

When some package uses Pony::Object, it becomes strict and modern (can use perl 5.10 features like as say). Also dump function is redefined and shows data structure. It's useful for debugging.

Specific moments

Besides new function dump Pony::Object has other specific moments.

has

Keyword has declares new fields. All fields are public. You can also describe object methods via has... If you want.

package News;
use Pony::Object;

  # Fields
  has 'title';
  has text => '';
  has authors => [ qw/Alice Bob/ ];
  
  # Methods
  sub printTitle
    {
      my $this = shift;
      say $this->title;
    }

  sub printAuthors
    {
      my $this = shift;
      print @{$this->authors};
    }
1;

package main;

my $news = new News;
$news->printAuthors();
$news->title = 'Something important';
$news->printTitle();

Pony::Object fields assigned via "=". For example: $obj->field = 'a'.

new

Pony::Objects hasn't method new. In fact, of course they has. But new is an internal function, so you should not use it if you don't want more "fun". Instead of this Pony::Object has init function, where you can write the same, what you wish write in new. init is after-hook for new.

package News;
use Pony::Object;
  
  has title => undef;
  has lower => undef;
  
  sub init
    {
      my $this = shift;
      $this->title = shift;
      $this->lower = lc $this->title;
    }
  
1;

package main;

my $news = new News('Big Event!');

print $news->lower;

toHash or to_h

Get object's data structure and return this as a hash.

package News;
use Pony::Object;
  
  has title => 'World';
  has text => 'Hello';
  
1;

package main;

my $news = new News;
print $news->toHash()->{text};
print $news->to_h()->{title};

dump

Return string which shows object's current struct.

package News;
use Pony::Object;

  has title => 'World';
  has text => 'Hello';
  
1;

package main;

my $news = new News;
$news->text = 'Hi';
print $news->dump();

Returns

$VAR1 = bless( {
  'text' => 'Hi',
  'title' => 'World'
}, 'News' );

public, protected, private properties

You can use has keyword to define property. If your variable starts with "_", variable becomes protected. "__" for private.

package News;
use Pony::Object;

  has text => '';
  has __authors => [ qw/Alice Bob/ ];
  
  sub getAuthorString
    {
      my $this = shift;
      return join(' ', @{$this->__authors});
    }
  
1;

package main;

my $news = new News;
say $news->getAuthorString();

The same but with keywords public, protected and private.

package News;
use Pony::Object;

  public text => '';
  private authors => [ qw/Alice Bob/ ];
  
  sub getAuthorString
    {
      my $this = shift;
      return join(' ', @{$this->authors});
    }
  
1;

package main;

my $news = new News;
say $news->getAuthorString();

Public, Protected, Private methods

Use attributes Public, Private and Protected to define method's access type.

package News;
use Pony::Object;

  public text => '';
  private authors => [ qw/Alice Bob/ ];
  
  sub getAuthorString : Public
    {
      return shift->joinAuthors(', ');
    }
  
  sub joinAuthors : Private
    {
      my $this = shift;
      my $delim = shift;
      
      return join( $delim, @{$this->authors} );
    }
1;

package main;

my $news = new News;
say $news->getAuthorString();

Inheritance

You can define base classes via use params. For example, use Pony::Object 'Base::Class';

package BaseCar;
use Pony::Object;
  
  public speed => 0;
  protected model => "Base Car";
  
  sub get_status_line : Public
    {
      my $this = shift;
      my $status = ($this->speed ? "Moving" : "Stopped");
      return $this->model . " " . $status;
    }
  
1;

package MyCar;
# extends BaseCar
use Pony::Object qw/BaseCar/;
  
  protected model => "My Car";
  protected color => undef;
  
  sub set_color : Public
    {
      my $this = shift;
      ($this->color) = @_;
    }
  
1;

use MyCar;
my $car = new MyCar;
$car->speed = 20;
$car->set_color("White");
print $car->get_status_line();
# "My Car Moving"

Singletons

Pony::Object has simple syntax for singletons . You can declare this via use param;

package Notes;
use Pony::Object 'singleton';
  
  protected list => [];
  
  sub add : Public
    {
      my $this = shift;
      push @{ $this->list }, @_;
    }
  
  sub show : Public
    {
      my $this = shift;
      say for @{$this->list};
    }
  
  sub flush : Public
    {
      my $this = shift;
      $this->list = [];
    }
  
1;

package main;
use Notes;

my $n1 = new Notes;
my $n2 = new Notes;

$n1->add(qw/eat sleep/);
$n1->add('Meet with Mary at 8 o`clock');

$n2->flush;

$n1->show();  # Print nothing.
              # Em... When I should meet Mary? 

Abstract methods and classes

You can use abstract methods and classes follows way:

# Let's define simple interface for texts.
package Text::Interface;
use Pony::Object -abstract; # Use 'abstract' or '-abstract'
                            # params to define abstract class.
  
  sub getText : Abstract; # Use 'Abstract' attribute to
  sub setText : Abstract; # define abstract method.
  
1;

# Now we can define base class for texts.
# It's abstract too but now it has some code.
package Text::Base;
use Pony::Object qw/abstract Text::Interface/;
  
  protected text => '';
  
  sub getText : Public
    {
      my $this = shift;
      return $this->text;
    }
  
1;

# In the end we can write Text class.
package Text;
use Pony::Object 'Text::Base';
  
  sub setText : Public
    {
      my $this = shift;
      $this->text = shift;
    }
  
1;

# Main file.
package main;
use Text;
use Text::Base;

my $textBase = new Text::Base;  # Raises an error!

my $text = new Text;
$text->setText('some text');
print $text->getText();   # Returns 'some text';

Don't forget, that perl looking for functions from left to right in list of inheritance. You should define abstract classes in the end of Pony::Object param list.

Exceptions

See Pony::Object::Throwable.

ALL

If you wanna get all default values of Pony::Object-based class, you can call ALL method. I don't know why you need them, but you can.

package News;
use Pony::Object;
  
  has 'title';
  has text => '';
  has authors => [ qw/Alice Bob/ ];
  
1;

package main;
my $news = new News;
print for keys %{ $news->ALL() };

META

One more internal method. It provides access to special hash %META. You can use this for Pony::Object introspection. It can be changed in next versions.

my $news = new News;
say dump $news->META;

$Pony::Object::DEFAULT

This is a global variable. It defines default Pony::Object's params. For example you can set $Pony::Object::DEFAULT-{''}->{withExceptions} = 1> to enable exceptions by default. Use it carefully. Use this if you sure, that this is smaller evil.

# Startup script
...
use Pony::Object;

BEGIN {
  # Use exceptions by default.
  $Pony::Object::DEFAULT->{''}->{withExceptions} = 1;
  # All classes will extends Default::Base.
  $Pony::Object::DEFAULT->{''}->{baseClass} = [qw/Default::Base/];
  # All classes in namespace "Default::NoBase" will not.
  $Pony::Object::DEFAULT->{'Default::NoBase'}->{baseClass} = [];
}
...

One more example:

# Startup script
...
use Pony::Object;

BEGIN {
  $Pony::Object::DEFAULT->{'My::Awesome::Project'} = {
    withExceptions => 1,
    baseClass => [],
  };
  
  $Pony::Object::DEFAULT->{'My::Awesome::Project::Model'} = {
    withExceptions => 1,
    baseClass => [qw/My::Awesome::Project::Model::Abstract/],
  };
}
...

SEE

Git

https://github.com/h15/pony-object

COPYRIGHT AND LICENSE

Copyright (C) 2011 - 2013, Georgy Bazhukov.

This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.