Ruby LotusでWeb Appを作ってみる
注意 この記事はIBM製のコラボレーションソフトについてのページではありません。Rubyで書かれたLotusというWebフレームワークについての記事です。
内容
Lotusとは何か
Lotusは新しいRubyで書かれたWebフレームワークです。比較的少人数のlotusチームが開発しています。 2014年9月の時点ではまだ本番環境では使えませんが、簡単なアプリを作るには十分に動作します。
Lotusのプロジェクトページに書かれているスローガンを見たときに一瞬で一目惚れしました。
ページにはこう書いてあります。(かなり意訳です)
Lotusは軽量で高速かつテストが容易なフレームワークです。Lotusはオブジェクト指向プログラミングのエッセンスを取り戻し、安定したAPI、最小限のDSLを提供してシンプルなオブジェクトに基づいたWeb開発を可能にします。
このスローガンを読んだ時、探していたものはこれだと思いました。(後で詳しく説明します)ちょうど個人でやっているプロジェクトでシンプルなAPIサーバを作ろうとしていたので早速Lotusを使ってみることにしました。 まだ情報がほとんど世の中に存在しないので色々苦労しましたが、最近は少しずつ Lotus Way がわかってきたのでこの記事で紹介しようと思います。
なぜRailsではなくLotusか
最近はアプリケーションをモジュール方式で開発する機会が増えてきました。この開発方法をSOAと呼ぼうがMicroserviceと呼ぼうがなんでもいいですが、多くのプロジェクトがこの開発方式を採用するようになってきています。 (Fylnnはお気に入りの例です)
アプリをモジュール方式で開発する利点はいくつかあります。
- テストがしやすい
- 高いポータビリティ
- 再利用しやすい
- デプロイが容易
Railsを使ってこれらのことを実現するのは簡単ではありません。Railsは素晴らしいですが、フレームワークスタックは巨大で沢山の機能が最初からビルトインされています。 要するにRailsは小さいコンポーネントを沢山作るには大きすぎます。
Sinatraやrails-apiが使えるのでは?と思う人もいると思います。 確かにSinatraは軽量です。ただ最近個人的にはDSLよりも 純粋なRubyのコード を好むようになってきました。学習コストを低く抑えれるからです。 正直rails-apiは使ったことがないのでよくわかりません。ただ、Railsがベースなのでそこまで軽量ではないのではないかと思っています。もし、知ってる人がいたら教えてください。
LotusのGithubページを見ればわかりますが、Lotusは複数のコンポーネントからできているので、この中の一つだけを自分のプロジェクトで使うことも可能です。 例えば、lotus-routerだけを自分のRackアプリに組み込んでHTTPルーターとして使うことができます。
またLotusはRailsのようにフルスタックなフレームワークとして使うこともできます。LotusはRailsのいいとこ取りをしているので(例えばCoCの積極的に採用)比較的少ないコードでアプリケーションを作ることもできます。
つまり、LotusはSinatraのように軽量なアプリを作ることができる一方で、Railsのようにフルスタックなアプリも作ることができるということです。
One-fileアプリケーションを作る
Lotusを使ってOne-fileアプリケーションを作ってみます。LotusのGithubに掲載されているone file applicationを参考にします。
まずは、プロジェクト用のディレクトリを作成します。今後の説明はこのディレクトリをカレントディレクトリに設定しているいう前提で進めます。
mkdir onefileapp && cd onefileapp
Lotusの公式なgemはまだ配布されていません。ここにありますが更新日は2014年1月となっています。最新のmasterブランチは これよりずっと進んでいるので、ソースからインストールします。そのために、まずLotusレポジトリをクローンします。
git clone https://github.com/lotus/lotus.git
Gemの管理にbundlerを使います。Gemfileを作成しましょう。
bundle init
次にGemfileを編集します。<your-path-to-lotus-repo>
をクローンしてきたLotusのレポジトリのディレクトリに適宜変更してください。
source "https://rubygems.org"
gem 'lotusrb', :path => <your-path-to-lotus-repo>
Gemをインストールします。
bundle install --path vendor/
これでアプリケーションを書く準備が整いました(といっても1ファイルですが)。以下のコードを config.ru として保存してください。
config.ru
require 'lotus'
module OneFile
class Application < Lotus::Application
configure do
routes do
get '/', to: 'home#index'
end
end
load!
end
module Controllers
module Home
include OneFile::Controller
action 'Index' do
def call(params)
end
end
end
end
module Views
module Home
class Index
include OneFile::View
def render
"Hello, Lotus"
end
end
end
end
end
run OneFile::Application.new
保存したらアプリを起動してみましょう。最新のmasterブランチには lotus server
コマンドがあるのでこれを使います。
bundle exec lotus server
起動できましたか?それではブラウザで http://localhost:2300 にアクセスしてみてください。 Hello, Lotus
と表示されるはずです。
コードの説明をします。
まず、最初に気づくことはControllers
とViews
モジュール内で定義されているクラスは継承を使っていないということです。
Lotusの哲学の一つにモジュールをインクルードして最小限のインターフェースを実装する
というものがあります。
この哲学は開発者に本当に必要なものだけをMixinして使うことを推奨します。
次にApplication
クラスを見てみましょう。今回の例ではこのクラスはルートの設定をしているだけです。
get '/', to: 'home#index'
とすることでGET /
のルートはHome::Index
コントローラを使うように設定しています。
今回はひとつだけしかルートを設定していませんが他のHTTPメソッドも同じように設定できます。
routes do
post '/books', to: 'book#create'
put '/books/:id', to: 'book#update'
delete '/books/:id', to: 'book#destroy'
# ワンライナーレスポンス
get '/ping', to: ->(env) {[200, {}, ['pong']]}
end
次にControllers
を見てみましょう。action
を呼んでいる以外は何もしていません。
action
とは何でしょうか?action
はHTTPリクエストのエンドポイントとして動き、ここでリクエストの中身を見たりレスポンスを生成したりします。
リクエストに対するビジネスロジックもここに書きます。多分、action
はRailsのControllerとほとんど同じものだと考えていいと思います。
ここでは先ほどみたルートから呼び出されるIndex
actionを定義しています。
最後にViews
を見ましょう。このクラスの仕事はRailsのViewとは異なります。
RailsではViewはブラウザでレンダリングされるコンテンツを吐き出すコードを書く場所でした。LotusではこれはTemplate
で行います。(今回の例ではTemplateはでてきません)
LotusではViewはPresenterレイヤーとして動きます。RailsではPresenterは標準ではありません。(Draperなどのgemで使えるようになります) Presenterの仕事はデータをControllerから受け取って抽象化してTemplateに見せることです。 このようにすることでコンテンツ描画コードをクリーンに保つことができるので最近では有名なデザインパターンです。
コードの説明に戻ります。ここではrender
メソッドを実装してHello, Lotus
というメッセージを表示しています。
この例はあまり面白くないですね。ViewとControllerを連携させてデータのやりとりをさせてみましょう。
Controllerのコードを以下のように編集します。
module Controllers
module Home
include OneFile::Controller
action 'Index' do
expose :time
def call(params)
@time = Time.now
end
end
end
end
2つ新しいメソッドが出てきました。expose
とcall
です。
ControllerからViewにデータを渡すには、exposeを使って明示的に公開する変数を指定しないといけません。
これも本当に必要なものだけを使う
というLotusの哲学の現れです。
call
はHTTPリクエストのエントリーポイントとして動きます。さっきも少し触れたようにこの中にビジネスロジックやレスポンス生成のコードを書きます。
ViewをControllerからデータを受け取るように変更しましょう。
module Views
module Home
class Index
include OneFile::View
def render
"Current time: #{time}"
end
end
end
end
Controllerが@time
をexpose
で公開しているので、Viewはこのデータにtime
変数経由でアクセスすることができます。
アプリケーションを再起動してください。ブラウザで同じページにアクセスするとCurrent time: 2014-09-11 23:18:30 +0900
のように表示されるはずです。
まとめ
LotusでWebアプリを書くのはとても簡単だということがわかってもらえたでしょうか?
ええ、あなたの心の声が聞こえてきますよ。この例は単純すぎて全然実用的ではないじゃないか という声が、、、
確かにその通りです。ですが、それは次の記事で紹介させてください。本当はFull stackアプリケーションに作り方まで紹介する予定だったのですが この記事を書くのに予想より手間取ってしまいました。
次の記事は、Ruby LotusでフルスタックWeb Appを作ってみる みたな感じになる予定です。