Sinatra 是一種 DSL,可以用最少的工作在 Ruby 中快速建立 Web 應用程式:
# 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
路由模式還可以包括 splat (或通配符)參數,可透過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
搜尋請求的 Accept 標頭。
您可以輕鬆定義自己的條件:
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
對於採用多個值的條件,請使用 splat:
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 回應、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
模板採用第二個參數,即選項雜湊:
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'
要記住的一件重要的事情是,您始終必須使用符號引用模板,即使它們位於子目錄中(在本例中,使用: :'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 |
例子 | 哈姆爾:索引,:格式=>:html5 |
依賴性 | erubi 或 erb(包含在 Ruby 中) |
檔案副檔名 | .erb 、 .rhtml或.erubi (僅限 Erubi) |
例子 | erb :索引 |
依賴性 | 建設者 |
檔案副檔名 | .builder |
例子 | 建構器 { |xml| xml.em「嗨」} |
它還需要一個內聯模板區塊(請參閱範例)。
依賴性 | 諾科吉里 |
檔案副檔名 | .nokogiri |
例子 | 諾科吉里 { |xml| xml.em「嗨」} |
它還需要一個內聯模板區塊(請參閱範例)。
依賴性 | sass 嵌入式 |
檔案副檔名 | .sass |
例子 | sass :stylesheet, :style => :expanded |
依賴性 | sass 嵌入式 |
檔案副檔名 | .scss |
例子 | scss :樣式表, :樣式 => :擴展 |
依賴性 | 液體 |
檔案副檔名 | 。 |
例子 | 液體 :index, :locals => { :key => 'value' } |
由於您無法從 Liquid 範本呼叫 Ruby 方法( yield
除外),因此您幾乎總是希望將局部變數傳遞給它。
依賴性 | 以下任一項:RDiscount、RedCarpet、kramdown、commonmarker pandoc |
檔案副檔名 | .markdown 、 .mkd和.md |
例子 | 降價:索引,:layout_engine =>:erb |
無法從 Markdown 呼叫方法,也無法將本地變數傳遞給它。因此,您通常會將其與另一個渲染引擎結合使用:
erb :overview , :locals => { :text => markdown ( :introduction ) }
請注意,您也可以從其他模板呼叫markdown
方法:
% h1 Hello From Haml!
% p = markdown ( :greetings )
由於您無法從 Markdown 呼叫 Ruby,因此您無法使用用 Markdown 編寫的佈局。但是,可以透過傳遞:layout_engine
選項為模板使用除佈局之外的其他渲染引擎。
依賴性 | 遠端文件 |
檔案副檔名 | .rdoc |
例子 | rdoc:自述文件,:layout_engine =>:erb |
無法從 RDoc 呼叫方法,也無法將局部變數傳遞給它。因此,您通常會將其與另一個渲染引擎結合使用:
erb :overview , :locals => { :text => rdoc ( :introduction ) }
請注意,您也可以從其他範本中呼叫rdoc
方法:
% h1 Hello From Haml!
% p = rdoc ( :greetings )
由於您無法從 RDoc 呼叫 Ruby,因此您無法使用用 RDoc 編寫的佈局。但是,可以透過傳遞:layout_engine
選項為模板使用除佈局之外的其他渲染引擎。
依賴性 | 阿西多克托 |
檔案副檔名 | .asciidoc 、 .adoc和.ad |
例子 | asciidoc:自述文件,:layout_engine =>:erb |
由於您無法直接從 AsciiDoc 範本呼叫 Ruby 方法,因此您幾乎總是希望將本機變數傳遞給它。
依賴性 | 馬爾卡比 |
檔案副檔名 | .mab |
例子 | 馬克比 { h1“歡迎!” } |
它還需要一個內聯模板區塊(請參閱範例)。
依賴性 | 拉布爾 |
檔案副檔名 | .rabl |
例子 | 拉布:索引 |
依賴性 | 斯利姆朗 |
檔案副檔名 | 。 |
例子 | 苗條:索引 |
依賴性 | 亞吉魯比 |
檔案副檔名 | .yajl |
例子 | yajl :index, :locals => { :key => 'qux' }, :callback => 'present', :variable => '資源' |
模板來源被評估為 Ruby 字串,並使用#to_json
轉換產生的 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 過濾器在與路由相同的上下文中的每個請求之後進行評估,並且還可以修改請求和回應。在過濾器之前和路由中設定的實例變數可以通過過濾器之後存取:
after do
puts response . status
end
注意:除非您使用body
方法而不是僅從路由返回 String,否則主體在 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
方法來定義在路由處理程序和範本中使用的幫助器方法: