Introducing Modern Perl
- 26. Resources Slides available on-line http://mag-sol.com/train/yapc/2010 Also see Slideshare http://www.slideshare.net/davorg/slideshows Get Satisfaction http://getsatisfaction.com/magnum
- 37. DIY Templating $text = 'this has a $foo in it and a $bar'; %user_defs = ( foo => 23, bar => 19, ); $text =~ s/(+)/$user_defs{$1}/g;
- 55. 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;
- 56. html.tt <html> <head> <title>[% obj.name %]</title> </head> <body> <h1>[% obj.name %]<h1> <p><img src=“[% obj.img %]” /><br /> [% obj.desc %]</p> <ul> [% FOREACH child IN obj.children -%] <li>[% child.name %]</li> [% END %] </body> </html>
- 57. text.tt [% obj.name | upper %] Image: [% obj.img %] [% obj.desc %] [% FOREACH child IN obj.children -%] * [% child.name %] [% END %]
- 61. Equation Revisited Data + Template = Output Template Toolkit Template + Output = Data Template::Extract Data + Output = Template Template::Generate
- 63. Dates & Times Perl has built-in functions to handle dates and times
- 64. time – seconds since 1st Jan 1970
- 77. 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:07
- 78. Using 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; # August
- 82. 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:00
- 83. Formatting Output use DateTime; my $dt = DateTime->new(year => 2010, month => 4, day => 14); say $dt->strftime('%A, %d %B %Y'); # Wednesday, 14 April 2010
- 96. Calendar Examples use DateTime::Calendar::Mayan; my $dt = DateTime::Calendar::Mayan->now; say $dt->date; # 12.19.17.9.13
- 137. 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;
- 138. 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;
- 139. 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 => $_ }); }
- 140. 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', );
- 141. Inserting CDs Find each artist and insert CD foreach (keys $cds) { my ($artist) = $art_rs->search( { name => $cds{$_} } ); $artist->add_to_cds({ title => $_, }); }
- 142. Retrieving Data Get CDs by artist my $name = 'Belle and Sebastian'; my ($artist) = $art_rs->search({ name => $name, }); foreach ($artist->cds) { say $_->title; }
- 145. Searching for Data Combinations $rs->search({forename => { 'like', 'Dav%' }, surname => 'Cross' });
- 151. 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;
- 155. You may as well make each column VARCHAR(255)
- 159. No Metadata (Excuse 1) "This is the only application that will ever access this database"
- 166. MySQL 3.x is not a database It's a set of data files with a vaguely SQL-like query syntax MySQL 4.x is a lot better
- 196. sub get_object { my ($class, $id) = @_; if (my $obj = find_obj_in_db($id)) { return $obj; } else { return; } }
- 198. my $obj = MyClass->get_object(100); print $obj->name; # error
- 202. sub get_object { my ($class, $id) = @_; if (my $obj = find_obj_in_db($id)) { return $obj; } else { die “No object found with id: $id”; } }
- 205. my $obj = eval { MyClass->get_object(100) }; if ($@) { # handle exception... } else { print $obj->name; # error }
- 207. 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, ); } }
- 209. try { ... } catch ($e) { ... }
- 211. TryCatch with Scalar try { some_function_that_might_die(); } catch ($e) { if ($e =~ /some error/) { # handle error } else { die $e; } }
- 212. TryCatch with Object try { some_function_that_might_die(); } catch ($e) { if ($e->type eq 'file') { # handle error } else { die $e; } }
- 213. Better Checks try { some_function_that_might_die(); } catch (My::Error $e) { # handle error }
- 214. Even Better Checks try { some_function_that_might_die(); } catch (HTTP::Error $e where { $e->code == 404 }) { # handle 404 error }
- 215. 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 }
- 224. 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); }
- 232. Defining Methods sub clear { my $self = shift; $self->{x} = 0; $self->y(0); } Standard method syntax
- 235. Subclassing package Point3D; use Moose; extends 'Point'; has 'z' => (isa => 'Int'); after 'clear' => sub { my $self = shift; $self->{z} = 0; };
- 245. $p3d = Point3D->new(x => 1, y => 2, z => 3);
- 255. has 'name' => ( is => 'rw', reader => 'get_name', writer => 'set_name', );
- 266. Attribute Properties lazy Only populate attribute when queried trigger Subroutine called after the attribute is set isa Set the type of an attribute Many more
- 275. Not Checking Errors open my $fh, '<', 'somefile.txt'; while (<$fh>) { # do something useful }
- 287. Can't be used if function can legitimately return a false value e.g. fork
- 289. $ perl -MFatal=open -E'open my $fh, "notthere"' Can't open(GLOB(0x86357a4), notthere): No such file or directory at (eval 1) line 4 main::__ANON__('GLOB(0x86357a4)', 'notthere') called at -e line 1
- 301. try { open my $fh, '<', 'not-there'; } catch ($e) { warn 'Error opening ', $e->args->[-1], ""; warn 'File: ', $e->file, ""; warn 'Function: ', $e->function, ""; warn 'Package: ', $e->package, ""; warn 'Caller: ', $e->caller, ""; warn 'Line: ', $e->line, ""; }
- 302. 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 1
- 305. autodie - The art of Klingon Programming http://perltraining.com.au/tips/2008-08-20.html
- 307. MVC Frameworks MVC frameworks are a popular way to write applications Particularly web applications
- 308. M, V and C Model Data storage & data access View Data presentation layer Controller Business logic to glue it all together
- 315. MVC in Perl Maypole The original Perl MVC framework CGI::Application Simple MVC for CGI programming Jifty Developed and used by Best Practical Catalyst Currently the popular choice
- 325. Simple Catalyst App Assume we already have model CD database from DBIx::Class section Use catalyst.pl to create project
- 326. $ catalyst.pl CD created "CD" created "CD/script" created "CD/lib" created "CD/root" ... many more ...
- 332. $ CD/script/cd_server.pl ... lots of output [info] CD powered by Catalyst 5.7015 You can connect to your server at http://localhost:3000
- 335. Next Steps Use various helper programs to create models and views for your application
- 341. 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"
- 343. sub index :Path :Args(0) { my ( $self, $c ) = @_; # Hello World $c->response_body($c->welcome_message); }
- 347. index.tt root/index.tt <html> <head> <title>CDs</title> </head> <body> <ul> [% FOREACH cd IN [ 1 .. 10 ] %] <li>CD [% cd %]</li> [% END %] </ul> </body> </html>
- 370. As powerful as any other framework In any language Lots of work still going on
- 375. 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/
- 377. Plack is a reference implementation (based on Ruby's Rack)
- 381. Hard to move an application between server architectures
- 389. The Goal What if we had a specification that allowed us to easily move web applications between server architectures and frameworks
- 391. PSGI Application my $app = sub { my $env = shift; return [ 200, [ ‘Content-Type’, ‘text/plain’ ], [ ‘Hello World’ ], ]; };
- 397. A Code Reference my $app = sub { my $env = shift; return [ 200, [ ‘Content-Type’, ‘text/plain’ ], [ ‘Hello World’ ], ]; };
- 398. A Code Reference my $app = sub { my $env = shift; return [ 200, [ ‘Content-Type’, ‘text/plain’ ], [ ‘Hello World’ ], ]; };
- 399. Environment Hash my $app = sub { my $env = shift; return [ 200, [ ‘Content-Type’, ‘text/plain’ ], [ ‘Hello World’ ], ]; };
- 400. Environment Hash my $app = sub { my $env = shift; return [ 200, [ ‘Content-Type’, ‘text/plain’ ], [ ‘Hello World’ ], ]; };
- 401. Return Array Ref my $app = sub { my $env = shift; return [ 200, [ ‘Content-Type’, ‘text/plain’ ], [ ‘Hello World’ ], ]; };
- 402. Return Array Ref my $app = sub { my $env = shift; return [ 200, [ ‘Content-Type’, ‘text/plain’ ], [ ‘Hello World’ ], ]; };
- 407. $ plackup app.psgi HTTP::Server::PSGI: Accepting connections at http://localhost:5000/
- 409. use Plack::Request; use Data::Dumper; my $app = sub { my $req = Plack::Request->new(shift); return [ 200, [ 'Content-type', 'text/plain' ], [ Dumper $req ], ]; }
- 411. 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; }
- 417. 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; }
- 418. 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.000050
- 419. 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.000050
- 443. Most of the frameworks and server you use already support PSGI
- 454. Perl is a powerful and flexible programming language
- 455. Perl is a great way to get your job done