Waves のチュートリアル Compact Apps をやってみる

リソース指向というのを体験してみるため、Waves のオフィシャルサイトに乗っている Getting Started: Compact Apps をやってみたいと思います。

※以下、まだメモ書きなので日本語がこなれていません。

アプリケーションの雛形を作成

他のフレームワーク同様に、アプリケーションの雛形を作成する waves コマンドがあります。これで、雛形を作成します。

$ waves generate --name=spit_ball --template=compact
** Waves 0.8.2 **
** Creating new Waves application ...
** Application created!

waves の generate コマンドで spit_ball という名前のアプリケーションを compact テンプレートを使って作成しました。

waves コマンドの実行でエラーが発生した場合は、Ubuntu 8.10 に Waves をインストール を参考に追加インストールしてみて下さい。

テンプレートとして指定した compact っていうのは、画面のテンプレートではなく、作成するアプリケーションのテンプレートになるようです。compact と classic を指定できるのですが、compact を指定すると動作に必要なたった一つの雛形ファイルが作成されます。classic を指定すると Rails のように MVC スタイルのファイルがたくさん作成されるようです。

waves コマンドのオプションとして、利用する ORM も指定できます。詳しくは waves --help で。

出来上がったファイルを見てみると、spit_ball というディレクトリに startup.rb というファイルが作成されていました。

中身はこんな感じです。

startup.rb

require 'foundations/compact'

module SpitBall
  include Waves::Foundations::Compact
end

まさにコンパクト。さてこれを実行してみたいと思います。

$ cd spit_ball
$ waves server
** Waves 0.8.2 **
I, [2008-12-23 13:44:11 #16704]  INFO -- : Logger started.
I, [2008-12-23 13:44:11 #16704]  INFO -- : Waves::Server starting ...
no such file to load -- ruby-debug

動かんではないか!ということで、sudo gem install ruby-debug して再実行すると、

$ waves server
** Waves 0.8.2 **
I, [2008-12-23 13:49:49 #16971]  INFO -- : Logger started.
I, [2008-12-23 13:49:49 #16971]  INFO -- : Waves::Server starting ...
I, [2008-12-23 13:49:49 #16971]  INFO -- : ruby-debug enabled
I, [2008-12-23 13:49:50 #16971]  INFO -- : Mongrel started on 127.0.0.1:3000.

無事に起動しました。

まずはこの状態で http://localhost:3000/ にアクセスしてみると、あずき色の背景に 404 Not Found と表示されます。

アプリケーションのレイヤー

Waves で作るアプリケーションは、モジュールの Mixin を使った階層化構造になっているらしい。と言う解説が書いてあった。ここはサラッと流して次にすすんでみた。そのうちわかるだろう。

リソース

Waves にとってリソースはスパルタの戦士らしい。強そうだ。他のクラスはこのリソースの奴隷なんだそうだ。強いにちがいない。

ということで、リソースを追加してみる。もともとあった startup.rb に module Resources と class Map を追加する。

startup.rb

require 'foundations/compact'

module SpitBall
  include Waves::Foundations::Compact

  module Resources
    class Map
      on(:get) { "Hello World!" }
    end
  end
end

SpitBall::Resources::Map クラスはアプリケーションのエントリーポイントになるそうです。みたまんま、HTTP GET のときに "Hello World!" を返すということで、waves server して http://localhost:3000/ すると Hello World! と表示された。

このままでは waves server コマンドはコードのリロードをしないそうなので、CTL+C してからもう一回 waves server する必要があるそうです。

Map クラスの on メソッドをもうちょっと詳しく理解するために、2 行追加します。

startup.rb

require 'foundations/compact'

module SpitBall
  include Waves::Foundations::Compact

  module Resources
    class Map
      on(:get) { "Hello World!" }
      on(:get, ['hello']) { "こんにちは!" }
      on(:get, ['hello', :name]) { "Hello, #{captured.name}!" }
    end
  end
end

on メソッドの指定

URL

表示される文字列

on(:get)

http://localhost:3000/

Hello World!

on(:get, ['hello'])

http://localhost:3000/hello

こんにちは!

on(:get, ['hello', :name])

http://localhost:3000/hello/パラメータ

Hello, パラメータ!

ということで、on メソッドの 2 番目の引数には URL のパスにマッチするように Rails とかでいうルーティングの指定をするようです。

こういう場合に重要となってくる on メソッドの指定順序ですが、同じような on があった場合、後ろの方に書いた on メソッドが前の on を上書きするそうです。なので、

startup.rb

require 'foundations/compact'

module SpitBall
  include Waves::Foundations::Compact

  module Resources
    class Map
      on(:get) { "Hello World!" }
      on(:get, ['hello', 'japanese']) { "こんにちは!" }
      on(:get, ['hello', :name]) { "Hello, #{captured.name}!" }
    end
  end
end

こうすると、on(:get, ['hello', :name]) が on(:get, ['hello', 'japanese']) を上書きすることになるので、ブラウザに 'こんにちは!' と表示されることはないのですね。

コードのリロードとリソースの委譲

コードを変更するたびに waves server を再起動しなくてはいけませんでしたが、自動でコードを再読み込みするようにすることができます。それから、リソースの委譲について。

startup.rb を書き換えて、新しく greeting.rb ファイルを作成します。

startup.rb

require 'foundations/compact'
require 'autocode'

module SpitBall
  include Waves::Foundations::Compact

  module Resources
    include AutoCode
    auto_load true, :directories => '.'

    class Map
      on(true) { to(:greeting) }
    end
  end

  module Configurations
    class Development
      reloadable [Resources]
    end
  end
end

greeting.rb

module SpitBall
  module Resources
    class Greeting
      include Waves::Resources::Mixin

      on(:get) { "Hello World!" }
      on(:get, ['hello']) { "こんにちは!" }
      on(:get, ['hello', :name]) { "Hello, #{captured.name}!" }
    end
  end
end

先に書いてあった、モジュールを積み重ねて Mixin してといったあたりがだんだん見えてきました。

まずは require 'autocode' で有効になった AutoCodeSpitBall::Resources で include しています。その他もろもろのメソッド指定によって、SpitBall::Resources モジュール内のクラス Greeting が必要なときに greeting.rb を動的にロードするようになっています。

クラス名とファイル名の関連は snake-case (っていうんですね) を使って、たとえば BlogPost というクラスは blog_post という名前に変換してファイルをロードするそうです。

そして、SpitBall::Configurations::Development の reloadable [Resources] で、見たまんまですが、開発時は SpitBall::Resources モジュール内のクラスをリロードできるようにしています。こうすることで、SpitBall::Resources モジュール内のファイルを変更した際に waves server がファイルを自動的にリロードするようになります。いちいちサーバーを再起動しなくてもよくなるってことですね。

それから、さっきまでいじっていた on に true を指定すると、この on がすべてのリクエストをハンドリングするようになります。ブロック指定で to(:greeting) することで、SpitBall::Resources::Greeting へリクエストを委譲するようになります。そしてこの、SpitBall::Resources::Greeting は、AutoLoad によって自動で読み込まれるということで。なるほど。

まだまだ続きます...


Waves - Ruby の WEB アプリケーションフレームワーク


CategoryWaves

ボンノウドットコム Wiki: Waves のチュートリアル Compact Apps をやってみる (last edited 2008-12-23 06:27:30 by JunKikuchi)

このサイトに関するお問い合わせは kikuchi@bonnou.com までお願いします