unoh.github.com

Sinatra気に入った

2009-05-15 09:12:16 +0000

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

おはようございます。内田です。 今まで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
{"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}


<%= yield %>


使いたくないときは
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 %>
  
<%= item.name %>
<% 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 おしまい