Sinatra adalah DSL untuk membuat aplikasi web dengan cepat di Ruby dengan sedikit usaha:
# myapp.rb
require 'sinatra'
get '/' do
'Hello world!'
end
Instal permata yang dibutuhkan:
gem install sinatra rackup puma
Dan jalankan dengan:
ruby myapp.rb
Lihat di: http://localhost:4567
Kode yang Anda ubah tidak akan berlaku sampai Anda me-restart server. Silakan restart server setiap kali Anda mengubah atau menggunakan kode reloader seperti rerun atau rack-unreloader.
Disarankan juga untuk menjalankan gem install puma
, yang akan diambil Sinatra jika tersedia.
yield
dan tata letak bersarangDi Sinatra, rute adalah metode HTTP yang dipasangkan dengan pola pencocokan URL. Setiap rute dikaitkan dengan sebuah blok:
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
Rute dicocokkan sesuai urutan yang ditentukan. Rute pertama yang cocok dengan permintaan akan dipanggil.
Rute dengan garis miring berbeda dengan rute tanpa garis miring:
get '/foo' do
# Does not match "GET /foo/"
end
Pola rute dapat mencakup parameter bernama, yang dapat diakses melalui hash params
:
get '/hello/:name' do
# matches "GET /hello/foo" and "GET /hello/bar"
# params['name'] is 'foo' or 'bar'
"Hello #{ params [ 'name' ] } !"
end
Anda juga dapat mengakses parameter bernama melalui parameter blok:
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
Pola rute juga dapat mencakup parameter percikan (atau wildcard), yang dapat diakses melalui array 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
Atau dengan parameter blok:
get '/download/*.*' do | path , ext |
[ path , ext ] # => ["path/to/file", "xml"]
end
Pencocokan rute dengan Ekspresi Reguler:
get / / hello / ([ w ]+)/ do
"Hello, #{ params [ 'captures' ] . first } !"
end
Atau dengan parameter blok:
get %r{/hello/([ w ]+)} do | c |
# Matches "GET /meta/hello/world", "GET /hello/world/1234" etc.
"Hello, #{ c } !"
end
Pola rute mungkin memiliki parameter opsional:
get '/posts/:format?' do
# matches "GET /posts/" and any extension "GET /posts/json", "GET /posts/xml" etc
end
Rute juga dapat menggunakan parameter kueri:
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
Ngomong-ngomong, kecuali Anda menonaktifkan perlindungan serangan traversal jalur (lihat di bawah), jalur permintaan mungkin diubah sebelum dicocokkan dengan rute Anda.
Anda dapat menyesuaikan opsi Mustermann yang digunakan untuk rute tertentu dengan meneruskan hash :mustermann_opts
:
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
Kelihatannya seperti suatu kondisi, tapi sebenarnya bukan suatu kondisi! Opsi-opsi ini akan digabungkan ke dalam hash global :mustermann_opts
yang dijelaskan di bawah.
Rute dapat mencakup berbagai kondisi pencocokan, seperti agen pengguna:
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
Kondisi lain yang tersedia adalah host_name
dan 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
pencarian header Terima permintaan.
Anda dapat dengan mudah menentukan kondisi Anda sendiri:
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
Untuk kondisi yang memerlukan banyak nilai, gunakan percikan:
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
Nilai kembalian dari blok rute menentukan setidaknya isi respons yang diteruskan ke klien HTTP atau setidaknya middleware berikutnya di tumpukan Rack. Umumnya, ini adalah string, seperti pada contoh di atas. Namun nilai-nilai lain juga diterima.
Anda dapat mengembalikan objek yang berupa respons Rack yang valid, objek isi Rak, atau kode status HTTP:
[status (Integer), headers (Hash), response body (responds to #each)]
[status (Integer), response body (responds to #each)]
#each
dan hanya meneruskan string ke blok tertentuDengan begitu kita dapat, misalnya, dengan mudah mengimplementasikan contoh streaming:
class Stream
def each
100 . times { | i | yield " #{ i } n " }
end
end
get ( '/' ) { Stream . new }
Anda juga dapat menggunakan metode stream
helper (dijelaskan di bawah) untuk mengurangi boilerplate dan menyematkan logika streaming di rute.
Seperti yang ditunjukkan di atas, Sinatra dikirimkan dengan dukungan bawaan untuk menggunakan pola String dan ekspresi reguler sebagai pencocokan rute. Namun, hal itu tidak berhenti sampai di situ. Anda dapat dengan mudah menentukan pencocokan Anda sendiri:
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
Perhatikan bahwa contoh di atas mungkin direkayasa secara berlebihan, karena dapat juga dinyatakan sebagai:
get /.*/ do
pass if request . path_info == "/index"
# ...
end
File statis disajikan dari direktori ./public
. Anda dapat menentukan lokasi lain dengan mengatur opsi :public_folder
:
set :public_folder , __dir__ + '/static'
Perhatikan bahwa nama direktori publik tidak disertakan dalam URL. File ./public/css/style.css
tersedia sebagai http://example.com/css/style.css
.
Gunakan pengaturan :static_cache_control
(lihat di bawah) untuk menambahkan info header Cache-Control
.
Setiap bahasa templat diekspos melalui metode renderingnya sendiri. Metode ini hanya mengembalikan sebuah string:
get '/' do
erb :index
end
Ini membuat views/index.erb
.
Selain nama templat, Anda juga bisa langsung memasukkan konten templat:
get '/' do
code = "<%= Time.now %>"
erb code
end
Templat mengambil argumen kedua, opsi hash:
get '/' do
erb :index , :layout => :post
end
Ini akan membuat views/index.erb
tertanam di views/post.erb
(defaultnya adalah views/layout.erb
, jika ada).
Opsi apa pun yang tidak dipahami oleh Sinatra akan diteruskan ke mesin templat:
get '/' do
haml :index , :format => :html5
end
Anda juga dapat mengatur opsi per bahasa template secara umum:
set :haml , :format => :html5
get '/' do
haml :index
end
Opsi diteruskan ke metode render menggantikan opsi yang disetel melalui set
.
Opsi yang Tersedia:
Templat diasumsikan terletak tepat di bawah direktori ./views
. Untuk menggunakan direktori views yang berbeda:
set :views , settings . root + '/templates'
Satu hal penting untuk diingat adalah Anda harus selalu mereferensikan templat dengan simbol, meskipun templat tersebut berada dalam subdirektori (dalam hal ini, gunakan: :'subdir/template'
atau 'subdir/template'.to_sym
). Anda harus menggunakan simbol karena jika tidak, metode rendering akan merender string apa pun yang diteruskan ke metode tersebut secara langsung.
get '/' do
haml '%div.title Hello World'
end
Merender string templat. Anda juga dapat menentukan :path
dan :line
untuk penelusuran balik yang lebih jelas jika ada jalur atau baris sistem file yang terkait dengan string tersebut:
get '/' do
haml '%div.title Hello World' , :path => 'examples/file.haml' , :line => 3
end
Beberapa bahasa memiliki banyak implementasi. Untuk menentukan implementasi apa yang akan digunakan (dan agar thread-safe), Anda cukup mewajibkannya terlebih dahulu:
require 'rdiscount'
get ( '/' ) { markdown :index }
Ketergantungan | haml |
Ekstensi File | .haml |
Contoh | haml :indeks, :format => :html5 |
Ketergantungan | erubi atau erb (termasuk dalam Ruby) |
Ekstensi File | .erb , .rhtml atau .erubi (khusus Erubi) |
Contoh | erb :indeks |
Ketergantungan | pembangun |
Ekstensi File | .pembangun |
Contoh | pembangun { |xml| xml.em "hai" } |
Ini juga memerlukan satu blok untuk templat sebaris (lihat contoh).
Ketergantungan | nokogiri |
Ekstensi File | .nokogiri |
Contoh | nokogiri { |xml| xml.em "hai" } |
Ini juga memerlukan satu blok untuk templat sebaris (lihat contoh).
Ketergantungan | tertanam sass |
Ekstensi File | .kelancangan |
Contoh | sass :stylesheet, :style => :diperluas |
Ketergantungan | tertanam sass |
Ekstensi File | .scss |
Contoh | scss :stylesheet, :style => :diperluas |
Ketergantungan | cairan |
Ekstensi File | .cairan |
Contoh | cair :indeks, :lokal => { :kunci => 'nilai' } |
Karena Anda tidak dapat memanggil metode Ruby (kecuali yield
) dari templat Liquid, Anda hampir selalu ingin meneruskan metode lokal ke sana.
Ketergantungan | Siapa pun dari: RDiscount, RedCarpet, kramdown, commonmarker pandoc |
Ekstensi File | .penurunan harga , .mkd dan .md |
Contoh | penurunan harga :index, :layout_engine => :erb |
Tidak mungkin memanggil metode dari Markdown, atau meneruskan penduduk lokal ke sana. Oleh karena itu, Anda biasanya akan menggunakannya dalam kombinasi dengan mesin rendering lain:
erb :overview , :locals => { :text => markdown ( :introduction ) }
Perhatikan bahwa Anda juga dapat memanggil metode markdown
dari dalam templat lain:
% h1 Hello From Haml!
% p = markdown ( :greetings )
Karena Anda tidak dapat memanggil Ruby dari Markdown, Anda tidak dapat menggunakan tata letak yang ditulis dalam Markdown. Namun, dimungkinkan untuk menggunakan mesin rendering lain untuk templat selain untuk tata letak dengan meneruskan opsi :layout_engine
.
Ketergantungan | RDok |
Ekstensi File | .rdoc |
Contoh | rdoc :README, :layout_engine => :erb |
Tidak mungkin memanggil metode dari RDoc, atau meneruskan metode lokal ke sana. Oleh karena itu, Anda biasanya akan menggunakannya dalam kombinasi dengan mesin rendering lain:
erb :overview , :locals => { :text => rdoc ( :introduction ) }
Perhatikan bahwa Anda juga dapat memanggil metode rdoc
dari dalam templat lain:
% h1 Hello From Haml!
% p = rdoc ( :greetings )
Karena Anda tidak dapat memanggil Ruby dari RDoc, Anda tidak dapat menggunakan tata letak yang ditulis dalam RDoc. Namun, dimungkinkan untuk menggunakan mesin rendering lain untuk templat selain untuk tata letak dengan meneruskan opsi :layout_engine
.
Ketergantungan | Asciidoctor |
Ekstensi File | .asciidoc , .adoc dan .ad |
Contoh | asciidoc :README, :layout_engine => :erb |
Karena Anda tidak dapat memanggil metode Ruby langsung dari templat AsciiDoc, Anda hampir selalu ingin meneruskan metode lokal ke sana.
Ketergantungan | Markaby |
Ekstensi File | .mab |
Contoh | markaby { h1 "Selamat datang!" } |
Ini juga memerlukan satu blok untuk templat sebaris (lihat contoh).
Ketergantungan | rabel |
Ekstensi File | .rabl |
Contoh | rabl :index |
Ketergantungan | Lang Lang |
Ekstensi File | .langsing |
Contoh | ramping: indeks |
Ketergantungan | yajl-ruby |
Ekstensi File | .yajl |
Contoh | yajl :index, :locals => { :key => 'qux' }, :callback => 'present', :variable => 'resource' |
Sumber templat dievaluasi sebagai string Ruby, dan variabel json yang dihasilkan dikonversi menggunakan #to_json
:
json = { :foo => 'bar' }
json [ :baz ] = key
Opsi :callback
dan :variable
dapat digunakan untuk menghiasi objek yang dirender:
var resource = { "foo" : "bar" , "baz" : "qux" } ;
present ( resource ) ;
Templat dievaluasi dalam konteks yang sama dengan penangan rute. Variabel instan yang diatur dalam pengendali rute dapat diakses langsung melalui templat:
get '/:id' do
@foo = Foo . find ( params [ 'id' ] )
haml '%h1= @foo.name'
end
Atau, tentukan Hash eksplisit dari variabel lokal:
get '/:id' do
foo = Foo . find ( params [ 'id' ] )
haml '%h1= bar.name' , :locals => { :bar => foo }
end
Ini biasanya digunakan ketika merender template sebagai bagian dari dalam template lain.
yield
dan tata letak bersarang Tata letak biasanya hanya berupa templat yang memanggil yield
. Templat seperti itu dapat digunakan melalui opsi :template
seperti dijelaskan di atas, atau dapat dirender dengan blok sebagai berikut:
erb :post , :layout => false do
erb :index
end
Kode ini sebagian besar setara dengan erb :index, :layout => :post
.
Meneruskan blok ke metode rendering paling berguna untuk membuat tata letak bertingkat:
erb :main_layout , :layout => false do
erb :admin_layout do
erb :user
end
end
Ini juga dapat dilakukan dalam lebih sedikit baris kode dengan:
erb :admin_layout , :layout => :main_layout do
erb :user
end
Saat ini, metode rendering berikut menerima blok: erb
, haml
, liquid
, slim
. Selain itu, metode render
umum menerima blok.
Templat dapat ditentukan di akhir file sumber:
require 'sinatra'
get '/' do
haml :index
end
__END__
@@ layout
%html
!= yield
@@ index
%div.title Hello world.
CATATAN: Templat sebaris yang ditentukan dalam file sumber yang memerlukan Sinatra dimuat secara otomatis. Panggil enable :inline_templates
secara eksplisit jika Anda memiliki templat sebaris di file sumber lain.
Templat juga dapat ditentukan menggunakan metode template
tingkat atas:
template :layout do
"%html n =yield n "
end
template :index do
'%div.title Hello World!'
end
get '/' do
haml :index
end
Jika template bernama "layout" ada, maka template tersebut akan digunakan setiap kali template dirender. Anda dapat menonaktifkan tata letak satu per satu dengan meneruskan :layout => false
atau menonaktifkannya secara default melalui set :haml, :layout => false
:
get '/' do
haml :index , :layout => ! request . xhr?
end
Untuk mengaitkan ekstensi file dengan mesin templat, gunakan Tilt.register
. Misalnya, jika Anda ingin menggunakan ekstensi file tt
untuk templat Haml, Anda dapat melakukan hal berikut:
Tilt . register Tilt [ :haml ] , :tt
Pertama, daftarkan mesin Anda dengan Tilt, lalu buat metode rendering:
Tilt . register MyAwesomeTemplateEngine , :myat
helpers do
def myat ( * args ) render ( :myat , * args ) end
end
get '/' do
myat :index
end
Merender ./views/index.myat
. Pelajari lebih lanjut tentang Kemiringan.
Untuk menerapkan mekanisme pencarian templat Anda sendiri, Anda dapat menulis metode #find_template
Anda sendiri:
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
Sebelum filter dievaluasi sebelum setiap permintaan dalam konteks yang sama dengan rute dan dapat mengubah permintaan dan respons. Variabel instan yang diatur dalam filter dapat diakses melalui rute dan templat:
before do
@note = 'Hi!'
request . path_info = '/foo/bar/baz'
end
get '/foo/*' do
@note #=> 'Hi!'
params [ 'splat' ] #=> 'bar/baz'
end
Filter setelah dievaluasi setelah setiap permintaan dalam konteks yang sama dengan rutenya dan juga dapat mengubah permintaan dan respons. Variabel instan diatur sebelum filter dan rute dapat diakses setelah filter:
after do
puts response . status
end
Catatan: Kecuali Anda menggunakan metode body
daripada hanya mengembalikan sebuah String dari rute, body belum akan tersedia di filter setelahnya, karena dibuat nanti.
Filter secara opsional mengambil suatu pola, menyebabkannya dievaluasi hanya jika jalur permintaan cocok dengan pola tersebut:
before '/protected/*' do
authenticate!
end
after '/create/:slug' do | slug |
session [ :last_slug ] = slug
end
Seperti rute, filter juga mengambil ketentuan:
before :agent => /Songbird/ do
# ...
end
after '/blog/*' , :host_name => 'example.com' do
# ...
end
Gunakan metode helpers
tingkat atas untuk menentukan metode pembantu untuk digunakan dalam penangan rute dan templat: