sinatra 1.0 → 1.1.a
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sinatra might be problematic. Click here for more details.
- data/CHANGES +108 -1
- data/LICENSE +1 -1
- data/README.de.rdoc +1024 -0
- data/README.es.rdoc +1047 -0
- data/README.fr.rdoc +1038 -0
- data/README.hu.rdoc +607 -0
- data/README.jp.rdoc +473 -15
- data/README.rdoc +429 -41
- data/Rakefile +17 -6
- data/lib/sinatra/base.rb +357 -158
- data/lib/sinatra/showexceptions.rb +9 -1
- data/sinatra.gemspec +52 -9
- data/test/builder_test.rb +25 -1
- data/test/coffee_test.rb +88 -0
- data/test/encoding_test.rb +18 -0
- data/test/filter_test.rb +61 -2
- data/test/hello.mab +1 -0
- data/test/helper.rb +1 -0
- data/test/helpers_test.rb +141 -37
- data/test/less_test.rb +26 -2
- data/test/liquid_test.rb +58 -0
- data/test/markaby_test.rb +58 -0
- data/test/markdown_test.rb +35 -0
- data/test/nokogiri_test.rb +69 -0
- data/test/radius_test.rb +59 -0
- data/test/rdoc_test.rb +34 -0
- data/test/request_test.rb +12 -0
- data/test/routing_test.rb +35 -1
- data/test/sass_test.rb +46 -16
- data/test/scss_test.rb +88 -0
- data/test/settings_test.rb +32 -0
- data/test/sinatra_test.rb +4 -0
- data/test/static_test.rb +64 -0
- data/test/templates_test.rb +55 -1
- data/test/textile_test.rb +34 -0
- data/test/views/ascii.haml +2 -0
- data/test/views/explicitly_nested.str +1 -0
- data/test/views/hello.coffee +1 -0
- data/test/views/hello.liquid +1 -0
- data/test/views/hello.mab +1 -0
- data/test/views/hello.md +1 -0
- data/test/views/hello.nokogiri +1 -0
- data/test/views/hello.radius +1 -0
- data/test/views/hello.rdoc +1 -0
- data/test/views/hello.sass +1 -1
- data/test/views/hello.scss +3 -0
- data/test/views/hello.str +1 -0
- data/test/views/hello.textile +1 -0
- data/test/views/layout2.liquid +2 -0
- data/test/views/layout2.mab +2 -0
- data/test/views/layout2.nokogiri +3 -0
- data/test/views/layout2.radius +2 -0
- data/test/views/layout2.str +2 -0
- data/test/views/nested.str +1 -0
- data/test/views/utf8.haml +2 -0
- metadata +240 -33
- data/lib/sinatra/tilt.rb +0 -746
data/CHANGES
CHANGED
@@ -1,4 +1,111 @@
|
|
1
|
-
= 1.
|
1
|
+
= 1.1 / Not Yet Released
|
2
|
+
|
3
|
+
* Before and after filters now support pattern matching, including the
|
4
|
+
ability to use captures: "before('/user/:name') { |name| ... }". This
|
5
|
+
avoids manual path checking. No performance loss if patterns are avoided.
|
6
|
+
(Konstantin Haase)
|
7
|
+
|
8
|
+
* It is now possible to render SCSS files with the `scss` method, which
|
9
|
+
behaves exactly like `sass` except for the different file extension and
|
10
|
+
assuming the SCSS syntax. (Pedro Menezes, Konstantin Haase)
|
11
|
+
|
12
|
+
* Added `liquid`, `markdown`, `nokogiri`, `textile`, `rdoc`, `radius`,
|
13
|
+
`markaby`, and `coffee` rendering methods for rendering Liquid, Markdown,
|
14
|
+
Nokogiri, Textile, RDoc, Radius, Markaby and CoffeeScript templates.
|
15
|
+
(Konstantin Haase)
|
16
|
+
|
17
|
+
* Now supports byte-range requests (the HTTP_RANGE header) for static files.
|
18
|
+
Multi-range requests are not supported, however. (Jens Alfke)
|
19
|
+
|
20
|
+
* You can now use #settings method from class and top level for convenience.
|
21
|
+
(Konstantin Haase)
|
22
|
+
|
23
|
+
* Setting multiple values now no longer relies on #to_hash and therefore
|
24
|
+
accepts any Enumerable as parameter. (Simon Rozet)
|
25
|
+
|
26
|
+
* Nested templates default the `layout` option to `false` rather than `true`.
|
27
|
+
This eases the use of partials. If you wanted to render one haml template
|
28
|
+
embedded in another, you had to call `haml :partial, {}, :layout => false`.
|
29
|
+
As you almost never want the partial to be wrapped in the standard layout
|
30
|
+
in this situation, you now only have to call `haml :partial`. Passing in
|
31
|
+
`layout` explicitly is still possible. (Konstantin Haase)
|
32
|
+
|
33
|
+
* If a the return value of one of the render functions is used as a response
|
34
|
+
body and the content type has not been set explicitly, Sinatra chooses a
|
35
|
+
content type corresponding to the rendering engine rather than just using
|
36
|
+
"text/html". (Konstantin Haase)
|
37
|
+
|
38
|
+
* README is now available in French (Mickael Riga), German (Bernhard Essl,
|
39
|
+
Konstantin Haase, burningTyger), Hungarian (Janos Hardi) and Spanish
|
40
|
+
(Gabriel Andretta). The extremely outdated Japanese README has been updated
|
41
|
+
(Kouhei Yanagita).
|
42
|
+
|
43
|
+
* It is now possible to access Sinatra's template_cache from the outside.
|
44
|
+
(Nick Sutterer)
|
45
|
+
|
46
|
+
* The `last_modified` method now also accepts DateTime instances and makes
|
47
|
+
sure the header will always be set to a string. (Konstantin Haase)
|
48
|
+
|
49
|
+
* 599 now is a legal status code. (Steve Shreeve)
|
50
|
+
|
51
|
+
* This release is compatible with Ruby 1.9.2. Sinatra was trying to read
|
52
|
+
none existent files Ruby added to the call stack. (Shota Fukumori,
|
53
|
+
Konstantin Haase)
|
54
|
+
|
55
|
+
* Prevents a memory leak on 1.8.6 is production mode. Note, however, that
|
56
|
+
this is due to a bug in 1.8.6 and request will have the additional overhead
|
57
|
+
of parsing templates again on that version. It is recommended to use at
|
58
|
+
least Ruby 1.8.7. (Konstantin Haase)
|
59
|
+
|
60
|
+
* Compares last modified date correctly. `last_modified` was halting only
|
61
|
+
when the 'If-Modified-Since' header date was equal to the time specified.
|
62
|
+
Now, it halts when is equal or later than the time specified (Gabriel
|
63
|
+
Andretta).
|
64
|
+
|
65
|
+
* Sinatra is now usable in combination with Rails 3. When mounting a Sinatra
|
66
|
+
application under a subpath in Rails 3, the PATH_INFO is not prefixed with
|
67
|
+
a slash and no routes did match. (José Valim)
|
68
|
+
|
69
|
+
* Better handling of encodings in 1.9, defaults params encoding to UTF-8 and
|
70
|
+
respects Encoding.default_internal and Encoding.default_external.
|
71
|
+
(Konstantin Haase)
|
72
|
+
|
73
|
+
* `show_exeptions` handling is now triggered after custom error handlers, if
|
74
|
+
it is set to `:after_handlers`, thus not disabling those handler in
|
75
|
+
development mode. (pangel, Konstantin Haase)
|
76
|
+
|
77
|
+
* Added ability to handle weighted HTTP_ACCEPT headers. (Davide D'Agostino)
|
78
|
+
|
79
|
+
* `send_file` now always respects the `:type` option if set. Previously it
|
80
|
+
was discarded if no matching mime type was found, which made it impossible
|
81
|
+
to directly pass a mime type. (Konstantin Haase)
|
82
|
+
|
83
|
+
* `redirect` always redirects to an absolute URI, even if a relative URI was
|
84
|
+
passed. Ensures compatibility with RFC 2616 section 14.30. (Jean-Philippe
|
85
|
+
Garcia Ballester, Anthony Williams)
|
86
|
+
|
87
|
+
* Broken examples for using Erubis, Haml and Test::Unit in README have been
|
88
|
+
fixed. (Nick Sutterer, Doug Ireton, Jason Stewart, Eric Marden)
|
89
|
+
|
90
|
+
* Sinatra now handles SIGTERM correctly. (Patrick Collison)
|
91
|
+
|
92
|
+
* Fixes an issue with inline templates in modular applications that manually
|
93
|
+
call `run!`. (Konstantin Haase)
|
94
|
+
|
95
|
+
* Spaces after inline template names are now ignored (Konstantin Haase)
|
96
|
+
|
97
|
+
* It's now possible to use Sinatra with different package management
|
98
|
+
systems defining a custom require. (Konstantin Haase)
|
99
|
+
|
100
|
+
* Lighthouse has been dropped in favor of GitHub issues.
|
101
|
+
|
102
|
+
* Tilt is now a dependency and therefore no longer ships bundled with
|
103
|
+
Sinatra. (Ryan Tomayko, Konstantin Haase)
|
104
|
+
|
105
|
+
* Sinatra now depends on Rack 1.1 or higher. Rack 1.0 is no longer supported.
|
106
|
+
(Konstantin Haase)
|
107
|
+
|
108
|
+
= 1.0 / 2010-03-23
|
2
109
|
|
3
110
|
* It's now possible to register blocks to run after each request using
|
4
111
|
after filters. After filters run at the end of each request, after
|
data/LICENSE
CHANGED
data/README.de.rdoc
ADDED
@@ -0,0 +1,1024 @@
|
|
1
|
+
= Sinatra
|
2
|
+
<i>Wichtig: Dieses Dokument ist eine Übersetzung aus dem Englischen und unter Umständen nicht auf dem aktuellsten Stand.</i>
|
3
|
+
|
4
|
+
Sinatra ist eine DSL, die das schnelle Erstellen von Webanwendungen in Ruby
|
5
|
+
mit minimalen Aufwand ermöglicht:
|
6
|
+
|
7
|
+
# myapp.rb
|
8
|
+
require 'sinatra'
|
9
|
+
get '/' do
|
10
|
+
'Hallo Welt!'
|
11
|
+
end
|
12
|
+
|
13
|
+
Einfach via rubygems installieren und starten:
|
14
|
+
|
15
|
+
gem install sinatra
|
16
|
+
ruby -rubygems myapp.rb
|
17
|
+
|
18
|
+
Die Seite kann nun unter http://localhost:4567 betrachtet werden.
|
19
|
+
|
20
|
+
== Routen
|
21
|
+
|
22
|
+
In Sinatra wird eine Route durch eine HTTP-Methode und ein URL-Muster definiert. Jeder dieser Routen wird ein
|
23
|
+
Ruby-Block zugeordnet.
|
24
|
+
|
25
|
+
get '/' do
|
26
|
+
.. zeige etwas ..
|
27
|
+
end
|
28
|
+
|
29
|
+
post '/' do
|
30
|
+
.. erstelle etwas ..
|
31
|
+
end
|
32
|
+
|
33
|
+
put '/' do
|
34
|
+
.. update etwas ..
|
35
|
+
end
|
36
|
+
|
37
|
+
delete '/' do
|
38
|
+
.. entferne etwas ..
|
39
|
+
end
|
40
|
+
|
41
|
+
Die Routen werden in der Reihenfolge durchlaufen, in der sie definiert wurden.
|
42
|
+
Das erste Routemuster, das mit dem Request übereinstimmt, wird ausgeführt.
|
43
|
+
|
44
|
+
Die Muster der Routen können benannte Parameter beinhalten, die über den
|
45
|
+
<tt>params</tt>-Hash zugänglich gemacht werden:
|
46
|
+
|
47
|
+
get '/hallo/:name' do
|
48
|
+
# passt auf "GET /hallo/foo" und "GET /hallo/bar"
|
49
|
+
# params[:name] ist 'foo' oder 'bar'
|
50
|
+
"Hallo #{params[:name]}!"
|
51
|
+
end
|
52
|
+
|
53
|
+
Man kann auf diese auch mit Blockparametern zugreifen:
|
54
|
+
|
55
|
+
get '/hallo/:name' do |n|
|
56
|
+
"Hallo #{n}!"
|
57
|
+
end
|
58
|
+
|
59
|
+
Routenmuster können auch mit Splat- oder Wildcardparametern über das
|
60
|
+
<tt>params[:splat]</tt> Array angesprochen werden.
|
61
|
+
|
62
|
+
get '/sag/*/zu/*' do
|
63
|
+
# passt auf /sag/hallo/zu/welt
|
64
|
+
params[:splat] # => ["hallo", "welt"]
|
65
|
+
end
|
66
|
+
|
67
|
+
get '/download/*.*' do
|
68
|
+
# passt auf /download/pfad/zu/datei.xml
|
69
|
+
params[:splat] # => ["pfad/zu/datei", "xml"]
|
70
|
+
end
|
71
|
+
|
72
|
+
Routen mit regulären Ausdrücken sind auch möglich:
|
73
|
+
|
74
|
+
get %r{/hallo/([\w]+)} do
|
75
|
+
"Hallo, #{params[:captures].first}!"
|
76
|
+
end
|
77
|
+
|
78
|
+
Und auch hier kann man Blockparameter nutzen:
|
79
|
+
|
80
|
+
get %r{/hallo/([\w]+)} do |c|
|
81
|
+
"Hallo, #{c}!"
|
82
|
+
end
|
83
|
+
|
84
|
+
=== Bedingungen
|
85
|
+
|
86
|
+
An Routen können eine Vielzahl von Bedingungen angehängt werden, die erfüllt
|
87
|
+
sein müssen, damit der Block ausgeführt wird. Möglich wäre etwa eine
|
88
|
+
Einschränkung des User Agents:
|
89
|
+
|
90
|
+
get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
|
91
|
+
"Du verwendest Songbird Version #{params[:agent][0]}"
|
92
|
+
end
|
93
|
+
|
94
|
+
get '/foo' do
|
95
|
+
# passt auf andere Browser
|
96
|
+
end
|
97
|
+
|
98
|
+
Andere mitgelieferte Bedingungen sind +host_name+ und +provides+:
|
99
|
+
|
100
|
+
get '/', :host_name => /^admin\./ do
|
101
|
+
"Adminbereich, Zugriff verweigert!"
|
102
|
+
end
|
103
|
+
|
104
|
+
get '/', :provides => 'html' do
|
105
|
+
haml :index
|
106
|
+
end
|
107
|
+
|
108
|
+
get '/', :provides => ['rss', 'atom', 'xml'] do
|
109
|
+
builder :feed
|
110
|
+
end
|
111
|
+
|
112
|
+
Man kann auch relativ einfach eigene Bedingungen hinzufügen:
|
113
|
+
|
114
|
+
set(:probability) { |value| condition { rand <= value } }
|
115
|
+
|
116
|
+
get '/auto_gewinnen', :probability => 0.1 do
|
117
|
+
"Du hast gewonnen!"
|
118
|
+
end
|
119
|
+
|
120
|
+
get '/auto_gewinnen' do
|
121
|
+
"Tut mir leid, verloren."
|
122
|
+
end
|
123
|
+
|
124
|
+
=== Rückgabewerte
|
125
|
+
|
126
|
+
Durch den Rückgabewert eines Routenblocks wird mindestens der Response Body
|
127
|
+
festgelegt, der an den HTTP Client, bzw die nächste Rack Middleware
|
128
|
+
weitergegeben wird. Im Normalfall handelt es sich hierbei, wie
|
129
|
+
in den vorangehenden Beispielen zu sehen war, um einen String. Es werden allerdings auch andere
|
130
|
+
Werte akzeptiert.
|
131
|
+
|
132
|
+
Man kann jedes Objekt zurückgeben, bei dem es sich entweder um einenen validen
|
133
|
+
Rack-Rückgabewert, einen validen Rack-Body oder einen HTTP Status Code
|
134
|
+
handelt:
|
135
|
+
|
136
|
+
* Ein Array mit drei Elementen: <tt>[Status (Fixnum), Headers (Hash), Response Body (hört auf #each)]</tt>
|
137
|
+
* Ein Array mit zwei Elementen: <tt>[Status (Fixnum), Response Body (hört auf #each)]</tt>
|
138
|
+
* Ein Objekt, das auf <tt>#each</tt> hört und den an diese Methode übergebenen Block nur mit Strings als Übergabewerte aufruft.
|
139
|
+
* Ein Fixnum, das den Status Code festlegt.
|
140
|
+
|
141
|
+
Damit lässt sich relativ einfach Streaming implementieren:
|
142
|
+
|
143
|
+
class Stream
|
144
|
+
def each
|
145
|
+
100.times { |i| yield "#{i}\n" }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
get('/') { Stream.new }
|
150
|
+
|
151
|
+
== Statische Dateien
|
152
|
+
|
153
|
+
Statische Dateien werden aus dem <tt>./public</tt> Ordner ausgeliefert. Es ist
|
154
|
+
möglich einen anderen Ort zu definieren, indem man die <tt>:public</tt> Option
|
155
|
+
setzt:
|
156
|
+
|
157
|
+
set :public, File.dirname(__FILE__) + '/static'
|
158
|
+
|
159
|
+
Zu beachten ist, dass der Ordnername public nicht Teil der URL ist. Die Datei
|
160
|
+
<tt>./public/css/style.css</tt> ist unter
|
161
|
+
<tt>http://example.com/css/style.css</tt> zu finden.
|
162
|
+
|
163
|
+
== Views / Templates
|
164
|
+
|
165
|
+
Standardmäßig wird davon ausgegangen, dass sich Templates im
|
166
|
+
<tt>./views</tt> Ordner befinden. Man kann jedoch einen anderen Ordner
|
167
|
+
festlegen:
|
168
|
+
|
169
|
+
set :views, File.dirname(__FILE__) + '/templates'
|
170
|
+
|
171
|
+
Eine wichtige Sache, die man sich hierbei merken sollte, ist das man immer mit
|
172
|
+
Symbols auf Templates verweisen sollte, auch wenn sich ein Template in einem
|
173
|
+
Unterordner befindet (in diesen Fall <tt>:'subdir/template'</tt>).
|
174
|
+
Renderingmethoden rendern jeden String direkt.
|
175
|
+
|
176
|
+
=== Haml-Templates
|
177
|
+
|
178
|
+
Das haml gem wird benötigt, um Haml-Templates rendern zu können:
|
179
|
+
|
180
|
+
## haml muss eingebunden werden
|
181
|
+
require 'haml'
|
182
|
+
|
183
|
+
get '/' do
|
184
|
+
haml :index
|
185
|
+
end
|
186
|
+
|
187
|
+
Dieser Code rendert <tt>./views/index.haml</tt>.
|
188
|
+
|
189
|
+
{Hamls Optionen}[http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#options]
|
190
|
+
können global durch die Sinatrakonfiguration gesetzt werden,
|
191
|
+
siehe {Optionen und Konfiguration}[http://www.sinatrarb.com/configuration.html],
|
192
|
+
und individuell überschrieben werden.
|
193
|
+
|
194
|
+
set :haml, :format => :html5 # Standard Haml-Format ist :xhtml
|
195
|
+
|
196
|
+
get '/' do
|
197
|
+
haml :index, :format => :html4 # überschrieben
|
198
|
+
end
|
199
|
+
|
200
|
+
=== Erb-Templates
|
201
|
+
|
202
|
+
## erb muss eingebunden werden
|
203
|
+
require 'erb'
|
204
|
+
|
205
|
+
get '/' do
|
206
|
+
erb :index
|
207
|
+
end
|
208
|
+
|
209
|
+
Dieser Code rendert <tt>./views/index.erb</tt>.
|
210
|
+
|
211
|
+
=== Erubis
|
212
|
+
|
213
|
+
Das erubis gem wird benötigt, um Erubis-Templates rendern zu können:
|
214
|
+
|
215
|
+
## erbubis muss eingebunden werden
|
216
|
+
require 'erubis'
|
217
|
+
|
218
|
+
get '/' do
|
219
|
+
erubis :index
|
220
|
+
end
|
221
|
+
|
222
|
+
Dieser Code rendert <tt>./views/index.erubis</tt>.
|
223
|
+
|
224
|
+
=== Builder-Templates
|
225
|
+
|
226
|
+
Das buidler gem wird benötigt, um Builder-Templates rendern zu können:
|
227
|
+
|
228
|
+
## builder muss eingebunden werden
|
229
|
+
require 'builder'
|
230
|
+
|
231
|
+
get '/' do
|
232
|
+
builder :index
|
233
|
+
end
|
234
|
+
|
235
|
+
Dieser Code rendert <tt>./views/index.builder</tt>.
|
236
|
+
|
237
|
+
=== Nokogiri-Templates
|
238
|
+
|
239
|
+
Das nokogiri gem wird benötigt, um Nokogiri-Templates rendern zu können:
|
240
|
+
|
241
|
+
## nokogiri muss eingebunden werden
|
242
|
+
require 'nokogiri'
|
243
|
+
|
244
|
+
get '/' do
|
245
|
+
nokogiri :index
|
246
|
+
end
|
247
|
+
|
248
|
+
Dieser Code rendert <tt>./views/index.nokogiri</tt>.
|
249
|
+
|
250
|
+
=== Sass-Templates
|
251
|
+
|
252
|
+
Das haml gem wird benötigt, um SASS-Templates rendern zu können:
|
253
|
+
|
254
|
+
## sass muss eingebunden werden
|
255
|
+
require 'sass'
|
256
|
+
|
257
|
+
get '/stylesheet.css' do
|
258
|
+
sass :stylesheet
|
259
|
+
end
|
260
|
+
|
261
|
+
Dieser Code rendert <tt>./views/stylesheet.sass</tt>.
|
262
|
+
|
263
|
+
{Sass Optionen}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options]
|
264
|
+
können global durch die Sinatra-Konfiguration gesetzt werden,
|
265
|
+
siehe {Optionen und Konfiguration}[http://www.sinatrarb.com/configuration.html],
|
266
|
+
und individuell überschrieben werden.
|
267
|
+
|
268
|
+
set :sass, :style => :compact # Standard Sass-Style ist :nested
|
269
|
+
|
270
|
+
get '/stylesheet.css' do
|
271
|
+
sass :stylesheet, :style => :expanded # überschrieben
|
272
|
+
end
|
273
|
+
|
274
|
+
=== Scss-Templates
|
275
|
+
|
276
|
+
Das haml gem wird benötigt, um SCSS-Templates rendern zu können:
|
277
|
+
|
278
|
+
## sass muss eingebunden werden
|
279
|
+
require 'sass'
|
280
|
+
|
281
|
+
get '/stylesheet.css' do
|
282
|
+
scss :stylesheet
|
283
|
+
end
|
284
|
+
|
285
|
+
Dieser Code rendert <tt>./views/stylesheet.scss</tt>.
|
286
|
+
|
287
|
+
{Scss Optionen}[http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options]
|
288
|
+
können global durch die Sinatra-Konfiguration gesetzt werden,
|
289
|
+
siehe {Optionen und Konfiguration}[http://www.sinatrarb.com/configuration.html],
|
290
|
+
und individuell überschrieben werden.
|
291
|
+
|
292
|
+
set :scss, :style => :compact # Standard Scss-Style ist :nested
|
293
|
+
|
294
|
+
get '/stylesheet.css' do
|
295
|
+
scss :stylesheet, :style => :expanded # überschrieben
|
296
|
+
end
|
297
|
+
|
298
|
+
=== Less-Templates
|
299
|
+
|
300
|
+
Das less gem wird benötigt, um Less-Templates rendern zu können:
|
301
|
+
|
302
|
+
## less muss eingebunden werden
|
303
|
+
require 'less'
|
304
|
+
|
305
|
+
get '/stylesheet.css' do
|
306
|
+
less :stylesheet
|
307
|
+
end
|
308
|
+
|
309
|
+
Dieser Code rendert <tt>./views/stylesheet.less</tt>.
|
310
|
+
|
311
|
+
=== Liquid-Templates
|
312
|
+
|
313
|
+
Das liquid gem wird benötigt, um Liquid-Templates rendern zu können:
|
314
|
+
|
315
|
+
## liquid muss eingebunden werden
|
316
|
+
require 'liquid'
|
317
|
+
|
318
|
+
get '/' do
|
319
|
+
liquid :index
|
320
|
+
end
|
321
|
+
|
322
|
+
Dieser Code rendert <tt>./views/index.liquid</tt>.
|
323
|
+
|
324
|
+
Da man aus Liquid-Templates heraus keine Methoden (abgesehen von +yield+)
|
325
|
+
aufrufen kann, will man nahezu in allen Fällen +locals+ übergeben:
|
326
|
+
|
327
|
+
liquid :index, :locals => { :key => 'value' }
|
328
|
+
|
329
|
+
=== Markdown-Templates
|
330
|
+
|
331
|
+
Das rdiscount gem wird benötigt, um Markdown-Templates rendern zu können:
|
332
|
+
|
333
|
+
## rdiscount muss eingebunden werden
|
334
|
+
require "rdiscount"
|
335
|
+
|
336
|
+
get '/' do
|
337
|
+
markdown :index
|
338
|
+
end
|
339
|
+
|
340
|
+
Dieser Code rendert <tt>./views/index.markdown</tt> (+md+ und +mkd+ sind
|
341
|
+
ebenfalls zulässige Dateiendungen).
|
342
|
+
|
343
|
+
Da es weder möglich ist Methoden aufzurufen, noch +locals+ zu übergeben, ist
|
344
|
+
es am sinnvollsten Markdown in Kombination mit einer anderen Template-Engine
|
345
|
+
zu nutzen:
|
346
|
+
|
347
|
+
erb :overview, :locals => { :text => markdown(:introduction) }
|
348
|
+
|
349
|
+
Es ist auch möglich die +markdown+ Methode aus anderen Templates heraus
|
350
|
+
aufzurufen:
|
351
|
+
|
352
|
+
%h1 Hallo von Haml!
|
353
|
+
%p= markdown(:greetings)
|
354
|
+
|
355
|
+
=== Textile-Templates
|
356
|
+
|
357
|
+
Das RedCloth gem wird benötigt, um Textile-Templates rendern zu können:
|
358
|
+
|
359
|
+
## redcloth muss eingebunden werden
|
360
|
+
require "redcloth"
|
361
|
+
|
362
|
+
get '/' do
|
363
|
+
textile :index
|
364
|
+
end
|
365
|
+
|
366
|
+
Dieser Code rendert <tt>./views/index.textile</tt>.
|
367
|
+
|
368
|
+
Da es weder möglich ist Methoden aufzurufen, noch +locals+ zu übergeben, ist
|
369
|
+
es am sinnvollsten Textile in Kombination mit einer anderen Template-Engine
|
370
|
+
zu nutzen:
|
371
|
+
|
372
|
+
erb :overview, :locals => { :text => textile(:introduction) }
|
373
|
+
|
374
|
+
Es ist auch möglich die +textile+ Methode aus anderen Templates heraus
|
375
|
+
aufzurufen:
|
376
|
+
|
377
|
+
%h1 Hallo von Haml!
|
378
|
+
%p= textile(:greetings)
|
379
|
+
|
380
|
+
=== RDoc-Templates
|
381
|
+
|
382
|
+
Das rdoc gem wird benötigt, um RDoc-Templates rendern zu können:
|
383
|
+
|
384
|
+
## RDoc muss eingebunden werden
|
385
|
+
require "rdoc"
|
386
|
+
|
387
|
+
get '/' do
|
388
|
+
rdoc :index
|
389
|
+
end
|
390
|
+
|
391
|
+
Dieser Code rendert <tt>./views/index.rdoc</tt>.
|
392
|
+
|
393
|
+
Da es weder möglich ist Methoden aufzurufen, noch +locals+ zu übergeben, ist
|
394
|
+
es am sinnvollsten RDoc in Kombination mit einer anderen Template-Engine
|
395
|
+
zu nutzen:
|
396
|
+
|
397
|
+
erb :overview, :locals => { :text => rdoc(:introduction) }
|
398
|
+
|
399
|
+
Es ist auch möglich die +rdoc+ Methode aus anderen Templates heraus
|
400
|
+
aufzurufen:
|
401
|
+
|
402
|
+
%h1 Hallo von Haml!
|
403
|
+
%p= rdoc(:greetings)
|
404
|
+
|
405
|
+
=== Radius-Templates
|
406
|
+
|
407
|
+
Das radius gem wird benötigt, um Radius-Templates rendern zu können:
|
408
|
+
|
409
|
+
## radius muss eingebunden werden
|
410
|
+
require 'radius'
|
411
|
+
|
412
|
+
get '/' do
|
413
|
+
radius :index
|
414
|
+
end
|
415
|
+
|
416
|
+
Dieser Code rendert <tt>./views/index.radius</tt>.
|
417
|
+
|
418
|
+
Da man aus Radius-Templates heraus keine Methoden (abgesehen von +yield+)
|
419
|
+
aufrufen kann, will man nahezu in allen Fällen +locals+ übergeben:
|
420
|
+
|
421
|
+
radius :index, :locals => { :key => 'value' }
|
422
|
+
|
423
|
+
=== Markaby-Templates
|
424
|
+
|
425
|
+
Das markaby gem wird benötigt, um Markaby-Templates rendern zu können:
|
426
|
+
|
427
|
+
## markaby muss eingebunden werden
|
428
|
+
require 'markaby'
|
429
|
+
|
430
|
+
get '/' do
|
431
|
+
markaby :index
|
432
|
+
end
|
433
|
+
|
434
|
+
Dieser Code rendert <tt>./views/index.mab</tt>.
|
435
|
+
|
436
|
+
=== CoffeScript-Templates
|
437
|
+
|
438
|
+
Das coffee-script gem und das `coffee`-Programm werden benötigt, um CoffeScript-Templates rendern zu können:
|
439
|
+
|
440
|
+
## coffee-script muss eingebunden werden
|
441
|
+
require 'coffee-script'
|
442
|
+
|
443
|
+
get '/application.js' do
|
444
|
+
coffee :application
|
445
|
+
end
|
446
|
+
|
447
|
+
Dieser Code rendert <tt>./views/application.coffee</tt>.
|
448
|
+
|
449
|
+
=== Inline-Templates
|
450
|
+
|
451
|
+
get '/' do
|
452
|
+
haml '%div.title Hallo Welt'
|
453
|
+
end
|
454
|
+
|
455
|
+
Rendert den Inline-Template-String.
|
456
|
+
|
457
|
+
=== Auf Variablen in Templates zugreifen
|
458
|
+
|
459
|
+
Templates werden im selben Kontext ausgeführt wie Routen. Instanzvariablen in
|
460
|
+
Routen sind auch direkt im Template verfügbar:
|
461
|
+
|
462
|
+
get '/:id' do
|
463
|
+
@foo = Foo.find(params[:id])
|
464
|
+
haml '%h1= @foo.name'
|
465
|
+
end
|
466
|
+
|
467
|
+
Oder durch einen expliziten Hash von lokalen Variablen:
|
468
|
+
|
469
|
+
get '/:id' do
|
470
|
+
foo = Foo.find(params[:id])
|
471
|
+
haml '%h1= foo.name', :locals => { :foo => foo }
|
472
|
+
end
|
473
|
+
|
474
|
+
Dies wird typischerweise bei Verwendung von Subtemplates (partials) in anderen
|
475
|
+
Templates eingesetzt.
|
476
|
+
|
477
|
+
=== Inline-Templates
|
478
|
+
|
479
|
+
Templates können auch am Ende der Datei definiert werden:
|
480
|
+
|
481
|
+
require 'sinatra'
|
482
|
+
|
483
|
+
get '/' do
|
484
|
+
haml :index
|
485
|
+
end
|
486
|
+
|
487
|
+
__END__
|
488
|
+
|
489
|
+
@@ layout
|
490
|
+
%html
|
491
|
+
= yield
|
492
|
+
|
493
|
+
@@ index
|
494
|
+
%div.title Hallo Welt!!!!!
|
495
|
+
|
496
|
+
Anmerkung: Inline-Templates die in der Datei definiert sind, die <tt>require
|
497
|
+
'sinatra'</tt> aufruft, werden automatisch geladen. Um andere Inline-Templates
|
498
|
+
in anderen Dateien aufzurufen, muss <tt>enable :inline_templates</tt> explizit
|
499
|
+
verwendet werden.
|
500
|
+
|
501
|
+
=== Benannte Templates
|
502
|
+
|
503
|
+
Templates können auch mit der Top-Level <tt>template</tt>-Methode definiert
|
504
|
+
werden:
|
505
|
+
|
506
|
+
template :layout do
|
507
|
+
"%html\n =yield\n"
|
508
|
+
end
|
509
|
+
|
510
|
+
template :index do
|
511
|
+
'%div.title Hallo Welt!'
|
512
|
+
end
|
513
|
+
|
514
|
+
get '/' do
|
515
|
+
haml :index
|
516
|
+
end
|
517
|
+
|
518
|
+
Wenn ein Template mit dem Namen "layout" existiert, wird es bei jedem Aufruf
|
519
|
+
verwendet. Durch <tt>:layout => false</tt> kann das Ausführen verhindert werden.
|
520
|
+
|
521
|
+
get '/' do
|
522
|
+
haml :index, :layout => !request.xhr?
|
523
|
+
end
|
524
|
+
|
525
|
+
== Helfer
|
526
|
+
|
527
|
+
Durch die Top-Level <tt>helpers</tt>-Methode, werden sogenannte Helfer-Methoden
|
528
|
+
definiert, die in Routen und Templates verwendet werden können:
|
529
|
+
|
530
|
+
helpers do
|
531
|
+
def bar(name)
|
532
|
+
"#{name}bar"
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
get '/:name' do
|
537
|
+
bar(params[:name])
|
538
|
+
end
|
539
|
+
|
540
|
+
== Filter
|
541
|
+
|
542
|
+
Before-Filter werden immer vor jedem Request in dem selben Kontext wie danach
|
543
|
+
die Routen ausgeführt. So kann man etwa Request und Antwort ändern. Gesetzte
|
544
|
+
Instanzvariablen in Filtern können in Routen und Templates verwendet werden:
|
545
|
+
|
546
|
+
before do
|
547
|
+
@note = 'Hi!'
|
548
|
+
request.path_info = '/foo/bar/baz'
|
549
|
+
end
|
550
|
+
|
551
|
+
get '/foo/*' do
|
552
|
+
@note #=> 'Hi!'
|
553
|
+
params[:splat] #=> 'bar/baz'
|
554
|
+
end
|
555
|
+
|
556
|
+
After-Filter werden nach jedem Request im selben Kontext ausgeführt, und
|
557
|
+
können ebenfalls Request und Antwort ändern. In Before-Filtern gesetzte
|
558
|
+
Instanzvariablen können in After-Filterm verwendet werden:
|
559
|
+
|
560
|
+
after do
|
561
|
+
puts response.status
|
562
|
+
end
|
563
|
+
|
564
|
+
Filter können optional auch mit einem Pattern ausgestattet werden, welche auf den Request-Pfad passen müssen, damit der Filter ausgeführt wird:
|
565
|
+
|
566
|
+
before '/protected/*' do
|
567
|
+
authenticate!
|
568
|
+
end
|
569
|
+
|
570
|
+
after '/create/:slug' do |slug|
|
571
|
+
session[:last_slug] = slug
|
572
|
+
end
|
573
|
+
|
574
|
+
== Anhalten
|
575
|
+
|
576
|
+
Zum sofortigen stoppen eines Request in einem Filter oder einer Route:
|
577
|
+
|
578
|
+
halt
|
579
|
+
|
580
|
+
Der Status kann beim stoppen auch angegeben werden:
|
581
|
+
|
582
|
+
halt 410
|
583
|
+
|
584
|
+
Oder auch den Response-Body:
|
585
|
+
|
586
|
+
halt 'Hier steht der Body'
|
587
|
+
|
588
|
+
Oder beides:
|
589
|
+
|
590
|
+
halt 401, 'verschwinde!'
|
591
|
+
|
592
|
+
Sogar mit Headers:
|
593
|
+
|
594
|
+
halt 402, {'Content-Type' => 'text/plain'}, 'Rache'
|
595
|
+
|
596
|
+
== Weiterspringen
|
597
|
+
|
598
|
+
Eine Route kann mittels <tt>pass</tt> zu der nächsten passenden Route springen:
|
599
|
+
|
600
|
+
get '/raten/:wer' do
|
601
|
+
pass unless params[:wer] == 'Frank'
|
602
|
+
'Du hast mich!'
|
603
|
+
end
|
604
|
+
|
605
|
+
get '/raten/*' do
|
606
|
+
'Du hast mich verfehlt!'
|
607
|
+
end
|
608
|
+
|
609
|
+
Der Block wird sofort verlassen und es wird nach der nächsten treffenden Route
|
610
|
+
gesucht. Ein 404 Fehler wird zurückgegeben, wenn kein treffendes Routen-Muster
|
611
|
+
gefunden wird.
|
612
|
+
|
613
|
+
== Das Request-Objekt
|
614
|
+
|
615
|
+
Auf das `request`-Objeket der eigehenden Anfrage kann man vom Anfragescope aus zugreifen:
|
616
|
+
|
617
|
+
# App läuft unter http://example.com/example
|
618
|
+
get '/foo' do
|
619
|
+
request.body # Request Body des Clients (siehe unten)
|
620
|
+
request.scheme # "http"
|
621
|
+
request.script_name # "/example"
|
622
|
+
request.path_info # "/foo"
|
623
|
+
request.port # 80
|
624
|
+
request.request_method # "GET"
|
625
|
+
request.query_string # ""
|
626
|
+
request.content_length # Länge von request.body
|
627
|
+
request.media_type # Media-Type von request.body
|
628
|
+
request.host # "example.com"
|
629
|
+
request.get? # true (ähnliche Methoden für andere Verben)
|
630
|
+
request.form_data? # false
|
631
|
+
request["SOME_HEADER"] # Wert des SOME_HEADER-headers
|
632
|
+
request.referer # der Referrer des Clients oder '/'
|
633
|
+
request.user_agent # User Agent (genutzt von :agent-Bedingung)
|
634
|
+
request.cookies # Hash der Cookies
|
635
|
+
request.xhr? # Ist dies eine Ajax-Anfrage?
|
636
|
+
request.url # "http://example.com/example/foo"
|
637
|
+
request.path # "/example/foo"
|
638
|
+
request.ip # Client IP-Addresse
|
639
|
+
request.secure? # false
|
640
|
+
requuest.env # env-Hash den Rack durchreicht
|
641
|
+
end
|
642
|
+
|
643
|
+
Manche Optionen, wie etwa <tt>script_name</tt> oder <tt>path_info</tt> sind
|
644
|
+
auch schreibbar:
|
645
|
+
|
646
|
+
before { request.path_info = "/" }
|
647
|
+
|
648
|
+
get "/" do
|
649
|
+
"Alle Anfragen kommen hier an!"
|
650
|
+
end
|
651
|
+
|
652
|
+
Der <tt>request.body</tt> ist einn IO- oder StringIO-Objekt:
|
653
|
+
|
654
|
+
post "/api" do
|
655
|
+
request.body.rewind # falls schon jemand davon gelesen hat
|
656
|
+
daten = JSON.parse request.body.read
|
657
|
+
"Hallo #{daten['name']}!"
|
658
|
+
end
|
659
|
+
|
660
|
+
== Konfiguration
|
661
|
+
|
662
|
+
Wird einmal beim Starten in jedweder Umgebung ausgeführt:
|
663
|
+
|
664
|
+
configure do
|
665
|
+
...
|
666
|
+
end
|
667
|
+
|
668
|
+
Läuft nur, wenn die Umgebung (RACK_ENV Umgebungsvariable) auf
|
669
|
+
<tt>:production</tt> gesetzt ist:
|
670
|
+
|
671
|
+
configure :production do
|
672
|
+
...
|
673
|
+
end
|
674
|
+
|
675
|
+
Läuft nur, wenn die Umgebung auf <tt>:production</tt> oder auf <tt>:test</tt>
|
676
|
+
gesetzt ist:
|
677
|
+
|
678
|
+
configure :production, :test do
|
679
|
+
...
|
680
|
+
end
|
681
|
+
|
682
|
+
== Fehlerbehandlung
|
683
|
+
|
684
|
+
Error Handler laufen im selben Kontext wie Routen und Filter, was bedeutet,
|
685
|
+
dass alle Goodies wie <tt>haml</tt>, <tt>erb</tt>, <tt>halt</tt>, etc.
|
686
|
+
verwendet werden können.
|
687
|
+
|
688
|
+
=== Nicht gefunden
|
689
|
+
|
690
|
+
Wenn eine <tt>Sinatra::NotFound</tt> Exception geworfen wird oder der Statuscode 404 ist, wird der <tt>not_found</tt> Handler ausgeführt:
|
691
|
+
|
692
|
+
not_found do
|
693
|
+
'Seite kann nirgendwo gefunden werden.'
|
694
|
+
end
|
695
|
+
|
696
|
+
=== Fehler
|
697
|
+
|
698
|
+
Der +error+ Handler wird immer ausgeführt, wenn eine Exception in einem Routenblock
|
699
|
+
oder in einen Filter geworfen wurde. Die Exception kann über die
|
700
|
+
<tt>sinatra.error</tt> Rack-Variable angesprochen werden:
|
701
|
+
|
702
|
+
error do
|
703
|
+
'Entschuldige es gab einen hässlichen Fehler - ' + env['sinatra.error'].name
|
704
|
+
end
|
705
|
+
|
706
|
+
Benutzerdefinierte Fehler:
|
707
|
+
|
708
|
+
error MeinFehler do
|
709
|
+
'Was passiert ist...' + request.env['sinatra.error'].message
|
710
|
+
end
|
711
|
+
|
712
|
+
Dann, wenn das passiert:
|
713
|
+
|
714
|
+
get '/' do
|
715
|
+
raise MeinFehler, 'etwas schlechtes'
|
716
|
+
end
|
717
|
+
|
718
|
+
Bekommt man dieses:
|
719
|
+
|
720
|
+
Was passiert ist... etwas schlechtes
|
721
|
+
|
722
|
+
Alternativ kann ein Error Handler auch für Statuscode definiert werden:
|
723
|
+
|
724
|
+
error 403 do
|
725
|
+
'Zugriff verboten'
|
726
|
+
end
|
727
|
+
|
728
|
+
get '/geheim' do
|
729
|
+
403
|
730
|
+
end
|
731
|
+
|
732
|
+
Oder ein Statuscode-Bereich:
|
733
|
+
|
734
|
+
error 400..510 do
|
735
|
+
'Boom'
|
736
|
+
end
|
737
|
+
|
738
|
+
Sinatra setzt verschiedene <tt>not_found</tt> und <tt>error</tt>
|
739
|
+
Handler in der Development Umgebung.
|
740
|
+
|
741
|
+
== Mime-Types
|
742
|
+
|
743
|
+
Wenn <tt>send_file</tt> oder statische Dateien verwendet werden, kann es
|
744
|
+
vorkommen, dass Sinatra den Mime-Typ nicht kennt. Registriert wird dieser mit
|
745
|
+
+mime_type+ per Dateiendung:
|
746
|
+
|
747
|
+
mime_type :foo, 'text/foo'
|
748
|
+
|
749
|
+
Es kann aber auch der +content_type+ Helfer verwendet werden:
|
750
|
+
|
751
|
+
content_type :foo
|
752
|
+
|
753
|
+
== Rack Middleware
|
754
|
+
|
755
|
+
Sinatra baut auf Rack[http://rack.rubyforge.org/], einem minimalen Standardinterface für Ruby Webframeworks. Eines der interessantesten
|
756
|
+
Features für Entwickler ist der Support von Middleware, die
|
757
|
+
zwischen den Server und die Anwendung geschaltet wird und so HTTP
|
758
|
+
Request und/oder Antwort überwachen und/oder manipulieren kann.
|
759
|
+
|
760
|
+
Sinatra macht das erstellen von Middleware-Verkettungen mit der Top-Level
|
761
|
+
Methode +use+ zu einem Kinderspiel:
|
762
|
+
|
763
|
+
require 'sinatra'
|
764
|
+
require 'meine_middleware'
|
765
|
+
|
766
|
+
use Rack::Lint
|
767
|
+
use MeineMiddleware
|
768
|
+
|
769
|
+
get '/hallo' do
|
770
|
+
'Hallo Welt'
|
771
|
+
end
|
772
|
+
|
773
|
+
Die Semantik von +use+ entspricht der gleichnamigen Methode der
|
774
|
+
Rack::Builder[http://rack.rubyforge.org/doc/classes/Rack/Builder.html] DSL
|
775
|
+
(meist verwendet in Rackup-Dateien). Ein Beispiel dafür ist, dass die
|
776
|
+
+use+-Methode mehrere/verschiedene Argumente und auch Blöcke entgegen nimmt:
|
777
|
+
|
778
|
+
use Rack::Auth::Basic do |username, password|
|
779
|
+
username == 'admin' && password == 'geheim'
|
780
|
+
end
|
781
|
+
|
782
|
+
Rack bietet eine Vielzahl von standard Middleware für Logging, Debugging,
|
783
|
+
URL-Routing, Authentifizierung und Session-Verarbeitung.
|
784
|
+
Sinatra verwendet viele von diesen Komponenten automatisch, abhängig von der
|
785
|
+
Konfiguration. So muss man häufig +use+ nicht explizit verwenden.
|
786
|
+
|
787
|
+
== Testen
|
788
|
+
|
789
|
+
Sinatra Tests können mit jedem auf Rack aufbauendem Test Framework geschrieben
|
790
|
+
werden. {Rack::Test}[http://gitrdoc.com/brynary/rack-test] wird empfohlen:
|
791
|
+
|
792
|
+
require 'my_sinatra_app'
|
793
|
+
require 'test/unit'
|
794
|
+
require 'rack/test'
|
795
|
+
|
796
|
+
class MyAppTest < Test::Unit::TestCase
|
797
|
+
include Rack::Test::Methods
|
798
|
+
|
799
|
+
def app
|
800
|
+
Sinatra::Application
|
801
|
+
end
|
802
|
+
|
803
|
+
def test_my_default
|
804
|
+
get '/'
|
805
|
+
assert_equal 'Hallo Welt!', last_response.body
|
806
|
+
end
|
807
|
+
|
808
|
+
def test_with_params
|
809
|
+
get '/meet', :name => 'Frank'
|
810
|
+
assert_equal 'Hallo Frank!', last_response.body
|
811
|
+
end
|
812
|
+
|
813
|
+
def test_with_rack_env
|
814
|
+
get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
|
815
|
+
assert_equal "Du verwendest Songbird!", last_response.body
|
816
|
+
end
|
817
|
+
end
|
818
|
+
|
819
|
+
Anmerkung: Das eingebaute Sinatra::Test Modul und die Sinatra::TestHarness
|
820
|
+
Klasse werden seit Version 0.9.2 nicht mehr unterstützt.
|
821
|
+
|
822
|
+
== Sinatra::Base - Middleware, Bibliotheken, und modulare Anwendungen
|
823
|
+
|
824
|
+
Das Definitieren einer Top-Level Anwendung funktioniert gut für
|
825
|
+
Microanwendungen, hat aber Nachteile, wenn man wiederverwendbare Komponenten
|
826
|
+
wie Middleware, Rails Metal, einfache Bibliotheken mit Server Komponenten
|
827
|
+
oder auch Sinatra Erweiterungen bauen will.
|
828
|
+
Die Top-Level DSL belastet den Objekt-Namespace und setzt einen Microanwendungsstil voraus (eine einzelne Anwendungsdatei, ./public und ./views
|
829
|
+
Ordner, Logging, Exception-Detail-Seite, usw.). Genau hier kommt Sinatra::Base
|
830
|
+
ins Spiel:
|
831
|
+
|
832
|
+
require 'sinatra/base'
|
833
|
+
|
834
|
+
class MyApp < Sinatra::Base
|
835
|
+
set :sessions, true
|
836
|
+
set :foo, 'bar'
|
837
|
+
|
838
|
+
get '/' do
|
839
|
+
'Hallo Welt!'
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|
843
|
+
Die MyApp-Klasse ist eine unabhängige Rack-Komponente, die als Middleware,
|
844
|
+
Endpunkt oder via Rails Metal verwendet werden kann. Verwendet wird sie durch
|
845
|
+
+use+ oder +run+ von einer Rackup +config.ru+ Datei oder als Serverkomponente
|
846
|
+
einer Bibliothek:
|
847
|
+
|
848
|
+
MyApp.run! :host => 'localhost', :port => 9090
|
849
|
+
|
850
|
+
Die Methoden der Sinatra::Base-Subklasse sind genau die selben wie die
|
851
|
+
der Top-Level DSL. Die meisten Top-Level Anwendungen können mit nur zwei Veränderungen zu Sinatra::Base-Komponenten konvertiert werden:
|
852
|
+
|
853
|
+
* Die Datei sollte <tt>require 'sinatra/base'</tt> anstelle von
|
854
|
+
<tt>require 'sinatra/base'</tt> aufrufen, ansonsten werden alle von
|
855
|
+
Sinatras DSL Methoden in den Top-Level- Namespace importiert.
|
856
|
+
* Alle Routen, Error Handler, Filter und Optionen der Applikation müssen in
|
857
|
+
einer Subklasse von Sinatra::Base definiert werden.
|
858
|
+
|
859
|
+
<tt>Sinatra::Base</tt> ist ein unbeschriebense Blatt. Die meisten Optionen sind per default deaktiviert. Das betrifft auch den eingebauten Server. Siehe {Optionen und Konfiguration}[http://sinatra.github.com/configuration.html] für Details über möglichen Optionen.
|
860
|
+
|
861
|
+
=== Sinatra als Middleware nutzen
|
862
|
+
|
863
|
+
Es ist nicht nur möglich andere Rack-Middleware mit Sinatra zu nutzen, man
|
864
|
+
kann außerdem jede Sinatra-Anwendung selbst als Middlware vor jeden beliebigen
|
865
|
+
Rack-Endpunkt hängen. Bei diesem Endpunkt muss es sich nicht um eine andere
|
866
|
+
Sinatra-Anwendung handen, es kann jede andere Rack-Anwendung sein
|
867
|
+
(Rails/Ramaze/Camping/...).
|
868
|
+
|
869
|
+
require 'sinatra/base'
|
870
|
+
|
871
|
+
class LoginScreen < Sinatra::Base
|
872
|
+
enable :session
|
873
|
+
|
874
|
+
get('/login') { haml :login }
|
875
|
+
|
876
|
+
post('/login') do
|
877
|
+
if params[:name] = 'admin' and params[:password] = 'admin'
|
878
|
+
session['user_name'] = params[:name]
|
879
|
+
else
|
880
|
+
redirect '/login'
|
881
|
+
end
|
882
|
+
end
|
883
|
+
end
|
884
|
+
|
885
|
+
class MyApp < Sinatra::Base
|
886
|
+
# Middleware wird vor Filtern ausgeführt
|
887
|
+
use LoginScreen
|
888
|
+
|
889
|
+
before do
|
890
|
+
unless session['user_name']
|
891
|
+
halt "Zugriff verweigert, bitte <a href='/login'>einloggen</a>."
|
892
|
+
end
|
893
|
+
end
|
894
|
+
|
895
|
+
get('/') { "Hallo #{session['user_name']}." }
|
896
|
+
end
|
897
|
+
|
898
|
+
== Scopes und Bindung
|
899
|
+
|
900
|
+
In welchem Scope man sich gerade befinded legt fest, welche Methoden und
|
901
|
+
Variablen zur Verfügung stehen.
|
902
|
+
|
903
|
+
=== Anwendungs- oder Klassenscope
|
904
|
+
|
905
|
+
Jede Sinatra-Anwendung entspricht einer Sinatra::Base-Subklasse. Falls man die Top-Level-DSL verwendet (<tt>require 'sinatra'</tt>), so handelt es sich hierbei um Sinatra::Application, andernfalls is es jene Subklasse, die man explizit angelegt hat. Auf Klassenebene stehen Methoden wie `get` oder `before` zur Verfügung, man hat aber keinen Zugriff auf das `request`-Object oder die `session`, da nur eine einzige Klasse für alle eingehenden Anfragen genutzt wird.
|
906
|
+
|
907
|
+
Optionen die via `set` gesetzt werden, sind Methoden auf Klassenebene:
|
908
|
+
|
909
|
+
class MyApp << Sinatra::Base
|
910
|
+
# Hey, ich bin im Anwendungsscope!
|
911
|
+
set :foo, 42
|
912
|
+
foo # => 42
|
913
|
+
|
914
|
+
get '/foo' do
|
915
|
+
# Hey, ich bin nicht mehr im Anwendungsscope!
|
916
|
+
end
|
917
|
+
end
|
918
|
+
|
919
|
+
Im Anwendungsscope befindet man sich:
|
920
|
+
|
921
|
+
* In der Anwenungsklasse.
|
922
|
+
* In Methoden die von Erweiterungen definiert werden.
|
923
|
+
* Im Block, der an `helpers` übergeben wird.
|
924
|
+
* In Procs und Blöcken die an `set` übergeben werden.
|
925
|
+
|
926
|
+
Man kann auf das Scope-Object (die Klasse) wie folgt zugreifen:
|
927
|
+
|
928
|
+
* Über das Objekt, dass an den `configure`-Block übergeben wird (<tt>configure
|
929
|
+
{ |c| ... }</tt>).
|
930
|
+
* `settings` aus den anderen Scopes heraus.
|
931
|
+
|
932
|
+
=== Anfrage- oder Instanzscope
|
933
|
+
|
934
|
+
Für jede eingehende Anfrage wird eine neue Instanz der Anwendungsklasse erstellt und alle Handlers werden in diesem Scope ausgeführt. Aus diesem Scope heraus kann man auf `request` oder `session` zugreifen und Methoden wie `erb` oder `haml` aufrufen. Man kann mit der `settings` Methode außerdem auf den Anwengungsscope zugreifen.
|
935
|
+
|
936
|
+
class MyApp << Sinatra::Base
|
937
|
+
# Hey, ich bin im Anwendungsscope!
|
938
|
+
get '/neue_route/:name' do
|
939
|
+
# Anfragescope für '/neue_route/:name'
|
940
|
+
@value = 42
|
941
|
+
|
942
|
+
settings.get "/#{params[:name]}" do
|
943
|
+
# Anfragescope für "/#{params[:name]}"
|
944
|
+
@value # => nil (nicht die gleiche Anfrage)
|
945
|
+
end
|
946
|
+
|
947
|
+
"Route definiert!"
|
948
|
+
end
|
949
|
+
end
|
950
|
+
|
951
|
+
Im Anfragescope befindet man sich:
|
952
|
+
|
953
|
+
* In get/head/post/put/delete Blöcken
|
954
|
+
* In before/after Filtern
|
955
|
+
* In Helfermethoden
|
956
|
+
* In Templates
|
957
|
+
|
958
|
+
=== Delegation-Scope
|
959
|
+
|
960
|
+
Vom Delegation-Scope aus werden Methoden einfach an den Klassenscope
|
961
|
+
weitergeleitet. Dieser verhält sich jedoch nicht 100%ig wie der Klassenscope,
|
962
|
+
da man nicht die Bindung der Klasse besitzt: Nur Methoden, die explizit als
|
963
|
+
deligierbar markiert wurden stehen hier zur Verfügung und man kann nicht auf
|
964
|
+
die Variablen des Klassenscopes zugreifen (mit anderen Worten: man hat ein
|
965
|
+
anderes `self`). Man kann mit <tt>Sinatra::Delegator.delegate
|
966
|
+
:methoden_name</tt> auch weitere Delegationen hinzufügen.
|
967
|
+
|
968
|
+
Im Delegation-Scop befindet man sich:
|
969
|
+
|
970
|
+
* Im Top-Level, wenn man <tt>require 'sinatra'</tt> aufgerufen hat.
|
971
|
+
* In einem Objekt, dass mit dem `Sinatra::Delegator` mixin erweitert wurde.
|
972
|
+
|
973
|
+
Schau am besten im Code nach: Hier ist {Sinatra::Delegator mixin}[http://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1064] definiert und wird in den {globalen Namespace eingebunden}[http://github.com/sinatra/sinatra/blob/master/lib/sinatra/main.rb#L25].
|
974
|
+
|
975
|
+
== Kommandozeile
|
976
|
+
|
977
|
+
Sinatra Anwendungen können direkt von der Kommandozeile aus gestartet werden:
|
978
|
+
|
979
|
+
ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-h HOST] [-s HANDLER]
|
980
|
+
|
981
|
+
Die Optionen sind:
|
982
|
+
|
983
|
+
-h # Hilfe
|
984
|
+
-p # Port setzen (Standard ist 4567)
|
985
|
+
-h # Host setzen (Standard ist 0.0.0.0)
|
986
|
+
-e # Umgebung setzen (Standard ist development)
|
987
|
+
-s # Rack Server/Handler setzen (Standard ist thin)
|
988
|
+
-x # Mutex lock einschalten (Standard ist off)
|
989
|
+
|
990
|
+
== Der neueste Stand (The Bleeding Edge)
|
991
|
+
|
992
|
+
Um auf den neuesten Stand von Sinatras Code zu sein, kann eine lokale Kopie
|
993
|
+
angelegt werden. Gestartet wird in der Anwendung mit dem <tt>sinatra/lib</tt>
|
994
|
+
Ordner im <tt>LOAD_PATH</tt>:
|
995
|
+
|
996
|
+
cd myapp
|
997
|
+
git clone git://github.com/sinatra/sinatra.git
|
998
|
+
ruby -Isinatra/lib myapp.rb
|
999
|
+
|
1000
|
+
Alternativ kann der <tt>sinatra/lib</tt> Ordner zum <tt>LOAD_PATH</tt> in
|
1001
|
+
der Anwendung hinzugefügt werden:
|
1002
|
+
|
1003
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
|
1004
|
+
require 'rubygems'
|
1005
|
+
require 'sinatra'
|
1006
|
+
|
1007
|
+
get '/ueber' do
|
1008
|
+
"Ich laufe auf Version " + Sinatra::VERSION
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
Um Sinatra Code von Zeit zu Zeit zu aktualisieren:
|
1012
|
+
|
1013
|
+
cd myproject/sinatra
|
1014
|
+
git pull
|
1015
|
+
|
1016
|
+
== Mehr
|
1017
|
+
|
1018
|
+
* {Projekt Website}[http://sinatra.github.com/] - Ergänzende Dokumentation,
|
1019
|
+
News und Links zu anderen Ressourcen.
|
1020
|
+
* {Hilfe beisteuern}[http://sinatra.github.com/contributing.html] - Einen Fehler gefunden? Brauchst du Hilfe? Hast du einen Patch?
|
1021
|
+
* {Issue Tracker}[http://github.com/sinatra/sinatra/issues]
|
1022
|
+
* {Twitter}[http://twitter.com/sinatra]
|
1023
|
+
* {Mailingliste}[http://groups.google.com/group/sinatrarb]
|
1024
|
+
* {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] auf http://freenode.net
|