-
会場について
- 飲食・喫煙・トイレetc
-
写真撮影について
-
写真撮影NGな方は、お手数ですが申し出てください
-
写真はPerl普及団体の JPA ( Japan Perl Association )への活動報告に利用します
-
- 講師・サポーター紹介
-
せっかく今日集まったので、テーブルで自己紹介をしましょう。
-
話題は自由ですが、以下がオススメです。
-
名前(ハンドルネーム)
-
なぜPerlを勉強してみようと思ったか
-
なぜPerl入学式に参加してみようと思ったか
-
前回参加してからの学習の進捗
-
-
サブルーチン
-
Webアプリ、その前に
-
HTTP の基礎
-
Mojolicious の準備
-
Mojolicious とは
-
Mojolicious::Lite
-
Mojolicious 入門
-
簡易 BBS の作成
プログラムの中で、意味や内容がまとまっている作業をひとかたまりにしたものを サブルーチン と呼びます。
Perlにおけるサブルーチンは、「関数」とほぼ同義です。
Perlには、これまで使ってきた print
や join
など、Perlが提供する関数(組み込み関数)が用意されています。
サブルーチンを使うことで、 print
や join
のように、「特定の処理を行うコード」をひとかたまりにして、 簡単に呼ぶことが出来るようになります。
それでは、早速サブルーチンを定義していきましょう。
今回は、末尾に自動的に改行(\n
)を付与しながら文字列を表示する say
というサブルーチンを定義してみます。
sub say { # -┐
my $str = shift @_; # │ サブルーチン say を
print "$str\n"; # │ 定義しているところ
} # -┘
say("hello, world!"); # hello, world!
Perlでサブルーチンを定義する為には、sub サブルーチン名 { ... }
と書きます。
それでは、詳しく見て行きましょう。
sub say { ... }
-
末尾の
}
の後に、;
を書く必要はありません。 -
サブルーチン名として使える文字は以下です。
- 大文字・小文字の英数字
- アンダースコア(
_
)
-
ただし、サブルーチン名の先頭文字には以下の制限があります。
- 英文字
_
これは変数名と同じルールです。
sub say_hello_world { ... }
sub say_good_morning { ... }
複数の単語でサブルーチン名を構築する時は、このように単語間を _
で繋げる場合が多いです。
このような _
で単語をつなげる記法をスネークケース(snake_case)といいます。
Perlでは基本的にスネークケースを推奨しています。
sub hoge! { ... }
sub _hoge { ... }
sub 123_hoge { ... }
sub hoge_123 { ... }
この中で、サブルーチン名として正しいものはどれでしょうか?
sub hoge! { ... } # 記号 '!' はサブルーチン名に使えない
sub _hoge { ... }
sub 123_hoge { ... } # 先頭は 英字 or '_' のみ
# 数字は先頭に使えない
sub hoge_123 { ... }
正解は _hoge
と hoge_123
です。
say('Hello Perl');
定義したサブルーチンは、定義したサブルーチン名の後ろに ()
を付けることで利用できます。
行末に書く場合には、 ;
が必要です。
このようにサブルーチンを利用することを「サブルーチンの呼び出し」といいます。
サブルーチンに値(引数)を渡したい場合、 ()
の中に書きます。
()
を使わずに, サブルーチン名の先頭に &
を付けて &say
で呼びだすこともできますが、古い書き方なので使わないようにしましょう。
sub say {
my $str = shift @_; # ←┐
print "$str\n"; # │ サブルーチンの引数 'Hello Perl' は
} # │ @_ という配列に格納される
# │
say('Hello Perl'); # ─┘
サブルーチンに与えられた引数は、 @_
という配列に格納されます。
2行目では、shift
を使って、この @_
の先頭の要素を取得しています。
このサブルーチンを say('hoge');
のように呼んだ場合、 @_
の中身は('hoge')
となり、 $str
には hoge
という文字列が入ります。
sub say {
my $str = shift; # @_ が省略されている
print "$str\n";
}
say('Hello Perl'); # Hello Perl
@_
は、省略することができます。
その為、2行目の my $str = shift;
は、 my $str = shift @_;
と同じ意味になります。
say('Hello Perl'); # Hello Perl
sub say {
my $str = shift;
print "$str\n";
}
同じファイル内であれば、サブルーチンの位置にかかわらず say('hoge');
として呼び出すことができます。
ファイル末尾にサブルーチンがまとまっている方が見やすい場合は、このスタイルで書きましょう。
sub add { # ┐
my ($left, $right) = @_; # │サブルーチン add の定義部
return $left + $right; # │
} # ┘
my $result = add(2, 5); # サブルーチン add の呼び出し
print $result . "\n"; # 7
次に、2つの引数を受け取り、その和を返すサブルーチン add
を考えてみることにします。
add
サブルーチンの定義と呼び出しは、このように書くことができます。
sub add {
my ($left, $right) = @_; # @_ の中に 2, 5が入る
return $left + $right; # ↑
} # │
# │
my $result = add(2, 5); # ┘ add の引数 2, 5
print $result . "\n"; # 7
サブルーチンに複数の引数が与えられた場合(この場合は 2
と 5
)、サブルーチン側ではこのようにして受け取ることができます。
サブルーチンに複数の引数を与える時は、( )
の中で配列のようにカンマ ,
で区切って渡します。
sub add {
# @_ を省略した場合
my $left = shift; # @_ の先頭から1つ取り出して変数に入れている
my $right = shift; # @_ の先頭から1つ取り出して変数に入れている
return $left + $right;
}
my $result = add(2, 5);
sub add {
my $left = $_[0]; # $_[0] : @_ の最初の要素
my $right = $_[1]; # $_[1] : @_ の次の要素
return $left + $right;
}
my $result = add(2, 5);
先程の引数の受け取り方は、上記のコードと同じ意味になります。
sub add {
my ($left, $right) = @_;
return $left + $right; # $left + $right の結果を返す
}
my $result = add(2, 5);
print $result . "\n"; # 7
サブルーチンは, return
を使うことで、任意のデータを呼び出し元へ返すことができます。
サブルーチンや関数の処理結果のことを 返り値 といいます。
この場合、 $left + $right
の計算結果が呼び出し元へ返され、 $result
に格納されます。
sub is_same {
my ( $left, $right ) = @_;
if ( $left eq $right ) {
print "true\n"; # $left と $right が等しければ表示
return 1;
}
else {
print "false\n"; # $left と $right が異なれば表示
return 0;
}
print "YOU WILL NEVER SEE IT\n"; # 絶対に表示されない!
return;
}
return
はサブルーチンの中に複数個書くことができます。
return
に到達した場合、それ以降の処理は一切行われず、すぐさま値を返してサブルーチンの実行を終了します。(ガード節といいます)
sub add_and_min {
my ( $left, $right ) = @_;
return ( $left + $right, $left - $right );
}
my ( $add, $min ) = add_and_min( 5, 4 );
サブルーチンは、このようにリストを返すことで複数個の値を返すこともできます。
引数がどのようにサブルーチンに渡されて処理されるか、追ってみましょう。
sub add {
my ($left, $right) = @_;
$left + $right; # サブルーチンの中で最後に評価された行
}
my $result = add(2, 5);
print $result . "\n"; # 7
サブルーチンの中に return
がない場合、サブルーチンの返り値は最後に評価された処理の結果(この場合、 $left + $right
の計算結果)を返します。
値を返すという意図を明確にするため、 return
は書くようにしましょう。
次のようなサブルーチンを持つコードを simple_calc.pl
という名前で作成しよう。
- 2つの引数の和(足し算)を計算する
add
- 2つの引数の差(引き算)を計算する
min
- 2つの引数の積(掛け算)を計算する
mul
- 2つの引数の商(割り算)を計算する
div
これらのサブルーチンが正しく実装できているか(与えた2つの引数に対して, 適切な値を返すか)を確認するコードも一緒に書くこと。
-
時間の余った人は「0」で割った際のエラーを回避する仕組みを入れてみよう
-
さらに時間の余った人は数字以外が入力された場合に 'INPUT NUMBER PLEASE'と表示する仕組みを入れてみよう
ワープロや表計算などといった、コンピュータを「応用」する目的に応じた、コンピュータ・プログラムである。
**インターネット(もしくはイントラネット)などのネットワークを介して使用するアプリケーションソフトウェアである。**
多くの場合、これらのアプリケーションは、Webブラウザ上で動作するプログラミング言語(たとえばJavaScript)によるプログラムと
Webサーバ側のプログラム
が協調することによって動作し、ユーザはそれをWebブラウザ上で使用する。
この Webサーバ側のプログラム(スクリプト) を今回の講義で作成していきます。
- スクリプトを作る
- ターミナルで実行し、入力待ち状態になる
- ターミナルの標準入力から入力する
- 入力された内容を、スクリプトが処理する
- ターミナルの標準出力に、結果が表示される
- スクリプトを作る
- ターミナルで実行し
- Webブラウザに画面が表示される
- Webブラウザの入力フォームに入力する
- 入力された内容を、サーバーでスクリプトが処理する
- Webブラウザに、結果が表示される
プログラムにおいて、必要とされる機能を第三者にも扱えるようにまとめたものを、**モジュール(ライブラリ)**といいます。
第4回目でData::Dumper
モジュールを使いましたが、それは Perl に最初から入っている組み込みモジュールでした。
これから学習していく Mojolicious は外部から追加しなくてはならないモジュールです。
モジュールのインストール方法は様々な方法がありますが、この講義では local::lib と cpanm を使って入れることにします。
local::libは、モジュールを自分のホームディレクトリで管理することができるモジュールです。
local::lib を使うことで、システム全体への影響を抑えることができます。
Perlのモジュールの多くはMetaCPANで公開されています。
このサイトや、GitHubからターミナルでモジュールをインストールすることができるモジュールが cpanm です。
cpanm は通常、 perl が入っているディレクトリにモジュールをインストールしますが、 -l
オプションで指定することで、任意のディレクトリにインストールすることが可能です。
この講義では、自分のホームディレクトリ配下にモジュールをインストールします。
ターミナルで以下のコマンドを一つずつ打っていきます。
先頭の $
はターミナルで一般権限ユーザの時に表示されるもので、入力は不要です。
$ curl -L cpanmin.us -o cpanm
$ chmod +x cpanm
$ ./cpanm -l ~/extlib local::lib
$ perl -I ~/extlib/lib/perl5 -Mlocal::lib=~/extlib | tee -a ~/.bash_profile
$ exec $SHELL -l
$ ./cpanm Mojolicious
インストールに躓いたり, エラーが出た時はサポーターを呼んだり、Slackでエラーメッセージを貼り付けて聞いてみてください。
先ほど入力したものの詳細はこちらです。
# curlコマンドでcpanminusプログラムをダウンロードし、cpanmという名前で保存する
$ curl -L cpanmin.us -o cpanm
# cpanmに実行権限をつける
$ chmod +x cpanm
# cpanmの -l(エル)オプションで、指定したディレクトリ(extlib)に指定したモジュール(local::lib)を
インストールする
$ ./cpanm -l ~/extlib local::lib
# perlのモジュール検索パスを追加し(~/extlib/lib/perl5)、extlibにパスを通すための設定を表示
# それをteeコマンドを利用して起動時のシェル設定ファイルにも書き込む
$ perl -I ~/extlib/lib/perl5 -Mlocal::lib=~/extlib | tee -a ~/.bash_profile
# シェルを再起動する
$ exec $SHELL -l
# MSYSのみ実行。Windowsでシンボリックリンクを利用することをMSYSに伝える
$ export MSYS=winsymlinks
# -n テストなしでMojoliciousをインストールする。
# 基本的には -n をつけずにインストールを行うが、時間の都合上、Perl入学式ではテストなしでインストールします。
$ ./cpanm -n Mojolicious
以下のコマンドをターミナルから実行し、 Mojolicious のバージョン番号が出力されればインストール成功です。
$ perl -MMojolicious -e 'print "$Mojolicious::VERSION\n"'
cpanm を利用することで、 Mojolicious の他にも数多くのモジュールを利用することができます。 気になったモジュールがあれば
$ ./cpanm モジュール名
でインストールして使ってみましょう!
モジュールの検索はmetacpanやGitHubを利用します。
「やりたいこと Perl」 でGoogle検索するのもおすすめです。
Perlの有用なモジュールは数多くあるので、全ては紹介できません。ごくごく一部を紹介します。
また、「・・・有用?」というようなモジュールもあります。これらはAcmeモジュールと言われるジョークモジュール群です。
このように、Perlのモジュールの世界は懐が広いのが特徴です。ぜひ下記の参考リンクも見てみてください。
Web アプリケーションフレームワーク(WAF) とは、Webサービスを作る際の必須機能や定型の処理を、まとめて提供する仕組みのことです。
framework 「枠組み」「骨組み」「構造」などと和訳できる英単語wikipedia([フレームワーク](https://ja.wikipedia.org/wiki/%E9%9B%BB%E5%AD%90%E6%8E%B2%E7%A4%BA%E6%9D%BF))
Mojolicious は Perl の軽量WAF の1つです。
類似の軽量WAF
- Amon2 (Perl)
- Sinatra (Ruby)
- Flask (Python)
- Express (Node.js)
似ていない(重量級の)WAF
- Catalyst (Perl)
- Ruby on Rails (Ruby)
WAFでは、機能のまとまりごとに処理を分けて開発を行っていきます。機能の分け方には様々なやり方があり、手法も数多くありますが、ここでは MVCモデル を紹介します。
- M: Model
- Viewから受け取ったデータの処理や、Viewに提供するデータの用意を行う
- V: View
- 見栄え、データの表示や入力受付、装飾などを行う
- C: Controller
- アドレス(URL)ごとに、どのModelやViewを割り当てるかの交通整理役
MojoliciousはMVCモデルのうち、Modelを除いた「View」と「Controller」の機能を持っています。
では、 Model はどうするのか?
この入門では、難しい表現を避けるために、厳密には正しくない事も書いてあります。
また、講義時間内に収めるために、ごくごく一部のコマンドや機能についてのみ説明しています。
沢山の引数やコマンド、記法については、本家サイトなどのリファレンスをご覧ください。
Mojoliciousをインストールすると、mojo
というコマンドが使えるようになります。ターミナルで以下のコマンドを入力してください。
$ mojo generate lite_app hello_mojo.pl
mojo generate lite_app
Mojolicious::Lite
を利用した小規模アプリ用のひな形を作成するコマンド。
hello_mojo.pl
- 引数。作成するファイル名。
現在のディレクトリに hello_mojo.pl
というファイルが作成されていれば成功です。このファイルは雛形であり、このファイルに手を加えてWebアプリケーションを作成していきます。
Mojoliciousをインストールすると、 morbo
というコマンドも使えるようになります。
morbo
は開発用のWebアプリケーションサーバです。この morbo コマンドで mojolicious を起動し、ブラウザで表示を確認しつつ、修正やデバッグをしてWebアプリを作成していきます。
インターネット上では主に Apache や nginx といったWebサーバと、 Webアプリケーションサーバが連携してWebサービスを提供しています。
ターミナルから、以下のように打ち込んで実行してください。
$ morbo hello_mojo.pl
Web ブラウザで http://127.0.0.1:3000
にアクセスしてみましょう。
画面上に Server available at http://127.0.0.1:3000.
と表示されれば起動しています。
ターミナル上で Ctrl(又は Control )キーを押しながら C キーを押します。
ターミナルが入力待ちの状態に戻れば morbo は終了しています。
ブラウザをリロードすると、ページが表示できなきなくなっています。
入力したアドレスについては簡単な説明で済ませます。興味のある方はネットワークについて勉強してみましょう!
-
Webにアクセスする際には、対象のサーバのIPアドレスが必要です。
-
127.0.0.1
はローカルループバックアドレスといい、自分自身を指す特殊なIPアドレスです。 -
:3000
はポート番号とよばれるものです。通常のhttpサーバは80番ポートを使います。メールの送信(SMTP)には25番、メールの受信には110番、など利用するアプリケーションごとに番号が決められています。
それでは、先ほど作成した雛形、 hello_mojo.pl
の解説を簡単に行なっていきます。
コード全体はこちらからも確認できます。
#!/usr/bin/env perl
use Mojolicious::Lite;
use Mojolicious::Lite;
とすることで、Mojolicious の関数が利用できるようになります。
また、自動的に strict
、 warnings
、 utf8
、 Perl 5.10 feature
が有効になります。
use strict; # お約束
use warnings; # お約束
use utf8; # スクリプトの中でマルチバイト文字(日本語など)を使う時に書く
use feature ':5.10';# Perl バージョン5.10で用意された関数を利用可能にする
use Mojolicious::Lite;
と書くことで、上記の記述を含むことになります。
get '/' => sub {
my $c = shift;
$c->render(template => 'index');
};
MVCモデルの Controller の部分です。
ウェブアプリケーションでは、URLごとに処理を変更できると便利です。URLごとに処理を振り分ける機能のことを router
や dispatcher
と呼びます。
Mojolicious::Lite
では、 情報を取得する GET メソッド用の router
として get
という関数が用意されています。
get '/' => sub { 省略 };
見慣れない書き方ですが、これは、先に説明した get
という関数に、2つの引数を渡しているものです。
1つ目の引数が '/'
という文字列、2つ目の引数がコードリファレンス(サブルーチンリファレンス)です。
コードリファレンス(サブルーチンリファレンス)は sub
から始まっていますが、先に学習したサブルーチンではありません。サブルーチンのリファレンスです。1点重要な違いとして末尾にセミコロンが必要です。
このように書くことで、GET メソッドで /
にアクセスした時、 sub { ... }
に書かれている処理が行われます。
my $c = shift;
$c->render(template => 'index');
コードリファレンス内の最初の行は、引数を $c というスカラー変数で受け取っています。この $c はコントローラーの略称と思ってください。
$cの中に入るのは、「どのブラウザからアクセスしてきたか?」「入力項目にどのような値が入っているか?」「どのような操作が可能か?」といった情報の塊、オブジェクトです(詳細は「すぐわかる オブジェクト指向Perl」で)。
コントローラーには render
というメソッドがあり、どのような出力をするのかを書くことができます。メソッドは、オブジェクトに紐づいたサブルーチンと思ってください。
ここでは index
のテンプレートに出力するように書かかれています。
app->start;
コントローラーの処理を書いた後、Mojolicious が用意した app オブジェクトの start メソッドを利用してアプリを起動します。
このコードがないと Mojolicious は起動しません。
__DATA__
__DATA__
この行以降をデータセクションといいます。
Perlはこの行以降は文字通りデータとして扱い、コードとして解釈しなくなります。
Mojolicious::Liteでは、ここにブラウザで表示される部分、MVCフレームワークの View に関するコードを書いていきます。
Mojolicious::Liteでは、Viewをさらに分割しています。
- ページの内容を記述する「テンプレート部」
- ページのレイアウトを設定する「レイアウト(レイアウトテンプレート)部」
@@ index.html.ep
ここからはページの内容を記述するテンプレート部となります。
Mojolicious::Lite
では、 @@ index.html.ep
と書くと、次に @@
が出てくるまでの範囲を index.html.ep
というファイルとして扱います。
このようにすれば、1つのPerlスクリプトで多くのページを作ることができ、効率的にWebアプリを書くことができます。
ep
は、Mojoliciousの標準的なテンプレート機能を使用するための拡張子です。拡張子を ep
にすることで、テンプレートであることを示します。
% layout 'default';
% title 'Welcome';
<h1>Welcome to the Mojolicious real-time web framework!</h1>
-
layout
関数でレイアウトを指定します。ここではdefault
を設定しています。(後ほど詳しく説明します) -
title
関数はタイトルを指定します。ここではWelcome
を設定しています。(後ほど詳しく説明します) -
それ以外の通常の文字列は、そのままHTMLとして表示されます。
@@ layouts/default.html.ep
@@
が書いてあるので「テンプレート部」はこの上の行までとなります。これ以降は「レイアウト(レイアウトテンプレート)部」です。
以下をまとめて書いておくことで、ページごとに記述する手間を省くことができます。
<html></html>
タグや<head></head>
タグ<body></body>
などの必須HTMLタグ- タイトルロゴや会社案内などのヘッダーやフッターのHTML
また、このレイアウトもテンプレートと同じく、仮想的なファイル layouts/default.html.ep
つまり layouts
ディレクトリにある default.html.ep
というファイルとして扱われます。
<!DOCTYPE html>
<html>
<head><title> 省略 </title></head>
<body> 省略 </body>
</html>
<!DOCTYPE html>
HTMLのバージョン5(HTML5)で書かれていることをブラウザに伝えるHTMLのマークアップ宣言です。<html>...</html>
このタグの内部にHTMLを記述します。<head>...</head>
このタグの内部にHTMLのヘッダー情報を記述します。<title></title>
このタグの内部にページタイトルを記述します
<body>...</body>
このタグの内部にHTMLの本文を記述します。
HTMLタグの内側に書かれているものについての解説です。
<head><title><%= title %></title></head>
<body><%= content %></body>
-
<%= ... %>
(あるいは%=
から始まる行)は、Perl のコードを実行するだけでなく、変数の値を表示したい時に書きます。 -
<%= title %>
は、14行目で% title 'Welcome';
と指定したので、Welcome
と表示されます。title
は、Mojoliciousが用意した関数です。 -
content
は、レイアウトテンプレート内で使える関数で、テンプレート部(12 - 15行目)の中身がここに代入されます。
morbo
が起動していない人はターミナルから以下のコマンドで起動します。
$ morbo hello_mojo.pl
先に作成した hello_mojo.pl
のファイルを編集していきます。
まず、Controllerで変数を設定して、それをView(テンプレート)に渡してみましょう。 [GitHub] hello_mojo.pl
get '/' => sub {
my $c = shift;
$c->stash( greeting => 'Hello Mojo' ); # この行を追加
$c->render('index');
};
コントローラー部で $c->stash( greeting => 'Hello Mojo' );
と書くことで、テンプレート内でスカラー変数 $greeting
(中身は文字列'Hello Mojo')を利用することが可能になります。
stash
メソッドの引数がハッシュ形式であることにも注目です。
Controllerで設定した変数を、View(テンプレート)で、表示してみます。
Welcome〜 の行の下に、 <%= $greeting %>
と1行追加してください。
<h1>Welcome to the Mojolicious real-time web framework!</h1>
<%= $greeting %> # この行を追加
追加したらスクリプトを保存して、ブラウザをリロードしてください。
Hello Mojo と表示されたら成功です。
このように、Controller で設定した変数を、 <%= 変数名 %> という特別なタグをつかってテンプレート内で表示することができます。
つぎに、ページの増やし方です。新たにひな形を作って実践していきます。
$ mojo generate lite_app mojo_prof.pl
$ morbo mojo_prof.pl
作成した mojo_prof.pl
を編集していきます。
まず、コントローラー部にルーターを追加します。
get '/' => sub {
my $c = shift;
$c->render(template => 'index');
};
# 以下の4行を追加
get '/profile' => sub { # get関数の最初の引数が
my $c = shift; # /profile となっている
$c->render(template => 'index');
};
ここまで入力したら、ブラウザをリロード(再読み込み)してから以下のアドレスにアクセスしてみてください。
同じページが表示されていれば成功です。
また、ルーターを追加していない適当なアドレスを入力して、エラーが出ることを確認してみましょう。
では、ページのアドレスごとに表示される内容を変更します。引き続き、mojo_prof.pl
を編集します。今度はViewのテンプレート部に追加します。
Welcome のメッセージ下にある4行をコピペして追加します。なお、<!-- コメント -->
はテンプレート(HTML部分)にコメントを書くときの記法です。[GitHub] mojo_prof.pl
<h1>Welcome to the Mojolicious real-time web framework!</h1>
<!-- <h1>タグの下に以下の4行を追加する -->
@@ profile.html.ep
% layout 'default';
% title 'ぷろふぃーる';
<h1>プロフィール</h1>
@@ layouts/default.html.ep
view の用意ができたので、コントローラー部の renderメソッドを変更します。
$c->render(template => 'index');
};
# 以下の4行を追加
get '/profile' => sub {
my $c = shift;
$c->render(template => 'profile');# ここを index から profile に変更する
};
ブラウザをリロード(再読み込み)してから以下のそれぞれのアドレスにアクセスしてみてください。
http://127.0.0.1:3000/profile
にアクセスした時に「プロフィール」と表示されていたら成功です。
これでページのアドレスごとに異なる内容を表示することができました。
先ほど作成したhttp://127.0.0.1:3000/profile
を充実させましょう。以下のページからコードをコピペして利用してもokです。
@@ profile.html.ep
% layout 'default';
% title 'profile';
<h1>プロフィール</h1>
<p>私の名前は<%= $name %>です</p>
<p>趣味は<%= $hobby %>で, 好きなプログラミング言語は<%= $lang %>です</p>
- テンプレート部の profile を、コピペして上記のものに置き換えます。
- コントローラー内で stash を利用して
name
,hobby
,lang
変数に値を代入します。
- 思いつかない人用ハッシュ
(name => 'larry', hobby => 'study', lang => 'Perl' )
テンプレートは単にHTMLを表示したり、コントローラーで設定した変数を表示するだけではありません。
if文やfor文のような、Perlの制御構文をテンプレート内で記述することができます。
さっそく練習用の雛形を作って実行してみましょう。
$ mojo generate lite_app mojo_fizzbuzz.pl
$ morbo mojo_fizzbuzz.pl
名前から分かる通り、 fizzbuzz をやってきます。
今回はテンプレートの活用なので、テンプレート部の「Welcome 〜 」の下の行から書いていきます。
<h1>Welcome to the Mojolicious real-time web framework!</h1>
<!-- 以下4行を追加 -->
<% for my $num (1 .. 100){ %>
<%= $num %>
<% } %>
書き終えたら、ブラウザをリロードしてください。1 から 100 までの数字が表示されていれば成功です。
では解説します。
<% for my $num (1 .. 100){ %>
<%= $num %>
<% } %>
テンプレートで利用する特殊なタグを外すとこのようになります。
for my $num (1 .. 100){
$num
}
Perlで書くfor文とほぼ同じです。
<% for my $num (1 .. 100){ %>
<% } %>
テンプレートでのfor文ですが、これはそれぞれの行を <% %>
というテンプレート用の特殊なタグで囲っています。
<% for my $num (1 .. 100){ %>
<%= $num %>
<% } %>
そして、forで処理された変数 $num
を囲む特殊タグが、forの特殊タグと異なるところに注目してください。
変数を表示するタグには =
があり、Perlの構文を書くタグには =
がありません。
-
変数を表示する : <%= 変数 %>
-
Perlの文を書く: <% Perlの文 %>
このように、その行で何をしているかによって特殊タグを変える必要があります。
なお、変数を表示する際の print
は不要です。
引き続き、fizzbuzz.plを編集していきます。
<% for my $num (1 .. 100){ %>
<% if ($num % 3 == 0 ){ %>
fizz
<% } else { %>
<%= $num %>
<% } %>
<% } %>
for文の中にif文を書いています。一気に難しくなったようにみえますが、分解して解説していきます。
for文の中のif文の部分だけを取り出してみます。
<% if ($num % 3 == 0 ){ %>
fizz
<% } else { %>
<%= $num %>
<% } %>
さらに、テンプレートで利用する特殊なタグを外してみます。
if ($num % 3 == 0 ){
fizz
} else {
$num
}
馴染みのある形になったと思います。
<% if ($num % 3 == 0 ){ %>
fizz
<% } else { %>
<%= $num %>
<% } %>
ここでもfor文とほぼ同じで、
-
条件分岐のif文の行は
<% %>
で囲われている -
単に文字を表示するときはその文字
fizz
のみ -
変数を表示するときは
<%= %>
というルールでタグに囲まれています。
fizzbuzz を完成させましょう。 [GitHub] mojo_fizzbuzz.pl
-
fizzbuzzのルール
- 1 から 100 までの数をカウントしていく
- 3 で割り切れる場合、数字ではなく fizz と表示
- 5 で割り切れる場合、数字ではなく buzz と表示
- 3 でも 5 でも割り切れる場合、数字ではなく fizzbuzz と表示
- いずれも満たさない場合は、その数を表示
-
時間が余った人向け課題
<br>
で改行したり、<font color ='blue'>
や<font color ='red'>
などで結果に応じた色をつけてみる- テンプレート部ではなく、コントローラー部に fizzbuzz を書いてテンプレート経由で表示する
いよいよPerl入学式の講義も最終項目となりました。
これから作るのは、Webアプリの基本形ともいえる BBS、掲示板 です。
電子掲示板(でんしけいじばん、BBS、英語: Bulletin Board System)とは、コンピュータネットワークを使用した環境で、記事を書き込んだり、閲覧したり、コメント(レス)を付けられるようにした仕組みのことである。[wikipedia 電子掲示板](https://ja.wikipedia.org/wiki/%E9%9B%BB%E5%AD%90%E6%8E%B2%E7%A4%BA%E6%9D%BF)
簡易BBSを構成する最低限の要素は以下の3つです。
-
ページが表示できる
-
ページを経由して情報を送信できる
-
送信した内容に応じて、ページ内の情報やサービスが変わる
これは全てのWebアプリで必須の要素であり、簡易BBSを通して実装を学ぶことができます。
Twitter や Instagram、交通情報や天気、音楽アプリやゲームなどでも共通する要素です。
なお、Webに限らず、アプリの基本要素をまとめたものをCRUDといい、以下の略称となります。
-
Create: 情報を生成する。
-
Read: 情報を閲覧できる。
-
Update: 情報を更新できる
-
Delete: 情報を削除できる
Perl入学式での簡易BBS作成は、CRUDのうち、 Create と Read を実装します。
以下を完成形として作っていきます。
-
Webブラウザで表示ができる
-
ページに入力欄がある
-
入力欄から入力した文字を投稿すると、その文字がページに表示される
-
複数回投稿すると、投稿した順番でページに表示される
$ mojo generate lite_app mojo_bbs.pl
$ morbo mojo_bbs.pl
作成された mojo_bbs.pl
を編集していきます。
まず、indexテンプレートを変更します。 [GitHub] mojo_bbs.pl
変更前
@@ index.html.ep
% layout 'default';
% title 'Welcome';
<h1>Welcome to the Mojolicious real-time web framework!</h1>
変更後( title と <h1></h1>
タグの中身を変更)
@@ index.html.ep
% layout 'default';
% title 'BBS';
<h1>掲示板です</h1>
ブラウザをリロードして、「掲示板です」と表示されるか確認します。
入力フォームを設置します。
<h1>掲示板です</h1>
の下に、4行追加します。
<h1>掲示板です</h1>
<!-- ここから4行追加 -->
<form action="/" method="get">
<input name="body" type="text">
<input type="submit" value="投稿する">
</form>
追加したら保存します。
ブラウザをリロード (あるいはhttp://127.0.0.1:3000
)
にアクセス) してみましょう。
入力欄が表示されていれば成功です。
ここで、入力欄に「hogehoge」といれて「投稿する」ボタンを押してみます。
画面上に変化がないように見えます・・・が、ブラウザのアドレスバーに注目してください。以下のようになっているはずです。
http://127.0.0.1:3000/?body=hogehoge
他の文字を入れた時も、アドレスバーは入力された文字に応じて表示が変わります。
body
は テンプレートのform
タグのname
hogehoge
は入力内容
この ?body=hogehoge
の部分を**クエリ文字列、クエリストリング(query string)**といいます。
MVCモデルを思い出しましょう。
いま、入力欄が表示されているのは View です。
この View で入力された情報を View で表示するためには、 一度 Controller に入力内容を渡す必要があります。
そして、Controller から View に情報を渡す必要があります。
クエリ文字列を使って、View(の中にあるフォーム) から Controller に入力内容を渡します。
(再掲) $cの中に入るのは、「どのブラウザからアクセスしてきたか?」「入力項目にどのような値が入っているか?」「どのような操作が可能か?」といった情報の塊、オブジェクトです(詳細はオブジェクト指向Perlで)。
確認してみましょう。Controllerに、以下のようなデバッグ情報を追加して保存します。
get '/' => sub {
my $c = shift;
print '-----' ."\n" ; # 追加:単なる区切り線
print $c->param('body') . "\n";# 追加:デバッグプリント
print '-----' ."\n" ; # 追加:単なる区切り線
$c->render('index');
};
ブラウザをリロードして、適当な内容をフォームに入れて「投稿する」ボタンを押してみましょう。
ターミナルのログの中に、入力した文字が表示されています。
先ほどコントローラー部に追加した4行のうち、デバッグ用の表示部分を除いた肝心の部分はこの1行です。
Mojolicious の get メソッド内にある $c の param
メソッドです。
my $entry = $c->param('body'); # 追加
この $c
の param
メソッドの引数に form
の name
(今回はbody) を指定することで、テンプレート内にある入力フォームから送信された内容を取得することが可能です。
このような流れでテンプレート部のフォームの内容をコントローラーが受け取ります。
-
Viewで表示されたフォームに入力
-
「投稿する」ボタンを押す
-
フォームのname(今回はbody)と入力内容が含まれたクエリ文字列が作成される
-
クエリ文字列がGETメソッドでサーバー(Mojolicious)に送信される
-
Mojolicousが送信内容を受け取る
受け取った内容をviewに反映させるため、さらに Controller に追加します。
Controller から View に渡す方法は hello_mojo.pl や mojo_prof.pl で実践済みの stash
を使います。
[GitHub] mojo_bbs.pl
get '/' => sub {
my $c = shift;
my $entry = $c->param('body') ; # クエリストリング body を受け取り $entry に代入
$c->stash( kakikomi => $entry );# 追加
$c->render('index');
};
受け取った情報をスカラー変数 $entry
に代入しています。そして、$entry をstashメソッドの引数(ハッシュのvalue)として渡しています。
Controller から受け取った情報を表示します。
formタグの下に、以下を追加します。
<p><%= $kakikomi %></p>
ここまで出来たら、保存してからブラウザをリロード (あるいはhttp://127.0.0.1:3000
にアクセス) してみます。
フォームに文字を入力して、「投稿する」ボタンをクリックし、入力した文字がフォームの下に表示されることを確認します。
さて、ここまでで投稿した内容をページに表示することができるようになりました。
しかし、再度投稿すると、上書きされてしまいます。
過去に投稿した記事がページに表示されるように変更します。
記事を蓄える場合、主に以下のような方法があります。
-
MySQL や PostgreSQL 、SQLite などのデータベースを使う
-
ファイルを作成し、そのファイルに記事を保存
今回は時間の制約上、データを蓄える方法として配列を使った方法を紹介します。
なお、配列はWebアプリケーションが停止・再起動した時点でデータが消えてしまいます。現実的ではないですが、無駄というわけではありません。
実際には、データベースから抜き出したデータを配列に格納し、Viewに渡す、という用途が多いです。応用が効く方法です。
まず、投稿を保存する配列を用意する必要があります。
use Mojolicious::Lite;
my @entries = (); # 追加する
get '/' => sub {
配列は get
のコードリファレンスの外で宣言します。なぜでしょう?
コードリファレンスの中で my @entries
とすると、 get
でアクセスの都度、配列が初期化されてしまい、投稿を貯めることができなくなるためです。
コントローラーの部分を変更します。
get '/' => sub {
my $c = shift;
my $entry = $c->param('body');
push @entries , $entry; # 追加
$c->stash( kakikomi => \@entries );# 変更
$c->render('index');
};
クエリストリングから取得した記事を配列 @entries
に push
します。
また、stash
メソッドに渡す引数を配列リファレンスに変更します。
コントローラーから受け取ったスカラー変数を、テンプレート部で表示しています。
<p><%= $kakikomi %></p>
この時点でブラウザをリロードすると、入力欄の下に ARRAY(0x7fb17f0d1610) などと表示されます。
これは配列リファレンスを print した時と同じです。
コントローラー部からテンプレートへ配列リファレンスが引き渡されていることがわかります。
この配列リファレンスをデリファレンスします。配列といえば for 文です。<p>
タグで囲まれたところを変更します。 [GitHub] mojo_bbs.pl
変更前
<p><%= $kakikomi %></p>
変更後
<p>
<% for my $kakiko (@{$kakikomi}){ %>
<%= $kakiko %><br>
<% } %>
</p>
これで、投稿が配列に溜まり続け、また、その投稿が表示されるようになりました。
これまで作成してきた簡易 BBS を, 改造してみましょう!
例えば...?
-
名前/メールアドレスを入力/表示できるようにする
-
メールアドレスが「age」であれば、記事を
push
ではなくunshift
する(一番上に表示される) -
テンプレートを整理して、見た目を綺麗にする
-
レイアウトにTwitter Bootstrapを使ってみる
などなど。
非常に簡単ではありますが、BBS (のような) Web サービスを開発してみました。
Perl を使った Web サービス開発の基本的な流れはこのようになっています。
今日ここまで紹介してきた内容は、基礎中の基礎です。
そして、Webサービス全体のうち、「サーバサイド」と呼ばれる部分の一部です。
「 Web サービスを作ろう!」となると、Perl以外にも挑戦しなければならない「壁」はいくつもあります。
- HTMLのコーディング
- HTML5, WEB標準
- Webデザイン、Webアクセシビリティ、ユーザーインターフェイス
- CSS, スタイルシートフレームワーク
- インタラクティブなサイト作り
- JavaScript、Javascriptフレームワーク
- WebサーバとWebアプリケーションサーバの運用管理
- Apache, nginx, plack, starman
- データベースの運用管理
- MySQL, PostgreSQL, SQLite, Oracle
- ネットワーク
- ルーティング, CDN, DNS
- セキュリティ
- XSS, 各種インジェクション攻撃対策
しかし、皆さんは Hello World
の表示からはじめて、Webサービスの基礎を学ぶところまでたどり着きました。
同じように、他の分野の知識も一歩一歩着実に学ぶことで身につけることができます。
また、自分ができない分野は、他の誰かが得意な分野かもしれません。
困ったことがあったら、Perl入学式の資料やスタッフを是非頼って下さい!
是非Perl入学式のslackに参加して、 サポーターや参加者の皆さんと交流しましょう。
今回はWebアプリケーションを作っていきますが、その前にWebについて最低限の解説を行います。
皆さんが使っているブラウザと、インターネット上にあるサーバはHTTPというプロトコルを用いて通信を行なっています。
- HTTP: Hyper Text Transfer Protocol
- Hyper Text:複数の文書(テキスト)を相互に関連付け、結び付ける仕組み(wikipedia)
- プロトコル:手順
HTTPというプロトコルでは、情報の取得を行う**メソッド(方法・手段)**として、主に以下の2つが利用されています。
-
GET : (主に)サーバからデータを取得する
-
POST : (主に)サーバにデータを送信する
このGETとPOSTを利用して、ブラウザとWebアプリ間の情報をやりとりします。
-
主にサーバーからデータを取得する際に利用
-
サーバーにデータを送る際、URLに情報が含まれる
-
GETの例
- Yahoo!Japanの検索ボックスに Perl という文字を入れて検索すると、移動後のページで以下のようなURLになっている
https://search.yahoo.co.jp/search?p=Perl&x=wrt&aq=-1&ai=&clone=&ei=UTF-8&fr=top_ga1_sa
- 検索語である Perl がURLの中に含まれている
-
主にサーバーにデータを送信する際に利用
-
サーバーにデータを送る際、URLに情報が含まない
-
POSTの例
- 日本郵便のページから郵便番号検索した時のURL
https://www.post.japanpost.jp/cgi-zip/zipcode.php
- GETの時と違って、入力された情報が移動後のURLの中に含まれない
GET / POST で通信を行なっているのはパソコンで動いているブラウザだけではありません。
Android や iPhone などのスマホのアプリも、インターネットにあるサーバの情報を GET / POST でやりとりしています。
そして、スマホのアプリがつながるインターネット側では、 Perl をはじめ、node.js ( Javascript ) , Ruby, Python, C や Java などのプログラムが動いています。
完成させたBBSのフォームは、GETメソッドを利用してデータを送信していました。
<form action="/" method="get">
(中略)
</form>
GETメソッドを利用する際には、以下の注意が必要です。
-
送信データは2KB程度(全角で1000文字くらい)が限度
- 画像データなどは、2KBを軽く超える
-
URLにフォームの内容が残り、セキュリティ上の問題になることも
また、 GET と POST は利用用途で使い分ける方が好ましいです。GETとPOSTの復習です。
-
GET : (主に)サーバからデータを取得する
-
POST : (主に)サーバにデータを送信する
GETでは、URLに投稿した内容をクエリストリングという形で付与してデータをサーバに送りました。
POSTでは、リクエストメッセージ内のリクエストボディというデータ領域にデータを込めて送ります。
このリクエストメッセージは容量制限が緩く、画像データなどのバイナリデータを込めることが可能です。
落ち穂拾いでは、POSTメソッドを使った入力フォームを作っていきます。
また、「表示」と「投稿」で機能を分けた設計にしていきます。
ここまでのコードは本編の終了時のコードを元に編集していきます。ただし、ファイル名は新規に mojo_post_bbs.pl
とします。ファイルをコピーするなどして対応するか、以下のリンクからコードをコピぺしてください。
まず、テンプレート部にある、既存のフォーム内のボタンを以下のように変更します。
<form action="/" method="get">
<input name="body" type="text">
<input type="submit" value="GETで投稿する"> <!-- ボタン名を変更 -->
</form>
次に、テンプレート部にPOSTメソッド用の入力フォームを追加します。GETメソッドのフォームとの違いは以下の3つです。
<form>
タグのactionが/post
になっている<form>
タグのmethodが/post
になっている<form>
タグ内のボタンの文字列をPOSTにしている
<input type="submit" value="GETで投稿する">
</form>
<!-- 以下の4行追加 -->
<form action="/post" method="post">
<input name="body" type="text">
<input type="submit" value="POSTで投稿する">
</form>
この時点でブラウザをリロードすると、POSTで投稿するフォームとボタンが表示されます。
しかし、POSTの入力欄に入れて「POSTで投稿」ボタンを押しても、エラーが出ます。
これは、テンプレートにある入力フォームがPOSTメソッドで情報を送っても、その情報を受け取るコントローラーがないためです。
POSTを受け付けるコントローラーを追加します。 [GitHub] mojo_post_bbs.pl
$c->render('index');
};
# 以下の6行追加
post '/post' => sub { # getではなく、post 。また第一引数にも注目
my $c = shift;
my $entry = $c->param('body');
push @entries , $entry;
$c->stash( kakikomi => \@entries );
$c->render('index');
};
追加したコントローラーのメソッドが get
ではなく、 post
であり、postメソッドの第一引数が /post
となっています。それ以外は get
メソッドと同じです。
この時点でPOSTメソッドでの投稿が可能になっています。
GETとPOST、それぞれの方法で投稿して、ブラウザのアドレスバーに表示される内容が異なっていることを確認します。
ここからは、さらなる「落ち穂拾い」です。
コントローラー部のgetメソッドとpostメソッドを比較すると、異なっているのはそれぞれのコードリファレンスの最初だけです。
get '/' => sub {
# 中略
}
post '/post' => sub {
# 中略
}
また、 GET と POST は利用用途で使い分ける方が好ましいです。GETとPOSTの復習です。
-
GET : (主に)サーバからデータを取得する
-
POST : (主に)サーバにデータを送信する
この、GETとPOSTの原則をコードで再現します。
コントローラー部にあるgetメソッドから、投稿データを受け取り配列に保存する部分をコメントアウトします。
GET : (主に)サーバからデータを取得する
get '/' => sub {
my $c = shift;
# my $entry = $c->param('body'); # コメントアウト
# push @entries , $entry; # コメントアウト
$c->stash( kakikomi => \@entries );
$c->render('index');
};
先のコメントアウトにより、getメソッドは「サーバから取得したデータの表示」の役割のみになります。
ブラウザでGETの入力欄に入力して「GETで投稿する」ボタンを押しても、投稿は反映されなくなりました。
引き続きpostメソッドです。少しだけ複雑です。
POST : (主に)サーバにデータを送信する
postメソッドを見ると、以下の二つの機能が原則から外れています。これらはデータの取得と表示のための機能で、POSTの原則である「データの送信」から離れています。これをコメントアウトします。 [GitHub] mojo_post_bbs.pl
-
テンプレートに投稿(配列リファレンス)を渡すための
stash
-
indexテンプレートを表示する
render
post '/post' => sub {
my $c = shift;
my $entry = $c->param('body');
push @entries , $entry;
# $c->stash( kakikomi => \@entries );# コメントアウト
# $c->render('index'); # コメントアウト
};
しかし、この時点でブラウザからPOSTで投稿するとタイムアウトしてしまいます。
これは、投稿を保存した後に何を表示するか?という $c->render('index');
も削ってしまったためです。
ここで、投稿した内容を表示しているのは get
メソッドであることを思い出し、post
の処理が終わったら get
に処理を引き渡す1行を追加します。
postメソッドの処理の最後に、 get '/'
へ処理を遷移させる redirect_to
メソッドを追加します。
このように書くことで、postの処理が終わった後にコントローラー内の get '/'
へと処理が移ります。 [GitHub] mojo_post_bbs.pl
post '/post' => sub {
my $c = shift;
my $entry = $c->param('body');
push @entries , $entry;
# $c->stash( kakikomi => \@entries );# コメントアウト
# $c->render('index'); # コメントアウト
$c->redirect_to('/'); # 投稿を受け付けた後に、get で / に移動
};
- getでページが表示される
- postの入力欄に何かを入力し、「POSTで投稿」ボタンを押す
- フォームがコントローラーにpostメソッドで情報を送る
- 投稿内容をコントローラーのpostメソッドが受け取る
- postメソッドが投稿を配列
@entries
に追加する - 処理をgetメソッドに移す
- getメソッドは
@entries
を配列リファレンスにして、stashメソッドに格納する - getでページが表示され、stashで渡された配列リファレンスをテンプレート内で表示する
POSTがデータの投稿の処理を行うので、GETから投稿の処理を削除します。 [GitHub] mojo_post_bbs.pl
テンプレート内にある、GETメソッドで送信しているformタグを削除します。
<form action="/" method="get">
<input name="body" type="text">
<input type="submit" value="GETで投稿する">
</form>
ほかにも、コントローラー部にあるコメントアウトした行もついでに削除します。
ここで保存してブラウザをリロードすると、フォームが一つになっているはずです。
実際に、投稿ができるか、過去の投稿も表示されるか確認しましょう。
また、投稿時にURLが変わらないことも確認しましょう。
これでおしまいです。お疲れ様でした!