« ImageMagickのテキスト描画を画像にしてコストダウン | メイン | Software Design 6月号に「diffの動作原理を知る」の記事を執筆しました »

Sinatra気に入った
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

先日、まちつく!正式リリースになりました。よろしければ是非携帯でアクセスして遊んでみてください。

おはようございます。内田です。

今までRailsを使うほどでも無いアプリはオレオレフレームワークで作ってたのですが、最近巷で流行ってるsinatraのコードを読んでみたら必要十分な機能があり、センスも良く、とても気に入りました。

今回は公式ドキュメントの流れで、使いそうな機能をまとめてみました

一番簡単な例

sudo gem install sinatra
# app.rb
require 'rubygems'
require 'sinatra'

get '/' do
  'Hello, world'
end
ruby app.rb
curl http://localhost:4567/

Routes

HTTPメソッドにURLとブロックを渡します
get '/' do
end
post '/' do
end
put '/' do
end
delete '/' do
end

パラメータを含めたURLも可能

get '/hello/:name' do
  "Hello #{params[:name]}"
end

上記パラメータはブロック引数でも取れる

get '/hello/:name' do |n|
  "Hello #{n}"
end

ワイルドカードもつかえます

get '/say/*/to/*' do
  # /say/hello/to/worldにアクセス
  params["splat"] # => ["hello", "world]
end

?つきのパラメータやPOST等のパラメータはparams[:xxx]で取得できるよ

アプリケーションファイルは複数に分けることが可能。
読み込みにはrequireを使わずにloadを使うとdevelopmentモードの時に便利

require 'rubygems'
require 'sinatra'
get '/' do
  "Hello world"
end
load 'more_routes.rb'
# more_routes.rb
get '/foo' do
  "Foo"
end

Handlers

Redirect

redirect '/'
redirect 'http://www.google.co.jp'
redirect '/', 303
redirect '/', 307

Session
クッキーベースのセッション
有効にするにはTOPレベルか、configureブロックに書く

enable :sessions
get '/' do
  session["count"] ||= 0
  session["count"] += 1
  "count: #{session['count']}"
end

Status
通常では200番のステータスコードになるがstatusメソッドをつかうと変更できる

get '/' do
  status 404
  "Not found"
end

Filters

イベントの前に実行される
before do
end
before do
  new_params = {}
  params.each_pair do |full_key, value|
    this_param = new_params
    split_keys = full_key.split(/\]\[|\]|\[/)
    split_keys.each_index do |index|
      break if split_keys.length == index + 1
      this_param[split_keys[index]] ||= {}
      this_param = this_param[split_keys[index]]
   end
   this_param[split_keys.last] = value
  end
  request.params.replace new_params
end
<form>
  <input ... name="post[title]" />
  <input ... name="post[body]" />
  <input ... name="post[author]" />
</form>
{"post"=>{ "title"=>"", "body"=>"", "author"=>"" }}

views

Template Languages
viewファイルはroot/viewsに置きましょう
Haml,Sass,Erb,Builderがつかえる
# app.rb
get '/' do
  erb :index     # views/index.erb
  sass :styles   # views/styles.sass
  haml :index    # views/index.haml
  builder :index # views/index.builder
end

builderはブロックを使ってRSSを出力できたりする
サンプルプログラムが公式にあります。

Layouts
root/views/layout.{erb|haml|builder}

<html>
<body>
<%= yield %>
</body>
</html>

使いたくないときは

get '/' do
  erb :index, layout => false
end

アプリケーションと同じファイルにviewが書ける
が、個人的には使わない。公式参照

Models

sinatraはmodelを提供してないので、好きなのを使うとよろし
Sequelを使ってみる。
# app.rb
require 'rubygems'
require 'sinatra'
require 'sequel'
Sequel::Model.plugin(:schema)
sequel.connect('sqlite://test.db')
class Items < Sequel::Model
  unless table_exista?
    set_schema do
      primary_key :id
      string :name
      timestamp :created_at
    end
    create_table
  end
end
get '/' do
  @items = Items.all
  erb :index
end
# views/index.erb
<% for item in @items %>
  <div><%= item.name %></div>
<% end %>

DatamapperやActiveRecordを使いたい場合は公式参照

API的なJSONでも出力してみる

require 'json'
get '/api/items.json' do
  content_type :json
  JSON.unparse(Items.all.map{|e|e.values})
end

Helpers

helpersブロックでメソッドを定義するとイベント内やテンプレートで使えます
helpers do
  def bar(name)
    "#{name}bar"
  end
end
get '/:name' do
  bar(params[:name])
end

Rails的なpartialを定義

helpers do
  def partial(page, options={})
    erb page, options.merge!(:layout => false)
  end
end

escape_html等のaliasを定義しとくと便利

helpers do
  include Rack::Urils
  alias_method :h, :escape_html
  alias_method :u, :escape
end

Rack Middleware

useメソッドで指定しなさい
use Rack::Lint
get '/' do
  "hello"
end

Sinatra自体がいくつか読み込んでるので、重複するかもしれません。
Loggerとか。1リクエストでログが複数件でてビックリしました。

Error Handling

not_found
定義されてないURLにアクセスがあった場合に動作
not_found do
  "Not found"
end

しかし、デフォルトのメッセージがセンス良すぎなので、production時にのみ定義したい。

error
例外が投げられたら動作

error do
  'error - ' + request.env['sinatra.error'].name
end
error MyCustomError do
  'So what happened was...' + request.env['sinatra.error'].message
end

これもセンス良すぎなので次の方法でproduction時のみ動作にしましょう
configureメソッドをつかいます

configure :production do
  not_found do
    "Not found"
  end
  error do
    "Error"
  end
end

Configuration

configureブロックの中で変数を使う場合はsetをつかいましょう
configure :development do
  set :dbname, 'devdb'
end
configure :production do
  set :dbname, 'productiondb'
end
get '/whatdb' do
  'We are using the database named ' + options.dbname
end

Deploy

個人的にはpassengerが良い
アプリケーションのrootディレクトリにtmp,publicディレクトリを作りconfig.ruを書く
#config.ru
require 'app'
run Sinatra::Application

最新バージョンのrack(1.0)やpassennger(2.0.3)を使ったときのバグが公式に書いてありますので参照下さい。

参考

http://www.sinatrarb.com/
http://www.sinatrarb.com/book.html
http://www.sinatrarb.com/faq.html
http://www.sinatrarb.com/testing.html
http://www.sinatrarb.com/extensions.html

おしまい

トラックバック

このエントリーのトラックバックURL:
http://www.unoh.net/mt32/mt-tb.cgi/1628

コメント

typoを見つけたので。

unless table_exista?
 →unless table_exists?

include Rack::Urils
 →include Rack::Utils

コメントを投稿


画像の中に見える文字を入力してください。