Upload
andrew-shitov
View
728
Download
2
Embed Size (px)
Citation preview
Perl 6 in Production
15 years of development
Ready December 2015
This December
Start using?
Perl 6 for Web
Development
What’s wrong with Perl 6?
What’s wrong with today’s Perl 6?
Not that it is too late
Rather that it is too mature
Lots of blog posts
Lots of documentation
Lots of code examples
Lots of errors
Everything has been googled
Not easy to find how this or that works
Most of code examples and modules are outdated
Outdated before the release!
Nothing works!
Even if it used to work
===SORRY!=== Error while compiling !
Undeclared routine: eval used at line 7. Did you mean 'val'?
===SORRY!=== Error while compiling !
Undeclared routine: eval used at line 7. Did you mean 'val'?
(use EVAL)
A bit of history
2000 Perl 6 announced
First implementations
Parrot
Parrot with Perl 6 compiler
Pugs
Pugs, the Perl 6 compiler
Rakudo
Rakudo Star
Past
2004 real.perl6.ru
http://web.archive.org/web/*/real.perl6.ru
Some examples of the code of 2004
Reading environment variables
my @keys = ('SERVER_NAME', 'REMOTE_ADDR', 'HTTP_USER_AGENT'); !
my $key; foreach $key (@keys){ print "$key=%ENV{$key}<br />\n"; }
Looks almost like Perl 5
my @keys = ('SERVER_NAME', 'REMOTE_ADDR', 'HTTP_USER_AGENT'); !
my $key; foreach $key (@keys){ print "$key=%ENV{$key}<br />\n"; }
You could learn Perl 6 in a few hours
Setting/getting cookies
print "Content-‐Type: text/html\n" print 'Set-‐Cookie: cookie-‐name=test-‐value; path=/;\n\n'; !
print %ENV{'HTTP_COOKIE'};
URL GET parameters
read_params ( %ENV{'QUERY_STRING'}, @params_key, @params_value );
sub read_params ($query, @params_key, @params_value){ my $pos = 0; loop (my $c = 0; 1; $c++) { my $newpos = index ($query, '&', $pos); my @keyvalue; my $pair = substr ($query, $pos, $newpos == -‐1 ?? length ($query) :: $newpos -‐ $pos); split_pair ($pair, @keyvalue); @params_key[$c] = @keyvalue[0]; @params_value[$c] = @keyvalue[1]; last if $newpos == -‐1; $pos = $newpos + 1; } }
sub read_params ($query, @params_key, @params_value){ my $pos = 0; loop (my $c = 0; 1; $c++) { my $newpos = index ($query, '&', $pos); my @keyvalue; my $pair = substr ($query, $pos, $newpos == -‐1 ?? length ($query) :: $newpos -‐ $pos); split_pair ($pair, @keyvalue); @params_key[$c] = @keyvalue[0]; @params_value[$c] = @keyvalue[1]; last if $newpos == -‐1; $pos = $newpos + 1; } }
sub split_pair ($pair, @keyvalue){ my $pos = index ($pair, '='); if ($pos == -‐1){ @keyvalue[0] = $pair; @keyvalue[1] = ''; } else{ @keyvalue[0] = substr ($pair, 0, $pos); @keyvalue[1] = substr ($pair, $pos + 1); } }
URL GET parameters using hashes
sub params2hash (%params, @params_key, @params_value){ for 0 .. @params_key -‐> $c{ %params{@params_key[$c]} = @params_value[$c]; } } !read_params (%ENV{'QUERY_STRING'}, @params_key, @params_value); my %params; params2hash (%params, @params_key, @params_value);
To speed it up
Compiling to bytecode
.pasm .imc
100% compatible
2007/2008 november-wiki.org
https://github.com/viklund/november
November::CGI
class November::CGI { has %.params; has %.cookie; has @.keywords; has November::URI $.uri;
self.parse_params(%*ENV<QUERY_STRING> // '');
has $!crlf = "\x[0D]\x[0A]"; . . . !print "Status: $status$!crlf"; print "Location: $uri"; print "$!crlf$!crlf";
has $!crlf = "\x[0D]\x[0A]"; . . . !print "Status: $status$!crlf"; print "Location: $uri"; print "$!crlf$!crlf";
Compare https://p6weekly.wordpress.com/2015/11/09/2015-46-production-today/
Smartmatch and junctions
method add_param ( Str $key, $value ) { if %.params{$key} :exists { # RAKUDO: ~~ Scalar if %.params{$key} ~~ Str | Int { my $old_param = %.params{$key}; %!params{$key} = [ $old_param, $value ]; } elsif %.params{$key} ~~ Array { %!params{$key}.push( $value ); } } else { %!params{$key} = $value; } }
Compiler incompatibilities
method add_param ( Str $key, $value ) { if %.params{$key} :exists { # RAKUDO: ~~ Scalar if %.params{$key} ~~ Str | Int { my $old_param = %.params{$key}; %!params{$key} = [ $old_param, $value ]; } elsif %.params{$key} ~~ Array { %!params{$key}.push( $value ); } } else { %!params{$key} = $value; } }
if %*ENV<MODPERL6> { my $r = Apache::RequestRec.new(); my $len = $r.read($input, %*ENV<CONTENT_LENGTH>); } else { # Maybe check content_length here # and only take that many bytes? $input = $*IN.slurp; } !
(I never managed to install mod_parrot)
Grammar for URL parsing
grammar November::URI::Grammar { token TOP { ^ [<scheme> ':']? [ '//' <authority>]? <path> ['?' <query>]? ['#' <fragment>]? $ }; token scheme { <-‐[:/&?#]>+ }; token authority { <host> [':' <port>]? }; token host { <-‐[/&?#:]>* }; token port { (\d**1..5) <?{ $0 < 2 ** 16 }> <!before \d> }; token path { <slash>? [ <chunk> '/'?]* }; token slash { '/' }; token chunk { <-‐[/?#]>+ }; token query { <-‐[#]>* }; token fragment { .* }; }
# Official regexp (p5): # my($scheme, $authority, $path, $query, $fragment) = # $uri =~ m/ # (?:([^:/?#]+):)? # (?://([^/?#]*))? # ([^?#]*) # (?:\?([^#]*))? # (?:#(.*))? # /x;
Not like Perl 5 any more :-)
2011 Plackdo
https://github.com/lopnor/p6-plackdo
Plack-like web interface on Perl 6
my $app = sub (%env) { return ( 200, [ Content-‐Type => 'text/plain', Content-‐Length => %env.perl.bytes, ], [ %env.perl ] ); };
HTTP status code
my $app = sub (%env) { return ( 200, [ Content-‐Type => 'text/plain', Content-‐Length => %env.perl.bytes, ], [ %env.perl ] ); };
HTTP headers
my $app = sub (%env) { return ( 200, [ Content-‐Type => 'text/plain', Content-‐Length => %env.perl.bytes, ], [ %env.perl ] ); };
Response body
my $builder = Plackdo::Builder.new; $builder.add_middleware( Plackdo::Middleware::XFramework.new( framework => 'foobar') ); $builder.to_app($app);
~2014 wee6
https://github.com/vti/wee6
Present
Rakudo Star
http://rakudo.org
+
modules.perl6.org
Installing Rakudo*
perl Configure.pl \ -‐-‐backend=moar \ -‐-‐gen-‐moar !
make !
make install
MoarVM
http://moarvm.org
Managing modules
“Ecosystem”
https://github.com/perl6/ecosystem
Panda !
for installing Perl 6 modules
modules/panda/bootstrap.pl
panda install Module::X
Distribution modules live in install/share/perl6/lib
Panda puts modules to install/share/perl6/site
BTW, Rakudo’s “make install”
compiles modules to .moarvm
OK, Perl. Let’s build a web server
HTTP::Easy
Core’s
HTTP::Easy::PSGI
Core’s
use HTTP::Easy::PSGI;
my $http = HTTP::Easy::PSGI.new( :port(8080) );
my $app = sub (%env) { . . . }
my $app = sub (%env) { . . . } !
$http.handle($app);
my $app = sub (%env) { return [ 200, [ 'Content-‐Type' => 'text/plain' ], [ 'Hello, World!’ ] ]; }
use HTTP::Easy::PSGI; my $http = HTTP::Easy::PSGI.new(:port(8080)); !
my $app = sub (%env) { my $name = %env<QUERY_STRING> || "World"; return [ 200, [ 'Content-‐Type' => 'text/plain' ], [ "Hello $name" ] ]; } !
$http.handle($app);
!
Web::App module set
Explore
Bailador
Bailador(Dancer)
Available in the Rakudo* distribution
(Does not instantly work in the 2015.09 distribution)
use Bailador;
use Bailador; !
get '/' => sub { !
}
use Bailador; !
get '/' => sub { return "Hi\n"; } !
use Bailador; !
get '/' => sub { return "Hi\n"; } !
baile;
use Bailador; !
get '/' => sub { "Hi\n" } !
baile;
$ perl6 test.pl !
Entering the development dance floor: http://0.0.0.0:3000 [2015-‐11-‐17T13:41:08Z] Started HTTP server.
Started… !
Then open it in a browser
Method 'send' not found for invocant of class 'IO::Socket::INET' in method run at /home/ash/p/rakudo-‐star-‐2015.09/install/share/perl6/lib/HTTP/Easy.pm6:193 in sub baile at /home/ash/p/rakudo-‐star-‐2015.09/install/share/perl6/lib/Bailador.pm:153 in block <unit> at test.pl:8
Update HTTP::Easy using panda
git clone ... panda install ./Bailador
!
-‐ connection.send($res.Str); !
+ connection.print($res.Str);
use Bailador; !
get '/' => sub { return "Hi\n"; } !
get '/hello/:name' => sub ($name) { return "Hi, $name\n"; } !
baile;
use Bailador; !
get '/' => sub { return "Hi\n"; } !
get '/hello/:name' => sub ($name) { return "Hi, $name\n"; } !
baile;
NB!
!
get '/hello/:name' => sub ($name) { !
vs.!
get '/hello/:name' => sub($name) {
===SORRY!=== Error while compiling test1.pl Variable '$name' is not declared at test1.pl:7 !
-‐-‐-‐-‐-‐-‐> get '/hello/:name' => sub(⏏$name)
Accessing request data
get '/' => sub { return request.perl; }
Bailador::Request.new(env => {:HTTP_ACCEPT("*/*"), :HTTP_HOST("0.0.0.0:3000"), :HTTP_USER_AGENT("curl/7.35.0"), :PATH_INFO("/"), :QUERY_STRING(""), :REQUEST_METHOD("GET"), :REQUEST_URI("/"), :SERVER_NAME("0.0.0.0"), :SERVER_PORT(3000), :SERVER_PROTOCOL("HTTP/1.1"), "p6sgi.encoding" => "UTF-‐8", "p6sgi.errors" => IO::Handle.new(path => IO::Special.new(what => "<STDERR>"), ins => 0, chomp => Bool::True), "p6sgi.errors.buffered" => Bool::True,
What is a ‘request’?
class Bailador::App { . . . method request { $.context.request } method response { $.context.response } . . . }
get /.*/ => sub { return request.env<REQUEST_URI> ~ "\n"; }
get /.*/ => sub { return request.env<REQUEST_URI> ~ "\n"; }
Templates
get '/' => sub { template 't.tt', { name => 'Name' } }
get '/' => sub { template 't.tt', { name => 'Name' } }
% my ($h) = @_; <html> <head> <title> Hi, <%= $h<name> %> </title> </head> <body> <h1>Hello <%= $h<name> %></h1> </body> </html>
% my ($h) = @_; <html> <head> <title> Hi, <%= $h<name> %> </title> </head> <body> <h1>Hello <%= $h<name> %></h1> </body> </html>
Use of uninitialized value $_location of type Any in string context Any of .^name, .perl, .gist, or .say can stringify undefined things, if needed. in method template at /home/ash/p/rakudo-‐star-‐2015.09/install/share/perl6/site/lib/Bailador/App.pm:14 Failed to open file /views/t.tt: no such file or directory in method template at
my $_location; !
. . . !
$!renderer.render( slurp( "$_location/views/$tmpl" ), @params );
lib/Bailador/App.pm
my $_location; !
. . . !
$!renderer.render( slurp( "$_location/views/$tmpl" ), @params );
lib/Bailador/App.pm
my $_location = '.'; !
. . . !
$!renderer.render( slurp( "$_location/views/$tmpl" ), @params );
lib/Bailador/App.pm
OK, Perl. What about databases?
DBIish
panda install DBIish
use DBIish;
use DBIish; my $dbh = DBIish.connect( 'mysql', :host<example.com>, :port(3306), :database<$dbname>, :user<$dbuser>, :password<$dbpassword>);
my $sth = $dbh.prepare( "select now()" ); !
$sth.execute();
my $arr = $sth.fetchall_arrayref();
my $arr = $sth.fetchall_arrayref(); !
for $arr -‐> $x { say $x; }
It works!