Sinatraの使い方を学びつつ、ついでにKomodo IDEで使うSinatraアプリのテンプレートを作成してみます。
Sinatraアプリの原形とセッション&Flashメッセージの組み込み
とりあえずSinatraのインストールから。
$ sudo gem install sinatra
Successfully installed rack-1.0.1
Successfully installed sinatra-0.9.4
SinatraとRackがインストールされました。
アプリのオートリロードするためにShotgunをインストール。
$ sudo gem install shotgun
セッションはRackのセッションを利用し、nakajima/rack-flash @ GitHubでRails風のFlashメッセージを利用します。
$ sudo gem install rack-flash
Sinatraアプリ本体をapp.rbとして作成。
RackのセッションとFlashメッセージを利用できるように設定。
トップページでFlashメッセージをセットして、リンク先/helloでメッセージを表示します。
# -*- encoding: UTF-8 -*-
require 'sinatra'
require 'rack/flash'
configure do
use Rack::Session::Cookie,
#:key => 'rack.session',
#:domain => 'example.com',
#:path => '/',
:expire_after => 3600,
:secret => 'IgR~tKW4YxEvzSHqp^uArcmbFeJklf5dNVQDwCUhOosyiMZTGj'
use Rack::Flash
end
get '/' do
flash[:notice] = "Hello world!"
"<a href='/hello'>Hello world!</a>"
end
get '/hello' do
flash[:notice]
end
でアプリを実行して、http://localhost:9393にアクセスして、動作を確認。
したのは良いんですけど、shotgunを終了したらゾンビになってしまいました。
のでSinatraでshotgunの代わりにRack::Reloaderを使う方法 – Hello, world! – s21gを参考に
configure :development do
class Sinatra::Reloader < Rack::Reloader
def safe_load(file, mtime, stderr = $stderr)
::Sinatra::Application.reset!
use_in_file_templates! file
stderr.puts "#{self.class}: reseting routes"
super
end
end
use Sinatra::Reloader
end
に変更して、
として、リロードされるようにしました。
HamlとSassを組み込む
HamlとSassをインストール。
viewsディレクトリを作成します。
ページレイアウト用にviews/layout.hamlを作成します。
タイトルを表示してflashメッセージを表示するコード。
!!! XML
!!! Strict
%html
%head
%title Sinatra Template
%link{:href => "/styles.css", :rel => "stylesheet", :type => "text/css", :media => "screen"}
%body
#branding
%h1 Sinatra Template
- if flash[:notice]
%p.notice= flash['notice']
- if flash[:error]
%p.error_notice= flash['error']
#content
!= yield
indexページ用にviews/index.hamlを作成します。
%form{:method => 'POST', :action => '/hello'}
%input{:type => 'submit', :value => 'Say hello!'}
app.rbにこれらを表示するためのコードを追加&変更。
require 'haml'
get '/' do
haml :index
end
post '/hello' do
flash[:notice] = "Hello world!"
redirect '/hello'
end
get '/hello' do
flash[:notice]
end
indexページのSay hello!ボタンをクリックすると/helloにPOSTします。さらにそのPOSTでFlashメッセージをセットして、/helloへリダイレクト。/helloでFlashメッセージが表示されます、という内容。
次にSass。
views/styles.sassを作成。内容はあとでリセット入れたり自分用にカスタマイズするとして、今は動作検証のために簡単なコードに。
app.rbにスタイルシートへアクセスするコードを追加。
get '/*.css' do |path|
content_type 'text/css', :charset => 'utf-8'
sass path.to_sym, :sass => {:load_paths => options.views}
end
で、動作確認。期待した通りページが表示されました。
ORM => DataMapperの組み込み
ORMはDataMapperを利用します。
$ sudo gem install datamapper
$ sudo gem install do_sqlite3
app.rbにDataMapperの設定を記述。
データベースにはSQLiteを使用。developmentではmemory、productionではファイルを使用します。
require 'dm-core'
require 'logger'
configure :development do
# リロード設定が記述してあります。
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper::Logger.new(STDOUT, :debug)
end
configure :production do
DataMapper.setup(:default, 'sqlite3:production.db')
end
ユーザ認証はどうしましょうか。maxjustus’s sinatra-authentication at master – GitHubとかsubbarao’s sinatra-openid at master – GitHubが便利そうで試してみたんですか、どちらもうまく動かず。DataMapperのプロパティのタイプにBCryptHashがあるので、それを利用して自作するのが簡単かな。とりあえず保留。
テスト環境の導入
テストにはShouldaとCucumber+Webratを利用しようとおもいます。
まずはShoulda。一緒にrack-testも。
$ sudo gem install shoulda
$ sudo gem install rack-test
testディレクトリを作成。
Testing
Sinatra tests can be written using any Rack-based testing library or framework. Rack::Test is recommended:
Sinatra: README
を参考にtest/app_test.rbを作成。
require File.join( File.dirname(__FILE__), '../app.rb')
require 'test/unit'
require 'shoulda'
require 'rack/test'
class AppTest < Test::Unit::TestCase
include Rack::Test::Methods
def app
Sinatra::Application
end
context "Access pages" do
should "show index" do
get '/'
assert_match 'Say hello!', last_response.body
end
should "show hello" do
post '/hello'
follow_redirect!
assert_match 'Hello world!', last_response.body
end
end
end
次にCucumber。
$ sudo gem install cucumbe webrat
features, featuers/support, features/step_definitionsディレクトリを作成しました。
cucumber.ymlを「default: –language ja features」という内容で作成しました。
features/support/env.rbを作成しました。
# -*- encoding: UTF-8 -*-
app_file = File.join(File.dirname(__FILE__), '../../app.rb')
require app_file
Sinatra::Application.app_file = app_file
require 'test/unit/assertions'
require 'shoulda'
require 'rack/test'
require 'webrat'
Encoding.default_external = 'UTF-8'
Webrat.configure do |config|
config.mode = :rack
config.application_framework = :sinatra
config.application_port = 4567
end
World(Test::Unit::Assertions) do
def app
Sinatra::Application
end
include Rack::Test::Methods
include Webrat::Methods
include Webrat::Matchers
end
Before do
DataMapper.auto_migrate!
end
features/step_definitions/webrat_steps.rbは他のシステムで利用しているものをコピー。
問題はfeatures/step_definitions/result_steps.rb。これまではRSpecを利用していたのですが、今回はtest/unitを使うので、xpathの検証とかはどうするかなど。とりあえず動いたコードがこれ。
# -*- encoding: UTF-8 -*-
ならば /^"(.*)"と表示される$/ do |text|
assert_match(/#{text}/m, @response.body)
end
ならば /^"(.*)"と表示されない$/ do |text|
assert_no_match(/#{text}/m, @response.body)
end
ならば /^(\w+)メッセージが表示さる$/ do |message_type|
assert_not_equal 0, Nokogiri::HTML.parse(@response.body).search("//*[@class='#{message_type}']").length
end
ならば /^(.*)リクエストが失敗する/ do |_|
assert_not_equal 200, @response.status
end
ならば /ページ読み込みが成功する/ do
assert_equal 200, @response.status
end
xpathの検査がかっこわるい…。良い方法があったらコメントください。
Rakefileは以下の内容にしました。
require 'cucumber/rake/task'
desc 'Run all tests'
task :test do
require 'rake/testtask'
Rake::TestTask.new do |t|
t.test_files = FileList[File.join('test', '**', '*_test.rb')]
end
end
desc "Run all features in features directory"
Cucumber::Rake::Task.new(:features)
あとは
- Sassを完成させる
- rack cacheの導入
- モデル作成したときのためのFixtureの準備
- configディレクトリを作成して設定ファイルをそこに置くか
- publicディレクトリの作成
- ほかいろいろ…
をやったりやらなかったり。
そしてKomodo IDEでプロジェクトテンプレートを作成。