@@ -934,17 +1165,29 @@ Auf Variablen in Templates zugreifen
Templates werden in demselben Kontext ausgeführt wie Routen. Instanzvariablen
in Routen sind auch direkt im Template verfügbar:
-get '/:id' do
- @foo = Foo.find(params[:id])
- haml '%h1= @foo.name'
-end
-
+
+
+
+
get '/:id' do
+ @foo = Foo.find(params[:id])
+ haml '%h1= @foo.name'
+end
+
+
+
+
Oder durch einen expliziten Hash von lokalen Variablen:
-get '/:id' do
- foo = Foo.find(params[:id])
- haml '%h1= bar.name', :locals => { :bar => foo }
-end
-
+
+
+
+
get '/:id' do
+ foo = Foo.find(params[:id])
+ haml '%h1= bar.name', :locals => { :bar => foo }
+end
+
+
+
+
Dies wird typischerweise bei Verwendung von Subtemplates (partials) in anderen
Templates eingesetzt.
@@ -954,26 +1197,44 @@ Templates mit yield
und verschachtelte Layouts
Ein Layout ist üblicherweise ein Template, dass ein yield
aufruft. Ein solches
Template kann entweder wie oben beschrieben über die :template
option
verwendet werden oder mit einem Block gerendert werden:
-erb :post, :layout => false do
- erb :index
-end
-
+
+
+
+
erb :post, :layout => false do
+ erb :index
+end
+
+
+
+
Dieser Code entspricht weitestgehend erb :index, :layout => :post
.
Blöcke an Render-Methoden weiterzugeben ist besonders bei verschachtelten
Layouts hilfreich:
-erb :main_layout, :layout => false do
- erb :admin_layout do
- erb :user
- end
-end
-
+
+
+
+
erb :main_layout, :layout => false do
+ erb :admin_layout do
+ erb :user
+ end
+end
+
+
+
+
Der gleiche Effekt kann auch mit weniger Code erreicht werden:
-erb :admin_layout, :layout => :main_layout do
- erb :user
-end
-
-Zur Zeit nehmen folgende Renderer Blöcke an: erb
, haml
, liquid
, slim
+
+
+
+
erb :admin_layout, :layout => :main_layout do
+ erb :user
+end
+
+
+
+
+Zur Zeit nehmen folgende Renderer Blöcke an: erb
, haml
, liquid
, slim
und wlang
.
Das gleich gilt auch für die allgemeine render
Methode.
@@ -982,21 +1243,27 @@ Templates mit yield
und verschachtelte Layouts
Inline-Templates
Templates können auch am Ende der Datei definiert werden:
-require 'sinatra'
-get '/' do
- haml :index
-end
+
+
+
require 'sinatra'
+
+get '/' do
+ haml :index
+end
-__END__
+__END__
@@ layout
%html
= yield
@@ index
-%div.title Hallo Welt!!!!!
-
+%div.title Hallo Welt!!!!!
+
+
+
+
Anmerkung: Inline-Templates, die in der Datei definiert sind, die require
'sinatra'
aufruft, werden automatisch geladen. Um andere Inline-Templates in
anderen Dateien aufzurufen, muss explizit enable :inline_templates
verwendet
@@ -1006,47 +1273,71 @@
Inline-Templates
Benannte Templates
Templates können auch mit der Top-Level template
-Methode definiert werden:
-template :layout do
- "%html\n =yield\n"
-end
-
-template :index do
- '%div.title Hallo Welt!'
-end
-
-get '/' do
- haml :index
-end
-
-Wenn ein Template mit dem Namen "layout" existiert, wird es bei jedem Aufruf
+
+
+
+
template :layout do
+ "%html\n =yield\n"
+end
+
+template :index do
+ '%div.title Hallo Welt!'
+end
+
+get '/' do
+ haml :index
+end
+
+
+
+
+Wenn ein Template mit dem Namen “layout” existiert, wird es bei jedem Aufruf
verwendet. Durch :layout => false
kann das Ausführen verhindert werden:
-get '/' do
- haml :index, :layout => request.xhr?
-end
-
+
+
+
+
get '/' do
+ haml :index, :layout => request.xhr?
+end
+
+
+
+
Dateiendungen zuordnen
Um eine Dateiendung einer Template-Engine zuzuordnen, kann Tilt.register
genutzt werden. Wenn etwa die Dateiendung tt
für Textile-Templates genutzt
werden soll, lässt sich dies wie folgt bewerkstelligen:
-Tilt.register :tt, Tilt[:textile]
-
+
+
+
+
Tilt.register :tt, Tilt[:textile]
+
+
+
+
Eine eigene Template-Engine hinzufügen
Zu allererst muss die Engine bei Tilt registriert und danach eine
Rendering-Methode erstellt werden:
-Tilt.register :mtt, MeineTolleTemplateEngine
-helpers do
- def mtt(*args) render(:mtt, *args) end
-end
+
+
+
Tilt.register :mtt, MeineTolleTemplateEngine
+
+helpers do
+ def mtt(*args) render(:mtt, *args) end
+end
+
+get '/' do
+ mtt :index
+end
+
+
+
-get '/' do
- mtt :index
-end
-
Dieser Code rendert ./views/application.mtt
. Siehe
github.com/rtomayko/tilt, um mehr über
Tilt zu erfahren.
@@ -1058,133 +1349,228 @@ Filter
Routen, ausgeführt. So können etwa Request und Antwort geändert werden.
Gesetzte Instanzvariablen in Filtern können in Routen und Templates verwendet
werden:
-before do
- @note = 'Hi!'
- request.path_info = '/foo/bar/baz'
-end
-
-get '/foo/*' do
- @note #=> 'Hi!'
- params[:splat] #=> 'bar/baz'
-end
-
+
+
+
+
before do
+ @note = 'Hi!'
+ request.path_info = '/foo/bar/baz'
+end
+
+get '/foo/*' do
+ @note #=> 'Hi!'
+ params[:splat] #=> 'bar/baz'
+end
+
+
+
+
After-Filter werden nach jedem Request in demselben Kontext ausgeführt und
können ebenfalls Request und Antwort ändern. In Before-Filtern gesetzte
Instanzvariablen können in After-Filtern verwendet werden:
-after do
- puts response.status
-end
-
+
+
+
+
after do
+ puts response.status
+end
+
+
+
+
Filter können optional auch mit einem Muster ausgestattet werden, welches auf
den Request-Pfad passen muss, damit der Filter ausgeführt wird:
-before '/protected/*' do
- authenticate!
-end
-
-after '/create/:slug' do |slug|
- session[:last_slug] = slug
-end
-
+
+
+
+
before '/protected/*' do
+ authenticate!
+end
+
+after '/create/:slug' do |slug|
+ session[:last_slug] = slug
+end
+
+
+
+
Ähnlich wie Routen können Filter auch mit weiteren Bedingungen eingeschränkt
werden:
-before :agent => /Songbird/ do
- # ...
-end
-
-after '/blog/*', :host_name => 'example.com' do
- # ...
-end
-
+
+
+
+
before :agent => /Songbird/ do
+ # ...
+end
+
+after '/blog/*', :host_name => 'example.com' do
+ # ...
+end
+
+
+
+
Helfer
Durch die Top-Level helpers
-Methode werden sogenannte Helfer-Methoden
definiert, die in Routen und Templates verwendet werden können:
-helpers do
- def bar(name)
- "#{name}bar"
- end
-end
-
-get '/:name' do
- bar(params[:name])
-end
-
+
+
+
+
helpers do
+ def bar(name)
+ "#{name}bar"
+ end
+end
+
+get '/:name' do
+ bar(params[:name])
+end
+
+
+
+
Sessions verwenden
-
Sessions werden verwendet, um Zustände zwischen den Requests zu speichern. Sind
sie aktiviert, kann ein Session-Hash je Benutzer-Session verwendet werden:
-enable :sessions
-get '/' do
- "value = " << session[:value].inspect
-end
+
+
+
enable :sessions
+
+get '/' do
+ "value = " << session[:value].inspect
+end
+
+get '/:value' do
+ session[:value] = params[:value]
+end
+
+
+
-get '/:value' do
- session[:value] = params[:value]
-end
-
Beachte, dass enable :sessions
alle Daten in einem Cookie speichert. Unter
Umständen kann dies negative Effekte haben, z.B. verursachen viele Daten
höheren, teilweise überflüssigen Traffic. Um das zu vermeiden, kann eine Rack-
Session-Middleware verwendet werden. Dabei wird auf enable :sessions
verzichtet und die Middleware wie üblich im Programm eingebunden:
-use Rack::Session::Pool, :expire_after => 2592000
-get '/' do
- "value = " << session[:value].inspect
-end
+
+
+
use Rack::Session::Pool, :expire_after => 2592000
+
+get '/' do
+ "value = " << session[:value].inspect
+end
+
+get '/:value' do
+ session[:value] = params[:value]
+end
+
+
+
-get '/:value' do
- session[:value] = params[:value]
-end
-
Um die Sicherheit zu erhöhen, werden Cookies, die Session-Daten führen, mit
einem sogenannten Session-Secret signiert. Da sich dieses Geheimwort bei jedem
Neustart der Applikation automatisch ändert, ist es sinnvoll, ein eigenes zu
wählen, damit sich alle Instanzen der Applikation dasselbe Session-Secret
teilen:
-set :session_secret, 'super secret'
-
+
+
+
+
set :session_secret, 'super secret'
+
+
+
+
Zur weiteren Konfiguration kann man einen Hash mit Optionen in den sessions
Einstellungen ablegen.
-set :sessions, :domain => 'foo.com'
-
+
+
+
+
set :sessions, :domain => 'foo.com'
+
+
+
+
Anhalten
Zum sofortigen Stoppen eines Request in einem Filter oder einer Route:
-halt
-
+
+
+
Der Status kann beim Stoppen auch angegeben werden:
-halt 410
-
-Oder auch den Response-Body:
-halt 'Hier steht der Body'
-
-Oder beides:
-halt 401, 'verschwinde!'
-
-Sogar mit Headern:
-halt 402, {'Content-Type' => 'text/plain'}, 'Rache'
-
-Natürlich ist es auch möglich, ein Template mit halt
zu verwenden:
-halt erb(:error)
-
-
-Weiterspringen
+
+
+
+Oder auch den Response-Body:
+
+
+
+
halt 'Hier steht der Body'
+
+
+
+
+Oder beides:
+
+
+
+
halt 401, 'verschwinde!'
+
+
+
+
+Sogar mit Headern:
+
+
+
+
halt 402, {'Content-Type' => 'text/plain'}, 'Rache'
+
+
+
+
+Natürlich ist es auch möglich, ein Template mit halt
zu verwenden:
+
+
+
+
+Weiterspringen
Eine Route kann mittels pass
zu der nächsten passenden Route springen:
-get '/raten/:wer' do
- pass unless params[:wer] == 'Frank'
- 'Du hast mich!'
-end
-
-get '/raten/*' do
- 'Du hast mich nicht!'
-end
-
+
+
+
+
get '/raten/:wer' do
+ pass unless params[:wer] == 'Frank'
+ 'Du hast mich!'
+end
+
+get '/raten/*' do
+ 'Du hast mich nicht!'
+end
+
+
+
+
Der Block wird sofort verlassen und es wird nach der nächsten treffenden Route
gesucht. Ein 404-Fehler wird zurückgegeben, wenn kein treffendes Routen-Muster
gefunden wird.
@@ -1194,15 +1580,21 @@ Eine andere Route ansteuern
Manchmal entspricht pass
nicht den Anforderungen, wenn das Ergebnis einer
anderen Route gefordert wird. Um das zu erreichen, lässt sich call
nutzen:
-get '/foo' do
- status, headers, body = call env.merge("PATH_INFO" => '/bar')
- [status, headers, body.map(&:upcase)]
-end
-
-get '/bar' do
- "bar"
-end
-
+
+
+
+
get '/foo' do
+ status, headers, body = call env.merge("PATH_INFO" => '/bar')
+ [status, headers, body.map(&:upcase)]
+end
+
+get '/bar' do
+ "bar"
+end
+
+
+
+
Beachte, dass in dem oben angegeben Beispiel die Performance erheblich erhöht
werden kann, wenn "bar"
in eine Helfer-Methode umgewandelt wird, auf die
/foo
und /bar
zugreifen können.
@@ -1222,27 +1614,39 @@ Body, Status-Code und Header setzen
gesetzt wird. Das lässt sich mit der Helfer-Methode body
bewerkstelligen.
Wird body
verwendet, lässt sich der Body jederzeit über diese Methode
aufrufen:
-get '/foo' do
- body "bar"
-end
-
-after do
- puts body
-end
-
+
+
+
+
get '/foo' do
+ body "bar"
+end
+
+after do
+ puts body
+end
+
+
+
+
Ebenso ist es möglich, einen Block an body
weiterzureichen, der dann vom
Rack-Handler ausgeführt wird (lässt sich z.B. zur Umsetzung von Streaming
-einsetzen, siehe auch "Rückgabewerte").
+einsetzen, siehe auch “Rückgabewerte”).
Vergleichbar mit body
lassen sich auch Status-Code und Header setzen:
-get '/foo' do
- status 418
- headers \
- "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
- "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
- halt "Ich bin ein Teekesselchen"
-end
-
+
+
+
+
get '/foo' do
+ status 418
+ headers \
+ "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
+ "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
+ halt "Ich bin ein Teekesselchen"
+end
+
+
+
+
Genau wie bei body
liest ein Aufrufen von headers
oder status
ohne
Argumente den aktuellen Wert aus.
@@ -1254,16 +1658,22 @@ Response-Streams
Verbindung auch erst dann beenden und Daten so lange an den Client
zurückschicken, bis er die Verbindung abbricht. Für diese Fälle gibt es die
stream
-Helfer-Methode, die es einem erspart eigene Lösungen zu schreiben:
-get '/' do
- stream do |out|
- out << "Das ist ja mal wieder fanta -\n"
- sleep 0.5
- out << " (bitte warten…) \n"
- sleep 1
- out << "- stisch!\n"
- end
-end
-
+
+
+
+
get '/' do
+ stream do |out|
+ out << "Das ist ja mal wieder fanta -\n"
+ sleep 0.5
+ out << " (bitte warten…) \n"
+ sleep 1
+ out << "- stisch!\n"
+ end
+end
+
+
+
+
Damit lassen sich Streaming-APIs realisieren, sog.
Server Sent Events die als Basis für
WebSockets dienen. Ebenso können sie
@@ -1283,46 +1693,58 @@
Response-Streams
späteren Zeitpunkt nachholen. Die Funktion ist jedoch nur bei Event-gesteuerten
Serven wie Thin oder Rainbows möglich, andere Server werden trotzdem den Stream
beenden:
-# Durchgehende Anfrage (long polling)
-set :server, :thin
-connections = []
+
+
+
# Durchgehende Anfrage (long polling)
+
+set :server, :thin
+connections = []
+
+get '/subscribe' do
+ # Client-Registrierung beim Server, damit Events mitgeteilt werden können
+ stream(:keep_open) { |out| connections << out }
-get '/subscribe' do
- # Client-Registrierung beim Server, damit Events mitgeteilt werden können
- stream(:keep_open) { |out| connections << out }
+ # tote Verbindungen entfernen
+ connections.reject!(&:closed?)
- # tote Verbindungen entfernen
- connections.reject!(&:closed?)
+ # Rückmeldung
+ "Angemeldet"
+end
- # Rückmeldung
- "Angemeldet"
-end
+post '/message' do
+ connections.each do |out|
+ # Den Client über eine neue Nachricht in Kenntnis setzen
+ # notify client that a new message has arrived
+ out << params[:message] << "\n"
-post '/message' do
- connections.each do |out|
- # Den Client über eine neue Nachricht in Kenntnis setzen
- # notify client that a new message has arrived
- out << params[:message] << "\n"
+ # Den Client zur erneuten Verbindung auffordern
+ out.close
+ end
- # Den Client zur erneuten Verbindung auffordern
- out.close
- end
+ # Rückmeldung
+ "Mitteiling erhalten"
+end
+
+
+
- # Rückmeldung
- "Mitteiling erhalten"
-end
-
Logger
Im Geltungsbereich eines Request stellt die logger
Helfer-Methode eine Logger
Instanz zur Verfügung:
-get '/' do
- logger.info "es passiert gerade etwas"
- # ...
-end
-
+
+
+
+
get '/' do
+ logger.info "es passiert gerade etwas"
+ # ...
+end
+
+
+
+
Der Logger übernimmt dabei automatisch alle im Rack-Handler eingestellten
Log-Vorgaben. Ist Loggen ausgeschaltet, gibt die Methode ein Leerobjekt zurück.
In den Routen und Filtern muss man sich also nicht weiter darum kümmern.
@@ -1330,12 +1752,18 @@ Logger
Beachte, dass das Loggen standardmäßig nur für Sinatra::Application
voreingestellt ist. Wird über Sinatra::Base
vererbt, muss es erst aktiviert
werden:
-class MyApp < Sinatra::Base
- configure :production, :development do
- enable :logging
- end
-end
-
+
+
+
+
class MyApp < Sinatra::Base
+ configure :production, :development do
+ enable :logging
+ end
+end
+
+
+
+
Damit auch keine Middleware das Logging aktivieren kann, muss die logging
Einstellung auf nil
gesetzt werden. Das heißt aber auch, dass logger
in
diesem Fall nil
zurückgeben wird. Üblicherweise wird das eingesetzt, wenn ein
@@ -1348,23 +1776,41 @@
Mime-Types
Wenn send_file
oder statische Dateien verwendet werden, kann es vorkommen,
dass Sinatra den Mime-Typ nicht kennt. Registriert wird dieser mit mime_type
per Dateiendung:
-configure do
- mime_type :foo, 'text/foo'
-end
-
+
+
+
+
configure do
+ mime_type :foo, 'text/foo'
+end
+
+
+
+
Es kann aber auch der content_type
-Helfer verwendet werden:
-get '/' do
- content_type :foo
- "foo foo foo"
-end
-
+
+
+
+
get '/' do
+ content_type :foo
+ "foo foo foo"
+end
+
+
+
+
URLs generieren
Zum Generieren von URLs sollte die url
-Helfer-Methode genutzen werden, so z.B.
beim Einsatz von Haml:
-%a{:href => url('/foo')} foo
-
+
+
+
+
%a{:href => url('/foo')} foo
+
+
+
+
Soweit vorhanden, wird Rücksicht auf Proxys und Rack-Router genommen.
Diese Methode ist ebenso über das Alias to
zu erreichen (siehe Beispiel unten).
@@ -1374,41 +1820,71 @@ Browser-Umleitung
Eine Browser-Umleitung kann mithilfe der redirect
-Helfer-Methode erreicht
werden:
-get '/foo' do
- redirect to('/bar')
-end
-
+
+
+
+
get '/foo' do
+ redirect to('/bar')
+end
+
+
+
+
Weitere Parameter werden wie Argumente der halt
-Methode behandelt:
-redirect to('/bar'), 303
-redirect 'http://google.com', 'Hier bist du falsch'
-
+
+
+
+
redirect to('/bar'), 303
+redirect 'http://google.com', 'Hier bist du falsch'
+
+
+
+
Ebenso leicht lässt sich ein Schritt zurück mit dem Alias redirect back
erreichen:
-get '/foo' do
- "<a href='/bar'>mach was</a>"
-end
-
-get '/bar' do
- mach_was
- redirect back
-end
-
+
+
+
+
get '/foo' do
+ "<a href='/bar'>mach was</a>"
+end
+
+get '/bar' do
+ mach_was
+ redirect back
+end
+
+
+
+
Um Argumente an ein Redirect weiterzugeben, können sie entweder dem Query
übergeben:
-redirect to('/bar?summe=42')
-
+
+
+
+
redirect to('/bar?summe=42')
+
+
+
+
oder eine Session verwendet werden:
-enable :sessions
-get '/foo' do
- session[:secret] = 'foo'
- redirect to('/bar')
-end
+
+
+
enable :sessions
+
+get '/foo' do
+ session[:secret] = 'foo'
+ redirect to('/bar')
+end
+
+get '/bar' do
+ session[:secret]
+end
+
+
+
-get '/bar' do
- session[:secret]
-end
-
Cache einsetzen
@@ -1416,52 +1892,88 @@ Cache einsetzen
ordentliches HTTP-Caching.
Der Cache-Control-Header lässt sich ganz einfach einstellen:
-get '/' do
- cache_control :public
- "schon gecached!"
-end
-
+
+
+
+
get '/' do
+ cache_control :public
+ "schon gecached!"
+end
+
+
+
+
Profitipp: Caching im before-Filter aktivieren
-before do
- cache_control :public, :must_revalidate, :max_age => 60
-end
-
+
+
+
+
before do
+ cache_control :public, :must_revalidate, :max_age => 60
+end
+
+
+
+
Bei Verwendung der expires
-Helfermethode zum Setzen des gleichnamigen Headers,
wird Cache-Control
automatisch eigestellt:
-before do
- expires 500, :public, :must_revalidate
-end
-
+
+
+
+
before do
+ expires 500, :public, :must_revalidate
+end
+
+
+
+
Um alles richtig zu machen, sollten auch etag
oder last_modified
verwendet
werden. Es wird empfohlen, dass diese Helfer aufgerufen werden bevor die
eigentliche Arbeit anfängt, da sie sofort eine Antwort senden, wenn der Client
eine aktuelle Version im Cache vorhält:
-get '/article/:id' do
- @article = Article.find params[:id]
- last_modified @article.updated_at
- etag @article.sha1
- erb :article
-end
-
+
+
+
+
get '/article/:id' do
+ @article = Article.find params[:id]
+ last_modified @article.updated_at
+ etag @article.sha1
+ erb :article
+end
+
+
+
+
ebenso ist es möglich einen
schwachen ETag zu verwenden:
-etag @article.sha1, :weak
-
+
+
+
+
etag @article.sha1, :weak
+
+
+
+
Diese Helfer führen nicht das eigentliche Caching aus, sondern geben die dafür
notwendigen Informationen an den Cache weiter. Für schnelle Reverse-Proxy
Cache-Lösungen bietet sich z.B.
rack-cache an:
-require "rack/cache"
-require "sinatra"
-use Rack::Cache
+
+
+
require "rack/cache"
+require "sinatra"
+
+use Rack::Cache
+
+get '/' do
+ cache_control :public, :max_age => 36000
+ sleep 5
+ "hello"
+end
+
+
+
-get '/' do
- cache_control :public, :max_age => 36000
- sleep 5
- "hello"
-end
-
Um den Cache-Control
-Header mit Informationen zu versorgen, verwendet man die
:static_cache_control
-Einstellung (s.u.).
@@ -1472,27 +1984,51 @@ Cache einsetzen
wobei anderen Ressourcen (besipielsweise bei post), als neue Ressourcen
behandelt werden. Dieses Verhalten lässt sich mit der :new_resource
Option
ändern:
-get '/create' do
- etag '', :new_resource => true
- Article.create
- erb :new_article
-end
-
+
+
+
+
get '/create' do
+ etag '', :new_resource => true
+ Article.create
+ erb :new_article
+end
+
+
+
+
Soll das schwache ETag trotzdem verwendet werden, verwendet man die :kind
Option:
-etag '', :new_resource => true, :kind => :weak
-
+
+
+
+
etag '', :new_resource => true, :kind => :weak
+
+
+
+
Dateien versenden
Zum Versenden von Dateien kann die send_file
-Helfer-Methode verwendet werden:
-get '/' do
- send_file 'foo.png'
-end
-
+
+
+
+
get '/' do
+ send_file 'foo.png'
+end
+
+
+
+
Für send_file
stehen einige Hash-Optionen zur Verfügung:
-send_file 'foo.png', :type => :jpg
-
+
+
+
+
send_file 'foo.png', :type => :jpg
+
+
+
+
- filename
- Dateiname als Response. Standardwert ist der eigentliche Dateiname.
@@ -1522,131 +2058,191 @@ Das Request-Objekt
Auf das request
-Objekt der eigehenden Anfrage kann vom Anfrage-Scope aus
zugegriffen werden:
-# App läuft unter http://example.com/example
-get '/foo' do
- t = %w[text/css text/html application/javascript]
- request.accept # ['text/html', '*/*']
- request.accept? 'text/xml' # true
- request.preferred_type(t) # 'text/html'
- request.body # Request-Body des Client (siehe unten)
- request.scheme # "http"
- request.script_name # "/example"
- request.path_info # "/foo"
- request.port # 80
- request.request_method # "GET"
- request.query_string # ""
- request.content_length # Länge des request.body
- request.media_type # Medientypus von request.body
- request.host # "example.com"
- request.get? # true (ähnliche Methoden für andere Verben)
- request.form_data? # false
- request["irgendein_param"] # Wert von einem Parameter; [] ist die Kurzform für den params Hash
- request.referrer # Der Referrer des Clients oder '/'
- request.user_agent # User-Agent (verwendet in der :agent Bedingung)
- request.cookies # Hash des Browser-Cookies
- request.xhr? # Ist das hier ein Ajax-Request?
- request.url # "http://example.com/example/foo"
- request.path # "/example/foo"
- request.ip # IP-Adresse des Clients
- request.secure? # false (true wenn SSL)
- request.forwarded? # true (Wenn es hinter einem Reverse-Proxy verwendet wird)
- request.env # vollständiger env-Hash von Rack übergeben
-end
-
+
+
+
+
# App läuft unter http://example.com/example
+get '/foo' do
+ t = %w[text/css text/html application/javascript]
+ request.accept # ['text/html', '*/*']
+ request.accept? 'text/xml' # true
+ request.preferred_type(t) # 'text/html'
+ request.body # Request-Body des Client (siehe unten)
+ request.scheme # "http"
+ request.script_name # "/example"
+ request.path_info # "/foo"
+ request.port # 80
+ request.request_method # "GET"
+ request.query_string # ""
+ request.content_length # Länge des request.body
+ request.media_type # Medientypus von request.body
+ request.host # "example.com"
+ request.get? # true (ähnliche Methoden für andere Verben)
+ request.form_data? # false
+ request["irgendein_param"] # Wert von einem Parameter; [] ist die Kurzform für den params Hash
+ request.referrer # Der Referrer des Clients oder '/'
+ request.user_agent # User-Agent (verwendet in der :agent Bedingung)
+ request.cookies # Hash des Browser-Cookies
+ request.xhr? # Ist das hier ein Ajax-Request?
+ request.url # "http://example.com/example/foo"
+ request.path # "/example/foo"
+ request.ip # IP-Adresse des Clients
+ request.secure? # false (true wenn SSL)
+ request.forwarded? # true (Wenn es hinter einem Reverse-Proxy verwendet wird)
+ request.env # vollständiger env-Hash von Rack übergeben
+end
+
+
+
+
Manche Optionen, wie etwa script_name
oder path_info
, sind auch
schreibbar:
-before { request.path_info = "/" }
-get "/" do
- "Alle Anfragen kommen hier an!"
-end
-
+
+
+
before { request.path_info = "/" }
+
+get "/" do
+ "Alle Anfragen kommen hier an!"
+end
+
+
+
+
Der request.body
ist ein IO- oder StringIO-Objekt:
-post "/api" do
- request.body.rewind # falls schon jemand davon gelesen hat
- daten = JSON.parse request.body.read
- "Hallo #{daten['name']}!"
-end
-
+
+
+
+
post "/api" do
+ request.body.rewind # falls schon jemand davon gelesen hat
+ daten = JSON.parse request.body.read
+ "Hallo #{daten['name']}!"
+end
+
+
+
+
Anhänge
Damit der Browser erkennt, dass ein Response gespeichert und nicht im Browser
angezeigt werden soll, kann der attachment
-Helfer verwendet werden:
-get '/' do
- attachment
- "Speichern!"
-end
-
+
+
+
+
get '/' do
+ attachment
+ "Speichern!"
+end
+
+
+
+
Ebenso kann eine Dateiname als Parameter hinzugefügt werden:
-get '/' do
- attachment "info.txt"
- "Speichern!"
-end
-
+
+
+
+
get '/' do
+ attachment "info.txt"
+ "Speichern!"
+end
+
+
+
+
Umgang mit Datum und Zeit
Sinatra bietet eine time_for
-Helfer-Methode, die aus einem gegebenen Wert ein
Time-Objekt generiert. Ebenso kann sie nach DateTime
, Date
und ähnliche
Klassen konvertieren:
-get '/' do
- pass if Time.now > time_for('Dec 23, 2012')
- "noch Zeit"
-end
-
+
+
+
+
get '/' do
+ pass if Time.now > time_for('Dec 23, 2012')
+ "noch Zeit"
+end
+
+
+
+
Diese Methode wird intern für +expires, last_modiefied
und ihresgleichen
verwendet. Mit ein paar Handgriffen lässt sich diese Methode also in ihrem
Verhalten erweitern, indem man time_for
in der eigenen Applikation
überschreibt:
-helpers do
- def time_for(value)
- case value
- when :yesterday then Time.now - 24*60*60
- when :tomorrow then Time.now + 24*60*60
- else super
- end
- end
-end
-
-get '/' do
- last_modified :yesterday
- expires :tomorrow
- "Hallo"
-end
-
+
+
+
+
helpers do
+ def time_for(value)
+ case value
+ when :yesterday then Time.now - 24*60*60
+ when :tomorrow then Time.now + 24*60*60
+ else super
+ end
+ end
+end
+
+get '/' do
+ last_modified :yesterday
+ expires :tomorrow
+ "Hallo"
+end
+
+
+
+
Nachschlagen von Template-Dateien
Die find_template
-Helfer-Methode wird genutzt, um Template-Dateien zum Rendern
aufzufinden:
-find_template settings.views, 'foo', Tilt[:haml] do |file|
- puts "könnte diese hier sein: #{file}"
-end
-
+
+
+
+
find_template settings.views, 'foo', Tilt[:haml] do |file|
+ puts "könnte diese hier sein: #{file}"
+end
+
+
+
+
Das ist zwar nicht wirklich brauchbar, aber wenn man sie überschreibt, kann sie
nützlich werden, um eigene Nachschlage-Mechanismen einzubauen. Zum Beispiel
dann, wenn mehr als nur ein view-Verzeichnis verwendet werden soll:
-set :views, ['views', 'templates']
-
-helpers do
- def find_template(views, name, engine, &block)
- Array(views).each { |v| super(v, name, engine, &block) }
- end
-end
-
+
+
+
+
set :views, ['views', 'templates']
+
+helpers do
+ def find_template(views, name, engine, &block)
+ Array(views).each { |v| super(v, name, engine, &block) }
+ end
+end
+
+
+
+
Ein anderes Beispiel wäre, verschiedene Vereichnisse für verschiedene Engines
zu verwenden:
-set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
-
-helpers do
- def find_template(views, name, engine, &block)
- _, folder = views.detect { |k,v| engine == Tilt[k] }
- folder ||= views[:default]
- super(folder, name, engine, &block)
- end
-end
-
+
+
+
+
set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
+
+helpers do
+ def find_template(views, name, engine, &block)
+ _, folder = views.detect { |k,v| engine == Tilt[k] }
+ folder ||= views[:default]
+ super(folder, name, engine, &block)
+ end
+end
+
+
+
+
Ebensogut könnte eine Extension aber auch geschrieben und mit anderen geteilt
werden!
@@ -1662,45 +2258,69 @@ Nachschlagen von Template-Dateien
Konfiguration
Wird einmal beim Starten in jedweder Umgebung ausgeführt:
-configure do
- # setze eine Option
- set :option, 'wert'
- # setze mehrere Optionen
- set :a => 1, :b => 2
+
+
+
configure do
+ # setze eine Option
+ set :option, 'wert'
+
+ # setze mehrere Optionen
+ set :a => 1, :b => 2
- # das gleiche wie `set :option, true`
- enable :option
+ # das gleiche wie `set :option, true`
+ enable :option
- # das gleiche wie `set :option, false`
- disable :option
+ # das gleiche wie `set :option, false`
+ disable :option
+
+ # dynamische Einstellungen mit Blöcken
+ set(:css_dir) { File.join(views, 'css') }
+end
+
+
+
- # dynamische Einstellungen mit Blöcken
- set(:css_dir) { File.join(views, 'css') }
-end
-
Läuft nur, wenn die Umgebung (RACK_ENV-Umgebungsvariable) auf :production
gesetzt ist:
-configure :production do
- ...
-end
-
+
+
+
+
configure :production do
+ ...
+end
+
+
+
+
Läuft nur, wenn die Umgebung auf :production
oder auf :test
gesetzt ist:
-configure :production, :test do
- ...
-end
-
+
+
+
+
configure :production, :test do
+ ...
+end
+
+
+
+
Diese Einstellungen sind über settings
erreichbar:
-configure do
- set :foo, 'bar'
-end
-
-get '/' do
- settings.foo? # => true
- settings.foo # => 'bar'
- ...
-end
-
+
+
+
+
configure do
+ set :foo, 'bar'
+end
+
+get '/' do
+ settings.foo? # => true
+ settings.foo # => 'bar'
+ ...
+end
+
+
+
+
Einstellung des Angriffsschutzes
@@ -1710,18 +2330,34 @@ Einstellung des Angriffsschutzes
lässt sich selbstverständlich deaktivieren, der damit verbundene
Geschwindigkeitszuwachs steht aber in keinem Verhätnis zu den möglichen
Risiken.
-disable :protection
-
+
+
+
Um einen bestimmten Schutzmechanismus zu deaktivieren, fügt man protection
einen Hash mit Optionen hinzu:
-set :protection, :except => :path_traversal
-
+
+
+
+
set :protection, :except => :path_traversal
+
+
+
+
Neben Strings akzeptiert :except
auch Arrays, um gleich mehrere
Schutzmechanismen zu deaktivieren:
-set :protection, :except => [:path_traversal, :session_hijacking]
-
-
-Mögliche Einstellungen
+
+
+
+
set :protection, :except => [:path_traversal, :session_hijacking]
+
+
+
+## Mögliche Einstellungen
- absolute_redirects
@@ -1736,9 +2372,8 @@ Mögliche Einstellungen
- add_charsets
- Mime-Types werden hier automatisch der Helfer-Methode
content_type zugeordnet. Es empfielt sich, Werte hinzuzufügen statt
- sie zu überschreiben: settings.add_charsets
-
-
+ sie zu überschreiben: settings.add_charsets << "application/foobar"
+
- app_file
- Pfad zur Hauptdatei der Applikation. Wird verwendet, um das Wurzel-,
@@ -1869,8 +2504,10 @@
Umgebungen
Um die Anwendung in einer anderen Umgebung auszuführen kann man die -e
Option verwenden:
-ruby my_app.rb -e [ENVIRONMENT]
-
+
+ruby my_app.rb -e [ENVIRONMENT]
+
+
In der Anwendung kann man die die Methoden development?
, test?
und
production?
verwenden, um die aktuelle Umgebung zu erfahren.
@@ -1885,47 +2522,85 @@ Nicht gefunden
Wenn eine Sinatra::NotFound
-Exception geworfen wird oder der Statuscode 404
ist, wird der not_found
-Handler ausgeführt:
-not_found do
- 'Seite kann nirgendwo gefunden werden.'
-end
-
+
+
+
+
not_found do
+ 'Seite kann nirgendwo gefunden werden.'
+end
+
+
+
+
Fehler
Der error
-Handler wird immer ausgeführt, wenn eine Exception in einem
Routen-Block oder in einem Filter geworfen wurde. Die Exception kann über die
sinatra.error
-Rack-Variable angesprochen werden:
-error do
- 'Entschuldige, es gab einen hässlichen Fehler - ' + env['sinatra.error'].name
-end
-
+
+
+
+
error do
+ 'Entschuldige, es gab einen hässlichen Fehler - ' + env['sinatra.error'].name
+end
+
+
+
+
Benutzerdefinierte Fehler:
-error MeinFehler do
- 'Au weia, ' + env['sinatra.error'].message
-end
-
+
+
+
+
error MeinFehler do
+ 'Au weia, ' + env['sinatra.error'].message
+end
+
+
+
+
Dann, wenn das passiert:
-get '/' do
- raise MeinFehler, 'etwas Schlimmes ist passiert'
-end
-
+
+
+
+
get '/' do
+ raise MeinFehler, 'etwas Schlimmes ist passiert'
+end
+
+
+
+
bekommt man dieses:
-Au weia, etwas Schlimmes ist passiert
-
+
+Au weia, etwas Schlimmes ist passiert
+
+
Alternativ kann ein Error-Handler auch für einen Status-Code definiert werden:
-error 403 do
- 'Zugriff verboten'
-end
-
-get '/geheim' do
- 403
-end
-
+
+
+
+
error 403 do
+ 'Zugriff verboten'
+end
+
+get '/geheim' do
+ 403
+end
+
+
+
+
Oder ein Status-Code-Bereich:
-error 400..510 do
- 'Hallo?'
-end
-
+
+
+
+
error 400..510 do
+ 'Hallo?'
+end
+
+
+
+
Sinatra setzt verschiedene not_found
- und error
-Handler in der
Development-Umgebung ein, um hilfreiche Debugging Informationen und Stack Traces
anzuzeigen.
@@ -1941,24 +2616,36 @@ Rack-Middleware
Sinatra macht das Erstellen von Middleware-Verkettungen mit der
Top-Level-Methode use
zu einem Kinderspiel:
-require 'sinatra'
-require 'meine_middleware'
-use Rack::Lint
-use MeineMiddleware
+
+
+
require 'sinatra'
+require 'meine_middleware'
+
+use Rack::Lint
+use MeineMiddleware
+
+get '/hallo' do
+ 'Hallo Welt'
+end
+
+
+
-get '/hallo' do
- 'Hallo Welt'
-end
-
Die Semantik von use
entspricht der gleichnamigen Methode der
Rack::Builder-DSL
(meist verwendet in Rackup-Dateien). Ein Beispiel dafür ist, dass die
use
-Methode mehrere/verschiedene Argumente und auch Blöcke entgegennimmt:
-use Rack::Auth::Basic do |username, password|
- username == 'admin' && password == 'geheim'
-end
-
+
+
+
+
use Rack::Auth::Basic do |username, password|
+ username == 'admin' && password == 'geheim'
+end
+
+
+
+
Rack bietet eine Vielzahl von Standard-Middlewares für Logging, Debugging,
URL-Routing, Authentifizierung und Session-Verarbeitung. Sinatra verwendet
viele von diesen Komponenten automatisch, abhängig von der Konfiguration. So
@@ -1976,33 +2663,39 @@
Testen
Sinatra-Tests können mit jedem auf Rack aufbauendem Test-Framework geschrieben
werden. Rack::Test
wird empfohlen:
-require 'my_sinatra_app'
-require 'test/unit'
-require 'rack/test'
-
-class MyAppTest < Test::Unit::TestCase
- include Rack::Test::Methods
-
- def app
- Sinatra::Application
- end
-
- def test_my_default
- get '/'
- assert_equal 'Hallo Welt!', last_response.body
- end
-
- def test_with_params
- get '/meet', :name => 'Frank'
- assert_equal 'Hallo Frank!', last_response.body
- end
-
- def test_with_rack_env
- get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
- assert_equal "Du verwendest Songbird!", last_response.body
- end
-end
-
+
+
+
+
require 'my_sinatra_app'
+require 'test/unit'
+require 'rack/test'
+
+class MyAppTest < Test::Unit::TestCase
+ include Rack::Test::Methods
+
+ def app
+ Sinatra::Application
+ end
+
+ def test_my_default
+ get '/'
+ assert_equal 'Hallo Welt!', last_response.body
+ end
+
+ def test_with_params
+ get '/meet', :name => 'Frank'
+ assert_equal 'Hallo Frank!', last_response.body
+ end
+
+ def test_with_rack_env
+ get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
+ assert_equal "Du verwendest Songbird!", last_response.body
+ end
+end
+
+
+
+
Hinweis: Wird Sinatra modular verwendet, muss Sinatra::Application mit
dem Namen der Applikations-Klasse ersetzt werden.
@@ -2017,32 +2710,44 @@ Testen
sie z.B. bei einer einzelnen Anwendungsdatei, ./public
und ./views
Ordner,
Logging, Exception-Detail-Seite, usw.). Genau hier kommt Sinatra::Base
ins
Spiel:
-require 'sinatra/base'
-class MyApp < Sinatra::Base
- set :sessions, true
- set :foo, 'bar'
+
+
+
require 'sinatra/base'
+
+class MyApp < Sinatra::Base
+ set :sessions, true
+ set :foo, 'bar'
+
+ get '/' do
+ 'Hallo Welt!'
+ end
+end
+
+
+
- get '/' do
- 'Hallo Welt!'
- end
-end
-
Die MyApp-Klasse ist eine unabhängige Rack-Komponente, die als Middleware,
Endpunkt oder via Rails Metal verwendet werden kann. Verwendet wird sie durch
use
oder run
von einer Rackup-config.ru
-Datei oder als Server-Komponente
einer Bibliothek:
-MyApp.run! :host => 'localhost', :port => 9090
-
+
+
+
+
MyApp.run! :host => 'localhost', :port => 9090
+
+
+
+
Die Methoden der Sinatra::Base
-Subklasse sind genau dieselben wie die der
Top-Level-DSL. Die meisten Top-Level-Anwendungen können mit nur zwei
Veränderungen zu Sinatra::Base
konvertiert werden:
-- Die Datei sollte
require 'sinatra/base'
anstelle von require
+- Die Datei sollte
require 'sinatra/base'
anstelle von require
'sinatra/base'
aufrufen, ansonsten werden alle von Sinatras DSL-Methoden
in den Top-Level-Namespace importiert.
-- Alle Routen, Error-Handler, Filter und Optionen der Applikation müssen in
+
- Alle Routen, Error-Handler, Filter und Optionen der Applikation müssen in
einer Subklasse von
Sinatra::Base
definiert werden.
Sinatra::Base
ist ein unbeschriebenes Blatt. Die meisten Optionen sind per
@@ -2108,53 +2813,81 @@
Eine modulare Applikation bereitstellen
Es gibt zwei übliche Wege, eine modulare Anwendung zu starten. Zum einen über
run!
:
-# mein_app.rb
-require 'sinatra/base'
-class MeinApp < Sinatra::Base
- # ... Anwendungscode hierhin ...
+
+
+
# mein_app.rb
+require 'sinatra/base'
+
+class MeinApp < Sinatra::Base
+ # ... Anwendungscode hierhin ...
+
+ # starte den Server, wenn die Ruby-Datei direkt ausgeführt wird
+ run! if app_file == $0
+end
+
+
+
- # starte den Server, wenn die Ruby-Datei direkt ausgeführt wird
- run! if app_file == $0
-end
-
Starte mit:
-ruby mein_app.rb
-
+
+ruby mein_app.rb
+
+
Oder über eine config.ru
-Datei, die es erlaubt, einen beliebigen
Rack-Handler zu verwenden:
-# config.ru (mit rackup starten)
-require './mein_app'
-run MeineApp
-
+
+
+
+
# config.ru (mit rackup starten)
+require './mein_app'
+run MeineApp
+
+
+
+
Starte:
-rackup -p 4567
-
+
+rackup -p 4567
+
+
Eine klassische Anwendung mit einer config.ru verwenden
Schreibe eine Anwendungsdatei:
-# app.rb
-require 'sinatra'
-get '/' do
- 'Hallo Welt!'
-end
-
+
+
+
# app.rb
+require 'sinatra'
+
+get '/' do
+ 'Hallo Welt!'
+end
+
+
+
+
sowie eine dazugehörige config.ru
-Datei:
-require './app'
-run Sinatra::Application
-
+
+
+
+
require './app'
+run Sinatra::Application
+
+
+
+
Wann sollte eine config.ru-Datei verwendet werden?
Anzeichen dafür, dass eine config.ru
-Datei gebraucht wird:
-- Es soll ein anderer Rack-Handler verwendet werden (Passenger, Unicorn,
-Heroku, ...).
-- Es gibt mehr als nur eine Subklasse von
Sinatra::Base
.
-- Sinatra soll als Middleware verwendet werden, nicht als Endpunkt.
+- Es soll ein anderer Rack-Handler verwendet werden (Passenger, Unicorn,
+Heroku, …).
+ - Es gibt mehr als nur eine Subklasse von
Sinatra::Base
.
+ - Sinatra soll als Middleware verwendet werden, nicht als Endpunkt.
Es gibt keinen Grund, eine config.ru
-Datei zu verwenden, nur weil eine
Anwendung im modularen Stil betrieben werden soll. Ebenso wird keine Anwendung
@@ -2167,75 +2900,99 @@ Sinatra als Middleware nutzen
kann außerdem jede Sinatra-Anwendung selbst als Middleware vor jeden
beliebigen Rack-Endpunkt gehangen werden. Bei diesem Endpunkt muss es sich
nicht um eine andere Sinatra-Anwendung handeln, es kann jede andere
-Rack-Anwendung sein (Rails/Ramaze/Camping/...):
-require 'sinatra/base'
-
-class LoginScreen < Sinatra::Base
- enable :sessions
-
- get('/login') { haml :login }
-
- post('/login') do
- if params[:name] == 'admin' && params[:password] == 'admin'
- session['user_name'] = params[:name]
- else
- redirect '/login'
- end
- end
-end
-
-class MyApp < Sinatra::Base
- # Middleware wird vor Filtern ausgeführt
- use LoginScreen
-
- before do
- unless session['user_name']
- halt "Zugriff verweigert, bitte <a href='/login'>einloggen</a>."
- end
- end
-
- get('/') { "Hallo #{session['user_name']}." }
-end
-
+Rack-Anwendung sein (Rails/Ramaze/Camping/…):
+
+
+
+
require 'sinatra/base'
+
+class LoginScreen < Sinatra::Base
+ enable :sessions
+
+ get('/login') { haml :login }
+
+ post('/login') do
+ if params[:name] == 'admin' && params[:password] == 'admin'
+ session['user_name'] = params[:name]
+ else
+ redirect '/login'
+ end
+ end
+end
+
+class MyApp < Sinatra::Base
+ # Middleware wird vor Filtern ausgeführt
+ use LoginScreen
+
+ before do
+ unless session['user_name']
+ halt "Zugriff verweigert, bitte <a href='/login'>einloggen</a>."
+ end
+ end
+
+ get('/') { "Hallo #{session['user_name']}." }
+end
+
+
+
+
Dynamische Applikationserstellung
Manche Situationen erfordern die Erstellung neuer Applikationen zur Laufzeit,
ohne dass sie einer Konstanten zugeordnet werden. Dies lässt sich mit
Sinatra.new
erreichen:
-require 'sinatra/base'
-my_app = Sinatra.new { get('/') { "hallo" } }
-my_app.run!
-
+
+
+
+
require 'sinatra/base'
+my_app = Sinatra.new { get('/') { "hallo" } }
+my_app.run!
+
+
+
+
Die Applikation kann mit Hilfe eines optionalen Parameters erstellt werden:
-# config.ru
-require 'sinatra/base'
-
-controller = Sinatra.new do
- enable :logging
- helpers MyHelpers
-end
-
-map('/a') do
- run Sinatra.new(controller) { get('/') { 'a' } }
-end
-
-map('/b') do
- run Sinatra.new(controller) { get('/') { 'b' } }
-end
-
+
+
+
+
# config.ru
+require 'sinatra/base'
+
+controller = Sinatra.new do
+ enable :logging
+ helpers MyHelpers
+end
+
+map('/a') do
+ run Sinatra.new(controller) { get('/') { 'a' } }
+end
+
+map('/b') do
+ run Sinatra.new(controller) { get('/') { 'b' } }
+end
+
+
+
+
Das ist besonders dann interessant, wenn Sinatra-Erweiterungen getestet werden
oder Sinatra in einer Bibliothek Verwendung findet.
Ebenso lassen sich damit hervorragend Sinatra-Middlewares erstellen:
-require 'sinatra/base'
-use Sinatra do
- get('/') { ... }
-end
+
+
+
require 'sinatra/base'
+
+use Sinatra do
+ get('/') { ... }
+end
+
+run RailsProject::Application
+
+
+
-run RailsProject::Application
-
Geltungsbereich und Bindung
@@ -2254,31 +3011,38 @@ Anwendungs- oder Klassen-Scope
wird.
Optionen, die via set
gesetzt werden, sind Methoden auf Klassenebene:
-class MyApp < Sinatra::Base
- # Hey, ich bin im Anwendungsscope!
- set :foo, 42
- foo # => 42
-
- get '/foo' do
- # Hey, ich bin nicht mehr im Anwendungs-Scope!
- end
-end
-
+
+
+
+
class MyApp < Sinatra::Base
+ # Hey, ich bin im Anwendungsscope!
+ set :foo, 42
+ foo # => 42
+
+ get '/foo' do
+ # Hey, ich bin nicht mehr im Anwendungs-Scope!
+ end
+end
+
+
+
+
Im Anwendungs-Scope befindet man sich:
-- In der Anwendungs-Klasse.
-- In Methoden, die von Erweiterungen definiert werden.
-- Im Block, der an
helpers
übergeben wird.
-- In Procs und Blöcken, die an
set
übergeben werden.
-- Der an
Sinatra.new
übergebene Block
+- In der Anwendungs-Klasse.
+ - In Methoden, die von Erweiterungen definiert werden.
+ - Im Block, der an
helpers
übergeben wird.
+ - In Procs und Blöcken, die an
set
übergeben werden.
+ - Der an
Sinatra.new
übergebene Block
Auf das Scope-Objekt (die Klasse) kann wie folgt zugegriffen werden:
-- Über das Objekt, das an den
configure
-Block übergeben wird (configure {
+- Über das Objekt, das an den
configure
-Block übergeben wird (configure {
|c| ... }
).
--
settings
aus den anderen Scopes heraus.
+ -
+
settings
aus den anderen Scopes heraus.
Anfrage- oder Instanz-Scope
@@ -2288,28 +3052,34 @@ Anfrage- oder Instanz-Scope
kann auf request
oder session
zugegriffen und Methoden wie erb
oder
haml
aufgerufen werden. Außerdem kann mit der settings
-Method auf den
Anwendungs-Scope zugegriffen werden:
-class MyApp < Sinatra::Base
- # Hey, ich bin im Anwendungs-Scope!
- get '/neue_route/:name' do
- # Anfrage-Scope für '/neue_route/:name'
- @value = 42
-
- settings.get "/#{params[:name]}" do
- # Anfrage-Scope für "/#{params[:name]}"
- @value # => nil (nicht dieselbe Anfrage)
- end
-
- "Route definiert!"
- end
-end
-
+
+
+
+
class MyApp < Sinatra::Base
+ # Hey, ich bin im Anwendungs-Scope!
+ get '/neue_route/:name' do
+ # Anfrage-Scope für '/neue_route/:name'
+ @value = 42
+
+ settings.get "/#{params[:name]}" do
+ # Anfrage-Scope für "/#{params[:name]}"
+ @value # => nil (nicht dieselbe Anfrage)
+ end
+
+ "Route definiert!"
+ end
+end
+
+
+
+
Im Anfrage-Scope befindet man sich:
-- In get/head/post/put/delete-Blöcken
-- In before/after-Filtern
-- In Helfer-Methoden
-- In Templates
+- In get/head/post/put/delete-Blöcken
+ - In before/after-Filtern
+ - In Helfer-Methoden
+ - In Templates
Delegation-Scope
@@ -2325,8 +3095,8 @@ Delegation-Scope
Im Delegation-Scop befindet man sich:
-- Im Top-Level, wenn
require 'sinatra'
aufgerufen wurde.
-- In einem Objekt, das mit dem
Sinatra::Delegator
-Mixin erweitert wurde.
+- Im Top-Level, wenn
require 'sinatra'
aufgerufen wurde.
+ - In einem Objekt, das mit dem
Sinatra::Delegator
-Mixin erweitert wurde.
Schau am besten im Code nach: Hier ist Sinatra::Delegator
mixin definiert und wird in den [globalen Namespace
@@ -2336,16 +3106,20 @@
Delegation-Scope
Kommandozeile
Sinatra-Anwendungen können direkt von der Kommandozeile aus gestartet werden:
-ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-h HOST] [-s HANDLER]
-
+
+ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-h HOST] [-s HANDLER]
+
+
Die Optionen sind:
--h # Hilfe
+
+-h # Hilfe
-p # Port setzen (Standard ist 4567)
-h # Host setzen (Standard ist 0.0.0.0)
-e # Umgebung setzen (Standard ist development)
-s # Rack-Server/Handler setzen (Standard ist thin)
-x # Mutex-Lock einschalten (Standard ist off)
-
+
+
Systemanforderungen
@@ -2393,10 +3167,10 @@ Systemanforderungen
Sinatra unterstützt, funktionieren aber normalerweise:
-- Ruby Enterprise Edition
-- Ältere Versionen von JRuby und Rubinius
-- MacRuby, Maglev, IronRuby
-- Ruby 1.9.0 und 1.9.1 (wird jedoch nicht empfohlen, s.o.)
+- Ruby Enterprise Edition
+ - Ältere Versionen von JRuby und Rubinius
+ - MacRuby, Maglev, IronRuby
+ - Ruby 1.9.0 und 1.9.1 (wird jedoch nicht empfohlen, s.o.)
Nicht offiziell unterstützt bedeutet, dass wenn Sachen nicht funktionieren,
wir davon ausgehen, dass es nicht an Sinatra sondern an der jeweiligen
@@ -2419,8 +3193,10 @@
Der neuste Stand (The Bleeding Edge)
Um auf dem neusten Stand zu bleiben, kann der Master-Branch verwendet werden.
Er sollte recht stabil sein. Ebenso gibt es von Zeit zu Zeit prerelease Gems,
die so installiert werden:
-gem install sinatra --pre
-
+
+gem install sinatra --pre
+
+
Mit Bundler
@@ -2429,61 +3205,84 @@ Mit Bundler
nachfolgenden Weg.
Soweit Bundler noch nicht installiert ist:
-gem install bundler
-
+
+gem install bundler
+
+
Anschließend wird eine Gemfile
-Datei im Projektverzeichnis mit folgendem
Inhalt erstellt:
-source :rubygems
-gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
-# evtl. andere Abhängigkeiten
-gem 'haml' # z.B. wenn du Haml verwendest...
-gem 'activerecord', '~> 3.0' # ...oder ActiveRecord 3.x
-
+
+
+
source :rubygems
+gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
+
+# evtl. andere Abhängigkeiten
+gem 'haml' # z.B. wenn du Haml verwendest...
+gem 'activerecord', '~> 3.0' # ...oder ActiveRecord 3.x
+
+
+
+
Beachte: Hier sollten alle Abhängigkeiten eingetragen werden. Sinatras eigene,
direkte Abhängigkeiten (Tilt und Rack) werden von Bundler automatisch aus dem
Gemfile von Sinatra hinzugefügt.
Jetzt kannst du deine Applikation starten:
-bundle exec ruby myapp.rb
-
+
+bundle exec ruby myapp.rb
+
+
Eigenes Repository
-
Um auf dem neuesten Stand von Sinatras Code zu sein, kann eine lokale Kopie
angelegt werden. Gestartet wird in der Anwendung mit dem sinatra/lib
- Ordner
im LOAD_PATH
:
-cd myapp
+
+cd myapp
git clone git://github.com/sinatra/sinatra.git
ruby -Isinatra/lib myapp.rb
-
+
+
Alternativ kann der sinatra/lib
-Ordner zum LOAD_PATH
in der Anwendung
hinzugefügt werden:
-$LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
-require 'rubygems'
-require 'sinatra'
-
-get '/ueber' do
- "Ich laufe auf Version " + Sinatra::VERSION
-end
-
+
+
+
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
+require 'rubygems'
+require 'sinatra'
+
+get '/ueber' do
+ "Ich laufe auf Version " + Sinatra::VERSION
+end
+
+
+
+
Um Sinatra-Code von Zeit zu Zeit zu aktualisieren:
-cd myproject/sinatra
+
+cd myproject/sinatra
git pull
-
+
+
Gem erstellen
Aus der eigenen lokalen Kopie kann nun auch ein globales Gem gebaut werden:
-git clone git://github.com/sinatra/sinatra.git
+
+git clone git://github.com/sinatra/sinatra.git
cd sinatra
rake sinatra.gemspec
rake install
-
+
+
Falls Gems als Root installiert werden sollen, sollte die letzte Zeile
folgendermaßen lauten:
-sudo rake install
-
+
+sudo rake install
+
+
Versions-Verfahren
@@ -2494,24 +3293,25 @@ Versions-Verfahren
Mehr