perl6 in-production

Post on 11-Apr-2017

728 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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!

__END__

Cluj-Napoka 2015 !

!

Andrew Shitov | andy@shitov.ru

top related