perl teach-in (part 2)
TRANSCRIPT
What is Perl
Perl Teach-In
A One Day Perl Tutorial
Dave Cross
Magnum Solutions Ltd
Object Oriented Perl
Object Oriented Perl
How to design objects
Design Patterns
Inside-Out Objects
Moose
What We Won't Cover
Writing objects in Perl
Assume you already know that
perldoc perlboot
Object Oriented Perl Damian Conway
How To Design Objects
Designing Objects is hard - OO Barbie
Very few hard and fast rules
A few heuristics
A bit of experience
A bit of guesswork
Prototyping
Plan to throw one away; you will, anyhow
- Fred Brooks (The Mythical Man Month)
You won't get it right first time
Unless you're very lucky
Make it easy to refactor your code
Unit tests
Source code control
Subclassing
A good class is easy to subclass
Two argument bless
sub new {
my $class = shift;
my $self = {};
return bless $self, $class;
}
Constructor Tip
You'll often see code like this
sub new {
my $thing = shift;
my $class = ref $thing || $thing;
return bless {}, $class;
}
Don't do that
Confusing Methods
The previous constructor can be called as a class method or an instance method
my $obj = MyClass->new;
my $obj2 = $obj->new;
Potentially confusing
What does $obj->new do?
Clone?
Separate Methods
Class method creates a new, empty, object
sub new {
my $class = shift;
return bless {}, $class;
}
Separate Methods
Instance method creates a copy of an object
sub clone {
my $self = shift;
# warning! simplified! Buggy!
return bless { %$self },
ref $self;
}
Multiple Constructors
In Perl an constructor is just a subroutine
new is not a keyword
You can have as many constructors as you want
They can be called whatever you want
But using new for the standard constructor is recommended
new is Not a Keyword
People coming from other languages often write
my $obj = new MyObject;
This is potentially dangerous
See "perldoc perlobj" for gory details
Most of the time it will be fine
But avoid it
my $obj = MyObject->new;
Overriding Methods
Subclasses are created so that methods can be overridden
Or so that new methods can be added
Make it as easy as possible to subclass your classes
Create many methods
Case Study
I needed to create a new graph type for GD::Graph
Waterfall graph
Based on bar chart
Subclassing GD::Graph::bars
Bar Chart
Waterfall Chart
Things to Override
Colour choosing
pick_data_clr
Legend drawing
???
The author didn't envisage my use case
I ended up copying far too much code
Be Consistent
A good object design is consistent
Similar things act in similar ways
Good candidates for programming standards
Some examples
Accessor vs Mutator
Or "getter vs setter"
Some people like one method foo
Works out what to do based on parameters
Some people like get_foo and set_foo
Pick one and stick to it
Mutator Return Values
What does a mutator return?
The old value
The new value
The object
Nothing
Pick one and stick to it
Don't Always Subclass
Not all relationships are "isa_a"
Sometimes "has_a" is more appropriate
If you're connecting to a database
Don't subclass DBI
Have a DBI attribute
Design Patterns
Perl does have some design patterns
Some of them come from Design Patterns
Some are more "Perlish"
Factory Object
Call constructor on one class
Constructor works out what is the most appropriate class to use
Returns an object of the appropriate class
Often not the same class as the constructor was called on
E.g. DBI->connect
AudioFile::Info
There are many Perl modules for reading tags from MP3 files
MP3::ID3Lib
MP3::Info
MP3::Tag
And a couple for reading tags from Ogg Vorbis files
Ogg::Vorbis::Header
Ogg::Vorbis::Header::PurePerl
Using AudioFile::Info
AudioFile::Info simplifies reading tag information from audio files
One syntax across numerous modules
$song = AudioFile::Info->new('a_song.mp3');
print $song->title, ' - ', $song->artist;
$song2 = AudioFile::Info->new('a_song.ogg');
print $song2->title, ' - ', $song2->artist;
print ref $song;
# AudioFile::Info::MP3::Tag
print ref $song2;
# AudioFile::Info::Ogg::Vorbis::Header
AudioFile::Info->new
Works out which kind of file it has been given
Works out the best installed module to handle that kind of file
Loads the appropriate module
Calls the constructor
Returns the new object
Singleton Pattern
Highlander pattern
There can be only one
Only ever one instance of the class
If an instance has been created then use that
Otherwise create new instance
Singleton Class
package MySingleton;
my $single;
sub new {
my $class = shift;
unless ($single) {
$single = bless {}, $class;
}
return $single;
}
More Design Patterns
See Perl Design Patterns Wiki
http://perldesignpatterns.com/
Inside-Out Objects
Standard Perl objects are usually based on hashes
bless { name => 'Dave',
email => '[email protected]' },
'Person';
Two problems
People can access attributes directly
People can add attributes easily
Accessing Attributes
$person->{name} = '';
Avoids any checks in the mutator method
sub set_name {
my $self = shift;
my $name = shift;
croak "Name can't be empty"
unless $name;
$self->{name} = $name;
}
Adding Attributes
No checks on adding entries to the hash
$person->{nick} = 'davorg';
Our class knows nothing about this attribute
No check on mistyped attributes
$person->{NAME} = 'dave';
Inside-Out Objects
Inside-out objects solve both of these problems
An object is no longer a hash containing attributes
Each attribute is a package variable
A hash
Key is unique identifier for object
Value is the attribute value for that object
Example
package Person;
use strict;
my %name;
my %email;
sub new {
my $self = bless {}, shift;
$name{$self} = shift;
$email{$self} = shift;
return $self;
}
Example (cont)
sub get_name {
my $self = shift;
return $name{$self};
}
sub set_name {
my $self = shift;
my $name = shift;
croak "name cannot be empty" unless $name;
$name{$self} = $name;
}
How It Works
The object is still a hash reference
Still blessed into the correct class
But it contains no data
All data is stored in the lexical variable hashes
Hence the name - Inside-Out
Solving Problems
People can access attributes directly
Attributes are now stored in lexical variables
Only visible from within package
All access is through methods
People can add attributes easily
Attribute names are now the names of lexical variables
use strict ensures that variable names can't be mistyped
One Improvement
The object is still a blessed hash
But we never put anything into it
So it may as well be a blessed scalar
sub new {
my $self = bless \(my $dummy),
shift;
$name{$self} = shift;
$email{$self} = shift;
return $self;
}
No anonymous scalars
One New Problem
When our objects go out of scope, the blessed scalar ceases to exist
But the values still exist in the attribute hashes
Need a DESTROY method
sub DESTROY {
my $self = shift;
delete $name{$self};
delete $email{$self};
}
More Stuff
Need to handle inheritance
Automation of inside-out objects
Class::Std
Class::InsideOut
Object::InsideOut
See also Perl Best Practices (Damian Conway)
Moose
A complete modern object system for Perl 5
Based on experiments with Perl 6 object model
Built on top of Class::MOP
MOP - Meta Object Protocol
Set of abstractions for components of an object system
Classes, Objects, Methods, Attributes
An example might help
Moose Example
package Point;
use Moose;
has 'x' => (isa => 'Int',
is => 'ro');
has 'y' => (isa => 'Int',
is => 'rw');
sub clear {
my $self = shift;
$self->{x} = 0;
$self->y(0);
}
Understanding Moose
There's a lot going on here
use Moose
Loads Moose environment
Makes our class a subclass of Moose::Object
Turns on strict and warnings
Creating Attributes
has 'x' => (isa => 'Int',
is => 'ro')
Creates an attribute called 'x'
Constrainted to be an integer
Read-only accessor
has 'y' => (isa => 'Int',
is => 'rw')
Defining Methods
sub clear {
my $self = shift;
$self->{x} = 0;
$self->y(0);
}
Standard method syntax
Uses generated method to set y
Direct hash access for x
Subclassing
package Point3D;
use Moose;
extends 'Point';
has 'z' => (isa => 'Int');
after 'clear' => sub {
my $self = shift;
$self->{z} = 0;
};
Subclasses
extends 'Point'
Similar to use base
Overwrites @ISA instead of appending
has 'z' => (isa = 'Int')
Adds new attribute 'z'
No accessor function - private attribute
Extending Methods
after 'clear' => sub {
my $self = shift;
$self->{z} = 0;
};
New clear method for subclass
Called after method for superclass
Cleaner than $self->SUPER::clear()
Creating Objects
Moose classes are used just like any other Perl class
$point = Point->new(x => 1,
y => 2);
$p3d = Point3D->new(x => 1,
y => 2,
z => 3);
More Moose
Only scratching the surface
Many more options
Moose is well worth investigating
perldoc Moose::Cookbook::*
Configuration Files
Configuration Files
Can you just add...?
Users are never satisfied
Always want something changed
Most users won't edit code
Most users can be trained to edit config files
Move as much as possible into config files
Configuration in Code
This is bad
#!/usr/bin/perl
use strict;
use warnings;
## Configuration
my $debug = 0;
my $email = '[email protected]';
my $output_file = 'output.txt';
## DO NOT EDIT BEYOND THIS POINT
Why is This Bad?
Don't trust 'em
Something will get broken
Code doesn't match what is in source code control
Recipe for disaster
Don't do it
Windows INI Files
[debugging]
debug=1
verbose=0
Most users will understand this
Provide them with a dry-run option
Tell them what would happen
Parse with Config::IniFiles
XML
1
0
or
Too complicated
Parse with XML::Simple (or XML::LibXML / XML::XPath)
YAML
---
debugging:
debug: 1
verbose: 0
Looks a bit like INI file
Human-readable
Still give them a dry-run option
Parse with YAML
Swiss Army Config Parser
Config::Auto
"Magical config file parser"
Guesses where your config file is
Guesses what format it is in
And usually gets it right
Other Places
Environment variables
Command line options
Parse with Getopt::Long
Need to establish an order of precedence
$debug = defined $opt{debug} ? $opt{debug} :
defined $ENV{DEBUG} ? $ENV{DEBUG} :
defined $conf{debug} ? $conf{debug} :
0;
Web 2.0 Perl
Web 2.0 Perl
Mashups
Data Feeds
APIs
Ajax
Don't need to be using Ruby on Rails
CPAN modules can help
Reading Web Feeds
A lot of data available as web feeds
RSS / Atom
But which version of RSS
RDF vs RSS
Parsing RSS
XML::RSS
use XML::RSS;
my $rss = XML::RSS->new;
$rss->parsefile('myfeed.rss');
foreach (@{$rss->{items}}) {
print $_->{title}, "\n";
print $_->{link}, "n";
}
Supports RSS 0.9, 0.91, 1.0 and 2.0
Most of the versions you'll see in the wild
Parsing Atom
XML::Atom
use XML::Atom::Feed;
my $atom = XML::Atom::Feed->new('myatom.xml');
foreach ($atom->entries) {
print $_->title, "\n";
print $_->link, "\n";
}
Cleverer than XML::RSS
Handles things like autodiscovery
my @feeds =
XML::Atom::Feed->find_feeds
('http://example.com/');
Parsing RSS and Atom
XML::Feed uses XML::RSS or XML::Atom as appropriate
Allows code to handle all web feeds.
use XML::Feed;
my $feed = XML::Feed->parse('feed.xml');
print $feed->title;
foreach ($feed->entries) {
print $_->title;
}
Parsing Broken Feeds
Not all XML feeds are valid XML
This is bad!
You should complain bitterly to the provider
But until it is fixed you can use XML::Liberal
Slightly badly named
What it parses isn't XML
Mashing Up Web Feeds
Plagger - Pluggable RSS/Atom Aggregator
Huge distribution, installs half of CPAN
Dozens of small plugins
Single program (plagger)
YAML configuration file
Web Services APIs
Many web sites expose web services
REST, RPC, SOAP
HTTP request
Parse response
Usually XML
Or JSON
Web Services on CPAN
Many CPAN modules for handling web services
Wrappers around LWP or WWW::Mechanize
Parse response into data structures or objects
Make dealing with web services very easy
CPAN Examples
Net::Backpack
Net::Amazon::*
Flickr::API
Geo::Google
Geo::Coder::Yahoo
API Keys
Many of these sites will monitor the requests you make
Use an API key
Apply for the key on the web site
Use the key in every request you use
API Example: Flickr
Get details of photos
Details at http://www.flickr.com/services/api/
Many methods
Perl module gives low level access
Need to know the API pretty well
Flickr API
#!/usr/bin/perl
use strict;
use warnings;
use Flickr::API;
my $flickr = Flickr::API->new({
key => 'your key goes here'
});
my $response = $flickr->execute_method(
'flickr.photos.getRecent',
{ per_page => 2 }
);
print $response->content;
Flickr API Results
APIs Without CPAN
You might find an API that doesn't have a CPAN module
Easy to do it yourself
Read the API documentation
LWP / WWW::Mechanize
Parse the response
(Release to CPAN)
Ajax
You don't need to be using Ruby on Rails to use AJAX
AJAX is largely just Javascript
With a server-side application
Which can be written in Perl
Ajax on CPAN
CGI::Ajax
Creates AJAX code in your CGI program output
Similar to Ruby on Rails AJAX helpers
JSON
Perl module for creating JSON
Common format for AJAX data exchange
Serialised Javascript Objects
A lot like YAML
Further Information
Further Information
Some suggestions for places to go for further information
Web sites
Books
Magazines
Mailing lists
Conferences
Copenhagen Perl Mongers
http://copenhagen.pm.org/
Mailing list
Regular meetings
Nordic Perl Workshop
YAPC::Europe
Many other local Perl Monger groups
http://pm.org/
Web Sites
use Perl;
Perl news site
Also journals
perl.com
O'Reilly run site
High quality articles
Web Sites
Perl Monks
Best web site for Perl questions
Many Perl experts
The Perl directory
http://perl.org/
Lists of many Perl-related sites
Books
Some recent Perl books
Perl Best Practices - Damian Conway
Advanced Perl Programming - Simon Cozens
Perl Hacks - chromatic, Conway & Poe
Intermediate Perl - Schwartz, foy & Phoenix
Mastering Perl - brian d foy
More Books
Higher Order Perl - Mark-Jason Dominus
Minimal Perl - Tim Maher
Pro Perl Debugging - Richard Foley & Joe McMahon
Perl & LWP - Sean M Burke
Updated online edition
http://lwp.interglacial.com/
See http://books.perl.org/
Magazines
The Perl Review
http://www.theperlreview.com/
Randal's monthly columns
Linux Magazine
SysAdmin
Mailing Lists
Many mailing lists devoted to Perl topics
See http://lists.cpan.org/
Conferences
The Open Source Convention
Portland 21-25 July 2008
YAPC
Chicago 16-18 June 2008
Copenhagen 13-15 August 2008
Brazil, Asia, Israel, Australia
One-Day Perl Workshops
See http://yapc.org/
The End
That's all folks
Any questions?
Click to edit the title text format
Click to edit the outline text format
Second Outline Level
Third Outline Level
Fourth Outline Level
Fifth Outline Level
Sixth Outline Level
Seventh Outline Level
Eighth Outline Level
Ninth Outline Level
YAPC::Europe12th August 2008