sinatra は ruby の web アプリケーションフレームワーク。rails よりもシンプルで柔軟なプログラムが可能となる。つまり、しかれた rails に乗り切れない人のためのフレームワーク。
本稿では以下について書く。
- sinatra インストール
- hello world アプリケーション
- ルーティング
- フィルタ
- ヘルパー
- テンプレートの呼び出し
前準備: インストール
ruby 2.0 を rbenv でインストールする。
以下、作業は /Users/momota/dev/sinatra/
で行う。
1
2
3
4
5
6
7
| $ rbenv install 2.0.0-p247
$ rbenv local 2.0.0-p247
$ rbenv rehash
$ rbenv version
2.0.0-p247 (set by /Users/momota/dev/sinatra/.ruby-version)
$ ruby -v
ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.4.0]
|
bundler で sinatra と関連 gem をインストールする。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| $ gem install bundler
$ bundle -v
Bundler version 1.3.5
$ bundle init
Writing new Gemfile to /Users/momota/dev/sinatra/Gemfile
$ cat << EOF >> ./Gemfile
heredoc> gem "activerecord", "3.2.13"
heredoc> gem "sqlite3", "1.3.7"
heredoc> gem "sinatra", "1.4.3"
heredoc> gem "sinatra-contrib", "1.4.0"
heredoc> EOF
$ bundle install --path vendor/bundle
Fetching gem metadata from https://rubygems.org/...........
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Installing i18n (0.6.1)
Installing multi_json (1.8.0)
Installing activesupport (3.2.13)
Installing builder (3.0.4)
Installing activemodel (3.2.13)
Installing arel (3.0.2)
Installing tzinfo (0.3.37)
Installing activerecord (3.2.13)
Installing backports (3.3.4)
Installing eventmachine (1.0.3)
Installing rack (1.5.2)
Installing rack-protection (1.5.0)
Installing rack-test (0.6.2)
Installing tilt (1.4.1)
Installing sinatra (1.4.3)
Installing sinatra-contrib (1.4.0)
Installing sqlite3 (1.3.7)
Using bundler (1.3.5)
Your bundle is complete!
It was installed into ./vendor/bundle
|
hello world を返す sinatra アプリケーションを書く
サイトのルートへアクセスが遇ったときに “hello world” を返す main.rb
を作成する。適当なエディタで以下を書いて保存する。
1
2
3
4
5
| require 'sinatra'
get '/' do
"hello world"
end
|
アプリケーションを実行する。
1
| $ bundle exec ruby main.rb
|
動作確認をする。
1
2
| $ curl http://localhost:4567/
hello world%
|
ちゃんと返ってきている。簡単。
ここでは、 curl
で確認したが、もちろん web ブラウザで http://localhost:4567/ へアクセスして確認してもOK。
アプリケーションの終了は Ctrl-c
でOK。
ルーティング: 複数のリクエストをさばく
sinatra では、以下のように HTTP メソッド (GET, POST, …)とURLがペアでルーティングされる。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| get '/' do
# show something
end
post '/' do
# create something
end
put '/' do
# replace something
end
patch '/' do
# modify something
end
delete '/' do
# annihilate something
end
options '/' do
# appease something
end
link '/' do
# affiliate something
end
unlink '/' do
# separate something
end
|
先ほど書いた main.rb
を修正していろいろな HTTP GET リクエストに対応する。
ここでは http://localhost:4567/about にアクセスが有った場合、 “about this site” 文字列を返すように追記する。
以下は、git diff
の結果を示す。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| diff --git a/main.rb b/main.rb
index 713861d..9423680 100644
--- a/main.rb
+++ b/main.rb
@@ -1,5 +1,11 @@
require 'sinatra'
+require 'sinatra/reloader'
get '/' do
"hello world"
end
+
+get '/about' do
+ "about this site"
+end
+
|
通常、スクリプトの修正をアプリケーションへ反映するためには、アプリケーションの再起動が必要となる。require 'sinatra/reloader'
により、その必要がなくなる。
URL からのパラメータを扱う
以下のメソッドを書くことにより、http://localhost:4567/hello/SOME_NAME へアクセスすると SOME_NAME 部分を扱うことができる。
1
2
3
| get '/hello/:name' do
"hello #{params[:name]}"
end
|
これは以下のようにも書ける。
1
2
3
| get '/hello/:name' do |n|
"hello #{n}"
end
|
複数のパラメータを扱うときは以下のように書く。
http://localhost:4567/hello/FAMILY_NAME/LAST_NAME へアクセスすると、FAMILY_NAME と LAST_NAME を扱える。
1
2
3
| get '/hello/:fname/?:lname?' do |f, l|
"hello #{f} #{l}"
end
|
パラメータは、ワイルドカードや正規表現で扱うことができる。
1
2
3
| get '/from/*/to/*' do |f, t|
"from #{f} to #{t}"
end
|
結果は以下のとおり。
1
2
| $ curl http://localhost:4567/from/fukuoka/to/tokyo
from fukuoka to tokyo%
|
正規表現で扱う場合は、以下。ここでは、/users/
以下がすべて数字であるアクセスの場合にマッチングさせている。
1
2
3
| get %r{/users/([0-9]+)} do |i|
"user id = #{i}"
end
|
結果は以下のとおり。
1
2
| $ curl http://localhost:4567/users/12345
user id = 12345%
|
before/after filter
sinatra のフィルタは、ルーティングされたコンテキストを実行する前後(before / after)で、リクエストとレスポンスを変更することができる。
1
2
3
4
5
6
7
8
9
10
11
| before do
@before_value = "foo"
end
get '/' do
"before_value has been set to #{@before_value}"
end
after do
puts "After filter called to perform some task."
end
|
以下のように記述することで、フィルタは特定パスのリクエストにのみ評価される。
1
2
3
4
| before '/path/you/want/*'
# execute only before the '/path/you/want/*' route
authenticate
end
|
helper
ヘルパーメソッドを定義して、ルートハンドラーやテンプレートとして使える。
1
2
3
4
5
6
7
8
9
10
| helpers do
# 共通関数を書ける
def say_hello( name )
"hello, #{name}"
end
end
get '/:name' do |n|
say_hello( n )
end
|
上記は、モジュールとしても記述できる。
1
2
3
4
5
6
7
8
9
| module Hello
def say_hello( name ) "hello, #{name}" end
end
module Goodbye
def say_goodbye( name ) "goodbye, #{name}" end
end
helpers Hello, Goodbye
|
テンプレートエンジンを扱う
sinatra では様々なテンプレートエンジンを扱うことができる。
例えば、haml, erb, sass, markdown, slim, coffescript など。詳細は http://www.sinatrarb.com/intro.html#Available%20Template%20Languages このあたりを参照。
ここでは、erb の例を示す。
views/index.erb
を作成する。スクリプトからは以下のように呼び出せばOK。
1
2
3
| get '/' do
erb :index
end
|
テンプレートエンジンにパラメータを渡す
インスタンス変数に渡して、テンプレート側からコールする。
1
2
3
4
5
| get '/:name' do |n|
@name = n
@title = 'sinatra sample'
erb :index
end
|
views/index.erb
は以下。
1
2
3
4
5
6
7
8
9
10
| <!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="urf-8">
<title><%= @title %></title>
</head>
<body>
<h1>hello <%= @name %></h1>
</body>
</html>
|
実行結果は以下のとおり。
1
2
3
4
5
6
7
8
9
10
11
| $ curl http://localhost:4567/taro
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="urf-8">
<title>sinatra sample</title>
</head>
<body>
<h1>hello taro</h1>
</body>
</html>
|
layout テンプレート
テンプレートが複数存在するときに、ヘッダーやフッターなど、共通部分が出てくる。
そのような共通部分を views/layout.erb
切り出すことができる。(erb以外のときはファイル拡張子を変えればよい。)
views/layout.erb
は優先的に読み込まれる。
共通部分を layout.erb
に記述し、個別記述部分を yield
で呼び出す。以下に layout.erb
の例を示す。
1
2
3
4
5
6
7
8
9
| <!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="urf-8">
<title>test</title>
</head>
<body>
<%= yield %>
</body>
|
この時、以下のような index.erb
テンプレートと
1
2
| <h1>test</h1>
<h2><%= @name%></h2>
|
以下のルーティングにより
1
2
3
4
5
6
7
| require 'sinatra'
require 'sinatra/reloader'
get '/:name' do |n|
@name = n
erb :index
end
|
以下の様な結果になる。
1
2
3
4
5
6
7
8
9
10
11
12
| $ curl http://localhost:4567/hanako
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="urf-8">
<title>test</title>
</head>
<body>
<h1>test</h1>
<h2>hanako</h2>
</body>
|