名前

Mojolicious::Guides::Tutorial - Mojoliciousをはじめよう

Mojolicious::Liteの特徴を簡単なサンプルで紹介していきます。 ここで学んだことは、ほとんどすべてがフルバージョンのMojoliciousアプリケーションにも当てはまります。

チュートリアルはMojolicious::Guidesのはじめの章です。その他のガイドでは、各トピックについて深く掘り下げます。たとえば、Mojolicious::Liteのプロトタイプをしっかり構築したMojolicious アプリケーションに育てるためのgrowing、またはroutingrendering、その他にもたくさんあります。これを読み終わった後は、残りのガイドを読むことををおすすめします。

Hello World!

かんたんなHello Worldアプリケーションはこのようになります。strict, warnings, utf8 、Perl 5.10のfeatures|feature が自動的に有効になり、 Mojolicious::Litefunctions がいくつかインポートされます。 Mojolicious::Liteを使うと、あなたのスクリプトは完全な機能を備えたウェブアプリケーションになります。

#!/usr/bin/env perl
use Mojolicious::Lite;

get '/' => sub {
my $c = shift;
$c->render(text => 'Hello World!');
};

app->start;

Mojolicious::Command::Author::generate::lite_app には、小さなアプリケーションサンプルを生成するためのヘルパーコマンドがあります。

$ mojo generate lite_app myapp.pl

コマンド

多くのcommands が自動的にコマンドラインから利用できるようになります。CGIまたはPSGI のどちらの環境であるかは自動的に検知されるため、通常はコマンドで指定しなくても動作します。

$ ./myapp.pl daemon
Server available at http://127.0.0.1:3000.

$ ./myapp.pl daemon --listen http://*:8080
Server available at http://127.0.0.1:8080.

$ ./myapp.pl cgi
...CGI output...

$ ./myapp.pl get /
Hello World!

$ ./myapp.pl
...利用可能なコマンドが表示(または自動的に環境が検知される)...

Mojoliciousstart (app->start)を呼び出すと、コマンドシステムが開始されます。この呼び出しはアプリケーションの最後に置くべきです。というのは、返り値が大きな影響をもつ場合があるからです。

# @ARGVを使ってコマンドを取得する
app->start;

# "daemon"コマンドを開始する
app->start('daemon', '-l', 'http://*:8080');

リロード

開発用サーバーのmorboでアプリケーションを起動すれば、 アプリケーションは自動的にリロードされます。ソースコードを変更した後に毎回サーバを再起動させる必要はありません。

$ morbo myapp.pl
Server available at http://127.0.0.1:3000.

アプリケーションのデプロイ方法について詳しい情報は、 Mojolicious::Guides::Cookbookデプロイメントの項目を見てください。

ルーティング(Routes)

ルーティング(routes)とは、一般的にいうと異なる種類のプレースホルダを含むことのできる仮想的なパスのことです。通常はアクションにつながっており、リクエストURLのパス部分にマッチしたときに実行されます。すべてのアクション($self)に渡される第一引数は、Mojolicious::Controllerのインスタンスです。これにはHTTPリクエストとレスポンスが含まれています。

use Mojolicious::Lite;

# テキストをレンダリングするアクションへのルーティング
get '/foo' => sub {
my $c = shift;
$c->render(text => 'Hello World!');
};

app->start;

レスポンスコンテントの多くは Mojolicious::Controllerrenderを使ったアクションによって生成されます。詳しくは後ほど。

GET/POSTパラメーター

すべてのGETPOSTパラメーターはMojolicious::Controllerparamを通じてアクセスできます。

use Mojolicious::Lite;

# /foo?user=sri
get '/foo' => sub {
my $c    = shift;
my $user = $c->param('user');
$c->render(text => "Hello $user.");
};

app->start;

スタッシュとテンプレート

Mojolicious::Controllerstashはデータをテンプレートに渡すために利用します。テンプレートはDATAセクションに埋め込むことができます。templatetextdataなどのいくつかがスタッシュの値として予約されており、Mojolicious::Controllerrenderで使われて、レスポンスをどのように生成するかが決定されます。

use Mojolicious::Lite;

# テンプレートを描画するアクションに至るルート
get '/foo' => sub {
my $c = shift;
$c->stash(one => 23);
$c->render(template => 'magic', two => 24);
};

app->start;
__DATA__;

@@ magic.html.ep
The magic numbers are <%= $one %> and <%= $two %>.

テンプレートについて詳しい情報は Mojolicious::Guides::Rendering埋め込みPerlの項を見てください。

HTTP

Mojolicious::ControllerreqMojolicious::Controllerres を使って、HTTPの機能と情報のすべてに完全にアクセスすることができます。

use Mojolicious::Lite;

# リクエストの情報にアクセス
get '/agent' => sub {
my $c    = shift;
my $host = $c->req->url->to_abs->host;
my $ua   = $c->req->headers->user_agent;
$c->render(text => "Request by $ua reached $host.");
};

# リクエストボディをエコーして、レスポンスのついたカスタムヘッダを送信
post '/echo' => sub {
my $c = shift;
$c->res->headers->header('X-Bender' => 'Bite my shiny metal ass!');
$c->render(data => $c->req->body);
};

app->start;

Mojolicious::Command::getを使って、 コマンドラインからより発展的なサンプルをテストできます。

$ ./myapp.pl get -v -M POST -c 'test' /echo

JSON

JSONは、ウェブサービスでもっともよく使われるデータ交換フォーマットです。 MojoliciousはJSONが大好きです。ピュアPerlの実装ではおそらく最速の Mojo::JSON が組み込まれており、Mojo::Messagejson または予約済みスタッシュ値のjsonによってアクセスできます。

use Mojolicious::Lite;

# 受け取ったJSONドキュメントを変更して返す
put '/reverse' => sub {
my $c    = shift;
my $hash = $c->req->json;
$hash->{message} = reverse $hash->{message};
$c->render(json => $hash);
};

app->start;

コマンドラインからMojolicious::Command::getを使ってJSONドキュメントを送信できます。

$ ./myapp.pl get -M PUT -c '{"message":"Hello Mojo!"}' /reverse

組み込みの例外(exception)とノットファウンド(not_found)ページ

開発中、間違いを犯したときはいつでも、 このページに遭遇するでしょう。ここには、素晴らしい、アプリケーションのデバックに役立つ 情報がたくさん含まれています。

use Mojolicious::Lite;

# Not found (404)
get '/missing' => sub { shift->render(template => 'does_not_exist') };

# Exception (500)
get '/dies' => sub { die 'Intentional error' };

app->start;

Mojolicious::Command::get でCSSセレクタを使えば、実際に知りたい情報だけを取り出すこともできます。

$ ./myapp.pl get /dies '#error'

ページに情報が見えすぎるからといって心配しないでください。これが有効になるのは開発中だけです。プロダクション環境では、大切な情報が表示されないページに自動的に置き換わります。

ルーティング名

すべてのルーティング(routes)には名前を付けることができます。名前を付けることによってテンプレートの自動検出やMojolicious::Controllerurl_forによる逆引きができるようになり、Mojolicious::Plugin::TagHelperslink_toなど、多くのヘルパーやメソッドがこれに基づいて動きます。

use Mojolicious::Lite;

# "index.html.ep"というテンプレートを描画
get '/' => sub {
my $c = shift;
$c->render;
} => 'index';

# "hello.html.ep"というテンプレートを描画
# "hello.html.ep"というテンプレートを描画

app->start;
__DATA__;

__DATA__;
__DATA__;
<%= link_to Reload => 'index' %>.

@@ hello.html.ep
Hello World!

名前がないルートには、自動生成されたルート名が割り当てられます。この名前は、ルート自身の名前からノンワード文字を除いたものと同じです。

レイアウト

テンプレートにはレイアウトを持たせることができます。レイアウトはMojolicious::Plugin::DefaultHelperslayoutヘルパーを使って選択することができ、Mojolicious::Plugin::DefaultHelperscontentヘルパーを使って現在のテンプレートの結果を入れることができます。

use Mojolicious::Lite;

get '/with_layout';

app->start;
__DATA__;

@@ with_layout.html.ep
% title 'Green';
% layout 'green';
Hello World!

@@ layouts/green.html.ep
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body><%= content %></body>
</html>

スタッシュやMojolicious::Plugin::DefaultHelperstitleのようなヘルパーを使うと、追加のデータをレイアウトに渡せます。

ブロック

テンプレートブロックは通常のPerl関数のように利用でき、常にbeginendというキーワードで区切ります。これは多くのヘルパーの基盤になっています。

use Mojolicious::Lite;

use Mojolicious::Lite;

app->start;
__DATA__;

@@ block.html.ep
% my $link = begin
% my ($url, $name) = @_;
Try <%= link_to $url => begin %><%= $name %><% end %>.
% end
<!DOCTYPE html>
<html>
<head><title>Sebastians frameworks</title></head>
<body>
%= $link->('http://mojolicious.org', 'Mojolicious')
%= $link->('http://catalystframework.org', 'Catalyst')
</body>
</html>

ヘルパー

ヘルパーは Mojolicious::Litehelper キーワードで作ることができる小さな関数です。アクションからテンプレートまでアプリケーション全体において利用することができます。

use Mojolicious::Lite;

# 訪問者を特定するヘルパー
helper whois => sub {
my $c     = shift;
my $agent = $c->req->headers->user_agent || 'Anonymous';
my $ip    = $c->tx->remote_address;
return "$agent ($ip)";
};

# アクションとテンプレートのなかでヘルパーを使う
get '/secret' => sub {
my $c    = shift;
my $user = $c->whois;
$c->app->log->debug("Request from $user");
};

app->start;
__DATA__;

@@ secret.html.ep
We know who you are <%= whois %>.

すべての組み込みヘルパーのリストは、 Mojolicious::Plugin::DefaultHelpersMojolicious::Plugin::TagHelpersにあります。

プレースホルダー

ルーティング(routes)プレースホルダを使用すると、区切り文字の / あるいは . が出現するまでの部分を、リクエストパスからキャプチャできます。結果はMojolicious::Controllerstashparamを通じて利用できます。

use Mojolicious::Lite;

# /foo/test
# /foo/test123
get '/foo/:bar' => sub {
my $c   = shift;
my $bar = $c->stash('bar');
$c->render(text => "Our :bar placeholder matched $bar");
};

# /testsomething/foo
# /test123something/foo
get '/<:bar>something/foo' => sub {
my $c   = shift;
my $bar = $c->param('bar');
$c->render(text => "Our :bar placeholder matched $bar");
};

app->start;

プレースホルダーを周囲の文字列と区別するためには、 <> で囲みます。こうした場合、プレフィックスのコロンはオプションになります。

リラックスプレースホルダー

リラックスプレースホルダーを使えば、 /が出現するまでのすべてにマッチさせることができます。これは正規表現の([^/]+)に似ています。

use Mojolicious::Lite;

use Mojolicious::Lite;
# /hello/test.html
get '/hello/*you' => 'groovy';

app->start;
__DATA__;

__DATA__;
Your name is <%= $you %>.

ワイルドカードプレースホルダー

ワイルドカードプレースホルダを使用すると、/.を含むすべてにマッチさせることができます。正規表現の(.+)に似ています。

use Mojolicious::Lite;

use Mojolicious::Lite;
# /hello/test123
# /hello/test.123/test/123
get '/hello/*you' => 'groovy';

app->start;
__DATA__;

__DATA__;
Your name is <%= $you %>.

HTTPメソッド

ルーティングは Mojolicious::Lite/getMojolicious::Liteanyといったキーワードによって特定のリクエストメソッドに限定できます。

use Mojolicious::Lite;

# "hello.html.ep"というテンプレートを描画
# "hello.html.ep"というテンプレートを描画
my $c = shift;
$c->render(text => 'Hello World!');
};

# PUT /hello
put '/hello' => sub {
my $c    = shift;
my $size = length $c->req->body;
$c->render(text => "You uploaded $size bytes to /hello.");
};

# GET|POST|PATCH /bye
any ['GET', 'POST', 'PATCH'] => '/bye' => sub {
my $c = shift;
$c->render(text => 'Bye World!');
};

# * /whatever
any '/whatever' => sub {
my $c      = shift;
my $method = $c->req->method;
$c->render(text => "You called /whatever with $method.");
};

app->start;

プレースホルダーのオプション

すべてのプレースホルダーは値を必要としますが、 プレースホルダーにデフォルト値を設定することにより キャプチャをオプショナルなものにすることができます。

use Mojolicious::Lite;

# /hello
# /hello/Sara
get '/hello/:name' => {name => 'Sebastian', day => 'Monday'} => sub {
my $c = shift;
$c->render(template => 'groovy', format => 'txt');
};

app->start;
__DATA__;

@@ groovy.txt.ep
My name is <%= $name %> and it is <%= $day %>.

プレースホルダーに所属しないデフォルト値は、 いつでも単純にスタッシュにマージされます。

制約的なプレースホルダー

プレースホルダーにより多くの制約を加えるには、選択肢を使うのが一番簡単です。候補となる値のリストを作るだけでOKです。

use Mojolicious::Lite;

# /test
# /123
any '/:foo' => [foo => ['test', '123']] => sub {
my $c   = shift;
my $foo = $c->param('foo');
$c->render(text => "Our :foo placeholder matched $foo");
};

app->start;

すべてのプレースホルダーは、内部で正規表現にコンパイルされます。この処理はカスタマイズすることもできます。^$を使ったり、(...)でグループのキャプチャは行わないでください。けれどもキャプチャしない(?:...)は大丈夫です。

use Mojolicious::Lite;

use Mojolicious::Lite;
# /123
any '/:bar' => [bar => qr/\d+/] => sub {
my $c   = shift;
my $bar = $c->param('bar');
$c->render(text => "Our :bar placeholder matched $bar");
};

app->start;

生成されたすべての正規表現は、 Mojolicious::Command::routesで詳しく確認することができます。

$ ./myapp.pl routes -v

アンダー (Under)

認証や複数のルーティングの間でコードを共有するためには、Mojolicious::Liteunder構文を使う簡単です。以降のすべてのルーティングは、underコールバックが真値を返したときだけ評価されます。

use Mojolicious::Lite;

# nameパラメータを元にした認証
# すべてのルートで共有されるグローバルなロジック
my $c = shift;

# 認証された
my $name = $c->param('name') || '';
my $name = $self->param('name') || '';

# 認証されなかった
$c->render(template => 'denied');
return undef;
};

# / (with authentication)
get '/' => 'index';

app->start;
__DATA__;

__DATA__;
You are not Bender, permission denied.

__DATA__;
Hi Bender.

複数のルーティングをあらかじめ決めるために使うのもまた良い利用方法です。

use Mojolicious::Lite;

# /foo
under '/foo';

# /foo/bar
get '/bar' => {text => 'foo bar'};

# /foo/baz
get '/baz' => {text => 'foo baz'};

# /
under '/' => {msg => 'whatever'};

# /bar
get '/bar' => {inline => '<%= $msg %> works'};

app->start;

Mojolicious::Litegroupで関連するルーティングをグループ化(group)することもできます。これによって、underで生成したルートをネストできるようになります。

use Mojolicious::Lite;

# すべてのルートで共有されるグローバルなロジック
# すべてのルートで共有されるグローバルなロジック
my $c = shift;
return 1 if $c->req->headers->header('X-Bender');
$c->render(text => "You're not Bender.");
return undef;
};

# Adminの部分
group {

# グループ内のルートだけに共有されるローカルなロジック
under '/admin' => sub {
my $c = shift;
return 1 if $c->req->headers->header('X-Awesome');
$c->render(text => "You're not awesome enough.");
return undef;
};

# GET /admin/dashboard
get '/dashboard' => {text => 'Nothing to see here yet.'};
};

# GET /welcome
get '/welcome' => {text => 'Hi Bender.'};

app->start;

フォーマット

フォーマット(formats)は、.htmlなどのファイル拡張子によって自動的に検出されます。フォーマットは正しいテンプレートを探したり、正確なContent-Typeヘッダーを生成するために使用されます。

use Mojolicious::Lite;

use Mojolicious::Lite;
# /detection.html
# /detection.txt
get '/detection' => sub {
my $c = shift;
$c->render(template => 'detected');
};

app->start;
__DATA__;

@@ detected.html.ep
<!DOCTYPE html>
<html>
<head><title>Detected</title></head>
<body>HTML was detected.</body>
</html>

@@ detected.txt.ep
TXT was detected.

デフォルトのフォーマットは htmlです。プレースホルダで制限すれば、取りうる値を限定できます。

use Mojolicious::Lite;

# /hello.json
# /hello.txt
get '/hello' => [format => ['json', 'txt']] => sub {
my $c = shift;
return $c->render(json => {hello => 'world'})
if $c->stash('format') eq 'json';
$c->render(text => 'hello world');
};

app->start;

フォーマットの検知は、特別なタイプのプレースホルダーを使うことで無効にすることもできます。

use Mojolicious::Lite;

# /hello
get '/hello' => [format => 0] => {text => 'No format detection.'};

# 検出を無効にして、以降のルートにおいて必要であれば再び有効にする
under [format => 0];

# /foo
get '/foo' => {text => 'No format detection again.'};

# /bar.txt
get '/bar' => [format => 'txt'] => {text => ' Just one format.'};

app->start;

コンテントネゴシエーション

異なる方法で表現されるリソースや本当にRESTfulなコンテントネゴーシエーションが必要な場合は、Mojolicious::Plugin::DefaultHelpersrespond_toを使用することもできます。

use Mojolicious::Lite;

# /hello (Accept: application/json)
# /hello (Accept: application/xml)
# /hello.json
# /hello.xml
# /hello?format=json
# /hello?format=xml
# "hello.html.ep"というテンプレートを描画
my $c = shift;
$c->respond_to(
json => {json => {hello => 'world'}},
xml  => {text => '<hello>world</hello>'},
any  => {data => '', status => 204}
);
};

app->start;

MIMEタイプのマッピングは、Mojolicioustypesによって拡張したり、変更したりすることができます。

app->types->type(rdf => 'application/rdf+xml');

静的ファイル

テンプレートに似て、静的ファイルはDATAセクションの中にインラインで記述することができ、自動的にサーブされます。ただし、使える拡張子が1種類に限られるのと、Base64エンコーディングが使える点が異なります。

use Mojolicious::Lite;

app->start;
__DATA__;

@@ something.js
alert('hello!');

@@ test.txt (base64)
dGVzdCAxMjMKbGFsYWxh

外部に置いた静的ファイルは、拡張子が1種類に制限されず、publicディレクトリが存在すればそこから自動的にサーブされます。

$ mkdir public
$ mv something.js public/something.js
$ mv mojolicious.tar.gz public/mojolicious.tar.gz

両方とも優先度はGETHEADリクエストのルーティングよりも高くなります。 RangeIf-None-MatchIf-Modified-Sinceヘッダー によるコンテンツネゴシエーションにも対応していて、 Mojolicious::Command::getで簡単にテストできます。

$ ./myapp.pl get /something.js -v -H 'Range: bytes=2-4'

外部テンプレート

外部テンプレートは、レンダラによってtemplates ディレクトリから検索されます。

$ mkdir -p templates/foo
$ echo 'Hello World!' > templates/foo/bar.html.ep

これらはDATAセクションにあるテンプレートよりも優先されます。

use Mojolicious::Lite;

# "templates/foo/bar.html.ep"というテンプレートを描画する
any '/external' => sub {
my $c = shift;
$c->render(template => 'foo/bar');
};

app->start;

ホーム

Mojolicioushome を使うと、アプリケーションがホームとしているディレクトリにアクセスできます。ホームディレクトリは、アプリケーションがpublic, templatesディレクトリを検索する場所です。ここにあらゆる種類のアプリケーションデータを保存することもできます。

$ mkdir cache
$ echo 'Hello World!' > cache/hello.txt

Mojo::Home には Mojo::Fileから継承した便利なメソッドがたくさんあります。たとえば、Mojo::Filechildslurpは、アプリケーションを様々なオペレーティングシステムにまたがって使用できるようにしています。

use Mojolicious::Lite;

# メッセージをメモリに読み込む
my $hello = app->home->child('cache', 'hello.txt')->slurp;

# メッセージを表示する
get '/' => sub {
my $c = shift;
$c->render(text => $hello);
};

Mojolicious::Command::eval を使うことでも、コマンドラインからアプリケーションを検証できます。

$ ./myapp.pl eval -v 'app->home'

条件

Mojolicious::Plugin::HeaderConditionagenthostといった条件 を使用すれば、より強力なルーティングを構築できます。

use Mojolicious::Lite;

# Firefox
get '/foo' => (agent => qr/Firefox/) => sub {
my $c = shift;
$c->render(text => 'Congratulations, you are using a cool browser.');
};

# Internet Explorer
get '/foo' => (agent => qr/Internet Explorer/) => sub {
my $c = shift;
$c->render(text => 'Dude, you really need to upgrade to Firefox.');
};

# http://mojolicious.org/bar
get '/bar' => (host => 'mojolicious.org') => sub {
my $c = shift;
$c->render(text => 'Hello Mojolicious.');
};

app->start;

セッション

Mojolicious::Plugin::DefaultHelperssessionヘルパーを使うとすぐに、クッキーをベースとしたセッションが機能します。すべてのセッションデータはMojo::JSONでシリアライズされ、 クライアントサイドに保存されることを意識しておいてください。改ざんを防ぐために、暗号化された署名がついています。

use Mojolicious::Lite;

# アクションとテンプレートの中のセッションデータへのアクセス
get '/counter' => sub {
my $c = shift;
$c->session->{counter}++;
};

app->start;
__DATA__;

__DATA__;
Counter: <%= session 'counter' %>

署名付き(signed)クッキーを本当に改ざんできなくするには、Mojolicioussecretをカスタムして使用してください。

app->secrets(['My secret passphrase here']);

ファイルアップロード

ファイルは、multipart/form-dataリクエストを通してアップロードされると、自動的に Mojolicious::ControllerparamからMojo::Uploadのインスタンスとして利用可能になります。 メモリの使用率を気にする必要はありません。250KBを超えるすべてのファイルは自動的に一時ファイルに保存されるからです。HTMLフォームを効率的に構築するために、 Mojolicious::Plugin::TagHelpersform_forのような タグヘルパーを使うこともできます。

use Mojolicious::Lite;

# DATAセクションのformをアップロード
get '/' => 'form';

# Multipartのアップロードのハンドラ
post '/upload' => sub {
my $c = shift;

# ファイルサイズのチェック
return $c->render(text => 'File is too big.', status => 200)
if $c->req->is_limit_exceeded;

# アップロードしたファイルを処理
return $c->redirect_to('form') unless my $example = $c->param('example');
my $size = $example->size;
my $name = $example->filename;
$c->render(text => "Thanks for uploading $size byte file $name.");
};

app->start;
__DATA__;

@@ form.html.ep
<!DOCTYPE html>
<html>
<head><title>Upload</title></head>
<body>
%= form_for upload => (enctype => 'multipart/form-data') => begin
%= file_field 'example'
%= submit_button 'Upload'
% end
</body>
</html>

極端に大きなファイルから保護するために、デフォルトで16MBの制限があります。サイズはMojoliciousmax_request_size 属性で変更できます。

# 制限を1GBに増やす
app->max_request_size(1073741824);

ユーザーエージェント

Mojo::UserAgentは、完全に機能を備えたHTTP 1.1とWebSocketの組み込みのユーザーエージェントです。Mojolicious::Plugin::DefaultHelpersuaを通して利用できます。特にMojo::JSONMojo::DOMの組み合わせはとても強力なツールになります。

use Mojolicious::Lite;

# ブロッキング
# ブロッキング
my $c   = shift;
my $url = $c->param('url') || 'https://mojolicious.org';
my $dom = $c->ua->get($url)->result->dom;
$c->render(json => $dom->find('h1, h2, h3')->map('text')->to_array);
};

# ノンブロッキング
get '/title' => sub {
my $c = shift;
$c->ua->get('mojolicious.org' => sub {
my ($ua, $tx) = @_;
$c->render(data => $tx->result->dom->at('title')->text);
});
};

# 並列のノンブロッキング
get '/titles' => sub {
my $c  = shift;
my $c = shift;
my $cpan = $c->ua->get_p('https://metacpan.org');
Mojo::Promise->all($mojo, $cpan)->then(sub {
my ($mojo, $cpan) = @_;
$c->render(json => {
mojo => $mojo->[0]->result->dom->at('title')->text,
cpan => $cpan->[0]->result->dom->at('title')->text
});
})->wait;
};

app->start;

ユーザーエージェントについてより詳しい情報は、Mojolicious::Guides::Cookbookユーザーエージェントの項目にあります。

WebSocket

WebSocketアプリケーションはこれまでに見たこともないくらい簡単です。Mojo::Transaction::WebSocketjsonと同じイベントを、Mojolicious::Controlleronを使って購読することによってメッセージを受信できます。メッセージを送信するには Mojolicious::Controllersendを使います。

use Mojolicious::Lite;

use Mojolicious::Lite;
my $c = shift;
$c->on(json => sub {
my ($c, $hash) = @_;
my ($self, $hash) = @_;
$c->send({json => $hash});
});
};

get '/' => 'index';

app->start;
__DATA__;

__DATA__;
<!DOCTYPE html>
<html>
<head>
<title>Echo</title>
<script>
var ws = new WebSocket('<%= url_for('echo')->to_abs %>');
ws.onmessage = function (event) {
document.body.innerHTML += JSON.parse(event.data).msg;
};
ws.onopen = function (event) {
ws.send(JSON.stringify({msg: 'I ♥ Mojolicious!'}));
};
</script>
</head>
</html>

リアルタイムウェブ機能についてのより詳しい情報は、Mojolicious::Guides::CookbookREAL-TIME WEBにあります。

モード

ポータブルにデバッグメッセージを収集するために、MojologメソッドでMojo::Logオブジェクトを利用できます。Mojoliciousの処理モードを変更することによって、後のプロダクション用の設定においてデバッグを自動的に無効化することができます。これはMojoliciousmode属性によって読み取り可能です。

use Mojolicious::Lite;

# startupの間にモードに合ったメッセージを準備する
my $msg = app->mode eq 'development' ?'Development!' : 'Something else!';

get '/' => sub {
my $c = shift;
$c->app->log->debug('Rendering mode specific message');
$c->render(text => $msg);
};

app->log->debug('Starting application.');
app->start;

デフォルトの処理モードは通常 developmentですが、コマンドラインオプションか MOJO_MODEあるいはPLACK_ENV環境変数によって変更することもできます。development以外のモードでは、ログレベルがdebugからinfoに上がります。

$ ./myapp.pl daemon -m production

すべてのメッセージはSTDERRに出力されるか、 logディレクトリが存在する場合はlog/$mode.logに出力されます。

$ mkdir log

モードの変更は、exceptionnot_foundテンプレートなどのフレームワークのその他の面に影響します。モードをdevelopmentからproductionに切り替えると 、例外ページに機密情報が表示されなくなります。

テスト

アプリケーションをテストするのはとても簡単です。tディレクトリを作成して 普通のPerlの単体テストを書くだけです。Test::Mojoのおかげで、 とても楽しいです。

use Test::More;
use Mojo::File 'path';
use Test::Mojo;

# Portably point to "../myapp.pl"
my $script = path(__FILE__)->dirname->sibling('myapp.pl');

my $t = Test::Mojo->new($script);
$t->get_ok('/')->status_is(200)->content_like(qr/Funky/);

done_testing();

テストはproveで実行します。

$ prove -l -v
$ prove -l -v t/basic.t

もっと

さあ、Mojolicious::Guides を続けるか、Mojolicious wikiを見てみましょう。多くの著者がたくさんのドキュメントやサンプルを書いています。

サポート

このドキュメントでわからない部分があれば、 mailing listirc.freenode.net (chat now!)の公式IRCチャンネル #mojo まで気軽に質問してください。

参考

Mojolicious, Mojolicious::Guides, http://mojolicio.us.

(2019/03/16 Mojolicious 8.12)