perl teach-in (part 2)

Download Perl Teach-In (part 2)

If you can't read please download the document

Upload: dave-cross

Post on 16-Apr-2017

6.733 views

Category:

Technology


0 download

TRANSCRIPT

What is Perl

Perl Teach-In

A One Day Perl Tutorial

Dave Cross

Magnum Solutions Ltd

[email protected]

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