sinatra 1.3.6 → 1.4.0.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.

Files changed (71) hide show
  1. data/CHANGES +96 -22
  2. data/Gemfile +11 -3
  3. data/README.de.md +2590 -0
  4. data/README.es.rdoc +66 -38
  5. data/README.fr.md +2630 -0
  6. data/README.hu.rdoc +3 -2
  7. data/README.jp.rdoc +16 -3
  8. data/README.ko.rdoc +11 -5
  9. data/README.md +2699 -0
  10. data/README.pt-br.rdoc +152 -21
  11. data/README.pt-pt.rdoc +3 -2
  12. data/README.ru.md +2724 -0
  13. data/README.zh.rdoc +3 -3
  14. data/Rakefile +3 -4
  15. data/examples/chat.rb +3 -3
  16. data/lib/sinatra/base.rb +433 -247
  17. data/lib/sinatra/main.rb +4 -2
  18. data/lib/sinatra/showexceptions.rb +6 -1
  19. data/lib/sinatra/version.rb +1 -1
  20. data/test/base_test.rb +21 -9
  21. data/test/builder_test.rb +15 -19
  22. data/test/coffee_test.rb +4 -6
  23. data/test/compile_test.rb +154 -0
  24. data/test/contest.rb +4 -6
  25. data/test/creole_test.rb +5 -5
  26. data/test/delegator_test.rb +1 -3
  27. data/test/erb_test.rb +32 -20
  28. data/test/extensions_test.rb +1 -3
  29. data/test/filter_test.rb +65 -56
  30. data/test/haml_test.rb +34 -26
  31. data/test/helpers_test.rb +331 -221
  32. data/test/integration_helper.rb +8 -0
  33. data/test/integration_test.rb +3 -1
  34. data/test/less_test.rb +10 -8
  35. data/test/liquid_test.rb +22 -4
  36. data/test/mapped_error_test.rb +122 -96
  37. data/test/markaby_test.rb +5 -5
  38. data/test/markdown_test.rb +5 -5
  39. data/test/middleware_test.rb +3 -3
  40. data/test/nokogiri_test.rb +4 -6
  41. data/test/rabl_test.rb +89 -0
  42. data/test/radius_test.rb +4 -4
  43. data/test/rdoc_test.rb +7 -7
  44. data/test/readme_test.rb +14 -30
  45. data/test/request_test.rb +15 -0
  46. data/test/response_test.rb +3 -4
  47. data/test/result_test.rb +11 -33
  48. data/test/route_added_hook_test.rb +10 -10
  49. data/test/routing_test.rb +123 -1
  50. data/test/sass_test.rb +26 -26
  51. data/test/scss_test.rb +16 -16
  52. data/test/server_test.rb +2 -2
  53. data/test/settings_test.rb +48 -4
  54. data/test/sinatra_test.rb +2 -7
  55. data/test/slim_test.rb +37 -23
  56. data/test/static_test.rb +56 -15
  57. data/test/streaming_test.rb +11 -2
  58. data/test/templates_test.rb +117 -45
  59. data/test/textile_test.rb +9 -9
  60. data/test/views/hello.rabl +2 -0
  61. data/test/views/hello.wlang +1 -0
  62. data/test/views/hello.yajl +1 -0
  63. data/test/views/layout2.rabl +3 -0
  64. data/test/views/layout2.wlang +2 -0
  65. data/test/wlang_test.rb +87 -0
  66. data/test/yajl_test.rb +86 -0
  67. metadata +27 -17
  68. data/README.de.rdoc +0 -2097
  69. data/README.fr.rdoc +0 -2036
  70. data/README.rdoc +0 -2017
  71. data/README.ru.rdoc +0 -1785
@@ -7,32 +7,32 @@ class TextileTest < Test::Unit::TestCase
7
7
  def textile_app(&block)
8
8
  mock_app do
9
9
  set :views, File.dirname(__FILE__) + '/views'
10
- get '/', &block
10
+ get('/', &block)
11
11
  end
12
12
  get '/'
13
13
  end
14
14
 
15
15
  it 'renders inline textile strings' do
16
- textile_app { textile 'h1. Hiya' }
16
+ textile_app { textile('h1. Hiya') }
17
17
  assert ok?
18
18
  assert_equal "<h1>Hiya</h1>", body
19
19
  end
20
20
 
21
21
  it 'renders .textile files in views path' do
22
- textile_app { textile :hello }
22
+ textile_app { textile(:hello) }
23
23
  assert ok?
24
24
  assert_equal "<h1>Hello From Textile</h1>", body
25
25
  end
26
26
 
27
27
  it "raises error if template not found" do
28
- mock_app { get('/') { textile :no_such_template } }
28
+ mock_app { get('/') { textile(:no_such_template) } }
29
29
  assert_raise(Errno::ENOENT) { get('/') }
30
30
  end
31
31
 
32
32
  it "renders with inline layouts" do
33
33
  mock_app do
34
34
  layout { 'THIS. IS. #{yield.upcase}!' }
35
- get('/') { textile 'Sparta', :layout_engine => :str }
35
+ get('/') { textile('Sparta', :layout_engine => :str) }
36
36
  end
37
37
  get '/'
38
38
  assert ok?
@@ -40,7 +40,9 @@ class TextileTest < Test::Unit::TestCase
40
40
  end
41
41
 
42
42
  it "renders with file layouts" do
43
- textile_app { textile 'Hello World', :layout => :layout2, :layout_engine => :erb }
43
+ textile_app {
44
+ textile('Hello World', :layout => :layout2, :layout_engine => :erb)
45
+ }
44
46
  assert ok?
45
47
  assert_body "ERB Layout!\n<p>Hello World</p>"
46
48
  end
@@ -49,9 +51,7 @@ class TextileTest < Test::Unit::TestCase
49
51
  mock_app do
50
52
  template(:inner) { "hi" }
51
53
  template(:outer) { "<outer><%= textile :inner %></outer>" }
52
- get '/' do
53
- erb :outer
54
- end
54
+ get('/') { erb :outer }
55
55
  end
56
56
 
57
57
  get '/'
@@ -0,0 +1,2 @@
1
+ object @foo
2
+ attributes :bar
@@ -0,0 +1 @@
1
+ Hello from wlang!
@@ -0,0 +1 @@
1
+ json = { :yajl => "hello" }
@@ -0,0 +1,3 @@
1
+ node(:qux) do
2
+ ::JSON.parse(yield)
3
+ end
@@ -0,0 +1,2 @@
1
+ WLang Layout!
2
+ +{yield}
@@ -0,0 +1,87 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ begin
4
+ require 'wlang'
5
+
6
+ class WLangTest < Test::Unit::TestCase
7
+ def engine
8
+ Tilt::WLangTemplate
9
+ end
10
+
11
+ def wlang_app(&block)
12
+ mock_app {
13
+ set :views, File.dirname(__FILE__) + '/views'
14
+ get '/', &block
15
+ }
16
+ get '/'
17
+ end
18
+
19
+ it 'uses the correct engine' do
20
+ assert_equal engine, Tilt[:wlang]
21
+ end
22
+
23
+ it 'renders .wlang files in views path' do
24
+ wlang_app { wlang :hello }
25
+ assert ok?
26
+ assert_equal "Hello from wlang!\n", body
27
+ end
28
+
29
+ it 'renders in the app instance scope' do
30
+ mock_app do
31
+ helpers do
32
+ def who; "world"; end
33
+ end
34
+ get('/') { wlang 'Hello +{who}!' }
35
+ end
36
+ get '/'
37
+ assert ok?
38
+ assert_equal 'Hello world!', body
39
+ end
40
+
41
+ it 'takes a :locals option' do
42
+ wlang_app do
43
+ locals = {:foo => 'Bar'}
44
+ wlang 'Hello ${foo}!', :locals => locals
45
+ end
46
+ assert ok?
47
+ assert_equal 'Hello Bar!', body
48
+ end
49
+
50
+ it "renders with inline layouts" do
51
+ mock_app do
52
+ layout { 'THIS. IS. +{yield.upcase}!' }
53
+ get('/') { wlang 'Sparta' }
54
+ end
55
+ get '/'
56
+ assert ok?
57
+ assert_equal 'THIS. IS. SPARTA!', body
58
+ end
59
+
60
+ it "renders with file layouts" do
61
+ wlang_app { wlang 'Hello World', :layout => :layout2 }
62
+ assert ok?
63
+ assert_body "WLang Layout!\nHello World"
64
+ end
65
+
66
+ it "can rendere truly nested layouts by accepting a layout and a block with the contents" do
67
+ mock_app do
68
+ template(:main_outer_layout) { "<h1>Title</h1>\n>{ yield }" }
69
+ template(:an_inner_layout) { "<h2>Subtitle</h2>\n>{ yield }" }
70
+ template(:a_page) { "<p>Contents.</p>\n" }
71
+ get('/') do
72
+ wlang :main_outer_layout, :layout => false do
73
+ wlang :an_inner_layout do
74
+ wlang :a_page
75
+ end
76
+ end
77
+ end
78
+ end
79
+ get '/'
80
+ assert ok?
81
+ assert_body "<h1>Title</h1>\n<h2>Subtitle</h2>\n<p>Contents.</p>\n"
82
+ end
83
+ end
84
+
85
+ rescue LoadError
86
+ warn "#{$!.to_s}: skipping wlang tests"
87
+ end
@@ -0,0 +1,86 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ begin
4
+ require 'yajl'
5
+
6
+ class YajlTest < Test::Unit::TestCase
7
+ def yajl_app(&block)
8
+ mock_app do
9
+ set :views, File.dirname(__FILE__) + '/views'
10
+ get('/', &block)
11
+ end
12
+ get '/'
13
+ end
14
+
15
+ it 'renders inline Yajl strings' do
16
+ yajl_app { yajl('json = { :foo => "bar" }') }
17
+ assert ok?
18
+ assert_body '{"foo":"bar"}'
19
+ end
20
+
21
+ it 'renders .yajl files in views path' do
22
+ yajl_app { yajl(:hello) }
23
+ assert ok?
24
+ assert_body '{"yajl":"hello"}'
25
+ end
26
+
27
+ it 'raises error if template not found' do
28
+ mock_app { get('/') { yajl(:no_such_template) } }
29
+ assert_raise(Errno::ENOENT) { get('/') }
30
+ end
31
+
32
+ it 'accepts a :locals option' do
33
+ yajl_app do
34
+ locals = { :object => { :foo => 'bar' } }
35
+ yajl 'json = object', :locals => locals
36
+ end
37
+ assert ok?
38
+ assert_body '{"foo":"bar"}'
39
+ end
40
+
41
+ it 'accepts a :scope option' do
42
+ yajl_app do
43
+ scope = { :object => { :foo => 'bar' } }
44
+ yajl 'json = self[:object]', :scope => scope
45
+ end
46
+ assert ok?
47
+ assert_body '{"foo":"bar"}'
48
+ end
49
+
50
+ it 'decorates the json with a callback' do
51
+ yajl_app do
52
+ yajl(
53
+ 'json = { :foo => "bar" }',
54
+ { :callback => 'baz' }
55
+ )
56
+ end
57
+ assert ok?
58
+ assert_body 'baz({"foo":"bar"});'
59
+ end
60
+
61
+ it 'decorates the json with a variable' do
62
+ yajl_app do
63
+ yajl(
64
+ 'json = { :foo => "bar" }',
65
+ { :variable => 'qux' }
66
+ )
67
+ end
68
+ assert ok?
69
+ assert_body 'var qux = {"foo":"bar"};'
70
+ end
71
+
72
+ it 'decorates the json with a callback and a variable' do
73
+ yajl_app do
74
+ yajl(
75
+ 'json = { :foo => "bar" }',
76
+ { :callback => 'baz', :variable => 'qux' }
77
+ )
78
+ end
79
+ assert ok?
80
+ assert_body 'var qux = {"foo":"bar"}; baz(qux);'
81
+ end
82
+ end
83
+
84
+ rescue LoadError
85
+ warn "#{$!.to_s}: skipping yajl tests"
86
+ end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.6
5
- prerelease:
4
+ version: 1.4.0.a
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Blake Mizerany
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2013-03-15 00:00:00.000000000 Z
15
+ date: 2013-02-26 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rack
@@ -74,16 +74,16 @@ email: sinatrarb@googlegroups.com
74
74
  executables: []
75
75
  extensions: []
76
76
  extra_rdoc_files:
77
- - README.de.rdoc
77
+ - README.de.md
78
78
  - README.es.rdoc
79
- - README.fr.rdoc
79
+ - README.fr.md
80
80
  - README.hu.rdoc
81
81
  - README.jp.rdoc
82
82
  - README.ko.rdoc
83
+ - README.md
83
84
  - README.pt-br.rdoc
84
85
  - README.pt-pt.rdoc
85
- - README.rdoc
86
- - README.ru.rdoc
86
+ - README.ru.md
87
87
  - README.zh.rdoc
88
88
  - LICENSE
89
89
  files:
@@ -92,16 +92,16 @@ files:
92
92
  - CHANGES
93
93
  - Gemfile
94
94
  - LICENSE
95
- - README.de.rdoc
95
+ - README.de.md
96
96
  - README.es.rdoc
97
- - README.fr.rdoc
97
+ - README.fr.md
98
98
  - README.hu.rdoc
99
99
  - README.jp.rdoc
100
100
  - README.ko.rdoc
101
+ - README.md
101
102
  - README.pt-br.rdoc
102
103
  - README.pt-pt.rdoc
103
- - README.rdoc
104
- - README.ru.rdoc
104
+ - README.ru.md
105
105
  - README.zh.rdoc
106
106
  - Rakefile
107
107
  - examples/chat.rb
@@ -118,6 +118,7 @@ files:
118
118
  - test/base_test.rb
119
119
  - test/builder_test.rb
120
120
  - test/coffee_test.rb
121
+ - test/compile_test.rb
121
122
  - test/contest.rb
122
123
  - test/creole_test.rb
123
124
  - test/delegator_test.rb
@@ -139,6 +140,7 @@ files:
139
140
  - test/middleware_test.rb
140
141
  - test/nokogiri_test.rb
141
142
  - test/public/favicon.ico
143
+ - test/rabl_test.rb
142
144
  - test/rack_test.rb
143
145
  - test/radius_test.rb
144
146
  - test/rdoc_test.rb
@@ -178,6 +180,7 @@ files:
178
180
  - test/views/hello.mab
179
181
  - test/views/hello.md
180
182
  - test/views/hello.nokogiri
183
+ - test/views/hello.rabl
181
184
  - test/views/hello.radius
182
185
  - test/views/hello.rdoc
183
186
  - test/views/hello.sass
@@ -186,18 +189,24 @@ files:
186
189
  - test/views/hello.str
187
190
  - test/views/hello.test
188
191
  - test/views/hello.textile
192
+ - test/views/hello.wlang
193
+ - test/views/hello.yajl
189
194
  - test/views/layout2.builder
190
195
  - test/views/layout2.erb
191
196
  - test/views/layout2.haml
192
197
  - test/views/layout2.liquid
193
198
  - test/views/layout2.mab
194
199
  - test/views/layout2.nokogiri
200
+ - test/views/layout2.rabl
195
201
  - test/views/layout2.radius
196
202
  - test/views/layout2.slim
197
203
  - test/views/layout2.str
198
204
  - test/views/layout2.test
205
+ - test/views/layout2.wlang
199
206
  - test/views/nested.str
200
207
  - test/views/utf8.erb
208
+ - test/wlang_test.rb
209
+ - test/yajl_test.rb
201
210
  homepage: http://www.sinatrarb.com/
202
211
  licenses: []
203
212
  post_install_message:
@@ -219,16 +228,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
219
228
  version: '0'
220
229
  segments:
221
230
  - 0
222
- hash: -3428773898316879023
231
+ hash: 610663960316584040
223
232
  required_rubygems_version: !ruby/object:Gem::Requirement
224
233
  none: false
225
234
  requirements:
226
- - - ! '>='
235
+ - - ! '>'
227
236
  - !ruby/object:Gem::Version
228
- version: '0'
229
- segments:
230
- - 0
231
- hash: -3428773898316879023
237
+ version: 1.3.1
232
238
  requirements: []
233
239
  rubyforge_project:
234
240
  rubygems_version: 1.8.23
@@ -239,6 +245,7 @@ test_files:
239
245
  - test/base_test.rb
240
246
  - test/builder_test.rb
241
247
  - test/coffee_test.rb
248
+ - test/compile_test.rb
242
249
  - test/creole_test.rb
243
250
  - test/delegator_test.rb
244
251
  - test/encoding_test.rb
@@ -255,6 +262,7 @@ test_files:
255
262
  - test/markdown_test.rb
256
263
  - test/middleware_test.rb
257
264
  - test/nokogiri_test.rb
265
+ - test/rabl_test.rb
258
266
  - test/rack_test.rb
259
267
  - test/radius_test.rb
260
268
  - test/rdoc_test.rb
@@ -274,3 +282,5 @@ test_files:
274
282
  - test/streaming_test.rb
275
283
  - test/templates_test.rb
276
284
  - test/textile_test.rb
285
+ - test/wlang_test.rb
286
+ - test/yajl_test.rb
@@ -1,2097 +0,0 @@
1
- = Sinatra
2
-
3
- <i>Wichtig: Dieses Dokument ist eine Übersetzung aus dem Englischen und unter
4
- Umständen nicht auf dem aktuellen Stand.</i>
5
-
6
- Sinatra ist eine DSL, die das schnelle Erstellen von Webanwendungen in Ruby
7
- mit minimalem Aufwand ermöglicht:
8
-
9
- # myapp.rb
10
- require 'sinatra'
11
- get '/' do
12
- 'Hallo Welt!'
13
- end
14
-
15
- Einfach via +rubygems+ installieren und starten:
16
-
17
- gem install sinatra
18
- ruby -rubygems myapp.rb
19
-
20
- Die Seite kann nun unter http://localhost:4567 betrachtet werden.
21
-
22
- Es wird empfohlen, den Thin-Server via <tt>gem install thin</tt> zu
23
- installieren, den Sinatra dann, soweit vorhanden, automatisch verwendet.
24
-
25
- == Routen
26
-
27
- In Sinatra wird eine Route durch eine HTTP-Methode und ein URL-Muster
28
- definiert. Jeder dieser Routen wird ein Ruby-Block zugeordnet:
29
-
30
- get '/' do
31
- .. zeige etwas ..
32
- end
33
-
34
- post '/' do
35
- .. erstelle etwas ..
36
- end
37
-
38
- put '/' do
39
- .. update etwas ..
40
- end
41
-
42
- delete '/' do
43
- .. entferne etwas ..
44
- end
45
-
46
- options '/' do
47
- .. zeige, was wir können ..
48
- end
49
-
50
- Die Routen werden in der Reihenfolge durchlaufen, in der sie definiert wurden.
51
- Das erste Routen-Muster, das mit dem Request übereinstimmt, wird ausgeführt.
52
-
53
- Die Muster der Routen können benannte Parameter beinhalten, die über den
54
- <tt>params</tt>-Hash zugänglich gemacht werden:
55
-
56
- get '/hallo/:name' do
57
- # passt auf "GET /hallo/foo" und "GET /hallo/bar"
58
- # params[:name] ist 'foo' oder 'bar'
59
- "Hallo #{params[:name]}!"
60
- end
61
-
62
- Man kann auf diese auch mit Block-Parametern zugreifen:
63
-
64
- get '/hallo/:name' do |n|
65
- "Hallo #{n}!"
66
- end
67
-
68
- Routen-Muster können auch mit Splat- oder Wildcard-Parametern über das
69
- <tt>params[:splat]</tt>-Array angesprochen werden:
70
-
71
- get '/sag/*/zu/*' do
72
- # passt auf /sag/hallo/zu/welt
73
- params[:splat] # => ["hallo", "welt"]
74
- end
75
-
76
- get '/download/*.*' do
77
- # passt auf /download/pfad/zu/datei.xml
78
- params[:splat] # => ["pfad/zu/datei", "xml"]
79
- end
80
-
81
- Oder mit Block-Parametern:
82
-
83
- get '/download/*.*' do |pfad, endung|
84
- [pfad, endung] # => ["Pfad/zu/Datei", "xml"]
85
- end
86
-
87
- Routen mit regulären Ausdrücken sind auch möglich:
88
-
89
- get %r{/hallo/([\w]+)} do
90
- "Hallo, #{params[:captures].first}!"
91
- end
92
-
93
- Und auch hier können Block-Parameter genutzt werden:
94
-
95
- get %r{/hallo/([\w]+)} do |c|
96
- "Hallo, #{c}!"
97
- end
98
-
99
- Routen-Muster können auch mit optionalen Parametern ausgestattet werden:
100
-
101
- get '/posts.?:format?' do
102
- # passt auf "GET /posts" sowie jegliche Erweiterung
103
- # wie "GET /posts.json", "GET /posts.xml" etc.
104
- end
105
-
106
- Anmerkung: Solange man den sog. Path Traversal Attack-Schutz nicht deaktiviert
107
- (siehe weiter unten), kann es sein, dass der Request-Pfad noch vor dem Abgleich
108
- mit den Routen modifiziert wird.
109
-
110
- === Bedingungen
111
-
112
- An Routen können eine Vielzahl von Bedingungen angehängt werden, die erfüllt
113
- sein müssen, damit der Block ausgeführt wird. Möglich wäre etwa eine
114
- Einschränkung des User-Agents:
115
-
116
- get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
117
- "Du verwendest Songbird Version #{params[:agent][0]}"
118
- end
119
-
120
- get '/foo' do
121
- # passt auf andere Browser
122
- end
123
-
124
- Andere mitgelieferte Bedingungen sind +host_name+ und +provides+:
125
-
126
- get '/', :host_name => /^admin\./ do
127
- "Adminbereich, Zugriff verweigert!"
128
- end
129
-
130
- get '/', :provides => 'html' do
131
- haml :index
132
- end
133
-
134
- get '/', :provides => ['rss', 'atom', 'xml'] do
135
- builder :feed
136
- end
137
-
138
- Es können auch andere Bedingungen relativ einfach hinzugefügt werden:
139
-
140
- set(:probability) { |value| condition { rand <= value } }
141
-
142
- get '/auto_gewinnen', :probability => 0.1 do
143
- "Du hast gewonnen!"
144
- end
145
-
146
- get '/auto_gewinnen' do
147
- "Tut mir leid, verloren."
148
- end
149
-
150
- Bei Bedingungen, die mehrere Werte annehmen können, sollte ein Splat verwendet
151
- werden:
152
-
153
- set(:auth) do |*roles| # <- hier kommt der Splat ins Spiel
154
- condition do
155
- unless logged_in? && roles.any? {|role| current_user.in_role? role }
156
- redirect "/login/", 303
157
- end
158
- end
159
- end
160
-
161
- get "/mein/account/", :auth => [:user, :admin] do
162
- "Mein Account"
163
- end
164
-
165
- get "/nur/admin/", :auth => :admin do
166
- "Nur Admins dürfen hier rein!"
167
- end
168
-
169
- === Rückgabewerte
170
-
171
- Durch den Rückgabewert eines Routen-Blocks wird mindestens der Response-Body
172
- festgelegt, der an den HTTP-Client, bzw. die nächste Rack-Middleware,
173
- weitergegeben wird. Im Normalfall handelt es sich hierbei, wie in den
174
- vorangehenden Beispielen zu sehen war, um einen String. Es werden allerdings
175
- auch andere Werte akzeptiert.
176
-
177
- Es kann jedes gültige Objekt zurückgegeben werden, bei dem es sich entweder um
178
- einen Rack-Rückgabewert, einen Rack-Body oder einen HTTP-Status-Code handelt:
179
-
180
- * Ein Array mit drei Elementen: <tt>[Status (Fixnum), Headers (Hash),
181
- Response-Body (antwortet auf #each)]</tt>.
182
- * Ein Array mit zwei Elementen: <tt>[Status (Fixnum), Response-Body (antwortet
183
- auf #each)]</tt>.
184
- * Ein Objekt, das auf <tt>#each</tt> antwortet und den an diese Methode
185
- übergebenen Block nur mit Strings als Übergabewerte aufruft.
186
- * Ein Fixnum, das den Status-Code festlegt.
187
-
188
- Damit lässt sich relativ einfach Streaming implementieren:
189
-
190
- class Stream
191
- def each
192
- 100.times { |i| yield "#{i}\n" }
193
- end
194
- end
195
-
196
- get('/') { Stream.new }
197
-
198
- Ebenso kann die +stream+-Helfer-Methode (s.u.) verwendet werden, die Streaming
199
- direkt in die Route integriert.
200
-
201
- === Eigene Routen-Muster
202
-
203
- Wie oben schon beschrieben, ist Sinatra von Haus aus mit Unterstützung für
204
- String-Muster und Reguläre Ausdrücke zum Abgleichen von Routen ausgestattet.
205
- Das muss aber noch nicht alles sein, es können ohne großen Aufwand eigene
206
- Routen-Muster erstellt werden:
207
-
208
- class AllButPattern
209
- Match = Struct.new(:captures)
210
-
211
- def initialize(except)
212
- @except = except
213
- @captures = Match.new([])
214
- end
215
-
216
- def match(str)
217
- @captures unless @except === str
218
- end
219
- end
220
-
221
- def all_but(pattern)
222
- AllButPattern.new(pattern)
223
- end
224
-
225
- get all_but("/index") do
226
- # ...
227
- end
228
-
229
- Beachte, dass das obige Beispiel etwas übertrieben wirkt. Es geht auch
230
- einfacher:
231
-
232
- get // do
233
- pass if request.path_info == "/index"
234
- # ...
235
- end
236
-
237
- Oder unter Verwendung eines negativen look ahead:
238
-
239
- get %r{^(?!/index$)} do
240
- # ...
241
- end
242
-
243
- == Statische Dateien
244
-
245
- Statische Dateien werden aus dem <tt>./public</tt>-Ordner ausgeliefert. Es ist
246
- möglich, einen anderen Ort zu definieren, indem man die
247
- <tt>:public_folder</tt>-Option setzt:
248
-
249
- set :public_folder, File.dirname(__FILE__) + '/static'
250
-
251
- Zu beachten ist, dass der Ordnername public nicht Teil der URL ist. Die Datei
252
- <tt>./public/css/style.css</tt> ist unter
253
- <tt>http://example.com/css/style.css</tt> zu finden.
254
-
255
- Um den <tt>Cache-Control</tt>-Header mit Informationen zu versorgen, verwendet
256
- man die <tt>:static_cache_control</tt>-Einstellung (s.u.).
257
-
258
- == Views/Templates
259
-
260
- Alle Templatesprachen verwenden ihre eigene Renderingmethode, die jeweils
261
- einen String zurückgibt:
262
-
263
- get '/' do
264
- erb :index
265
- end
266
-
267
- Dieses Beispiel rendert <tt>views/index.erb</tt>.
268
-
269
- Anstelle eines Templatenamens kann man auch direkt die Templatesprache
270
- verwenden:
271
-
272
- get '/' do
273
- code = "<%= Time.now %>"
274
- erb code
275
- end
276
-
277
- Templates nehmen ein zweite Argument an, den Options-Hash:
278
-
279
- get '/' do
280
- erb :index, :layout => :post
281
- end
282
-
283
- Dieses Beispiel rendert <tt>views/index.erb</tt> eingebettet in
284
- <tt>views/post.erb</tt> (Voreinstellung ist <tt>views/layout.erb</tt>, sofern
285
- es vorhanden ist.)
286
-
287
- Optionen, die Sinatra nicht versteht, werden an das Template weitergereicht:
288
-
289
- get '/' do
290
- haml :index, :format => :html5
291
- end
292
-
293
- Für alle Templates können auch generelle Einstellungen festgelegt werden:
294
-
295
- set :haml, :format => :html5
296
-
297
- get '/' do
298
- haml :index
299
- end
300
-
301
- Optionen, die an die Rendermethode weitergegeben werden, überschreiben die
302
- Einstellungen, die mit +set+ festgelegt wurden.
303
-
304
- Mögliche Einstellungen:
305
-
306
- [locals]
307
- Liste von lokalen Variablen, die and das Dokument weitergegeben werden.
308
- Praktisch für Partials.
309
- Beispiel: <tt>erb "<%= foo %>", :locals => {:foo => "bar"}</tt>
310
-
311
- [default_encoding]
312
- Gibt die Stringkodierung an, die verwendet werden soll. Voreingestellt auf
313
- <tt>settings.default_encoding</tt>.
314
-
315
- [views]
316
- Ordner, aus dem die Templates heraus geladen werden. Voreingestellt auf
317
- <tt>settings.views</tt>.
318
-
319
- [layout]
320
- Legt fest, ob ein Layouttemplate verwendet werden soll oder nicht (+true+
321
- oder +false+). Ist es ein Symbol, dass legt es fest, welches Template als
322
- Layout verwendet wird. Beispiel:
323
- <tt>erb :index, :layout => !request.xhr?</tt>
324
-
325
- [content_type]
326
- Content-Type den das Template ausgibt. Voreinstellung hängt von der
327
- Templatesprache ab.
328
-
329
- [scope]
330
- Scope, in dem das Template gerendert wird. Liegt standardmäßig innerhalb der
331
- App-Instanz. Wird Scope geändert, sind Instanzvariablen und Helfermethoden
332
- nicht verfügbar.
333
-
334
- [layout_engine]
335
- Legt fest, welcher Renderer für das Layout verantwortlich ist.
336
- Hilfreich für Sprachen, die sonst keine Templates unterstützen.
337
- Voreingestellt auf den Renderer, der für das Template verwendet wird.
338
- Beispiel: <tt>set :rdoc, :layout_engine => :erb</tt>
339
-
340
- Sinatra geht davon aus, dass die Templates sich im <tt>./views</tt> Verzeichnis
341
- befinden. Es kann jedoch ein anderer Ordner festgelegt werden:
342
-
343
- set :views, settings.root + '/templates'
344
-
345
- Es ist zu beachten, dass immer mit Symbolen auf Templates verwiesen werden
346
- muss, auch dann, wenn sie sich in einem Unterordner befinden:
347
-
348
- haml :'unterverzeichnis/template'
349
-
350
- Rendering-Methoden rendern jeden String direkt.
351
-
352
- === Verfügbare Templatesprachen
353
-
354
- Einige Sprachen haben mehrere Implementierungen. Um festzulegen, welche
355
- verwendet wird (und dann auch Thread-sicher ist), verwendet man am besten zu
356
- Beginn ein 'require':
357
-
358
- require 'rdiscount' # oder require 'bluecloth'
359
- get('/') { markdown :index }
360
-
361
- === Haml Templates
362
-
363
- Abhängigkeit:: {haml}[http://haml.info/]
364
- Dateierweiterungs:: <tt>.haml</tt>
365
- Beispiel:: <tt>haml :index, :format => :html5</tt>
366
-
367
- === Erb Templates
368
-
369
- Abhängigkeit:: {erubis}[http://www.kuwata-lab.com/erubis/] oder
370
- erb (included in Ruby)
371
- Dateierweiterungs:: <tt>.erb</tt>, <tt>.rhtml</tt> oder <tt>.erubis</tt>
372
- (nur Erubis)
373
- Beispiel:: <tt>erb :index</tt>
374
-
375
- === Builder Templates
376
-
377
- Abhängigkeit:: {builder}[http://builder.rubyforge.org/]
378
- Dateierweiterungs:: <tt>.builder</tt>
379
- Beispiel:: <tt>builder { |xml| xml.em "Hallo" }</tt>
380
-
381
- Nimmt ebenso einen Block für Inline-Templates entgegen (siehe Beispiel).
382
-
383
- === Nokogiri Templates
384
-
385
- Abhängigkeit:: {nokogiri}[http://nokogiri.org/]
386
- Dateierweiterungs:: <tt>.nokogiri</tt>
387
- Beispiel:: <tt>nokogiri { |xml| xml.em "Hallo" }</tt>
388
-
389
- Nimmt ebenso einen Block für Inline-Templates entgegen (siehe Beispiel).
390
-
391
- === Sass Templates
392
-
393
- Abhängigkeit:: {sass}[http://sass-lang.com/]
394
- Dateierweiterungs:: <tt>.sass</tt>
395
- Beispiel:: <tt>sass :stylesheet, :style => :expanded</tt>
396
-
397
- === SCSS Templates
398
-
399
- Abhängigkeit:: {sass}[http://sass-lang.com/]
400
- Dateierweiterungs:: <tt>.scss</tt>
401
- Beispiel:: <tt>scss :stylesheet, :style => :expanded</tt>
402
-
403
- === Less Templates
404
-
405
- Abhängigkeit:: {less}[http://www.lesscss.org/]
406
- Dateierweiterungs:: <tt>.less</tt>
407
- Beispiel:: <tt>less :stylesheet</tt>
408
-
409
- === Liquid Templates
410
-
411
- Abhängigkeit:: {liquid}[http://www.liquidmarkup.org/]
412
- Dateierweiterungs:: <tt>.liquid</tt>
413
- Beispiel:: <tt>liquid :index, :locals => { :key => 'Wert' }</tt>
414
-
415
- Da man aus dem Liquid-Template heraus keine Ruby-Methoden aufrufen kann
416
- (ausgenommen +yield+), wird man üblicherweise locals verwenden wollen, mit
417
- denen man Variablen weitergibt.
418
-
419
- === Markdown Templates
420
-
421
- Abhängigkeit:: {rdiscount}[https://github.com/rtomayko/rdiscount],
422
- {redcarpet}[https://github.com/tanoku/redcarpet],
423
- {bluecloth}[http://deveiate.org/projects/BlueCloth],
424
- {kramdown}[http://kramdown.rubyforge.org/] *oder*
425
- {maruku}[http://maruku.rubyforge.org/]
426
- Dateierweiterungs:: <tt>.markdown</tt>, <tt>.mkd</tt> und <tt>.md</tt>
427
- Beispiel:: <tt>markdown :index, :layout_engine => :erb</tt>
428
-
429
- Da man aus den Markdown-Templates heraus keine Ruby-Methoden aufrufen und auch
430
- keine locals verwenden kann, wird man Markdown üblicherweise in Kombination mit
431
- anderen Renderern verwenden wollen:
432
-
433
- erb :overview, :locals => { :text => markdown(:einfuehrung) }
434
-
435
- Beachte, dass man die +markdown+-Methode auch aus anderen Templates heraus
436
- aufrufen kann:
437
-
438
- %h1 Gruß von Haml!
439
- %p= markdown(:Grüße)
440
-
441
- Da man Ruby nicht von Markdown heraus aufrufen kann, können auch Layouts nicht
442
- in Markdown geschrieben werden. Es ist aber möglich, einen Renderer für die
443
- Templates zu verwenden und einen anderen für das Layout, indem die
444
- <tt>:layout_engine</tt>-Option verwendet wird.
445
-
446
- === Textile Templates
447
-
448
- Abhängigkeit:: {RedCloth}[http://redcloth.org/]
449
- Dateierweiterungs:: <tt>.textile</tt>
450
- Beispiel:: <tt>textile :index, :layout_engine => :erb</tt>
451
-
452
- Da man aus dem Textile-Template heraus keine Ruby-Methoden aufrufen und auch
453
- keine locals verwenden kann, wird man Textile üblicherweise in Kombination mit
454
- anderen Renderern verwenden wollen:
455
-
456
- erb :overview, :locals => { :text => textile(:einfuehrung) }
457
-
458
- Beachte, dass man die +textile+-Methode auch aus anderen Templates heraus
459
- aufrufen kann:
460
-
461
- %h1 Gruß von Haml!
462
- %p= textile(:Grüße)
463
-
464
- Da man Ruby nicht von Textile heraus aufrufen kann, können auch Layouts nicht
465
- in Textile geschrieben werden. Es ist aber möglich, einen Renderer für die
466
- Templates zu verwenden und einen anderen für das Layout, indem die
467
- <tt>:layout_engine</tt>-Option verwendet wird.
468
-
469
- === RDoc Templates
470
-
471
- Abhängigkeit:: {rdoc}[http://rdoc.rubyforge.org/]
472
- Dateierweiterungs:: <tt>.rdoc</tt>
473
- Beispiel:: <tt>textile :README, :layout_engine => :erb</tt>
474
-
475
- Da man aus dem RDoc-Template heraus keine Ruby-Methoden aufrufen und auch
476
- keine locals verwenden kann, wird man RDoc üblicherweise in Kombination mit
477
- anderen Renderern verwenden wollen:
478
-
479
- erb :overview, :locals => { :text => rdoc(:einfuehrung) }
480
-
481
- Beachte, dass man die +rdoc+-Methode auch aus anderen Templates heraus
482
- aufrufen kann:
483
-
484
- %h1 Gruß von Haml!
485
- %p= rdoc(:Grüße)
486
-
487
- Da man Ruby nicht von RDoc heraus aufrufen kann, können auch Layouts nicht
488
- in RDoc geschrieben werden. Es ist aber möglich, einen Renderer für die
489
- Templates zu verwenden und einen anderen für das Layout, indem die
490
- <tt>:layout_engine</tt>-Option verwendet wird.
491
-
492
- === Radius Templates
493
-
494
- Abhängigkeit:: {radius}[http://radius.rubyforge.org/]
495
- Dateierweiterungs:: <tt>.radius</tt>
496
- Beispiel:: <tt>radius :index, :locals => { :key => 'Wert' }</tt>
497
-
498
- Da man aus dem Radius-Template heraus keine Ruby-Methoden aufrufen kann, wird
499
- man üblicherweise locals verwenden wollen, mit denen man Variablen weitergibt.
500
-
501
- === Markaby Templates
502
-
503
- Abhängigkeit:: {markaby}[http://markaby.github.com/]
504
- Dateierweiterungs:: <tt>.mab</tt>
505
- Beispiel:: <tt>markaby { h1 "Willkommen!" }</tt>
506
-
507
- Nimmt ebenso einen Block für Inline-Templates entgegen (siehe Beispiel).
508
-
509
- === Slim Templates
510
-
511
- Abhängigkeit:: {slim}[http://slim-lang.com/]
512
- Dateierweiterungs:: <tt>.slim</tt>
513
- Beispiel:: <tt>slim :index</tt>
514
-
515
- === Creole Templates
516
-
517
- Abhängigkeit:: {creole}[https://github.com/minad/creole]
518
- Dateierweiterungs:: <tt>.creole</tt>
519
- Beispiel:: <tt>creole :wiki, :layout_engine => :erb</tt>
520
-
521
- Da man aus dem Creole-Template heraus keine Ruby-Methoden aufrufen und auch
522
- keine locals verwenden kann, wird man Creole üblicherweise in Kombination mit
523
- anderen Renderern verwenden wollen:
524
-
525
- erb :overview, :locals => { :text => creole(:einfuehrung) }
526
-
527
- Beachte, dass man die +creole+-Methode auch aus anderen Templates heraus
528
- aufrufen kann:
529
-
530
- %h1 Gruß von Haml!
531
- %p= creole(:Grüße)
532
-
533
- Da man Ruby nicht von Creole heraus aufrufen kann, können auch Layouts nicht
534
- in Creole geschrieben werden. Es ist aber möglich, einen Renderer für die
535
- Templates zu verwenden und einen anderen für das Layout, indem die
536
- <tt>:layout_engine</tt>-Option verwendet wird.
537
-
538
- === CoffeeScript Templates
539
-
540
- Abhängigkeit:: {coffee-script}[https://github.com/josh/ruby-coffee-script]
541
- und eine {Möglichkeit JavaScript auszuführen}[https://github.com/sstephenson/execjs/blob/master/README.md#readme]
542
- Dateierweiterungs:: <tt>.coffee</tt>
543
- Beispiel:: <tt>coffee :index</tt>
544
-
545
- === Eingebettete Templates
546
-
547
- get '/' do
548
- haml '%div.title Hallo Welt'
549
- end
550
-
551
- Rendert den eingebetteten Template-String.
552
-
553
- === Auf Variablen in Templates zugreifen
554
-
555
- Templates werden in demselben Kontext ausgeführt wie Routen. Instanzvariablen
556
- in Routen sind auch direkt im Template verfügbar:
557
-
558
- get '/:id' do
559
- @foo = Foo.find(params[:id])
560
- haml '%h1= @foo.name'
561
- end
562
-
563
- Oder durch einen expliziten Hash von lokalen Variablen:
564
-
565
- get '/:id' do
566
- foo = Foo.find(params[:id])
567
- haml '%h1= bar.name', :locals => { :bar => foo }
568
- end
569
-
570
- Dies wird typischerweise bei Verwendung von Subtemplates (partials) in anderen
571
- Templates eingesetzt.
572
-
573
- === Inline-Templates
574
-
575
- Templates können auch am Ende der Datei definiert werden:
576
-
577
- require 'sinatra'
578
-
579
- get '/' do
580
- haml :index
581
- end
582
-
583
- __END__
584
-
585
- @@ layout
586
- %html
587
- = yield
588
-
589
- @@ index
590
- %div.title Hallo Welt!!!!!
591
-
592
- Anmerkung: Inline-Templates, die in der Datei definiert sind, die <tt>require
593
- 'sinatra'</tt> aufruft, werden automatisch geladen. Um andere Inline-Templates
594
- in anderen Dateien aufzurufen, muss explizit <tt>enable :inline_templates</tt>
595
- verwendet werden.
596
-
597
- === Benannte Templates
598
-
599
- Templates können auch mit der Top-Level <tt>template</tt>-Methode definiert
600
- werden:
601
-
602
- template :layout do
603
- "%html\n =yield\n"
604
- end
605
-
606
- template :index do
607
- '%div.title Hallo Welt!'
608
- end
609
-
610
- get '/' do
611
- haml :index
612
- end
613
-
614
- Wenn ein Template mit dem Namen "layout" existiert, wird es bei jedem Aufruf
615
- verwendet. Durch <tt>:layout => false</tt> kann das Ausführen verhindert
616
- werden:
617
-
618
- get '/' do
619
- haml :index, :layout => request.xhr?
620
- end
621
-
622
- === Dateiendungen zuordnen
623
-
624
- Um eine Dateiendung einer Template-Engine zuzuordnen, kann
625
- <tt>Tilt.register</tt> genutzt werden. Wenn etwa die Dateiendung +tt+ für
626
- Textile-Templates genutzt werden soll, lässt sich dies wie folgt
627
- bewerkstelligen:
628
-
629
- Tilt.register :tt, Tilt[:textile]
630
-
631
- === Eine eigene Template-Engine hinzufügen
632
-
633
- Zu allererst muss die Engine bei Tilt registriert und danach eine
634
- Rendering-Methode erstellt werden:
635
-
636
- Tilt.register :mtt, MeineTolleTemplateEngine
637
-
638
- helpers do
639
- def mtt(*args) render(:mtt, *args) end
640
- end
641
-
642
- get '/' do
643
- mtt :index
644
- end
645
-
646
- Dieser Code rendert <tt>./views/application.mtt</tt>. Siehe
647
- github.com/rtomayko/tilt[https://github.com/rtomayko/tilt], um mehr über Tilt
648
- zu lernen.
649
-
650
- == Filter
651
-
652
- Before-Filter werden vor jedem Request in demselben Kontext, wie danach die
653
- Routen, ausgeführt. So können etwa Request und Antwort geändert werden.
654
- Gesetzte Instanzvariablen in Filtern können in Routen und Templates verwendet
655
- werden:
656
-
657
- before do
658
- @note = 'Hi!'
659
- request.path_info = '/foo/bar/baz'
660
- end
661
-
662
- get '/foo/*' do
663
- @note #=> 'Hi!'
664
- params[:splat] #=> 'bar/baz'
665
- end
666
-
667
- After-Filter werden nach jedem Request in demselben Kontext ausgeführt und
668
- können ebenfalls Request und Antwort ändern. In Before-Filtern gesetzte
669
- Instanzvariablen können in After-Filtern verwendet werden:
670
-
671
- after do
672
- puts response.status
673
- end
674
-
675
- Filter können optional auch mit einem Muster ausgestattet werden, welches auf
676
- den Request-Pfad passen muss, damit der Filter ausgeführt wird:
677
-
678
- before '/protected/*' do
679
- authenticate!
680
- end
681
-
682
- after '/create/:slug' do |slug|
683
- session[:last_slug] = slug
684
- end
685
-
686
- Ähnlich wie Routen können Filter auch mit weiteren Bedingungen eingeschränkt
687
- werden:
688
-
689
- before :agent => /Songbird/ do
690
- # ...
691
- end
692
-
693
- after '/blog/*', :host_name => 'example.com' do
694
- # ...
695
- end
696
-
697
- == Helfer
698
-
699
- Durch die Top-Level <tt>helpers</tt>-Methode werden sogenannte Helfer-Methoden
700
- definiert, die in Routen und Templates verwendet werden können:
701
-
702
- helpers do
703
- def bar(name)
704
- "#{name}bar"
705
- end
706
- end
707
-
708
- get '/:name' do
709
- bar(params[:name])
710
- end
711
-
712
- === Sessions verwenden
713
- Sessions werden verwendet, um Zustände zwischen den Requests zu speichern.
714
- Sind sie aktiviert, kann ein Session-Hash je Benutzer-Session verwendet werden.
715
-
716
- enable :sessions
717
-
718
- get '/' do
719
- "value = " << session[:value].inspect
720
- end
721
-
722
- get '/:value' do
723
- session[:value] = params[:value]
724
- end
725
-
726
- Beachte, dass <tt>enable :sessions</tt> alle Daten in einem Cookie speichert.
727
- Unter Umständen kann dies negative Effekte haben, z.B. verursachen viele Daten
728
- höheren, teilweise überflüssigen Traffic. Um das zu vermeiden, kann eine Rack-
729
- Session-Middleware verwendet werden. Dabei wird auf <tt>enable :sessions</tt>
730
- verzichtet und die Middleware wie üblich im Programm eingebunden:
731
-
732
- use Rack::Session::Pool, :expire_after => 2592000
733
-
734
- get '/' do
735
- "value = " << session[:value].inspect
736
- end
737
-
738
- get '/:value' do
739
- session[:value] = params[:value]
740
- end
741
-
742
- Um die Sicherheit zu erhöhen, werden Cookies, die Session-Daten führen, mit
743
- einem sogenannten Session-Secret signiert. Da sich dieses Geheimwort bei jedem
744
- Neustart der Applikation automatisch ändert, ist es sinnvoll, ein eigenes zu
745
- wählen, damit sich alle Instanzen der Applikation dasselbe Session-Secret
746
- teilen:
747
-
748
- set :session_secret, 'super secret'
749
-
750
- Zur weiteren Konfiguration kann man einen Hash mit Optionen in den +sessions+
751
- Einstellungen ablegen.
752
-
753
- set :sessions, :domain => 'foo.com'
754
-
755
- == Anhalten
756
-
757
- Zum sofortigen Stoppen eines Request in einem Filter oder einer Route:
758
-
759
- halt
760
-
761
- Der Status kann beim Stoppen auch angegeben werden:
762
-
763
- halt 410
764
-
765
- Oder auch den Response-Body:
766
-
767
- halt 'Hier steht der Body'
768
-
769
- Oder beides:
770
-
771
- halt 401, 'verschwinde!'
772
-
773
- Sogar mit Headern:
774
-
775
- halt 402, {'Content-Type' => 'text/plain'}, 'Rache'
776
-
777
- Natürlich ist es auch möglich, ein Template mit +halt+ zu verwenden:
778
-
779
- halt erb(:error)
780
-
781
- == Weiterspringen
782
-
783
- Eine Route kann mittels <tt>pass</tt> zu der nächsten passenden Route springen:
784
-
785
- get '/raten/:wer' do
786
- pass unless params[:wer] == 'Frank'
787
- 'Du hast mich!'
788
- end
789
-
790
- get '/raten/*' do
791
- 'Du hast mich nicht!'
792
- end
793
-
794
- Der Block wird sofort verlassen und es wird nach der nächsten treffenden Route
795
- gesucht. Ein 404-Fehler wird zurückgegeben, wenn kein treffendes Routen-Muster
796
- gefunden wird.
797
-
798
- === Eine andere Route ansteuern
799
-
800
- Manchmal entspricht +pass+ nicht den Anforderungen, wenn das Ergebnis einer
801
- anderen Route gefordert wird. Um das zu erreichen, lässt sich +call+ nutzen:
802
-
803
- get '/foo' do
804
- status, headers, body = call env.merge("PATH_INFO" => '/bar')
805
- [status, headers, body.map(&:upcase)]
806
- end
807
-
808
- get '/bar' do
809
- "bar"
810
- end
811
-
812
- Beachte, dass in dem oben angegeben Beispiel die Performance erheblich erhöht
813
- werden kann, wenn <tt>"bar"</tt> in eine Helfer-Methode umgewandelt wird, auf
814
- die <tt>/foo</tt> und <tt>/bar</tt> zugreifen können.
815
-
816
- Wenn der Request innerhalb derselben Applikations-Instanz aufgerufen und keine
817
- Kopie der Instanz erzeugt werden soll, kann <tt>call!</tt> anstelle von
818
- +call+ verwendet werden.
819
-
820
- Die Rack-Spezifikationen enthalten weitere Informationen zu +call+.
821
-
822
- === Body, Status-Code und Header setzen
823
-
824
- Es ist möglich und empfohlen, den Status-Code sowie den Response-Body mit einem
825
- Returnwert in der Route zu setzen. In manchen Situationen kann es jedoch sein,
826
- dass der Body an irgendeiner anderen Stelle während der Ausführung gesetzt
827
- wird. Das lässt sich mit der Helfer-Methode +body+ bewerkstelligen. Wird +body+
828
- verwendet, lässt sich der Body jederzeit über diese Methode aufrufen:
829
-
830
- get '/foo' do
831
- body "bar"
832
- end
833
-
834
- after do
835
- puts body
836
- end
837
-
838
- Ebenso ist es möglich, einen Block an +body+ weiterzureichen, der dann vom
839
- Rack-Handler ausgeführt wird (lässt sich z.B. zur Umsetzung von Streaming
840
- einsetzen, siehe auch "Rückgabewerte").
841
-
842
- Vergleichbar mit +body+ lassen sich auch Status-Code und Header setzen:
843
-
844
- get '/foo' do
845
- status 418
846
- headers \
847
- "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
848
- "Refresh" => "Refresh: 20; http://www.ietf.org/rfc/rfc2324.txt"
849
- halt "Ich bin ein Teekesselchen"
850
- end
851
-
852
- Genau wie bei +body+ liest ein Aufrufen von +headers+ oder +status+ ohne
853
- Argumente den aktuellen Wert aus.
854
-
855
- === Response-Streams
856
-
857
- In manchen Situationen sollen Daten bereits an den Client zurückgeschickt
858
- werden, bevor ein vollständiger Response bereit steht. Manchmal will man die
859
- Verbindung auch erst dann beenden und Daten so lange an den Client
860
- zurückschicken, bis er die Verbindung abbricht. Für diese Fälle gibt es die
861
- +stream+-Helfer-Methode, die es einem erspart eigene Lösungen zu schreiben:
862
-
863
- get '/' do
864
- stream do |out|
865
- out << "Das ist ja mal wieder fanta -\n"
866
- sleep 0.5
867
- out << " (bitte warten…) \n"
868
- sleep 1
869
- out << "- stisch!\n"
870
- end
871
- end
872
-
873
- Damit lassen sich Streaming-APIs realisieren, sog.
874
- {Server Sent Events}[http://dev.w3.org/html5/eventsource/] die als Basis für
875
- {WebSockets}[http://en.wikipedia.org/wiki/WebSocket] dienen. Ebenso können sie
876
- verwendet werden, um den Durchsatz zu erhöhen, wenn ein Teil der Daten von
877
- langsamen Ressourcen abhängig ist.
878
-
879
- Es ist zu beachten, dass das Verhalten beim Streaming, insbesondere die Anzahl
880
- nebenläufiger Anfragen, stark davon abhängt, welcher Webserver für die
881
- Applikation verwendet wird. Einige Server, z.B. WEBRick, unterstützen Streaming
882
- nicht oder nur teilweise. Sollte der Server Streaming nicht unterstützen, wird
883
- ein vollständiger Response-Body zurückgeschickt, sobald der an +stream+
884
- weitergegebene Block abgearbeitet ist. Mit Shotgun funktioniert Streaming z.B.
885
- überhaupt nicht.
886
-
887
- Ist der optionale Parameter +keep_open+ aktiviert, wird beim gestreamten Objekt
888
- +close+ nicht aufgerufen und es ist einem überlassen dies an einem beliebigen
889
- späteren Zeitpunkt nachholen. Die Funktion ist jedoch nur bei Event-gesteuerten
890
- Serven wie Thin oder Rainbows möglich, andere Server werden trotzdem den Stream
891
- beenden:
892
-
893
- set :server, :thin
894
- connections = []
895
-
896
- get '/' do
897
- # Den Stream offen halten
898
- stream(:keep_open) { |out| connections << out }
899
- end
900
-
901
- post '/' do
902
- # In alle offenen Streams schreiben
903
- connections.each { |out| out << params[:message] << "\n" }
904
- "Nachricht verschickt"
905
- end
906
-
907
- === Logger
908
-
909
- Im Geltungsbereich eines Request stellt die +logger+ Helfer-Methode eine
910
- +Logger+ Instanz zur Verfügung:
911
-
912
- get '/' do
913
- logger.info "es passiert gerade etwas"
914
- # ...
915
- end
916
-
917
- Der Logger übernimmt dabei automatisch alle im Rack-Handler eingestellten Log-
918
- Vorgaben. Ist Loggen ausgeschaltet, gibt die Methode ein Leerobjekt zurück.
919
- In den Routen und Filtern muss man sich also nicht weiter darum kümmern.
920
-
921
- Beachte, dass das Loggen standardmäßig nur für <tt>Sinatra::Application</tt>
922
- voreingestellt ist. Wird über <tt>Sinatra::Base</tt> vererbt, muss es erst
923
- aktiviert werden:
924
-
925
- class MyApp < Sinatra::Base
926
- configure :production, :development do
927
- enable :logging
928
- end
929
- end
930
-
931
- Damit auch keine Middleware das Logging aktivieren kann, muss die +logging+
932
- Einstellung auf +nil+ gesetzt werden. Das heißt aber auch, dass +logger+ in
933
- diesem Fall +nil+ zurückgeben wird. Üblicherweise wird das eingesetzt, wenn ein
934
- eigener Logger eingerichtet werden soll. Sinatra wird dann verwenden, was in
935
- <tt>env['rack.logger']</tt> eingetragen ist.
936
-
937
- == Mime-Types
938
-
939
- Wenn <tt>send_file</tt> oder statische Dateien verwendet werden, kann es
940
- vorkommen, dass Sinatra den Mime-Typ nicht kennt. Registriert wird dieser mit
941
- +mime_type+ per Dateiendung:
942
-
943
- configure do
944
- mime_type :foo, 'text/foo'
945
- end
946
-
947
- Es kann aber auch der +content_type+-Helfer verwendet werden:
948
-
949
- get '/' do
950
- content_type :foo
951
- "foo foo foo"
952
- end
953
-
954
- === URLs generieren
955
-
956
- Zum Generieren von URLs sollte die +url+-Helfer-Methode genutzen werden, so
957
- z.B. beim Einsatz von Haml:
958
-
959
- %a{:href => url('/foo')} foo
960
-
961
- Soweit vorhanden, wird Rücksicht auf Proxys und Rack-Router genommen.
962
-
963
- Diese Methode ist ebenso über das Alias +to+ zu erreichen (siehe Beispiel
964
- unten).
965
-
966
- === Browser-Umleitung
967
-
968
- Eine Browser-Umleitung kann mithilfe der +redirect+-Helfer-Methode erreicht
969
- werden:
970
-
971
- get '/foo' do
972
- redirect to('/bar')
973
- end
974
-
975
- Weitere Parameter werden wie Argumente der +halt+-Methode behandelt:
976
-
977
- redirect to('/bar'), 303
978
- redirect 'http://google.com', 'Hier bist du falsch'
979
-
980
- Ebenso leicht lässt sich ein Schritt zurück mit dem Alias
981
- <tt>redirect back</tt> erreichen:
982
-
983
- get '/foo' do
984
- "<a href='/bar'>mach was</a>"
985
- end
986
-
987
- get '/bar' do
988
- mach_was
989
- redirect back
990
- end
991
-
992
- Um Argumente an ein Redirect weiterzugeben, können sie entweder dem Query
993
- übergeben:
994
-
995
- redirect to('/bar?summe=42')
996
-
997
- oder eine Session verwendet werden:
998
-
999
- enable :sessions
1000
-
1001
- get '/foo' do
1002
- session[:secret] = 'foo'
1003
- redirect to('/bar')
1004
- end
1005
-
1006
- get '/bar' do
1007
- session[:secret]
1008
- end
1009
-
1010
-
1011
- === Cache einsetzen
1012
-
1013
- Ein sinnvolles Einstellen von Header-Daten ist die Grundlage für ein
1014
- ordentliches HTTP-Caching.
1015
-
1016
- Der Cache-Control-Header lässt sich ganz einfach einstellen:
1017
-
1018
- get '/' do
1019
- cache_control :public
1020
- "schon gecached!"
1021
- end
1022
-
1023
- Profitipp: Caching im before-Filter aktivieren
1024
-
1025
- before do
1026
- cache_control :public, :must_revalidate, :max_age => 60
1027
- end
1028
-
1029
- Bei Verwendung der +expires+-Helfermethode zum Setzen des gleichnamigen
1030
- Headers, wird <tt>Cache-Control</tt> automatisch eigestellt:
1031
-
1032
- before do
1033
- expires 500, :public, :must_revalidate
1034
- end
1035
-
1036
- Um alles richtig zu machen, sollten auch +etag+ oder +last_modified+ verwendet
1037
- werden. Es wird empfohlen, dass diese Helfer aufgerufen werden *bevor* die
1038
- eigentliche Arbeit anfängt, da sie sofort eine Antwort senden, wenn der
1039
- Client eine aktuelle Version im Cache vorhält:
1040
-
1041
- get '/article/:id' do
1042
- @article = Article.find params[:id]
1043
- last_modified @article.updated_at
1044
- etag @article.sha1
1045
- erb :article
1046
- end
1047
-
1048
- ebenso ist es möglich einen
1049
- {schwachen ETag}[http://de.wikipedia.org/wiki/HTTP_ETag] zu verwenden:
1050
-
1051
- etag @article.sha1, :weak
1052
-
1053
- Diese Helfer führen nicht das eigentliche Caching aus, sondern geben die dafür
1054
- notwendigen Informationen an den Cache weiter. Für schnelle Reverse-Proxy
1055
- Cache-Lösungen bietet sich z.B.
1056
- {rack-cache}[http://rtomayko.github.com/rack-cache/] an:
1057
-
1058
- require "rack/cache"
1059
- require "sinatra"
1060
-
1061
- use Rack::Cache
1062
-
1063
- get '/' do
1064
- cache_control :public, :max_age => 36000
1065
- sleep 5
1066
- "hello"
1067
- end
1068
-
1069
- Um den <tt>Cache-Control</tt>-Header mit Informationen zu versorgen, verwendet
1070
- man die <tt>:static_cache_control</tt>-Einstellung (s.u.).
1071
-
1072
- Nach RFC 2616 sollte sich die Anwendung anders verhalten, wenn ein
1073
- If-Match oder ein If-None_match Header auf <tt>*</tt> gesetzt wird in
1074
- Abhängigkeit davon, ob die Resource bereits existiert. Sinatra geht
1075
- davon aus, dass Ressourcen bei sicheren Anfragen (z.B. bei get oder Idempotenten
1076
- Anfragen wie put) bereits existieren, wobei anderen Ressourcen
1077
- (besipielsweise bei post), als neue Ressourcen behandelt werden. Dieses
1078
- Verhalten lässt sich mit der <tt>:new_resource</tt> Option ändern:
1079
-
1080
- get '/create' do
1081
- etag '', :new_resource => true
1082
- Article.create
1083
- erb :new_article
1084
- end
1085
-
1086
- Soll das schwache ETag trotzdem verwendet werden, verwendet man die
1087
- <tt>:kind</tt> Option:
1088
-
1089
- etag '', :new_resource => true, :kind => :weak
1090
-
1091
- === Dateien versenden
1092
-
1093
- Zum Versenden von Dateien kann die <tt>send_file</tt>-Helfer-Methode verwendet
1094
- werden:
1095
-
1096
- get '/' do
1097
- send_file 'foo.png'
1098
- end
1099
-
1100
- Für <tt>send_file</tt> stehen einige Hash-Optionen zur Verfügung:
1101
-
1102
- send_file 'foo.png', :type => :jpg
1103
-
1104
- [filename]
1105
- Dateiname als Response. Standardwert ist der eigentliche Dateiname.
1106
-
1107
- [last_modified]
1108
- Wert für den Last-Modified-Header, Standardwert ist +mtime+ der Datei.
1109
-
1110
- [type]
1111
- Content-Type, der verwendet werden soll. Wird, wenn nicht angegeben, von der
1112
- Dateiendung abgeleitet.
1113
-
1114
- [disposition]
1115
- Verwendet für Content-Disposition. Mögliche Werte sind: +nil+ (Standard),
1116
- <tt>:attachment</tt> und <tt>:inline</tt>.
1117
-
1118
- [length]
1119
- Content-Length-Header. Standardwert ist die Dateigröße.
1120
-
1121
- Soweit vom Rack-Handler unterstützt, werden neben der Übertragung über den
1122
- Ruby-Prozess auch andere Möglichkeiten genutzt. Bei Verwendung der
1123
- <tt>send_file</tt>-Helfer-Methode kümmert sich Sinatra selbstständig um die
1124
- Range-Requests.
1125
-
1126
- == Das Request-Objekt
1127
-
1128
- Auf das +request+-Objekt der eigehenden Anfrage kann vom Anfrage-Scope aus
1129
- zugegriffen werden:
1130
-
1131
- # App läuft unter http://example.com/example
1132
- get '/foo' do
1133
- t = %w[text/css text/html application/javascript]
1134
- request.accept # ['text/html', '*/*']
1135
- request.accept? 'text/xml' # true
1136
- request.preferred_type(t) # 'text/html'
1137
- request.body # Request-Body des Client (siehe unten)
1138
- request.scheme # "http"
1139
- request.script_name # "/example"
1140
- request.path_info # "/foo"
1141
- request.port # 80
1142
- request.request_method # "GET"
1143
- request.query_string # ""
1144
- request.content_length # Länge des request.body
1145
- request.media_type # Medientypus von request.body
1146
- request.host # "example.com"
1147
- request.get? # true (ähnliche Methoden für andere Verben)
1148
- request.form_data? # false
1149
- request["IRGENDEIN_HEADER"] # Wert von IRGENDEIN_HEADER header
1150
- request.referrer # Der Referrer des Clients oder '/'
1151
- request.user_agent # User-Agent (verwendet in der :agent Bedingung)
1152
- request.cookies # Hash des Browser-Cookies
1153
- request.xhr? # Ist das hier ein Ajax-Request?
1154
- request.url # "http://example.com/example/foo"
1155
- request.path # "/example/foo"
1156
- request.ip # IP-Adresse des Clients
1157
- request.secure? # false (true wenn SSL)
1158
- request.forwarded? # true (Wenn es hinter einem Reverse-Proxy verwendet wird)
1159
- request.env # vollständiger env-Hash von Rack übergeben
1160
- end
1161
-
1162
- Manche Optionen, wie etwa <tt>script_name</tt> oder <tt>path_info</tt>, sind
1163
- auch schreibbar:
1164
-
1165
- before { request.path_info = "/" }
1166
-
1167
- get "/" do
1168
- "Alle Anfragen kommen hier an!"
1169
- end
1170
-
1171
- Der <tt>request.body</tt> ist ein IO- oder StringIO-Objekt:
1172
-
1173
- post "/api" do
1174
- request.body.rewind # falls schon jemand davon gelesen hat
1175
- daten = JSON.parse request.body.read
1176
- "Hallo #{daten['name']}!"
1177
- end
1178
-
1179
- === Anhänge
1180
-
1181
- Damit der Browser erkennt, dass ein Response gespeichert und nicht im Browser
1182
- angezeigt werden soll, kann der +attachment+-Helfer verwendet werden:
1183
-
1184
- get '/' do
1185
- attachment
1186
- "Speichern!"
1187
- end
1188
-
1189
- Ebenso kann eine Dateiname als Parameter hinzugefügt werden:
1190
-
1191
- get '/' do
1192
- attachment "info.txt"
1193
- "Speichern!"
1194
- end
1195
-
1196
- === Umgang mit Datum und Zeit
1197
-
1198
- Sinatra bietet eine <tt>time_for</tt>-Helfer-Methode, die aus einem gegebenen
1199
- Wert ein Time-Objekt generiert. Ebenso kann sie nach +DateTime+, +Date+ und
1200
- ähnliche Klassen konvertieren:
1201
-
1202
- get '/' do
1203
- pass if Time.now > time_for('Dec 23, 2012')
1204
- "noch Zeit"
1205
- end
1206
-
1207
- Diese Methode wird intern für +expires, +last_modiefied+ und Freunde verwendet.
1208
- Mit ein paar Handgriffen lässt sich diese Methode also in ihrem Verhalten
1209
- erweitern, indem man +time_for+ in der eigenen Applikation überschreibt:
1210
-
1211
- helpers do
1212
- def time_for(value)
1213
- case value
1214
- when :yesterday then Time.now - 24*60*60
1215
- when :tomorrow then Time.now + 24*60*60
1216
- else super
1217
- end
1218
- end
1219
- end
1220
-
1221
- get '/' do
1222
- last_modified :yesterday
1223
- expires :tomorrow
1224
- "Hallo"
1225
- end
1226
-
1227
- === Nachschlagen von Template-Dateien
1228
-
1229
- Die <tt>find_template</tt>-Helfer-Methode wird genutzt, um Template-Dateien zum
1230
- Rendern aufzufinden:
1231
-
1232
- find_template settings.views, 'foo', Tilt[:haml] do |file|
1233
- puts "könnte diese hier sein: #{file}"
1234
- end
1235
-
1236
- Das ist zwar nicht wirklich brauchbar, aber wenn man sie überschreibt, kann sie
1237
- nützlich werden, um eigene Nachschlage-Mechanismen einzubauen. Zum Beispiel
1238
- dann, wenn mehr als nur ein view-Verzeichnis verwendet werden soll:
1239
-
1240
- set :views, ['views', 'templates']
1241
-
1242
- helpers do
1243
- def find_template(views, name, engine, &block)
1244
- Array(views).each { |v| super(v, name, engine, &block) }
1245
- end
1246
- end
1247
-
1248
- Ein anderes Beispiel wäre, verschiedene Vereichnisse für verschiedene Engines
1249
- zu verwenden:
1250
-
1251
- set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
1252
-
1253
- helpers do
1254
- def find_template(views, name, engine, &block)
1255
- _, folder = views.detect { |k,v| engine == Tilt[k] }
1256
- folder ||= views[:default]
1257
- super(folder, name, engine, &block)
1258
- end
1259
- end
1260
-
1261
- Ebensogut könnte eine Extension aber auch geschrieben und mit anderen geteilt
1262
- werden!
1263
-
1264
- Beachte, dass <tt>find_template</tt> nicht prüft, ob eine Datei tatsächlich
1265
- existiert. Es wird lediglich der angegebene Block aufgerufen und nach allen
1266
- möglichen Pfaden gesucht. Das ergibt kein Performance-Problem, da +render+
1267
- +block+ verwendet, sobald eine Datei gefunden wurde. Ebenso werden
1268
- Template-Pfade samt Inhalt gecached, solange nicht im Entwicklungsmodus
1269
- gearbeitet wird. Das sollte im Hinterkopf behalten werden, wenn irgendwelche
1270
- verrückten Methoden zusammenbastelt werden.
1271
-
1272
- == Konfiguration
1273
-
1274
- Wird einmal beim Starten in jedweder Umgebung ausgeführt:
1275
-
1276
- configure do
1277
- # setze eine Option
1278
- set :option, 'wert'
1279
-
1280
- # setze mehrere Optionen
1281
- set :a => 1, :b => 2
1282
-
1283
- # das gleiche wie `set :option, true`
1284
- enable :option
1285
-
1286
- # das gleiche wie `set :option, false`
1287
- disable :option
1288
-
1289
- # dynamische Einstellungen mit Blöcken
1290
- set(:css_dir) { File.join(views, 'css') }
1291
- end
1292
-
1293
- Läuft nur, wenn die Umgebung (RACK_ENV-Umgebungsvariable) auf
1294
- <tt>:production</tt> gesetzt ist:
1295
-
1296
- configure :production do
1297
- ...
1298
- end
1299
-
1300
- Läuft nur, wenn die Umgebung auf <tt>:production</tt> oder auf <tt>:test</tt>
1301
- gesetzt ist:
1302
-
1303
- configure :production, :test do
1304
- ...
1305
- end
1306
-
1307
- Diese Einstellungen sind über +settings+ erreichbar:
1308
-
1309
- configure do
1310
- set :foo, 'bar'
1311
- end
1312
-
1313
- get '/' do
1314
- settings.foo? # => true
1315
- settings.foo # => 'bar'
1316
- ...
1317
- end
1318
-
1319
- === Einstellung des Angriffsschutzes
1320
-
1321
- Sinatra verwendet
1322
- {Rack::Protection}[https://github.com/rkh/rack-protection#readme], um die
1323
- Anwendung vor häufig vorkommenden Angriffen zu schützen. Diese Voreinstellung
1324
- lässt sich selbstverständlich auch deaktivieren, z.B. um
1325
- Geschwindigkeitsvorteile zu gewinnen:
1326
-
1327
- disable :protection
1328
-
1329
- Um einen bestimmten Schutzmechanismus zu deaktivieren, fügt man +protection+
1330
- einen Hash mit Optionen hinzu:
1331
-
1332
- set :protection, :except => :path_traversal
1333
-
1334
- Neben Strings akzeptiert <tt>:except</tt> auch Arrays, um gleich mehrere
1335
- Schutzmechanismen zu deaktivieren:
1336
-
1337
- set :protection, :except => [:path_traversal, :session_hijacking]
1338
-
1339
- === Mögliche Einstellungen
1340
-
1341
- [absolute_redirects] Wenn ausgeschaltet, wird Sinatra relative Redirects
1342
- zulassen. Jedoch ist Sinatra dann nicht mehr mit RFC
1343
- 2616 (HTTP 1.1) konform, das nur absolute Redirects
1344
- zulässt.
1345
-
1346
- Sollte eingeschaltet werden, wenn die Applikation
1347
- hinter einem Reverse-Proxy liegt, der nicht ordentlich
1348
- eingerichtet ist. Beachte, dass die
1349
- +url+-Helfer-Methode nach wie vor absolute URLs
1350
- erstellen wird, es sei denn, es wird als zweiter
1351
- Parameter +false+ angegeben.
1352
-
1353
- Standardmäßig nicht aktiviert.
1354
-
1355
- [add_charsets] Mime-Types werden hier automatisch der Helfer-Methode
1356
- <tt>content_type</tt> zugeordnet.
1357
-
1358
- Es empfielt sich, Werte hinzuzufügen statt sie zu
1359
- überschreiben:
1360
-
1361
- settings.add_charsets << "application/foobar"
1362
-
1363
- [app_file] Pfad zur Hauptdatei der Applikation. Wird verwendet, um
1364
- das Wurzel-, Inline-, View- und öffentliche Verzeichnis
1365
- des Projekts festzustellen.
1366
-
1367
- [bind] IP-Address, an die gebunden wird
1368
- (Standardwert: 0.0.0.0). Wird nur für den eingebauten
1369
- Server verwendet.
1370
-
1371
- [default_encoding] Das Encoding, falls keines angegeben wurde.
1372
- Standardwert ist <tt>"utf-8"</tt>.
1373
-
1374
- [dump_errors] Fehler im Log anzeigen.
1375
-
1376
- [environment] Momentane Umgebung. Standardmäßig auf
1377
- <tt>content_type</tt> oder <tt>"development"</tt>
1378
- eingestellt, soweit ersteres nicht vorhanden.
1379
-
1380
- [logging] Den Logger verwenden.
1381
-
1382
- [lock] Jeder Request wird gelocked. Es kann nur ein Request
1383
- pro Ruby-Prozess gleichzeitig verarbeitet werden.
1384
-
1385
- Eingeschaltet, wenn die Applikation threadsicher ist.
1386
- Standardmäßig nicht aktiviert.
1387
-
1388
- [method_override] Verwende <tt>_method</tt>, um put/delete-Formulardaten
1389
- in Browsern zu verwenden, die dies normalerweise nicht
1390
- unterstützen.
1391
-
1392
- [port] Port für die Applikation. Wird nur im internen Server
1393
- verwendet.
1394
-
1395
- [prefixed_redirects] Entscheidet, ob <tt>request.script_name</tt> in
1396
- Redirects eingefügt wird oder nicht, wenn kein
1397
- absoluter Pfad angegeben ist. Auf diese Weise verhält
1398
- sich <tt>redirect '/foo'</tt> so, als wäre es ein
1399
- <tt>redirect to('/foo')</tt>. Standardmäßig nicht
1400
- aktiviert.
1401
-
1402
- [protection] Legt fest, ob der Schutzmechanismus für häufig
1403
- Vorkommende Webangriffe auf Webapplikationen aktiviert
1404
- wird oder nicht. Weitere Informationen im vorhergehenden
1405
- Abschnitt.
1406
-
1407
- [public_folder] Das öffentliche Verzeichnis, aus dem Daten zur
1408
- Verfügung gestellt werden können. Wird nur dann
1409
- verwendet, wenn statische Daten zur Verfügung
1410
- gestellt werden können (s.u. <tt>static</tt>
1411
- Option). Leitet sich von der <tt>app_file</tt>
1412
- Einstellung ab, wenn nicht gesetzt.
1413
-
1414
- [reload_templates] Im development-Modus aktiviert.
1415
-
1416
- [root] Wurzelverzeichnis des Projekts. Leitet sich von der
1417
- <tt>app_file</tt> Einstellung ab, wenn nicht gesetzt.
1418
-
1419
- [raise_errors] Einen Ausnahmezustand aufrufen. Beendet die
1420
- Applikation. Ist automatisch aktiviert, wenn die
1421
- Umgebung auf <tt>"test"</tt> eingestellt ist.
1422
- Ansonsten ist diese Option deaktiviert.
1423
-
1424
- [run] Wenn aktiviert, wird Sinatra versuchen, den Webserver
1425
- zu starten. Nicht verwenden, wenn Rackup oder anderes
1426
- verwendet werden soll.
1427
-
1428
- [running] Läuft der eingebaute Server? Diese Einstellung nicht
1429
- ändern!
1430
-
1431
- [server] Server oder Liste von Servern, die als eingebaute
1432
- Server zur Verfügung stehen.
1433
- Standardmäßig auf ['thin', 'mongrel', 'webrick']
1434
- voreingestellt. Die Anordnung gibt die Priorität vor.
1435
-
1436
- [sessions] Sessions auf Cookiebasis mittels
1437
- <tt>Rack::Session::Cookie</tt>aktivieren. Für
1438
- weitere Infos bitte in der Sektion 'Sessions
1439
- verwenden' nachschauen.
1440
-
1441
- [show_exceptions] Bei Fehlern einen Stacktrace im Browseranzeigen. Ist
1442
- automatisch aktiviert, wenn die Umgebung auf
1443
- <tt>"development"</tt> eingestellt ist. Ansonsten ist
1444
- diese Option deaktiviert.
1445
-
1446
-
1447
- [static] Entscheidet, ob Sinatra statische Dateien zur Verfügung
1448
- stellen soll oder nicht.
1449
- Sollte nicht aktiviert werden, wenn ein Server
1450
- verwendet wird, der dies auch selbstständig erledigen
1451
- kann. Deaktivieren wird die Performance erhöhen.
1452
- Standardmäßig aktiviert.
1453
-
1454
- [static_cache_control] Wenn Sinatra statische Daten zur Verfügung stellt,
1455
- können mit dieser Einstellung die +Cache-Control+
1456
- Header zu den Responses hinzugefügt werden. Die
1457
- Einstellung verwendet dazu die +cache_control+
1458
- Helfer-Methode. Standardmäßig deaktiviert.
1459
- Ein Array wird verwendet, um mehrere Werte gleichzeitig
1460
- zu übergeben:
1461
- <tt>set :static_cache_control, [:public, :max_age => 300]</tt>
1462
-
1463
- [views] Verzeichnis der Views. Leitet sich von der
1464
- <tt>app_file</tt> Einstellung ab, wenn nicht gesetzt.
1465
-
1466
- == Umgebungen
1467
-
1468
- Es gibt drei voreingestellte Umgebungen in Sinatra: <tt>"development"</tt>,
1469
- <tt>"production"</tt> und <tt>"test"</tt>. Umgebungen können über die
1470
- +RACK_ENV+ Umgebungsvariable gesetzt werden. Die Standardeinstellung ist
1471
- <tt>"development"</tt>. In diesem Modus werden alle Templates zwischen
1472
- Requests neu geladen. Dazu gibt es besondere Fehlerseiten für 404 Stati
1473
- und Fehlermeldungen. In <tt>"production"</tt> und <tt>"test"</tt> werden
1474
- Templates automatisch gecached.
1475
-
1476
- Um die Anwendung in einer anderen Umgebung auszuführen kann man die
1477
- <tt>-e</tt> Option verwenden:
1478
-
1479
- ruby my_app.rb -e [ENVIRONMENT]
1480
-
1481
- In der Anwendung kann man die die Methoden +development?+, +test?+ und
1482
- +production?+ verwenden, um die aktuelle Umgebung zu erfahren.
1483
-
1484
- == Fehlerbehandlung
1485
-
1486
- Error-Handler laufen in demselben Kontext wie Routen und Filter, was bedeutet,
1487
- dass alle Goodies wie <tt>haml</tt>, <tt>erb</tt>, <tt>halt</tt>, etc.
1488
- verwendet werden können.
1489
-
1490
- === Nicht gefunden
1491
-
1492
- Wenn eine <tt>Sinatra::NotFound</tt>-Exception geworfen wird oder der
1493
- Statuscode 404 ist, wird der <tt>not_found</tt>-Handler ausgeführt:
1494
-
1495
- not_found do
1496
- 'Seite kann nirgendwo gefunden werden.'
1497
- end
1498
-
1499
- === Fehler
1500
-
1501
- Der +error+-Handler wird immer ausgeführt, wenn eine Exception in einem
1502
- Routen-Block oder in einem Filter geworfen wurde. Die Exception kann über die
1503
- <tt>sinatra.error</tt>-Rack-Variable angesprochen werden:
1504
-
1505
- error do
1506
- 'Entschuldige, es gab einen hässlichen Fehler - ' + env['sinatra.error'].name
1507
- end
1508
-
1509
- Benutzerdefinierte Fehler:
1510
-
1511
- error MeinFehler do
1512
- 'Au weia, ' + env['sinatra.error'].message
1513
- end
1514
-
1515
- Dann, wenn das passiert:
1516
-
1517
- get '/' do
1518
- raise MeinFehler, 'etwas Schlimmes ist passiert'
1519
- end
1520
-
1521
- bekommt man dieses:
1522
-
1523
- Au weia, etwas Schlimmes ist passiert
1524
-
1525
- Alternativ kann ein Error-Handler auch für einen Status-Code definiert werden:
1526
-
1527
- error 403 do
1528
- 'Zugriff verboten'
1529
- end
1530
-
1531
- get '/geheim' do
1532
- 403
1533
- end
1534
-
1535
- Oder ein Status-Code-Bereich:
1536
-
1537
- error 400..510 do
1538
- 'Hallo?'
1539
- end
1540
-
1541
- Sinatra setzt verschiedene <tt>not_found</tt>- und <tt>error</tt>-Handler in
1542
- der Development-Umgebung.
1543
-
1544
- == Rack-Middleware
1545
-
1546
- Sinatra baut auf Rack[http://rack.rubyforge.org/], einem minimalistischen
1547
- Standard-Interface für Ruby-Webframeworks. Eines der interessantesten
1548
- Features für Entwickler ist der Support von Middlewares, die zwischen den
1549
- Server und die Anwendung geschaltet werden und so HTTP-Request und/oder Antwort
1550
- überwachen und/oder manipulieren können.
1551
-
1552
- Sinatra macht das Erstellen von Middleware-Verkettungen mit der
1553
- Top-Level-Methode +use+ zu einem Kinderspiel:
1554
-
1555
- require 'sinatra'
1556
- require 'meine_middleware'
1557
-
1558
- use Rack::Lint
1559
- use MeineMiddleware
1560
-
1561
- get '/hallo' do
1562
- 'Hallo Welt'
1563
- end
1564
-
1565
- Die Semantik von +use+ entspricht der gleichnamigen Methode der
1566
- Rack::Builder[http://rack.rubyforge.org/doc/classes/Rack/Builder.html]-DSL
1567
- (meist verwendet in Rackup-Dateien). Ein Beispiel dafür ist, dass die
1568
- +use+-Methode mehrere/verschiedene Argumente und auch Blöcke entgegennimmt:
1569
-
1570
- use Rack::Auth::Basic do |username, password|
1571
- username == 'admin' && password == 'geheim'
1572
- end
1573
-
1574
- Rack bietet eine Vielzahl von Standard-Middlewares für Logging, Debugging,
1575
- URL-Routing, Authentifizierung und Session-Verarbeitung. Sinatra verwendet
1576
- viele von diesen Komponenten automatisch, abhängig von der Konfiguration. So
1577
- muss +use+ häufig nicht explizit verwendet werden.
1578
-
1579
- Hilfreiche Middleware gibt es z.B. hier:
1580
- {rack}[https://github.com/rack/rack/tree/master/lib/rack],
1581
- {rack-contrib}[https://github.com/rack/rack-contrib#readme],
1582
- mit {CodeRack}[http://coderack.org/] oder im
1583
- {Rack wiki}[https://github.com/rack/rack/wiki/List-of-Middleware].
1584
-
1585
- == Testen
1586
-
1587
- Sinatra-Tests können mit jedem auf Rack aufbauendem Test-Framework geschrieben
1588
- werden. {Rack::Test}[http://rdoc.info/github/brynary/rack-test/master/frames]
1589
- wird empfohlen:
1590
-
1591
- require 'my_sinatra_app'
1592
- require 'test/unit'
1593
- require 'rack/test'
1594
-
1595
- class MyAppTest < Test::Unit::TestCase
1596
- include Rack::Test::Methods
1597
-
1598
- def app
1599
- Sinatra::Application
1600
- end
1601
-
1602
- def test_my_default
1603
- get '/'
1604
- assert_equal 'Hallo Welt!', last_response.body
1605
- end
1606
-
1607
- def test_with_params
1608
- get '/meet', :name => 'Frank'
1609
- assert_equal 'Hallo Frank!', last_response.body
1610
- end
1611
-
1612
- def test_with_rack_env
1613
- get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
1614
- assert_equal "Du verwendest Songbird!", last_response.body
1615
- end
1616
- end
1617
-
1618
- == Sinatra::Base - Middleware, Bibliotheken und modulare Anwendungen
1619
-
1620
- Das Definieren einer Top-Level-Anwendung funktioniert gut für
1621
- Mikro-Anwendungen, hat aber Nachteile, wenn wiederverwendbare Komponenten wie
1622
- Middleware, Rails Metal, einfache Bibliotheken mit Server-Komponenten oder auch
1623
- Sinatra-Erweiterungen geschrieben werden sollen.
1624
-
1625
- Das Top-Level geht von einer Konfiguration für eine Mikro-Anwendung aus
1626
- (wie sie z.B. bei einer einzelnen Anwendungsdatei, <tt>./public</tt>
1627
- und <tt>./views</tt> Ordner, Logging, Exception-Detail-Seite, usw.). Genau
1628
- hier kommt <tt>Sinatra::Base</tt> ins Spiel:
1629
-
1630
- require 'sinatra/base'
1631
-
1632
- class MyApp < Sinatra::Base
1633
- set :sessions, true
1634
- set :foo, 'bar'
1635
-
1636
- get '/' do
1637
- 'Hallo Welt!'
1638
- end
1639
- end
1640
-
1641
- Die MyApp-Klasse ist eine unabhängige Rack-Komponente, die als Middleware,
1642
- Endpunkt oder via Rails Metal verwendet werden kann. Verwendet wird sie durch
1643
- +use+ oder +run+ von einer Rackup-<tt>config.ru</tt>-Datei oder als
1644
- Server-Komponente einer Bibliothek:
1645
-
1646
- MyApp.run! :host => 'localhost', :port => 9090
1647
-
1648
- Die Methoden der <tt>Sinatra::Base</tt>-Subklasse sind genau dieselben wie die
1649
- der Top-Level-DSL. Die meisten Top-Level-Anwendungen können mit nur zwei
1650
- Veränderungen zu <tt>Sinatra::Base</tt> konvertiert werden:
1651
-
1652
- * Die Datei sollte <tt>require 'sinatra/base'</tt> anstelle von
1653
- <tt>require 'sinatra/base'</tt> aufrufen, ansonsten werden alle von
1654
- Sinatras DSL-Methoden in den Top-Level-Namespace importiert.
1655
- * Alle Routen, Error-Handler, Filter und Optionen der Applikation müssen in
1656
- einer Subklasse von <tt>Sinatra::Base</tt> definiert werden.
1657
-
1658
- <tt>Sinatra::Base</tt> ist ein unbeschriebenes Blatt. Die meisten Optionen sind
1659
- per Standard deaktiviert. Das betrifft auch den eingebauten Server. Siehe
1660
- {Optionen und Konfiguration}[http://sinatra.github.com/configuration.html] für
1661
- Details über mögliche Optionen.
1662
-
1663
- === Modularer vs. klassischer Stil
1664
-
1665
- Entgegen häufiger Meinungen gibt es nichts gegen den klassischen Stil
1666
- einzuwenden. Solange es die Applikation nicht beeinträchtigt, besteht kein
1667
- Grund, eine modulare Applikation zu erstellen.
1668
-
1669
- Der größte Nachteil der klassischen Sinatra Anwendung gegenüber einer modularen
1670
- ist die Einschränkung auf eine Sinatra Anwendung pro Ruby-Prozess. Sollen
1671
- mehrere zum Einsatz kommen, muss auf den modularen Stil umgestiegen werden.
1672
- Dabei ist es kein Problem klassische und modulare Anwendungen miteinander zu
1673
- vermischen.
1674
-
1675
- Bei einem Umstieg, sollten einige Unterschiede in den Einstellungen beachtet
1676
- werden:
1677
-
1678
- Szenario Classic Modular
1679
-
1680
- app_file sinatra ladende Datei Sinatra::Base subklassierende Datei
1681
- run $0 == app_file false
1682
- logging true false
1683
- method_override true false
1684
- inline_templates true false
1685
-
1686
- === Eine modulare Applikation bereitstellen
1687
-
1688
- Es gibt zwei übliche Wege, eine modulare Anwendung zu starten. Zum einen über
1689
- <tt>run!</tt>:
1690
-
1691
- # mein_app.rb
1692
- require 'sinatra/base'
1693
-
1694
- class MeinApp < Sinatra::Base
1695
- # ... Anwendungscode hierhin ...
1696
-
1697
- # starte den Server, wenn die Ruby-Datei direkt ausgeführt wird
1698
- run! if app_file == $0
1699
- end
1700
-
1701
- Starte mit:
1702
-
1703
- ruby mein_app.rb
1704
-
1705
- Oder über eine <tt>config.ru</tt>-Datei, die es erlaubt, einen beliebigen
1706
- Rack-Handler zu verwenden:
1707
-
1708
- # config.ru
1709
- require './mein_app'
1710
- run MeineApp
1711
-
1712
- Starte:
1713
-
1714
- rackup -p 4567
1715
-
1716
- === Eine klassische Anwendung mit einer config.ru verwenden
1717
-
1718
- Schreibe eine Anwendungsdatei:
1719
-
1720
- # app.rb
1721
- require 'sinatra'
1722
-
1723
- get '/' do
1724
- 'Hallo Welt!'
1725
- end
1726
-
1727
- sowie eine dazugehörige <tt>config.ru</tt>-Datei:
1728
-
1729
- require './app'
1730
- run Sinatra::Application
1731
-
1732
- === Wann sollte eine config.ru-Datei verwendet werden?
1733
-
1734
- Anzeichen dafür, dass eine <tt>config.ru</tt>-Datei gebraucht wird:
1735
-
1736
- * Es soll ein anderer Rack-Handler verwendet werden (Passenger, Unicorn,
1737
- Heroku, ...).
1738
- * Es gibt mehr als nur eine Subklasse von <tt>Sinatra::Base</tt>.
1739
- * Sinatra soll als Middleware verwendet werden, nicht als Endpunkt.
1740
-
1741
- <b>Es gibt keinen Grund, eine <tt>config.ru</tt>-Datei zu verwenden, nur weil
1742
- eine Anwendung im modularen Stil betrieben werden soll. Ebenso wird keine
1743
- Anwendung mit modularem Stil benötigt, um eine <tt>config.ru</tt>-Datei zu
1744
- verwenden.</b>
1745
-
1746
- === Sinatra als Middleware nutzen
1747
-
1748
- Es ist nicht nur möglich, andere Rack-Middleware mit Sinatra zu nutzen, es kann
1749
- außerdem jede Sinatra-Anwendung selbst als Middleware vor jeden beliebigen
1750
- Rack-Endpunkt gehangen werden. Bei diesem Endpunkt muss es sich nicht um eine
1751
- andere Sinatra-Anwendung handeln, es kann jede andere Rack-Anwendung sein
1752
- (Rails/Ramaze/Camping/...):
1753
-
1754
- require 'sinatra/base'
1755
-
1756
- class LoginScreen < Sinatra::Base
1757
- enable :sessions
1758
-
1759
- get('/login') { haml :login }
1760
-
1761
- post('/login') do
1762
- if params[:name] == 'admin' && params[:password] == 'admin'
1763
- session['user_name'] = params[:name]
1764
- else
1765
- redirect '/login'
1766
- end
1767
- end
1768
- end
1769
-
1770
- class MyApp < Sinatra::Base
1771
- # Middleware wird vor Filtern ausgeführt
1772
- use LoginScreen
1773
-
1774
- before do
1775
- unless session['user_name']
1776
- halt "Zugriff verweigert, bitte <a href='/login'>einloggen</a>."
1777
- end
1778
- end
1779
-
1780
- get('/') { "Hallo #{session['user_name']}." }
1781
- end
1782
-
1783
- === Dynamische Applikationserstellung
1784
-
1785
- Manche Situationen erfordern die Erstellung neuer Applikationen zur Laufzeit,
1786
- ohne dass sie einer Konstanten zugeordnet werden. Dies lässt sich mit
1787
- <tt>Sinatra.new</tt> erreichen:
1788
-
1789
- require 'sinatra/base'
1790
- my_app = Sinatra.new { get('/') { "hallo" } }
1791
- my_app.run!
1792
-
1793
- Die Applikation kann mit Hilfe eines optionalen Parameters erstellt werden:
1794
-
1795
- # config.ru
1796
- require 'sinatra/base'
1797
-
1798
- controller = Sinatra.new do
1799
- enable :logging
1800
- helpers MyHelpers
1801
- end
1802
-
1803
- map('/a') do
1804
- run Sinatra.new(controller) { get('/') { 'a' } }
1805
- end
1806
-
1807
- map('/b') do
1808
- run Sinatra.new(controller) { get('/') { 'b' } }
1809
- end
1810
-
1811
- Das ist besonders dann interessant, wenn Sinatra-Erweiterungen getestet werden
1812
- oder Sinatra in einer Bibliothek Verwendung findet.
1813
-
1814
- Ebenso lassen sich damit hervorragend Sinatra-Middlewares erstellen:
1815
-
1816
- require 'sinatra/base'
1817
-
1818
- use Sinatra do
1819
- get('/') { ... }
1820
- end
1821
-
1822
- run RailsProject::Application
1823
-
1824
- == Geltungsbereich und Bindung
1825
-
1826
- Der Geltungsbereich (Scope) legt fest, welche Methoden und Variablen zur
1827
- Verfügung stehen.
1828
-
1829
- === Anwendungs- oder Klassen-Scope
1830
-
1831
- Jede Sinatra-Anwendung entspricht einer <tt>Sinatra::Base</tt>-Subklasse. Falls
1832
- die Top- Level-DSL verwendet wird (<tt>require 'sinatra'</tt>), handelt es sich
1833
- um <tt>Sinatra::Application</tt>, andernfalls ist es jene Subklasse, die
1834
- explizit angelegt wurde. Auf Klassenebene stehen Methoden wie +get+ oder
1835
- +before+ zur Verfügung, es gibt aber keinen Zugriff auf das +request+-Object
1836
- oder die +session+, da nur eine einzige Klasse für alle eingehenden Anfragen
1837
- genutzt wird.
1838
-
1839
- Optionen, die via +set+ gesetzt werden, sind Methoden auf Klassenebene:
1840
-
1841
- class MyApp < Sinatra::Base
1842
- # Hey, ich bin im Anwendungsscope!
1843
- set :foo, 42
1844
- foo # => 42
1845
-
1846
- get '/foo' do
1847
- # Hey, ich bin nicht mehr im Anwendungs-Scope!
1848
- end
1849
- end
1850
-
1851
- Im Anwendungs-Scope befindet man sich:
1852
-
1853
- * In der Anwendungs-Klasse.
1854
- * In Methoden, die von Erweiterungen definiert werden.
1855
- * Im Block, der an +helpers+ übergeben wird.
1856
- * In Procs und Blöcken, die an +set+ übergeben werden.
1857
- * Der an <tt>Sinatra.new</tt> übergebene Block
1858
-
1859
- Auf das Scope-Objekt (die Klasse) kann wie folgt zugegriffen werden:
1860
-
1861
- * Über das Objekt, das an den +configure+-Block übergeben wird (<tt>configure
1862
- { |c| ... }</tt>).
1863
- * +settings+ aus den anderen Scopes heraus.
1864
-
1865
- === Anfrage- oder Instanz-Scope
1866
-
1867
- Für jede eingehende Anfrage wird eine neue Instanz der Anwendungs-Klasse
1868
- erstellt und alle Handler in diesem Scope ausgeführt. Aus diesem Scope
1869
- heraus kann auf +request+ oder +session+ zugegriffen und Methoden wie +erb+
1870
- oder +haml+ aufgerufen werden. Außerdem kann mit der +settings+-Method auf den
1871
- Anwendungs-Scope zugegriffen werden:
1872
-
1873
- class MyApp < Sinatra::Base
1874
- # Hey, ich bin im Anwendungs-Scope!
1875
- get '/neue_route/:name' do
1876
- # Anfrage-Scope für '/neue_route/:name'
1877
- @value = 42
1878
-
1879
- settings.get "/#{params[:name]}" do
1880
- # Anfrage-Scope für "/#{params[:name]}"
1881
- @value # => nil (nicht dieselbe Anfrage)
1882
- end
1883
-
1884
- "Route definiert!"
1885
- end
1886
- end
1887
-
1888
- Im Anfrage-Scope befindet man sich:
1889
-
1890
- * In get/head/post/put/delete-Blöcken
1891
- * In before/after-Filtern
1892
- * In Helfer-Methoden
1893
- * In Templates
1894
-
1895
- === Delegation-Scope
1896
-
1897
- Vom Delegation-Scope aus werden Methoden einfach an den Klassen-Scope
1898
- weitergeleitet. Dieser verhält sich jedoch nicht 100%ig wie der Klassen-Scope,
1899
- da man nicht die Bindung der Klasse besitzt: Nur Methoden, die explizit als
1900
- delegierbar markiert wurden, stehen hier zur Verfügung und es kann nicht auf
1901
- die Variablen des Klassenscopes zugegriffen werden (mit anderen Worten: es gibt
1902
- ein anderes +self+). Weitere Delegationen können mit
1903
- <tt>Sinatra::Delegator.delegate :methoden_name</tt> hinzugefügt werden.
1904
-
1905
- Im Delegation-Scop befindet man sich:
1906
-
1907
- * Im Top-Level, wenn <tt>require 'sinatra'</tt> aufgerufen wurde.
1908
- * In einem Objekt, das mit dem <tt>Sinatra::Delegator</tt>-Mixin erweitert
1909
- wurde.
1910
-
1911
- Schau am besten im Code nach: Hier ist
1912
- {Sinatra::Delegator mixin}[http://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1064]
1913
- definiert und wird in den
1914
- {globalen Namespace eingebunden}[http://github.com/sinatra/sinatra/blob/master/lib/sinatra/main.rb#L25].
1915
-
1916
- == Kommandozeile
1917
-
1918
- Sinatra-Anwendungen können direkt von der Kommandozeile aus gestartet werden:
1919
-
1920
- ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-h HOST] [-s HANDLER]
1921
-
1922
- Die Optionen sind:
1923
-
1924
- -h # Hilfe
1925
- -p # Port setzen (Standard ist 4567)
1926
- -h # Host setzen (Standard ist 0.0.0.0)
1927
- -e # Umgebung setzen (Standard ist development)
1928
- -s # Rack-Server/Handler setzen (Standard ist thin)
1929
- -x # Mutex-Lock einschalten (Standard ist off)
1930
-
1931
- == Systemanforderungen
1932
-
1933
- Die folgenden Versionen werden offiziell unterstützt:
1934
-
1935
- [ Ruby 1.8.7 ]
1936
- 1.8.7 wird vollständig unterstützt, aber solange nichts dagegen spricht,
1937
- wird ein Update auf 1.9.2 oder ein Umstieg auf JRuby/Rubinius empfohlen.
1938
- Unterstützung für 1.8.7 wird es mindestens bis Sinatra 2.0 und Ruby 2.0 geben,
1939
- es sei denn, dass der unwahrscheinliche Fall eintritt und 1.8.8 rauskommt.
1940
- Doch selbst dann ist es eher wahrscheinlich, dass 1.8.7 weiterhin unterstützt
1941
- wird. <b>Ruby 1.8.6 wird nicht mehr unterstützt.</b> Soll Sinatra unter 1.8.6
1942
- eingesetzt werden, muss Sinatra 1.2 verwendet werden, dass noch bis zum
1943
- Release von Sinatra 1.4.0 fortgeführt wird.
1944
-
1945
- [ Ruby 1.9.2 ]
1946
- 1.9.2 wird voll unterstützt und empfohlen. Beachte, dass Markaby und Radius
1947
- momentan noch nicht kompatibel mit 1.9 sind. Version 1.9.2p0 sollte nicht
1948
- verwendet werden, da unter Sinatra immer wieder Segfaults auftreten.
1949
- Unterstützung wird es mindestens bis zum Release von Ruby 1.9.4/2.0 geben und
1950
- das letzte Sinatra Release für 1.9 wird so lange unterstützt, wie das Ruby
1951
- Core-Team 1.9 pflegt.
1952
-
1953
- [ Ruby 1.9.3 ]
1954
- 1.9.3 wird vollständig unterstützt. Momentan wird empfohlen auf einen
1955
- höheren Pachtlevel zu warten, bevor Sinatra in der Produktion
1956
- eingesetzt wird (aktueller Patchlevel ist p0). Bei einem Wechsel zu
1957
- 1.9.3 werden alle Sessions ungültig.
1958
- Obwohl Tests bereits auf 1.9.3 laufen, sind bisher keine Applikationen auf
1959
- 1.9.3 in Produktion bekannt. Ebenso wie bei 1.9.2 besteht die gleiche Warnung
1960
- zum Patchlevel 0.
1961
-
1962
- [ Rubinius ]
1963
- Rubinius (rbx >= 1.2.4) wird offiziell unter Einbezug aller Templates
1964
- unterstützt. Die kommende 2.0 Version wird ebenfalls unterstützt.
1965
-
1966
- [ JRuby ]
1967
- JRuby wird offiziell unterstützt (JRuby >= 1.6.5). Probleme mit Template-
1968
- Bibliotheken Dritter sind nicht bekannt. Falls JRuby zum Einsatz kommt,
1969
- sollte aber darauf geachtet werden, dass ein JRuby-Rack-Handler zum Einsatz
1970
- kommt – der Thin-Web-Server wird bisher nicht unterstütz. JRubys
1971
- Unterstützung für C-Erweiterungen sind zur Zeit noch experimenteller Natur,
1972
- betrifft im Moment aber nur RDiscount, Redcarpet und RedCloth.
1973
-
1974
-
1975
- Weiterhin werden wir auf kommende Ruby-Versionen ein Auge haben.
1976
-
1977
- Die nachfolgend aufgeführten Ruby-Implementierungen werden offiziell nicht von
1978
- Sinatra unterstützt, funktionieren aber normalerweise:
1979
-
1980
- * Ruby Enterprise Edition
1981
- * Ältere Versionen von JRuby und Rubinius
1982
- * MacRuby, Maglev, IronRuby
1983
- * Ruby 1.9.0 und 1.9.1 (wird jedoch nicht empfohlen, s.o.)
1984
-
1985
- Nicht offiziell unterstützt bedeutet, dass wenn Sachen nicht funktionieren,
1986
- wir davon ausgehen, dass es nicht an Sinatra sondern an der jeweiligen
1987
- Implentierung liegt.
1988
-
1989
- Im Rahmen unserer CI (Kontinuierlichen Integration) wird bereits ruby-head
1990
- (das kommende Ruby 2.0.0) und 1.9.4 mit eingebunden. Da noch alles im Fluss ist,
1991
- kann zur Zeit für nichts garantiert werden. Es kann aber erwartet werden, dass
1992
- Ruby 2.0.0p0 und 1.9.4p0 von Sinatra unterstützt werden wird.
1993
-
1994
- Sinatra sollte auf jedem Betriebssystem laufen, dass den gewählten Ruby-
1995
- Interpreter unterstützt.
1996
-
1997
- Sinatra wird aktuell nicht unter Cardinal, SmallRuby, BleuRuby oder irgendeiner
1998
- Version von Ruby vor 1.8.7 laufen.
1999
-
2000
- == Der neuste Stand (The Bleeding Edge)
2001
-
2002
- Um auf dem neusten Stand zu bleiben, kann der Master-Branch verwendet werden.
2003
- Er sollte recht stabil sein. Ebenso gibt es von Zeit zu Zeit prerelease Gems,
2004
- die so installiert werden:
2005
-
2006
- gem install sinatra --pre
2007
-
2008
- === Mit Bundler
2009
-
2010
- Wenn die Applikation mit der neuesten Version von Sinatra und
2011
- {Bundler}[http://gembundler.com/] genutzt werden soll, empfehlen wir den
2012
- nachfolgenden Weg.
2013
-
2014
- Soweit Bundler noch nicht installiert ist:
2015
-
2016
- gem install bundler
2017
-
2018
- Anschließend wird eine +Gemfile+-Datei im Projektverzeichnis mit folgendem
2019
- Inhalt erstellt:
2020
-
2021
- source :rubygems
2022
- gem 'sinatra', :git => "git://github.com/sinatra/sinatra.git"
2023
-
2024
- # evtl. andere Abhängigkeiten
2025
- gem 'haml' # z.B. wenn du Haml verwendest...
2026
- gem 'activerecord', '~> 3.0' # ...oder ActiveRecord 3.x
2027
-
2028
- Beachte: Hier sollten alle Abhängigkeiten eingetragen werden. Sinatras eigene,
2029
- direkte Abhängigkeiten (Tilt und Rack) werden von Bundler automatisch aus dem
2030
- Gemfile von Sinatra hinzugefügt.
2031
-
2032
- Jetzt kannst du deine Applikation starten:
2033
-
2034
- bundle exec ruby myapp.rb
2035
-
2036
- === Eigenes Repository
2037
- Um auf dem neuesten Stand von Sinatras Code zu sein, kann eine lokale Kopie
2038
- angelegt werden. Gestartet wird in der Anwendung mit dem <tt>sinatra/lib</tt>-
2039
- Ordner im <tt>LOAD_PATH</tt>:
2040
-
2041
- cd myapp
2042
- git clone git://github.com/sinatra/sinatra.git
2043
- ruby -Isinatra/lib myapp.rb
2044
-
2045
- Alternativ kann der <tt>sinatra/lib</tt>-Ordner zum <tt>LOAD_PATH</tt> in
2046
- der Anwendung hinzugefügt werden:
2047
-
2048
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
2049
- require 'rubygems'
2050
- require 'sinatra'
2051
-
2052
- get '/ueber' do
2053
- "Ich laufe auf Version " + Sinatra::VERSION
2054
- end
2055
-
2056
- Um Sinatra-Code von Zeit zu Zeit zu aktualisieren:
2057
-
2058
- cd myproject/sinatra
2059
- git pull
2060
-
2061
- === Gem erstellen
2062
-
2063
- Aus der eigenen lokalen Kopie kann nun auch ein globales Gem gebaut werden:
2064
-
2065
- git clone git://github.com/sinatra/sinatra.git
2066
- cd sinatra
2067
- rake sinatra.gemspec
2068
- rake install
2069
-
2070
- Falls Gems als Root installiert werden sollen, sollte die letzte Zeile
2071
- folgendermaßen lauten:
2072
-
2073
- sudo rake install
2074
-
2075
- == Versions-Verfahren
2076
-
2077
- Sinatra folgt dem sogenannten {Semantic Versioning}[http://semver.org/], d.h.
2078
- SemVer und SemVerTag.
2079
-
2080
- == Mehr
2081
-
2082
- * {Projekt-Website}[http://sinatra.github.com/] - Ergänzende Dokumentation,
2083
- News und Links zu anderen Ressourcen.
2084
- * {Mitmachen}[http://sinatra.github.com/contributing.html] - Einen
2085
- Fehler gefunden? Brauchst du Hilfe? Hast du einen Patch?
2086
- * {Issue-Tracker}[http://github.com/sinatra/sinatra/issues]
2087
- * {Twitter}[http://twitter.com/sinatra]
2088
- * {Mailing-Liste}[http://groups.google.com/group/sinatrarb]
2089
- * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] auf http://freenode.net
2090
- * {Sinatra Book}[http://sinatra-book.gittr.com] Kochbuch Tutorial
2091
- * {Sinatra Recipes}[http://recipes.sinatrarb.com/] Sinatra-Rezepte aus
2092
- der Community
2093
- * API Dokumentation für die {aktuelle Version}[http://rubydoc.info/gems/sinatra]
2094
- oder für {HEAD}[http://rubydoc.info/github/sinatra/sinatra] auf
2095
- http://rubydoc.info
2096
- * {CI Server}[http://ci.rkh.im/view/Sinatra/]
2097
-