Sinatra ist eine DSL zum schnellen Erstellen von Webanwendungen in Ruby mit minimalem Aufwand:
# myapp.rb
require 'sinatra'
get '/' do
'Hello world!'
end
Installieren Sie die benötigten Edelsteine:
gem install sinatra rackup puma
Und laufen mit:
ruby myapp.rb
Ansicht unter: http://localhost:4567
Der von Ihnen geänderte Code wird erst wirksam, wenn Sie den Server neu starten. Bitte starten Sie den Server jedes Mal neu, wenn Sie Änderungen vornehmen oder einen Code-Reloader wie Rerun oder Rack-Unreloader verwenden.
Es wird empfohlen, auch gem install puma
auszuführen, das Sinatra übernimmt, sofern verfügbar.
yield
und verschachtelten LayoutsIn Sinatra ist eine Route eine HTTP-Methode gepaart mit einem URL-Matching-Muster. Jeder Route ist ein Block zugeordnet:
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
Routen werden in der Reihenfolge abgeglichen, in der sie definiert sind. Die erste Route, die der Anfrage entspricht, wird aufgerufen.
Routen mit abschließenden Schrägstrichen unterscheiden sich von Routen ohne:
get '/foo' do
# Does not match "GET /foo/"
end
Routenmuster können benannte Parameter enthalten, auf die über den params
-Hash zugegriffen werden kann:
get '/hello/:name' do
# matches "GET /hello/foo" and "GET /hello/bar"
# params['name'] is 'foo' or 'bar'
"Hello #{ params [ 'name' ] } !"
end
Sie können auch über Blockparameter auf benannte Parameter zugreifen:
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
Routenmuster können auch Splat- (oder Platzhalter-)Parameter enthalten, auf die über das Array params['splat']
zugegriffen werden kann:
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
Oder mit Blockparametern:
get '/download/*.*' do | path , ext |
[ path , ext ] # => ["path/to/file", "xml"]
end
Routenabgleich mit regulären Ausdrücken:
get / / hello / ([ w ]+)/ do
"Hello, #{ params [ 'captures' ] . first } !"
end
Oder mit einem Blockparameter:
get %r{/hello/([ w ]+)} do | c |
# Matches "GET /meta/hello/world", "GET /hello/world/1234" etc.
"Hello, #{ c } !"
end
Routenmuster können optionale Parameter haben:
get '/posts/:format?' do
# matches "GET /posts/" and any extension "GET /posts/json", "GET /posts/xml" etc
end
Routen können auch Abfrageparameter verwenden:
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
Übrigens: Sofern Sie den Path-Traversal-Angriffsschutz nicht deaktivieren (siehe unten), kann es sein, dass der Anforderungspfad geändert wird, bevor er mit Ihren Routen abgeglichen wird.
Sie können die für eine bestimmte Route verwendeten Mustermann-Optionen anpassen, indem Sie einen :mustermann_opts
-Hash übergeben:
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
Es sieht nach einem Zustand aus, ist aber keiner! Diese Optionen werden in den unten beschriebenen globalen :mustermann_opts
-Hash zusammengeführt.
Routen können eine Vielzahl von Übereinstimmungsbedingungen enthalten, z. B. den Benutzeragenten:
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
Weitere verfügbare Bedingungen sind host_name
und 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
die Suche im Accept-Header der Anfrage.
Sie können ganz einfach Ihre eigenen Bedingungen definieren:
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
Für eine Bedingung, die mehrere Werte annimmt, verwenden Sie ein 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
Der Rückgabewert eines Route-Blocks bestimmt mindestens den Antworttext, der an den HTTP-Client oder mindestens die nächste Middleware im Rack-Stack weitergeleitet wird. Am häufigsten ist dies eine Zeichenfolge, wie in den obigen Beispielen. Aber auch andere Werte werden akzeptiert.
Sie können ein Objekt zurückgeben, das entweder eine gültige Rack-Antwort, ein Rack-Body-Objekt oder ein HTTP-Statuscode wäre:
[status (Integer), headers (Hash), response body (responds to #each)]
[status (Integer), response body (responds to #each)]
#each
antwortet und nichts als Strings an den angegebenen Block übergibtSo können wir beispielsweise ganz einfach ein Streaming-Beispiel umsetzen:
class Stream
def each
100 . times { | i | yield " #{ i } n " }
end
end
get ( '/' ) { Stream . new }
Sie können auch die stream
Hilfsmethode (unten beschrieben) verwenden, um den Boilerplate zu reduzieren und die Streaming-Logik in die Route einzubetten.
Wie oben gezeigt, verfügt Sinatra über eine integrierte Unterstützung für die Verwendung von String-Mustern und regulären Ausdrücken als Routenübereinstimmungen. Dabei bleibt es jedoch nicht. Sie können ganz einfach Ihre eigenen Matcher definieren:
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
Beachten Sie, dass das obige Beispiel möglicherweise überkonstruiert ist, da es auch wie folgt ausgedrückt werden kann:
get /.*/ do
pass if request . path_info == "/index"
# ...
end
Statische Dateien werden aus dem Verzeichnis ./public
bereitgestellt. Sie können einen anderen Speicherort angeben, indem Sie die Option :public_folder
festlegen:
set :public_folder , __dir__ + '/static'
Beachten Sie, dass der Name des öffentlichen Verzeichnisses nicht in der URL enthalten ist. Eine Datei ./public/css/style.css
wird als http://example.com/css/style.css
zur Verfügung gestellt.
Verwenden Sie die Einstellung :static_cache_control
(siehe unten), um Cache-Control
Header-Informationen hinzuzufügen.
Jede Vorlagensprache wird über ihre eigene Rendering-Methode verfügbar gemacht. Diese Methoden geben einfach eine Zeichenfolge zurück:
get '/' do
erb :index
end
Dadurch wird views/index.erb
gerendert.
Anstelle eines Vorlagennamens können Sie auch einfach den Vorlageninhalt direkt übergeben:
get '/' do
code = "<%= Time.now %>"
erb code
end
Vorlagen benötigen ein zweites Argument, den Options-Hash:
get '/' do
erb :index , :layout => :post
end
Dadurch wird views/index.erb
in views/post.erb
eingebettet gerendert (Standard ist views/layout.erb
, sofern vorhanden).
Alle Optionen, die Sinatra nicht versteht, werden an die Template-Engine weitergeleitet:
get '/' do
haml :index , :format => :html5
end
Sie können auch allgemein Optionen pro Vorlagensprache festlegen:
set :haml , :format => :html5
get '/' do
haml :index
end
An die Rendermethode übergebene Optionen überschreiben die über set
festgelegten Optionen.
Verfügbare Optionen:
Es wird davon ausgegangen, dass sich Vorlagen direkt im Verzeichnis ./views
befinden. So verwenden Sie ein anderes Ansichtsverzeichnis:
set :views , settings . root + '/templates'
Beachten Sie unbedingt, dass Sie Vorlagen immer mit Symbolen referenzieren müssen, auch wenn sie sich in einem Unterverzeichnis befinden (verwenden Sie in diesem Fall: :'subdir/template'
oder 'subdir/template'.to_sym
). Sie müssen ein Symbol verwenden, da Rendering-Methoden sonst alle an sie übergebenen Zeichenfolgen direkt rendern.
get '/' do
haml '%div.title Hello World'
end
Rendert die Vorlagenzeichenfolge. Sie können optional :path
und :line
für eine klarere Rückverfolgung angeben, wenn dieser Zeichenfolge ein Dateisystempfad oder eine Dateisystemzeile zugeordnet ist:
get '/' do
haml '%div.title Hello World' , :path => 'examples/file.haml' , :line => 3
end
Einige Sprachen haben mehrere Implementierungen. Um anzugeben, welche Implementierung verwendet werden soll (und um Thread-sicher zu sein), sollten Sie sie einfach zuerst anfordern:
require 'rdiscount'
get ( '/' ) { markdown :index }
Abhängigkeit | haml |
Dateierweiterung | .haml |
Beispiel | haml :index, :format => :html5 |
Abhängigkeit | erubi oder erb (in Ruby enthalten) |
Dateierweiterungen | .erb , .rhtml oder .erubi (nur Erubi) |
Beispiel | erb :index |
Abhängigkeit | Baumeister |
Dateierweiterung | .Baumeister |
Beispiel | Builder { |xml| xml.em „Hallo“ } |
Es benötigt auch einen Block für Inline-Vorlagen (siehe Beispiel).
Abhängigkeit | nokogiri |
Dateierweiterung | .nokogiri |
Beispiel | nokogiri { |xml| xml.em „Hallo“ } |
Es benötigt auch einen Block für Inline-Vorlagen (siehe Beispiel).
Abhängigkeit | sass-eingebettet |
Dateierweiterung | .sass |
Beispiel | sass :stylesheet, :style => :expanded |
Abhängigkeit | sass-eingebettet |
Dateierweiterung | .scss |
Beispiel | scss :stylesheet, :style => :expanded |
Abhängigkeit | flüssig |
Dateierweiterung | .flüssig |
Beispiel | liquid :index, :locals => { :key => 'value' } |
Da Sie Ruby-Methoden (außer yield
) nicht aus einer Liquid-Vorlage aufrufen können, möchten Sie fast immer lokale Methoden an diese übergeben.
Abhängigkeit | Jeder von: RDiscount, RedCarpet, Kramdown, Commonmarker Pandoc |
Dateierweiterungen | .markdown , .mkd und .md |
Beispiel | Markdown :index, :layout_engine => :erb |
Es ist nicht möglich, Methoden von Markdown aufzurufen oder lokale Methoden daran zu übergeben. Daher werden Sie es normalerweise in Kombination mit einer anderen Rendering-Engine verwenden:
erb :overview , :locals => { :text => markdown ( :introduction ) }
Beachten Sie, dass Sie die markdown
-Methode auch aus anderen Vorlagen heraus aufrufen können:
% h1 Hello From Haml!
% p = markdown ( :greetings )
Da Sie Ruby nicht von Markdown aus aufrufen können, können Sie keine in Markdown geschriebenen Layouts verwenden. Es ist jedoch möglich, für die Vorlage eine andere Rendering-Engine als für das Layout zu verwenden, indem Sie die Option :layout_engine
übergeben.
Abhängigkeit | RDoc |
Dateierweiterung | .rdoc |
Beispiel | rdoc :README, :layout_engine => :erb |
Es ist nicht möglich, Methoden von RDoc aus aufzurufen oder lokale Methoden daran zu übergeben. Daher werden Sie es normalerweise in Kombination mit einer anderen Rendering-Engine verwenden:
erb :overview , :locals => { :text => rdoc ( :introduction ) }
Beachten Sie, dass Sie die rdoc
-Methode auch aus anderen Vorlagen heraus aufrufen können:
% h1 Hello From Haml!
% p = rdoc ( :greetings )
Da Sie Ruby nicht von RDoc aus aufrufen können, können Sie keine in RDoc geschriebenen Layouts verwenden. Es ist jedoch möglich, für die Vorlage eine andere Rendering-Engine als für das Layout zu verwenden, indem Sie die Option :layout_engine
übergeben.
Abhängigkeit | Asciidoctor |
Dateierweiterung | .asciidoc , .adoc und .ad |
Beispiel | asciidoc :README, :layout_engine => :erb |
Da Sie Ruby-Methoden nicht direkt aus einer AsciiDoc-Vorlage aufrufen können, möchten Sie fast immer lokale Methoden an diese übergeben.
Abhängigkeit | Markaby |
Dateierweiterung | .mab |
Beispiel | markaby { h1 „Willkommen!“ } |
Es benötigt auch einen Block für Inline-Vorlagen (siehe Beispiel).
Abhängigkeit | Rabl |
Dateierweiterung | .rabl |
Beispiel | rabl :index |
Abhängigkeit | Schlanker Lang |
Dateierweiterung | .schlank |
Beispiel | schlank :index |
Abhängigkeit | yajl-ruby |
Dateierweiterung | .yajl |
Beispiel | yajl :index, :locals => { :key => 'qux' }, :callback => 'present', :variable => 'resource' |
Die Vorlagenquelle wird als Ruby-String ausgewertet und die resultierende JSON-Variable wird mit #to_json
konvertiert:
json = { :foo => 'bar' }
json [ :baz ] = key
Die Optionen :callback
und :variable
können verwendet werden, um das gerenderte Objekt zu dekorieren:
var resource = { "foo" : "bar" , "baz" : "qux" } ;
present ( resource ) ;
Vorlagen werden im selben Kontext wie Routenhandler ausgewertet. In Routenhandlern festgelegte Instanzvariablen sind über Vorlagen direkt zugänglich:
get '/:id' do
@foo = Foo . find ( params [ 'id' ] )
haml '%h1= @foo.name'
end
Oder geben Sie einen expliziten Hash lokaler Variablen an:
get '/:id' do
foo = Foo . find ( params [ 'id' ] )
haml '%h1= bar.name' , :locals => { :bar => foo }
end
Dies wird normalerweise verwendet, wenn Vorlagen als Teildateien aus anderen Vorlagen gerendert werden.
yield
und verschachtelten Layouts Ein Layout ist normalerweise nur eine Vorlage, die yield
aufruft. Eine solche Vorlage kann entweder wie oben beschrieben über die Option :template
verwendet werden oder wie folgt mit einem Block gerendert werden:
erb :post , :layout => false do
erb :index
end
Dieser Code entspricht größtenteils erb :index, :layout => :post
.
Die Übergabe von Blöcken an Rendering-Methoden ist zum Erstellen verschachtelter Layouts am nützlichsten:
erb :main_layout , :layout => false do
erb :admin_layout do
erb :user
end
end
Dies kann auch in weniger Codezeilen erfolgen mit:
erb :admin_layout , :layout => :main_layout do
erb :user
end
Derzeit akzeptieren die folgenden Rendering-Methoden einen Block: erb
, haml
, liquid
, slim
. Außerdem akzeptiert die allgemeine render
einen Block.
Vorlagen können am Ende der Quelldatei definiert werden:
require 'sinatra'
get '/' do
haml :index
end
__END__
@@ layout
%html
!= yield
@@ index
%div.title Hello world.
HINWEIS: In der Quelldatei definierte Inline-Vorlagen, die Sinatra erfordern, werden automatisch geladen. Rufen Sie enable :inline_templates
explizit auf, wenn Sie Inline-Vorlagen in anderen Quelldateien haben.
Vorlagen können auch mithilfe der template
der obersten Ebene definiert werden:
template :layout do
"%html n =yield n "
end
template :index do
'%div.title Hello World!'
end
get '/' do
haml :index
end
Wenn eine Vorlage mit dem Namen „layout“ vorhanden ist, wird sie jedes Mal verwendet, wenn eine Vorlage gerendert wird. Sie können Layouts einzeln deaktivieren, indem Sie :layout => false
übergeben, oder sie standardmäßig über set :haml, :layout => false
deaktivieren:
get '/' do
haml :index , :layout => ! request . xhr?
end
Um einer Vorlagen-Engine eine Dateierweiterung zuzuordnen, verwenden Sie Tilt.register
. Wenn Sie beispielsweise die Dateierweiterung tt
für Haml-Vorlagen verwenden möchten, können Sie Folgendes tun:
Tilt . register Tilt [ :haml ] , :tt
Registrieren Sie zunächst Ihre Engine bei Tilt und erstellen Sie dann eine Rendering-Methode:
Tilt . register MyAwesomeTemplateEngine , :myat
helpers do
def myat ( * args ) render ( :myat , * args ) end
end
get '/' do
myat :index
end
Rendert ./views/index.myat
. Erfahren Sie mehr über Tilt.
Um Ihren eigenen Vorlagensuchmechanismus zu implementieren, können Sie Ihre eigene #find_template
-Methode schreiben:
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
Vorher-Filter werden vor jeder Anfrage im selben Kontext wie die Routen ausgewertet und können die Anfrage und Antwort ändern. Auf in Filtern festgelegte Instanzvariablen kann über Routen und Vorlagen zugegriffen werden:
before do
@note = 'Hi!'
request . path_info = '/foo/bar/baz'
end
get '/foo/*' do
@note #=> 'Hi!'
params [ 'splat' ] #=> 'bar/baz'
end
Nachfilter werden nach jeder Anfrage im selben Kontext wie die Routen ausgewertet und können auch die Anfrage und Antwort ändern. Auf vor Filtern und Routen festgelegte Instanzvariablen kann über Nachfilter zugegriffen werden:
after do
puts response . status
end
Hinweis: Sofern Sie nicht die body
-Methode verwenden, anstatt nur einen String aus den Routen zurückzugeben, ist der Body noch nicht im Nachfilter verfügbar, da er später generiert wird.
Filter nehmen optional ein Muster an, sodass sie nur dann ausgewertet werden, wenn der Anforderungspfad mit diesem Muster übereinstimmt:
before '/protected/*' do
authenticate!
end
after '/create/:slug' do | slug |
session [ :last_slug ] = slug
end
Wie Routen akzeptieren auch Filter Bedingungen:
before :agent => /Songbird/ do
# ...
end
after '/blog/*' , :host_name => 'example.com' do
# ...
end
Verwenden Sie die helpers
der obersten Ebene, um Hilfsmethoden zur Verwendung in Routenhandlern und Vorlagen zu definieren: