README.jp.rdoc in sinatra-1.0 vs README.jp.rdoc in sinatra-1.1.a

- old
+ new

@@ -1,20 +1,20 @@ = Sinatra +<i>注) 本文書は英語から翻訳したものであり、その内容が最新でない場合もあります。最新の情報はオリジナルの英語版を参照して下さい。</i> SinatraはRubyで下記のような最小労力で手早くウェブアプリケーションを作成するためのDSLです。 # myapp.rb - require 'rubygems' require 'sinatra' get '/' do 'Hello world!' end gemをインストールして動かしてみる。 - sudo gem install sinatra - ruby myapp.rb + gem install sinatra + ruby -rubygems myapp.rb http://localhost:4567 を見る。 == ルート @@ -77,20 +77,75 @@ get %r{/hello/([\w]+)} do |c| "Hello, #{c}!" end + +=== 条件 + ルートにはユーザエージェントのようなさまざまな条件を含めることができます。 get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do "You're using Songbird version #{params[:agent][0]}" end get '/foo' do # Matches non-songbird browsers end +ほかに+host_name+と+provides+条件が利用可能です: + + get '/', :host_name => /^admin\./ do + "Admin Area, Access denied!" + end + + get '/', :provides => 'html' do + haml :index + end + + get '/', :provides => ['rss', 'atom', 'xml'] do + builder :feed + end + +独自の条件を定義することも簡単にできます: + + set(:probability) { |value| condition { rand <= value } } + + get '/win_a_car', :probability => 0.1 do + "You won!" + end + + get '/win_a_car' do + "Sorry, you lost." + end + + +=== 戻り値 + +ルートブロックの戻り値は、HTTPクライアントまたはRackスタックでの次のミドルウェアに渡されるレスポンスボディを決定します。 + +これは大抵の場合、上の例のように文字列ですが、それ以外の値も使用することができます。 + +Rackレスポンス、Rackボディオブジェクト、HTTPステータスコードのいずれかとして +妥当なオブジェクトであればどのようなオブジェクトでも返すことができます: + +* 3要素の配列: <tt>[ステータス(Fixnum), ヘッダ(Hash), レスポンスボディ(#eachに応答する)]</tt> +* 2要素の配列: <tt>[ステータス(Fixnum), レスポンスボディ(#eachに応答する)]</tt> +* <tt>#each</tt>に応答し、与えられたブロックに文字列を渡すオブジェクト +* ステータスコードを表現するFixnum + +そのように、例えばストリーミングの例を簡単に実装することができます: + + class Stream + def each + 100.times { |i| yield "#{i}\n" } + end + end + + get('/') { Stream.new } + + == 静的ファイル 静的ファイルは<tt>./public</tt>ディレクトリから配信されます。 <tt>:public</tt>オプションを指定することで別の場所を指定することができます。 @@ -121,11 +176,11 @@ haml :index end <tt>./views/index.haml</tt>を表示します。 -{Haml's options}[http://haml.hamptoncatlin.com/docs/rdoc/classes/Haml.html] +{Haml's options}[http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#options] はSinatraの設定でグローバルに設定することができます。 {Options and Configurations}[http://www.sinatrarb.com/configuration.html], を参照してそれぞれ設定を上書きして下さい。 set :haml, {:format => :html5 } # デフォルトのフォーマットは:xhtml @@ -144,51 +199,241 @@ erb :index end <tt>./views/index.erb</tt>を表示します。 +=== Erubis + +erubisテンプレートを表示するには、erubisライブラリが必要です: + + ## erubisを読み込みます + require 'erubis' + + get '/' do + erubis :index + end + +<tt>./views/index.erubis</tt>を表示します。 + === Builder テンプレート builderを使うにはbuilderライブラリが必要です: ## builderを読み込みます require 'builder' get '/' do - content_type 'application/xml', :charset => 'utf-8' builder :index end <tt>./views/index.builder</tt>を表示します。 +=== 鋸 テンプレート + +鋸を使うには鋸ライブラリが必要です: + + ## 鋸を読み込みます + require 'nokogiri' + + get '/' do + nokogiri :index + end + +<tt>./views/index.nokogiri</tt>を表示します。 + === Sass テンプレート Sassテンプレートを使うにはsassライブラリが必要です: ## hamlかsassを読み込みます require 'sass' get '/stylesheet.css' do - content_type 'text/css', :charset => 'utf-8' sass :stylesheet end <tt>./views/stylesheet.sass</tt>を表示します。 -{Sass' options}[http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html] +{Sass' options}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options] はSinatraの設定でグローバルに設定することができます。 see {Options and Configurations}[http://www.sinatrarb.com/configuration.html], を参照してそれぞれ設定を上書きして下さい。 set :sass, {:style => :compact } # デフォルトのSass styleは :nested get '/stylesheet.css' do - content_type 'text/css', :charset => 'utf-8' sass :stylesheet, :sass_options => {:style => :expanded } # 上書き end +=== Scss テンプレート +Scssテンプレートを使うにはsassライブラリが必要です: + + ## hamlかsassを読み込みます + require 'sass' + + get '/stylesheet.css' do + scss :stylesheet + end + +<tt>./views/stylesheet.scss</tt>を表示します。 + +{Sass' options}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options] +はSinatraの設定でグローバルに設定することができます。 +see {Options and Configurations}[http://www.sinatrarb.com/configuration.html], +を参照してそれぞれ設定を上書きして下さい。 + + set :scss, :style => :compact # デフォルトのScss styleは:nested + + get '/stylesheet.css' do + scss :stylesheet, :style => :expanded # 上書き + end + +=== Less テンプレート + +Lessテンプレートを使うにはlessライブラリが必要です: + + ## lessを読み込みます + require 'less' + + get '/stylesheet.css' do + less :stylesheet + end + +<tt>./views/stylesheet.less</tt>を表示します。 + +=== Liquid テンプレート + +Liquidテンプレートを使うにはliquidライブラリが必要です: + + ## liquidを読み込みます + require 'liquid' + + get '/' do + liquid :index + end + +<tt>./views/index.liquid</tt>を表示します。 + +LiquidテンプレートからRubyのメソッド(+yield+を除く)を呼び出すことができないため、 +ほぼ全ての場合にlocalsを指定する必要があるでしょう: + + liquid :index, :locals => { :key => 'value' } + +=== Markdown テンプレート + +Markdownテンプレートを使うにはrdiscountライブラリが必要です: + + ## rdiscountを読み込みます + require "rdiscount" + + get '/' do + markdown :index + end + +<tt>./views/index.markdown</tt>を表示します。(+md+と+mkd+も妥当な拡張子です) + +markdownからメソッドを呼び出すことも、localsに変数を渡すこともできません。 +それゆえ、他のレンダリングエンジンとの組み合わせで使うのが普通です: + + erb :overview, :locals => { :text => markdown(:introduction) } + +他のテンプレートからmarkdownメソッドを呼び出してもよいことに注意してください: + + %h1 Hello From Haml! + %p= markdown(:greetings) + +=== Textile テンプレート + +Textileテンプレートを使うにはRedClothライブラリが必要です: + + ## redclothを読み込みます + require "redcloth" + + get '/' do + textile :index + end + +<tt>./views/index.textile</tt>を表示します。 + +textileからメソッドを呼び出すことも、localsに変数を渡すこともできません。 +それゆえ、他のレンダリングエンジンとの組み合わせで使うのが普通です: + + erb :overview, :locals => { :text => textile(:introduction) } + +他のテンプレートからtextileメソッドを呼び出してもよいことに注意してください: + + %h1 Hello From Haml! + %p= textile(:greetings) + +=== RDoc テンプレート + +RDocテンプレートを使うにはRDocライブラリが必要です: + + ## rdocを読み込みます + require "rdoc" + + get '/' do + rdoc :index + end + +<tt>./views/index.rdoc</tt>を表示します。 + +rdocからメソッドを呼び出すことも、localsに変数を渡すこともできません。 +それゆえ、他のレンダリングエンジンとの組み合わせで使うのが普通です: + + erb :overview, :locals => { :text => rdoc(:introduction) } + +他のテンプレートからrdocメソッドを呼び出してもよいことに注意してください: + + %h1 Hello From Haml! + %p= rdoc(:greetings) + +=== Radius テンプレート + +Radiusテンプレートを使うにはradiusライブラリが必要です: + + ## radiusを読み込みます + require 'radius' + + get '/' do + radius :index + end + +<tt>./views/index.radius</tt>を表示します。 + +RadiusテンプレートからRubyのメソッド(+yield+を除く)を呼び出すことができないため、 +ほぼ全ての場合にlocalsを指定する必要があるでしょう: + + radius :index, :locals => { :key => 'value' } + +=== Markaby テンプレート + +Markabyテンプレートを使うにはmarkabyライブラリが必要です: + + ## markabyを読み込みます + require 'markaby' + + get '/' do + markaby :index + end + +<tt>./views/index.mab</tt>を表示します。 + +=== CoffeeScript テンプレート + +CoffeeScriptテンプレートを表示するにはcoffee-scriptライブラリと`coffee`バイナリが必要です: + + ## coffee-scriptを読み込みます + require 'coffee-script' + + get '/application.js' do + coffee :application + end + +<tt>./views/application.coffee</tt>を表示します。 + === インラインテンプレート get '/' do haml '%div.title Hello World' end @@ -233,11 +478,11 @@ @@ index %div.title Hello world!!!!! 注意: sinatraをrequireするファイル内で定義されたファイル内テンプレートは自動的に読み込まれます。 -他のファイルで定義されているテンプレートを使うには <tt>use_in_file_templates!</tt>メソッドで指定します。 +他のファイルで定義されているテンプレートを使うには <tt>enable :inline_templates</tt>を明示的に呼んでください。 === 名前付きテンプレート テンプレートはトップレベルの<tt>template</tt>メソッドで定義することができます。 @@ -252,11 +497,11 @@ get '/' do haml :index end 「layout」というテンプレートが存在する場合、そのテンプレートファイルは他のテンプレートが -表示される度に使用されます。<tt>:layout => false</tt>.することでlayoutsを無効にできます。 +表示される度に使用されます。<tt>:layout => false</tt>することでlayoutsを無効にできます。 get '/' do haml :index, :layout => !request.xhr? end @@ -289,24 +534,52 @@ get '/foo/*' do @note #=> 'Hi!' params[:splat] #=> 'bar/baz' end +afterフィルタは同じコンテキストにあるリクエストの後に評価され、 +同じくリクエストとレスポンスを変更することができます。 +beforeフィルタとルートで設定されたインスタンス変数は、 +afterフィルタからアクセスすることができます: + + after do + puts response.status + end + +フィルタにはオプションとしてパターンを渡すことができ、 +この場合はリクエストのパスがパターンにマッチした場合のみフィルタが評価されます: + + before '/protected/*' do + authenticate! + end + + after '/create/:slug' do |slug| + session[:last_slug] = slug + end + == 強制終了 ルートかbeforeフィルタ内で直ちに実行を終了する方法: halt +ステータスを指定することができます: + + halt 410 + body部を指定することもできます ... halt 'ここにbodyを書く' ステータスとbody部を指定する ... halt 401, '立ち去れ!' +ヘッダを指定: + + halt 402, {'Content-Type' => 'text/plain'}, 'リベンジ' + == パッシング(Passing) ルートは<tt>pass</tt>を使って次のルートに飛ばすことができます: get '/guess/:who' do @@ -319,25 +592,72 @@ end ルートブロックからすぐに抜け出し、次にマッチするルートを実行します。 マッチするルートが見当たらない場合は404が返されます。 +== リクエストオブジェクトへのアクセス + +受信するリクエストオブジェクトは、`request`メソッドを通じてリクエストレベル(フィルタ、ルート、エラーハンドラ)からアクセスすることができます: + + # アプリケーションが http://example.com/example で動作している場合 + get '/foo' do + request.body # クライアントによって送信されたリクエストボディ(下記参照) + request.scheme # "http" + request.script_name # "/example" + request.path_info # "/foo" + request.port # 80 + request.request_method # "GET" + request.query_string # "" + request.content_length # request.bodyの長さ + request.media_type # request.bodyのメディアタイプ + request.host # "example.com" + request.get? # true (他の動詞についても同様のメソッドあり) + request.form_data? # false + request["SOME_HEADER"] # SOME_HEADERヘッダの値 + request.referer # クライアントのリファラまたは'/' + request.user_agent # ユーザエージェント (:agent 条件によって使用される) + request.cookies # ブラウザクッキーのハッシュ + request.xhr? # Ajaxリクエストかどうか + request.url # "http://example.com/example/foo" + request.path # "/example/foo" + request.ip # クライアントのIPアドレス + request.secure? # false + request.env # Rackによって渡された生のenvハッシュ + end + +<tt>script_name</tt>や<tt>path_info</tt>などのオプションは次のように利用することもできます: + + before { request.path_info = "/" } + + get "/" do + "全てのリクエストはここに来る" + end + +<tt>request.body</tt>はIOまたはStringIOのオブジェクトです: + + post "/api" do + request.body.rewind # 既に読まれているときのため + data = JSON.parse request.body.read + "Hello #{data['name']}!" + end + + == 設定 どの環境でも起動時に1回だけ実行されます。 configure do ... end -環境変数<tt>:production</tt>(RACK_ENV環境変数) がセットされている時だけ実行する方法: +環境(RACK_ENV環境変数)が<tt>:production</tt>に設定されている時だけ実行する方法: configure :production do ... end -環境変数<tt>:production</tt> か<tt>:test</tt>の場合に設定する方法: +環境が<tt>:production</tt>か<tt>:test</tt>の場合に設定する方法: configure :production, :test do ... end @@ -356,11 +676,11 @@ end === エラー +error+ ハンドラーはルートブロックかbeforeフィルタ内で例外が発生した時はいつでも発動します。 -block or before filter. 例外オブジェクトはRack変数<tt>sinatra.error</tt>から取得されます。 +例外オブジェクトはRack変数<tt>sinatra.error</tt>から取得できます。 error do 'エラーが発生しました。 - ' + env['sinatra.error'].name end @@ -378,20 +698,41 @@ そうするとこうなります: エラーメッセージ... 何かがまずかったようです +あるいは、ステータスコードに対応するエラーハンドラを設定することもできます: + + error 403 do + 'Access forbidden' + end + + get '/secret' do + 403 + end + +範囲指定もできます: + + error 400..510 do + 'Boom' + end + + 開発環境として実行している場合、Sinatraは特別な<tt>not_found</tt>と<tt>error</tt>ハンドラーを インストールしています。 == MIMEタイプ <tt>send_file</tt>か静的ファイルを使う時、Sinatraが理解でいないMIMEタイプがある場合があります。 その時は +mime_type+ を使ってファイル拡張子毎に登録して下さい。 mime_type :foo, 'text/foo' +これはcontent_typeヘルパで利用することができます: + + content_type :foo + == Rackミドルウェア SinatraはRack[http://rack.rubyforge.org/]というRubyのWEBフレームワーク用の 最小限の標準インターフェース 上で動作しています。Rack中でもアプリケーションデベロッパー 向けに一番興味深い機能はミドルウェア(サーバとアプリケーション間に介在し、モニタリング、HTTPリクエストとレスポンス @@ -494,20 +835,137 @@ :get、 :put、 :post、:delete、 :before、:error、:not_found、 :configure、:set messagesのこれら 全てを受け取ります。 詳細を閲覧されたい方はこちら(英語): {Sinatra::Delegator mixin}[http://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1064] {included into the main namespace}[http://github.com/sinatra/sinatra/blob/master/lib/sinatra/main.rb#L25]. +=== Sinatraをミドルウェアとして利用する + +Sinatraは他のRackミドルウェアを利用することができるだけでなく、 +全てのSinatraアプリケーションは、それ自体ミドルウェアとして別のRackエンドポイントの前に追加することが可能です。 + +このエンドポイントには、別のSinatraアプリケーションまたは他のRackベースのアプリケーション(Rails/Ramaze/Camping/...)が用いられるでしょう。 + + require 'sinatra/base' + + class LoginScreen < Sinatra::Base + enable :session + + get('/login') { haml :login } + + post('/login') do + if params[:name] = 'admin' and params[:password] = 'admin' + session['user_name'] = params[:name] + else + redirect '/login' + end + end + end + + class MyApp < Sinatra::Base + # middleware will run before filters + use LoginScreen + + before do + unless session['user_name'] + halt "Access denied, please <a href='/login'>login</a>." + end + end + + get('/') { "Hello #{session['user_name']}." } + end + +== スコープとバインディング + +現在のスコープはどのメソッドや変数が利用可能かを決定します。 + +=== アプリケーション/クラスのスコープ + +全てのSinatraアプリケーションはSinatra::Baseのサブクラスに相当します。 +もしトップレベルDSLを利用しているならば(<tt>require 'sinatra'</tt>)このクラスはSinatra::Applicationであり、 +そうでなければ、あなたが明示的に作成したサブクラスです。 +クラスレベルでは`get`や`before`のようなメソッドを持っています。 +しかし`request`オブジェクトや`session`には、全てのリクエストのために1つのアプリケーションクラスが存在するためアクセスできません。 + +`set`によって作られたオプションはクラスレベルのメソッドです: + + class MyApp < Sinatra::Base + # Hey, I'm in the application scope! + set :foo, 42 + foo # => 42 + + get '/foo' do + # Hey, I'm no longer in the application scope! + end + end + +次の場所ではアプリケーションスコープバインディングを持ちます: + +* アプリケーションのクラス本体 +* 拡張によって定義されたメソッド +* `helpers`に渡されたブロック +* `set`の値として使われるProcまたはブロック + +このスコープオブジェクト(クラス)は次のように利用できます: + +* configureブロックに渡されたオブジェクト経由(<tt>configure { |c| ... }</tt>) +* リクエストスコープの中での`settings` + +=== リクエスト/インスタンスのスコープ + +やってくるリクエストごとに、あなたのアプリケーションクラスの新しいインスタンスが作成され、全てのハンドラブロックがそのスコープで実行されます。 +このスコープの内側からは`request`や`session`オブジェクトにアクセスすることができ、`erb`や`haml`のような表示メソッドを呼び出すことができます。 +リクエストスコープの内側からは、`settings`ヘルパによってアプリケーションスコープにアクセスすることができます。 + + class MyApp << Sinatra::Base + # Hey, I'm in the application scope! + get '/define_route/:name' do + # Request scope for '/define_route/:name' + @value = 42 + + settings.get("/#{params[:name]}") do + # Request scope for "/#{params[:name]}" + @value # => nil (not the same request) + end + + "Route defined!" + end + end + +次の場所ではリクエストスコープバインディングを持ちます: + +* get/head/post/put/delete ブロック +* before/after フィルタ +* helper メソッド +* テンプレート/ビュー + +=== デリゲートスコープ + +デリゲートスコープは、単にクラススコープにメソッドを転送します。 +しかしながら、クラスのバインディングを持っていないため、クラススコープと全く同じふるまいをするわけではありません: +委譲すると明示的に示されたメソッドのみが利用可能であり、またクラススコープと変数/状態を共有することはできません(注: 異なった`self`を持っています)。 +<tt>Sinatra::Delegator.delegate :method_name</tt>を呼び出すことによってデリゲートするメソッドを明示的に追加することができます。 + +次の場所ではデリゲートスコープを持ちます: + +* もし<tt>require "sinatra"</tt>しているならば、トップレベルバインディング +* `Sinatra::Delegator` mixinでextendされたオブジェクト + +コードをご覧ください: ここでは +{Sinatra::Delegator mixin}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/base.rb#L1128] +は{main 名前空間にincludeされています}[http://github.com/sinatra/sinatra/blob/ceac46f0bc129a6e994a06100aa854f606fe5992/lib/sinatra/main.rb#L28]. + == コマンドライン Sinatraアプリケーションは直接実行できます。 - ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-s HANDLER] + ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-o HOST] [-s HANDLER] オプション: -h # ヘルプ -p # ポート指定(デフォルトは4567) + -o # ホスト指定(デフォルトは0.0.0.0) -e # 環境を指定 (デフォルトはdevelopment) -s # rackserver/handlerを指定 (デフォルトはthin) -x # mutex lockを付ける (デフォルトはoff) == 最新開発版について @@ -544,9 +1002,9 @@ * {プロジェクトサイト}[http://sinatra.github.com/] - ドキュメント、 ニュース、他のリソースへのリンクがあります。 * {プロジェクトに参加(貢献)する}[http://sinatra.github.com/contributing.html] - バグレポート パッチの送信、サポートなど -* {Lighthouse}[http://sinatra.lighthouseapp.com] - チケット管理とリリース計画 +* {Issue tracker}[http://github.com/sinatra/sinatra/issues] - チケット管理とリリース計画 * {Twitter}[http://twitter.com/sinatra] * {メーリングリスト}[http://groups.google.com/group/sinatrarb] * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] on http://freenode.net