NAME Pony::Object - An object system. OVERVIEW If you wanna protected methods, abstract classes and other OOP stuff, 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. Also you 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' ); Without Objects If you like functions "say", "dump", "try"/"catch", you can use them without creating object. Use ":noobject" option to enable them but do not create object/making class. use Pony::Object qw/:noobject :try/; my $a = {deep => [{deep => ['structure']}]}; say dump $a; my $data = try { local $/; open my $fh, './some/file' or die; my $slurp = <$fh>; close $fh; return $slurp; } catch { return ''; }; say "\$data: $data"; 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 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.