sinatra-acd 1.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +5 -0
  3. data/AUTHORS +61 -0
  4. data/CHANGES +1293 -0
  5. data/Gemfile +76 -0
  6. data/LICENSE +23 -0
  7. data/README.de.md +2864 -0
  8. data/README.es.md +2786 -0
  9. data/README.fr.md +2924 -0
  10. data/README.hu.md +694 -0
  11. data/README.ja.md +2726 -0
  12. data/README.ko.md +2832 -0
  13. data/README.md +2980 -0
  14. data/README.pt-br.md +965 -0
  15. data/README.pt-pt.md +791 -0
  16. data/README.ru.md +2799 -0
  17. data/README.zh.md +2158 -0
  18. data/Rakefile +199 -0
  19. data/examples/chat.rb +61 -0
  20. data/examples/simple.rb +3 -0
  21. data/examples/stream.ru +26 -0
  22. data/lib/sinatra.rb +4 -0
  23. data/lib/sinatra/base.rb +2044 -0
  24. data/lib/sinatra/images/404.png +0 -0
  25. data/lib/sinatra/images/500.png +0 -0
  26. data/lib/sinatra/main.rb +34 -0
  27. data/lib/sinatra/show_exceptions.rb +345 -0
  28. data/lib/sinatra/version.rb +3 -0
  29. data/sinatra.gemspec +19 -0
  30. data/test/asciidoctor_test.rb +72 -0
  31. data/test/base_test.rb +171 -0
  32. data/test/builder_test.rb +91 -0
  33. data/test/coffee_test.rb +90 -0
  34. data/test/compile_test.rb +183 -0
  35. data/test/contest.rb +100 -0
  36. data/test/creole_test.rb +65 -0
  37. data/test/delegator_test.rb +160 -0
  38. data/test/encoding_test.rb +20 -0
  39. data/test/erb_test.rb +116 -0
  40. data/test/extensions_test.rb +98 -0
  41. data/test/filter_test.rb +487 -0
  42. data/test/haml_test.rb +109 -0
  43. data/test/helper.rb +131 -0
  44. data/test/helpers_test.rb +1917 -0
  45. data/test/integration/app.rb +79 -0
  46. data/test/integration_helper.rb +236 -0
  47. data/test/integration_test.rb +104 -0
  48. data/test/less_test.rb +69 -0
  49. data/test/liquid_test.rb +77 -0
  50. data/test/mapped_error_test.rb +285 -0
  51. data/test/markaby_test.rb +80 -0
  52. data/test/markdown_test.rb +82 -0
  53. data/test/mediawiki_test.rb +68 -0
  54. data/test/middleware_test.rb +68 -0
  55. data/test/nokogiri_test.rb +67 -0
  56. data/test/public/favicon.ico +0 -0
  57. data/test/rabl_test.rb +89 -0
  58. data/test/rack_test.rb +45 -0
  59. data/test/radius_test.rb +59 -0
  60. data/test/rdoc_test.rb +66 -0
  61. data/test/readme_test.rb +130 -0
  62. data/test/request_test.rb +97 -0
  63. data/test/response_test.rb +63 -0
  64. data/test/result_test.rb +76 -0
  65. data/test/route_added_hook_test.rb +59 -0
  66. data/test/routing_test.rb +1412 -0
  67. data/test/sass_test.rb +115 -0
  68. data/test/scss_test.rb +88 -0
  69. data/test/server_test.rb +48 -0
  70. data/test/settings_test.rb +582 -0
  71. data/test/sinatra_test.rb +12 -0
  72. data/test/slim_test.rb +102 -0
  73. data/test/static_test.rb +236 -0
  74. data/test/streaming_test.rb +149 -0
  75. data/test/stylus_test.rb +90 -0
  76. data/test/templates_test.rb +382 -0
  77. data/test/textile_test.rb +65 -0
  78. data/test/views/a/in_a.str +1 -0
  79. data/test/views/ascii.erb +2 -0
  80. data/test/views/b/in_b.str +1 -0
  81. data/test/views/calc.html.erb +1 -0
  82. data/test/views/error.builder +3 -0
  83. data/test/views/error.erb +3 -0
  84. data/test/views/error.haml +3 -0
  85. data/test/views/error.sass +2 -0
  86. data/test/views/explicitly_nested.str +1 -0
  87. data/test/views/foo/hello.test +1 -0
  88. data/test/views/hello.asciidoc +1 -0
  89. data/test/views/hello.builder +1 -0
  90. data/test/views/hello.coffee +1 -0
  91. data/test/views/hello.creole +1 -0
  92. data/test/views/hello.erb +1 -0
  93. data/test/views/hello.haml +1 -0
  94. data/test/views/hello.less +5 -0
  95. data/test/views/hello.liquid +1 -0
  96. data/test/views/hello.mab +1 -0
  97. data/test/views/hello.md +1 -0
  98. data/test/views/hello.mediawiki +1 -0
  99. data/test/views/hello.nokogiri +1 -0
  100. data/test/views/hello.rabl +2 -0
  101. data/test/views/hello.radius +1 -0
  102. data/test/views/hello.rdoc +1 -0
  103. data/test/views/hello.sass +2 -0
  104. data/test/views/hello.scss +3 -0
  105. data/test/views/hello.slim +1 -0
  106. data/test/views/hello.str +1 -0
  107. data/test/views/hello.styl +2 -0
  108. data/test/views/hello.test +1 -0
  109. data/test/views/hello.textile +1 -0
  110. data/test/views/hello.wlang +1 -0
  111. data/test/views/hello.yajl +1 -0
  112. data/test/views/layout2.builder +3 -0
  113. data/test/views/layout2.erb +2 -0
  114. data/test/views/layout2.haml +2 -0
  115. data/test/views/layout2.liquid +2 -0
  116. data/test/views/layout2.mab +2 -0
  117. data/test/views/layout2.nokogiri +3 -0
  118. data/test/views/layout2.rabl +3 -0
  119. data/test/views/layout2.radius +2 -0
  120. data/test/views/layout2.slim +3 -0
  121. data/test/views/layout2.str +2 -0
  122. data/test/views/layout2.test +1 -0
  123. data/test/views/layout2.wlang +2 -0
  124. data/test/views/nested.str +1 -0
  125. data/test/views/utf8.erb +2 -0
  126. data/test/wlang_test.rb +87 -0
  127. data/test/yajl_test.rb +86 -0
  128. metadata +280 -0
data/Gemfile ADDED
@@ -0,0 +1,76 @@
1
+ # Why use bundler?
2
+ # Well, not all development dependencies install on all rubies. Moreover, `gem
3
+ # install sinatra --development` doesn't work, as it will also try to install
4
+ # development dependencies of our dependencies, and those are not conflict free.
5
+ # So, here we are, `bundle install`.
6
+ #
7
+ # If you have issues with a gem: `bundle install --without-coffee-script`.
8
+
9
+ RUBY_ENGINE = 'ruby' unless defined? RUBY_ENGINE
10
+ source 'https://rubygems.org' unless ENV['QUICK']
11
+ gemspec
12
+
13
+ gem 'rake'
14
+ gem 'rack-test', '>= 0.5.6'
15
+
16
+ # Allows stuff like `tilt=1.2.2 bundle install` or `tilt=master ...`.
17
+ # Used by the CI.
18
+ github = "git://github.com/%s.git"
19
+ repos = {'tilt' => github % "rtomayko/tilt", 'rack' => github % "rack/rack"}
20
+
21
+ %w[tilt rack].each do |lib|
22
+ dep = case ENV[lib]
23
+ when 'stable', nil then nil
24
+ when /(\d+\.)+\d+/ then "~> " + ENV[lib].sub("#{lib}-", '')
25
+ else {:git => repos[lib], :branch => dep}
26
+ end
27
+ gem lib, dep
28
+ end
29
+
30
+ if RUBY_ENGINE == 'jruby'
31
+ gem 'nokogiri', '!= 1.5.0'
32
+ gem 'jruby-openssl'
33
+ gem 'trinidad'
34
+ end
35
+
36
+ if RUBY_ENGINE == "ruby" and RUBY_VERSION > '1.9.2'
37
+ gem 'less', '~> 2.0'
38
+ gem 'therubyracer'
39
+ gem 'redcarpet'
40
+ gem 'wlang', '>= 2.0.1'
41
+ gem 'bluecloth'
42
+ gem 'rdiscount'
43
+ gem 'RedCloth'
44
+ gem 'puma'
45
+ gem 'net-http-server'
46
+ gem 'yajl-ruby'
47
+ gem 'nokogiri'
48
+ gem 'thin'
49
+ gem 'slim', '~> 1.0'
50
+ gem 'coffee-script', '>= 2.0'
51
+ gem 'rdoc'
52
+ gem 'kramdown'
53
+ gem 'maruku'
54
+ gem 'creole'
55
+ gem 'wikicloth'
56
+ gem 'markaby'
57
+ gem 'radius'
58
+ gem 'asciidoctor'
59
+ gem 'liquid'
60
+ gem 'stylus'
61
+ gem 'rabl'
62
+ gem 'builder'
63
+ gem 'erubis'
64
+ gem 'haml', '>= 3.0'
65
+ gem 'sass'
66
+ end
67
+
68
+ if RUBY_ENGINE == "rbx"
69
+ gem 'json'
70
+ gem 'rubysl'
71
+ gem 'rubysl-test-unit'
72
+ end
73
+
74
+ platforms :ruby_18, :jruby do
75
+ gem 'json' unless RUBY_VERSION > '1.9' # is there a jruby but 1.8 only selector?
76
+ end
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2007, 2008, 2009 Blake Mizerany
2
+ Copyright (c) 2010, 2011, 2012, 2013, 2014 Konstantin Haase
3
+
4
+ Permission is hereby granted, free of charge, to any person
5
+ obtaining a copy of this software and associated documentation
6
+ files (the "Software"), to deal in the Software without
7
+ restriction, including without limitation the rights to use,
8
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the
10
+ Software is furnished to do so, subject to the following
11
+ conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,2864 @@
1
+ # Sinatra
2
+
3
+ *Wichtig: Dieses Dokument ist eine Übersetzung aus dem Englischen und unter
4
+ Umständen nicht auf dem aktuellen Stand (aktuell Sinatra 1.4.2).*
5
+
6
+ Sinatra ist eine
7
+ [DSL](http://de.wikipedia.org/wiki/Domänenspezifische_Sprache), die das
8
+ schnelle Erstellen von Webanwendungen in Ruby mit minimalem Aufwand
9
+ ermöglicht:
10
+
11
+ Sinatra via `rubygems` installieren:
12
+
13
+ ```shell
14
+ gem install sinatra
15
+ ```
16
+
17
+ Eine Datei mit dem Namen `myapp.rb` erstellen:
18
+
19
+ ```ruby
20
+ require 'sinatra'
21
+ get '/' do
22
+ 'Hallo Welt!'
23
+ end
24
+ ```
25
+
26
+ und im gleichen Verzeichnis ausführen:
27
+
28
+ ```shell
29
+ ruby myapp.rb
30
+ ```
31
+
32
+ Die Seite kann nun unter [http://localhost:4567](http://localhost:4567)
33
+ aufgerufen werden.
34
+
35
+ ## Inhalt
36
+
37
+ * [Sinatra](#sinatra)
38
+ * [Routen](#routen)
39
+ * [Bedingungen](#bedingungen)
40
+ * [Rückgabewerte](#rckgabewerte)
41
+ * [Eigene Routen-Muster](#eigene-routen-muster)
42
+ * [Statische Dateien](#statische-dateien)
43
+ * [Views/Templates](#viewstemplates)
44
+ * [Direkte Templates](#direkte-templates)
45
+ * [Verfügbare Templatesprachen](#verfgbare-templatesprachen)
46
+ * [Haml Templates](#haml-templates)
47
+ * [Erb Templates](#erb-templates)
48
+ * [Builder Templates](#builder-templates)
49
+ * [Nokogiri Templates](#nokogiri-templates)
50
+ * [Sass Templates](#sass-templates)
51
+ * [SCSS Templates](#scss-templates)
52
+ * [Less Templates](#less-templates)
53
+ * [Liquid Templates](#liquid-templates)
54
+ * [Markdown Templates](#markdown-templates)
55
+ * [Textile Templates](#textile-templates)
56
+ * [RDoc Templates](#rdoc-templates)
57
+ * [Radius Templates](#radius-templates)
58
+ * [Markaby Templates](#markaby-templates)
59
+ * [RABL Templates](#rabl-templates)
60
+ * [Slim Templates](#slim-templates)
61
+ * [Creole Templates](#creole-templates)
62
+ * [CoffeeScript Templates](#coffeescript-templates)
63
+ * [Stylus Templates](#stylus-templates)
64
+ * [Yajl Templates](#yajl-templates)
65
+ * [WLang Templates](#wlang-templates)
66
+ * [Auf Variablen in Templates zugreifen](#auf-variablen-in-templates-zugreifen)
67
+ * [Templates mit `yield` und verschachtelte Layouts](#templates-mit-yield-und-verschachtelte-layouts)
68
+ * [Inline-Templates](#inline-templates)
69
+ * [Benannte Templates](#benannte-templates)
70
+ * [Dateiendungen zuordnen](#dateiendungen-zuordnen)
71
+ * [Eine eigene Template-Engine hinzufügen](#eine-eigene-template-engine-hinzufgen)
72
+ * [Filter](#filter)
73
+ * [Helfer](#helfer)
74
+ * [Sessions verwenden](#sessions-verwenden)
75
+ * [Anhalten](#anhalten)
76
+ * [Weiterspringen](#weiterspringen)
77
+ * [Eine andere Route ansteuern](#eine-andere-route-ansteuern)
78
+ * [Body, Status-Code und Header setzen](#body-status-code-und-header-setzen)
79
+ * [Response-Streams](#response-streams)
80
+ * [Logger](#logger)
81
+ * [Mime-Types](#mime-types)
82
+ * [URLs generieren](#urls-generieren)
83
+ * [Browser-Umleitung](#browser-umleitung)
84
+ * [Cache einsetzen](#cache-einsetzen)
85
+ * [Dateien versenden](#dateien-versenden)
86
+ * [Das Request-Objekt](#das-request-objekt)
87
+ * [Anhänge](#anhnge)
88
+ * [Umgang mit Datum und Zeit](#umgang-mit-datum-und-zeit)
89
+ * [Nachschlagen von Template-Dateien](#nachschlagen-von-template-dateien)
90
+ * [Konfiguration](#konfiguration)
91
+ * [Einstellung des Angriffsschutzes](#einstellung-des-angriffsschutzes)
92
+ * [Mögliche Einstellungen](#mgliche-einstellungen)
93
+ * [Umgebungen](#umgebungen)
94
+ * [Fehlerbehandlung](#fehlerbehandlung)
95
+ * [Nicht gefunden](#nicht-gefunden)
96
+ * [Fehler](#fehler)
97
+ * [Rack-Middleware](#rack-middleware)
98
+ * [Testen](#testen)
99
+ * [Sinatra::Base - Middleware, Bibliotheken und modulare Anwendungen](#sinatrabase---middleware-bibliotheken-und-modulare-anwendungen)
100
+ * [Modularer vs. klassischer Stil](#modularer-vs-klassischer-stil)
101
+ * [Eine modulare Applikation bereitstellen](#eine-modulare-applikation-bereitstellen)
102
+ * [Eine klassische Anwendung mit einer config.ru verwenden](#eine-klassische-anwendung-mit-einer-configru-verwenden)
103
+ * [Wann sollte eine config.ru-Datei verwendet werden?](#wann-sollte-eine-configru-datei-verwendet-werden)
104
+ * [Sinatra als Middleware nutzen](#sinatra-als-middleware-nutzen)
105
+ * [Dynamische Applikationserstellung](#dynamische-applikationserstellung)
106
+ * [Geltungsbereich und Bindung](#geltungsbereich-und-bindung)
107
+ * [Anwendungs- oder Klassen-Scope](#anwendungs--oder-klassen-scope)
108
+ * [Anfrage- oder Instanz-Scope](#anfrage--oder-instanz-scope)
109
+ * [Delegation-Scope](#delegation-scope)
110
+ * [Kommandozeile](#kommandozeile)
111
+ * [Systemanforderungen](#systemanforderungen)
112
+ * [Der neuste Stand (The Bleeding Edge)](#der-neuste-stand-the-bleeding-edge)
113
+ * [Mit Bundler](#mit-bundler)
114
+ * [Eigenes Repository](#eigenes-repository)
115
+ * [Gem erstellen](#gem-erstellen)
116
+ * [Versions-Verfahren](#versions-verfahren)
117
+ * [Mehr](#mehr)
118
+
119
+ ## Routen
120
+
121
+ In Sinatra wird eine Route durch eine HTTP-Methode und ein URL-Muster definiert.
122
+ Jeder dieser Routen wird ein Ruby-Block zugeordnet:
123
+
124
+ ```ruby
125
+ get '/' do
126
+ .. zeige etwas ..
127
+ end
128
+
129
+ post '/' do
130
+ .. erstelle etwas ..
131
+ end
132
+
133
+ put '/' do
134
+ .. update etwas ..
135
+ end
136
+
137
+ delete '/' do
138
+ .. entferne etwas ..
139
+ end
140
+
141
+ options '/' do
142
+ .. zeige, was wir können ..
143
+ end
144
+
145
+ link '/' do
146
+ .. verbinde etwas ..
147
+ end
148
+
149
+ unlink '/' do
150
+ .. trenne etwas ..
151
+ end
152
+ ```
153
+
154
+ Die Routen werden in der Reihenfolge durchlaufen, in der sie definiert wurden.
155
+ Das erste Routen-Muster, das mit dem Request übereinstimmt, wird ausgeführt.
156
+
157
+ Die Muster der Routen können benannte Parameter beinhalten, die über den
158
+ `params`-Hash zugänglich gemacht werden:
159
+
160
+ ```ruby
161
+ get '/hallo/:name' do
162
+ # passt auf "GET /hallo/foo" und "GET /hallo/bar"
163
+ # params[:name] ist dann 'foo' oder 'bar'
164
+ "Hallo #{params[:name]}!"
165
+ end
166
+ ```
167
+
168
+ Man kann auf diese auch mit Block-Parametern zugreifen:
169
+
170
+ ```ruby
171
+ get '/hallo/:name' do |n|
172
+ # n entspricht hier params[:name]
173
+ "Hallo #{n}!"
174
+ end
175
+ ```
176
+
177
+ Routen-Muster können auch mit sog. Splat- oder Wildcard-Parametern über das
178
+ `params[:splat]`-Array angesprochen werden:
179
+
180
+ ```ruby
181
+ get '/sag/*/zu/*' do
182
+ # passt z.B. auf /sag/hallo/zu/welt
183
+ params[:splat] # => ["hallo", "welt"]
184
+ end
185
+
186
+ get '/download/*.*' do
187
+ # passt auf /download/pfad/zu/datei.xml
188
+ params[:splat] # => ["pfad/zu/datei", "xml"]
189
+ end
190
+ ```
191
+
192
+ Oder mit Block-Parametern:
193
+
194
+ ```ruby
195
+ get '/download/*.*' do |pfad, endung|
196
+ [pfad, endung] # => ["Pfad/zu/Datei", "xml"]
197
+ end
198
+ ```
199
+
200
+ Routen mit regulären Ausdrücken sind auch möglich:
201
+
202
+ ```ruby
203
+ get %r{/hallo/([\w]+)} do
204
+ "Hallo, #{params[:captures].first}!"
205
+ end
206
+ ```
207
+
208
+ Und auch hier können Block-Parameter genutzt werden:
209
+
210
+ ```ruby
211
+ get %r{/hallo/([\w]+)} do |c|
212
+ "Hallo, #{c}!"
213
+ end
214
+ ```
215
+
216
+ Routen-Muster können auch mit optionalen Parametern ausgestattet werden:
217
+
218
+ ```ruby
219
+ get '/posts.?:format?' do
220
+ # passt auf "GET /posts" sowie jegliche Erweiterung
221
+ # wie "GET /posts.json", "GET /posts.xml" etc.
222
+ end
223
+ ```
224
+
225
+ Anmerkung: Solange man den sog. Path Traversal Attack-Schutz nicht deaktiviert
226
+ (siehe weiter unten), kann es sein, dass der Request-Pfad noch vor dem
227
+ Abgleich mit den Routen modifiziert wird.
228
+
229
+ ### Bedingungen
230
+
231
+ An Routen können eine Vielzahl von Bedingungen geknüpft werden, die erfüllt
232
+ sein müssen, damit der Block ausgeführt wird. Möglich wäre etwa eine
233
+ Einschränkung des User-Agents über die interne Bedingung `:agent`:
234
+
235
+ ```ruby
236
+ get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
237
+ "Du verwendest Songbird Version #{params[:agent][0]}"
238
+ end
239
+ ```
240
+
241
+ Wird Songbird als Browser nicht verwendet, springt Sinatra zur nächsten Route:
242
+
243
+ ```ruby
244
+ get '/foo' do
245
+ # passt auf andere Browser
246
+ end
247
+ ```
248
+
249
+ Andere mitgelieferte Bedingungen sind `:host_name` und `:provides`:
250
+
251
+ ```ruby
252
+ get '/', :host_name => /^admin\./ do
253
+ "Adminbereich, Zugriff verweigert!"
254
+ end
255
+
256
+ get '/', :provides => 'html' do
257
+ haml :index
258
+ end
259
+
260
+ get '/', :provides => ['rss', 'atom', 'xml'] do
261
+ builder :feed
262
+ end
263
+ ```
264
+
265
+ Eigene Bedingungen können relativ einfach hinzugefügt werden:
266
+
267
+ ```ruby
268
+ set(:wahrscheinlichkeit) { |value| condition { rand <= value } }
269
+
270
+ get '/auto_gewinnen', :wahrscheinlichkeit => 0.1 do
271
+ "Du hast gewonnen!"
272
+ end
273
+
274
+ get '/auto_gewinnen' do
275
+ "Tut mir leid, verloren."
276
+ end
277
+ ```
278
+
279
+ Bei Bedingungen, die mehrere Werte annehmen können, sollte ein Splat verwendet
280
+ werden:
281
+
282
+ ```ruby
283
+ set(:auth) do |*roles| # <- hier kommt der Splat ins Spiel
284
+ condition do
285
+ unless logged_in? && roles.any? {|role| current_user.in_role? role }
286
+ redirect "/login/", 303
287
+ end
288
+ end
289
+ end
290
+
291
+ get "/mein/account/", :auth => [:user, :admin] do
292
+ "Mein Account"
293
+ end
294
+
295
+ get "/nur/admin/", :auth => :admin do
296
+ "Nur Admins dürfen hier rein!"
297
+ end
298
+ ```
299
+
300
+ ### Rückgabewerte
301
+
302
+ Durch den Rückgabewert eines Routen-Blocks wird mindestens der Response-Body
303
+ festgelegt, der an den HTTP-Client, bzw. die nächste Rack-Middleware,
304
+ weitergegeben wird. Im Normalfall handelt es sich hierbei, wie in den
305
+ vorangehenden Beispielen zu sehen war, um einen String. Es werden allerdings
306
+ auch andere Werte akzeptiert.
307
+
308
+ Es kann jedes gültige Objekt zurückgegeben werden, bei dem es sich entweder um
309
+ einen Rack-Rückgabewert, einen Rack-Body oder einen HTTP-Status-Code handelt:
310
+
311
+ * Ein Array mit drei Elementen: `[Status (Fixnum), Headers (Hash),
312
+ Response-Body (antwortet auf #each)]`.
313
+ * Ein Array mit zwei Elementen: `[Status (Fixnum), Response-Body (antwortet
314
+ auf #each)]`.
315
+ * Ein Objekt, das auf `#each` antwortet und den an diese Methode übergebenen
316
+ Block nur mit Strings als Übergabewerte aufruft.
317
+ * Ein Fixnum, das den Status-Code festlegt.
318
+
319
+ Damit lässt sich relativ einfach Streaming implementieren:
320
+
321
+ ```ruby
322
+ class Stream
323
+ def each
324
+ 100.times { |i| yield "#{i}\n" }
325
+ end
326
+ end
327
+
328
+ get('/') { Stream.new }
329
+ ```
330
+
331
+ Ebenso kann die `stream`-Helfer-Methode (s.u.) verwendet werden, die Streaming
332
+ direkt in die Route integriert.
333
+
334
+ ### Eigene Routen-Muster
335
+
336
+ Wie oben schon beschrieben, ist Sinatra von Haus aus mit Unterstützung für
337
+ String-Muster und Reguläre Ausdrücke zum Abgleichen von Routen ausgestattet.
338
+ Das muss aber noch nicht alles sein, es können ohne großen Aufwand eigene
339
+ Routen-Muster erstellt werden:
340
+
341
+ ```ruby
342
+ class AllButPattern
343
+ Match = Struct.new(:captures)
344
+
345
+ def initialize(except)
346
+ @except = except
347
+ @captures = Match.new([])
348
+ end
349
+
350
+ def match(str)
351
+ @captures unless @except === str
352
+ end
353
+ end
354
+
355
+ def all_but(pattern)
356
+ AllButPattern.new(pattern)
357
+ end
358
+
359
+ get all_but("/index") do
360
+ # ...
361
+ end
362
+ ```
363
+
364
+ Beachte, dass das obige Beispiel etwas übertrieben wirkt. Es geht auch einfacher:
365
+
366
+ ```ruby
367
+ get // do
368
+ pass if request.path_info == "/index"
369
+ # ...
370
+ end
371
+ ```
372
+
373
+ Oder unter Verwendung eines negativen look ahead:
374
+
375
+ ```ruby
376
+ get %r{^(?!/index$)} do
377
+ # ...
378
+ end
379
+ ```
380
+
381
+ ## Statische Dateien
382
+
383
+ Statische Dateien werden im `./public`-Ordner erwartet. Es ist möglich,
384
+ einen anderen Ort zu definieren, indem man die `:public_folder`-Option setzt:
385
+
386
+ ```ruby
387
+ set :public_folder, File.dirname(__FILE__) + '/static'
388
+ ```
389
+
390
+ Zu beachten ist, dass der Ordnername `public` nicht Teil der URL ist. Die Datei
391
+ `./public/css/style.css` ist unter `http://example.com/css/style.css` zu finden.
392
+
393
+ Um den `Cache-Control`-Header mit Informationen zu versorgen, verwendet man
394
+ die `:static_cache_control`-Einstellung (s.u.).
395
+
396
+ ## Views/Templates
397
+
398
+ Alle Templatesprachen verwenden ihre eigene Renderingmethode, die jeweils
399
+ einen String zurückgibt:
400
+
401
+ ```ruby
402
+ get '/' do
403
+ erb :index
404
+ end
405
+ ```
406
+
407
+ Dieses Beispiel rendert `views/index.erb`.
408
+
409
+ Anstelle eines Templatenamens kann man auch direkt die Templatesprache verwenden:
410
+
411
+ ```ruby
412
+ get '/' do
413
+ code = "<%= Time.now %>"
414
+ erb code
415
+ end
416
+ ```
417
+
418
+ Templates nehmen ein zweite Argument an, den Options-Hash:
419
+
420
+ ```ruby
421
+ get '/' do
422
+ erb :index, :layout => :post
423
+ end
424
+ ```
425
+
426
+ Dieses Beispiel rendert `views/index.erb` eingebettet in `views/post.erb`
427
+ (Voreinstellung ist `views/layout.erb`, sofern es vorhanden ist.)
428
+
429
+ Optionen, die Sinatra nicht versteht, werden an das Template weitergereicht:
430
+
431
+ ```ruby
432
+ get '/' do
433
+ haml :index, :format => :html5
434
+ end
435
+ ```
436
+
437
+ Für alle Templates können auch Einstellungen, die für alle Routen gelten,
438
+ festgelegt werden:
439
+
440
+ ```ruby
441
+ set :haml, :format => :html5
442
+
443
+ get '/' do
444
+ haml :index
445
+ end
446
+ ```
447
+
448
+ Optionen, die an die Rendermethode weitergegeben werden, überschreiben die
449
+ Einstellungen, die mit `set` festgelegt wurden.
450
+
451
+ Einstellungen:
452
+
453
+ <dl>
454
+ <dt>locals</dt>
455
+ <dd>Liste von lokalen Variablen, die an das Dokument weitergegeben werden.
456
+ Praktisch für Partials:
457
+
458
+ <tt>erb "<%= foo %>", :locals => {:foo => "bar"}</tt></dd>
459
+
460
+ <dt>default_encoding</dt>
461
+ <dd>Gibt die Stringkodierung an, die verwendet werden soll. Voreingestellt
462
+ auf <tt>settings.default_encoding</tt>.</dd>
463
+
464
+ <dt>views</dt>
465
+ <dd>Ordner, aus dem die Templates geladen werden. Voreingestellt auf
466
+ <tt>settings.views</tt>.</dd>
467
+
468
+ <dt>layout</dt>
469
+ <dd>Legt fest, ob ein Layouttemplate verwendet werden soll oder nicht
470
+ (<tt>true</tt> oder<tt>false</tt>). Ist es ein Symbol, dann legt es fest,
471
+ welches Template als Layout verwendet wird:
472
+
473
+ <tt>erb :index, :layout => !request.xhr?</tt></dd>
474
+
475
+ <dt>content_type</dt>
476
+ <dd>Content-Typ den das Template ausgibt. Voreinstellung hängt von der
477
+ Templatesprache ab.</dd>
478
+
479
+ <dt>scope</dt>
480
+ <dd>Scope, in dem das Template gerendert wird. Liegt standardmäßig innerhalb
481
+ der App-Instanz. Wird Scope geändert, sind Instanzvariablen und
482
+ Helfermethoden nicht verfügbar.</dd>
483
+
484
+ <dt>layout_engine</dt>
485
+ <dd>Legt fest, welcher Renderer für das Layout verantwortlich ist. Hilfreich
486
+ für Sprachen, die sonst keine Templates unterstützen. Voreingestellt auf
487
+ den Renderer, der für das Template verwendet wird:
488
+
489
+ <tt>set :rdoc, :layout_engine => :erb</tt></dd>
490
+
491
+ <dt>layout_options</dt>
492
+ <dd>Besondere Einstellungen, die nur für das Rendering verwendet werden:
493
+
494
+ <tt>set :rdoc, :layout_options => { :views => 'views/layouts' }</tt></dd>
495
+ </dl>
496
+
497
+ Sinatra geht davon aus, dass die Templates sich im `./views` Verzeichnis
498
+ befinden. Es kann jedoch ein anderer Ordner festgelegt werden:
499
+
500
+ ```ruby
501
+ set :views, settings.root + '/templates'
502
+ ```
503
+
504
+ Es ist zu beachten, dass immer mit Symbolen auf Templates verwiesen werden muss,
505
+ auch dann, wenn sie sich in einem Unterordner befinden:
506
+
507
+ ```ruby
508
+ haml :'unterverzeichnis/template'
509
+ ```
510
+
511
+ Rendering-Methoden rendern jeden String direkt.
512
+
513
+ ### Direkte Templates
514
+
515
+ ``` ruby
516
+ get '/' do
517
+ haml '%div.title Hallo Welt'
518
+ end
519
+ ```
520
+
521
+ Hier wird der String direkt gerendert.
522
+
523
+ ### Verfügbare Templatesprachen
524
+
525
+ Einige Sprachen haben mehrere Implementierungen. Um festzulegen, welche
526
+ verwendet wird (und dann auch Thread-sicher ist), verwendet man am besten zu
527
+ Beginn ein `'require'`:
528
+
529
+ ```ruby
530
+ require 'rdiscount' # oder require 'bluecloth'
531
+ get('/') { markdown :index }
532
+ ```
533
+
534
+ #### Haml Templates
535
+
536
+ <table>
537
+ <tr>
538
+ <td>Abhängigkeit</td>
539
+ <td><a href="http://haml.info/">haml</a></td>
540
+ </tr>
541
+ <tr>
542
+ <td>Dateierweiterung</td>
543
+ <td><tt>.haml</tt></td>
544
+ </tr>
545
+ <tr>
546
+ <td>Beispiel</td>
547
+ <td><tt>haml :index, :format => :html5</tt></td>
548
+ </tr>
549
+ </table>
550
+
551
+
552
+ #### Erb Templates
553
+
554
+ <table>
555
+ <tr>
556
+ <td>Abhängigkeit</td>
557
+ <td><a href="http://www.kuwata-lab.com/erubis/">erubis</a> oder erb
558
+ (Standardbibliothek von Ruby)</td>
559
+ </tr>
560
+ <tr>
561
+ <td>Dateierweiterungen</td>
562
+ <td><tt>.erb</tt>, <tt>.rhtml</tt> oder <tt>.erubis</tt> (nur Erubis)</td>
563
+ </tr>
564
+ <tr>
565
+ <td>Beispiel</td>
566
+ <td><tt>erb :index</tt></td>
567
+ </tr>
568
+ </table>
569
+
570
+
571
+ #### Builder Templates
572
+
573
+ <table>
574
+ <tr>
575
+ <td>Abhängigkeit</td>
576
+ <td><a href="http://builder.rubyforge.org/">builder</a></td>
577
+ </tr>
578
+ <tr>
579
+ <td>Dateierweiterung</td>
580
+ <td><tt>.builder</tt></td>
581
+ </tr>
582
+ <tr>
583
+ <td>Beispiel</td>
584
+ <td><tt>builder { |xml| xml.em "Hallo" }</tt></td>
585
+ </tr>
586
+ </table>
587
+
588
+ Nimmt ebenso einen Block für Inline-Templates entgegen (siehe Beispiel).
589
+
590
+ #### Nokogiri Templates
591
+
592
+ <table>
593
+ <tr>
594
+ <td>Abhängigkeit</td>
595
+ <td><a href="http://nokogiri.org/">nokogiri</a></td>
596
+ </tr>
597
+ <tr>
598
+ <td>Dateierweiterung</td>
599
+ <td><tt>.nokogiri</tt></td>
600
+ </tr>
601
+ <tr>
602
+ <td>Beispiel</td>
603
+ <td><tt>nokogiri { |xml| xml.em "Hallo" }</tt></td>
604
+ </tr>
605
+ </table>
606
+
607
+ Nimmt ebenso einen Block für Inline-Templates entgegen (siehe Beispiel).
608
+
609
+ #### Sass Templates
610
+
611
+ <table>
612
+ <tr>
613
+ <td>Abhängigkeit</td>
614
+ <td><a href="http://sass-lang.com/">sass</a></td>
615
+ </tr>
616
+ <tr>
617
+ <td>Dateierweiterung</td>
618
+ <td><tt>.sass</tt></td>
619
+ </tr>
620
+ <tr>
621
+ <td>Beispiel</td>
622
+ <td><tt>sass :stylesheet, :style => :expanded</tt></td>
623
+ </tr>
624
+ </table>
625
+
626
+
627
+ #### SCSS Templates
628
+
629
+ <table>
630
+ <tr>
631
+ <td>Abhängigkeit</td>
632
+ <td><a href="http://sass-lang.com/">sass</a></td>
633
+ </tr>
634
+ <tr>
635
+ <td>Dateierweiterung</td>
636
+ <td><tt>.scss</tt></td>
637
+ </tr>
638
+ <tr>
639
+ <td>Beispiel</td>
640
+ <td><tt>scss :stylesheet, :style => :expanded</tt></td>
641
+ </tr>
642
+ </table>
643
+
644
+
645
+ #### Less Templates
646
+
647
+ <table>
648
+ <tr>
649
+ <td>Abhängigkeit</td>
650
+ <td><a href="http://www.lesscss.org/">less</a></td>
651
+ </tr>
652
+ <tr>
653
+ <td>Dateierweiterung</td>
654
+ <td><tt>.less</tt></td>
655
+ </tr>
656
+ <tr>
657
+ <td>Beispiel</td>
658
+ <td><tt>less :stylesheet</tt></td>
659
+ </tr>
660
+ </table>
661
+
662
+
663
+ #### Liquid Templates
664
+
665
+ <table>
666
+ <tr>
667
+ <td>Abhängigkeit</td>
668
+ <td><a href="http://www.liquidmarkup.org/">liquid</a></td>
669
+ </tr>
670
+ <tr>
671
+ <td>Dateierweiterung</td>
672
+ <td><tt>.liquid</tt></td>
673
+ </tr>
674
+ <tr>
675
+ <td>Beispiel</td>
676
+ <td><tt>liquid :index, :locals => { :key => 'Wert' }</tt></td>
677
+ </tr>
678
+ </table>
679
+
680
+ Da man aus dem Liquid-Template heraus keine Ruby-Methoden aufrufen kann
681
+ (ausgenommen `yield`), wird man üblicherweise locals verwenden wollen, mit
682
+ denen man Variablen weitergibt.
683
+
684
+ #### Markdown Templates
685
+
686
+ <table>
687
+ <tr>
688
+ <td>Abhängigkeit</td>
689
+ <td>Eine der folgenden Bibliotheken:
690
+ <a href="https://github.com/rtomayko/rdiscount" title="RDiscount">RDiscount</a>,
691
+ <a href="https://github.com/vmg/redcarpet" title="RedCarpet">RedCarpet</a>,
692
+ <a href="http://deveiate.org/projects/BlueCloth" title="BlueCloth">BlueCloth</a>,
693
+ <a href="http://kramdown.rubyforge.org/" title="kramdown">kramdown</a> oder
694
+ <a href="http://maruku.rubyforge.org/" title="maruku">maruku</a>
695
+ </td>
696
+ </tr>
697
+ <tr>
698
+ <td>Dateierweiterungen</td>
699
+ <td><tt>.markdown</tt>, <tt>.mkd</tt> und <tt>.md</tt></td>
700
+ </tr>
701
+ <tr>
702
+ <td>Beispiel</td>
703
+ <td><tt>markdown :index, :layout_engine => :erb</tt></td>
704
+ </tr>
705
+ </table>
706
+
707
+ Da man aus den Markdown-Templates heraus keine Ruby-Methoden aufrufen und auch
708
+ keine locals verwenden kann, wird man Markdown üblicherweise in Kombination
709
+ mit anderen Renderern verwenden wollen:
710
+
711
+ ```ruby
712
+ erb :overview, :locals => { :text => markdown(:einfuehrung) }
713
+ ```
714
+
715
+ Beachte, dass man die `markdown`-Methode auch aus anderen Templates heraus
716
+ aufrufen kann:
717
+
718
+ ```ruby
719
+ %h1 Gruß von Haml!
720
+ %p= markdown(:Grüße)
721
+ ```
722
+
723
+ Da man Ruby nicht von Markdown heraus aufrufen kann, können auch Layouts nicht
724
+ in Markdown geschrieben werden. Es ist aber möglich, einen Renderer für die
725
+ Templates zu verwenden und einen anderen für das Layout, indem die
726
+ `:layout_engine`-Option verwendet wird.
727
+
728
+ #### Textile Templates
729
+
730
+ <table>
731
+ <tr>
732
+ <td>Abhängigkeit</td>
733
+ <td><a href="http://redcloth.org/">RedCloth</a></td>
734
+ </tr>
735
+ <tr>
736
+ <td>Dateierweiterung</td>
737
+ <td><tt>.textile</tt></td>
738
+ </tr>
739
+ <tr>
740
+ <td>Beispiel</td>
741
+ <td><tt>textile :index, :layout_engine => :erb</tt></td>
742
+ </tr>
743
+ </table>
744
+
745
+ Da man aus dem Textile-Template heraus keine Ruby-Methoden aufrufen und auch
746
+ keine locals verwenden kann, wird man Textile üblicherweise in Kombination mit
747
+ anderen Renderern verwenden wollen:
748
+
749
+ ```ruby
750
+ erb :overview, :locals => { :text => textile(:einfuehrung) }
751
+ ```
752
+
753
+ Beachte, dass man die `textile`-Methode auch aus anderen Templates heraus
754
+ aufrufen kann:
755
+
756
+ ```ruby
757
+ %h1 Gruß von Haml!
758
+ %p= textile(:Grüße)
759
+ ```
760
+
761
+ Da man Ruby nicht von Textile heraus aufrufen kann, können auch Layouts nicht
762
+ in Textile geschrieben werden. Es ist aber möglich, einen Renderer für die
763
+ Templates zu verwenden und einen anderen für das Layout, indem die
764
+ `:layout_engine`-Option verwendet wird.
765
+
766
+ #### RDoc Templates
767
+
768
+ <table>
769
+ <tr>
770
+ <td>Abhängigkeit</td>
771
+ <td><a href="http://rdoc.rubyforge.org/">rdoc</a></td>
772
+ </tr>
773
+ <tr>
774
+ <td>Dateierweiterung</td>
775
+ <td><tt>.rdoc</tt></td>
776
+ </tr>
777
+ <tr>
778
+ <td>Beispiel</td>
779
+ <td><tt>textile :README, :layout_engine => :erb</tt></td>
780
+ </tr>
781
+ </table>
782
+
783
+ Da man aus dem RDoc-Template heraus keine Ruby-Methoden aufrufen und auch
784
+ keine locals verwenden kann, wird man RDoc üblicherweise in Kombination mit
785
+ anderen Renderern verwenden wollen:
786
+
787
+ ```ruby
788
+ erb :overview, :locals => { :text => rdoc(:einfuehrung) }
789
+ ```
790
+
791
+ Beachte, dass man die `rdoc`-Methode auch aus anderen Templates heraus
792
+ aufrufen kann:
793
+
794
+ ```ruby
795
+ %h1 Gruß von Haml!
796
+ %p= rdoc(:Grüße)
797
+ ```
798
+
799
+ Da man Ruby nicht von RDoc heraus aufrufen kann, können auch Layouts nicht in
800
+ RDoc geschrieben werden. Es ist aber möglich, einen Renderer für die Templates
801
+ zu verwenden und einen anderen für das Layout, indem die
802
+ `:layout_engine`-Option verwendet wird.
803
+
804
+ #### Radius Templates
805
+
806
+ <table>
807
+ <tr>
808
+ <td>Abhängigkeit</td>
809
+ <td><a href="http://radius.rubyforge.org/">radius</a></td>
810
+ </tr>
811
+ <tr>
812
+ <td>Dateierweiterung</td>
813
+ <td><tt>.radius</tt></td>
814
+ </tr>
815
+ <tr>
816
+ <td>Beispiel</td>
817
+ <td><tt>radius :index, :locals => { :key => 'Wert' }</tt></td>
818
+ </tr>
819
+ </table>
820
+
821
+ Da man aus dem Radius-Template heraus keine Ruby-Methoden aufrufen kann, wird
822
+ man üblicherweise locals verwenden wollen, mit denen man Variablen weitergibt.
823
+
824
+ #### Markaby Templates
825
+
826
+ <table>
827
+ <tr>
828
+ <td>Abhängigkeit</td>
829
+ <td><a href="http://markaby.github.com/">markaby</a></td>
830
+ </tr>
831
+ <tr>
832
+ <td>Dateierweiterung</td>
833
+ <td><tt>.mab</tt></td>
834
+ </tr>
835
+ <tr>
836
+ <td>Beispiel</td>
837
+ <td><tt>markaby { h1 "Willkommen!" }</tt></td>
838
+ </tr>
839
+ </table>
840
+
841
+ Nimmt ebenso einen Block für Inline-Templates entgegen (siehe Beispiel).
842
+
843
+ #### RABL Templates
844
+
845
+ <table>
846
+ <tr>
847
+ <td>Abhängigkeit</td>
848
+ <td><a href="https://github.com/nesquena/rabl">rabl</a></td>
849
+ </tr>
850
+ <tr>
851
+ <td>Dateierweiterung</td>
852
+ <td><tt>.rabl</tt></td>
853
+ </tr>
854
+ <tr>
855
+ <td>Beispiel</td>
856
+ <td><tt>rabl :index</tt></td>
857
+ </tr>
858
+ </table>
859
+
860
+ #### Slim Templates
861
+
862
+ <table>
863
+ <tr>
864
+ <td>Abhängigkeit</td>
865
+ <td><a href="http://slim-lang.com/">slim</a></td>
866
+ </tr>
867
+ <tr>
868
+ <td>Dateierweiterung</td>
869
+ <td><tt>.slim</tt></td>
870
+ </tr>
871
+ <tr>
872
+ <td>Beispiel</td>
873
+ <td><tt>slim :index</tt></td>
874
+ </tr>
875
+ </table>
876
+
877
+ #### Creole Templates
878
+
879
+ <table>
880
+ <tr>
881
+ <td>Abhängigkeit</td>
882
+ <td><a href="https://github.com/minad/creole">creole</a></td>
883
+ </tr>
884
+ <tr>
885
+ <td>Dateierweiterung</td>
886
+ <td><tt>.creole</tt></td>
887
+ </tr>
888
+ <tr>
889
+ <td>Beispiel</td>
890
+ <td><tt>creole :wiki, :layout_engine => :erb</tt></td>
891
+ </tr>
892
+ </table>
893
+
894
+ Da man aus dem Creole-Template heraus keine Ruby-Methoden aufrufen und auch
895
+ keine locals verwenden kann, wird man Creole üblicherweise in Kombination mit
896
+ anderen Renderern verwenden wollen:
897
+
898
+ ```ruby
899
+ erb :overview, :locals => { :text => creole(:einfuehrung) }
900
+ ```
901
+
902
+ Beachte, dass man die `creole`-Methode auch aus anderen Templates heraus
903
+ aufrufen kann:
904
+
905
+ ```ruby
906
+ %h1 Gruß von Haml!
907
+ %p= creole(:Grüße)
908
+ ```
909
+
910
+ Da man Ruby nicht von Creole heraus aufrufen kann, können auch Layouts nicht in
911
+ Creole geschrieben werden. Es ist aber möglich, einen Renderer für die Templates
912
+ zu verwenden und einen anderen für das Layout, indem die `:layout_engine`-Option
913
+ verwendet wird.
914
+
915
+ #### CoffeeScript Templates
916
+
917
+ <table>
918
+ <tr>
919
+ <td>Abhängigkeit</td>
920
+ <td><a href="https://github.com/josh/ruby-coffee-script">coffee-script</a>
921
+ und eine <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme">Möglichkeit JavaScript auszuführen</a>.
922
+ </td>
923
+ </tr>
924
+ <td>Dateierweiterung</td>
925
+ <td><tt>.coffee</tt></td>
926
+ </tr>
927
+ <tr>
928
+ <td>Beispiel</td>
929
+ <td><tt>coffee :index</tt></td>
930
+ </tr>
931
+ </table>
932
+
933
+ #### Stylus Templates
934
+
935
+ <table>
936
+ <tr>
937
+ <td>Abhängigkeit</td>
938
+ <td>
939
+ <a href="https://github.com/lucasmazza/ruby-stylus" title="Ruby Stylus">
940
+ Stylus
941
+ </a> und eine Möglichkeit
942
+ <a href="https://github.com/sstephenson/execjs/blob/master/README.md#readme" title="ExecJS">
943
+ JavaScript auszuführen
944
+ </a>.
945
+ </td>
946
+ </tr>
947
+ <tr>
948
+ <td>Dateierweiterung</td>
949
+ <td><tt>.styl</tt></td>
950
+ </tr>
951
+ <tr>
952
+ <td>Beispiel</td>
953
+ <td><tt>stylus :index</tt></td>
954
+ </tr>
955
+ </table>
956
+
957
+ Um Stylus-Templates ausführen zu können, müssen `stylus` und `stylus/tilt`
958
+ zuerst geladen werden:
959
+
960
+ ``` ruby
961
+ require 'sinatra'
962
+ require 'stylus'
963
+ require 'stylus/tilt'
964
+
965
+ get '/' do
966
+ stylus :example
967
+ end
968
+ ```
969
+
970
+ #### Yajl Templates
971
+
972
+ <table>
973
+ <tr>
974
+ <td>Abhängigkeit</td>
975
+ <td><a href="https://github.com/brianmario/yajl-ruby" title="yajl-ruby">yajl-ruby</a></td>
976
+ </tr>
977
+ <tr>
978
+ <td>Dateierweiterung</td>
979
+ <td><tt>.yajl</tt></td>
980
+ </tr>
981
+ <tr>
982
+ <td>Beispiel</td>
983
+ <td>
984
+ <tt>
985
+ yajl :index,
986
+ :locals => { :key => 'qux' },
987
+ :callback => 'present',
988
+ :variable => 'resource'
989
+ </tt>
990
+ </td>
991
+ </tr>
992
+ </table>
993
+
994
+ Die Template-Quelle wird als Ruby-String evaluiert. Die daraus resultierende
995
+ json Variable wird mit Hilfe von `#to_json` umgewandelt:
996
+
997
+ ``` ruby
998
+ json = { :foo => 'bar' }
999
+ json[:baz] = key
1000
+ ```
1001
+
1002
+ Die `:callback` und `:variable` Optionen können mit dem gerenderten Objekt
1003
+ verwendet werden:
1004
+
1005
+ ``` ruby
1006
+ var resource = {"foo":"bar","baz":"qux"}; present(resource);
1007
+ ```
1008
+
1009
+ #### WLang Templates
1010
+
1011
+ <table>
1012
+ <tr>
1013
+ <td>Abhängigkeit</td>
1014
+ <td><a href="https://github.com/blambeau/wlang/">wlang</a></td>
1015
+ </tr>
1016
+ <tr>
1017
+ <td>Dateierweiterung</td>
1018
+ <td><tt>.wlang</tt></td>
1019
+ </tr>
1020
+ <tr>
1021
+ <td>Beispiel</td>
1022
+ <td><tt>wlang :index, :locals => { :key => 'value' }</tt></td>
1023
+ </tr>
1024
+ </table>
1025
+
1026
+ Ruby-Methoden in wlang aufzurufen entspricht nicht den idiomatischen Vorgaben
1027
+ von wlang, es bietet sich deshalb an, `:locals` zu verwenden. Layouts, die
1028
+ wlang und `yield` verwenden, werden aber trotzdem unterstützt.
1029
+
1030
+ Rendert den eingebetteten Template-String.
1031
+
1032
+ ### Auf Variablen in Templates zugreifen
1033
+
1034
+ Templates werden in demselben Kontext ausgeführt wie Routen. Instanzvariablen
1035
+ in Routen sind auch direkt im Template verfügbar:
1036
+
1037
+ ```ruby
1038
+ get '/:id' do
1039
+ @foo = Foo.find(params[:id])
1040
+ haml '%h1= @foo.name'
1041
+ end
1042
+ ```
1043
+
1044
+ Oder durch einen expliziten Hash von lokalen Variablen:
1045
+
1046
+ ```ruby
1047
+ get '/:id' do
1048
+ foo = Foo.find(params[:id])
1049
+ haml '%h1= bar.name', :locals => { :bar => foo }
1050
+ end
1051
+ ```
1052
+
1053
+ Dies wird typischerweise bei Verwendung von Subtemplates (partials) in anderen
1054
+ Templates eingesetzt.
1055
+
1056
+ ### Templates mit `yield` und verschachtelte Layouts
1057
+
1058
+ Ein Layout ist üblicherweise ein Template, das ein `yield` aufruft. Ein solches
1059
+ Template kann entweder wie oben beschrieben über die `:template` Option
1060
+ verwendet werden oder mit einem Block gerendert werden:
1061
+
1062
+ ``` ruby
1063
+ erb :post, :layout => false do
1064
+ erb :index
1065
+ end
1066
+ ```
1067
+
1068
+ Dieser Code entspricht weitestgehend `erb :index, :layout => :post`.
1069
+
1070
+ Blöcke an Render-Methoden weiterzugeben ist besonders bei verschachtelten
1071
+ Layouts hilfreich:
1072
+
1073
+ ``` ruby
1074
+ erb :main_layout, :layout => false do
1075
+ erb :admin_layout do
1076
+ erb :user
1077
+ end
1078
+ end
1079
+ ```
1080
+
1081
+ Der gleiche Effekt kann auch mit weniger Code erreicht werden:
1082
+
1083
+ ``` ruby
1084
+ erb :admin_layout, :layout => :main_layout do
1085
+ erb :user
1086
+ end
1087
+ ```
1088
+
1089
+ Zur Zeit nehmen folgende Renderer Blöcke an: `erb`, `haml`, `liquid`, `slim `
1090
+ und `wlang`.
1091
+
1092
+ Das gleich gilt auch für die allgemeine `render` Methode.
1093
+
1094
+ ### Inline-Templates
1095
+
1096
+ Templates können auch am Ende der Datei definiert werden:
1097
+
1098
+ ```ruby
1099
+ require 'sinatra'
1100
+
1101
+ get '/' do
1102
+ haml :index
1103
+ end
1104
+
1105
+ __END__
1106
+
1107
+ @@ layout
1108
+ %html
1109
+ = yield
1110
+
1111
+ @@ index
1112
+ %div.title Hallo Welt!!!!!
1113
+ ```
1114
+
1115
+ Anmerkung: Inline-Templates, die in der Datei definiert sind, die `require
1116
+ 'sinatra'` aufruft, werden automatisch geladen. Um andere Inline-Templates in
1117
+ anderen Dateien aufzurufen, muss explizit `enable :inline_templates` verwendet
1118
+ werden.
1119
+
1120
+ ### Benannte Templates
1121
+
1122
+ Templates können auch mit der Top-Level `template`-Methode definiert werden:
1123
+
1124
+ ```ruby
1125
+ template :layout do
1126
+ "%html\n =yield\n"
1127
+ end
1128
+
1129
+ template :index do
1130
+ '%div.title Hallo Welt!'
1131
+ end
1132
+
1133
+ get '/' do
1134
+ haml :index
1135
+ end
1136
+ ```
1137
+
1138
+ Wenn ein Template mit dem Namen "layout" existiert, wird es bei jedem Aufruf
1139
+ verwendet. Durch `:layout => false` kann das Ausführen verhindert werden:
1140
+
1141
+ ```ruby
1142
+ get '/' do
1143
+ haml :index, :layout => !request.xhr?
1144
+ # !request.xhr? prüft, ob es sich um einen asynchronen Request handelt.
1145
+ # wenn nicht, dann verwende ein Layout (negiert durch !)
1146
+ end
1147
+ ```
1148
+
1149
+ ### Dateiendungen zuordnen
1150
+
1151
+ Um eine Dateiendung einer Template-Engine zuzuordnen, kann `Tilt.register`
1152
+ genutzt werden. Wenn etwa die Dateiendung `tt` für Textile-Templates genutzt
1153
+ werden soll, lässt sich dies wie folgt bewerkstelligen:
1154
+
1155
+ ```ruby
1156
+ Tilt.register :tt, Tilt[:textile]
1157
+ ```
1158
+
1159
+ ### Eine eigene Template-Engine hinzufügen
1160
+
1161
+ Zu allererst muss die Engine bei Tilt registriert und danach eine
1162
+ Rendering-Methode erstellt werden:
1163
+
1164
+ ```ruby
1165
+ Tilt.register :mtt, MeineTolleTemplateEngine
1166
+
1167
+ helpers do
1168
+ def mtt(*args) render(:mtt, *args) end
1169
+ end
1170
+
1171
+ get '/' do
1172
+ mtt :index
1173
+ end
1174
+ ```
1175
+
1176
+ Dieser Code rendert `./views/application.mtt`. Siehe
1177
+ [github.com/rtomayko/tilt](https://github.com/rtomayko/tilt), um mehr über
1178
+ Tilt zu erfahren.
1179
+
1180
+ ## Filter
1181
+
1182
+ Before-Filter werden vor jedem Request in demselben Kontext, wie danach die
1183
+ Routen, ausgeführt. So können etwa Request und Antwort geändert werden.
1184
+ Gesetzte Instanzvariablen in Filtern können in Routen und Templates verwendet
1185
+ werden:
1186
+
1187
+ ```ruby
1188
+ before do
1189
+ @note = 'Hi!'
1190
+ request.path_info = '/foo/bar/baz'
1191
+ end
1192
+
1193
+ get '/foo/*' do
1194
+ @note #=> 'Hi!'
1195
+ params[:splat] #=> 'bar/baz'
1196
+ end
1197
+ ```
1198
+
1199
+ After-Filter werden nach jedem Request in demselben Kontext ausgeführt und
1200
+ können ebenfalls Request und Antwort ändern. In Before-Filtern gesetzte
1201
+ Instanzvariablen können in After-Filtern verwendet werden:
1202
+
1203
+ ```ruby
1204
+ after do
1205
+ puts response.status
1206
+ end
1207
+ ```
1208
+
1209
+ Filter können optional auch mit einem Muster ausgestattet werden, das auf den
1210
+ Request-Pfad passen muss, damit der Filter ausgeführt wird:
1211
+
1212
+ ```ruby
1213
+ before '/protected/*' do
1214
+ authenticate!
1215
+ end
1216
+
1217
+ after '/create/:slug' do |slug|
1218
+ session[:last_slug] = slug
1219
+ end
1220
+ ```
1221
+
1222
+ Ähnlich wie Routen können Filter auch mit weiteren Bedingungen eingeschränkt
1223
+ werden:
1224
+
1225
+ ```ruby
1226
+ before :agent => /Songbird/ do
1227
+ # ...
1228
+ end
1229
+
1230
+ after '/blog/*', :host_name => 'example.com' do
1231
+ # ...
1232
+ end
1233
+ ```
1234
+
1235
+ ## Helfer
1236
+
1237
+ Durch die Top-Level `helpers`-Methode werden sogenannte Helfer-Methoden
1238
+ definiert, die in Routen und Templates verwendet werden können:
1239
+
1240
+ ```ruby
1241
+ helpers do
1242
+ def bar(name)
1243
+ "#{name}bar"
1244
+ end
1245
+ end
1246
+
1247
+ get '/:name' do
1248
+ bar(params[:name])
1249
+ end
1250
+ ```
1251
+
1252
+ ### Sessions verwenden
1253
+ Sessions werden verwendet, um Zustände zwischen den Requests zu speichern. Sind
1254
+ sie aktiviert, kann ein Session-Hash je Benutzer-Session verwendet werden:
1255
+
1256
+ ```ruby
1257
+ enable :sessions
1258
+
1259
+ get '/' do
1260
+ "value = " << session[:value].inspect
1261
+ end
1262
+
1263
+ get '/:value' do
1264
+ session[:value] = params[:value]
1265
+ end
1266
+ ```
1267
+
1268
+ Beachte, dass `enable :sessions` alle Daten in einem Cookie speichert. Unter
1269
+ Umständen kann dies negative Effekte haben, z.B. verursachen viele Daten
1270
+ höheren, teilweise überflüssigen Traffic. Um das zu vermeiden, kann eine Rack-
1271
+ Session-Middleware verwendet werden. Dabei wird auf `enable :sessions`
1272
+ verzichtet und die Middleware wie üblich im Programm eingebunden:
1273
+
1274
+ ```ruby
1275
+ use Rack::Session::Pool, :expire_after => 2592000
1276
+
1277
+ get '/' do
1278
+ "value = " << session[:value].inspect
1279
+ end
1280
+
1281
+ get '/:value' do
1282
+ session[:value] = params[:value]
1283
+ end
1284
+ ```
1285
+
1286
+ Um die Sicherheit zu erhöhen, werden Cookies, die Session-Daten führen, mit
1287
+ einem sogenannten Session-Secret signiert. Da sich dieses Geheimwort bei jedem
1288
+ Neustart der Applikation automatisch ändert, ist es sinnvoll, ein eigenes zu
1289
+ wählen, damit sich alle Instanzen der Applikation dasselbe Session-Secret
1290
+ teilen:
1291
+
1292
+ ```ruby
1293
+ set :session_secret, 'super_geheimes_Gegeimnis'
1294
+ ```
1295
+
1296
+ Zur weiteren Konfiguration kann man einen Hash mit Optionen in den `sessions`
1297
+ Einstellungen ablegen.
1298
+
1299
+ ```ruby
1300
+ set :sessions, :domain => 'foo.com'
1301
+ ```
1302
+
1303
+ ### Anhalten
1304
+
1305
+ Zum sofortigen Stoppen eines Request in einem Filter oder einer Route:
1306
+
1307
+ ```ruby
1308
+ halt
1309
+ ```
1310
+
1311
+ Der Status kann beim Stoppen mit angegeben werden:
1312
+
1313
+ ```ruby
1314
+ halt 410
1315
+ ```
1316
+
1317
+ Oder auch den Response-Body:
1318
+
1319
+ ```ruby
1320
+ halt 'Hier steht der Body'
1321
+ ```
1322
+
1323
+ Oder beides:
1324
+
1325
+ ```ruby
1326
+ halt 401, 'verschwinde!'
1327
+ ```
1328
+
1329
+ Sogar mit Headern:
1330
+
1331
+ ```ruby
1332
+ halt 402, {'Content-Type' => 'text/plain'}, 'Rache'
1333
+ ```
1334
+
1335
+ Natürlich ist es auch möglich, ein Template mit `halt` zu verwenden:
1336
+
1337
+ ```ruby
1338
+ halt erb(:error)
1339
+ ```
1340
+
1341
+ ### Weiterspringen
1342
+
1343
+ Eine Route kann mittels `pass` zu der nächsten passenden Route springen:
1344
+
1345
+ ```ruby
1346
+ get '/raten/:wer' do
1347
+ pass unless params[:wer] == 'Frank'
1348
+ 'Du hast mich!'
1349
+ end
1350
+
1351
+ get '/raten/*' do
1352
+ 'Du hast mich nicht!'
1353
+ end
1354
+ ```
1355
+
1356
+ Der Block wird sofort verlassen und es wird nach der nächsten treffenden Route
1357
+ gesucht. Ein 404-Fehler wird zurückgegeben, wenn kein treffendes Routen-Muster
1358
+ gefunden wird.
1359
+
1360
+ ### Eine andere Route ansteuern
1361
+
1362
+ Wenn nicht zu einer anderen Route gesprungen werden soll, sondern nur das
1363
+ Ergebnis einer anderen Route gefordert wird, kann `call` für einen internen
1364
+ Request verwendet werden:
1365
+
1366
+ ```ruby
1367
+ get '/foo' do
1368
+ status, headers, body = call env.merge("PATH_INFO" => '/bar')
1369
+ [status, headers, body.map(&:upcase)]
1370
+ end
1371
+
1372
+ get '/bar' do
1373
+ "bar"
1374
+ end
1375
+ ```
1376
+
1377
+ Beachte, dass in dem oben angegeben Beispiel die Performance erheblich erhöht
1378
+ werden kann, wenn `"bar"` in eine Helfer-Methode umgewandelt wird, auf die
1379
+ `/foo` und `/bar` zugreifen können.
1380
+
1381
+ Wenn der Request innerhalb derselben Applikations-Instanz aufgerufen und keine
1382
+ Kopie der Instanz erzeugt werden soll, kann `call!` anstelle von `call`
1383
+ verwendet werden.
1384
+
1385
+ ### Body, Status-Code und Header setzen
1386
+
1387
+ Es ist möglich und empfohlen, den Status-Code sowie den Response-Body mit einem
1388
+ Returnwert in der Route zu setzen. In manchen Situationen kann es jedoch sein,
1389
+ dass der Body an anderer Stelle während der Ausführung gesetzt werden soll.
1390
+ Dafür kann man die Helfer-Methode `body` einsetzen. Ist sie gesetzt, kann sie zu
1391
+ einem späteren Zeitpunkt aufgerufen werden:
1392
+
1393
+ ```ruby
1394
+ get '/foo' do
1395
+ body "bar"
1396
+ end
1397
+
1398
+ after do
1399
+ puts body
1400
+ end
1401
+ ```
1402
+
1403
+ Ebenso ist es möglich, einen Block an `body` weiterzureichen, der dann vom
1404
+ Rack-Handler ausgeführt wird (lässt sich z.B. zur Umsetzung von Streaming
1405
+ einsetzen, siehe auch "Rückgabewerte").
1406
+
1407
+ Vergleichbar mit `body` lassen sich auch Status-Code und Header setzen:
1408
+
1409
+ ```ruby
1410
+ get '/foo' do
1411
+ status 418
1412
+ headers \
1413
+ "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
1414
+ "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
1415
+ halt "Ich bin ein Teekesselchen"
1416
+ end
1417
+ ```
1418
+
1419
+ Genau wie bei `body` liest ein Aufrufen von `headers` oder `status` ohne
1420
+ Argumente den aktuellen Wert aus.
1421
+
1422
+ ### Response-Streams
1423
+
1424
+ In manchen Situationen sollen Daten bereits an den Client zurückgeschickt
1425
+ werden, bevor ein vollständiger Response bereit steht. Manchmal will man die
1426
+ Verbindung auch erst dann beenden und Daten so lange an den Client
1427
+ zurückschicken, bis er die Verbindung abbricht. Für diese Fälle gibt es die
1428
+ `stream`-Helfer-Methode, die es einem erspart eigene Lösungen zu schreiben:
1429
+
1430
+ ```ruby
1431
+ get '/' do
1432
+ stream do |out|
1433
+ out << "Das ist ja mal wieder fanta -\n"
1434
+ sleep 0.5
1435
+ out << " (bitte warten…) \n"
1436
+ sleep 1
1437
+ out << "- stisch!\n"
1438
+ end
1439
+ end
1440
+ ```
1441
+
1442
+ Damit lassen sich Streaming-APIs realisieren, sog.
1443
+ [Server Sent Events](http://dev.w3.org/html5/eventsource/), die als Basis für
1444
+ [WebSockets](http://en.wikipedia.org/wiki/WebSocket) dienen. Ebenso können sie
1445
+ verwendet werden, um den Durchsatz zu erhöhen, wenn ein Teil der Daten von
1446
+ langsamen Ressourcen abhängig ist.
1447
+
1448
+ Es ist zu beachten, dass das Verhalten beim Streaming, insbesondere die Anzahl
1449
+ nebenläufiger Anfragen, stark davon abhängt, welcher Webserver für die
1450
+ Applikation verwendet wird. Einige Server, z.B. WEBRick, unterstützen
1451
+ Streaming nicht oder nur teilweise. Sollte der Server Streaming nicht
1452
+ unterstützen, wird ein vollständiger Response-Body zurückgeschickt, sobald der
1453
+ an `stream` weitergegebene Block abgearbeitet ist. Mit Shotgun funktioniert
1454
+ Streaming z.B. überhaupt nicht.
1455
+
1456
+ Ist der optionale Parameter `keep_open` aktiviert, wird beim gestreamten Objekt
1457
+ `close` nicht aufgerufen und es ist einem überlassen dies an einem beliebigen
1458
+ späteren Zeitpunkt nachholen. Die Funktion ist jedoch nur bei Event-gesteuerten
1459
+ Serven wie Thin oder Rainbows möglich, andere Server werden trotzdem den Stream
1460
+ beenden:
1461
+
1462
+ ```ruby
1463
+ # Durchgehende Anfrage (long polling)
1464
+
1465
+ set :server, :thin
1466
+ connections = []
1467
+
1468
+ get '/subscribe' do
1469
+ # Client-Registrierung beim Server, damit Events mitgeteilt werden können
1470
+ stream(:keep_open) { |out| connections << out }
1471
+
1472
+ # tote Verbindungen entfernen
1473
+ connections.reject!(&:closed?)
1474
+
1475
+ # Rückmeldung
1476
+ "Angemeldet"
1477
+ end
1478
+
1479
+ post '/message' do
1480
+ connections.each do |out|
1481
+ # Den Client über eine neue Nachricht in Kenntnis setzen
1482
+ # notify client that a new message has arrived
1483
+ out << params[:message] << "\n"
1484
+
1485
+ # Den Client zur erneuten Verbindung auffordern
1486
+ out.close
1487
+ end
1488
+
1489
+ # Rückmeldung
1490
+ "Mitteiling erhalten"
1491
+ end
1492
+ ```
1493
+
1494
+ ### Logger
1495
+
1496
+ Im Geltungsbereich eines Request stellt die `logger` Helfer-Methode eine `Logger`
1497
+ Instanz zur Verfügung:
1498
+
1499
+ ```ruby
1500
+ get '/' do
1501
+ logger.info "es passiert gerade etwas"
1502
+ # ...
1503
+ end
1504
+ ```
1505
+
1506
+ Der Logger übernimmt dabei automatisch alle im Rack-Handler eingestellten
1507
+ Log-Vorgaben. Ist Loggen ausgeschaltet, gibt die Methode ein Leerobjekt zurück.
1508
+ In den Routen und Filtern muss man sich also nicht weiter darum kümmern.
1509
+
1510
+ Beachte, dass das Loggen standardmäßig nur für `Sinatra::Application`
1511
+ voreingestellt ist. Wird über `Sinatra::Base` vererbt, muss es erst aktiviert
1512
+ werden:
1513
+
1514
+ ```ruby
1515
+ class MyApp < Sinatra::Base
1516
+ configure :production, :development do
1517
+ enable :logging
1518
+ end
1519
+ end
1520
+ ```
1521
+
1522
+ Damit auch keine Middleware das Logging aktivieren kann, muss die `logging`
1523
+ Einstellung auf `nil` gesetzt werden. Das heißt aber auch, dass `logger` in
1524
+ diesem Fall `nil` zurückgeben wird. Üblicherweise wird das eingesetzt, wenn ein
1525
+ eigener Logger eingerichtet werden soll. Sinatra wird dann verwenden, was in
1526
+ `env['rack.logger']` eingetragen ist.
1527
+
1528
+ ### Mime-Types
1529
+
1530
+ Wenn `send_file` oder statische Dateien verwendet werden, kann es vorkommen,
1531
+ dass Sinatra den Mime-Typ nicht kennt. Registriert wird dieser mit `mime_type`
1532
+ per Dateiendung:
1533
+
1534
+ ```ruby
1535
+ configure do
1536
+ mime_type :foo, 'text/foo'
1537
+ end
1538
+ ```
1539
+
1540
+ Es kann aber auch der `content_type`-Helfer verwendet werden:
1541
+
1542
+ ```ruby
1543
+ get '/' do
1544
+ content_type :foo
1545
+ "foo foo foo"
1546
+ end
1547
+ ```
1548
+
1549
+ ### URLs generieren
1550
+
1551
+ Zum Generieren von URLs sollte die `url`-Helfer-Methode genutzen werden, so z.B.
1552
+ beim Einsatz von Haml:
1553
+
1554
+ ```ruby
1555
+ %a{:href => url('/foo')} foo
1556
+ ```
1557
+
1558
+ Soweit vorhanden, wird Rücksicht auf Proxys und Rack-Router genommen.
1559
+
1560
+ Diese Methode ist ebenso über das Alias `to` zu erreichen (siehe Beispiel unten).
1561
+
1562
+ ### Browser-Umleitung
1563
+
1564
+ Eine Browser-Umleitung kann mithilfe der `redirect`-Helfer-Methode erreicht
1565
+ werden:
1566
+
1567
+ ```ruby
1568
+ get '/foo' do
1569
+ redirect to('/bar')
1570
+ end
1571
+ ```
1572
+
1573
+ Weitere Parameter werden wie Argumente der `halt`-Methode behandelt:
1574
+
1575
+ ```ruby
1576
+ redirect to('/bar'), 303
1577
+ redirect 'http://google.com', 'Hier bist du falsch'
1578
+ ```
1579
+
1580
+ Ebenso leicht lässt sich ein Schritt zurück mit dem Alias `redirect back`
1581
+ erreichen:
1582
+
1583
+ ```ruby
1584
+ get '/foo' do
1585
+ "<a href='/bar'>mach was</a>"
1586
+ end
1587
+
1588
+ get '/bar' do
1589
+ mach_was
1590
+ redirect back
1591
+ end
1592
+ ```
1593
+
1594
+ Um Argumente an ein Redirect weiterzugeben, können sie entweder dem Query
1595
+ übergeben:
1596
+
1597
+ ```ruby
1598
+ redirect to('/bar?summe=42')
1599
+ ```
1600
+
1601
+ oder eine Session verwendet werden:
1602
+
1603
+ ```ruby
1604
+ enable :sessions
1605
+
1606
+ get '/foo' do
1607
+ session[:secret] = 'foo'
1608
+ redirect to('/bar')
1609
+ end
1610
+
1611
+ get '/bar' do
1612
+ session[:secret]
1613
+ end
1614
+ ```
1615
+
1616
+ ### Cache einsetzen
1617
+
1618
+ Ein sinnvolles Einstellen von Header-Daten ist die Grundlage für ein
1619
+ ordentliches HTTP-Caching.
1620
+
1621
+ Der Cache-Control-Header lässt sich ganz einfach einstellen:
1622
+
1623
+ ```ruby
1624
+ get '/' do
1625
+ cache_control :public
1626
+ "schon gecached!"
1627
+ end
1628
+ ```
1629
+
1630
+ Profitipp: Caching im before-Filter aktivieren
1631
+
1632
+ ```ruby
1633
+ before do
1634
+ cache_control :public, :must_revalidate, :max_age => 60
1635
+ end
1636
+ ```
1637
+
1638
+ Bei Verwendung der `expires`-Helfermethode zum Setzen des gleichnamigen Headers,
1639
+ wird `Cache-Control` automatisch eigestellt:
1640
+
1641
+ ```ruby
1642
+ before do
1643
+ expires 500, :public, :must_revalidate
1644
+ end
1645
+ ```
1646
+
1647
+ Um alles richtig zu machen, sollten auch `etag` oder `last_modified` verwendet
1648
+ werden. Es wird empfohlen, dass diese Helfer aufgerufen werden **bevor** die
1649
+ eigentliche Arbeit anfängt, da sie sofort eine Antwort senden, wenn der Client
1650
+ eine aktuelle Version im Cache vorhält:
1651
+
1652
+ ```ruby
1653
+ get '/article/:id' do
1654
+ @article = Article.find params[:id]
1655
+ last_modified @article.updated_at
1656
+ etag @article.sha1
1657
+ erb :article
1658
+ end
1659
+ ```
1660
+
1661
+ ebenso ist es möglich einen
1662
+ [schwachen ETag](http://de.wikipedia.org/wiki/HTTP_ETag) zu verwenden:
1663
+
1664
+ ```ruby
1665
+ etag @article.sha1, :weak
1666
+ ```
1667
+
1668
+ Diese Helfer führen nicht das eigentliche Caching aus, sondern geben die dafür
1669
+ notwendigen Informationen an den Cache weiter. Für schnelle Reverse-Proxy
1670
+ Cache-Lösungen bietet sich z.B.
1671
+ [rack-cache](https://github.com/rtomayko/rack-cache) an:
1672
+
1673
+ ```ruby
1674
+ require "rack/cache"
1675
+ require "sinatra"
1676
+
1677
+ use Rack::Cache
1678
+
1679
+ get '/' do
1680
+ cache_control :public, :max_age => 36000
1681
+ sleep 5
1682
+ "hello"
1683
+ end
1684
+ ```
1685
+
1686
+ Um den `Cache-Control`-Header mit Informationen zu versorgen, verwendet man die
1687
+ `:static_cache_control`-Einstellung (s.u.).
1688
+
1689
+ Nach RFC 2616 sollte sich die Anwendung anders verhalten, wenn ein If-Match oder
1690
+ ein If-None_match Header auf `*` gesetzt wird in Abhängigkeit davon, ob die
1691
+ Resource bereits existiert. Sinatra geht davon aus, dass Ressourcen bei sicheren
1692
+ Anfragen (z.B. bei get oder Idempotenten Anfragen wie put) bereits existieren,
1693
+ wobei anderen Ressourcen (besipielsweise bei post), als neue Ressourcen
1694
+ behandelt werden. Dieses Verhalten lässt sich mit der `:new_resource` Option
1695
+ ändern:
1696
+
1697
+ ```ruby
1698
+ get '/create' do
1699
+ etag '', :new_resource => true
1700
+ Article.create
1701
+ erb :new_article
1702
+ end
1703
+ ```
1704
+
1705
+ Soll das schwache ETag trotzdem verwendet werden, verwendet man die `:kind`
1706
+ Option:
1707
+
1708
+ ```ruby
1709
+ etag '', :new_resource => true, :kind => :weak
1710
+ ```
1711
+
1712
+ ### Dateien versenden
1713
+
1714
+ Zum Versenden von Dateien kann die `send_file`-Helfer-Methode verwendet werden:
1715
+
1716
+ ```ruby
1717
+ get '/' do
1718
+ send_file 'foo.png'
1719
+ end
1720
+ ```
1721
+
1722
+ Für `send_file` stehen einige Hash-Optionen zur Verfügung:
1723
+
1724
+ ```ruby
1725
+ send_file 'foo.png', :type => :jpg
1726
+ ```
1727
+
1728
+ <dl>
1729
+ <dt>filename</dt>
1730
+ <dd>Dateiname als Response. Standardwert ist der eigentliche Dateiname.</dd>
1731
+
1732
+ <dt>last_modified</dt>
1733
+ <dd>Wert für den Last-Modified-Header, Standardwert ist <tt>mtime</tt> der
1734
+ Datei.</dd>
1735
+
1736
+ <dt>type</dt>
1737
+ <dd>Content-Type, der verwendet werden soll. Wird, wenn nicht angegeben, von
1738
+ der Dateiendung abgeleitet.</dd>
1739
+
1740
+ <dt>disposition</dt>
1741
+ <dd>Verwendet für Content-Disposition. Mögliche Werte sind: <tt>nil</tt>
1742
+ (Standard), <tt>:attachment</tt> und <tt>:inline</tt>.</dd>
1743
+
1744
+ <dt>length</dt>
1745
+ <dd>Content-Length-Header. Standardwert ist die Dateigröße.</dd>
1746
+ </dl>
1747
+
1748
+ Soweit vom Rack-Handler unterstützt, werden neben der Übertragung über den
1749
+ Ruby-Prozess auch andere Möglichkeiten genutzt. Bei Verwendung der
1750
+ `send_file`-Helfer-Methode kümmert sich Sinatra selbstständig um die
1751
+ Range-Requests.
1752
+
1753
+ ### Das Request-Objekt
1754
+
1755
+ Auf das `request`-Objekt der eigehenden Anfrage kann vom Anfrage-Scope aus
1756
+ zugegriffen werden:
1757
+
1758
+ ```ruby
1759
+ # App läuft unter http://example.com/example
1760
+ get '/foo' do
1761
+ t = %w[text/css text/html application/javascript]
1762
+ request.accept # ['text/html', '*/*']
1763
+ request.accept? 'text/xml' # true
1764
+ request.preferred_type(t) # 'text/html'
1765
+ request.body # Request-Body des Client (siehe unten)
1766
+ request.scheme # "http"
1767
+ request.script_name # "/example"
1768
+ request.path_info # "/foo"
1769
+ request.port # 80
1770
+ request.request_method # "GET"
1771
+ request.query_string # ""
1772
+ request.content_length # Länge des request.body
1773
+ request.media_type # Medientypus von request.body
1774
+ request.host # "example.com"
1775
+ request.get? # true (ähnliche Methoden für andere Verben)
1776
+ request.form_data? # false
1777
+ request["irgendein_param"] # Wert von einem Parameter; [] ist die Kurzform für den params Hash
1778
+ request.referrer # Der Referrer des Clients oder '/'
1779
+ request.user_agent # User-Agent (verwendet in der :agent Bedingung)
1780
+ request.cookies # Hash des Browser-Cookies
1781
+ request.xhr? # Ist das hier ein Ajax-Request?
1782
+ request.url # "http://example.com/example/foo"
1783
+ request.path # "/example/foo"
1784
+ request.ip # IP-Adresse des Clients
1785
+ request.secure? # false (true wenn SSL)
1786
+ request.forwarded? # true (Wenn es hinter einem Reverse-Proxy verwendet wird)
1787
+ request.env # vollständiger env-Hash von Rack übergeben
1788
+ end
1789
+ ```
1790
+
1791
+ Manche Optionen, wie etwa `script_name` oder `path_info`, sind auch
1792
+ schreibbar:
1793
+
1794
+ ```ruby
1795
+ before { request.path_info = "/" }
1796
+
1797
+ get "/" do
1798
+ "Alle Anfragen kommen hier an!"
1799
+ end
1800
+ ```
1801
+
1802
+ Der `request.body` ist ein IO- oder StringIO-Objekt:
1803
+
1804
+ ```ruby
1805
+ post "/api" do
1806
+ request.body.rewind # falls schon jemand davon gelesen hat
1807
+ daten = JSON.parse request.body.read
1808
+ "Hallo #{daten['name']}!"
1809
+ end
1810
+ ```
1811
+
1812
+ ### Anhänge
1813
+
1814
+ Damit der Browser erkennt, dass ein Response gespeichert und nicht im Browser
1815
+ angezeigt werden soll, kann der `attachment`-Helfer verwendet werden:
1816
+
1817
+ ```ruby
1818
+ get '/' do
1819
+ attachment
1820
+ "Speichern!"
1821
+ end
1822
+ ```
1823
+
1824
+ Ebenso kann eine Dateiname als Parameter hinzugefügt werden:
1825
+
1826
+ ```ruby
1827
+ get '/' do
1828
+ attachment "info.txt"
1829
+ "Speichern!"
1830
+ end
1831
+ ```
1832
+
1833
+ ### Umgang mit Datum und Zeit
1834
+
1835
+ Sinatra bietet eine `time_for`-Helfer-Methode, die aus einem gegebenen Wert ein
1836
+ Time-Objekt generiert. Ebenso kann sie nach `DateTime`, `Date` und ähnliche
1837
+ Klassen konvertieren:
1838
+
1839
+ ```ruby
1840
+ get '/' do
1841
+ pass if Time.now > time_for('Dec 23, 2012')
1842
+ "noch Zeit"
1843
+ end
1844
+ ```
1845
+
1846
+ Diese Methode wird intern für +expires, `last_modiefied` und ihresgleichen
1847
+ verwendet. Mit ein paar Handgriffen lässt sich diese Methode also in ihrem
1848
+ Verhalten erweitern, indem man `time_for` in der eigenen Applikation
1849
+ überschreibt:
1850
+
1851
+ ```ruby
1852
+ helpers do
1853
+ def time_for(value)
1854
+ case value
1855
+ when :yesterday then Time.now - 24*60*60
1856
+ when :tomorrow then Time.now + 24*60*60
1857
+ else super
1858
+ end
1859
+ end
1860
+ end
1861
+
1862
+ get '/' do
1863
+ last_modified :yesterday
1864
+ expires :tomorrow
1865
+ "Hallo"
1866
+ end
1867
+ ```
1868
+
1869
+ ### Nachschlagen von Template-Dateien
1870
+
1871
+ Die `find_template`-Helfer-Methode wird genutzt, um Template-Dateien zum Rendern
1872
+ aufzufinden:
1873
+
1874
+ ```ruby
1875
+ find_template settings.views, 'foo', Tilt[:haml] do |file|
1876
+ puts "könnte diese hier sein: #{file}"
1877
+ end
1878
+ ```
1879
+
1880
+ Das ist zwar nicht wirklich brauchbar, aber wenn man sie überschreibt, kann sie
1881
+ nützlich werden, um eigene Nachschlage-Mechanismen einzubauen. Zum Beispiel
1882
+ dann, wenn mehr als nur ein view-Verzeichnis verwendet werden soll:
1883
+
1884
+ ```ruby
1885
+ set :views, ['views', 'templates']
1886
+
1887
+ helpers do
1888
+ def find_template(views, name, engine, &block)
1889
+ Array(views).each { |v| super(v, name, engine, &block) }
1890
+ end
1891
+ end
1892
+ ```
1893
+
1894
+ Ein anderes Beispiel wäre, verschiedene Vereichnisse für verschiedene Engines
1895
+ zu verwenden:
1896
+
1897
+ ```ruby
1898
+ set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
1899
+
1900
+ helpers do
1901
+ def find_template(views, name, engine, &block)
1902
+ _, folder = views.detect { |k,v| engine == Tilt[k] }
1903
+ folder ||= views[:default]
1904
+ super(folder, name, engine, &block)
1905
+ end
1906
+ end
1907
+ ```
1908
+
1909
+ Ebensogut könnte eine Extension aber auch geschrieben und mit anderen geteilt
1910
+ werden!
1911
+
1912
+ Beachte, dass `find_template` nicht prüft, ob eine Datei tatsächlich existiert.
1913
+ Es wird lediglich der angegebene Block aufgerufen und nach allen möglichen
1914
+ Pfaden gesucht. Das ergibt kein Performance-Problem, da `render` `block`
1915
+ verwendet, sobald eine Datei gefunden wurde. Ebenso werden Template-Pfade samt
1916
+ Inhalt gecached, solange nicht im Entwicklungsmodus gearbeitet wird. Das sollte
1917
+ im Hinterkopf behalten werden, wenn irgendwelche verrückten Methoden
1918
+ zusammenbastelt werden.
1919
+
1920
+ ### Konfiguration
1921
+
1922
+ Wird einmal beim Starten in jedweder Umgebung ausgeführt:
1923
+
1924
+ ```ruby
1925
+ configure do
1926
+ # setze eine Option
1927
+ set :option, 'wert'
1928
+
1929
+ # setze mehrere Optionen
1930
+ set :a => 1, :b => 2
1931
+
1932
+ # das gleiche wie `set :option, true`
1933
+ enable :option
1934
+
1935
+ # das gleiche wie `set :option, false`
1936
+ disable :option
1937
+
1938
+ # dynamische Einstellungen mit Blöcken
1939
+ set(:css_dir) { File.join(views, 'css') }
1940
+ end
1941
+ ```
1942
+
1943
+ Läuft nur, wenn die Umgebung (RACK_ENV-Umgebungsvariable) auf `:production`
1944
+ gesetzt ist:
1945
+
1946
+ ```ruby
1947
+ configure :production do
1948
+ ...
1949
+ end
1950
+ ```
1951
+
1952
+ Läuft nur, wenn die Umgebung auf `:production` oder auf `:test` gesetzt ist:
1953
+
1954
+ ```ruby
1955
+ configure :production, :test do
1956
+ ...
1957
+ end
1958
+ ```
1959
+
1960
+ Diese Einstellungen sind über `settings` erreichbar:
1961
+
1962
+ ```ruby
1963
+ configure do
1964
+ set :foo, 'bar'
1965
+ end
1966
+
1967
+ get '/' do
1968
+ settings.foo? # => true
1969
+ settings.foo # => 'bar'
1970
+ ...
1971
+ end
1972
+ ```
1973
+
1974
+ #### Einstellung des Angriffsschutzes
1975
+
1976
+ Sinatra verwendet
1977
+ [Rack::Protection](https://github.com/rkh/rack-protection#readme), um die
1978
+ Anwendung vor häufig vorkommenden Angriffen zu schützen. Diese Voreinstellung
1979
+ lässt sich selbstverständlich deaktivieren, der damit verbundene
1980
+ Geschwindigkeitszuwachs steht aber in keinem Verhätnis zu den möglichen
1981
+ Risiken.
1982
+
1983
+ ```ruby
1984
+ disable :protection
1985
+ ```
1986
+
1987
+ Um einen bestimmten Schutzmechanismus zu deaktivieren, fügt man `protection`
1988
+ einen Hash mit Optionen hinzu:
1989
+
1990
+ ```ruby
1991
+ set :protection, :except => :path_traversal
1992
+ ```
1993
+
1994
+ Neben Strings akzeptiert `:except` auch Arrays, um gleich mehrere
1995
+ Schutzmechanismen zu deaktivieren:
1996
+
1997
+ ```ruby
1998
+ set :protection, :except => [:path_traversal, :session_hijacking]
1999
+ ```
2000
+
2001
+ #### Mögliche Einstellungen
2002
+
2003
+ <dl>
2004
+ <dt>absolute_redirects</dt>
2005
+ <dd>Wenn ausgeschaltet, wird Sinatra relative Redirects zulassen. Jedoch ist
2006
+ Sinatra dann nicht mehr mit RFC 2616 (HTTP 1.1) konform, das nur absolute
2007
+ Redirects zulässt. Sollte eingeschaltet werden, wenn die Applikation hinter
2008
+ einem Reverse-Proxy liegt, der nicht ordentlich eingerichtet ist. Beachte,
2009
+ dass die <tt>url</tt>-Helfer-Methode nach wie vor absolute URLs erstellen
2010
+ wird, es sei denn, es wird als zweiter Parameter <tt>false</tt> angegeben.
2011
+ Standardmäßig nicht aktiviert.</dd>
2012
+
2013
+ <dt>add_charsets</dt>
2014
+ <dd>Mime-Types werden hier automatisch der Helfer-Methode
2015
+ <tt>content_type</tt> zugeordnet. Es empfielt sich, Werte hinzuzufügen statt
2016
+ sie zu überschreiben: <tt>settings.add_charsets << "application/foobar"</tt>
2017
+ </dd>
2018
+
2019
+ <dt>app_file</dt>
2020
+ <dd>Pfad zur Hauptdatei der Applikation. Wird verwendet, um das Wurzel-,
2021
+ Inline-, View- und öffentliche Verzeichnis des Projekts festzustellen.</dd>
2022
+
2023
+ <dt>bind</dt>
2024
+ <dd>IP-Address, an die gebunden wird (Standardwert: <tt>0.0.0.0</tt>
2025
+ <em>oder</em> <tt>localhost</tt>). Wird nur für den eingebauten Server
2026
+ verwendet.</dd>
2027
+
2028
+ <dt>default_encoding</dt>
2029
+ <dd>Das Encoding, falls keines angegeben wurde. Standardwert ist
2030
+ <tt>"utf-8"</tt>.</dd>
2031
+
2032
+ <dt>dump_errors</dt>
2033
+ <dd>Fehler im Log anzeigen.</dd>
2034
+
2035
+ <dt>environment</dt>
2036
+ <dd>Momentane Umgebung. Standardmäßig auf <tt>content_type</tt> oder
2037
+ <tt>"development"</tt> eingestellt, soweit ersteres nicht vorhanden.</dd>
2038
+
2039
+ <dt>logging</dt>
2040
+ <dd>Den Logger verwenden.</dd>
2041
+
2042
+ <dt>lock</dt>
2043
+ <dd>Jeder Request wird gelocked. Es kann nur ein Request pro Ruby-Prozess
2044
+ gleichzeitig verarbeitet werden. Eingeschaltet, wenn die Applikation
2045
+ threadsicher ist. Standardmäßig nicht aktiviert.</dd>
2046
+
2047
+ <dt>method_override</dt>
2048
+ <dd>Verwende <tt>_method</tt>, um put/delete-Formulardaten in Browsern zu
2049
+ verwenden, die dies normalerweise nicht unterstützen.</dd>
2050
+
2051
+ <dt>port</dt>
2052
+ <dd>Port für die Applikation. Wird nur im internen Server verwendet.</dd>
2053
+
2054
+ <dt>prefixed_redirects</dt>
2055
+ <dd>Entscheidet, ob <tt>request.script_name</tt> in Redirects eingefügt wird
2056
+ oder nicht, wenn kein absoluter Pfad angegeben ist. Auf diese Weise verhält
2057
+ sich <tt>redirect '/foo'</tt> so, als wäre es ein <tt>redirect
2058
+ to('/foo')</tt>. Standardmäßig nicht aktiviert.</dd>
2059
+
2060
+ <dt>protection</dt>
2061
+ <dd>Legt fest, ob der Schutzmechanismus für häufig Vorkommende Webangriffe
2062
+ auf Webapplikationen aktiviert wird oder nicht. Weitere Informationen im
2063
+ vorhergehenden Abschnitt.</dd>
2064
+
2065
+ <dt>public_folder</dt>
2066
+ <dd>Das öffentliche Verzeichnis, aus dem Daten zur Verfügung gestellt werden
2067
+ können. Wird nur dann verwendet, wenn statische Daten zur Verfügung gestellt
2068
+ werden können (s.u. <tt>static</tt> Option). Leitet sich von der
2069
+ <tt>app_file</tt> Einstellung ab, wenn nicht gesetzt.</dd>
2070
+
2071
+ <dt>public_dir</dt>
2072
+ <dd>Alias für <tt>public_folder</tt>, s.o.</dd>
2073
+
2074
+ <dt>reload_templates</dt>
2075
+ <dd>Im development-Modus aktiviert.</dd>
2076
+
2077
+ <dt>root</dt>
2078
+ <dd>Wurzelverzeichnis des Projekts. Leitet sich von der <tt>app_file</tt>
2079
+ Einstellung ab, wenn nicht gesetzt.</dd>
2080
+
2081
+ <dt>raise_errors</dt>
2082
+ <dd>Einen Ausnahmezustand aufrufen. Beendet die Applikation. Ist automatisch
2083
+ aktiviert, wenn die Umgebung auf <tt>"test"</tt> eingestellt ist. Ansonsten
2084
+ ist diese Option deaktiviert.</dd>
2085
+
2086
+ <dt>run</dt>
2087
+ <dd>Wenn aktiviert, wird Sinatra versuchen, den Webserver zu starten. Nicht
2088
+ verwenden, wenn Rackup oder anderes verwendet werden soll.</dd>
2089
+
2090
+ <dt>running</dt>
2091
+ <dd>Läuft der eingebaute Server? Diese Einstellung nicht ändern!</dd>
2092
+
2093
+ <dt>server</dt>
2094
+ <dd>Server oder Liste von Servern, die als eingebaute Server zur Verfügung
2095
+ stehen. Die Reihenfolge gibt die Priorität vor, die Voreinstellung hängt von
2096
+ der verwendenten Ruby Implementierung ab.</dd>
2097
+
2098
+ <dt>sessions</dt>
2099
+ <dd>Sessions auf Cookiebasis mittels
2100
+ <tt>Rack::Session::Cookie</tt>aktivieren. Für weitere Infos bitte in der
2101
+ Sektion ‘Sessions verwenden’ nachschauen.</dd>
2102
+
2103
+ <dt>show_exceptions</dt>
2104
+ <dd>Bei Fehlern einen Stacktrace im Browseranzeigen. Ist automatisch
2105
+ aktiviert, wenn die Umgebung auf <tt>"development"</tt> eingestellt ist.
2106
+ Ansonsten ist diese Option deaktiviert. Kann auch auf <tt>:after_handler</tt>
2107
+ gestellt werden, um eine anwendungsspezifische Fehlerbehandlung auszulösen,
2108
+ bevor der Fehlerverlauf im Browser angezeigt wird.</dd>
2109
+
2110
+ <dt>static</dt>
2111
+ <dd>Entscheidet, ob Sinatra statische Dateien zur Verfügung stellen soll oder
2112
+ nicht. Sollte nicht aktiviert werden, wenn ein Server verwendet wird, der
2113
+ dies auch selbstständig erledigen kann. Deaktivieren wird die Performance
2114
+ erhöhen. Standardmäßig aktiviert.</dd>
2115
+
2116
+ <dt>static_cache_control</dt>
2117
+ <dd>Wenn Sinatra statische Daten zur Verfügung stellt, können mit dieser
2118
+ Einstellung die <tt>Cache-Control</tt> Header zu den Responses hinzugefügt
2119
+ werden. Die Einstellung verwendet dazu die <tt>cache_control</tt>
2120
+ Helfer-Methode. Standardmäßig deaktiviert. Ein Array wird verwendet, um
2121
+ mehrere Werte gleichzeitig zu übergeben: <tt>set :static_cache_control,
2122
+ [:public, :max_age => 300]</tt></dd>
2123
+
2124
+ <dt>threaded</dt>
2125
+ <dd>Wird es auf <tt>true</tt> gesetzt, wird Thin aufgefordert
2126
+ <tt>EventMachine.defer</tt> zur Verarbeitung des Requests einzusetzen.</dd>
2127
+
2128
+ <dt>views</dt>
2129
+ <dd>Verzeichnis der Views. Leitet sich von der <tt>app_file</tt> Einstellung
2130
+ ab, wenn nicht gesetzt.</dd>
2131
+
2132
+ <dt>x_cascade</dt>
2133
+ <dd>Einstellung, ob der X-Cascade Header bei fehlender Route gesetzt wird oder
2134
+ nicht. Standardeinstellung ist <tt>true</tt>.</dd>
2135
+ </dl>
2136
+
2137
+ ## Umgebungen
2138
+
2139
+ Es gibt drei voreingestellte Umgebungen in Sinatra: `"development"`,
2140
+ `"production"` und `"test"`. Umgebungen können über die `RACK_ENV`
2141
+ Umgebungsvariable gesetzt werden. Die Standardeinstellung ist `"development"`.
2142
+ In diesem Modus werden alle Templates zwischen Requests neu geladen. Dazu gibt
2143
+ es besondere Fehlerseiten für 404 Stati und Fehlermeldungen. In `"production"`
2144
+ und `"test"` werden Templates automatisch gecached.
2145
+
2146
+ Um die Anwendung in einer anderen Umgebung auszuführen kann man die `-e`
2147
+ Option verwenden:
2148
+
2149
+ ```shell
2150
+ ruby my_app.rb -e [ENVIRONMENT]
2151
+ ```
2152
+
2153
+ In der Anwendung kann man die die Methoden `development?`, `test?` und
2154
+ `production?` verwenden, um die aktuelle Umgebung zu erfahren.
2155
+
2156
+ ## Fehlerbehandlung
2157
+
2158
+ Error-Handler laufen in demselben Kontext wie Routen und Filter, was bedeutet,
2159
+ dass alle Goodies wie `haml`, `erb`, `halt`, etc. verwendet werden können.
2160
+
2161
+ ### Nicht gefunden
2162
+
2163
+ Wenn eine `Sinatra::NotFound`-Exception geworfen wird oder der Statuscode 404
2164
+ ist, wird der `not_found`-Handler ausgeführt:
2165
+
2166
+ ```ruby
2167
+ not_found do
2168
+ 'Seite kann nirgendwo gefunden werden.'
2169
+ end
2170
+ ```
2171
+
2172
+ ### Fehler
2173
+
2174
+ Der `error`-Handler wird immer ausgeführt, wenn eine Exception in einem
2175
+ Routen-Block oder in einem Filter geworfen wurde. Die Exception kann über die
2176
+ `sinatra.error`-Rack-Variable angesprochen werden:
2177
+
2178
+ ```ruby
2179
+ error do
2180
+ 'Entschuldige, es gab einen hässlichen Fehler - ' + env['sinatra.error'].name
2181
+ end
2182
+ ```
2183
+
2184
+ Benutzerdefinierte Fehler:
2185
+
2186
+ ```ruby
2187
+ error MeinFehler do
2188
+ 'Au weia, ' + env['sinatra.error'].message
2189
+ end
2190
+ ```
2191
+
2192
+ Dann, wenn das passiert:
2193
+
2194
+ ```ruby
2195
+ get '/' do
2196
+ raise MeinFehler, 'etwas Schlimmes ist passiert'
2197
+ end
2198
+ ```
2199
+
2200
+ bekommt man dieses:
2201
+
2202
+ ```shell
2203
+ Au weia, etwas Schlimmes ist passiert
2204
+ ```
2205
+
2206
+ Alternativ kann ein Error-Handler auch für einen Status-Code definiert werden:
2207
+
2208
+ ```ruby
2209
+ error 403 do
2210
+ 'Zugriff verboten'
2211
+ end
2212
+
2213
+ get '/geheim' do
2214
+ 403
2215
+ end
2216
+ ```
2217
+
2218
+ Oder ein Status-Code-Bereich:
2219
+
2220
+ ```ruby
2221
+ error 400..510 do
2222
+ 'Hallo?'
2223
+ end
2224
+ ```
2225
+
2226
+ Sinatra setzt verschiedene `not_found`- und `error`-Handler in der
2227
+ Development-Umgebung ein, um hilfreiche Debugging Informationen und Stack Traces
2228
+ anzuzeigen.
2229
+
2230
+ ## Rack-Middleware
2231
+
2232
+ Sinatra baut auf [Rack](http://rack.rubyforge.org/), einem minimalistischen
2233
+ Standard-Interface für Ruby-Webframeworks. Eines der interessantesten Features
2234
+ für Entwickler ist der Support von Middlewares, die zwischen den Server und
2235
+ die Anwendung geschaltet werden und so HTTP-Request und/oder Antwort
2236
+ überwachen und/oder manipulieren können.
2237
+
2238
+ Sinatra macht das Erstellen von Middleware-Verkettungen mit der
2239
+ Top-Level-Methode `use` zu einem Kinderspiel:
2240
+
2241
+ ```ruby
2242
+ require 'sinatra'
2243
+ require 'meine_middleware'
2244
+
2245
+ use Rack::Lint
2246
+ use MeineMiddleware
2247
+
2248
+ get '/hallo' do
2249
+ 'Hallo Welt'
2250
+ end
2251
+ ```
2252
+
2253
+ Die Semantik von `use` entspricht der gleichnamigen Methode der
2254
+ [Rack::Builder](http://rack.rubyforge.org/doc/classes/Rack/Builder.html)-DSL
2255
+ (meist verwendet in Rackup-Dateien). Ein Beispiel dafür ist, dass die
2256
+ `use`-Methode mehrere/verschiedene Argumente und auch Blöcke entgegennimmt:
2257
+
2258
+ ```ruby
2259
+ use Rack::Auth::Basic do |username, password|
2260
+ username == 'admin' && password == 'geheim'
2261
+ end
2262
+ ```
2263
+
2264
+ Rack bietet eine Vielzahl von Standard-Middlewares für Logging, Debugging,
2265
+ URL-Routing, Authentifizierung und Session-Verarbeitung. Sinatra verwendet
2266
+ viele von diesen Komponenten automatisch, abhängig von der Konfiguration. So
2267
+ muss `use` häufig nicht explizit verwendet werden.
2268
+
2269
+ Hilfreiche Middleware gibt es z.B. hier:
2270
+ [rack](https://github.com/rack/rack/tree/master/lib/rack),
2271
+ [rack-contrib](https://github.com/rack/rack-contrib#readme),
2272
+ oder im [Rack wiki](https://github.com/rack/rack/wiki/List-of-Middleware).
2273
+
2274
+ ## Testen
2275
+
2276
+ Sinatra-Tests können mit jedem auf Rack aufbauendem Test-Framework geschrieben
2277
+ werden. [Rack::Test](http://rdoc.info/github/brynary/rack-test/master/frames)
2278
+ wird empfohlen:
2279
+
2280
+ ```ruby
2281
+ require 'my_sinatra_app'
2282
+ require 'test/unit'
2283
+ require 'rack/test'
2284
+
2285
+ class MyAppTest < Test::Unit::TestCase
2286
+ include Rack::Test::Methods
2287
+
2288
+ def app
2289
+ Sinatra::Application
2290
+ end
2291
+
2292
+ def test_my_default
2293
+ get '/'
2294
+ assert_equal 'Hallo Welt!', last_response.body
2295
+ end
2296
+
2297
+ def test_with_params
2298
+ get '/meet', :name => 'Frank'
2299
+ assert_equal 'Hallo Frank!', last_response.body
2300
+ end
2301
+
2302
+ def test_with_rack_env
2303
+ get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
2304
+ assert_equal "Du verwendest Songbird!", last_response.body
2305
+ end
2306
+ end
2307
+ ```
2308
+
2309
+ Hinweis: Wird Sinatra modular verwendet, muss <tt>Sinatra::Application</tt> mit
2310
+ dem Namen der Applikations-Klasse ersetzt werden.
2311
+
2312
+ ## Sinatra::Base - Middleware, Bibliotheken und modulare Anwendungen
2313
+
2314
+ Das Definieren einer Top-Level-Anwendung funktioniert gut für
2315
+ Mikro-Anwendungen, hat aber Nachteile, wenn wiederverwendbare Komponenten wie
2316
+ Middleware, Rails Metal, einfache Bibliotheken mit Server-Komponenten oder
2317
+ auch Sinatra-Erweiterungen geschrieben werden sollen.
2318
+
2319
+ Das Top-Level geht von einer Konfiguration für eine Mikro-Anwendung aus (wie
2320
+ sie z.B. bei einer einzelnen Anwendungsdatei, `./public` und `./views` Ordner,
2321
+ Logging, Exception-Detail-Seite, usw.). Genau hier kommt `Sinatra::Base` ins
2322
+ Spiel:
2323
+
2324
+ ```ruby
2325
+ require 'sinatra/base'
2326
+
2327
+ class MyApp < Sinatra::Base
2328
+ set :sessions, true
2329
+ set :foo, 'bar'
2330
+
2331
+ get '/' do
2332
+ 'Hallo Welt!'
2333
+ end
2334
+ end
2335
+ ```
2336
+
2337
+ Die MyApp-Klasse ist eine unabhängige Rack-Komponente, die als Middleware,
2338
+ Endpunkt oder via Rails Metal verwendet werden kann. Verwendet wird sie durch
2339
+ `use` oder `run` von einer Rackup-`config.ru`-Datei oder als Server-Komponente
2340
+ einer Bibliothek:
2341
+
2342
+ ```ruby
2343
+ MyApp.run! :host => 'localhost', :port => 9090
2344
+ ```
2345
+
2346
+ Die Methoden der `Sinatra::Base`-Subklasse sind genau dieselben wie die der
2347
+ Top-Level-DSL. Die meisten Top-Level-Anwendungen können mit nur zwei
2348
+ Veränderungen zu `Sinatra::Base` konvertiert werden:
2349
+
2350
+ * Die Datei sollte `require 'sinatra/base'` anstelle von `require
2351
+ 'sinatra/base'` aufrufen, ansonsten werden alle von Sinatras DSL-Methoden
2352
+ in den Top-Level-Namespace importiert.
2353
+ * Alle Routen, Error-Handler, Filter und Optionen der Applikation müssen in
2354
+ einer Subklasse von `Sinatra::Base` definiert werden.
2355
+
2356
+
2357
+ `Sinatra::Base` ist ein unbeschriebenes Blatt. Die meisten Optionen sind per
2358
+ Standard deaktiviert. Das betrifft auch den eingebauten Server. Siehe
2359
+ [Optionen und Konfiguration](http://sinatra.github.com/configuration.html) für
2360
+ Details über mögliche Optionen.
2361
+
2362
+ ### Modularer vs. klassischer Stil
2363
+
2364
+ Entgegen häufiger Meinungen gibt es nichts gegen den klassischen Stil
2365
+ einzuwenden. Solange es die Applikation nicht beeinträchtigt, besteht kein
2366
+ Grund, eine modulare Applikation zu erstellen.
2367
+
2368
+ Der größte Nachteil der klassischen Sinatra Anwendung gegenüber einer
2369
+ modularen ist die Einschränkung auf eine Sinatra Anwendung pro Ruby-Prozess.
2370
+ Sollen mehrere zum Einsatz kommen, muss auf den modularen Stil umgestiegen
2371
+ werden. Dabei ist es kein Problem klassische und modulare Anwendungen
2372
+ miteinander zu vermischen.
2373
+
2374
+ Bei einem Umstieg, sollten einige Unterschiede in den Einstellungen beachtet
2375
+ werden:
2376
+
2377
+ <table>
2378
+ <tr>
2379
+ <th>Szenario</th>
2380
+ <th>Classic</th>
2381
+ <th>Modular</th>
2382
+ </tr>
2383
+
2384
+ <tr>
2385
+ <td>app_file</td>
2386
+ <td>Sinatra ladende Datei</td>
2387
+ <td>Sinatra::Base subklassierende Datei</td>
2388
+ </tr>
2389
+
2390
+ <tr>
2391
+ <td>run</td>
2392
+ <td>$0 == app_file</td>
2393
+ <td>false</td>
2394
+ </tr>
2395
+
2396
+ <tr>
2397
+ <td>logging</td>
2398
+ <td>true</td>
2399
+ <td>false</td>
2400
+ </tr>
2401
+
2402
+ <tr>
2403
+ <td>method_override</td>
2404
+ <td>true</td>
2405
+ <td>false</td>
2406
+ </tr>
2407
+
2408
+ <tr>
2409
+ <td>inline_templates</td>
2410
+ <td>true</td>
2411
+ <td>false</td>
2412
+ </tr>
2413
+
2414
+ <tr>
2415
+ <td>static</td>
2416
+ <td>true</td>
2417
+ <td>false</td>
2418
+ </tr>
2419
+ </table>
2420
+
2421
+ ### Eine modulare Applikation bereitstellen
2422
+
2423
+ Es gibt zwei übliche Wege, eine modulare Anwendung zu starten. Zum einen über
2424
+ `run!`:
2425
+
2426
+ ```ruby
2427
+ # mein_app.rb
2428
+ require 'sinatra/base'
2429
+
2430
+ class MeinApp < Sinatra::Base
2431
+ # ... Anwendungscode hierhin ...
2432
+
2433
+ # starte den Server, wenn die Ruby-Datei direkt ausgeführt wird
2434
+ run! if app_file == $0
2435
+ end
2436
+ ```
2437
+
2438
+ Starte mit:
2439
+
2440
+ ```shell
2441
+ ruby mein_app.rb
2442
+ ```
2443
+
2444
+ Oder über eine `config.ru`-Datei, die es erlaubt, einen beliebigen
2445
+ Rack-Handler zu verwenden:
2446
+
2447
+ ```ruby
2448
+ # config.ru (mit rackup starten)
2449
+ require './mein_app'
2450
+ run MeineApp
2451
+ ```
2452
+
2453
+ Starte:
2454
+
2455
+ ```shell
2456
+ rackup -p 4567
2457
+ ```
2458
+
2459
+ ### Eine klassische Anwendung mit einer config.ru verwenden
2460
+
2461
+ Schreibe eine Anwendungsdatei:
2462
+
2463
+ ```ruby
2464
+ # app.rb
2465
+ require 'sinatra'
2466
+
2467
+ get '/' do
2468
+ 'Hallo Welt!'
2469
+ end
2470
+ ```
2471
+
2472
+ sowie eine dazugehörige `config.ru`-Datei:
2473
+
2474
+ ```ruby
2475
+ require './app'
2476
+ run Sinatra::Application
2477
+ ```
2478
+
2479
+ ### Wann sollte eine config.ru-Datei verwendet werden?
2480
+
2481
+ Anzeichen dafür, dass eine `config.ru`-Datei gebraucht wird:
2482
+
2483
+ * Es soll ein anderer Rack-Handler verwendet werden (Passenger, Unicorn,
2484
+ Heroku, ...).
2485
+ * Es gibt mehr als nur eine Subklasse von `Sinatra::Base`.
2486
+ * Sinatra soll als Middleware verwendet werden, nicht als Endpunkt.
2487
+
2488
+
2489
+ **Es gibt keinen Grund, eine `config.ru`-Datei zu verwenden, nur weil eine
2490
+ Anwendung im modularen Stil betrieben werden soll. Ebenso wird keine Anwendung
2491
+ mit modularem Stil benötigt, um eine `config.ru`-Datei zu verwenden.**
2492
+
2493
+ ### Sinatra als Middleware nutzen
2494
+
2495
+ Es ist nicht nur möglich, andere Rack-Middleware mit Sinatra zu nutzen, es
2496
+ kann außerdem jede Sinatra-Anwendung selbst als Middleware vor jeden
2497
+ beliebigen Rack-Endpunkt gehangen werden. Bei diesem Endpunkt muss es sich
2498
+ nicht um eine andere Sinatra-Anwendung handeln, es kann jede andere
2499
+ Rack-Anwendung sein (Rails/Ramaze/Camping/...):
2500
+
2501
+ ```ruby
2502
+ require 'sinatra/base'
2503
+
2504
+ class LoginScreen < Sinatra::Base
2505
+ enable :sessions
2506
+
2507
+ get('/login') { haml :login }
2508
+
2509
+ post('/login') do
2510
+ if params[:name] == 'admin' && params[:password] == 'admin'
2511
+ session['user_name'] = params[:name]
2512
+ else
2513
+ redirect '/login'
2514
+ end
2515
+ end
2516
+ end
2517
+
2518
+ class MyApp < Sinatra::Base
2519
+ # Middleware wird vor Filtern ausgeführt
2520
+ use LoginScreen
2521
+
2522
+ before do
2523
+ unless session['user_name']
2524
+ halt "Zugriff verweigert, bitte <a href='/login'>einloggen</a>."
2525
+ end
2526
+ end
2527
+
2528
+ get('/') { "Hallo #{session['user_name']}." }
2529
+ end
2530
+ ```
2531
+
2532
+ ### Dynamische Applikationserstellung
2533
+
2534
+ Manche Situationen erfordern die Erstellung neuer Applikationen zur Laufzeit,
2535
+ ohne dass sie einer Konstanten zugeordnet werden. Dies lässt sich mit
2536
+ `Sinatra.new` erreichen:
2537
+
2538
+ ```ruby
2539
+ require 'sinatra/base'
2540
+ my_app = Sinatra.new { get('/') { "hallo" } }
2541
+ my_app.run!
2542
+ ```
2543
+
2544
+ Die Applikation kann mit Hilfe eines optionalen Parameters erstellt werden:
2545
+
2546
+ ```ruby
2547
+ # config.ru
2548
+ require 'sinatra/base'
2549
+
2550
+ controller = Sinatra.new do
2551
+ enable :logging
2552
+ helpers MyHelpers
2553
+ end
2554
+
2555
+ map('/a') do
2556
+ run Sinatra.new(controller) { get('/') { 'a' } }
2557
+ end
2558
+
2559
+ map('/b') do
2560
+ run Sinatra.new(controller) { get('/') { 'b' } }
2561
+ end
2562
+ ```
2563
+
2564
+ Das ist besonders dann interessant, wenn Sinatra-Erweiterungen getestet werden
2565
+ oder Sinatra in einer Bibliothek Verwendung findet.
2566
+
2567
+ Ebenso lassen sich damit hervorragend Sinatra-Middlewares erstellen:
2568
+
2569
+ ```ruby
2570
+ require 'sinatra/base'
2571
+
2572
+ use Sinatra do
2573
+ get('/') { ... }
2574
+ end
2575
+
2576
+ run RailsProject::Application
2577
+ ```
2578
+
2579
+ ## Geltungsbereich und Bindung
2580
+
2581
+ Der Geltungsbereich (Scope) legt fest, welche Methoden und Variablen zur
2582
+ Verfügung stehen.
2583
+
2584
+ ### Anwendungs- oder Klassen-Scope
2585
+
2586
+ Jede Sinatra-Anwendung entspricht einer `Sinatra::Base`-Subklasse. Falls die
2587
+ Top- Level-DSL verwendet wird (`require 'sinatra'`), handelt es sich um
2588
+ `Sinatra::Application`, andernfalls ist es jene Subklasse, die explizit
2589
+ angelegt wurde. Auf Klassenebene stehen Methoden wie `get` oder `before` zur
2590
+ Verfügung, es gibt aber keinen Zugriff auf das `request`-Object oder die
2591
+ `session`, da nur eine einzige Klasse für alle eingehenden Anfragen genutzt
2592
+ wird.
2593
+
2594
+ Optionen, die via `set` gesetzt werden, sind Methoden auf Klassenebene:
2595
+
2596
+ ```ruby
2597
+ class MyApp < Sinatra::Base
2598
+ # Hey, ich bin im Anwendungsscope!
2599
+ set :foo, 42
2600
+ foo # => 42
2601
+
2602
+ get '/foo' do
2603
+ # Hey, ich bin nicht mehr im Anwendungs-Scope!
2604
+ end
2605
+ end
2606
+ ```
2607
+
2608
+ Im Anwendungs-Scope befindet man sich:
2609
+
2610
+ * In der Anwendungs-Klasse.
2611
+ * In Methoden, die von Erweiterungen definiert werden.
2612
+ * Im Block, der an `helpers` übergeben wird.
2613
+ * In Procs und Blöcken, die an `set` übergeben werden.
2614
+ * Der an `Sinatra.new` übergebene Block
2615
+
2616
+
2617
+ Auf das Scope-Objekt (die Klasse) kann wie folgt zugegriffen werden:
2618
+
2619
+ * Über das Objekt, das an den `configure`-Block übergeben wird (`configure {
2620
+ |c| ... }`).
2621
+ * `settings` aus den anderen Scopes heraus.
2622
+
2623
+
2624
+ ### Anfrage- oder Instanz-Scope
2625
+
2626
+ Für jede eingehende Anfrage wird eine neue Instanz der Anwendungs-Klasse
2627
+ erstellt und alle Handler in diesem Scope ausgeführt. Aus diesem Scope heraus
2628
+ kann auf `request` oder `session` zugegriffen und Methoden wie `erb` oder
2629
+ `haml` aufgerufen werden. Außerdem kann mit der `settings`-Method auf den
2630
+ Anwendungs-Scope zugegriffen werden:
2631
+
2632
+ ```ruby
2633
+ class MyApp < Sinatra::Base
2634
+ # Hey, ich bin im Anwendungs-Scope!
2635
+ get '/neue_route/:name' do
2636
+ # Anfrage-Scope für '/neue_route/:name'
2637
+ @value = 42
2638
+
2639
+ settings.get "/#{params[:name]}" do
2640
+ # Anfrage-Scope für "/#{params[:name]}"
2641
+ @value # => nil (nicht dieselbe Anfrage)
2642
+ end
2643
+
2644
+ "Route definiert!"
2645
+ end
2646
+ end
2647
+ ```
2648
+
2649
+ Im Anfrage-Scope befindet man sich:
2650
+
2651
+ * In get, head, post, put, delete, options, patch, link und unlink Blöcken
2652
+ * In before und after Filtern
2653
+ * In Helfer-Methoden
2654
+ * In Templates
2655
+
2656
+
2657
+ ### Delegation-Scope
2658
+
2659
+ Vom Delegation-Scope aus werden Methoden einfach an den Klassen-Scope
2660
+ weitergeleitet. Dieser verhält sich jedoch nicht 100%ig wie der Klassen-Scope,
2661
+ da man nicht die Bindung der Klasse besitzt: Nur Methoden, die explizit als
2662
+ delegierbar markiert wurden, stehen hier zur Verfügung und es kann nicht auf
2663
+ die Variablen des Klassenscopes zugegriffen werden (mit anderen Worten: es
2664
+ gibt ein anderes `self`). Weitere Delegationen können mit
2665
+ `Sinatra::Delegator.delegate :methoden_name` hinzugefügt werden.
2666
+
2667
+ Im Delegation-Scop befindet man sich:
2668
+
2669
+ * Im Top-Level, wenn `require 'sinatra'` aufgerufen wurde.
2670
+ * In einem Objekt, das mit dem `Sinatra::Delegator`-Mixin erweitert wurde.
2671
+
2672
+
2673
+ Schau am besten im Code nach: Hier ist [Sinatra::Delegator
2674
+ mixin](http://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1064
2675
+ ) definiert und wird in den [globalen Namespace
2676
+ eingebunden](http://github.com/sinatra/sinatra/blob/master/lib/sinatra/main.rb
2677
+
2678
+ ## Kommandozeile
2679
+
2680
+ Sinatra-Anwendungen können direkt von der Kommandozeile aus gestartet werden:
2681
+
2682
+ ```shell
2683
+ ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-h HOST] [-s HANDLER]
2684
+ ```
2685
+
2686
+ Die Optionen sind:
2687
+
2688
+ ```
2689
+ -h # Hilfe
2690
+ -p # Port setzen (Standard ist 4567)
2691
+ -h # Host setzen (Standard ist 0.0.0.0)
2692
+ -e # Umgebung setzen (Standard ist development)
2693
+ -s # Rack-Server/Handler setzen (Standard ist thin)
2694
+ -x # Mutex-Lock einschalten (Standard ist off)
2695
+ ```
2696
+
2697
+ ## Systemanforderungen
2698
+
2699
+ Die folgenden Versionen werden offiziell unterstützt:
2700
+
2701
+ <dl>
2702
+ <dt>Ruby 1.8.7</dt>
2703
+ <dd>1.8.7 wird vollständig unterstützt, ein Wechsel zu JRuby oder Rubinius wird
2704
+ aber empfohlen. Ruby 1.8.7 wird noch bis Sinatra 2.0 unterstützt werden. Frühere
2705
+ Versionen von Ruby sind nicht kompatibel mit Sinatra.</dd>
2706
+
2707
+ <dt>Ruby 1.9.2</dt>
2708
+ <dd>1.9.2 wird mindestens bis Sinatra 1.5 voll unterstützt. Version 1.9.2p0
2709
+ sollte nicht verwendet werden, da unter Sinatra immer wieder Segfaults
2710
+ auftreten.</dd>
2711
+
2712
+ <dt>Ruby 1.9.3</dt>
2713
+ <dd>1.9.3 wird vollständig unterstützt und empfohlen. Achtung, bei einem
2714
+ Upgrade von einer früheren Version von Ruby zu Ruby 1.9.3 werden alle Sessions
2715
+ ungültig. Ruby 1.9.3 wird bis Sinatra 2.0 unterstützt werden.</dd>
2716
+
2717
+ <dt>Rubinius</dt>
2718
+ <dd>Rubinius (Version >= 2.x) wird offiziell unterstützt. Es wird empfohlen, den
2719
+ <a href="http://puma.io">Puma Server</a> zu installieren (<tt>gem install puma
2720
+ </tt>)</dd>
2721
+
2722
+ <dt>JRuby</dt>
2723
+ <dd>Aktuelle JRuby Versionen werden offiziell unterstützt. Es wird empfohlen,
2724
+ keine C-Erweiterungen zu verwenden und als Server Trinidad zu verwenden
2725
+ (<tt>gem install trinidad</tt>).</dd>
2726
+ </dl>
2727
+
2728
+ Die nachfolgend aufgeführten Ruby-Implementierungen werden offiziell nicht von
2729
+ Sinatra unterstützt, funktionieren aber normalerweise:
2730
+
2731
+ * Ruby Enterprise Edition
2732
+ * Ältere Versionen von JRuby und Rubinius
2733
+ * MacRuby (<tt>gem install control_tower</tt> wird empfohlen), Maglev, IronRuby
2734
+ * Ruby 1.9.0 und 1.9.1
2735
+
2736
+ Nicht offiziell unterstützt bedeutet, dass wenn Sachen nicht funktionieren,
2737
+ wir davon ausgehen, dass es nicht an Sinatra sondern an der jeweiligen
2738
+ Implementierung liegt.
2739
+
2740
+ Im Rahmen unserer CI (Kontinuierlichen Integration) wird bereits ruby-head
2741
+ (das kommende Ruby 2.1.0) mit eingebunden. Es kann davon ausgegangen
2742
+ werden, dass Sinatra Ruby 2.1.0 vollständig unterstützen wird.
2743
+
2744
+ Sinatra sollte auf jedem Betriebssystem laufen, dass einen funktionierenden
2745
+ Ruby-Interpreter aufweist.
2746
+
2747
+ Sinatra läuft aktuell nicht unter Cardinal, SmallRuby, BlueRuby oder Ruby <= 1.8.7.
2748
+
2749
+ ## Der neuste Stand (The Bleeding Edge)
2750
+
2751
+ Um auf dem neusten Stand zu bleiben, kann der Master-Branch verwendet werden.
2752
+ Er sollte recht stabil sein. Ebenso gibt es von Zeit zu Zeit prerelease Gems,
2753
+ die so installiert werden:
2754
+
2755
+ ```shell
2756
+ gem install sinatra --pre
2757
+ ```
2758
+
2759
+ ### Mit Bundler
2760
+
2761
+ Wenn die Applikation mit der neuesten Version von Sinatra und
2762
+ [Bundler](http://gembundler.com/) genutzt werden soll, empfehlen wir den
2763
+ nachfolgenden Weg.
2764
+
2765
+ Soweit Bundler noch nicht installiert ist:
2766
+
2767
+ ```shell
2768
+ gem install bundler
2769
+ ```
2770
+
2771
+ Anschließend wird eine `Gemfile`-Datei im Projektverzeichnis mit folgendem
2772
+ Inhalt erstellt:
2773
+
2774
+ ```ruby
2775
+ source :rubygems
2776
+ gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
2777
+
2778
+ # evtl. andere Abhängigkeiten
2779
+ gem 'haml' # z.B. wenn du Haml verwendest...
2780
+ gem 'activerecord', '~> 3.0' # ...oder ActiveRecord 3.x
2781
+ ```
2782
+
2783
+ Beachte: Hier sollten alle Abhängigkeiten eingetragen werden. Sinatras eigene,
2784
+ direkte Abhängigkeiten (Tilt und Rack) werden von Bundler automatisch aus dem
2785
+ Gemfile von Sinatra hinzugefügt.
2786
+
2787
+ Jetzt kannst du deine Applikation starten:
2788
+
2789
+ ```shell
2790
+ bundle exec ruby myapp.rb
2791
+ ```
2792
+
2793
+ ### Eigenes Repository
2794
+ Um auf dem neuesten Stand von Sinatras Code zu sein, kann eine lokale Kopie
2795
+ angelegt werden. Gestartet wird in der Anwendung mit dem `sinatra/lib`-Ordner
2796
+ im `LOAD_PATH`:
2797
+
2798
+ ```shell
2799
+ cd myapp
2800
+ git clone git://github.com/sinatra/sinatra.git
2801
+ ruby -Isinatra/lib myapp.rb
2802
+ ```
2803
+
2804
+ Alternativ kann der `sinatra/lib`-Ordner zum `LOAD_PATH` in der Anwendung
2805
+ hinzugefügt werden:
2806
+
2807
+ ```ruby
2808
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
2809
+ require 'rubygems'
2810
+ require 'sinatra'
2811
+
2812
+ get '/ueber' do
2813
+ "Ich laufe auf Version " + Sinatra::VERSION
2814
+ end
2815
+ ```
2816
+
2817
+ Um Sinatra-Code von Zeit zu Zeit zu aktualisieren:
2818
+
2819
+ ```shell
2820
+ cd myproject/sinatra
2821
+ git pull
2822
+ ```
2823
+
2824
+ ### Gem erstellen
2825
+
2826
+ Aus der eigenen lokalen Kopie kann nun auch ein globales Gem gebaut werden:
2827
+
2828
+ ```shell
2829
+ git clone git://github.com/sinatra/sinatra.git
2830
+ cd sinatra
2831
+ rake sinatra.gemspec
2832
+ rake install
2833
+ ```
2834
+
2835
+ Falls Gems als Root installiert werden sollen, sollte die letzte Zeile
2836
+ folgendermaßen lauten:
2837
+
2838
+ ```shell
2839
+ sudo rake install
2840
+ ```
2841
+
2842
+ ## Versions-Verfahren
2843
+
2844
+ Sinatra folgt dem sogenannten [Semantic Versioning](http://semver.org/), d.h.
2845
+ SemVer und SemVerTag.
2846
+
2847
+ ## Mehr
2848
+
2849
+ * [Projekt-Website](http://sinatra.github.com/) - Ergänzende Dokumentation,
2850
+ News und Links zu anderen Ressourcen.
2851
+ * [Mitmachen](http://sinatra.github.com/contributing.html) - Einen Fehler
2852
+ gefunden? Brauchst du Hilfe? Hast du einen Patch?
2853
+ * [Issue-Tracker](http://github.com/sinatra/sinatra/issues)
2854
+ * [Twitter](http://twitter.com/sinatra)
2855
+ * [Mailing-Liste](http://groups.google.com/group/sinatrarb)
2856
+ * [#sinatra](irc://chat.freenode.net/#sinatra) auf http://freenode.net Es
2857
+ gibt dort auch immer wieder deutschsprachige Entwickler, die gerne weiterhelfen.
2858
+ * [Sinatra Book](http://sinatra-book.gittr.com) Kochbuch Tutorial
2859
+ * [Sinatra Recipes](http://recipes.sinatrarb.com/) Sinatra-Rezepte aus der
2860
+ Community
2861
+ * API Dokumentation für die [aktuelle
2862
+ Version](http://rubydoc.info/gems/sinatra) oder für
2863
+ [HEAD](http://rubydoc.info/github/sinatra/sinatra) auf http://rubydoc.info
2864
+ * [CI Server](http://travis-ci.org/sinatra/sinatra)