sinatra 3.0.6 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '08567da318760f376b1c6c8ccafd4e1268ff19a800c90939d9f1448a7c85edcb'
4
- data.tar.gz: 4287d74952e33c257cd981ed731e732cd0811dbeaeeb7fa553817ef3ad44a9d8
3
+ metadata.gz: 71d0bb379c736d6c251ceb424cac84dbe3a8b22d80a54473a0af1085b93b7dbf
4
+ data.tar.gz: 489d48a5e4f934127e04cdafa2d0d582c5143cc2a8f476239ea5b5b0f0e492c9
5
5
  SHA512:
6
- metadata.gz: af4979f21e7a5bc8e2aebadc68138ad5885829d5c25060303c526fec354552d178d39ae050f5a49700da4bc4b4653264e5371c6dfda44df585a7f198353f65dc
7
- data.tar.gz: 3cd222fd4e5a5337cc63a6df8d813ec695cb2e4ea73294048de169e92c93dcee36a6d90f2bbb0a3525f3d27b86c3499f762f1c0b8904e79c7a012a9852095aeb
6
+ metadata.gz: fbe92c1867d3ebe8ddc3f707c4e9f9cf2b68bddf2556164b85083ac635650725d63f8c847b4c70d0ad2abf6793b5f1054918b0b7c4e04d303119867be84c3253
7
+ data.tar.gz: 0727d88e9f5574c304dd3f31c6107a2b3e1cde96914e258c86fee529a1e922b0ff1d023f109fcc3b232f010ae21d9bdb4c365001dc7c3f658c0bd75b95e8d24d
data/AUTHORS.md CHANGED
@@ -2,31 +2,37 @@ Sinatra was designed and developed by Blake Mizerany in California.
2
2
 
3
3
  ### Current Team
4
4
 
5
- * **Konstantin Haase** (maintainer)
5
+ * **Eloy Perez**
6
+ * **Jordan Owens**
7
+ * **Olle Jonsson**
8
+ * **Patrik Ragnarsson**
6
9
  * **Zachary Scott**
7
- * **Kashyap Kondamudi**
8
- * **Ashley Williams**
9
- * **Trevor Bramble**
10
- * **Kunpei Sakai**
11
10
 
12
11
  ### Alumni
13
12
 
14
13
  * **Blake Mizerany** (creator)
14
+ * **Konstantin Haase** (maintainer)
15
15
  * **Ryan Tomayko**
16
16
  * **Simon Rozet**
17
17
  * **Katrina Owen**
18
+ * **Kashyap Kondamudi**
19
+ * **Ashley Williams**
20
+ * **Trevor Bramble**
21
+ * **Kunpei Sakai**
18
22
 
19
23
  ### Thanks
20
24
 
21
25
  Sinatra would not have been possible without strong company backing.
22
26
  In the past, financial and emotional support have been provided mainly by
23
- [Heroku](http://heroku.com), [GitHub](https://github.com) and
24
- [Engine Yard](http://www.engineyard.com/), and is now taken care of by
25
- [Travis CI](http://travis-ci.com/).
27
+ [Heroku](https://heroku.com), [GitHub](https://github.com),
28
+ [Engine Yard](http://www.engineyard.com/) and [Travis CI](https://travis-ci.com/),
29
+ and is now taken care of by [84codes](https://www.84codes.com/).
26
30
 
27
31
  Special thanks to the following extraordinary individuals, without whom
28
32
  Sinatra would not be possible:
29
33
 
34
+ * [Benoit Daloze](https://eregon.me/blog/) (eregon) for help around TruffleRuby
35
+ and keyword arguments use in mustermann.
30
36
  * [Ryan Tomayko](http://tomayko.com/) (rtomayko) for constantly fixing
31
37
  whitespace errors __60d5006__
32
38
  * [Ezra Zygmuntowicz](http://brainspl.at/) (ezmobius) for initial help and
data/CHANGELOG.md CHANGED
@@ -1,6 +1,71 @@
1
- ## Unreleased
1
+ ## 4.0.0. / 2024-01-19
2
2
 
3
- * _Your new feature here._
3
+ * New: Add support for Rack 3 ([#1857])
4
+ * Note: you may want to read the [Rack 3 Upgrade Guide]
5
+
6
+ * Require Ruby 2.7.8 as minimum Ruby version ([#1993])
7
+
8
+ * Breaking change: Drop support for Rack 2 ([#1857])
9
+ * Note: when using Sinatra to start the web server, you now need the `rackup` gem installed
10
+
11
+ * Breaking change: Remove the `IndifferentHash` initializer ([#1982])
12
+
13
+ * Breaking change: Disable `session_hijacking` protection by default ([#1984])
14
+
15
+ * Breaking change: Remove `Rack::Protection::EncryptedCookie` ([#1989])
16
+ * Note: cookies are still encrypted (by [`Rack::Session::Cookie`])
17
+
18
+ [#1857]: https://github.com/sinatra/sinatra/pull/1857
19
+ [#1993]: https://github.com/sinatra/sinatra/pull/1993
20
+ [#1982]: https://github.com/sinatra/sinatra/pull/1982
21
+ [#1984]: https://github.com/sinatra/sinatra/pull/1984
22
+ [#1989]: https://github.com/sinatra/sinatra/pull/1989
23
+ [`Rack::Session::Cookie`]: https://github.com/rack/rack-session
24
+ [Rack 3 Upgrade Guide]: https://github.com/rack/rack/blob/main/UPGRADE-GUIDE.md
25
+
26
+ ## 3.2.0 / 2023-12-29
27
+
28
+ * New: Add `#except` method to `Sinatra::IndifferentHash` ([#1940])
29
+
30
+ * New: Use `Exception#detailed_message` to show backtrace ([#1952])
31
+
32
+ * New: Add `Sinatra::HamlHelpers` to sinatra-contrib ([#1960])
33
+
34
+ * Fix: Add `base64` to rack-protection runtime dependencies ([#1946])
35
+
36
+ * Fix: Avoid open-ended dependencies for sinatra-contrib and rack-protection ([#1949])
37
+
38
+ * Fix: Helpful message when `Sinatra::Runner` times out ([#1975])
39
+
40
+ * Fix: Ruby 3.3 + Bundler 2.5 compatibility ([#1975])
41
+
42
+ [#1940]: https://github.com/sinatra/sinatra/pull/1940
43
+ [#1946]: https://github.com/sinatra/sinatra/pull/1946
44
+ [#1949]: https://github.com/sinatra/sinatra/pull/1949
45
+ [#1952]: https://github.com/sinatra/sinatra/pull/1952
46
+ [#1960]: https://github.com/sinatra/sinatra/pull/1960
47
+ [#1975]: https://github.com/sinatra/sinatra/pull/1975
48
+
49
+ ## 3.1.0 / 2023-08-07
50
+
51
+ * New: Add sass support via sass-embedded [#1911] by なつき
52
+
53
+ * New: Add start and stop callbacks [#1913] by Jevin Sew
54
+
55
+ * New: Warn on dropping sessions [#1900] by Jonathan del Strother
56
+
57
+ * New: Make Puma the default server [#1924] by Patrik Ragnarsson
58
+
59
+ * Fix: Remove use of Tilt::Cache [#1922] by Jeremy Evans (allows use of Tilt 2.2.0 without deprecation warning)
60
+
61
+ * Fix: rack-protection: specify rack version requirement [#1932] by Patrik Ragnarsson
62
+
63
+ [#1911]: https://github.com/sinatra/sinatra/pull/1911
64
+ [#1913]: https://github.com/sinatra/sinatra/pull/1913
65
+ [#1900]: https://github.com/sinatra/sinatra/pull/1900
66
+ [#1924]: https://github.com/sinatra/sinatra/pull/1924
67
+ [#1922]: https://github.com/sinatra/sinatra/pull/1922
68
+ [#1932]: https://github.com/sinatra/sinatra/pull/1932
4
69
 
5
70
  ## 3.0.6 / 2023-04-11
6
71
 
data/Gemfile CHANGED
@@ -1,13 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Why use bundler?
4
- # Well, not all development dependencies install on all rubies. Moreover, `gem
5
- # install sinatra --development` doesn't work, as it will also try to install
6
- # development dependencies of our dependencies, and those are not conflict free.
7
- # So, here we are, `bundle install`.
8
- #
9
- # If you have issues with a gem: `bundle install --without-coffee-script`.
10
-
11
3
  source 'https://rubygems.org'
12
4
  gemspec
13
5
 
@@ -18,23 +10,29 @@ rack_version = nil if rack_version.empty? || (rack_version == 'stable')
18
10
  rack_version = { github: 'rack/rack' } if rack_version == 'head'
19
11
  gem 'rack', rack_version
20
12
 
13
+ rack_session_version = ENV['rack_session'].to_s
14
+ rack_session_version = nil if rack_session_version.empty? || (rack_session_version == 'stable')
15
+ rack_session_version = { github: 'rack/rack-session' } if rack_session_version == 'head'
16
+ gem 'rack-session', rack_session_version
17
+
18
+ gem 'rackup'
19
+
21
20
  puma_version = ENV['puma'].to_s
22
21
  puma_version = nil if puma_version.empty? || (puma_version == 'stable')
23
22
  puma_version = { github: 'puma/puma' } if puma_version == 'head'
24
23
  gem 'puma', puma_version
25
24
 
26
25
  gem 'minitest', '~> 5.0'
27
- gem 'rack-test', github: 'rack/rack-test'
26
+ gem 'rack-test'
28
27
  gem 'rubocop', '~> 1.32.0', require: false
29
- gem 'yard'
28
+ gem 'yard' # used by rake doc
30
29
 
31
30
  gem 'rack-protection', path: 'rack-protection'
32
31
  gem 'sinatra-contrib', path: 'sinatra-contrib'
33
32
 
34
- gem 'activesupport', '~> 6.1'
35
-
36
33
  gem 'asciidoctor'
37
34
  gem 'builder'
35
+ gem 'childprocess', '>= 5'
38
36
  gem 'commonmarker', '~> 0.23.4', platforms: [:ruby]
39
37
  gem 'erubi'
40
38
  gem 'eventmachine'
@@ -46,14 +44,18 @@ gem 'markaby'
46
44
  gem 'nokogiri', '> 1.5.0'
47
45
  gem 'pandoc-ruby', '~> 2.0.2'
48
46
  gem 'rabl'
49
- gem 'rainbows', platforms: [:mri] # uses #fork
50
47
  gem 'rdiscount', platforms: [:ruby]
51
48
  gem 'rdoc'
52
49
  gem 'redcarpet', platforms: [:ruby]
53
50
  gem 'simplecov', require: false
54
51
  gem 'slim', '~> 4'
55
52
  gem 'yajl-ruby', platforms: [:ruby]
56
-
57
- gem 'json', platforms: %i[jruby mri]
58
-
59
- gem 'jar-dependencies', '= 0.4.1', platforms: [:jruby] # Gem::LoadError with jar-dependencies 0.4.2
53
+ gem 'zeitwerk'
54
+
55
+ # sass-embedded depends on google-protobuf
56
+ # which fails to be installed on JRuby and TruffleRuby under aarch64
57
+ # https://github.com/jruby/jruby/issues/8062
58
+ # https://github.com/protocolbuffers/protobuf/issues/11935
59
+ java = %w(jruby truffleruby).include?(RUBY_ENGINE)
60
+ aarch64 = RbConfig::CONFIG["target_cpu"] == 'aarch64'
61
+ gem 'sass-embedded', '~> 1.54' unless java && aarch64
data/README.md CHANGED
@@ -54,6 +54,8 @@ pick up if available.
54
54
  - [Erb Templates](#erb-templates)
55
55
  - [Builder Templates](#builder-templates)
56
56
  - [Nokogiri Templates](#nokogiri-templates)
57
+ - [Sass Templates](#sass-templates)
58
+ - [Scss Templates](#scss-templates)
57
59
  - [Liquid Templates](#liquid-templates)
58
60
  - [Markdown Templates](#markdown-templates)
59
61
  - [RDoc Templates](#rdoc-templates)
@@ -93,6 +95,7 @@ pick up if available.
93
95
  - [Configuration](#configuration)
94
96
  - [Configuring attack protection](#configuring-attack-protection)
95
97
  - [Available Settings](#available-settings)
98
+ - [Lifecycle Events](#lifecycle-events)
96
99
  - [Environments](#environments)
97
100
  - [Error Handling](#error-handling)
98
101
  - [Not Found](#not-found)
@@ -649,6 +652,39 @@ It also takes a block for inline templates (see [example](#inline-templates)).
649
652
 
650
653
  It also takes a block for inline templates (see [example](#inline-templates)).
651
654
 
655
+ #### Sass Templates
656
+
657
+ <table>
658
+ <tr>
659
+ <td>Dependency</td>
660
+ <td><a href="https://github.com/ntkme/sass-embedded-host-ruby" title="sass-embedded">sass-embedded</a></td>
661
+ </tr>
662
+ <tr>
663
+ <td>File Extension</td>
664
+ <td><tt>.sass</tt></td>
665
+ </tr>
666
+ <tr>
667
+ <td>Example</td>
668
+ <td><tt>sass :stylesheet, :style => :expanded</tt></td>
669
+ </tr>
670
+ </table>
671
+
672
+ #### Scss Templates
673
+
674
+ <table>
675
+ <tr>
676
+ <td>Dependency</td>
677
+ <td><a href="https://github.com/ntkme/sass-embedded-host-ruby" title="sass-embedded">sass-embedded</a></td>
678
+ </tr>
679
+ <tr>
680
+ <td>File Extension</td>
681
+ <td><tt>.scss</tt></td>
682
+ </tr>
683
+ <tr>
684
+ <td>Example</td>
685
+ <td><tt>scss :stylesheet, :style => :expanded</tt></td>
686
+ </tr>
687
+ </table>
652
688
 
653
689
  #### Liquid Templates
654
690
 
@@ -810,7 +846,7 @@ It also takes a block for inline templates (see [example](#inline-templates)).
810
846
  <table>
811
847
  <tr>
812
848
  <td>Dependency</td>
813
- <td><a href="http://slim-lang.com/" title="Slim Lang">Slim Lang</a></td>
849
+ <td><a href="https://slim-template.github.io/" title="Slim Lang">Slim Lang</a></td>
814
850
  </tr>
815
851
  <tr>
816
852
  <td>File Extension</td>
@@ -1163,22 +1199,6 @@ $ ruby -e "require 'securerandom'; puts SecureRandom.hex(64)"
1163
1199
  99ae8af...snip...ec0f262ac
1164
1200
  ```
1165
1201
 
1166
- **Session Secret Generation (Bonus Points)**
1167
-
1168
- Use the [sysrandom gem](https://github.com/cryptosphere/sysrandom#readme) to
1169
- use the system RNG facilities to generate random values instead of
1170
- userspace `OpenSSL` which MRI Ruby currently defaults to:
1171
-
1172
- ```text
1173
- $ gem install sysrandom
1174
- Building native extensions. This could take a while...
1175
- Successfully installed sysrandom-1.x
1176
- 1 gem installed
1177
-
1178
- $ ruby -e "require 'sysrandom/securerandom'; puts SecureRandom.hex(64)"
1179
- 99ae8af...snip...ec0f262ac
1180
- ```
1181
-
1182
1202
  **Session Secret Environment Variable**
1183
1203
 
1184
1204
  Set a `SESSION_SECRET` environment variable for Sinatra to the value you
@@ -1193,14 +1213,10 @@ purposes only:
1193
1213
  **Session Secret App Config**
1194
1214
 
1195
1215
  Set up your app config to fail-safe to a secure random secret
1196
- if the `SESSION_SECRET` environment variable is not available.
1197
-
1198
- For bonus points use the [sysrandom
1199
- gem](https://github.com/cryptosphere/sysrandom#readme) here as well:
1216
+ if the `SESSION_SECRET` environment variable is not available:
1200
1217
 
1201
1218
  ```ruby
1202
1219
  require 'securerandom'
1203
- # -or- require 'sysrandom/securerandom'
1204
1220
  set :session_secret, ENV.fetch('SESSION_SECRET') { SecureRandom.hex(64) }
1205
1221
  ```
1206
1222
 
@@ -1405,53 +1421,9 @@ to `stream` finishes executing. Streaming does not work at all with Shotgun.
1405
1421
 
1406
1422
  If the optional parameter is set to `keep_open`, it will not call `close` on
1407
1423
  the stream object, allowing you to close it at any later point in the
1408
- execution flow. This only works on evented servers, like Rainbows.
1409
- Other servers will still close the stream:
1410
-
1411
- ```ruby
1412
- # config.ru
1413
- require 'sinatra/base'
1414
-
1415
- class App < Sinatra::Base
1416
- connections = []
1424
+ execution flow.
1417
1425
 
1418
- get '/subscribe', provides: 'text/event-stream' do
1419
- # register a client's interest in server events
1420
- stream(:keep_open) do |out|
1421
- connections << out
1422
- # purge dead connections
1423
- connections.reject!(&:closed?)
1424
- end
1425
- end
1426
-
1427
- post '/' do
1428
- connections.each do |out|
1429
- # notify client that a new message has arrived
1430
- out << "data: #{params[:msg]}\n\n"
1431
-
1432
- # indicate client to connect again
1433
- out.close
1434
- end
1435
-
1436
- 204 # response without entity body
1437
- end
1438
- end
1439
-
1440
- run App
1441
- ```
1442
-
1443
- ```ruby
1444
- # rainbows.conf
1445
- Rainbows! do
1446
- use :EventMachine
1447
- end
1448
- ````
1449
-
1450
- Run:
1451
-
1452
- ```shell
1453
- rainbows -c rainbows.conf
1454
- ```
1426
+ You can have a look at the [chat example](https://github.com/sinatra/sinatra/blob/main/examples/chat.rb)
1455
1427
 
1456
1428
  It's also possible for the client to close the connection when trying to
1457
1429
  write to the socket. Because of this, it's recommended to check
@@ -1950,7 +1922,7 @@ set :protection, :except => :path_traversal
1950
1922
  You can also hand in an array in order to disable a list of protections:
1951
1923
 
1952
1924
  ```ruby
1953
- set :protection, :except => [:path_traversal, :session_hijacking]
1925
+ set :protection, :except => [:path_traversal, :remote_token]
1954
1926
  ```
1955
1927
 
1956
1928
  By default, Sinatra will only set up session based protection if `:sessions`
@@ -2089,9 +2061,13 @@ set :protection, :session => true
2089
2061
 
2090
2062
  <dt>raise_errors</dt>
2091
2063
  <dd>
2092
- Raise exceptions (will stop application). Enabled by default when
2064
+ Raise unhandled errors (will stop application). Enabled by default when
2093
2065
  <tt>environment</tt> is set to <tt>"test"</tt>, disabled otherwise.
2094
2066
  </dd>
2067
+ <dd>
2068
+ Any explicitly defined error handlers always override this setting. See
2069
+ the "Error" section below.
2070
+ </dd>
2095
2071
 
2096
2072
  <dt>run</dt>
2097
2073
  <dd>
@@ -2184,6 +2160,24 @@ set :protection, :session => true
2184
2160
  </dd>
2185
2161
  </dl>
2186
2162
 
2163
+ ## Lifecycle Events
2164
+
2165
+ There are 2 lifecycle events currently exposed by Sinatra. One when the server starts and one when it stops.
2166
+
2167
+ They can be used like this:
2168
+
2169
+ ```ruby
2170
+ on_start do
2171
+ puts "===== Booting up ====="
2172
+ end
2173
+
2174
+ on_stop do
2175
+ puts "===== Shutting down ====="
2176
+ end
2177
+ ```
2178
+
2179
+ Note that these callbacks only work when using Sinatra to start the web server.
2180
+
2187
2181
  ## Environments
2188
2182
 
2189
2183
  There are three predefined `environments`: `"development"`,
@@ -2240,6 +2234,14 @@ show exceptions option to `:after_handler`:
2240
2234
  set :show_exceptions, :after_handler
2241
2235
  ```
2242
2236
 
2237
+ A catch-all error handler can be defined with `error` and a block:
2238
+
2239
+ ```ruby
2240
+ error do
2241
+ 'Sorry there was a nasty error'
2242
+ end
2243
+ ```
2244
+
2243
2245
  The exception object can be obtained from the `sinatra.error` Rack variable:
2244
2246
 
2245
2247
  ```ruby
@@ -2248,7 +2250,7 @@ error do
2248
2250
  end
2249
2251
  ```
2250
2252
 
2251
- Custom errors:
2253
+ Pass an error class as an argument to create handlers for custom errors:
2252
2254
 
2253
2255
  ```ruby
2254
2256
  error MyCustomError do
@@ -2294,6 +2296,51 @@ Sinatra installs special `not_found` and `error` handlers when
2294
2296
  running under the development environment to display nice stack traces
2295
2297
  and additional debugging information in your browser.
2296
2298
 
2299
+ ### Behavior with `raise_errors` option
2300
+
2301
+ When `raise_errors` option is `true`, errors that are unhandled are raised
2302
+ outside of the application. Additionally, any errors that would have been
2303
+ caught by the catch-all error handler are raised.
2304
+
2305
+ For example, consider the following configuration:
2306
+
2307
+ ```ruby
2308
+ # First handler
2309
+ error MyCustomError do
2310
+ 'A custom message'
2311
+ end
2312
+
2313
+ # Second handler
2314
+ error do
2315
+ 'A catch-all message'
2316
+ end
2317
+ ```
2318
+
2319
+ If `raise_errors` is `false`:
2320
+
2321
+ * When `MyCustomError` or descendant is raised, the first handler is invoked.
2322
+ The HTTP response body will contain `"A custom message"`.
2323
+ * When any other error is raised, the second handler is invoked. The HTTP
2324
+ response body will contain `"A catch-all message"`.
2325
+
2326
+ If `raise_errors` is `true`:
2327
+
2328
+ * When `MyCustomError` or descendant is raised, the behavior is identical to
2329
+ when `raise_errors` is `false`, described above.
2330
+ * When any other error is raised, the second handler is *not* invoked, and
2331
+ the error is raised outside of the application.
2332
+ * If the environment is `production`, the HTTP response body will contain
2333
+ a generic error message, e.g. `"An unhandled lowlevel error occurred. The
2334
+ application logs may have details."`
2335
+ * If the environment is not `production`, the HTTP response body will contain
2336
+ the verbose error backtrace.
2337
+ * Regardless of environment, if `show_exceptions` is set to `:after_handler`,
2338
+ the HTTP response body will contain the verbose error backtrace.
2339
+
2340
+ In the `test` environment, `raise_errors` is set to `true` by default. This
2341
+ means that in order to write a test for a catch-all error handler,
2342
+ `raise_errors` must temporarily be set to `false` for that particular test.
2343
+
2297
2344
  ## Rack Middleware
2298
2345
 
2299
2346
  Sinatra rides on [Rack](https://rack.github.io/), a minimal standard
@@ -2767,68 +2814,30 @@ by Konstantin_
2767
2814
  Sinatra doesn't impose any concurrency model but leaves that to the
2768
2815
  underlying Rack handler (server) like Puma or WEBrick. Sinatra
2769
2816
  itself is thread-safe, so there won't be any problem if the Rack handler
2770
- uses a threaded model of concurrency. This would mean that when starting
2771
- the server, you'd have to specify the correct invocation method for the
2772
- specific Rack handler. The following example is a demonstration of how
2773
- to start a multi-threaded Rainbows server:
2774
-
2775
- ```ruby
2776
- # config.ru
2777
-
2778
- require 'sinatra/base'
2779
-
2780
- class App < Sinatra::Base
2781
- get '/' do
2782
- "Hello, World"
2783
- end
2784
- end
2785
-
2786
- run App
2787
- ```
2788
-
2789
- ```ruby
2790
- # rainbows.conf
2791
-
2792
- # Rainbows configurator is based on Unicorn.
2793
- Rainbows! do
2794
- use :ThreadSpawn
2795
- end
2796
- ```
2797
-
2798
- To start the server, the command would be:
2799
-
2800
- ```shell
2801
- rainbows -c rainbows.conf
2802
- ```
2817
+ uses a threaded model of concurrency.
2803
2818
 
2804
2819
  ## Requirement
2805
2820
 
2806
2821
  The following Ruby versions are officially supported:
2807
2822
  <dl>
2808
- <dt>Ruby 2.6</dt>
2823
+ <dt>Ruby</dt>
2809
2824
  <dd>
2810
- 2.6 is fully supported and recommended. There are currently no plans to
2811
- drop official support for it.
2825
+ <a href="https://www.ruby-lang.org/en/downloads/">The stable releases</a> are fully supported and recommended.
2812
2826
  </dd>
2813
2827
 
2814
- <dt>Rubinius</dt>
2828
+ <dt>TruffleRuby</dt>
2815
2829
  <dd>
2816
- Rubinius is officially supported (Rubinius >= 2.x). It is recommended to
2817
- <tt>gem install puma</tt>.
2830
+ The latest stable release of TruffleRuby is supported.
2818
2831
  </dd>
2819
2832
 
2820
2833
  <dt>JRuby</dt>
2821
2834
  <dd>
2822
- The latest stable release of JRuby is officially supported. It is not
2823
- recommended to use C extensions with JRuby. It is recommended to
2824
- <tt>gem install trinidad</tt>.
2835
+ The latest stable release of JRuby is supported. It is not
2836
+ recommended to use C extensions with JRuby.
2825
2837
  </dd>
2826
2838
  </dl>
2827
2839
 
2828
- Versions of Ruby before 2.6 are no longer supported as of Sinatra 3.0.0.
2829
-
2830
- We also keep an eye on upcoming Ruby versions. Expect upcoming
2831
- 3.x releases to be fully supported.
2840
+ Versions of Ruby before 2.7.8 are no longer supported as of Sinatra 4.0.0.
2832
2841
 
2833
2842
  Sinatra should work on any operating system supported by the chosen Ruby
2834
2843
  implementation.
data/Rakefile CHANGED
@@ -191,7 +191,7 @@ if defined?(Gem)
191
191
  end
192
192
  end
193
193
 
194
- desc 'Commits the version to github repository'
194
+ desc 'Commits the version to git (no push)'
195
195
  task :commit_version do
196
196
  %w[
197
197
  lib/sinatra
@@ -203,10 +203,22 @@ if defined?(Gem)
203
203
  end
204
204
 
205
205
  sh <<-SH
206
- git commit --allow-empty -a -m '#{source_version} release' &&
207
- git tag -s v#{source_version} -m '#{source_version} release' &&
208
- git push && (git push origin || true) &&
209
- git push --tags && (git push origin --tags || true)
206
+ git commit --allow-empty --all --message '#{source_version} release'
207
+ SH
208
+ end
209
+
210
+ desc 'Tags the version in git (no push)'
211
+ task :tag_version do
212
+ sh <<-SH
213
+ git tag --sign v#{source_version} --message '#{source_version} release'
214
+ SH
215
+ end
216
+
217
+ desc 'Watch the release workflow run'
218
+ task :watch do
219
+ sh <<-SH
220
+ runId=$(gh run list --workflow=release.yml --limit 1 --json databaseId --jq '.[].databaseId')
221
+ gh run watch --interval 1 --exit-status $runId
210
222
  SH
211
223
  end
212
224
 
data/SECURITY.md CHANGED
@@ -6,7 +6,7 @@ After the initial reply to your report the security team will endeavor to keep y
6
6
 
7
7
  If you have not received a reply to your email within 48 hours, or have not heard from the security team for the past five days there are a few steps you can take:
8
8
 
9
- * Contact the current security coordinator [Zachary Scott](mailto:zzak@ruby-lang.org) directly
9
+ * Reach out to us on [discord](https://discord.gg/ncjsfsNHh7)
10
10
 
11
11
  ## Disclosure Policy
12
12
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.6
1
+ 4.0.0
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby -I ../lib -I lib
2
+ # frozen_string_literal: true
3
+
4
+ require 'sinatra'
5
+
6
+ get('/') do
7
+ 'This shows how lifecycle events work'
8
+ end
9
+
10
+ on_start do
11
+ puts "=============="
12
+ puts " Booting up"
13
+ puts "=============="
14
+ end
15
+
16
+ on_stop do
17
+ puts "================="
18
+ puts " Shutting down"
19
+ puts "================="
20
+ end
data/examples/stream.ru CHANGED
@@ -4,10 +4,8 @@
4
4
  #
5
5
  # run *one* of these:
6
6
  #
7
- # rackup -s mongrel stream.ru # gem install mongrel
8
7
  # unicorn stream.ru # gem install unicorn
9
8
  # puma stream.ru # gem install puma
10
- # rainbows -c rainbows.conf stream.ru # gem install rainbows eventmachine
11
9
 
12
10
  require 'sinatra/base'
13
11
 
data/lib/sinatra/base.rb CHANGED
@@ -2,8 +2,13 @@
2
2
 
3
3
  # external dependencies
4
4
  require 'rack'
5
+ begin
6
+ require 'rackup'
7
+ rescue LoadError
8
+ end
5
9
  require 'tilt'
6
10
  require 'rack/protection'
11
+ require 'rack/session'
7
12
  require 'mustermann'
8
13
  require 'mustermann/sinatra'
9
14
  require 'mustermann/regular'
@@ -176,8 +181,8 @@ module Sinatra
176
181
  result = body
177
182
 
178
183
  if drop_content_info?
179
- headers.delete 'Content-Length'
180
- headers.delete 'Content-Type'
184
+ headers.delete 'content-length'
185
+ headers.delete 'content-type'
181
186
  end
182
187
 
183
188
  if drop_body?
@@ -186,9 +191,9 @@ module Sinatra
186
191
  end
187
192
 
188
193
  if calculate_content_length?
189
- # if some other code has already set Content-Length, don't muck with it
194
+ # if some other code has already set content-length, don't muck with it
190
195
  # currently, this would be the static file-handler
191
- headers['Content-Length'] = body.map(&:bytesize).reduce(0, :+).to_s
196
+ headers['content-length'] = body.map(&:bytesize).reduce(0, :+).to_s
192
197
  end
193
198
 
194
199
  [status, headers, result]
@@ -197,7 +202,7 @@ module Sinatra
197
202
  private
198
203
 
199
204
  def calculate_content_length?
200
- headers['Content-Type'] && !headers['Content-Length'] && (Array === body)
205
+ headers['content-type'] && !headers['content-length'] && (Array === body)
201
206
  end
202
207
 
203
208
  def drop_content_info?
@@ -209,7 +214,7 @@ module Sinatra
209
214
  end
210
215
  end
211
216
 
212
- # Some Rack handlers (Rainbows!) implement an extended body object protocol, however,
217
+ # Some Rack handlers implement an extended body object protocol, however,
213
218
  # some middleware (namely Rack::Lint) will break it by not mirroring the methods in question.
214
219
  # This middleware will detect an extended body object and will make sure it reaches the
215
220
  # handler directly. We do this here, so our middleware and middleware set up by the app will
@@ -289,10 +294,8 @@ module Sinatra
289
294
  def block.each; yield(call) end
290
295
  response.body = block
291
296
  elsif value
292
- # Rack 2.0 returns a Rack::File::Iterator here instead of
293
- # Rack::File as it was in the previous API.
294
297
  unless request.head? || value.is_a?(Rack::Files::Iterator) || value.is_a?(Stream)
295
- headers.delete 'Content-Length'
298
+ headers.delete 'content-length'
296
299
  end
297
300
  response.body = value
298
301
  else
@@ -302,7 +305,10 @@ module Sinatra
302
305
 
303
306
  # Halt processing and redirect to the URI provided.
304
307
  def redirect(uri, *args)
305
- if (env['HTTP_VERSION'] == 'HTTP/1.1') && (env['REQUEST_METHOD'] != 'GET')
308
+ # SERVER_PROTOCOL is required in Rack 3, fall back to HTTP_VERSION
309
+ # for servers not updated for Rack 3 (like Puma 5)
310
+ http_version = env['SERVER_PROTOCOL'] || env['HTTP_VERSION']
311
+ if (http_version == 'HTTP/1.1') && (env['REQUEST_METHOD'] != 'GET')
306
312
  status 303
307
313
  else
308
314
  status 302
@@ -372,10 +378,10 @@ module Sinatra
372
378
  Base.mime_type(type)
373
379
  end
374
380
 
375
- # Set the Content-Type of the response body given a media type or file
381
+ # Set the content-type of the response body given a media type or file
376
382
  # extension.
377
383
  def content_type(type = nil, params = {})
378
- return response['Content-Type'] unless type
384
+ return response['content-type'] unless type
379
385
 
380
386
  default = params.delete :default
381
387
  mime_type = mime_type(type) || default
@@ -393,7 +399,7 @@ module Sinatra
393
399
  "#{key}=#{val}"
394
400
  end.join(', ')
395
401
  end
396
- response['Content-Type'] = mime_type
402
+ response['content-type'] = mime_type
397
403
  end
398
404
 
399
405
  # https://html.spec.whatwg.org/#multipart-form-data
@@ -412,12 +418,12 @@ module Sinatra
412
418
  params = format('; filename="%s"', File.basename(filename).gsub(/["\r\n]/, MULTIPART_FORM_DATA_REPLACEMENT_TABLE))
413
419
  response['Content-Disposition'] << params
414
420
  ext = File.extname(filename)
415
- content_type(ext) unless response['Content-Type'] || ext.empty?
421
+ content_type(ext) unless response['content-type'] || ext.empty?
416
422
  end
417
423
 
418
424
  # Use the contents of the file at +path+ as the response body.
419
425
  def send_file(path, opts = {})
420
- if opts[:type] || !response['Content-Type']
426
+ if opts[:type] || !response['content-type']
421
427
  content_type opts[:type] || File.extname(path), default: 'application/octet-stream'
422
428
  end
423
429
 
@@ -433,7 +439,7 @@ module Sinatra
433
439
  result = file.serving(request, path)
434
440
 
435
441
  result[1].each { |k, v| headers[k] ||= v }
436
- headers['Content-Length'] = result[1]['Content-Length']
442
+ headers['content-length'] = result[1]['content-length']
437
443
  opts[:status] &&= Integer(opts[:status])
438
444
  halt (opts[:status] || result[0]), result[2]
439
445
  rescue Errno::ENOENT
@@ -502,8 +508,7 @@ module Sinatra
502
508
  # the response body have not yet been generated.
503
509
  #
504
510
  # The close parameter specifies whether Stream#close should be called
505
- # after the block has been executed. This is only relevant for evented
506
- # servers like Rainbows.
511
+ # after the block has been executed.
507
512
  def stream(keep_open = false)
508
513
  scheduler = env['async.callback'] ? EventMachine : Stream
509
514
  current = @params.dup
@@ -726,7 +731,7 @@ module Sinatra
726
731
  # Possible options are:
727
732
  # :content_type The content type to use, same arguments as content_type.
728
733
  # :layout If set to something falsy, no layout is rendered, otherwise
729
- # the specified layout is used
734
+ # the specified layout is used (Ignored for `sass`)
730
735
  # :layout_engine Engine to use for rendering the layout.
731
736
  # :locals A hash with local variables that should be available
732
737
  # in the template
@@ -752,6 +757,20 @@ module Sinatra
752
757
  render(:haml, template, options, locals, &block)
753
758
  end
754
759
 
760
+ def sass(template, options = {}, locals = {})
761
+ options[:default_content_type] = :css
762
+ options[:exclude_outvar] = true
763
+ options[:layout] = nil
764
+ render :sass, template, options, locals
765
+ end
766
+
767
+ def scss(template, options = {}, locals = {})
768
+ options[:default_content_type] = :css
769
+ options[:exclude_outvar] = true
770
+ options[:layout] = nil
771
+ render :scss, template, options, locals
772
+ end
773
+
755
774
  def builder(template = nil, options = {}, locals = {}, &block)
756
775
  options[:default_content_type] = :xml
757
776
  render_ruby(:builder, template, options, locals, &block)
@@ -862,7 +881,11 @@ module Sinatra
862
881
  catch(:layout_missing) { return render(layout_engine, layout, options, locals) { output } }
863
882
  end
864
883
 
865
- output.extend(ContentTyped).content_type = content_type if content_type
884
+ if content_type
885
+ # sass-embedded returns a frozen string
886
+ output = +output
887
+ output.extend(ContentTyped).content_type = content_type
888
+ end
866
889
  output
867
890
  end
868
891
 
@@ -914,6 +937,35 @@ module Sinatra
914
937
  end
915
938
  end
916
939
 
940
+ # Extremely simple template cache implementation.
941
+ # * Not thread-safe.
942
+ # * Size is unbounded.
943
+ # * Keys are not copied defensively, and should not be modified after
944
+ # being passed to #fetch. More specifically, the values returned by
945
+ # key#hash and key#eql? should not change.
946
+ #
947
+ # Implementation copied from Tilt::Cache.
948
+ class TemplateCache
949
+ def initialize
950
+ @cache = {}
951
+ end
952
+
953
+ # Caches a value for key, or returns the previously cached value.
954
+ # If a value has been previously cached for key then it is
955
+ # returned. Otherwise, block is yielded to and its return value
956
+ # which may be nil, is cached under key and returned.
957
+ def fetch(*key)
958
+ @cache.fetch(key) do
959
+ @cache[key] = yield
960
+ end
961
+ end
962
+
963
+ # Clears the cache.
964
+ def clear
965
+ @cache = {}
966
+ end
967
+ end
968
+
917
969
  # Base class for all Sinatra applications and middleware.
918
970
  class Base
919
971
  include Rack::Utils
@@ -928,7 +980,7 @@ module Sinatra
928
980
  def initialize(app = nil, **_kwargs)
929
981
  super()
930
982
  @app = app
931
- @template_cache = Tilt::Cache.new
983
+ @template_cache = TemplateCache.new
932
984
  @pinned_response = nil # whether a before! filter pinned the content-type
933
985
  yield self if block_given?
934
986
  end
@@ -949,7 +1001,7 @@ module Sinatra
949
1001
  invoke { dispatch! }
950
1002
  invoke { error_block!(response.status) } unless @env['sinatra.error']
951
1003
 
952
- unless @response['Content-Type']
1004
+ unless @response['content-type']
953
1005
  if Array === body && body[0].respond_to?(:content_type)
954
1006
  content_type body[0].content_type
955
1007
  elsif (default = settings.default_content_type)
@@ -1012,7 +1064,7 @@ module Sinatra
1012
1064
  routes = base.routes[@request.request_method]
1013
1065
 
1014
1066
  routes&.each do |pattern, conditions, block|
1015
- response.delete_header('Content-Type') unless @pinned_response
1067
+ response.delete_header('content-type') unless @pinned_response
1016
1068
 
1017
1069
  returned_pass_block = process_route(pattern, conditions) do |*args|
1018
1070
  env['sinatra.route'] = "#{@request.request_method} #{pattern}"
@@ -1133,7 +1185,7 @@ module Sinatra
1133
1185
  invoke do
1134
1186
  static! if settings.static? && (request.get? || request.head?)
1135
1187
  filter! :before do
1136
- @pinned_response = !response['Content-Type'].nil?
1188
+ @pinned_response = !response['content-type'].nil?
1137
1189
  end
1138
1190
  route!
1139
1191
  end
@@ -1214,7 +1266,19 @@ module Sinatra
1214
1266
  end
1215
1267
 
1216
1268
  def dump_errors!(boom)
1217
- msg = ["#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} - #{boom.class} - #{boom.message}:", *boom.backtrace].join("\n\t")
1269
+ if boom.respond_to?(:detailed_message)
1270
+ msg = boom.detailed_message(highlight: false)
1271
+ if msg =~ /\A(.*?)(?: \(#{ Regexp.quote(boom.class.to_s) }\))?\n/
1272
+ msg = $1
1273
+ additional_msg = $'.lines(chomp: true)
1274
+ else
1275
+ additional_msg = []
1276
+ end
1277
+ else
1278
+ msg = boom.message
1279
+ additional_msg = []
1280
+ end
1281
+ msg = ["#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} - #{boom.class} - #{msg}:", *additional_msg, *boom.backtrace].join("\n\t")
1218
1282
  @env['rack.errors'].puts(msg)
1219
1283
  end
1220
1284
 
@@ -1223,6 +1287,7 @@ module Sinatra
1223
1287
  %r{/sinatra(/(base|main|show_exceptions))?\.rb$}, # all sinatra code
1224
1288
  %r{lib/tilt.*\.rb$}, # all tilt code
1225
1289
  /^\(.*\)$/, # generated code
1290
+ /\/bundled_gems.rb$/, # ruby >= 3.3 with bundler >= 2.5
1226
1291
  %r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks
1227
1292
  /active_support/, # active_support require hacks
1228
1293
  %r{bundler(/(?:runtime|inline))?\.rb}, # bundler require hacks
@@ -1230,7 +1295,7 @@ module Sinatra
1230
1295
  %r{zeitwerk/kernel\.rb} # Zeitwerk kernel#require decorator
1231
1296
  ].freeze
1232
1297
 
1233
- attr_reader :routes, :filters, :templates, :errors
1298
+ attr_reader :routes, :filters, :templates, :errors, :on_start_callback, :on_stop_callback
1234
1299
 
1235
1300
  def callers_to_ignore
1236
1301
  CALLERS_TO_IGNORE
@@ -1401,7 +1466,13 @@ module Sinatra
1401
1466
  # mime_types :js # => ['application/javascript', 'text/javascript']
1402
1467
  def mime_types(type)
1403
1468
  type = mime_type type
1404
- type =~ %r{^application/(xml|javascript)$} ? [type, "text/#{$1}"] : [type]
1469
+ if type =~ %r{^application/(xml|javascript)$}
1470
+ [type, "text/#{$1}"]
1471
+ elsif type =~ %r{^text/(xml|javascript)$}
1472
+ [type, "application/#{$1}"]
1473
+ else
1474
+ [type]
1475
+ end
1405
1476
  end
1406
1477
 
1407
1478
  # Define a before filter; runs before all requests within the same
@@ -1423,6 +1494,14 @@ module Sinatra
1423
1494
  filters[type] << compile!(type, path, block, **options)
1424
1495
  end
1425
1496
 
1497
+ def on_start(&on_start_callback)
1498
+ @on_start_callback = on_start_callback
1499
+ end
1500
+
1501
+ def on_stop(&on_stop_callback)
1502
+ @on_stop_callback = on_stop_callback
1503
+ end
1504
+
1426
1505
  # Add a route condition. The route is considered non-matching when the
1427
1506
  # block returns false.
1428
1507
  def condition(name = "#{caller.first[/`.*'/]} condition", &block)
@@ -1512,18 +1591,37 @@ module Sinatra
1512
1591
  warn '== Sinatra has ended his set (crowd applauds)' unless suppress_messages?
1513
1592
  set :running_server, nil
1514
1593
  set :handler_name, nil
1594
+
1595
+ on_stop_callback.call unless on_stop_callback.nil?
1515
1596
  end
1516
1597
 
1517
1598
  alias stop! quit!
1518
1599
 
1519
1600
  # Run the Sinatra app as a self-hosted server using
1520
- # Puma, Falcon, Mongrel, or WEBrick (in that order). If given a block, will call
1601
+ # Puma, Falcon, or WEBrick (in that order). If given a block, will call
1521
1602
  # with the constructed handler once we have taken the stage.
1522
1603
  def run!(options = {}, &block)
1604
+ unless defined?(Rackup::Handler)
1605
+ rackup_warning = <<~MISSING_RACKUP
1606
+ Sinatra could not start, the "rackup" gem was not found!
1607
+
1608
+ Add it to your bundle with:
1609
+
1610
+ bundle add rackup
1611
+
1612
+ or install it with:
1613
+
1614
+ gem install rackup
1615
+
1616
+ MISSING_RACKUP
1617
+ warn rackup_warning
1618
+ exit 1
1619
+ end
1620
+
1523
1621
  return if running?
1524
1622
 
1525
1623
  set options
1526
- handler = Rack::Handler.pick(server)
1624
+ handler = Rackup::Handler.pick(server)
1527
1625
  handler_name = handler.name.gsub(/.*::/, '')
1528
1626
  server_settings = settings.respond_to?(:server_settings) ? settings.server_settings : {}
1529
1627
  server_settings.merge!(Port: port, Host: bind)
@@ -1599,7 +1697,7 @@ module Sinatra
1599
1697
  set :running_server, server
1600
1698
  set :handler_name, handler_name
1601
1699
  server.threaded = settings.threaded if server.respond_to? :threaded=
1602
-
1700
+ on_start_callback.call unless on_start_callback.nil?
1603
1701
  yield server if block_given?
1604
1702
  end
1605
1703
  end
@@ -1655,7 +1753,7 @@ module Sinatra
1655
1753
  types.map! { |t| mime_types(t) }
1656
1754
  types.flatten!
1657
1755
  condition do
1658
- response_content_type = response['Content-Type']
1756
+ response_content_type = response['content-type']
1659
1757
  preferred_type = request.preferred_type(types)
1660
1758
 
1661
1759
  if response_content_type
@@ -1832,7 +1930,7 @@ module Sinatra
1832
1930
  set :dump_errors, proc { !test? }
1833
1931
  set :show_exceptions, proc { development? }
1834
1932
  set :sessions, false
1835
- set :session_store, Rack::Protection::EncryptedCookie
1933
+ set :session_store, Rack::Session::Cookie
1836
1934
  set :logging, false
1837
1935
  set :protection, true
1838
1936
  set :method_override, false
@@ -1870,11 +1968,10 @@ module Sinatra
1870
1968
 
1871
1969
  ruby_engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
1872
1970
 
1873
- server.unshift 'puma'
1874
- server.unshift 'falcon' if ruby_engine != 'jruby'
1875
- server.unshift 'mongrel' if ruby_engine.nil?
1876
1971
  server.unshift 'thin' if ruby_engine != 'jruby'
1972
+ server.unshift 'falcon' if ruby_engine != 'jruby'
1877
1973
  server.unshift 'trinidad' if ruby_engine == 'jruby'
1974
+ server.unshift 'puma'
1878
1975
 
1879
1976
  set :absolute_redirects, true
1880
1977
  set :prefixed_redirects, false
@@ -1939,7 +2036,7 @@ module Sinatra
1939
2036
  </head>
1940
2037
  <body>
1941
2038
  <h2>Sinatra doesn’t know this ditty.</h2>
1942
- <img src='#{uri '/__sinatra__/404.png'}'>
2039
+ <img src='#{request.script_name}/__sinatra__/404.png'>
1943
2040
  <div id="c">
1944
2041
  Try this:
1945
2042
  <pre>#{Rack::Utils.escape_html(code)}</pre>
@@ -1991,7 +2088,7 @@ module Sinatra
1991
2088
  delegate :get, :patch, :put, :post, :delete, :head, :options, :link, :unlink,
1992
2089
  :template, :layout, :before, :after, :error, :not_found, :configure,
1993
2090
  :set, :mime_type, :enable, :disable, :use, :development?, :test?,
1994
- :production?, :helpers, :settings, :register
2091
+ :production?, :helpers, :settings, :register, :on_start, :on_stop
1995
2092
 
1996
2093
  class << self
1997
2094
  attr_accessor :target
@@ -21,7 +21,8 @@ module Sinatra
21
21
  # writing interface (calling e.g. <tt>[]=</tt>, <tt>merge</tt>). This mapping
22
22
  # belongs to the public interface. For example, given:
23
23
  #
24
- # hash = Sinatra::IndifferentHash.new(:a=>1)
24
+ # hash = Sinatra::IndifferentHash.new
25
+ # hash[:a] = 1
25
26
  #
26
27
  # You are guaranteed that the key is returned as a string:
27
28
  #
@@ -29,7 +30,8 @@ module Sinatra
29
30
  #
30
31
  # Technically other types of keys are accepted:
31
32
  #
32
- # hash = Sinatra::IndifferentHash.new(:a=>1)
33
+ # hash = Sinatra::IndifferentHash
34
+ # hash[:a] = 1
33
35
  # hash[0] = 0
34
36
  # hash # => { "a"=>1, 0=>0 }
35
37
  #
@@ -41,12 +43,6 @@ module Sinatra
41
43
  new.merge!(Hash[*args])
42
44
  end
43
45
 
44
- def initialize(*args)
45
- args.map!(&method(:convert_value))
46
-
47
- super(*args)
48
- end
49
-
50
46
  def default(*args)
51
47
  args.map!(&method(:convert_key))
52
48
 
@@ -186,6 +182,12 @@ module Sinatra
186
182
  dup.tap(&:compact!)
187
183
  end
188
184
 
185
+ def except(*keys)
186
+ keys.map!(&method(:convert_key))
187
+
188
+ super(*keys)
189
+ end if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0")
190
+
189
191
  private
190
192
 
191
193
  def convert_key(key)
@@ -38,8 +38,8 @@ module Sinatra
38
38
  [
39
39
  500,
40
40
  {
41
- 'Content-Type' => content_type,
42
- 'Content-Length' => body.bytesize.to_s
41
+ 'content-type' => content_type,
42
+ 'content-length' => body.bytesize.to_s
43
43
  },
44
44
  [body]
45
45
  ]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sinatra
4
- VERSION = '3.0.6'
4
+ VERSION = '4.0.0'
5
5
  end
data/sinatra.gemspec CHANGED
@@ -43,12 +43,11 @@ RubyGems 2.0 or newer is required to protect against public gem pushes. You can
43
43
  'documentation_uri' => 'https://www.rubydoc.info/gems/sinatra'
44
44
  }
45
45
 
46
- s.required_ruby_version = '>= 2.6.0'
46
+ s.required_ruby_version = '>= 2.7.8'
47
47
 
48
48
  s.add_dependency 'mustermann', '~> 3.0'
49
- s.add_dependency 'rack', '~> 2.2', '>= 2.2.4'
49
+ s.add_dependency 'rack', '>= 3.0.0', '< 4'
50
+ s.add_dependency 'rack-session', '>= 2.0.0', '< 3'
50
51
  s.add_dependency 'rack-protection', version
51
52
  s.add_dependency 'tilt', '~> 2.0'
52
-
53
- s.add_development_dependency 'rack-test', '~> 2'
54
53
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.6
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blake Mizerany
8
8
  - Ryan Tomayko
9
9
  - Simon Rozet
10
10
  - Konstantin Haase
11
- autorequire:
11
+ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2023-04-11 00:00:00.000000000 Z
14
+ date: 2024-01-19 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: mustermann
@@ -31,64 +31,70 @@ dependencies:
31
31
  name: rack
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
- - - "~>"
35
- - !ruby/object:Gem::Version
36
- version: '2.2'
37
34
  - - ">="
38
35
  - !ruby/object:Gem::Version
39
- version: 2.2.4
36
+ version: 3.0.0
37
+ - - "<"
38
+ - !ruby/object:Gem::Version
39
+ version: '4'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '2.2'
47
44
  - - ">="
48
45
  - !ruby/object:Gem::Version
49
- version: 2.2.4
46
+ version: 3.0.0
47
+ - - "<"
48
+ - !ruby/object:Gem::Version
49
+ version: '4'
50
50
  - !ruby/object:Gem::Dependency
51
- name: rack-protection
51
+ name: rack-session
52
52
  requirement: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - '='
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 2.0.0
57
+ - - "<"
55
58
  - !ruby/object:Gem::Version
56
- version: 3.0.6
59
+ version: '3'
57
60
  type: :runtime
58
61
  prerelease: false
59
62
  version_requirements: !ruby/object:Gem::Requirement
60
63
  requirements:
61
- - - '='
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 2.0.0
67
+ - - "<"
62
68
  - !ruby/object:Gem::Version
63
- version: 3.0.6
69
+ version: '3'
64
70
  - !ruby/object:Gem::Dependency
65
- name: tilt
71
+ name: rack-protection
66
72
  requirement: !ruby/object:Gem::Requirement
67
73
  requirements:
68
- - - "~>"
74
+ - - '='
69
75
  - !ruby/object:Gem::Version
70
- version: '2.0'
76
+ version: 4.0.0
71
77
  type: :runtime
72
78
  prerelease: false
73
79
  version_requirements: !ruby/object:Gem::Requirement
74
80
  requirements:
75
- - - "~>"
81
+ - - '='
76
82
  - !ruby/object:Gem::Version
77
- version: '2.0'
83
+ version: 4.0.0
78
84
  - !ruby/object:Gem::Dependency
79
- name: rack-test
85
+ name: tilt
80
86
  requirement: !ruby/object:Gem::Requirement
81
87
  requirements:
82
88
  - - "~>"
83
89
  - !ruby/object:Gem::Version
84
- version: '2'
85
- type: :development
90
+ version: '2.0'
91
+ type: :runtime
86
92
  prerelease: false
87
93
  version_requirements: !ruby/object:Gem::Requirement
88
94
  requirements:
89
95
  - - "~>"
90
96
  - !ruby/object:Gem::Version
91
- version: '2'
97
+ version: '2.0'
92
98
  description: Sinatra is a DSL for quickly creating web applications in Ruby with minimal
93
99
  effort.
94
100
  email: sinatrarb@googlegroups.com
@@ -110,8 +116,7 @@ files:
110
116
  - SECURITY.md
111
117
  - VERSION
112
118
  - examples/chat.rb
113
- - examples/rainbows.conf
114
- - examples/rainbows.rb
119
+ - examples/lifecycle_events.rb
115
120
  - examples/simple.rb
116
121
  - examples/stream.ru
117
122
  - lib/sinatra.rb
@@ -133,7 +138,7 @@ metadata:
133
138
  bug_tracker_uri: https://github.com/sinatra/sinatra/issues
134
139
  mailing_list_uri: http://groups.google.com/group/sinatrarb
135
140
  documentation_uri: https://www.rubydoc.info/gems/sinatra
136
- post_install_message:
141
+ post_install_message:
137
142
  rdoc_options:
138
143
  - "--line-numbers"
139
144
  - "--title"
@@ -147,15 +152,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
147
152
  requirements:
148
153
  - - ">="
149
154
  - !ruby/object:Gem::Version
150
- version: 2.6.0
155
+ version: 2.7.8
151
156
  required_rubygems_version: !ruby/object:Gem::Requirement
152
157
  requirements:
153
158
  - - ">="
154
159
  - !ruby/object:Gem::Version
155
160
  version: '0'
156
161
  requirements: []
157
- rubygems_version: 3.4.10
158
- signing_key:
162
+ rubygems_version: 3.5.3
163
+ signing_key:
159
164
  specification_version: 4
160
165
  summary: Classy web-development dressed in a DSL
161
166
  test_files: []
@@ -1,3 +0,0 @@
1
- Rainbows! do
2
- use :EventMachine
3
- end
data/examples/rainbows.rb DELETED
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rainbows'
4
-
5
- module Rack
6
- module Handler
7
- class Rainbows
8
- def self.run(app, **options)
9
- rainbows_options = {
10
- listeners: ["#{options[:Host]}:#{options[:Port]}"],
11
- worker_processes: 1,
12
- timeout: 30,
13
- config_file: ::File.expand_path('rainbows.conf', __dir__)
14
- }
15
-
16
- ::Rainbows::HttpServer.new(app, rainbows_options).start.join
17
- end
18
- end
19
-
20
- register :rainbows, ::Rack::Handler::Rainbows
21
- end
22
- end