--- title: らくらくPerl6入門 tags: presentation slideOptions: theme: white slideNumber: 'c/t' center: false transition: 'none' keyboard: true width: '93%' height: '100%' --- <style> /* basic design */ .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6, .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p { font-family: 'Meiryo UI', 'Source Sans Pro', Helvetica, sans-serif, 'Helvetica Neue', 'Helvetica', 'Arial', 'Hiragino Sans', 'ヒラギノ角ゴシック', YuGothic, 'Yu Gothic'; text-align: left; line-height: 1.6; letter-spacing: normal; text-shadow: none; word-wrap: break-word; color: #444; } .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {font-weight: bold;} .reveal h1, .reveal h2, .reveal h3 {color: #2980b9;} .reveal th {background: #DDD;} .reveal section img {background:none; border:none; box-shadow:none; max-width: 95%; max-height: 95%;} .reveal blockquote {width: 90%; padding: 0.5vw 3.0vw;} .reveal table {margin: 1.0vw auto;} .reveal code {line-height: 1.2;} .reveal p, .reveal li {padding: 0vw; margin: 0vw;} .reveal .box {margin: -0.5vw 1.5vw 2.0vw -1.5vw; padding: 0.5vw 1.5vw 0.5vw 1.5vw; background: #EEE; border-radius: 1.5vw;} /* table design */ .reveal table {background: #f5f5f5;} .reveal th {background: #444; color: #fff;} .reveal td {position: relative; transition: all 300ms;} .reveal tbody:hover td { color: transparent; text-shadow: 0 0 3px #aaa;} .reveal tbody:hover tr:hover td {color: #444; text-shadow: 0 1px 0 #fff;} /* blockquote design */ .reveal blockquote { width: 90%; padding: 0.5vw 0 0.5vw 6.0vw; font-style: italic; background: #f5f5f5; } .reveal blockquote:before{ position: absolute; top: 0.1vw; left: 1vw; content: "\f10d"; font-family: FontAwesome; color: #2980b9; font-size: 3.0vw; } /* font size */ .reveal h1 {font-size: 5.0vw;} .reveal h2 {font-size: 4.0vw;} .reveal h3 {font-size: 2.8vw;} .reveal h4 {font-size: 2.6vw;} .reveal h5 {font-size: 2.4vw;} .reveal h6 {font-size: 2.2vw;} .reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {font-size: 2.2vw;} .reveal code {font-size: 1.6vw;} /* new color */ .red {color: #EE6557;} .blue {color: #16A6B6;} /* split slide */ #right {left: -18.33%; text-align: left; float: left; width: 50%; z-index: -10;} #left {left: 31.25%; text-align: left; float: left; width: 50%; z-index: -10;} </style> <style> /* specific design */ .reveal h2 { padding: 0 1.5vw; margin: 0.0vw 0 2.0vw -2.0vw; border-left: solid 1.2vw #2980b9; border-bottom: solid 0.8vw #d7d7d7; } </style> <!-- --------------------------------------------------------------------------------------- --> # らくらくPerl6入門 <!-- Put the link to this slide here so people can follow --> YAPC::Nagoya::Tiny 八雲アナグラ (@AnaTofuZ) --- ## 私です - 八雲アナグラ (@AnaTofuZ) - 琉球大学大学院M1 - 雇ってください - Okinawa.pm / Perl入学式in沖縄 - 最近はCatalinaと魔改造されたCコンパイラとCMakeとクロスコンパイルと戦っている - Perlは趣味で書いています - PerlConの参加関連ありがとうございました!! ![](https://pbs.twimg.com/profile_images/1153141142998794240/Yt9814c5_400x400.jpg) --- ## らくらくPerl6入門 - Raku(Perl6)についてのチュートリアルトークです - 実装, 世界観, おもしろ演算子, サブルーチン, WAFとかORMとか - 他の細部なネタは懇親会などでよろしくお願いします - Rakuへの名前変更に伴い、変更がある箇所は記載しています --- ## Raku (Perl6) とは? - LarryWallが設計した新しい言語 - ハッシュタグは `#rakulang` が使われている - 落語では? - Perl5との互換性は**無い** - 変数なども雰囲気が似ているが根本的に異なる物が多い - とはいえ同じ名前のコアライブラリがあったりはする - マルチパラダイムなスクリプト言語 - 仕様と実装が明確に区分されている --- ## 名前がかわりました - 詳しくはdanさんのトークで - 以前から名前変更話はありました - `6lang`, `Camelia`など - Cameliaに決まるかなと思いきや、「オブジェクト指向Perlマスターコース」のダミアン・コンウェイ先生により `raku`が提案され決定する - raku自体は少し前にPerl6の相性(エイリアス)として設定されていた - なんか議論の最中に「箱根にRaku」という地名があるぞという話が - https://www.hakone-raku.com/ - ハッカソンしたい --- ## Rakuの歴史と実装の歴史 - 2000年にLarryWallによって仕様が発表される - 2005年にAudrey TangによってHaskellで書かれた**Pugs**が実装される - 初めて登場したPerl6インタプリタ --- ## Parrot - 初めてVMとして動作する様になったPerl6処理系 - バイトコードに変換され、バイトコードをVMが処理していく - Perl5やPython, LuaなどもParrrot上で動かすことを目標としていた - Inline::PerlはParrotの機能を使って実装しようとしていた - 現在はRakudoにプロジェクトが切り替わっており、開発は止まっている - http://parrot.org/ --- ## Rakudo - 現在の主要なPerl6処理系 - ラクダ道や楽土(パラダイス)から名前が来ている - 3つのレイヤーで構成されている - Rakudo - Rakuのサブセット(NQP) - VM - VMはいくつか選択可能 - MoarVM - JVM - JavaScript - Rakudo自体はNQPとRakuによって記述されている - VMの機能を直接使いたい場合などにNQPを使う必要性がある --- ## 備考: Perlito - Perl5 to Perl6 - Perl5 to Java, JavaScript, Go, Python, Ruby, Listなトランスコンパイラ - https://fglock.github.io/Perlito/ --- ## Rakuの名前の確認 - 紛らわしいのもあるので一度整理しましょう - Perl - Perl5のこと。Raku(Perl6)のことではない - Raku(Perl6) - 仕様の名前 - **Perlの次期バージョンではない!!!** --- ## Rakuの名前の確認 - Rakudo - 主要な実装。RakuとNQPで記述されている - NQP - NotQuitPerl。 Rakuのサブセット言語 - MoarVM - Cで書かれたRaku専用のバーチャルマシン - zef - Raku/Perl6におけるcpanm的なもの - 以前は panda が使われていた --- ## NQP - Rakudoの開発者向け様のサブセット - これでプログラミングするのは推奨されていない - 束縛ベースでの記述などかなり使い勝手が異なっている - VMの機能を直接仕様する事が可能 - NQP自身, C, Java, JVMで実装されている - NQPが各処理系の実装を隠蔽している - NQPの時点でclassやGrammerなどのRakuっぽい機能は一通り使える --- ## MoarVM - Cで実装されたRakudo用のプロセスVM - レジスタマシン - RakudoもNQPも実際はMoarVMがバイトコードを読み込んで処理をしている - レジスタはSSA(静的単一代入)を使って処理をしている - 統計的に効果的な最適化などをする機能が最近搭載されている - 詳しくは[Jonathanのスライド](https://www.jnthn.net/papers/2019-perlcon-performance.pdf) - バイトコードを出力する機能などがある - コマンドは `moar` - lessっぽいのは `more` --- ## Rakuをダウンロードしよう - 環境がすべて入る `rakudo-star` を使うのが便利 - ワイルドカード的な `*` のスターらしい - 公式サイトからDownloadする - https://rakudo.org/files - macOSではdmg, unixではtarが配布されている - macOSの場合はbrewでも入る - `$brew install rakudo-star` - ローカルに入れたくない場合は6padをブラウザで - https://perl6.github.io/6pad/ - RakuのJavaScript実装 --- ## 他の方法 - rakudobrew - https://github.com/tadzik/rakudobrew - p6env - https://github.com/skaji/p6env --- ## ソースコードごと入手したい場合 - 開発者向けの`z` が便利 - https://github.com/perl6/z - MoarVM, NQP, Rakudoのソースコードごとダウンロード可能 - それぞれにデバッグオプションをつけてビルドなども可能 --- ## 現在のRaku - 現在はバージョン `6.d` - 次のバージョンは `6.e` - `6.f`でPerl6由来の命名関連は非推奨になる - `6.g`では完全にRakuに切り替わる --- ## RakuのIDE - EDUMENTが開発しているCommaがおすすめ - https://commaide.com/ - ![](https://commaide.com/images/header.svg) - 120ユーロ/年でComplete版が使える - 無料版も使用可能 - Javaで実装されており、JetBrain感が強いInterface --- ## Rakuの本 - 日本ではWEB+DB PRESSのPerlHakcersHUBに一部記事がある程度 - 雅なPerl入門(同人誌)などでも一部触れられている - 同人誌執筆チャンス(?) - 海外ではParrot時代に作られたのも含め何冊か出ている - とはいえ昔の書籍はコードが動かない可能性があるので... - Perl6のあなたにおすすめ本フローチャート - https://perl6book.com/ --- ## Rakuの本 - [ThinkPerl6](https://greenteapress.com/wp/think-perl-6/) - Perl6を用いたコンピュータサイエンス入門書。プログラミング初学者向け - [Using Raku](https://deeptext.media/using-raku) - Rakuを使った課題解決集。Tipsっぽい - フリーで入手可能 - [Perl6DeppDrive](https://www.packtpub.com/application-development/perl-6-deep-dive) - 個人的に一番良さそうな本。Perl6を隅々まで解説している - 関数型プログラミングやreactive programmingまで解説 - [Raku One Liners](https://raku.online/2019/10/18/raku-one-liners-a-free-book/) - RakuのワンライナーTips集 - フリーで入手可能 --- ## 名前変更に伴う書籍の対応 ![](https://www.i-programmer.info/images/stories/News/2019/oct/B/raku1.jpg) --- ## Rakuを使おう - `$perl6` コマンドを単体実行するとインタプリタが起動 - `$perl6 hoge.p6` などとスクリプトを渡すとスクリプトが実行される - pythonと同じような挙動 - インタプリタを拡張する場合はモジュールを導入する - `$perl6` 自体はmoarを起動するシェルスクリプト ```shell= #!/bin/sh exec /usr/local/Cellar/rakudo-star/2019.03/bin/moar \ --execname="$0" --libpath="/usr/local/Cellar/rakudo-star/2019.03/share/nqp/lib" \ --libpath="/usr/local/Cellar/rakudo-star/2019.03/share/nqp/lib" \ --libpath="/usr/local/Cellar/rakudo-star/2019.03/share/perl6/lib" \ --libpath="/usr/local/Cellar/rakudo-star/2019.03/share/perl6/runtime" \ /usr/local/Cellar/rakudo-star/2019.03/share/perl6/runtime/perl6.moarvm "$@" ``` --- ## Rakuを使おう - 現状は `$perl6` コマンドだが `$raku` コマンドが本体になる - `$perl6` はシンボリックリンクに - また `$perl6` で起動した場合はwarningを発生させたいらしい --- ## Rakuのファイル拡張子 - Perl5と同じ拡張子を使っている人々もいるが、分けるのが良い - Perl5と同じ拡張子なら `use v6;` を忘れない | 形式 | perl6 | raku | | ------------ | -------- | -------- | | スクリプト | .p6 | .raku | | モジュール | .pm6 | .rakumod | | ドキュメント | .pod6 | .rakudoc | | テスト | .t , .t6 | .rakutest | - Perl6由来の拡張子は`6.f`以降では非推奨扱い --- ## Perl6のModule - [Perl 6 Modules](https://modules.raku.org/) - このサイトからモジュールの検索が可能 - installは`zef` を使う - モジュールを作成する場合はskajiさんのApp::Mi6を使おう - https://github.com/skaji/mi6 - 依存関係は`META6.json`にガリガリ書いていく --- ## zefでinstallしたコマンド類 - zefでinstallしたコマンドは、 rakudo-starのディレクトリに配置される - brewで入れた場合PATHを自動で貼ってくれないのでいれる必要がある - `/usr/local/Cellar/rakudo-star/2019.03/share/perl6/site/bin/` のようなパス `export PATH="$(readlink $(where perl6) | perl -pne 's[\.\.][/usr/local]; s[(.*)/bin/perl6][$1/share/perl6/site/bin]'):$PATH"` - とか書くと便利...? --- ## Rakuを学ぶには? - 公式ドキュメントが信頼出来る - 公式ドキュメントから幾つかのサイトのリンクが有るケースも - AdventCalendar, ブログなど... - 書籍は上に挙げたフローチャートで紹介されている書籍が良いでしょう - ブログは幾つか前の情報や未実装のもの、妄想などが入っているので注意 - ドキュメントでも怪しい場合はRoast(テストスーツ)での実装を確認しましょう --- ## それでも困ったら? - IRCで問い合わせる - ツイッターでAlexanderに聞く - https://twitter.com/koto_san_kana --- ## 多言語からのRaku入門 - 公式ドキュメントにそういったものが充実しはじめてきている - Perl5 to Raku - JavaScript to Raku - Ruby to Raku - Haskell to Raku - Python to Raku - 当然Perl5 to Perl6のカテゴリが充実している --- ## QA - 「Rakuって遅いでしょ?」 - 遅いですが早くはなってきている - MoarVM側頑張っている - 処理ではRuby,Perl5, Pythonより早いケースもある - とはいえ起動時間が遅いので厳しい --- ## Perl5 - 変数のデータ型は3種類 - `$` スカラー - `@` 配列 - `%` ハッシュ --- ## Raku - Raku側ではPerl5と同様に3種類のシジルがある - `$` スカラー - `@` 配列 - `%` ハッシュ - これらは「変数の型」ではなく「変数のコンテナの種類」を示す指示子 - Rakuではオブジェクトを直接扱うのではなくコンテナと呼ばれるものを経由させる - 3種類で表せられない型は `$` にバインドされる - 頑張れば配列やハッシュも `$` で使うことが可能 - さらにシジルの後ろにTwigil(トゥイジル)という記号をつけるケースもある --- ## 軽く書く - シジルは変わらなくなったので便利 ``` my $str = "hello!"; my Int $n = 10; my @array_test = 1..10; @array_test[0].say; my %hoge = ( foo => 'piyo', bar => 'baz'); %hoge{"foo"}.say; ``` --- ## オブジェクト感 - `.` の次にメソッドを書くと実行できる - `$hoge.say` のような雰囲気 - `$hoge.perl` で文字列に変換できる - おおよそだいたいのオブジェクトクラスは Mu から継承されている - 無らしい --- ## デフォルト値 - コンパイル時にデフォルト値を保存しておき、対象の変数にNilが代入されたらデフォルト値に差し替える ``` > my $x is default(42); 42 > $x = 10; 10 > $x = Nil; 42 ``` --- ## 演算子 - Rakuの演算子はbuilt-inでモリモリ入っている - 自分自身で演算子(該当するサブルーチン)を定義可能 --- ## Infix Operator - 代入 `=` - 加算 `+` - 割り切れるかどうか `say 10 %% 3; #False` - 文字列論理演算子 `say 'A' ~| ' '; #a` - 文字列論理演算子 `say 'A' ~^ ' '; #a` --- ## Junction ジャンクション 演算子 - スカラーコンテナに複数の条件をいれられる - any, all, one, none -junctionが存在する - any ``` > my $junc = 25|42; any(25, 42) ``` - all ``` > my $all_junc = 25 & 42; all(25, 42) ``` - one ``` > my $one_junc = (1..10).one; one(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) ``` --- ## Junction - リストの中身をjunctionにすることでリスト全てに操作が可能 ``` > say "hoge" if 4 & 6 > 0; hoge > my @hoge = 1..10; [1 2 3 4 5 6 7 8 9 10] > say "hoge" if @hoge > 0; hoge > say "hoge" if all(@hoge) > 0; hoge > say "hoge" if @hoge > 2; hoge > say "hoge" if all(@hoge) > 2; () ``` --- ## Junction - `so`ルーチンを使うと、ジャンクションをboolに折りたたむ事が可能 ``` > say 5 & 6 > 0; all(True, True) > say so 5 & 6 > 0; True ``` --- ## boolean operator - `?`を先頭につけるとboolが取れる ``` say ?True; say ?49; say ?""; ``` - `!` を先頭につけるとboolを反転したものが得られる ``` say !True; say !49; say !""; ``` --- ## 疲れてきたので - Rakuクイズです - 有効なPerl6の構文を選ぼう 1. `言う「こんにちは」` 2. `4 たす 6;` 3. `my @anatofuz = ("父", "母", "子供");末代まで呪う@anatofuz;` --- ## 答え - Rakuクイズです - 有効なPerl6の構文を選ぼう 1. `言う「こんにちは」` 2. `4 たす 6;` 3. `my @anatofuz = ("父", "母", "子供");末代まで呪う@anatofuz;` - 全部!!!! --- ## 日本語対応言語 - カギカッコが使用可能 - なでしこっぽいものが作れる ``` sub 言う($msg) { say $msg; } 言う 「hello」; ``` --- ## 演算子 - Raku幾つかのバリエーションに分類される - Infix - Prefix - Postfix - Circumfix - Postcircumfix - 全部自分で書ける --- ## オレオレ演算子 - sub `バリエーション`:<`定義`>で書ける --- ## Postfix ``` sub prefix:<末代まで呪う>(@hoge is raw) { @hoge.map({ $_ = "㊗" ~ $_ ~ "呪"}) } my @anatofuz = ("父", "母", "子供"); 末代まで呪う@anatofuz; say @anatofuz; ``` --- ## Infix ``` sub infix:<たす>($a, $b) { return $a + $b; } say 4 たす 6; ``` --- ## サブルーチン - subで定義する - 関数名の次の `()` に引数を記述する - Perl5のサブルーチンシグネチャをデフォルトで使う世界観 - 最後に評価されたものがreturnされる ``` sub add($left, $right) { $left + $right; } add(10,20); ``` --- ## サブルーチンのデフォルト引数 - 入力がない場合のデフォルト引数を `=` で書く事が可能 ``` sub add($left, $right = 1) { $left + $right; } add(10); ``` --- ## 名前付き引数 - `:` を先頭に書くことで名前付き引数を設定可能 - 名前付き引数は ` name => value` の順で記述する ``` sub bmi(:$height, :$weight) { return $weight/(($height/100)**2) } bmi(height => 170, weight => 50); ``` --- ## もとの変数を書き換えたい ``` sub setZero($n is raw) { $n = 0; } my $n = 10; setZero($number); ``` ``` sub prefix:<末代まで呪う>(@hoge is raw) { @hoge.map({ $_ = "㊗" ~ $_ ~ "呪"}) } ``` - 引数に `is` で条件を指定出来る --- ## literalはimmutableなので... - rawでも渡す値が数値のリテラルだとimmutableなのでエラーが出る - 変数を渡さなければならない ``` sub setZero($n is raw) { $n = 0; } setZero(5); ``` --- ## リストを受け取るサブルーチン ``` sub add(@arr) { [+] @arr } my @a = <10 20 30>; say add(@a); # 60 ``` --- ## プレースホルダ - Rakuではサブルーチン中2 `^` のTwigilを使うことで変数に自動的に名前をつけられる - 変数名のアルファベット順に割り振られる ``` sub greet { say "Hello, $^name!"; } greet('Mark'); # Hello, Mark! sub subtract { $^b - $^a } say subtract(10, 8); # -2 sub subtract2 { $^b - $^c } ``` --- ## 引数の型 - 引数の型を指定出来る - 型名のみだとコンパイルタイムでチェックされる ``` sub add(Int $x, Int $b) { return $x + $b; } say add(30,20); ``` ``` ===SORRY!=== Error while compiling placeholders.p6 Calling add(Str, Int) will never work with declared signature (Int $x, Int $b) at placeholders.p6:15 ------> say ⏏add("30",20); ``` - 型の後ろに `:D` トレイトを指定するとサブルーチンが実行(実際に値を受ける)までチェックされない ``` sub add(Int:D $x, Int:D $b) { return $x + $b; } say add(30,20); ``` `` - シグネチャと関数定義の間に `of` キーワードを使って指定する ``` sub add(Int $left, Int $right ) of Int { return $x + $y; } ``` - subの前に型を書くケース ``` my Int sub add(Int $left, Int $right ) of Int { return $x + $y; } ``` --- ## ポリモーフィズム - sub ではなく multi で複数の定義が書ける - 引数の型による分類も可能 ``` multi happy-birthday( $name ) { say "Happy Birthday $name !"; } # version 2 multi happy-birthday( $name, $age ) { say "Happy {$age}th Birthday $name !"; } # version 3 multi happy-birthday( :$name, :$age, :$title = 'Mr' ) { say "Happy {$age}th Birthday $title $name !"; } ``` --- ## Perl5の @_ は? - 使えないこともない ``` sub at_anderscore { my $str = @_.shift; say $str; } at_anderscore("hoge"); ``` - `.shift` 的なことは出来ず `@_.shift` とする必要がある - シグネチャを使った場合のほうが色々と便利なのであまり推奨されていない --- ## クラス - classで宣言する - 勝手に`.new`メソッドが生えてインスタンスが作れる - `.WHAT`でクラス名がわかる - 1つのファイルだけなら `unit class` で宣言可能 - mi6で作製すると自動でunit classされる ``` class AnaTofuZ { } my $an = AnaTofuZ.new(); say $an.WHAT; ``` --- ## クラスの比較 - `===` で本当に同じインスタンスか比較できる - `$anatofuz === $anatofuz9999` - `eqv` で同じクラスのインスタンスか比較できる - `$anatofuz eqv $anatofuz9999` --- ## フィールド - `has`のあとにいい感じのTwigilを指定して宣言 - publicなAPIは twigil を `.`にする - デフォルトはread onlyなので、上書きしたいなら `is` で権限を書く ``` class AnaTofuZ { has $.offer is rw; } $anatofuz.offer; $anatofuz.offer = 9000; ``` --- ## privateな変数 - twigilを `!` にすると外部からアクセスできない ``` class AnaTofuZ { has $!offer is rw; } ``` --- ## XS的なもの - Perl5では特定の処理を高速化したい時にXSを書きました - C言語でのPerlAPI - `JSON::XS`とかとか... - Raku/Perl6では? --- ## NativeCallの世界 - RakuではNativeCallインターフェイスを使うことでそれっぽいのが実現可能 - 共有ライブラリを実行時に読み込んでRakuのプログラムから利用可能 --- ## C言語のrand ``` #include <stdio.h> #include <stdlib.h> int main() { int r = rand(); printf("%i\n", r); return 0; } ``` --- ## RakuでCのrandを呼び出す - returnsで引数の型を指定する必要がある - intではなく `int32` や `int64` などの明確な型が必要 - nativeで読み込むモジュールファイルを指定する - このケースではlibcが呼び出される ``` use NativeCall; sub c_rand() returns int32 is native('c') is symbol('rand') {*} say c_rand(); ``` --- ## Rakuでforkする - forkシステムコールをシュッと呼び出すことも可能 - nativeのforkを実行して返り値に応じてsayする内容を変更する ``` use NativeCall; sub fork() returns int32 is native {}; given fork() { when 0 { say "I'm a kid!"; }; when * > 0 { say "I'm a parent. The kid is at $_"; }; default { die "Failed :("; }; } sleep .5; say 'Hello, World!'; # OUTPUT: # I'm a parent. The kid is at 13099 # I'm a kid! # Hello, World! # Hello, World! ``` --- ## NativeCallの世界 - ライブラリファイルにすれば呼び出されるので... - 実はgolangも `$go build -buildmode=c-shared -o libgo.so libgo.go` などとすると soが手に入る ``` package main import ( "C" ) //export helloGo func helloGo(n int) int { return n * 2 } func main() { } ``` --- ## NativeCallの世界 - golangを呼び出せるぞ!!! - RakuGo...? ``` use NativeCall; sub helloGo(int32) returns int32 is native('libgo.so') {*} say helloGo(5); ``` --- ## RakuのWAF - 何個かある - Crust - https://github.com/tokuhirom/p6-Crust - RakuのPlack実装 - Bailador - シンプルなWAF - Hematite - https://github.com/whity/perl6-hematite - Cro - https://cro.services/ - COMMAと同じくEDUMENTが作っているWAF - WAFというよりはリアクティブプログラミングフレームワークらしい - Uzu - 静的サイトジェネレーター(WAFではないですね...) --- ## RakuのWAF - 開発が止まっているものが多いのでCroを使うのが良さそう - PerlConではCroを使って実装してみた系の話がなんこかあった - CroでLDAPを実装した例も - croに関しては商用サポートもEDUMENTが行っています - cro開発スタッフはRakuの何かしらのコアメンバーだったりするので... --- ## Croの雰囲気 - わりと機能が揃っている気配がある - websocketに対応している - フロントはReact.js/Redux.jsでいける - いくつかCLIツールが同梱されている - 海外では幾つか動いたりしているケースもある --- ## croを使ってみる - `cro` コマンドで色々出来る - `cro stub` で雛形が生成できる - `cro stub http hello hello` --- ## おおもと - なんとなく雰囲気で何をやっているかわかる気がする - `application => routes()` 潔い ``` use Cro::HTTP::Log::File; use Cro::HTTP::Server; use Routes; my Cro::Service $http = Cro::HTTP::Server.new( http => <1.1 2>, host => %*ENV<HELLO_HOST> || die("Missing HELLO_HOST in environment"), port => %*ENV<HELLO_PORT> || die("Missing HELLO_PORT in environment"), tls => %( private-key-file => %*ENV<HELLO_TLS_KEY> || %?RESOURCES<fake-tls/server-key.pem> || "resources/fake-tls/server-key.pem", certificate-file => %*ENV<HELLO_TLS_CERT> || %?RESOURCES<fake-tls/server-crt.pem> || "resources/fake-tls/server-crt.pem", ), application => routes(), after => [ Cro::HTTP::Log::File.new(logs => $*OUT, errors => $*ERR) ] ); $http.start; say "Listening at https://%*ENV<HELLO_HOST>:%*ENV<HELLO_PORT>"; react { whenever signal(SIGINT) { say "Shutting down..."; $http.stop; done; } } ``` --- ## ルーティング - ルーティングは`Cro::HTTP::Router` を使う - 自動生成される `lib/Routes.pm6` ``` use Cro::HTTP::Router; use Cro::HTTP::Router::WebSocket; sub routes() is export { route { get -> { content 'text/html', "<h1> hello </h1>"; } my $chat = Supplier.new; get -> 'chat' { web-socket -> $incoming { supply { whenever $incoming -> $message { $chat.emit(await $message.body-text); } whenever $chat -> $text { emit $text; } } } } } } ``` --- ## ほかには - tlsのモック的なのも生成される - pemがいっぱい - Dockerfileも自動生成される ``` FROM croservices/cro-http-websocket:0.8.1 RUN mkdir /app COPY . /app WORKDIR /app RUN zef install --deps-only . && perl6 -c -Ilib service.p6 ENV HELLO_PORT="10000" HELLO_HOST="0.0.0.0" EXPOSE 10000 CMD perl6 -Ilib service.p6 ``` --- ## ORM - いろいろある - RedがRakuっぽくて良い - https://github.com/FCO/Red - Inline::Perl的な機能でPerl5のものを使う逃げ方もある --- ## RED - またWIPのORMらしい - APIのテスト助けてくれという段階らしい - DBのマイグレーションから面倒みてくれて賢い - 問題は遅いとこだけど... - zefでインストール可能だが、依存しているライブラリの中でuuidのバイナリを必要とするものがある - `$brew install ossp-uuid` とかしておく --- ## RED - てごろにSQLite3で試してみた - こういうスクリプトを書くといい感じに作ってくれる - 定義がRakuのクラスっぽくて良いですね ``` use Red; model Person { has UInt $.id is serial; has Str $.name is column; has Str $.email is column{ :nullable }; } my $*RED-DB = database "SQLite", :database("hoge.sqlite3"); Person.^create-table; Person.^create: :name<Fernando>, :email<fco@aco.com>; Person.^create: :name<Aline>, :email<aja@aco.com>; Person.^create: :name<Fernanda>; Person.^create: :name<Sophia>; .say for Person.^all.grep(*.email.defined).map: *.name; ``` --- ## まとめ - Rakuは様々なおもしろ機能がある - WAFで使うならCroがおすすめ