introduction to modern perl
TRANSCRIPT
What is Perl
Introducing
Modern Perl
Dave CrossMagnum Solutions [email protected]
Modern Perl
Perl has been around for a long time
Achieved great popularity in the 1990s
The duct tape of the internet
Perl has moved on a lot since then
Many people's perceptions of Perl haven't
Modern Perl
Keeping up to date with Perl
Surveying modern modules and techniques
A lot to cover
Only an overview
Plenty of pointers to more information
What We Will Cover
Modern Core Perl
Template Toolkit
DateTime
DBIx::Class
TryCatch
What We Will Cover
Moose
autodie
Catalyst
PSGI/Plack
Schedule
10:00 Start
11:30 11:45 Coffee
13:00 14:00 Lunch
15:30 15:40 Coffee
18:00 End
18:00 Pre-Conference Meeting
Resources
Slides available on-linehttp://mag-sol.com/train/yapc/2011
Also see Slidesharehttp://www.slideshare.net/davorg/slideshows
Get Satisfactionhttp://getsatisfaction.com/magnum
Modern Core Perl
Perl Releases
Perl 5 has moved to a regular release cycle
Major release every year
Minor releases when required
Release Numbering
Even major numbers are production releases5.10, 5.12, 5.14
Odd major numbers are dev releases5.11, 5.13, 5.15
Perl 5.10
Released 18th Dec 2007Perl's 20th birthday
Many new features
Well worth upgrading
New Features
Defined-or operator
Switch operator
Smart matching
say()
Lexical $_
New Features
State variables
Stacked file tests
Regex improvements
Many more
Defined Or
Boolean expressions short-circuit
$val = $val || $default;
$val ||= $default;
What if 0 is a valid value?
Need to check definedness
$val = defined $val
? $val : $default;
$val = $default unless defined $val;
Defined Or
The defined or operator makes this easier
$val = $val // $default;
A different slant on truth
Checks definedness
Shortcircuit version too
$val //= $value;
Switch Statement
Switch.pm was added with Perl 5.8
Source filter
Parser limitationsRegular expressions
eval
5.10 introduces a build-in switch statement
Given ... When
Switch is spelled given
Case is spelled when
Powerful matching syntax
Given Example
given ($foo) {
when (/^abc/) { $abc = 1; }
when (/^def/) { $def = 1; }
when (/^xyz/) { $xyz = 1; }
default { $nothing = 1; }
}
New Keywords
Four new keywordsgiven
when
default
continue
given
given(EXPR)
Assigns the result of EXPR to $_ within the following block
Similar to do { my $_ = EXPR; ... }
when
when (EXPR)
Uses smart matching to compare $_ with EXPR
Equivalent to when ($_ ~~ EXPR)
~~ is the new smart match operator
Compares two values and does the right thing
default
default defines a block that is executed if no when blocks match
default block is optional
continue
continue keyword falls through to the next when block
Normal behaviour is to break out of given block once the first when condition is matched
continue
given($foo) {
when (/x/)
{ say '$foo contains an x';
continue }
when (/y/)
{ say '$foo contains a y' }
default
{ say '$foo contains no x or y' }
}
Smart Matching
~~ is the new Smart Match operator
Different kinds of matches
Dependent on the types of the operands
See perldoc perlsyn for the full details
CAVEAT: Subject to change
Smart Match Examples
$foo ~~ $bar; # == or cmp
@foo ~~ $bar; # array contains value
%foo ~~ $bar; # hash key exists
$foo ~~ qr{$bar}; # regex match
@foo ~~ @bar; # arrays are identical
%foo ~~ %bar; # hash keys match
Many more alternatives
say()
say() is a new alternative to print()
Adds a new line at the end of each call
say($foo); # print $foo, \n;
Two characters shorter than print
Less typing
Lexical $_
$_ is a package variable
Always exists in main package
Can lead to subtle bugs when not localised correctly
Can now use my $_ to create a lexically scoped variable called $_
State Variables
Lexical variables disappear when their scope is destroyed
sub variables {
my $x;
say ++$x;
}
variables() for 1 .. 3;
State Variables
State variables retain their value when their scope is destroyed
sub variables {
state $x;
say ++$x;
}
variables() for 1 .. 3;
Like static variables in C
Stacked File Tests
People often think you can do this
-f -w -x $file
Previously you couldn't
Now you can
Equivalent to
-x $file && -w _ && -f _
Regex Improvements
Plenty of regular expression improvements
Named capture buffers
Possessive quantifiers
Relative backreferences
New escape sequences
Many more
Named Capture Buffers
Variables $1, $2, etc change if the regex is altered
Named captures retain their names
(? ... ) to define
Use new %+ hash to access them
Named Capture Example
while () {
if (/(?[\w\s]+)
:\s+(?.+)/x) {
print "$+{header} -> ";
print "$+{value}\n";
}
}
Possessive Quantifiers
?+, *+, ++
Grab as much as they can
Never give it back
Finer control over backtracking
'aaaa' =~ /a++a/
Never matches
Relative Backreferences
\g{N}
More powerful version of \1, \2, etc
\g{1} is the same as \1
\g{-1} is the last capture buffer
\g{-2} is the one before that
New Escape Sequences
\h Horizontal white space
\v Vertical white space
Also \H and \V
Accessing New Features
Some new features would break backwards compatibility
They are therefore turned off by default
Turn them on with the feature pragma
use feature 'say';
use feature 'switch';
use feature 'state';
use feature ':5.10';
Implicit Loading
Two ways to automatically turn on 5.10 features
Require a high enough version of Perl
use 5.10.0; # Or higher
-E command line option
perl -e 'say hello'
perl -E 'say hello'
Perl 5.12
Released 12 April 20105.12.4 20 June 2011
Many new enhancements
5.12 Enhancements
Smart match changes
New modulesautodie
parent
5.12 Enhancements
package NAME VERSION syntax
... operator
Implicit strictures
Y2038 compliance
... Operator
Called the yada-yada operator
Used to stand in for unwritten code
sub unimplemented {
...
}
Code compiles
Throws an unimplemented exception when run
package NAME VER
Declare the version of a package in the package declaration
package My::Package 1.23;
Equivalent to
package My::Package;
our $VERSION = 1.23;
Implicit Strictures
Requiring a version of Perl greater than 5.11 implicitly turns on use strict
use 5.12.0;
Is equivalent to
use strict;
use feature ':5.12';
Y2038 Compliance
Core time functions are now Y2038 compliant
Smart Match Changes
Some changes to Smart Match operator
No longer commutative
See new table in perlsyn
CAVEAT: More changes coming
New Modules
Some new modules in the standard distribution
autodie
parentBetter version of base.
Perl 5.14
Released 14 May 20115.14.1 16 June 2011
Many new enhancements
5.16 due spring 2012
5.14 Enhancements
Non-destructive substitution
Container functions accept references
Package block
New modules
Non-destructive substitution
New /r option on s/// and tr///
Copies input
Acts on copy
Original unmodifed
$_ = 'cat';
$new = s/cat/dog/r'; # $_ remains 'cat'
Container functions accept references
Array & hash functions used to require arrays or hashespush @array, $value
@keys = keys %hash
Even if you have a referencepush @$arrayref, $value
@keys = keys %$hashref
Container functions accept references
Array & hash functions now accept referencespush $array_ref, $value
@keys = keys $hash_ref
Currently experimental
Package block
Attach a code block to a package declaration
package MyPackage { ... }
Equivalent to
{ package MyPackage; ... }
Can also declare a version
package MyPackage 1.23 { ... }
New Modules
Many modules for parsing META files
CPAN::Meta::YAML & JSON::PP
CPAN::Meta
CPAN::Meta::Spec & CPAN::Meta::History
Module::Metadata
New Modules
Other new modules
CPAN::Meta::YAML & JSON::PP
CPAN::Meta
CPAN::Meta::Spec & CPAN::Meta::History
Module::Metadata
More Information
perldoc perl5100delta
perldoc perl5120delta
Perldoc perl5140delta
Template Toolkit
Templates
Many people use templates to produce web pages
Advantages are well known
Standard look and feel (static/dynamic)
Reusable components
Separation of code logic from display logic
Different skill-sets (HTML vs Perl)
DIY Templating
Must be easy - so many people do it
See perlfaq4
How can I expand variables in text strings?
DIY Templating
$text =
'this has a $foo in it and a $bar';
%user_defs = (
foo => 23,
bar => 19,
);
$text =~ s/\$(\w+)/$user_defs{$1}/g;
Don't do that
Templating Options
Dozens of template modules on CPAN
Text::Template, HTML::Template, Mason, Template Toolkit
Many, many more
Questions to considerHTML only?
Template language
Template Toolkit
http://tt2.org/
Very powerful
Both web and non-web
Simple template language
Plugins give access to much of CPAN
Can use Perl code if you wantBut don't do that
Good Book Too!
The Template Equation
Data + Template = Output
Data + Alternative Template = Alternative Output
Different views of the same data
Only the template changes
Simple TT Example
use Template;
use My::Object;
my ($id, $format) = @ARGV;
$format ||= 'html';
my $obj = My::Object->new($id)
or die;
my $tt = Template->new;
$tt->process("$format.tt",
{ obj => $obj },
"$id.$format")
or die $tt->error;
html.tt
[% obj.name %]
[% obj.name %]
[% obj.desc %]
[% FOREACH child IN obj.children -%]-
[% child.name %]
[% END %]
text.tt
[% obj.name | upper %]
Image: [% obj.img %]
[% obj.desc %]
[% FOREACH child IN obj.children -%]
* [% child.name %]
[% END %]Adding New Formats
No new code required
Just add new output template
Perl programmer need not be involved
Equation Revisited
Data + Template = OutputTemplate Toolkit
Template + Output = DataTemplate::Extract
Data + Output = TemplateTemplate::Generate
DateTime
Dates & Times
Perl has built-in functions to handle dates and times
time seconds since 1st Jan 1970
localtime convert to human-readable
timelocal (in Time::Local) inverse of localtime
strftime (in POSIX) formatting dates and times
Dates & Times on CPAN
Look to CPAN for a better answer
Dozens of date/time modules on CPAN
Date::Manip is almost never what you want
Date::Calc, Date::Parse, Class::Date, Date::Simple, etc
Which one do you choose?
Perl DateTime Project
http://datetime.perl.org/
"The DateTime family of modules present a unified way to handle dates and times in Perl"
"unified" is good
Dozens of modules that work together in a consistent fashion
Using DateTime
use DateTime;
my $dt = DateTime->now;
say $dt; # 2010-08-02T10:06:07
say $dt->dmy; # 2010-08-02
say $dt->hms; # 10:06:07Using DateTime
use DateTime;
my $dt = DateTime->new(year => 2010,
month => 8,
day => 2);
say $dt->ymd('/'); # 2010/08/02
say $dt->month; # 8
say $dt->month_name; # AugustArithmetic
A DateTime object is a point in time
For date arithmetic you need a duration
Number of years, weeks, days, etc
Arithmetic
use DateTime;
my $dt = DateTime->new(year => 2010,
month => 8,
day => 2);
my $two_weeks =
DateTime::Duration->new(weeks => 2);
$dt += $two_weeks;
say $dt;
# 2010-08-16T00:00:00Formatting Output
use DateTime;
my $dt = DateTime->new(year => 2010,
month => 4,
day => 14);
say $dt->strftime('%A, %d %B %Y');
# Wednesday, 14 April 2010strftime uses UNIX standards
Control input format with DateTime::Format::Strptime
Parsing & Formatting
Ready made parsers and formatters for popular date and time formats
DateTime::Format::HTTP
DateTime::Format::MySQL
DateTime::Format::Excel
DateTime::Format::Babythe big hand is on...
Alternative Calendars
Handling non-standard calendars
DateTime::Calendar::Julian
DateTime::Calendar::Hebrew
DateTime::Calendar::Mayan
DateTime::Fiction::JRRTolkien::Shire
Calendar Examples
use DateTime::Calendar::Mayan;
my $dt = DateTime::Calendar::Mayan->now;
say $dt->date; # 12.19.17.9.13use DateTime::Fiction::JRRTolkien::Shire;
my $dt =
DateTime::Fiction::JRRTolkien::Shire->now;
say $dt->on_date; # Trewsday 14 Afterlithe 7474DBIx::Class
Object Relational Mapping
Mapping database relations into objects
Tables (relations) map onto classes
Rows (tuples) map onto objects
Columns (attributes) map onto attributes
Don't write SQL
SQL Is Tedious
Select the id and name from this table
Select all the details of this row
Select something about related tables
Update this row with these values
Insert a new record with these values
Delete this record
Replacing SQL
Instead of
SELECT *
FROM my_table
WHERE my_id = 10and then dealing with the prepare/execute/fetch code
Replacing SQL
We can write
use My::Object;
# warning! not a real orm
my $obj = My::Object->retrieve(10)Or something similar
Writing An ORM Layer
Not actually that hard to do yourself
Each class needs an associated table
Each class needs a list of columns
Create simple SQL for basic CRUD operations
Don't do that
Perl ORM Options
Plenty of choices on CPAN
Class::DBI
Rose::DB::Object
ORLite
DBIx::ClassThe current favourite
Fey::ORM
DBIx::Class
Standing on the shoulders of giants
Learning from problems in Class::DBI
More flexible
More powerful
DBIx::Class Example
Modeling a CD collection
Three tables
artist (artistid, name)
cd (cdid, artist, title)
track (trackid, cd, title)
Main Schema
Define main schema class
Music/DB.pm
package Music::DB;
use base qw/DBIx::Class::Schema/;
__PACKAGE__->load_classes();
1;Object Classes - Artist
Music/DB/Artist.pm
package Music::DB::Artist;
use base qw/DBIx::Class/;
__PACKAGE__->load_components(qw/Core/);
__PACKAGE__->table('artist');
__PACKAGE__->add_columns(qw/ artistid
name /);
__PACKAGE__->set_primary_key('artistid');
__PACKAGE__->has_many(cds =>
'Music::DB::Cd');
1;Object Classes- CD
Music/DB/CD.pm
package Music::DB::CD;
use base qw/DBIx::Class/;
__PACKAGE__->load_components(qw/Core/);
__PACKAGE__->table('cd');
__PACKAGE__->add_columns(qw/ cdid artist
title year /);
__PACKAGE__->set_primary_key('cdid');
__PACKAGE__->belongs_to(
artist => 'Music::DB:Artist');
1;Inserting Artists
my $schema =
Music::DB->connect($dbi_str);
my @artists = ('Florence + The Machine',
'Belle and Sebastian');
my $art_rs = $schema->resultset('Artist');
foreach (@artists) {
$art_rs->create({ name => $_ });
}Inserting CDs
Hash of Artists and CDs
my %cds = (
'Lungs' =>
'Florence + The Machine',
'The Boy With The Arab Strap' =>
'Belle and Sebastian',
'Dear Catastrophe Waitress' =>
'Belle and Sebastian',
);Inserting CDs
Find each artist and insert CD
foreach (keys %cds) {
my ($artist) = $art_rs->search(
{ name => $cds{$_} }
);
$artist->add_to_cds({
title => $_,
});
}Retrieving Data
Get CDs by artist
my $name = 'Belle and Sebastian';
my ($artist) = $art_rs->search({
name => $name,
});
foreach ($artist->cds) {
say $_->title;
}Searching for Data
Search conditions can be more complex
Alternatives
$rs->search({year => 2006},
{year => 2007});Like$rs->search({name =>
{ 'like', 'Dav%' }});Searching for Data
Combinations
$rs->search({forename =>
{ 'like', 'Dav%' },
surname => 'Cross' });Don't Repeat Yourself
There's a problem with this approach
Information is repeated
Columns and relationships defined in the database schema
Columns and relationships defined in class definitions
Repeated Information
CREATE TABLE artist (
artistid INTEGER PRIMARY KEY,
name TEXT NOT NULL
);Repeated Information
package Music::DB::Artist;
use base qw/DBIx::Class/;
__PACKAGE__->load_components(qw/Core/);
__PACKAGE__->table('artist');
__PACKAGE__->add_columns(qw/ artistid
name /);
__PACKAGE__->set_primary_key('artistid');
__PACKAGE__->has_many(cds =>
'Music::DB::Cd');
1;Database Metadata
Some people don't put enough metadata in their databases
Just tables and columns
No relationships. No constraints
You may as well make each column VARCHAR(255)
Database Metadata
Describe your data in your database
It's what your database is for
It's what your database does best
No Metadata (Excuse 1)
"This is the only application that will ever access this database"
Nonsense
All data will be shared eventually
People will update your database using other applications
Can you guarantee that someone won't use mysql to update your database?
No Metadata (Excuse 2)
"Database doesn't support those features"
Nonsense
MySQL 3.x is not a databaseIt's a set of data files with a vaguely SQL-like query syntax
MySQL 4.x is a lot better
MySQL 5.x is most of the way there
Don't be constrained by using inferior tools
DBIC::Schema::Loader
Creates classes by querying your database metadata
No more repeated data
We are now DRY
Schema definitions in one place
But...
Performance problems
Performance Problems
You don't really want to generate all your class definitions each time your program is run
Need to generate the classes in advance
dump_to_dir method
Regenerate classes each time schema changes
Alternative Approach
Need one canonical definition of the data tables
Doesn't need to be SQL DDL
Could be Perl code
Generate DDL from DBIx::Class definitionsHarder approach
Might need to generate ALTER TABLE
Conclusions
ORM is a bridge between relational objects and program objects
Avoid writing SQL in common cases
DBIx::Class is the currently fashionable module
Caveat: ORM may be overkill for simple programs
More Information
Manual pages (on CPAN)
DBIx::Class
DBIx::Class::Manual::*
DBIx::Class::Schema::Loader
Mailing list (Google for it)
TryCatch
Error Handling
How do you handle errors in your code?
Return error values from subroutines
sub get_object {
my ($class, $id) = @_;
if (my $obj = find_obj_in_db($id)) {
return $obj;
} else {
return;
}
}Problems
What if someone doesn't check return code?
my $obj = MyClass->get_object(100);
print $obj->name; # errorCaller assumes that $obj is a valid object
Bad things follow
Basic Exceptions
Throw an exception instead
sub get_object {
my ($class, $id) = @_;
if (my $obj = find_obj_in_db($id)) {
return $obj;
} else {
die No object found with id: $id;
}
}Now caller has to deal with exceptions
Dealing with Exceptions
Use eval to catch exceptions
my $obj = eval {
MyClass->get_object(100)
};
if ($@) {
# handle exception...
} else {
print $obj->name; # error
}Exceptions as Objects
$@ can be set to an object
sub get_object {
my ($class, $id) = @_;
if (my $obj = find_obj_in_db($id)) {
return $obj;
} else {
die MyException->new(
type => 'obj_not_found',
id => $id,
);
}
}Try Catch
TryCatch adds syntactic sugar
try {
...
}
catch ($e) {
...
}Looks a lot like many other languages
TryCatch with Scalar
try {
some_function_that_might_die();
}
catch ($e) {
if ($e =~ /some error/) {
# handle error
} else {
die $e;
}
}TryCatch with Object
try {
some_function_that_might_die();
}
catch ($e) {
if ($e->type eq 'file') {
# handle error
} else {
die $e;
}
}Better Checks
try {
some_function_that_might_die();
}
catch (My::Error $e) {
# handle error
}Even Better Checks
try {
some_function_that_might_die();
}
catch (HTTP::Error $e
where { $e->code == 404 }) {
# handle 404 error
}Multiple Checks
try {
some_function_that_might_die();
}
catch (HTTP::Error $e where { $e->code == 404 }) {
# handle 404 error
}
catch (HTTP::Error $e where { $e->code == 500 }) {
# handle 500 error
}
catch (HTTP::Error $e) {
# handle other HTTP error
}
catch ($e) {
# handle other error
}More Information
perldoc TryCatch
See also Try::Tiny
Moose
Moose
A complete modern object system for Perl 5
Based on Perl 6 object model
Built on top of Class::MOPMOP - 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 MooseLoads 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 About Attributes
Use the has keyword to define your class's attributes
has 'first_name' => ( is => 'rw' );
Use is to define rw or ro
Omitting is gives an attribute with no accessors
Getting & Setting
By default each attribute creates a method of the same name.
Used for both getting and setting the attribute
$dave->first_name('Dave');
say $dave->first_name;
Change Accessor Name
Change accessor names using reader and writer
has 'name' => (
is => 'rw',
reader => 'get_name',
writer => 'set_name',
);See also MooseX::FollowPBP
Required Attributes
Moose class attributes are optional
Change this with required
has 'name' => (
is => 'ro',
required => 1,
);Forces constructor to expect a name
Although that name could be undef
Attribute Defaults
Set a default value for an attribute with default
has 'size' => (
is => 'rw',
default => 'medium',
);Can use a subroutine reference
has 'size' => (
is => 'rw',
default => \&rand_size,
);Attribute Properties
lazyOnly populate attribute when queried
triggerSubroutine called after the attribute is set
isaSet the type of an attribute
Many more
More Moose
Many more options
Support for concepts like delegation and roles
Powerful plugin supportMooseX::*
Lots of work going on in this area
autodie
More on Exceptions
Exceptions force callers to deal with error conditions
But you have to explicitly code to throw exceptions
open my $fh, 'args->[-1], "\n";
warn 'File: ', $e->file, "\n";
warn 'Function: ', $e->function, "\n";
warn 'Package: ', $e->package, "\n";
warn 'Caller: ', $e->caller, "\n";
warn 'Line: ', $e->line, "\n";
}Nicer Errors Too
$ perl -Mautodie -E'open my $fh, "not-there"'
Can't open($fh, 'not-there'): No such file or directory at -e line 1More Information
perldoc Fatal
perldoc autodie
autodie - The art of Klingon Programming http://perltraining.com.au/tips/2008-08-20.html
Catalyst
MVC Frameworks
MVC frameworks are a popular way to write applicationsParticularly web applications
M, V and C
ModelData storage & data access
ViewData presentation layer
ControllerBusiness logic to glue it all together
MVC Examples
Ruby on Rails
Django (Python)
Struts (Java)
CakePHP
Many examples in most languages
Perl has many options
MVC in Perl
MaypoleThe original Perl MVC framework
CGI::ApplicationSimple MVC for CGI programming
JiftyDeveloped and used by Best Practical
CatalystCurrently the popular choice
Newer MVC in Perl
Dancer
Squatting
Mojolicious
Catalyst
MVC framework in Perl
Building on other heavily-used tools
Model uses DBIx::Class
View uses Template Toolkit
These are just defaults
Can use anything you want
Simple Catalyst App
Assume we already have modelCD database from DBIx::Class section
Use catalyst.pl to create project
$ catalyst.pl CD
created "CD"
created "CD/script"
created "CD/lib"
created "CD/root"
... many more ...What Just Happened?
Catalyst just generated a lot of useful stuff for us
Test web serversStandalone and FastCGI
Configuration files
Test stubs
Helpers for creating models, views and controllers
A Working Application
We already have a working application
$ CD/script/cd_server.pl
... lots of output
[info] CD powered by Catalyst 5.7015
You can connect to your server at http://localhost:3000Of course, it doesn't do much yet
Simple Catalyst App
Next Steps
Use various helper programs to create models and views for your application
Write controller code to tie it all together
Many plugins to handle various parts of the processAuthentication
URL resolution
Session handling
etc...
Create a View
$ script/cd_create.pl view Default TT
exists "/home/dave/training/cdlib/CD/script/../lib/CD/View"
exists "/home/dave/training/cdlib/CD/script/../t"
created "/home/dave/training/cdlib/CD/script/../lib/CD/View/Default.pm"
created "/home/dave/training/cdlib/CD/script/../t/view_Default.t"Remove Default Message
In lib/CD/Controller/Root.pm
sub index :Path :Args(0) {
my ( $self, $c ) = @_;
# Hello World
$c->response_body($c->welcome_message);
}Remove response_body line
Default behaviour is to render index.tt
Need to create that
index.tt
root/index.tt
CDs
[% FOREACH cd IN [ 1 .. 10 ] %]- CD [% cd %]
[% END %]
New Front Page
Adding Data
Of course that's hard-coded data
Need to add a model class
And then more views
And some controllers
There's a lot to do
I recommend working through a tutorial
Easier Catalyst
A lot of web applications do similar things
Given a database
Produce screens to edit the data
Surely most of this can be automated
It's called Catalyst::Plugin::AutoCRUD
(Demo)
Cat::Plugin::AutoCRUD
Does a lot of work
On the fly
For every request
No security on table updates
So it's not right for every project
Very impressive though
Conclusions
There's a lot to bear in mind when writing a web app
Using the right framework can help
Catalyst is the most popular Perl framework
As powerful as any other frameworkIn any language
Lots of work still going on
Large team, active development
Recommended Book
The Definitive Guide to CatalystKieren Diment
Matt S Trout
PSGI/Plack
PSGI/Plack
PSGI is an interface between Perl web applications and web servers, and Plack is a Perl module and toolkit that contains PSGI middleware, helpers and adapters to web servers.http://plackperl.org/
PSGI/Plack
PSGI is a specification (based on Python's WSGI)
Plack is a reference implementation (based on Ruby's Rack)
The Problem
There are many ways to write web applications
There are many ways to write web applications in Perl
Each is subtly different
Hard to move an application between server architectures
Server Architectures
CGI
FastCGI
mod_perl
etc...
Frameworks
There are many Perl web application frameworks
Each creates applications in subtly different ways
Hard to port applications between them
The Goal
What if we had a specification that allowed us to easily move web applications between server architectures and frameworks
PSGI is that specification
PSGI Application
my $app = sub {
my $env = shift;
return [
200,
[ Content-Type, text/plain ],
[ Hello World ],
];
};PSGI Application
A code reference
Passed a reference to an environment hash
Returns a reference to a three-element arrayStatus code
Headers
Body
A Code Reference
my $app = sub {
my $env = shift;
return [
200,
[ Content-Type, text/plain ],
[ Hello World ],
];
};A Code Reference
my $app = sub {
my $env = shift;
return [
200,
[ Content-Type, text/plain ],
[ Hello World ],
];
};Environment Hash
my $app = sub {
my $env = shift;
return [
200,
[ Content-Type, text/plain ],
[ Hello World ],
];
};Environment Hash
my $app = sub {
my $env = shift;
return [
200,
[ Content-Type, text/plain ],
[ Hello World ],
];
};Return Array Ref
my $app = sub {
my $env = shift;
return [
200,
[ Content-Type, text/plain ],
[ Hello World ],
];
};Return Array Ref
my $app = sub {
my $env = shift;
return [
200,
[ Content-Type, text/plain ],
[ Hello World ],
];
};Running PSGI App
Put code in app.psgi
Drop in into a configured PSGI-aware web server
Browse to URL
PSGI-Aware Server
Plack contains a simple test server called plackup
$ plackup app.psgi
HTTP::Server::PSGI: Accepting connections at http://localhost:5000/Plack::Request
Plack::Request turns the environment into a request object
use Plack::Request;
use Data::Dumper;
my $app = sub {
my $req = Plack::Request->new(shift);
return [
200,
[ 'Content-type', 'text/plain' ],
[ Dumper $req ],
];
}Plack::Response
Plack::Response builds a PSGI response object
use Plack::Request;
use Plack::Response;
use Data::Dumper;
my $app = sub {
my $req = Plack::Request->new(shift);
my $res = Plack::Response->new(200);
$res->content_type('text/plain');
$res->body(Dumper $req);
return $res->finalize;
}Middleware
Middleware wraps around an application
Returns another PSGI application
Simple spec makes this easy
Plack::Middleware::*
Plack::Builder adds middleware configuration language
Middleware Example
use Plack::Builder;
use Plack::Middleware::Runtime;
my $app = sub {
my $env = shift;
return [
200,
[ 'Content-type', 'text/plain' ],
[ 'Hello world' ],
]
};
builder {
enable 'Runtime';
$app;
}Middleware Example
$ HEAD http://localhost:5000
200 OK
Date: Tue, 20 Jul 2010 20:25:52 GMT
Server: HTTP::Server::PSGI
Content-Length: 11
Content-Type: text/plain
Client-Date: Tue, 20 Jul 2010 20:25:52 GMT
Client-Peer: 127.0.0.1:5000
Client-Response-Num: 1
X-Runtime: 0.000050Middleware Example
$ HEAD http://localhost:5000
200 OK
Date: Tue, 20 Jul 2010 20:25:52 GMT
Server: HTTP::Server::PSGI
Content-Length: 11
Content-Type: text/plain
Client-Date: Tue, 20 Jul 2010 20:25:52 GMT
Client-Peer: 127.0.0.1:5000
Client-Response-Num: 1
X-Runtime: 0.000050Plack::App::*
Ready-made solutions for common situations
Plack::App::CGIBinCgi-bin replacement
Plack::App::DirectoryServe files with directory index
Plack::App::URLMapMap apps to different paths
Plack::App::*
Many more bundled with Plack
Configured using Plack::Builder
Plack::App::CGIBin
use Plack::App::CGIBin;
use Plack::Builder;
my $app = Plack::App::CGIBin->new(
root => '/var/www/cgi-bin'
)->to_app;
builder {
mount '/cgi-bin' => $app;
};Plack::App::Directory
use Plack::App::Directory;
my $app = Plack::App::Directory->new(
root => '/home/dave/Dropbox/psgi'
)->to_app;Framework Support
Many modern Perl applications already support PSGI
Catalyst, CGI::Application, Dancer, Jifty, Mason, Maypole, Mojolicious, Squatting, Web::Simple
Many more
Catalyst Support
Catalyst::Engine::PSGI
use MyApp;
MyApp->setup_engine('PSGI');
my $app = sub { MyApp->run(@_) };Also Catalyst::Helper::PSGI
script/myapp_create.pl PSGI
PSGI Server Support
Many new web servers support PSGI
Starman, Starlet, Twiggy, Corona, HTTP::Server::Simple::PSGI
Perlbal::Plugin::PSGI
PSGI Server Support
nginx support
mod_psgi
Plack::Handler::Apache2
Plack::Handler::Apache2
SetHandler perl-script
PerlResponseHandler Plack::Handler::Apache2
PerlSetVar psgi_app /path/to/app.psgiPSGI/Plack Summary
PSGI is a specification
Plack is an implementation
PSGI makes your life easier
Most of the frameworks and server you use already support PSGI
No excuse not to use it
Further Information
perldoc PSGI
perldoc Plack
http://plackperl.org/
http://blog.plackperl.org/
http://github.com/miyagawa/Plack
#plack on irc.perl.org
Modern Perl Summary
Perl has changed a lot in the last five years
Perl continues to grow and change
Perl is not a scripting language
Perl is a powerful and flexible programming language
Perl is a great way to get your job done
That's all folks
Any questions?
Click to edit the outline text formatSecond Outline LevelThird Outline LevelFourth Outline LevelFifth Outline LevelSixth Outline LevelSeventh Outline LevelEighth Outline LevelNinth Outline Level
YAPC::Europe14th August 2011