Mojolicious-8.12 > Mojolicious::Guides::Rendering
Mojolicious-8.12

名前

Mojolicious::Guides::Rendering - Rendering content

Mojolicious::Guides::Rendering - コンテンツのレンダリング

説明

This document explains content generation with the Mojolicious renderer.

本書は、Mojoliciousレンダラを使ったコンテンツ生成について説明します。

概念

Essentials every Mojolicious developer should know.

すべてのMojolicious開発者が知るべき本質

レンダラ

The renderer is a tiny black box turning stash data into actual responses utilizing multiple template systems and data encoding modules.

レンダラは、複数のテンプレートシステムとデータエンコードモジュールを利用して、スタッシュデータを実際のレスポンスに変換する小さなブラックボックスです。

  {text => 'Hello.'}                 -> 200 OK, text/html, 'Hello.'
  {json => {x => 3}}                 -> 200 OK, application/json, '{"x":3}'
  {text => 'Oops.', status => '410'} -> 410 Gone, text/html, 'Oops.'

Templates can be automatically detected if enough information is provided by the developer or routes. Template names are expected to follow the template.format.handler scheme, with template defaulting to controller/action or the route name, format defaulting to html and handler to ep.

開発者またはルーティングから十分な情報が提供されれば、テンプレートは自動的に検出されます。テンプレート名はtemplate.format.handler命名規則に従うことが期待されています。templateはデフォルトではcontroller/actionまたはルート名です。デフォルトのformathtmlhandlerep です。

  {controller => 'users', action => 'list'} -> 'users/list.html.ep'
  {template => 'foo', format => 'txt'}      -> 'foo.txt.ep'
  {template => 'foo', handler => 'epl'}     -> 'foo.html.epl'

The controller value gets converted from CamelCase to snake_case using "decamelize" in Mojo::Util and - characters replaced with /.

controller値は、"decamelize" in Mojo::UtilによってCamelCaseからsnake_caseに変換されます。-文字は/ に置き換えられます。

  {controller => 'My::Users', action => 'add'} -> 'my/users/add.html.ep'
  {controller => 'my-users', action => 'show'} -> 'my/users/show.html.ep'

All templates should be in the templates directories of the application, which can be customized with "paths" in Mojolicious::Renderer, or one of the the DATA sections from "classes" in Mojolicious::Renderer.

テンプレートはすべてアプリケーションのtemplatesディレクトリに置いてください。このパスは"paths" in Mojolicious::Rendererで変更できます。または、"classes" in Mojolicious::RendererのうちいずれかのDATAセクションに記述してください。

  __DATA__

  @@ time.html.ep
  % use Time::Piece;
  % my $now = localtime;
  <!DOCTYPE html>
  <html>
    <head><title>Time</title></head>
    <body>The time is <%= $now->hms %>.</body>
  </html>

  @@ hello.txt.ep
  ...

The renderer can be easily extended to support additional template systems with plugins, but more about that later.

レンダラは、プラグインを使用して追加のテンプレートシステムをサポートするように簡単に拡張できますが、それについては後で詳しく説明します。

埋め込みPerl

Mojolicious includes a minimalistic but very powerful template system out of the box called Embedded Perl or ep for short. It is based on Mojo::Template and allows the embedding of Perl code right into actual content using a small set of special tags and line start characters. For all templates strict, warnings, utf8 and Perl 5.10 features are automatically enabled.

Mojoliciousには埋め込みPerlまたはepと呼ばれる、すぐに使える最小限でありながら非常に強力なテンプレートシステムが含まれています。それはMojo::Templateに基づいています。そして、少数の特別なタグと改行文字を使ってPerlコードを実際のコンテンツに埋め込むことができます。すべてのテンプレートに対してstrictwarningsutf8とPerl 5.10 featuresが自動的に有効になります。

  <% Perl code %>
  <%= Perl expression, replaced with XML escaped result %>
  <%== Perl expression, replaced with result %>
  <%# Comment, useful for debugging %>
  <%% Replaced with "<%", useful for generating templates %>
  % Perl code line, treated as "<% line =%>" (explained later)
  %= Perl expression line, treated as "<%= line %>"
  %== Perl expression line, treated as "<%== line %>"
  %# Comment line, useful for debugging
  %% Replaced with "%", useful for generating templates
  <% Perlコード %>
  <%= Perl式、XML文字がエスケープされた結果が返されます %>
  <%== Perl式、評価結果が返されます %>
  <%# デバッグに役立つコメント %>
  <%% "<%"に置換されます。テンプレートの生成に使えます %>
  % Perlコード行、"<% line =%>"(説明は後ほど)として扱われます
  %= Perl式行、"<%= line %>"として扱われます
  %== Perl式行、"<%== line %>"として扱われます
  %# コメント行、デバッグに役立ちます
  %% "%"に置き換えられ、テンプレートを生成するのに便利です

Tags and lines work pretty much the same, but depending on context one will usually look a bit better. Semicolons get automatically appended to all expressions.

タグと行はほとんど同じように機能しますが、コンテキストによって使い分けると見た目が少し良くなるでしょう。セミコロンは、すべての式に自動で追加されます。

  <% my $i = 10; %>
  <ul>
    <% for my $j (1 .. $i) { %>
      <li>
        <%= $j %>
      </li>
    <% } %>
  </ul>

  % my $i = 10;
  <ul>
    % for my $j (1 .. $i) {
      <li>
        %= $j
      </li>
    % }
  </ul>

Aside from differences in whitespace handling, both examples generate similar Perl code, a naive translation could look like this.

空白文字の扱いが異なることを別にすれば、両方のサンプルは似たPerlのコードを生成します。そのまま変換すると次のようになるでしょう。

  my $output = '';
  my $i = 10;
  $output .= '<ul>';
  for my $j (1 .. $i) {
    $output .= '<li>';
    $output .= xml_escape scalar + $j;
    $output .= '</li>';
  }
  $output .= '</ul>';
  return $output;

An additional equal sign can be used to disable escaping of the characters <, >, &, ' and " in results from Perl expressions, which is the default to prevent XSS attacks against your application.

イコールサインを追加すると、Perl式の結果に含まれる文字列<>&'"のエスケープを無効にできます。エスケープは、アプリケーションに対するXSS攻撃を防ぐためにデフォルトでおこなわれます。

  <%= 'I ♥ Mojolicious!' %>
  <%== '<p>I ♥ Mojolicious!</p>' %>

Only Mojo::ByteStream objects are excluded from automatic escaping.

Mojo::ByteStreamオブジェクトだけは自動エスケープの対象外です。

  <%= b('<p>I ♥ Mojolicious!</p>') %>

Whitespace characters around tags can be trimmed by adding an additional equal sign to the end of a tag.

タグの前後にある文字列は、追加のイコール記号をタグの最後につけることによって、除去できます。

  <% for (1 .. 3) { %>
    <%= 'Trim all whitespace characters around this expression' =%>
  <% } %>
  <% for (1 .. 3) { %>
    <%= 'この式の前後にある空白文字はトリムされます' =%>
  <% } %>

Newline characters can be escaped with a backslash.

改行はバックスラッシュでエスケープできます。

  This is <%= 1 + 1 %> a\
  single line
  これは <%= 1 + 1 %> \
  1行になります

And a backslash in front of a newline character can be escaped with another backslash.

改行の直前のバックスラッシュはもう一つのバックスラッシュ によってエスケープできます。

  This will <%= 1 + 1 %> result\\
  in multiple\\
  lines
  これは <%= 1 + 1 %> \\
  複数行に \\
  なります

A newline character gets appended automatically to every template, unless the last character is a backslash. And empty lines at the end of a template are ignored.

最後の文字がバックスラッシュでない限り、改行文字はすべてのテンプレートに自動的に追加されます。また、テンプレートの末尾の空行は無視されます。

  There is <%= 1 + 1 %> no newline at the end here\
  末尾に改行文字が付きません <%= 1 + 1 %> \

At the beginning of the template, stash values that don't have invalid characters in their name get automatically initialized as normal variables, and the controller object as both $self and $c.

テンプレートの最初で、名前に無効な文字を含まないスタッシュ値は通常の変数として自動的に初期化され、コントローラオブジェクトは$self$cの両方が自動的に初期化されます。

  $c->stash(name => 'tester');

  Hello <%= $name %> from <%= $c->tx->remote_address %>.

A prefix like myapp.* is commonly used for stash values that you don't want to expose in templates.

myapp.*のようなプレフィックスは、通常はテンプレートの中で見せたくないスタッシュ値に使います。

  $c->stash('myapp.name' => 'tester');

There are also many helper functions available, but more about that later.

たくさんのヘルパー関数が利用可能ですが、後ほど紹介します。

  <%= dumper {foo => 'bar'} %>

基礎

Most commonly used features every Mojolicious developer should know about.

すべてのMojolicious開発者が知っておくべきもっとも一般的に利用される機能

自動的な描画

The renderer can be manually started by calling the method "render" in Mojolicious::Controller, but that's usually not necessary, because it will get automatically called if nothing has been rendered after the router finished its work. This also means you can have routes pointing only to templates without actual actions.

"render" in Mojolicious::Controllerメソッドを呼び出すことで、レンダラを手動で起動できます。しかし、通常は必要ありません。なぜならルータの処理が終わったとき、何もレンダリングされていない場合はレンダラが自動的に呼び出されるからです。これは、何もアクションを実行しない、テンプレートだけを指し示すルーティングを作成できるということです。

  $c->render;

There is one big difference though, by calling it manually you can make sure that templates use the current controller object, and not the default controller specified with the attribute "controller_class" in Mojolicious.

ただし、大きな違いがひとつあります。renderを手動で呼ぶことによって、テンプレートが現在のコントローラオブジェクトを使用し、アプリケーションクラスの"controller_class" in Mojolicious属性で指定されたデフォルトコントローラを使用しないことを保証できます。

  $c->render_later;

You can also disable automatic rendering with the method "render_later" in Mojolicious::Controller, which can be very useful to delay rendering when a non-blocking operation has to be performed first.

"render_later" in Mojolicious::Controllerメソッドを使って自動レンダリングを無効にすることもできます。 これは、ノンブロッキング操作を先に実行したい場合にレンダリングを遅らせるのに非常に便利です。

テンプレートの描画

The renderer will always try to detect the right template, but you can also use the template stash value to render a specific one. Everything before the last slash will be interpreted as the subdirectory path in which to find the template.

レンダラはいつも正しいテンプレートを検知しようとしますが、スタッシュのtemplateの値を使って描画するテンプレートを指定することもできます。最後のスラッシュより前の部分は、テンプレートを探すサブディレクトリとして解釈されます。

  # foo/bar/baz.*.*
  $c->render(template => 'foo/bar/baz');

Choosing a specific format and handler is just as easy.

特定のformathandlerを選択することも同様に簡単です。

  # foo/bar/baz.txt.epl
  $c->render(template => 'foo/bar/baz', format => 'txt', handler => 'epl');

Because rendering a specific template is the most common task it also has a shortcut.

特定のテンプレートの描画は、とてもよくあるタスクなのでショートカットが用意されています。

  $c->render('foo/bar/baz');

If you're not sure in advance if a template actually exists, you can also use the method "render_maybe" in Mojolicious::Controller to try multiple alternatives.

テンプレートが実際に存在するかどうかわからない場合には、複数ある代わりのテンプレートを試すために "render_maybe" in Mojolicious::Controllerメソッドを使うこともできます。

  $c->render_maybe('localized/baz') or $c->render('foo/bar/baz');

文字列への描画

Sometimes you might want to use the rendered result directly instead of generating a response, for example, to send emails, this can be done with "render_to_string" in Mojolicious::Controller.

描画の結果をレスポンスとして生成するのではなく、直接使いたい場合もあることでしょう。たとえば、Eメールを送る場合などです。"render_to_string" in Mojolicious::Controller を使って行えます。

  my $html = $c->render_to_string('mail');

No encoding will be performed, making it easy to reuse the result in other templates or to generate binary data.

エンコーディングは実行されません。結果を他のテンプレートで再利用したり、バイナリデータを生成することが簡単になります。

  my $pdf = $c->render_to_string('invoice', format => 'pdf');
  $c->render(data => $pdf, format => 'pdf');

All arguments passed will get localized automatically and are only available during this render operation.

すべての渡された引数は、自動的にローカライズされ、 描画処理の間だけ利用できます。

テンプレートバリアント

To make your application look great on many different devices you can also use the variant stash value to choose between different variants of your templates.

異なったデバイス間でアプリケーションの見た目をよくするためには、複数あるテンプレートからいずれかを選択するために、variantスタッシュ値が利用できます。

  # foo/bar/baz.html+phone.ep
  # foo/bar/baz.html.ep
  $c->render('foo/bar/baz', variant => 'phone');

This can be done very liberally since it only applies when a template with the correct name actually exists and falls back to the generic one otherwise.

このスタッシュ値はとても自由に使えます。なぜなら、その名前のテンプレートが実際に存在したときだけ適用され、存在しなければ一般的なテンプレートにフォールバックするからです。

インラインテンプレートの描画

Some renderers such as ep allow templates to be passed inline.

epのようないくつかのレンダラは、テンプレートをインラインで渡すことができます。

  $c->render(inline => 'The result is <%= 1 + 1 %>.');
  $c->render(inline => 'The result is <%= 1 + 1%>!');

Since auto-detection depends on a path you might have to supply a handler too.

自動検知はパスに依存するため、handlerを与える必要があるかもしれません。

  $c->render(inline => "<%= shift->param('foo') %>", handler => 'epl');

テキストの描画

Characters can be rendered to bytes with the text stash value, the given content will be automatically encoded with "encoding" in Mojolicious::Renderer.

文字列はtextスタッシュ値を使ってバイトに変換できます。与えた値は"encoding" in Mojolicious::Rendererで自動的にエンコードされます。

  $c->render(text => 'I ♥ Mojolicious!');

データの描画

Bytes can be rendered with the data stash value, no encoding will be performed.

生のバイトはスタッシュのdataの値によって描画できます。エンコーディングは実行されません。

  $c->render(data => $bytes);

JSONの描画

The json stash value allows you to pass Perl data structures to the renderer which get directly encoded to JSON with Mojo::JSON.

スタッシュのjson の値を使用すると、Perlデータ構造がレンダラに渡され、Mojo::JSONを使用してJSONに直接エンコードされます。

  $c->render(json => {foo => [1, 'test', 3]});

ステータスコード

Response status codes can be changed with the status stash value.

レスポンスのステータスコードを、スタッシュのstatusの値によって変更できます。

  $c->render(text => 'Oops.', status => 500);

コンテンツタイプ

The Content-Type header of the response is actually based on the MIME type mapping of the format stash value.

レスポンスのContent-Typeヘッダは、実際のスタッシュのformatの値に対応するMIMEタイプが元になっています。

  # Content-Type: text/plain
  $c->render(text => 'Hello.', format => 'txt');

  # Content-Type: image/png
  $c->render(data => $bytes, format => 'png');

These mappings can be easily extended or changed with "types" in Mojolicious.

これらの対応は、"types" in Mojoliciousを使って、簡単に拡張したり変更したりできます。

  # Add new MIME type
  $app->types->type(md => 'text/markdown');
  # 新しいMIMEタイプの追加
  $app->types->type(md => 'text/markdown');

スタッシュデータ

Any of the native Perl data types can be passed to templates as references through the "stash" in Mojolicious::Controller.

データは、どのようなPerlのネイティブなデータ型のものであれ、stashを通してテンプレートにレファレンスとして渡せます。

  $c->stash(description => 'web framework');
  $c->stash(frameworks  => ['Catalyst', 'Mojolicious']);
  $c->stash(spinoffs    => {minion => 'job queue'});
  %= $description
  %= $frameworks->[1]
  %= $spinoffs->{minion}
  %= $frameworks->[1]
  %= $spinoffs->{minion}

Since everything is just Perl normal control structures just work.

以下はすべてPerlの通常の制御構造なので、どれもうまく動きます。

  % for my $framework (@$frameworks) {
    <%= $framework %> is a <%= $description %>.
  % }

  % if (my $description = $spinoffs->{minion}) {
    Minion is a <%= $description %>.
  % }

For templates that might get rendered in different ways and where you're not sure if a stash value will actually be set, you can just use the helper "stash" in Mojolicious::Plugin::DefaultHelpers.

さまざまな方法でレンダリングされる可能性があり、スタッシュ値が実際に設定されるかどうかわからない場合は、単に"stash" in Mojolicious::Plugin::DefaultHelpers を使用します。

  % if (my $spinoffs = stash 'spinoffs') {
    Minion is a <%= $spinoffs->{minion} %>.
  % }

ヘルパー

Helpers are little functions you can use in templates as well as application and controller code.

ヘルパーは、アプリケーション、コントローラー、テンプレートのどこででも使える小さな関数の集まりです。

  # Template
  %= dumper [1, 2, 3]
  # テンプレート
  %= dumper [1, 2, 3]
  # Application
  my $serialized = $app->dumper([1, 2, 3]);
  # アプリケーション
  my $serialized = $app->dumper([1, 2, 3]);
  # Controller
  my $serialized = $c->dumper([1, 2, 3]);
  # コントローラー
  my $serialized = $c->dumper([1, 2, 3]);

We differentiate between default helpers, which are more general purpose like "dumper" in Mojolicious::Plugin::DefaultHelpers, and tag helpers like "link_to" in Mojolicious::Plugin::TagHelpers, which are template specific and mostly used to generate HTML tags.

デフォルトヘルパーとタグヘルパーは区別されます。デフォルトヘルパーは、"dumper" in Mojolicious::Plugin::DefaultHelpersのようにより汎用的なものです。一方、タグヘルパーは"link_to" in Mojolicious::Plugin::TagHelpersのようにテンプレート専用であり、主にHTMLタグの生成に使用されます。

  %= link_to Mojolicious => 'https://mojolicious.org'

In controllers you can also use the method "helpers" in Mojolicious::Controller to fully qualify helper calls and ensure that they don't conflict with existing methods you may already have.

コントローラーでは、"helpers" in Mojolicious::Controllerメソッドを使ってヘルパーだけが呼び出されるように制限し、既存のメソッドとの衝突を防げます。

  my $serialized = $c->helpers->dumper([1, 2, 3]);

A list of all built-in helpers can be found in Mojolicious::Plugin::DefaultHelpers and Mojolicious::Plugin::TagHelpers.

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

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

For resources with different representations and that require truly RESTful content negotiation you can also use "respond_to" in Mojolicious::Plugin::DefaultHelpers instead of "render" in Mojolicious::Controller.

リソースの表現方法が複数あったり、RESTに忠実なコンテンツネゴーシエーションを行う必要があるときは、"render" in Mojolicious::Controllerの代わりに"respond_to" in Mojolicious::Plugin::DefaultHelpersも使用できます。

  # /hello (Accept: application/json) -> "json"
  # /hello (Accept: application/xml)  -> "xml"
  # /hello.json                       -> "json"
  # /hello.xml                        -> "xml"
  # /hello?format=json                -> "json"
  # /hello?format=xml                 -> "xml"
  $c->respond_to(
    json => {json => {hello => 'world'}},
    xml  => {text => '<hello>world</hello>'}
  );

The best possible representation will be automatically selected from the format GET/POST parameter, format stash value or Accept request header and stored in the format stash value. To change MIME type mappings for the Accept request header or the Content-Type response header you can use "types" in Mojolicious.

もっとも適切な表現がformatGET/POSTパラメーター、スタッシュのformatの値またはAcceptリクエストヘッダから自動的に選択され、スタッシュのformatの値に格納されます。AcceptリクエストヘッダまたはContent-TypeレスポンスヘッダのMIMEタイプマッピングを変更するには、"types" in Mojoliciousを使用します。

  $c->respond_to(
    json => {json => {hello => 'world'}},
    html => sub {
      $c->content_for(head => '<meta name="author" content="sri">');
      $c->render(template => 'hello', message => 'world')
    }
  );

Callbacks can be used for representations that are too complex to fit into a single render call.

ひとつのレンダー呼び出しに含めるには表現が複雑すぎる場合は、コールバックを使用できます。

  # /hello (Accept: application/json) -> "json"
  # /hello (Accept: text/html)        -> "html"
  # /hello (Accept: image/png)        -> "any"
  # /hello.json                       -> "json"
  # /hello.html                       -> "html"
  # /hello.png                        -> "any"
  # /hello?format=json                -> "json"
  # /hello?format=html                -> "html"
  # /hello?format=png                 -> "any"
  $c->respond_to(
    json => {json => {hello => 'world'}},
    html => {template => 'hello', message => 'world'},
    any  => {text => '', status => 204}
  );

And if no viable representation could be found, the any fallback will be used or an empty 204 response rendered automatically.

実行可能な表現が見つからない場合は、anyによるフォールバックが行われるか、 空の204レスポンスが自動的に描画されます。

  # /hello                      -> "html"
  # /hello (Accept: text/html)  -> "html"
  # /hello (Accept: text/xml)   -> "xml"
  # /hello (Accept: text/plain) -> undef
  # /hello.html                 -> "html"
  # /hello.xml                  -> "xml"
  # /hello.txt                  -> undef
  # /hello?format=html          -> "html"
  # /hello?format=xml           -> "xml"
  # /hello?format=txt           -> undef
  if (my $format = $c->accepts('html', 'xml')) {
    ...
  }

For even more advanced negotiation logic you can also use the helper "accepts" in Mojolicious::Plugin::DefaultHelpers.

より高度なネゴシエーションのロジックには、"accepts" in Mojolicious::Plugin::DefaultHelpersヘルパーを使うこともできます。

Rendering exception and not_found pages

(例外not_foundページの描画)

By now you've probably already encountered the built-in 404 (Not Found) and 500 (Server Error) pages, that get rendered automatically when you make a mistake. Those are fallbacks for when your own exception handling fails, which can be especially helpful during development. You can also render them manually with the helpers "reply->exception" in Mojolicious::Plugin::DefaultHelpers and "reply->not_found" in Mojolicious::Plugin::DefaultHelpers.

これまでにすでに組み込みの404(Not Found)や500(Server Error)ページを見たことがあるでしょう。間違いがあるとき自動的に描画されます。これはあなた自身が書いた例外ハンドリングが失敗したときのためのフォールバックです。開発中にとくに役に立つことでしょう。例外ページは、 "reply->exception" in Mojolicious::Plugin::DefaultHelpers"reply->not_found" in Mojolicious::Plugin::DefaultHelpersヘルパーを使って手動で描画することもできます。

  use Mojolicious::Lite;
  use Scalar::Util 'looks_like_number';

  get '/divide/:dividend/by/:divisor' => sub {
    my $c = shift;

    my $dividend = $c->param('dividend');
    my $divisor  = $c->param('divisor');

    # 404
    return $c->reply->not_found
      unless looks_like_number $dividend && looks_like_number $divisor;

    # 500
    return $c->reply->exception('Division by zero!') if $divisor == 0;

    # 200
    $c->render(text => $dividend / $divisor);
  };

  app->start;

You can also change the templates of those pages, since you most likely want to show your users something more closely related to your application in production. The renderer will always try to find exception.$mode.$format.* or not_found.$mode.$format.* before falling back to the built-in default templates.

例外ページのテンプレートは自由に変更できます。本番環境では、にアプリケーションにより関連した内容をユーザー表示したいことが多いですからね。レンダラは、組み込みのデフォルトテンプレートにフォールバックする前にexception.$mode.$format.*またはnot_found.$mode.$format.*を毎回探します。

  use Mojolicious::Lite;

  get '/dies' => sub { die 'Intentional error' };

  app->start;
  __DATA__
  @@ exception.production.html.ep
  <!DOCTYPE html>
  <html>
    <head><title>Server error</title></head>
    <body>
      <h1>Exception</h1>
      <p><%= $exception->message %></p>
      <h1>Stash</h1>
      <pre><%= dumper $snapshot %></pre>
    </body>
  </html>
  @@ exception.production.html.ep
  <!DOCTYPE html>
  <html>
    <head><title>Server error</title></head>
    <body>
      <h1>Exception</h1>
      <p><%= $exception->message %></p>
      <h1>スタッシュ</h1>
      <pre><%= dumper $snapshot %></pre>
  </body>
</html>

The hook "before_render" in Mojolicious makes even more advanced customizations possible by allowing you to intercept and modify the arguments passed to the renderer.

"before_render" in Mojoliciousフックを使えば、 レンダラに渡された引数を処理に割り入って変更できるようになり、より高度なカスタマイズが可能になります。

  use Mojolicious::Lite;

  hook before_render => sub {
    my ($c, $args) = @_;
    # Make sure we are rendering the exception template
    return unless my $template = $args->{template};
    return unless $template eq 'exception';
    # 例外テンプレートが確実に描画されるようにする
    return unless my $template = $args->{template};
    return unless $template eq 'exception';
    # Switch to JSON rendering if content negotiation allows it
    $args->{json} = {exception => $args->{exception}} if $c->accepts('json');
  };
    # コンテンツネゴシエーションで許可されている場合にJSONレンダリングに切り替える
    $args->{json} = {exception => $args->{exception}} if $c->accepts('json');
  };

  get '/' => sub { die "This sho...ALL GLORY TO THE HYPNOTOAD!\n" };

  app->start;

レイアウト

Most of the time when using ep templates you will want to wrap your generated content in an HTML skeleton, thanks to layouts that's absolutely trivial.

epテンプレートを使うほとんどの場合で、生成したコンテンツをHTMLの雛形の中にラップしたいのではないでしょうか。レイアウト機能のおかげでこれはとても簡単にできます。

  use Mojolicious::Lite;

  get '/' => {template => 'foo/bar'};

  app->start;
  __DATA__

  @@ foo/bar.html.ep
  % layout 'mylayout';
  Hello World!

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

You just select the right layout template with the helper "layout" in Mojolicious::Plugin::DefaultHelpers and place the result of the current template with the helper "content" in Mojolicious::Plugin::DefaultHelpers. You can also pass along normal stash values to the layout helper.

"layout" in Mojolicious::Plugin::DefaultHelpersヘルパーを使って適切なレイアウトテンプレートを選択し、現在のテンプレートの結果を"content" in Mojolicious::Plugin::DefaultHelpersヘルパーで配置できます。ふつうのスタッシュ値をlayoutヘルパーに渡すこともできます。

  use Mojolicious::Lite;

  get '/' => {template => 'foo/bar'};

  app->start;
  __DATA__

  @@ foo/bar.html.ep
  % layout 'mylayout', title => 'Hi there';
  Hello World!

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

Instead of the layout helper you could also just use the layout stash value, or call "render" in Mojolicious::Controller with the layout argument.

layoutヘルパーを使う代わりに、スタッシュのlayoutの値、または、layout引数を渡してrenderメソッドを呼び出すこともできます。

  $c->render(template => 'mytemplate', layout => 'mylayout');

To set a layout stash value application-wide you can use "defaults" in Mojolicious.

layoutのスタッシュ値をアプリケーション全体で利用できるようにするには、"defaults" in Mojoliciousが使えます。

  $app->defaults(layout => 'mylayout');

Layouts can also be used with "render_to_string" in Mojolicious::Controller, but the layout value needs to be passed as a render argument (not a stash value).

レイアウトは"render_to_string" in Mojolicious::Controllerでも利用可能ですが、 layoutの値はレンダラの引数(スタッシュの値ではなく)として渡される必要があります。

  my $html = $c->render_to_string('reminder', layout => 'mail');

部分テンプレート

You can break up bigger templates into smaller, more manageable chunks. These partial templates can also be shared with other templates. Just use the helper "include" in Mojolicious::Plugin::DefaultHelpers to include one template into another.

大きなテンプレートは、より小さくて管理しやすいかたまりに分割できます。こうしてできた部分テンプレートは、その他のテンプレートと共有できます。"include" in Mojolicious::Plugin::DefaultHelpersヘルパーを使えば、あるテンプレートを別のテンプレートにインクルードできます。

  use Mojolicious::Lite;

  get '/' => {template => 'foo/bar'};

  app->start;
  __DATA__

  @@ foo/bar.html.ep
  <!DOCTYPE html>
  <html>
    %= include '_header', title => 'Howdy'
    <body>Bar</body>
  </html>

  @@ _header.html.ep
  <head><title><%= $title %></title></head>

You can name partial templates however you like, but a leading underscore is a commonly used naming convention.

部分テンプレートにはなんでも好きな名前が付けられます。でも、名前の先頭にアンダースコアを付けるのが通例になっています。

再利用可能なテンプレートブロック

It's never fun to repeat yourself, that's why you can build reusable template blocks in ep that work very similar to normal Perl functions, with the begin and end keywords. Just be aware that both keywords are part of the surrounding tag and not actual Perl code, so there can only be whitespace after begin and before end.

同じことを繰り返すのは楽しくありません。だから、通常のPerlサブルーチンのように動く再利用可能なテンプレートブロックがepに書けるようになっています。beginendキーワードを使います。両方のキーワードは囲いタグであって、本物のPerlコードではないことに気を付けてください。そのため、beginendの後に置けるのは空白文字だけです。

  use Mojolicious::Lite;

  get '/' => 'welcome';

  app->start;
  __DATA__

  @@ welcome.html.ep
  <% my $block = begin %>
    % my $name = shift;
    Hello <%= $name %>.
  <% end %>
  <%= $block->('Wolfgang') %>
  <%= $block->('Baerbel') %>

A naive translation of the template to Perl code could look like this.

単純にPerlコードに変換すると次のようになるでしょう。

  my $output = '';
  my $block  = sub {
    my $name   = shift;
    my $output = '';
    $output .= 'Hello ';
    $output .= xml_escape scalar + $name;
    $output .= '.';
    return Mojo::ByteStream->new($output);
  };
  $output .= xml_escape scalar + $block->('Wolfgang');
  $output .= xml_escape scalar + $block->('Baerbel');
  return $output;

While template blocks cannot be shared between templates, they are most commonly used to pass parts of a template to helpers.

テンプレートブロックはテンプレート間で共有できませんが、多くの場合、テンプレートの部品をヘルパーに渡すために使われます。

ヘルパーの追加

You should always try to keep your actions small and reuse as much code as possible. Helpers make this very easy, they get passed the current controller object as first argument, and you can use them to do pretty much anything an action could do.

アクションは小さく、なるべく多くのコードが再利用できるようにしましょう。ヘルパーはこれをとても簡単にします。ヘルパーは現在のコントローラーオブジェクトを第一引数として渡すので、これを使ってアクションでできるたくさんのことが行えます。

  use Mojolicious::Lite;

  helper debug => sub {
    my ($c, $str) = @_;
    $c->app->log->debug($str);
  };
  get '/' => sub {
    my $c = shift;
    $c->debug('Hello from an action!');
  } => 'index';
  get '/' => sub {
    my $c = shift;
    $c->debug('アクションからのHello!');
  } => 'index';

  app->start;
  __DATA__
  @@ index.html.ep
  % debug 'Hello from a template!';
  @@ index.html.ep
  % debug 'テンプレートからのHello!';

Helpers can also accept template blocks as last argument, this for example, allows very pleasant to use tag helpers and filters. Wrapping the helper result into a Mojo::ByteStream object can prevent accidental double escaping.

ヘルパーは最後の引数にテンプレートブロックを受け取ることもできます。たとえば、タグヘルパーやフィルターを使うのに最適です。ヘルパーの結果をMojo::ByteStreamオブジェクトにラップすることで、間違えて二重エスケープをすることを防げます。

  use Mojolicious::Lite;
  use Mojo::ByteStream;

  helper trim_newline => sub {
    my ($c, $block) = @_;
    my $result = $block->();
    $result =~ s/\n//g;
    return Mojo::ByteStream->new($result);
  };

  get '/' => 'index';

  app->start;
  __DATA__

  @@ index.html.ep
  %= trim_newline begin
    Some text.
    %= 1 + 1
    More text.
  % end

Similar to stash values, you can use a prefix like myapp.* to keep helpers from getting exposed in templates as functions, and to organize them into namespaces as your application grows. Every prefix automatically becomes a helper that returns a proxy object containing the current controller object and on which you can call the nested helpers.

スタッシュ値と同様に、myapp.*のようなプレフィックスを使用することで、テンプレートのなかにむき出しの関数としてヘルパーを書かなくて済みます。また、アプリケーションが大きくなるにつれて、ネームスペース中に整理できるようになります。すべてのプレフィックスは自動的に、 現在のコントローラーオブジェクトを含んだプロキシオブジェクトを返却する ヘルパーになります。また、そこからはネストされたヘルパーを呼び出せます。

  use Mojolicious::Lite;

  helper 'cache_control.no_caching' => sub {
    my $c = shift;
    $c->res->headers->cache_control('private, max-age=0, no-cache');
  };

  helper 'cache_control.five_minutes' => sub {
    my $c = shift;
    $c->res->headers->cache_control('public, max-age=300');
  };

  get '/news' => sub {
    my $c = shift;
    $c->cache_control->no_caching;
    $c->render(text => 'Always up to date.');
  };

  get '/some_older_story' => sub {
    my $c = shift;
    $c->cache_control->five_minutes;
    $c->render(text => 'This one can be cached for a bit.');
  };

  app->start;

While helpers can also be redefined, this should only be done very carefully to avoid conflicts.

ヘルパーは再定義可能ですが、衝突を避けるために、よく注意してください。

コンテンツブロック

The helper "content_for" in Mojolicious::Plugin::DefaultHelpers allows you to pass whole blocks of content from one template to another. This can be very useful when your layout has distinct sections, such as sidebars, where content should be inserted by the template.

"content_for" in Mojolicious::Plugin::DefaultHelpersヘルパーを使うと、コンテンツのブロック全体をあるテンプレートから別のテンプレートへと渡せます。レイアウトがサイドバー等の独立したセクションをテンプレートに挿入する場合にとても便利です。

  use Mojolicious::Lite;

  get '/' => 'foo';

  app->start;
  __DATA__

  @@ foo.html.ep
  % layout 'mylayout';
  % content_for header => begin
    <meta http-equiv="Content-Type" content="text/html">
  % end
  <div>Hello World!</div>
  % content_for header => begin
    <meta http-equiv="Pragma" content="no-cache">
  % end

  @@ layouts/mylayout.html.ep
  <!DOCTYPE html>
  <html>
    <head><%= content 'header' %></head>
    <body><%= content %></body>
  </html>

フォーム

To build HTML forms more efficiently you can use tag helpers like "form_for" in Mojolicious::Plugin::TagHelpers, which can automatically select a request method for you if a route name is provided. And since most browsers only allow forms to be submitted with GET and POST, but not request methods like PUT or DELETE, they are spoofed with an _method query parameter.

HTMLフォームをより効率的に構築するために、"form_for" in Mojolicious::Plugin::TagHelpers のようなタグヘルパーを使うことができます。ルート名が与えられていれば、リクエストメソッドが自動的に選択されます。ほとんどのブラウザは、フォームをサブミットするメソッドとしてGETPOSTだけを許可していて、PUTDELETEには対応していないので、_methodクエリパラメーターで偽装できます。

  use Mojolicious::Lite;

  get '/' => 'form';

  # PUT  /nothing
  # POST /nothing?_method=PUT
  put '/nothing' => sub {
    my $c = shift;
    # Prevent double form submission with redirect
    my $value = $c->param('whatever');
    $c->flash(confirmation => "We did nothing with your value ($value).");
    $c->redirect_to('form');
  };
    # リダイレクトで二重フォーム送信を防ぐ
    my $value = $c->param('whatever');
    $c->flash(confirmation => "We did nothing with your value ($value).");
    $c->redirect_to('form');
  };

  app->start;
  __DATA__

  @@ form.html.ep
  <!DOCTYPE html>
  <html>
    <body>
      % if (my $confirmation = flash 'confirmation') {
        <p><%= $confirmation %></p>
      % }
      %= form_for nothing => begin
        %= text_field whatever => 'I ♥ Mojolicious!'
        %= submit_button
      % end
    </body>
  </html>

The helpers "flash" in Mojolicious::Plugin::DefaultHelpers and "redirect_to" in Mojolicious::Plugin::DefaultHelpers are often used together to prevent double form submission, allowing users to receive a confirmation message that will vanish if they decide to reload the page they've been redirected to.

二重フォーム送信を防ぐために"flash" in Mojolicious::Plugin::DefaultHelpers"redirect_to" in Mojolicious::Plugin::DefaultHelpersは一緒に使用されることが多く、リダイレクトされたページをリロードすると消える確認メッセージをユーザーが受信できるようになります。

フォーム検証

You can use "validation" in Mojolicious::Plugin::DefaultHelpers to validate GET and POST parameters submitted to your application. All unknown fields will be ignored by default, so you have to decide which should be required or optional before you can perform checks on their values. Every check is performed right away, so you can use the results immediately to build more advanced validation logic with methods like "is_valid" in Mojolicious::Validator::Validation.

アプリケーションに送信するGETPOSTパラメーターは"validation" in Mojolicious::Plugin::DefaultHelpersメソッドを使って検証できます。すべての未知のフィールドはデフォルトで無視されるので、どれをrequiredにして、どれをoptionalにするのかを、値のチェックを実行する前に決める必要があります。すべてのチェックはすぐに実行されます。"is_valid" in Mojolicious::Validator::Validationのようなメソッドからすぐに結果を得て、より高度な検証ロジックを構築できます。

  use Mojolicious::Lite;

  get '/' => sub {
    my $c = shift;
    # Check if parameters have been submitted
    my $v = $c->validation;
    return $c->render('index') unless $v->has_data;
    # パラメーターが送信されたかをチェック
    my $v = $c->validation;
    return $c->render('index') unless $v->has_data;
    # Validate parameters ("pass_again" depends on "pass")
    $v->required('user')->size(1, 20)->like(qr/^[a-z0-9]+$/);
    $v->required('pass_again')->equal_to('pass')
      if $v->optional('pass')->size(7, 500)->is_valid;
    # パラメーターを検証する(「pass」は「pass_again」に依存)
    $v->required('user')->size(1, 20)->like(qr/^[a-z0-9]+$/);
    $v->required('pass_again')->equal_to('pass')
      if $v->optional('pass')->size(7, 500)->is_valid;
    # Check if validation failed
    return $c->render('index') if $v->has_error;
    # 検証が失敗したかをチェック
    return $c->render('index') if $v->has_error;
    # Render confirmation
    $c->render('thanks');
  };
    # 結果を描画する
    $c->render('thanks');
  };

  app->start;
  __DATA__

  @@ index.html.ep
  <!DOCTYPE html>
  <html>
    <head>
      <style>
        label.field-with-error { color: #dd7e5e }
        input.field-with-error { background-color: #fd9e7e }
      </style>
    </head>
    <body>
      %= form_for index => begin
        %= label_for user => 'Username (required, 1-20 characters, a-z/0-9)'
        <br>
        %= text_field 'user', id => 'user'
        %= submit_button
        <br>
        %= label_for pass => 'Password (optional, 7-500 characters)'
        <br>
        %= password_field 'pass', id => 'pass'
        <br>
        %= label_for pass_again => 'Password again (equal to the value above)'
        <br>
        %= password_field 'pass_again', id => 'pass_again'
      % end
    </body>
  </html>

  @@ thanks.html.ep
  <!DOCTYPE html>
  <html><body>Thank you <%= validation->param('user') %>.</body></html>

Form elements generated with tag helpers from Mojolicious::Plugin::TagHelpers will automatically remember their previous values and add the class field-with-error for fields that failed validation to make styling with CSS easier.

Mojolicious::Plugin::TagHelpersのタグヘルパーによって生成されたフォーム要素は 自動的に以前の値を復元し、検証が失敗したフィールドのclass属性にfield-with-errorを 追加します。CSSによるスタイリングが簡単になります。

  <label class="field-with-error" for="user">
    Username (required, only characters e-t)
  </label>
  <input class="field-with-error" type="text" name="user" value="sri">

For a full list of available checks see also "CHECKS" in Mojolicious::Validator.

利用可能なチェックの完全なリストは、 "CHECKS" in Mojolicious::Validatorを参照してください。

フォーム検証チェックの追加

Validation checks can be registered with "add_check" in Mojolicious::Validator and return a false value if they were successful. A true value may be used to pass along additional information which can then be retrieved with "error" in Mojolicious::Validator::Validation.

検証チェックは"add_check" in Mojolicious::Validatorを使って登録できます。成功した場合はfalse値を返します。true値を使用して追加情報を渡すことができます。追加情報は"error" in Mojolicious::Validator::Validationで取得できます。

  use Mojolicious::Lite;
  # Add "range" check
  app->validator->add_check(range => sub {
    my ($v, $name, $value, $min, $max) = @_;
    return $value < $min || $value > $max;
  });
  # 「range(範囲)」チェックを追加する
  app->validator->add_check(range => sub {
    my ($v, $name, $value, $min, $max) = @_;
    return $value < $min || $value > $max;
  });

  get '/' => 'form';

  post '/test' => sub {
    my $c = shift;
    # Validate parameters with custom check
    my $v = $c->validation;
    $v->required('number')->range(3, 23);
    # カスタムチェックでパラメーターを検証する
    my $v = $c->validation;
    $v->required('number')->range(3, 23);
    # Render form again if validation failed
    return $c->render('form') if $v->has_error;
    # 検証が失敗したときフォームを再描画する
    return $c->render('form') if $v->has_error;
    # Prevent double form submission with redirect
    $c->flash(number => $v->param('number'));
    $c->redirect_to('form');
  };
    # リダイレクトで二重フォーム送信を防ぐ
    $c->flash(number => $v->param('number'));
    $c->redirect_to('form');
  };

  app->start;
  __DATA__
  @@ form.html.ep
  <!DOCTYPE html>
  <html>
    <body>
      % if (my $number = flash 'number') {
        <p>Thanks, the number <%= $number %> was valid.</p>
      % }
      %= form_for test => begin
        % if (my $err = validation->error('number')) {
          <p>
            %= 'Value is required.' if $err->[0] eq 'required'
            %= 'Value needs to be between 3 and 23.' if $err->[0] eq 'range'
          </p>
        % }
        %= text_field 'number'
        %= submit_button
      % end
    </body>
  </html>
  @@ form.html.ep
  <!DOCTYPE html>
  <html>
    <body>
      % if (my $number = flash 'number') {
        <p>ありがとう。数値 <%= $number %> は有効です。</p>
      % }
      %= form_for test => begin
        % if (my $err = validation->error('number')) {
          <p>
            %= '値が必要です。' if $err->[0] eq 'required'
            %= '値は3から23の範囲で入力してください。' if $err->[0] eq 'range'
          </p>
        % }
        %= text_field 'number'
        %= submit_button
      % end
    </body>
  </html>

クロスサイトリクエストフォージェリー(CSRF)

CSRF is a very common attack on web applications that trick your logged in users to submit forms they did not intend to send, with something as mundane as a link. All you have to do, to protect your users from this, is to add an additional hidden field to your forms with "csrf_field" in Mojolicious::Plugin::TagHelpers, and validate it with "csrf_protect" in Mojolicious::Validator::Validation.

CSRFはWebアプリケーションに対する非常に一般的な攻撃であり、普通のリンクなどを介して、ログインしているユーザーが送信するつもりのないフォームを送信するように仕掛けます。この攻撃からユーザー守るためにすべきことは、"csrf_field" in Mojolicious::Plugin::TagHelpersを使って隠しフィールドをフォームに追加し、"csrf_protect" in Mojolicious::Validator::Validationで 検証することだけです。

  use Mojolicious::Lite;

  get '/' => {template => 'target'};

  post '/' => sub {
    my $c = shift;
    # Check CSRF token
    my $v = $c->validation;
    return $c->render(text => 'Bad CSRF token!', status => 403)
      if $v->csrf_protect->has_error('csrf_token');
    # CSRFトークンのチェック
    my $v = $c->validation;
    return $c->render(text => '不正なCSRFトークンです!', status => 403)
      if $v->csrf_protect->has_error('csrf_token');
    my $city = $v->required('city')->param('city');
    $c->render(text => "Low orbit ion cannon pointed at $city!")
      unless $v->has_error;
  } => 'target';
    my $city = $v->required('city')->param('city');
    $c->render(text => "低軌道イオン砲が$cityに向けられている!")
      unless $v->has_error;
  } => 'target';

  app->start;
  __DATA__
  @@ target.html.ep
  <!DOCTYPE html>
  <html>
    <body>
      %= form_for target => begin
        %= csrf_field
        %= label_for city => 'Which city to point low orbit ion cannon at?'
        %= text_field 'city', id => 'city'
        %= submit_button
      %= end
    </body>
  </html>
  @@ target.html.ep
  <!DOCTYPE html>
  <html>
    <body>
      %= form_for target => begin
        %= csrf_field
        %= label_for city => 'どの街に低軌道イオン砲を向ける?'
        %= text_field 'city', id => 'city'
        %= submit_button
      %= end
    </body>
  </html>

For Ajax requests and the like, you can also generate a token directly with the helper "csrf_token" in Mojolicious::Plugin::DefaultHelpers, and then pass it along with the X-CSRF-Token request header.

Ajaxリクエストなどの場合、"csrf_token" in Mojolicious::Plugin::DefaultHelpersヘルパーを使用してトークンを直接生成することもできます。それから、トークンをX-CSRF-Tokenリクエストヘッダーと一緒に渡します。

発展

Less commonly used and more powerful features.

一般的ではないが、より強力な機能。

テンプレートの継承

Inheritance takes the layout concept above one step further, the helpers "content" in Mojolicious::Plugin::DefaultHelpers and "extends" in Mojolicious::Plugin::DefaultHelpers allow you to build skeleton templates with named blocks that child templates can override.

継承はレイアウトの概念を一歩進めます。"content" in Mojolicious::Plugin::DefaultHelpersヘルパーと "extends" in Mojolicious::Plugin::DefaultHelpersヘルパーを使って、名前付きブロックを含むテンプレートスケルトンを構築できます。スケルトンテンプレートは、子テンプレートによってオーバーライドできます。

  use Mojolicious::Lite;

  # first > mylayout
  get '/first' => {template => 'first', layout => 'mylayout'};

  # third > second > first > mylayout
  get '/third' => {template => 'third', layout => 'mylayout'};

  app->start;
  __DATA__

  @@ layouts/mylayout.html.ep
  <!DOCTYPE html>
  <html>
    <head><title>Hello</title></head>
    <body><%= content %></body>
  </html>
  @@ first.html.ep
  %= content header => begin
    Default header
  % end
  <div>Hello World!</div>
  %= content footer => begin
    Default footer
  % end
  @@ first.html.ep
  %= content header => begin
    デフォルトヘッダ―
  % end
  <div>Hello World!</div>
  %= content footer => begin
    デフォルトフッター
  % end
  @@ second.html.ep
  % extends 'first';
  % content header => begin
    New header
  % end
  @@ second.html.ep
  % extends 'first';
  % content header => begin
    新しいヘッダー
  % end
  @@ third.html.ep
  % extends 'second';
  % content footer => begin
    New footer
  % end
  @@ third.html.ep
  % extends 'second';
  % content footer => begin
    新しいフッター
  % end

This chain could go on and on to allow a very high level of template reuse.

この連鎖を進めれば、とてもハイレベルなテンプレートの再利用が可能になります。

静的ファイルのサーブ

Static files are automatically served from the public directories of the application, which can be customized with "paths" in Mojolicious::Static, or one of the DATA sections from "classes" in Mojolicious::Static. And if that's not enough you can also serve them manually with "reply->static" in Mojolicious::Plugin::DefaultHelpers and "reply->file" in Mojolicious::Plugin::DefaultHelpers.

静的ファイルは、アプリケーションのpublicディレクトリから自動的にサーブされます。サーブ対象のディレクトリは"paths" in Mojolicious::Staticまたは"classes" in Mojolicious::StaticにおけるDATAセクションによってカスタマイズできます。これで十分でない場合、"reply->static" in Mojolicious::Plugin::DefaultHelpers"reply->file" in Mojolicious::Plugin::DefaultHelpersを使って手動でサーブすることもできます。

  use Mojolicious::Lite;

  get '/' => sub {
    my $c = shift;
    $c->reply->static('index.html');
  };

  get '/some_download' => sub {
    my $c = shift;
    $c->res->headers->content_disposition('attachment; filename=bar.png;');
    $c->reply->static('foo/bar.png');
  };

  get '/leak' => sub {
    my $c = shift;
    $c->reply->file('/etc/passwd');
  };

  app->start;

カスタムレスポンス

Most response content, static as well as dynamic, gets served through Mojo::Asset::File and Mojo::Asset::Memory objects. For somewhat static content, like cached JSON data or temporary files, you can create your own and use the helper "reply->asset" in Mojolicious::Plugin::DefaultHelpers to serve them while allowing content negotiation to be performed with Range, If-Modified-Since and If-None-Match headers.

多くのレスポンス内容は、静的であれ動的であれ、Mojo::Asset::FileMojo::Asset::Memory オブジェクトによってサーブされます。キャッシュされたJSONデータや一時ファイルなどの静的コンテンツ のために、"reply->asset" in Mojolicious::Plugin::DefaultHelpers を使って、コンテンツネゴシエーションをRangeIf-Modified-SinceIf-None-Matchヘッダーで行いつつコンテンツをサーブできます。

  use Mojolicious::Lite;
  use Mojo::Asset::File;

  get '/leak' => sub {
    my $c = shift;
    $c->res->headers->content_type('text/plain');
    $c->reply->asset(Mojo::Asset::File->new(path => '/etc/passwd'));
  };

  app->start;

For even more control you can also just skip the helper and use "rendered" in Mojolicious::Controller to tell the renderer when you're done generating a response.

さらに強力なコントロールを得るために、ヘルパーを無視して "rendered" in Mojolicious::Controllerメソッドを使い、レスポンスの生成が完了した時点をレンダラに知らせることもできます。

  use Mojolicious::Lite;
  use Mojo::Asset::File;

  get '/leak' => sub {
    my $c = shift;
    $c->res->headers->content_type('text/plain');
    $c->res->content->asset(Mojo::Asset::File->new(path => '/etc/passwd'));
    $c->rendered(200);
  };

  app->start;

ヘルパープラグイン

Some helpers might be useful enough for you to share them between multiple applications, plugins make that very simple.

便利なヘルパーは、複数のアプリケーション間で共有したいこともあることでしょう。プラグインを使えば簡単です。

  package Mojolicious::Plugin::DebugHelper;
  use Mojo::Base 'Mojolicious::Plugin';

  sub register {
    my ($self, $app) = @_;
    $app->helper(debug => sub {
      my ($c, $str) = @_;
      $c->app->log->debug($str);
    });
  }

  1;

The register method will be called when you load the plugin. And to add your helper to the application, you can use "helper" in Mojolicious.

register メソッドがプラグインを読み込んだ時点でコールされます。そして、アプリケーションにヘルパーを追加するためには、 "helper" in Mojoliciousを使います。

  use Mojolicious::Lite;

  plugin 'DebugHelper';

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

  app->start;

A skeleton for a full CPAN compatible plugin distribution can be automatically generated.

CPAN完全互換の配布用プラグインのためのスケルトンを自動的に生成できます。

  $ mojo generate plugin DebugHelper

And if you have a PAUSE account (which can be requested at http://pause.perl.org), you are only a few commands away from releasing it to CPAN.

もしPAUSEアカウントを持っていれば(http://pause.perl.orgでリクエストできます)、わずか数コマンドでCPANにリリースできます。

  $ perl Makefile.PL
  $ make test
  $ make manifest
  $ make dist
  $ mojo cpanify -u USER -p PASS Mojolicious-Plugin-DebugHelper-0.01.tar.gz

プラグインへのコンテンツのバンドル

Assets such as templates and static files can be easily bundled with your plugins, even if you plan to release them to CPAN.

テンプレートや静的ファイルなどのアセットは、プラグインにバンドルできます。CPANにリリースする場合でも大丈夫です。

  $ mojo generate plugin AlertAssets
  $ mkdir Mojolicious-Plugin-AlertAssets/lib/Mojolicious/Plugin/AlertAssets
  $ cd Mojolicious-Plugin-AlertAssets/lib/Mojolicious/Plugin/AlertAssets
  $ mkdir public
  $ echo 'alert("Hello World!");' > public/alertassets.js
  $ mkdir templates
  $ echo '%= javascript "/alertassets.js"' > templates/alertassets.html.ep

Just give them reasonably unique names, ideally based on the name of your plugin, and append their respective directories to the list of search paths when register is called.

プラグインの名前に基づいた 合理的なユニークな名前を付けましょう。そして、registerが呼ばれるとき、対応するディレクトリを検索パスの一覧に追加します。

  package Mojolicious::Plugin::AlertAssets;
  use Mojo::Base 'Mojolicious::Plugin';

  use Mojo::File 'path';

  sub register {
    my ($self, $app) = @_;
    # Append "templates" and "public" directories
    my $base = path(__FILE__)->sibling('AlertAssets');
    push @{$app->renderer->paths}, $base->child('templates')->to_string;
    push @{$app->static->paths},   $base->child('public')->to_string;
  }
    # "templates"と"public"ディレクトリを追加する
    my $base = path(__FILE__)->sibling('AlertAssets');
    push @{$app->renderer->paths}, $base->child('templates')->to_string;
    push @{$app->static->paths},   $base->child('public')->to_string;
  }

  1;

Both will work just like normal templates and public directories once you've installed and loaded the plugin, with slightly lower precedence.

プラグインをいったんインストールし、読み込めば、両方とも通常のtemplatespublicディレクトリのように機能します。優先順位は少し低くなります。

  use Mojolicious::Lite;

  plugin 'AlertAssets';

  get '/alert_me';

  app->start;
  __DATA__

  @@ alert_me.html.ep
  <!DOCTYPE html>
  <html>
    <head>
      <title>Alert me!</title>
      %= include 'alertassets'
    </head>
    <body>You've been alerted.</body>
  </html>

And it works just the same for assets bundled in the DATA section of your plugin.

すると、バンドルしたプラグインのDATAセクションにあるアセットと同じように使用できます。

  package Mojolicious::Plugin::AlertAssets;
  use Mojo::Base 'Mojolicious::Plugin';

  sub register {
    my ($self, $app) = @_;
    # Append class
    push @{$app->renderer->classes}, __PACKAGE__;
    push @{$app->static->classes},   __PACKAGE__;
  }
    # クラスを追加する
    push @{$app->renderer->classes}, __PACKAGE__;
    push @{$app->static->classes},   __PACKAGE__;
  }

  1;
  __DATA__

  @@ alertassets.js
  alert("Hello World!");

  @@ alertassets.html.ep
  %= javascript "/alertassets.js"

動的コンテンツの後処理

While post-processing tasks are generally very easy with the hook "after_dispatch" in Mojolicious, for content generated by the renderer it is a lot more efficient to use "after_render" in Mojolicious.

一般的に"after_dispatch" in Mojoliciousフックによる後処理はとても簡単ですが、レンダラによって生成されたコンテンツのためには、"after_render" in Mojoliciousを使うのがより効率的です。

  use Mojolicious::Lite;
  use IO::Compress::Gzip 'gzip';

  hook after_render => sub {
    my ($c, $output, $format) = @_;
    # Check if "gzip => 1" has been set in the stash
    return unless $c->stash->{gzip};
    # "gzip => 1" がスタッシュにセットされているかを確認する
    return unless $c->stash->{gzip};
    # Check if user agent accepts gzip compression
    return unless ($c->req->headers->accept_encoding // '') =~ /gzip/i;
    $c->res->headers->append(Vary => 'Accept-Encoding');
    # ユーザーエージェントがgzip圧縮を許可するかどうかを確認する
    return unless ($c->req->headers->accept_encoding // '') =~ /gzip/i;
    $c->res->headers->append(Vary => 'Accept-Encoding');
    # Compress content with gzip
    $c->res->headers->content_encoding('gzip');
    gzip $output, \my $compressed;
    $$output = $compressed;
  };
    # gzipでコンテンツを圧縮する
    $c->res->headers->content_encoding('gzip');
    gzip $output, \my $compressed;
    $$output = $compressed;
  };

  get '/' => {template => 'hello', title => 'Hello', gzip => 1};

  app->start;
  __DATA__

  @@ hello.html.ep
  <!DOCTYPE html>
  <html>
    <head><title><%= title %></title></head>
    <body>Compressed content.</body>
  </html>

If you want to compress all dynamically generated content you can also activate "compress" in Mojolicious::Renderer.

動的に生成されたコンテンツのすべてを圧縮したい場合は、"compress" in Mojolicious::Rendererを有効にすることもできます。

ストリーミング

You don't have to render all content at once, the method "write" in Mojolicious::Controller can also be used to stream a series of smaller chunks.

すべてのコンテンツを一度に描画する必要はありません。"write" in Mojolicious::Controllerを使って小さなチャンクを連続で流すこともできます。

  use Mojolicious::Lite;

  get '/' => sub {
    my $c = shift;
    # Prepare body
    my $body = 'Hello World!';
    $c->res->headers->content_length(length $body);
    # ボディを準備する
    my $body = 'Hello World!';
    $c->res->headers->content_length(length $body);
    # Start writing directly with a drain callback
    my $drain;
    $drain = sub {
      my $c = shift;
      my $chunk = substr $body, 0, 1, '';
      $drain = undef unless length $body;
      $c->write($chunk, $drain);
    };
    $c->$drain;
  };
    # 排出コールバックに直接書き込みを開始する
    my $drain;
    $drain = sub {
      my $c = shift;
      my $chunk = substr $body, 0, 1, '';
      $drain = undef unless length $body;
      $c->write($chunk, $drain);
    };
    $c->$drain;
  };

  app->start;

The drain callback will be executed whenever the entire previous chunk of data has actually been written.

前のデータチャンク全部が実際に書き込まれるたびに、排出コールバックが実行されます。

  HTTP/1.1 200 OK
  Date: Sat, 13 Sep 2014 16:48:29 GMT
  Content-Length: 12
  Server: Mojolicious (Perl)

  Hello World!

Instead of providing a Content-Length header you can also call "finish" in Mojolicious::Controller and close the connection manually once you are done.

Content-Lengthヘッダーを提供する代わりに、"finish" in Mojolicious::Controllerを使用して、完了したときに接続を手動で閉じることもできます。

  use Mojolicious::Lite;

  get '/' => sub {
    my $c = shift;
    # Prepare body
    my $body = 'Hello World!';
    # ボディを準備する
    my $body = 'Hello World!';
    # Start writing directly with a drain callback
    my $drain;
    $drain = sub {
      my $c = shift;
      my $chunk = substr $body, 0, 1, '';
      length $chunk ? $c->write($chunk, $drain) : $c->finish;
    };
    $c->$drain;
  };
    # 排出コールバックに直接書き込みを開始する
    my $drain;
    $drain = sub {
      my $c = shift;
      my $chunk = substr $body, 0, 1, '';
      length $chunk ?$c->write($chunk, $drain) : $c->finish;
    };
    $c->$drain;
  };

  app->start;

While this is rather inefficient, as it prevents keep-alive, it is sometimes necessary for EventSource and similar applications.

Keep-aliveを妨げるため、この方法はかなり非効率的ですが、EventSourceおよび同様のアプリケーションのために必要な場合があります。

  HTTP/1.1 200 OK
  Date: Sat, 13 Sep 2014 16:48:29 GMT
  Connection: close
  Server: Mojolicious (Perl)

  Hello World!

チャンク化されたトランスファーエンコーディング

For very dynamic content you might not know the response content length in advance, that's where the chunked transfer encoding and "write_chunk" in Mojolicious::Controller come in handy. A common use would be to send the head section of an HTML document to the browser in advance and speed up preloading of referenced images and stylesheets.

コンテンツがとても動的な場合は、レスポンスコンテンツのContent-Lengthが前もってわからないかもしれません。そのような場合は、チャンク化されたトランスファーエンコーディングや "write_chunk" in Mojolicious::Controllerが便利です。一般的な用途として、HTMLドキュメントのheadセクションを事前にブラウザに送信し、参照する画像やスタイルシートの事前ロードを高速化できます。

  use Mojolicious::Lite;

  get '/' => sub {
    my $c = shift;
    $c->write_chunk('<html><head><title>Example</title></head>' => sub {
      my $c = shift;
      $c->finish('<body>Example</body></html>');
    });
  };

  app->start;

The optional drain callback ensures that all previous chunks have been written before processing continues. To end the stream you can call "finish" in Mojolicious::Controller or write an empty chunk of data.

オプションの排出コールバックは、処理を継続する前に、すべての以前のチャンクが書き込まれることを保障します。ストリームを終了するためには、"finish" in Mojolicious::Controller を呼び出すか、空データのチャンクを書き込みます。

  HTTP/1.1 200 OK
  Date: Sat, 13 Sep 2014 16:48:29 GMT
  Transfer-Encoding: chunked
  Server: Mojolicious (Perl)

  29
  <html><head><title>Example</title></head>
  1b
  <body>Example</body></html>
  0

Especially in combination with long inactivity timeouts this can be very useful for Comet (long polling). Due to limitations in some web servers this might not work perfectly in all deployment environments.

とくに、長時間応答がないときのタイムアウトと組み合わせるとき、Comet(ロングポーリング)をするのに便利でしょう。Webサーバーによっては制限のために、完璧には動作しないデプロイ環境があるかもしれません。

エンコーディング

Templates stored in files are expected to be UTF-8 by default, but that can be easily changed with "encoding" in Mojolicious::Renderer.

ファイルに保存されたテンプレートは、デフォルトではUTF-8であると期待されますが、 "encoding" in Mojolicious::Rendererを使って簡単に変更できます。

  $app->renderer->encoding('koi8-r');

All templates from the DATA section are bound to the encoding of the Perl script.

DATAセクションからのすべてのテンプレートは、必ずPerlスクリプトのエンコーディングになります。

  use Mojolicious::Lite;

  get '/heart';

  app->start;
  __DATA__

  @@ heart.html.ep
  I ♥ Mojolicious!

Base64エンコードDATAファイル

Base64 encoded static files such as images can be easily stored in the DATA section of your application, similar to templates.

画像などのBase64でエンコードされた静的ファイルは、テンプレートと同じように、簡単にアプリケーションのDATAセクションに保存できます。

  use Mojolicious::Lite;

  get '/' => {text => 'I ♥ Mojolicious!'};

  app->start;
  __DATA__

  @@ favicon.ico (base64)
  ...base64 encoded image...

DATA テンプレートのインフレ―ト

Templates stored in files get preferred over files from the DATA section, this allows you to include a default set of templates in your application that the user can later customize. The command Mojolicious::Command::Author::inflate will write all templates and static files from the DATA section into actual files in the templates and public directories.

ファイルとして保存されているテンプレートは、DATAセクションのファイルよりも優先されます。ファイルテンプレートはアプリケーションのデフォルトセットとして含めることができ、ユーザーは後にこれをカスタマイズできます。Mojolicious::Command::Author::inflateコマンドでDATAセクションにあるすべてのテンプレートと静的ファイルを、実際のファイルとしてtemplatesおよびpublic ディレクトリに書き込みます。

  $ ./myapp.pl inflate

テンプレート文法のカスタマイズ

You can easily change the whole template syntax by loading Mojolicious::Plugin::EPRenderer with a custom configuration.

EPRendererプラグインをカスタム設定と一緒にロードすることによって、簡単にテンプレートの文法全体を変更できます。

  use Mojolicious::Lite;

  plugin EPRenderer => {
    name     => 'mustache',
    template => {
      tag_start => '{{',
      tag_end   => '}}'
    }
  };

  get '/:name' => {name => 'Anonymous'} => 'index';

  app->start;
  __DATA__

  @@ index.html.mustache
  Hello {{= $name }}.

Mojo::Template contains the whole list of available options.

Mojo::Templateは利用できるすべてのオプションを含んでいます。

お気に入りテンプレートシステムの追加

Maybe you would prefer a different template system than ep, which is provided by Mojolicious::Plugin::EPRenderer, and there is not already a plugin on CPAN for your favorite one. All you have to do, is to add a new handler with "add_handler" in Mojolicious::Renderer when register is called.

Mojolicious::Plugin::EPRendererが提供するepではないテンプレートシステムがお好みのこともあるでしょう。また、CPANに登録されているプラグインのなかにお気に入りが見つからないかもしれません。そんなときは、新しいhandlerregisterが呼び出されるとき、"add_handler" in Mojolicious::Rendererで追加すれば大丈夫です。

  package Mojolicious::Plugin::MyRenderer;
  use Mojo::Base 'Mojolicious::Plugin';

  sub register {
    my ($self, $app) = @_;
    # Add "mine" handler
    $app->renderer->add_handler(mine => sub {
      my ($renderer, $c, $output, $options) = @_;
    # "mine"ハンドラーの追加
    $app->renderer->add_handler(mine => sub {
      my ($renderer, $c, $output, $options) = @_;
      # Check for one-time use inline template
      my $inline_template = $options->{inline};
      # ワンタイム使用インラインテンプレートのチェック
      my $inline_template = $options->{inline};
      # Check for appropriate template in "templates" directories
      my $template_path = $renderer->template_path($options);
      # "templates"ディレクトリに適切なテンプレートがあるかをチェック
      my $template_path = $renderer->template_path($options);
      # Check for appropriate template in DATA sections
      my $data_template = $renderer->get_data_template($options);
      # DATAセクションに適切なテンプレートがあるかをチェック
      my $data_template = $renderer->get_data_template($options);
      # This part is up to you and your template system :)
      ...
      # この部分はあなたのテンプレートシステムに応じて変わります :)
      ...
      # Pass the rendered result back to the renderer
      $$output = 'Hello World!';
      # 描画された結果をレンダラに渡す
      $$output = 'Hello World!';
      # Or just die if an error occurs
      die 'Something went wrong with the template';
    });
  }
      # またはエラーが起きたら終了する
      die 'Something went wrong with the template';
    });
  }

  1;

An inline template, if provided by the user, will be passed along with the options. You can use "template_path" in Mojolicious::Renderer to search the templates directories of the application, and "get_data_template" in Mojolicious::Renderer to search the DATA sections.

inlineテンプレートは、ユーザーによって提供されると、オプションとともに渡されます。アプリケーションのtemplatesディレクトリを検索するには"template_path" in Mojolicious::Rendererが、DATAセクションを検索するには"get_data_template" in Mojolicious::Rendererが使えます。

  use Mojolicious::Lite;

  plugin 'MyRenderer';
  # Render an inline template
  get '/inline' => {inline => '...', handler => 'mine'};
  # インラインテンプレートの描画
  get '/inline' => {inline => '...', handler => 'mine'};
  # Render a template from the DATA section
  get '/data' => {template => 'test'};
  # DATAセクションのテンプレートを描画
  get '/data' => {template => 'test'};

  app->start;
  __DATA__

  @@ test.html.mine
  ...

バイナリデータを生成するためのハンドラを追加する

By default the renderer assumes that every handler generates characters that need to be automatically encoded, but this can be easily disabled if you're generating bytes instead.

デフォルトでは、レンダラはすべてのhandlerが自動的にエンコードされる必要がある文字を生成しますが、代わりにバイトを生成することで簡単に無効にできます。

  use Mojolicious::Lite;
  use Storable 'nfreeze';
  # Add "storable" handler
  app->renderer->add_handler(storable => sub {
    my ($renderer, $c, $output, $options) = @_;
  # "storable"ハンドラを追加
  app->renderer->add_handler(storable => sub {
    my ($renderer, $c, $output, $options) = @_;
    # Disable automatic encoding
    delete $options->{encoding};
    # 自動的なエンコーディングを削除
    delete $options->{encoding};
    # Encode data from stash value
    $$output = nfreeze delete $c->stash->{storable};
  });
    # スタッシュのデータをエンコード
    $$output = nfreeze delete $c->stash->{storable};
  });
  # Set "handler" value automatically if "storable" value is set already
  app->hook(before_render => sub {
    my ($c, $args) = @_;
    $args->{handler} = 'storable'
      if exists $args->{storable} || exists $c->stash->{storable};
  });
  # "storable" 値がすでにセットされている場合に"ハンドラ" 値を自動的にセットする
  app->hook(before_render => sub {
    my ($c, $args) = @_;
    $args->{handler} = 'storable'
      if exists $args->{storable} || exists $c->stash->{storable};
  });

  get '/' => {storable => {i => '♥ mojolicious'}};

  app->start;

The hook "before_render" in Mojolicious can be used to make stash values like storable special, so that they no longer require a handler value to be set explicitly.

"before_render" in Mojoliciousフックは、storableのようなスタッシュ値のためにhandler値を明示的にセットしなくて済むようにするなど、個別に対応するために使用できます。

  # Explicit "handler" value
  $c->render(storable => {i => '♥ mojolicious'}, handler => 'storable');
  # 明示的な"handler" 値
  $c->render(storable => {i => '♥ mojolicious'}, handler => 'storable');
  # Implicit "handler" value (with "before_render" hook)
  $c->render(storable => {i => '♥ mojolicious'});
  # 暗黙的な "handler" 値("before_render" フックを使用)
  $c->render(storable => {i => '♥ mojolicious'});

もっと学ぶには

You can continue with Mojolicious::Guides now or take a look at the Mojolicious wiki, which contains a lot more documentation and examples by many different authors.

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

サポート

If you have any questions the documentation might not yet answer, don't hesitate to ask on the mailing list or the official IRC channel #mojo on irc.freenode.net (chat now!).

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