NAME

Pony::Object - An object system.

OVERVIEW

If you wanna protected methods, abstract classes and other staff like with, you may use Pony::Object. Also Pony::Objects are strict and modern.

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;

Methods and properties

has

Keyword has declares new property. You also can define methods via has.

package News;
use Pony::Object;
  
  # Properties:
  has 'title';
  has text => '';
  has authors => [ qw/Alice Bob/ ];
  
  # Methods:
  has printTitle => sub {
    my $this = shift;
    say $this->title;
  };
  
  sub printAuthors
    {
      my $this = shift;
      print @{$this->authors};
    }
1;



package main;
use News;
my $news = new News;
$news->printAuthors();
$news->title = 'Sensation!'; # Yep, you can assign property's value via "=".
$news->printTitle();

new

Pony::Objects hasn't method new. In fact, of course they has. But new is an internal function, so you should not use new as name of method.

Instead of this Pony::Objects has init methods, 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;
use News;
my $news = new News('Big Event!');
print $news->lower;

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;
use News;
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;
use News;
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;
use News;
my $news = new News;
say $news->getAuthorString();

Static properties

Just say "static" and property will the same in all objects of class.

package News;
use Pony::Object;
  
  public static 'default_publisher' => 'Georgy';
  public 'publisher';
  
  sub init : Public
    {
      my $this = shift;
      $this->publisher = $this->default_publisher;
    }
  
1;



package main;
use News;

my $n1 = new News;
$n1->default_publisher = 'Bazhukov';
my $n2 = new News;
print $n1->publisher; # "Georgy"
print $n2->publisher; # "Bazhukov"

Default methods

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;
use News;
my $news = new News;
print $news->toHash()->{text};
print $news->to_h()->{title};

dump

Shows object's current struct.

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



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

Returns

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

Classes

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;



package main;
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.

Inside

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 (try, catch, finally blocks) by default. Use it carefully.

# 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.