Sinatra は、最小限の労力で Ruby で Web アプリケーションを迅速に作成するための DSL です。
# myapp.rb
require 'sinatra'
get '/' do
'Hello world!'
end
必要な gem をインストールします。
gem install sinatra rackup puma
そして、次のように実行します。
ruby myapp.rb
表示場所: http://localhost:4567
変更したコードは、サーバーを再起動するまで有効になりません。コードを変更したり、再実行やラックアンリローダーなどのコード リローダーを使用したりするたびに、サーバーを再起動してください。
gem install puma
も実行することをお勧めします。利用可能な場合は Sinatra がそれを取得します。
yield
およびネストされたレイアウトを備えたテンプレートSinatra では、ルートは URL マッチング パターンと組み合わせられた HTTP メソッドです。各ルートはブロックに関連付けられています。
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
ルートは定義された順序で照合されます。リクエストに一致する最初のルートが呼び出されます。
末尾にスラッシュが付いているルートは、スラッシュがないルートとは異なります。
get '/foo' do
# Does not match "GET /foo/"
end
ルート パターンには、 params
ハッシュ経由でアクセスできる名前付きパラメータが含まれる場合があります。
get '/hello/:name' do
# matches "GET /hello/foo" and "GET /hello/bar"
# params['name'] is 'foo' or 'bar'
"Hello #{ params [ 'name' ] } !"
end
ブロック パラメーターを介して名前付きパラメーターにアクセスすることもできます。
get '/hello/:name' do | n |
# matches "GET /hello/foo" and "GET /hello/bar"
# params['name'] is 'foo' or 'bar'
# n stores params['name']
"Hello #{ n } !"
end
ルート パターンには、 params['splat']
配列経由でアクセスできるスプラット (またはワイルドカード) パラメーターも含まれる場合があります。
get '/say/*/to/*' do
# matches /say/hello/to/world
params [ 'splat' ] # => ["hello", "world"]
end
get '/download/*.*' do
# matches /download/path/to/file.xml
params [ 'splat' ] # => ["path/to/file", "xml"]
end
またはブロックパラメータを使用して:
get '/download/*.*' do | path , ext |
[ path , ext ] # => ["path/to/file", "xml"]
end
正規表現を使用したルート マッチング:
get / / hello / ([ w ]+)/ do
"Hello, #{ params [ 'captures' ] . first } !"
end
またはブロックパラメータを使用して:
get %r{/hello/([ w ]+)} do | c |
# Matches "GET /meta/hello/world", "GET /hello/world/1234" etc.
"Hello, #{ c } !"
end
ルート パターンにはオプションのパラメータが含まれる場合があります。
get '/posts/:format?' do
# matches "GET /posts/" and any extension "GET /posts/json", "GET /posts/xml" etc
end
ルートではクエリ パラメータを利用することもできます。
get '/posts' do
# matches "GET /posts?title=foo&author=bar"
title = params [ 'title' ]
author = params [ 'author' ]
# uses title and author variables; query is optional to the /posts route
end
ちなみに、パス トラバーサル攻撃保護 (以下を参照) を無効にしない限り、ルートと照合する前にリクエスト パスが変更される可能性があります。
:mustermann_opts
ハッシュを渡すことで、特定のルートに使用される Mustermann オプションをカスタマイズできます。
get 'A/postsz' , :mustermann_opts => { :type => :regexp , :check_anchors => false } do
# matches /posts exactly, with explicit anchoring
"If you match an anchored pattern clap your hands!"
end
条件のように見えますが、条件ではありません。これらのオプションは、以下で説明するグローバル:mustermann_opts
ハッシュにマージされます。
ルートには、ユーザー エージェントなどのさまざまな一致条件が含まれる場合があります。
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
provides
。
独自の条件を簡単に定義できます。
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
複数の値を取る条件の場合は、スプラットを使用します。
set ( :auth ) do |* roles | # <- notice the splat here
condition do
unless logged_in? && roles . any? { | role | current_user . in_role? role }
redirect "/login/" , 303
end
end
end
get "/my/account/" , :auth => [ :user , :admin ] do
"Your Account Details"
end
get "/only/admin/" , :auth => :admin do
"Only admins are allowed here!"
end
ルート ブロックの戻り値によって、少なくとも HTTP クライアントに渡される応答本文、またはラック スタック内の少なくとも次のミドルウェアが決まります。最も一般的には、上記の例のように、これは文字列です。ただし、他の値も受け入れられます。
有効な Rack 応答、Rack 本文オブジェクト、または HTTP ステータス コードのいずれかのオブジェクトを返すことができます。
[status (Integer), headers (Hash), response body (responds to #each)]
[status (Integer), response body (responds to #each)]
#each
に応答し、指定されたブロックに文字列だけを渡すオブジェクトそうすることで、たとえば、ストリーミングのサンプルを簡単に実装できます。
class Stream
def each
100 . times { | i | yield " #{ i } n " }
end
end
get ( '/' ) { Stream . new }
stream
ヘルパー メソッド (後述) を使用して定型文を削減し、ストリーミング ロジックをルートに埋め込むこともできます。
上で示したように、Sinatra には、ルート マッチとして文字列パターンと正規表現を使用するためのサポートが組み込まれています。しかし、それだけではありません。独自のマッチャーを簡単に定義できます。
class AllButPattern
def initialize ( except )
@except = except
end
def to_pattern ( options )
return self
end
def params ( route )
return { } unless @except === route
end
end
def all_but ( pattern )
AllButPattern . new ( pattern )
end
get all_but ( "/index" ) do
# ...
end
上記の例は次のように表現することもできるため、過剰に設計されている可能性があることに注意してください。
get /.*/ do
pass if request . path_info == "/index"
# ...
end
静的ファイルは./public
ディレクトリから提供されます。 :public_folder
オプションを設定すると、別の場所を指定できます。
set :public_folder , __dir__ + '/static'
パブリック ディレクトリ名は URL に含まれないことに注意してください。ファイル./public/css/style.css
はhttp://example.com/css/style.css
として利用可能です。
:static_cache_control
設定 (以下を参照) を使用して、 Cache-Control
ヘッダー情報を追加します。
各テンプレート言語は、独自のレンダリング方法を介して公開されます。これらのメソッドは単純に文字列を返します。
get '/' do
erb :index
end
これにより、 views/index.erb
がレンダリングされます。
テンプレート名の代わりに、テンプレートのコンテンツを直接渡すこともできます。
get '/' do
code = "<%= Time.now %>"
erb code
end
テンプレートは 2 番目の引数、オプションのハッシュを受け取ります。
get '/' do
erb :index , :layout => :post
end
これにより、 views/post.erb
に埋め込まれたviews/index.erb
がレンダリングされます (デフォルトは、 views/layout.erb
が存在する場合)。
Sinatra が理解できないオプションはすべてテンプレート エンジンに渡されます。
get '/' do
haml :index , :format => :html5
end
一般に、テンプレート言語ごとにオプションを設定することもできます。
set :haml , :format => :html5
get '/' do
haml :index
end
render メソッドに渡されるオプションは、 set
によって設定されたオプションをオーバーライドします。
利用可能なオプション:
テンプレートは./views
ディレクトリの直下にあると想定されます。別のビュー ディレクトリを使用するには:
set :views , settings . root + '/templates'
覚えておくべき重要な点の 1 つは、テンプレートがサブディレクトリにある場合でも、常にシンボルを含むテンプレートを参照する必要があるということです (この場合、 :'subdir/template'
または'subdir/template'.to_sym
を使用します)。シンボルを使用する必要があります。そうしないと、レンダリング メソッドに渡された文字列が直接レンダリングされてしまうためです。
get '/' do
haml '%div.title Hello World'
end
テンプレート文字列をレンダリングします。その文字列に関連付けられたファイルシステムのパスまたは行がある場合、オプションで:path
および:line
を指定すると、より明確なバックトレースが得られます。
get '/' do
haml '%div.title Hello World' , :path => 'examples/file.haml' , :line => 3
end
一部の言語には複数の実装があります。どの実装を使用するかを指定するには (そしてスレッドセーフにするために)、最初にそれを要求する必要があります。
require 'rdiscount'
get ( '/' ) { markdown :index }
依存 | ハムル |
ファイル拡張子 | .haml |
例 | haml :index, :format => :html5 |
依存 | erubi または erb (Ruby に含まれる) |
ファイル拡張子 | .erb 、 .rhtmlまたは.erubi (Erubi のみ) |
例 | erb:インデックス |
依存 | ビルダー |
ファイル拡張子 | 。ビルダー |
例 | ビルダー { |xml| xml.em "こんにちは" } |
インライン テンプレートのブロックも必要です (例を参照)。
依存 | 鋸ギリ |
ファイル拡張子 | .のこぎり |
例 | ノコギリ { |xml| xml.em "こんにちは" } |
インライン テンプレートのブロックも必要です (例を参照)。
依存 | Sass埋め込み型 |
ファイル拡張子 | .sass |
例 | sass :stylesheet, :style => :expanded |
依存 | Sass埋め込み型 |
ファイル拡張子 | .scss |
例 | scss :stylesheet, :style => :expanded |
依存 | 液体 |
ファイル拡張子 | 。液体 |
例 | 液体 :index, :locals => { :key => '値' } |
Liquid テンプレートから Ruby メソッド ( yield
を除く) を呼び出すことはできないため、ほとんどの場合、それにローカル変数を渡す必要があります。
依存 | 次のいずれか: RDiscount、RedCarpet、kramdown、commonmark pandoc |
ファイル拡張子 | .markdown 、 .mkd 、 .md |
例 | マークダウン :index、:layout_engine => :erb |
Markdown からメソッドを呼び出すことも、Markdown にローカルを渡すこともできません。したがって、通常は別のレンダリング エンジンと組み合わせて使用します。
erb :overview , :locals => { :text => markdown ( :introduction ) }
他のテンプレート内からmarkdown
メソッドを呼び出すこともできることに注意してください。
% h1 Hello From Haml!
% p = markdown ( :greetings )
MarkdownからRubyを呼び出すことができないため、Markdownで書かれたレイアウトは使用できません。ただし、 :layout_engine
オプションを渡すことで、レイアウト以外のテンプレートに別のレンダリング エンジンを使用することができます。
依存 | RDoc |
ファイル拡張子 | .rdoc |
例 | rdoc :README、:layout_engine => :erb |
RDoc からメソッドを呼び出したり、RDoc にローカルを渡すことはできません。したがって、通常は別のレンダリング エンジンと組み合わせて使用します。
erb :overview , :locals => { :text => rdoc ( :introduction ) }
他のテンプレート内からrdoc
メソッドを呼び出すこともできることに注意してください。
% h1 Hello From Haml!
% p = rdoc ( :greetings )
RDoc から Ruby を呼び出すことはできないため、RDoc で記述されたレイアウトは使用できません。ただし、 :layout_engine
オプションを渡すことで、レイアウト以外のテンプレートに別のレンダリング エンジンを使用することができます。
依存 | ホヤドクター |
ファイル拡張子 | .asciidoc 、 .adoc 、および.ad |
例 | asciidoc :README、:layout_engine => :erb |
AsciiDoc テンプレートから直接 Ruby メソッドを呼び出すことはできないため、ほとんどの場合、それにローカル変数を渡す必要があります。
依存 | マーカビー |
ファイル拡張子 | .mab |
例 | マーカビー { h1 「ようこそ!」 } |
インライン テンプレートのブロックも必要です (例を参照)。
依存 | ラブル |
ファイル拡張子 | .rabl |
例 | ラブル:インデックス |
依存 | スリムラング |
ファイル拡張子 | 。スリム |
例 | スリム:インデックス |
依存 | ヤジルルビー |
ファイル拡張子 | .yajl |
例 | yajl :index, :locals => { :key => 'qux' }, :callback => 'present', :variable => 'resource' |
テンプレート ソースは Ruby 文字列として評価され、結果の json 変数は#to_json
を使用して変換されます。
json = { :foo => 'bar' }
json [ :baz ] = key
:callback
および:variable
オプションを使用して、レンダリングされたオブジェクトを装飾できます。
var resource = { "foo" : "bar" , "baz" : "qux" } ;
present ( resource ) ;
テンプレートはルート ハンドラーと同じコンテキスト内で評価されます。ルート ハンドラーに設定されたインスタンス変数には、テンプレートから直接アクセスできます。
get '/:id' do
@foo = Foo . find ( params [ 'id' ] )
haml '%h1= @foo.name'
end
または、ローカル変数の明示的なハッシュを指定します。
get '/:id' do
foo = Foo . find ( params [ 'id' ] )
haml '%h1= bar.name' , :locals => { :bar => foo }
end
これは通常、テンプレートを他のテンプレート内から部分としてレンダリングするときに使用されます。
yield
およびネストされたレイアウトを備えたテンプレートレイアウトは通常、 yield
を呼び出す単なるテンプレートです。このようなテンプレートは、上で説明したように:template
オプションを使用して使用することも、次のようにブロックを使用してレンダリングすることもできます。
erb :post , :layout => false do
erb :index
end
このコードはerb :index, :layout => :post
とほぼ同等です。
レンダリング メソッドにブロックを渡すことは、ネストされたレイアウトを作成する場合に最も役立ちます。
erb :main_layout , :layout => false do
erb :admin_layout do
erb :user
end
end
これは、次のようにして、より少ないコード行で実行することもできます。
erb :admin_layout , :layout => :main_layout do
erb :user
end
現在、次のレンダリング メソッドがブロックを受け入れます: erb
、 haml
、 liquid
、 slim
。また、一般的なrender
メソッドはブロックを受け入れます。
テンプレートはソース ファイルの最後で定義できます。
require 'sinatra'
get '/' do
haml :index
end
__END__
@@ layout
%html
!= yield
@@ index
%div.title Hello world.
注: Sinatra を必要とするソース ファイルで定義されたインライン テンプレートは、自動的にロードされます。他のソース ファイルにインライン テンプレートがある場合は、 enable :inline_templates
明示的に呼び出します。
テンプレートは、トップレベルのtemplate
メソッドを使用して定義することもできます。
template :layout do
"%html n =yield n "
end
template :index do
'%div.title Hello World!'
end
get '/' do
haml :index
end
「layout」という名前のテンプレートが存在する場合、テンプレートがレンダリングされるたびにそれが使用されます。 :layout => false
渡すことでレイアウトを個別に無効にするか、 set :haml, :layout => false
でデフォルトでレイアウトを無効にすることができます。
get '/' do
haml :index , :layout => ! request . xhr?
end
ファイル拡張子をテンプレート エンジンに関連付けるには、 Tilt.register
を使用します。たとえば、Haml テンプレートにファイル拡張子tt
使用したい場合は、次の操作を行うことができます。
Tilt . register Tilt [ :haml ] , :tt
まず、エンジンを Tilt に登録し、次にレンダリング メソッドを作成します。
Tilt . register MyAwesomeTemplateEngine , :myat
helpers do
def myat ( * args ) render ( :myat , * args ) end
end
get '/' do
myat :index
end
./views/index.myat
をレンダリングします。チルトについて詳しくは、こちらをご覧ください。
独自のテンプレート検索メカニズムを実装するには、独自の#find_template
メソッドを記述します。
configure do
set :views , [ './views/a' , './views/b' ]
end
def find_template ( views , name , engine , & block )
Array ( views ) . each do | v |
super ( v , name , engine , & block )
end
end
Before フィルタは、ルートと同じコンテキスト内の各リクエストの前に評価され、リクエストとレスポンスを変更できます。フィルターに設定されたインスタンス変数には、ルートとテンプレートからアクセスできます。
before do
@note = 'Hi!'
request . path_info = '/foo/bar/baz'
end
get '/foo/*' do
@note #=> 'Hi!'
params [ 'splat' ] #=> 'bar/baz'
end
After フィルターは、ルートと同じコンテキスト内で各リクエストの後に評価され、リクエストと応答を変更することもできます。 before フィルターに設定されたインスタンス変数とルートは、after フィルターからアクセスできます。
after do
puts response . status
end
注: ルートから文字列を返すだけでなくbody
メソッドを使用しない限り、本文は後で生成されるため、after フィルターではまだ使用できません。
フィルターはオプションでパターンを受け取り、リクエスト パスがそのパターンに一致する場合にのみフィルターが評価されます。
before '/protected/*' do
authenticate!
end
after '/create/:slug' do | slug |
session [ :last_slug ] = slug
end
ルートと同様に、フィルターにも条件があります。
before :agent => /Songbird/ do
# ...
end
after '/blog/*' , :host_name => 'example.com' do
# ...
end
最上位のhelpers
メソッドを使用して、ルート ハンドラーとテンプレートで使用するヘルパー メソッドを定義します。