Perl/CGIをMojolicious+Xslate化した話 

とあるPerl/CGIでできていたシステムを訳あって再構成することになり、Mojolicious+Xslate化するまでにやったことをざっくりと紹介します。

# 目次

- [0. 変更前](#0-変更前)
- [1. CGI.pmの導入](#1-cgipmの導入)
- [2. Text::Xslateの導入](#2-textxslateの導入)
	- [とりあえず導入](#とりあえず導入)
	- [@{[ ... ]}での埋め込みをやめる](#--での埋め込みをやめる)
	- [テンプレートを外部ファイル化](#テンプレートを外部ファイル化)
- [3. Mojolicious導入](#3-mojolicious導入)
- [4. あとはがんばる](#4-あとはがんばる)

# 0. 変更前

- Perl/CGI
	- CGI.pm等も使わずに本当に生Perl

## index.pl

```pl
#!/usr/bin/perl
print"Content-type: text/html; \n\n";

my $a = "hoge";
my $b = "fuga";

print << "EOH";
<html>
<head>
<title>タイトル</title>

...
EOH

print "<span>$a</span>\n";
print "<input type=\"text\" name=\"foo\" value=\"$b\" />\n";

print << "EOL";

&create_select();

...

</body>
</html>
EOL

sub create_select {
print "<select name=\"xxx\">\n";
for(my $count=1; $count < 10; $count++){
print "<option value=\"$count\">$count回</option>\n";
}
print "</select>\n";
}
```

# 1. CGI.pmの導入

- 何度も`print << "EOL";`していたのがだるい
	- 一度で済ませる
- 生で`<select>`項目作るのがだるい
	- $cgi->popup_nemuメソッドの活用

## index.pl

```pl
#!/usr/bin/perl
use CGI;

my $cgi = new CGI;
print $cgi->header(-charset=>'UTF-8');

my $a = "hoge";
my $b = "fuga";

print << "EOL";
<html>
<head>
<title>タイトル</title>

...

<span>$a</span>
<input type="text" name="foo" value="$b" />

@{[ &create_select() ]}

...

</body>
</html>
EOL

sub create_select {
  my @values = (1..10);
  my %labels = map { $_ => "$_回" } @values;

  my ret = $cgi->pouup_menu(
    -name => "xxx",
    -values => \@values,
    -labels => \%labels
  );
  $ret;
}
```

# 2. Text::Xslateの導入

- ヒアドキュメントで直接変数を埋め込むのだるい
- テンプレートは別途編集したい

## とりあえず導入

- まずはテンプレートを文字列で定義してレンダリングする

### index.pl

```pl
#!/usr/bin/perl
use CGI;
use Text::Xslate;

my $cgi = new CGI;
print $cgi->header(-charset=>'UTF-8');

my $template << "EOL";
<html>
<head>
<title>タイトル</title>

...

<span><: \$a :></span>
<input type="text" name="foo" value="<: \$b :>" />

@{[ &create_select() ]}

...

</body>
</html>
EOL

my $tx = Text::Xslate->new();

printe $tx->render_string(
  $template,
  {
    a => "hoge",
    b => "fuga",
  }
);

sub create_select {
  my @values = (1..10);
  my %labels = map { $_ => "$_回" } @values;

  my ret = $cgi->pouup_menu(
    -name => "xxx",
    -values => \@values,
    -labels => \%labels
  );
  $ret;
}
```

## `@{[ ... ]}`での埋め込みをやめる

- Xslateの関数機能を使い、レンダリング時にPerlのサブルーチンを呼び出す

### index.pl

```pl
#!/usr/bin/perl
use CGI;
use Text::Xslate;

my $cgi = new CGI;
print $cgi->header(-charset=>'UTF-8');

my $template << "EOL";
<html>
<head>
<title>タイトル</title>

...

<span><: \$a :></span>
<input type="text" name="foo" value="<: \$b :>" />

<: create_select() | raw :>

...

</body>
</html>
EOL


my $tx = Text::Xslate->new(
  function => {
    create_select => \&create_select,
  }
);

printe $tx->render_string(
  $template,
  {
    a => "hoge",
    b => "fuga",
  }
);

sub create_select {
  my @values = (1..10);
  my %labels = map { $_ => "$_回" } @values;

  my ret = $cgi->pouup_menu(
    -name => "xxx",
    -values => \@values,
    -labels => \%labels
  );
  $ret;
}
```

## テンプレートを外部ファイル化

- テンプレートは別管理にしたい
	- 編集の容易さの確保
	- $をエスケープするのがだるい
- Xslateのrenderメソッドで外部ファイルに定義したテンプレートを指定

### index.tx
```html
<html>
<head>
<title>タイトル</title>

...

<span><: $a :></span>
<input type="text" name="foo" value="<: $b :>" />

<: create_select() | raw :>

...

</body>
</html>
```

### index.pl

```pl
#!/usr/bin/perl
use CGI;
use Text::Xslate;

my $cgi = new CGI;
print $cgi->header(-charset=>'UTF-8');

my $tx = Text::Xslate->new(
  function => {
    create_select => \&create_select,
  }
);

printe $tx->render(
  'index.tx',
  {
    a => "hoge",
    b => "fuga",
  }
);

sub create_select {
  my @values = (1..10);
  my %labels = map { $_ => "$_回" } @values;

  my ret = $cgi->pouup_menu(
    -name => "xxx",
    -values => \@values,
    -labels => \%labels
  );
  $ret;
}
```

# 3. Mojolicious導入

- *ちゃんとした*アプリにするには生CGIはつらい
- Perlで人気のWAFって何？
	- Mojolicios
- CGI.pmさようなら

## templates/index.html.tx

```html
<html>
<head>
<title>タイトル</title>

...

<span><: $a :></span>
<input type="text" name="foo" value="<: $b :>" />

<select name="xxx">
: for [1..10] -> $value {
  <option value="<: $value :>">
    <: $value :>回
  </option>
: }
</select>

...

</body>
</html>
```

## index.pl

```pl
#!/usr/bin/perl
use Mojolicious::Lite;
use Text::Xslate;

plugin 'xslate_renderer' => {
  template_options => {
    # これを設定しないとplファイルのフォルダー内にあるtmpフォルダーを使おうとする
    cache_dir => $Text::Xslate::DEFAULT_CACHE_DIR
  },
};

get '/' => sub {
  my $c = shift;

  $c->render(
    a => "hoge",
    b => "fuga",
  );
} => 'index';

app->start;
```

# 4. あとはがんばる

- 画面増やしたり、アクション増やしたり
- Mojoliciousはモデルバインディングはないのでがんばったり
- 画面の共通レイアウトを親テンプレート化したり
- 複数画面で使う`select`要素をテンプレート化したり
- etc...