Smalltalkで作るWebアプリケーション【10日目】
毎度お世話になっております。クラスメソッドの稲毛です。
弊社開発ブログを閲覧されている方の多くはなんらかの形でプログラミングに携わっているものと思いますが、「最近同じプログラミング言語、同じフレームワークの開発ばかりで退屈だなぁ。」と感じることはありませんか?そんな時は是非「いつもと違った」環境に飛び込んでみましょう!
クラスメソッドアドベントカレンダー10日目として、私からは「Smalltalkで作るWebアプリケーション」をお届けします。
Smalltalk環境(Pharo)の準備
何はともあれSmalltalk環境を用意して動かしてみましょう。今回は「Pharo」というSmalltalk環境を使用します。「Pharo」のホームページからアプリケーションをダウンロードします。
「Pharo-1.4-14557-OneClick.zip」を解凍すると「Pharo-1.4-one-click.app」が生成されます。Smalltalkは「Image」ファイルを「Virtual Machine」上で動作させる仮想環境です。ダウンロードしたOneClickパッケージにはWindows、MacOSX、LinuxのVMがすべて内包されています。それぞれの環境下での起動方法は下記の通りです。
Windows | バッチファイル「Pharo-1.4-one-click.app/Pharo-1.4-one-click.bat」を起動します。 |
---|---|
MacOSX | 「Pharo-1.4-one-click.app」がアプリケーションとして認識されますのでそのまま起動します。 |
Linux | シェルスクリプト「Pharo-1.4-one-click.app/Pharo-1.4-one-click.sh」を起動します。 |
問題なく起動すると下図のような画面が表示されます。
この画面がPharo Smalltalkの「開発環境」であり「実行環境」となります。
Seasideのインストール
次にWebアプリケーションフレームワークをインストールします。今回は「Seaside」というWebアプリケーションフレームワークを使用します。
それでは「コンフィグレーションブラウザ」を起動して「Seaside」をインストールしましょう。
下図の画面、テキストが選択状態になっています。
MetacelloConfigurationBrowser open.
選択状態のままショートカットキー「Command + d」または「Ctrl + d(Windows)」を押下することで「式を評価」し「コンフィグレーションブラウザ」が起動します。
「コンフィグレーションブラウザ(MetacelloConfigurationBrowser)」はパッケージ管理システム用のブラウザです。これを用いることで様々なプロジェクトを依存性が解決された状態でインストールすることが可能です。
それでは「Seaside 30」を選択し、右クリックによって表示されるコンテキストメニューから「Install configuration」を実行します。
少々時間がかかりますのでプログレスダイアログが消えるまで一服しましょう。( ´ー`)y-~~
プログレスダイアログが消え、操作が受け付けられていればSeasideフレームワークのインストールは完了しています。
ここで念のためイメージの保存を行いましょう。トラブルでフレームワークのインストールがやり直しになったら大変です。
Pharo環境上のバックグラウンドを左クリックすると「World」メニューが開きます。この中の「Save」を実行することで環境の現在の状態が保存されます。ロールプレイングゲームなどでレアなアイテムをゲットした時やボスに挑む前にはセーブを行いますよね?そのような感じで適宜「イメージの保存」を行いましょう。(^_^)
サーバアダプタの追加と起動
それではSeasideのコントロールパネルを開き、サーバアダプタを追加します。バックグラウンドの左クリックで「World」メニューを開き、「Tools → Seaside Control Panel」を実行します。
「Seaside Control Panel」が開いたら、ウィンドウ上部の領域で右クリックして「Add adaptor...」を実行します。
「Chose adaptor type」では「ZnZincServerAdaptor」を選択します。
ポート番号の入力を求められますので、任意のポート番号を割当てます。
作成されたアダプタ「[9090] ZnZincServerAdaptor (utf-8)」を選択した状態で「Start」ボタンをクリックします。
アダプタの左にある「ヒトデ」アイコンに色が付けばサーバアダプタの起動は完了です。星マークではありません。(^_^;)
それではWebブラウザから「http://localhost:9090/」へアクセスしてみましょう。下図のようなページが表示される筈です。
すかさずイメージの保存を行います。今回は「World」メニューから「Save and quite」を選択し、Pharoをいったん終了してみましょう。
再度Pharoを起動し、「http://localhost:9090/」にアクセスしてみてください。イメージは環境をまるごと(サーバアダプタの起動状態も含めて)保存していますので問題なくページが表示される筈です。(^_^)
Seasideコンポーネントの作成
早速ですがWebアプリケーションを作成してみたいと思います。
Seasideでの「Webアプリケーション」は「コンポーネント」であり、コンポーネントはコンポーネントを含むことが出来ます。
「Welcome to Seaside」ページの「Getting started」の「1. Try out some examples」にコンポーネントの例がありますが、ここはちょっと飛ばして「2. Create your first component」にコンポーネント名を入力し「Create」ボタンをクリックします。
イメージのクラスライブラリに変更が加えられる為、名前の入力を求められます。氏名を入力し「OK」ボタンをクリックします。
「MyFirstComponent」という名称でWebアプリケーションが作成されました。リンク「/MyFirstComponent」をクリックしてページを表示してみます。
下図の通り、Webアプリケーション「MyFirstComponent」が表示されます。
Webアプリケーションといってもインタラクションが無いので現状はただのWebページです。このコンポーネントがどのように定義されているか「クラスブラウザ」で閲覧してみましょう。
「World」メニューから「System Browser」を実行します。
下図のようなウィンドウが表示される筈です。これがイメージ内に存在するクラスライブラリを閲覧または編集する為の「クラスブラウザ」です。
ウィンドウ上部の4つのカラムは、左から「クラスカテゴリ」「クラス」「メソッドカテゴリ」「メソッド」となっており、「iTunes」の「カラムブラウザ」のように左から右へ絞り込みながらクラス内の情報を閲覧していきます。ウィンドウ下部のコードエリアには、カラム上でクラスが選択されていればクラス定義、メソッドが選択されていればメソッド定義が表示されます。
作成したコンポーネントのクラスはクラスカテゴリの最下部に追加されているので、閲覧するには「Seaside-User-Example(クラスカテゴリ) → MyFirstComponent(クラス)」と選択します。
「MyFirstComponent」クラスは「WAComponent」クラスのサブクラスとして定義されていることがなんとなくわかるかと思います。
WAComponent subclass: #MyFirstComponent instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Seaside-User-Examples'
続けて「rendering(メソッドカテゴリ) → renderContentOn:(メソッド)」と選択すると、コードエリアにはメソッドの内容が表示されます。
renderContentOn: html html image url: 'http://www.seaside.st/styles/logo-plain.png'. html paragraph: 'Hello World from Seaside.'. html paragraph: [ html text: 'To learn more about Seaside components follow the link to the book: '. html anchor url: 'http://book.seaside.st/book/fundamentals/rendering-components'; with: 'Dynamic Web Development with Seaside'. html text: '.' ]
Smalltalkの文法は「メッセージ式」になっています。「メッセージ式」は、「オブジェクト」に対して「メッセージ」を送信することで何らかの「結果」を得ます。Seasideコンポーネントは、「renderContentOn:」メソッドに渡されるオブジェクト「html」にhtmlタグを表すメッセージを送信することでWebページを描画しているのです。
例えば、
html paragraph: 'Hello World from Seaside.'.
は、
<p>Hello World from Seaside.</p>
のようにレンダリングされます。HTMLをすべてSmalltalkのメッセージ式で書いているわけですね。(^_^)
タスク(WATask)を使ったインタラクション
このままの「MyFirstComponent」ではWebアプリケーションとは呼べないですよね。最後にタスクという仕組みを使って「MyFirstComponent」に簡単なインタラクションを実装してみます。
始めに「MyFirstComponent」クラスから不要なメソッドを削除します。
メソッドカテゴリ「rendering」を選択し、右クリックで表示されるメニューから「Remove category...」を実行します。
メソッドが空になった所で新たな処理を定義していきましょう。
クラス「MyFirstComponent」をクリックしコードエリアにクラス定義を表示させます。
WAComponent subclass: #MyFirstComponent instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Seaside-User-Examples'
親クラスである「WAComponent」を「WATask」へ変更し、ショートカットキー「Command + s」または「Ctrl + d(Windows)」を押下して変更を確定します。
WATask subclass: #MyFirstComponent instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Seaside-User-Examples'
次に「-- all --(メソッドカテゴリ)」を選択し、コードエリアにメソッドのテンプレートを表示させます。
ここに「go」というメソッドを定義します。
go | name | name := self request: 'Input your name.'. self inform: 'Hello, ', name, '!'.
入力を終えたら、ショートカットキー「Command + s」または「Ctrl + d(Windows)」を押下して変更を確定します。
では、「http://localhost:9090/MyFirstComponent」にアクセス(リロード)してみましょう。
入力フィールドに文字列を入力してOKボタンをクリックすると……
入力した文字列がHelloに続けて表示されるようになりました!たった三行で簡単ですね!
変更を適用した際にサーバの再起動等を行なっていない点にも注目です!
解説
「WATask」のメソッド「go」は、複数のコンポーネントから成る画面遷移を、記述されているロジック通りシーケンシャルに実行します。
| name |
1. 一時変数「name」を宣言する。
name := self request: 'Input your name.'.
2. コンポーネント「WAInputDialog」によって文字列の入力を要求し、入力が確定された文字列を一時変数「name」へ格納する。
self inform: 'Hello, ', name, '!'.
3. コンポーネント「WAFormDialog」を用いて、結合した文字列を表示する。
OKボタンクリック後は「go」メソッド先頭の1へ戻る。
画面遷移を拡張する際も簡単です。例えば文字列が入力されないでOKボタンがクリックされた際に別のメッセージを表示させたい場合は、
go | name | name := self request: 'Input your name.'. name isEmpty "nameが空か?" ifTrue: [ self inform: 'Name is empty.' ] "空だった時(true)のメッセージ" ifFalse: [ self inform: 'Hello, ' , name , '!' ] "空でなかった時(false)のメッセージ"
のようにするだけです。画面遷移が条件分岐通りに行われるので見通しが良いですね。(^_^)
まとめ
急ぎ足になってしまいましたが、ハンズオンを通して「Smalltalk面白そう」とか「SeasideでWebアプリ作ってみようかなぁ」なんて思っていただけたら幸いです。ここでは魅力を殆ど伝えきれていないので、Smalltalkに興味を持たれた方は後述するサイトを覗いてみると良いかと思います。また、Smalltalkに限らず使ったことのない言語環境に触れてみると、思いがけない実装手法やアイデアが見つかるかもしれませんよ?(^^)