sinatra 3.0.0 → 3.1.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: 3951384ec9f9b0b48f46431b308f99d4f041181f6a5a946e18879905977b2d96
4
- data.tar.gz: fce5e68c20aa619bdaadc88976bd6898be0252e7a62f4aa45f2eca3e3958b8a2
3
+ metadata.gz: 315dee3d85d7778ffa48e041bd60370e9e89ecd3c01dbf0cf9450e41c62dc0d8
4
+ data.tar.gz: '083a914c0b520684471e2715ec091c67ca8121bfb8b5d4cf410307d6e14e4ac5'
5
5
  SHA512:
6
- metadata.gz: 3ad27c41c217cf1ff3e51b9c17cc9a6583869e1a870206aedc6b9be7003282ac3dc9b22d86725b3af8b0b431d069573059ab9ef9b53bc1dd5ed101c0db5c14d8
7
- data.tar.gz: fd0f1c35f005b3a70f43022f0fa95239147225bc9f7ca1a978cdf6f5c7fe13257004a5a2f1f7b36f141b80e2fd9156a81d97f613a994e2024e83c0db9cb0a4b1
6
+ metadata.gz: 2790a4d58595f0f89667c5fd4530dde2de532ddaf02628f373162cc47d393732b1c9475ab59775c756750dfb52e60e7091118936ac8e70739fb266b46f82d3bd
7
+ data.tar.gz: eb74f34bf0b9a681557809c656754312eb266e66c3b68fcabbf95699c3273cf4d998e3969224b09df9127ff90f5d34fba5bc93b1ff0c321b4a7646ddfcc0b6b7
data/CHANGELOG.md CHANGED
@@ -1,4 +1,60 @@
1
- ## 3.0.0 / Unreleased
1
+ ## Unreleased
2
+
3
+ * _Your new feature here._
4
+
5
+ ## 3.1.0 / 2023-08-07
6
+
7
+ * New: Add sass support via sass-embedded [#1911] by なつき
8
+
9
+ * New: Add start and stop callbacks [#1913] by Jevin Sew
10
+
11
+ * New: Warn on dropping sessions [#1900] by Jonathan del Strother
12
+
13
+ * New: Make Puma the default server [#1924] by Patrik Ragnarsson
14
+
15
+ * Fix: Remove use of Tilt::Cache [#1922] by Jeremy Evans (allows use of Tilt 2.2.0 without deprecation warning)
16
+
17
+ * Fix: rack-protection: specify rack version requirement [#1932] by Patrik Ragnarsson
18
+
19
+ [#1913]: https://github.com/sinatra/sinatra/pull/1913
20
+ [#1900]: https://github.com/sinatra/sinatra/pull/1900
21
+ [#1924]: https://github.com/sinatra/sinatra/pull/1924
22
+ [#1922]: https://github.com/sinatra/sinatra/pull/1922
23
+ [#1932]: https://github.com/sinatra/sinatra/pull/1932
24
+
25
+ ## 3.0.6 / 2023-04-11
26
+
27
+ * Fix: Add support to keep open streaming connections with Puma [#1858](https://github.com/sinatra/sinatra/pull/1858) by Jordan Owens
28
+
29
+ * Fix: Avoid crash in `uri` helper on Integer input [#1890](https://github.com/sinatra/sinatra/pull/1890) by Patrik Ragnarsson
30
+
31
+ * Fix: Rescue `RuntimeError` when trying to use `SecureRandom` [#1888](https://github.com/sinatra/sinatra/pull/1888) by Stefan Sundin
32
+
33
+ ## 3.0.5 / 2022-12-16
34
+
35
+ * Fix: Add Zeitwerk compatibility. [#1831](https://github.com/sinatra/sinatra/pull/1831) by Dawid Janczak
36
+
37
+ * Fix: Allow CALLERS_TO_IGNORE to be overridden
38
+
39
+ ## 3.0.4 / 2022-11-25
40
+
41
+ * Fix: Escape filename in the Content-Disposition header. [#1841](https://github.com/sinatra/sinatra/pull/1841) by Kunpei Sakai
42
+
43
+ ## 3.0.3 / 2022-11-11
44
+
45
+ * Fix: fixed ReDoS for Rack::Protection::IPSpoofing. [#1823](https://github.com/sinatra/sinatra/pull/1823) by @ooooooo-q
46
+
47
+ ## 3.0.2 / 2022-10-01
48
+
49
+ * New: Add Haml 6 support. [#1820](https://github.com/sinatra/sinatra/pull/1820) by Jordan Owens
50
+
51
+ ## 3.0.1 / 2022-09-26
52
+
53
+ * Fix: Revert removal of rack-protection.rb. [#1814](https://github.com/sinatra/sinatra/pull/1814) by Olle Jonsson
54
+
55
+ * Fix: Revert change to server start and stop messaging by using Kernel#warn. Renamed internal warn method warn_for_deprecation. [#1818](https://github.com/sinatra/sinatra/pull/1818) by Jordan Owens
56
+
57
+ ## 3.0.0 / 2022-09-26
2
58
 
3
59
  * New: Add Falcon support. [#1794](https://github.com/sinatra/sinatra/pull/1794) by Samuel Williams and @horaciob
4
60
 
@@ -44,6 +100,12 @@
44
100
 
45
101
  * Docs: Japanese documentation: Make Session section reflect changes done to README.md. [#1731](https://github.com/sinatra/sinatra/pull/1731) by @shu-i-chi
46
102
 
103
+ ## 2.2.3 / 2022-11-25
104
+
105
+ * Fix: Escape filename in the Content-Disposition header. [#1841](https://github.com/sinatra/sinatra/pull/1841) by Kunpei Sakai
106
+
107
+ * Fix: fixed ReDoS for Rack::Protection::IPSpoofing. [#1823](https://github.com/sinatra/sinatra/pull/1823) by @ooooooo-q
108
+
47
109
  ## 2.2.2 / 2022-07-23
48
110
 
49
111
  * Update mustermann dependency to version 2.
@@ -56,6 +118,8 @@
56
118
 
57
119
  ## 2.2.0 / 2022-02-15
58
120
 
121
+ * Breaking change: Add `#select`, `#reject` and `#compact` methods to `Sinatra::IndifferentHash`. If hash keys need to be converted to symbols, call `#to_h` to get a `Hash` instance first. [#1711](https://github.com/sinatra/sinatra/pull/1711) by Olivier Bellone
122
+
59
123
  * Handle EOFError raised by Rack and return Bad Request 400 status. [#1743](https://github.com/sinatra/sinatra/pull/1743) by tamazon
60
124
 
61
125
  * Minor refactors in `base.rb`. [#1640](https://github.com/sinatra/sinatra/pull/1640) by ceclinux
@@ -86,8 +150,6 @@
86
150
 
87
151
  * Remove unnecessary `test_files` from the gemspec. [#1712](https://github.com/sinatra/sinatra/pull/1712) by Masataka Pocke Kuwabara
88
152
 
89
- * Add `#select`, `#reject` and `#compact` methods to `Sinatra::IndifferentHash`. [#1711](https://github.com/sinatra/sinatra/pull/1711) by Olivier Bellone
90
-
91
153
  * Docs: Spanish documentation: Update README.es.md with removal of Thin. [#1630](https://github.com/sinatra/sinatra/pull/1630) by Espartaco Palma
92
154
 
93
155
  * Docs: German documentation: Fixed typos in German README.md. [#1648](https://github.com/sinatra/sinatra/pull/1648) by Juri
data/CONTRIBUTING.md CHANGED
@@ -65,21 +65,21 @@ track patch requests.
65
65
  also has its own [Git repository](http://github.com/sinatra/sinatra-recipes).
66
66
 
67
67
  * [The Introduction](http://www.sinatrarb.com/intro.html) is generated from
68
- Sinatra's [README file](http://github.com/sinatra/sinatra/blob/master/README.md).
68
+ Sinatra's [README file](http://github.com/sinatra/sinatra/blob/main/README.md).
69
69
 
70
70
  * If you want to help translating the documentation, the README is already
71
71
  available in
72
- [Japanese](http://github.com/sinatra/sinatra/blob/master/README.ja.md),
73
- [German](http://github.com/sinatra/sinatra/blob/master/README.de.md),
74
- [Chinese](https://github.com/sinatra/sinatra/blob/master/README.zh.md),
75
- [Russian](https://github.com/sinatra/sinatra/blob/master/README.ru.md),
76
- [European](https://github.com/sinatra/sinatra/blob/master/README.pt-pt.md) and
77
- [Brazilian](https://github.com/sinatra/sinatra/blob/master/README.pt-br.md)
72
+ [Japanese](http://github.com/sinatra/sinatra/blob/main/README.ja.md),
73
+ [German](http://github.com/sinatra/sinatra/blob/main/README.de.md),
74
+ [Chinese](https://github.com/sinatra/sinatra/blob/main/README.zh.md),
75
+ [Russian](https://github.com/sinatra/sinatra/blob/main/README.ru.md),
76
+ [European](https://github.com/sinatra/sinatra/blob/main/README.pt-pt.md) and
77
+ [Brazilian](https://github.com/sinatra/sinatra/blob/main/README.pt-br.md)
78
78
  Portuguese,
79
- [French](https://github.com/sinatra/sinatra/blob/master/README.fr.md),
80
- [Spanish](https://github.com/sinatra/sinatra/blob/master/README.es.md),
81
- [Korean](https://github.com/sinatra/sinatra/blob/master/README.ko.md), and
82
- [Hungarian](https://github.com/sinatra/sinatra/blob/master/README.hu.md).
79
+ [French](https://github.com/sinatra/sinatra/blob/main/README.fr.md),
80
+ [Spanish](https://github.com/sinatra/sinatra/blob/main/README.es.md),
81
+ [Korean](https://github.com/sinatra/sinatra/blob/main/README.ko.md), and
82
+ [Hungarian](https://github.com/sinatra/sinatra/blob/main/README.hu.md).
83
83
  The translations tend to fall behind the English version. Translations into
84
84
  other languages would also be appreciated.
85
85
 
data/Gemfile CHANGED
@@ -15,9 +15,14 @@ gem 'rake'
15
15
 
16
16
  rack_version = ENV['rack'].to_s
17
17
  rack_version = nil if rack_version.empty? || (rack_version == 'stable')
18
- rack_version = { github: 'rack/rack' } if rack_version == 'master'
18
+ rack_version = { github: 'rack/rack' } if rack_version == 'head'
19
19
  gem 'rack', rack_version
20
20
 
21
+ puma_version = ENV['puma'].to_s
22
+ puma_version = nil if puma_version.empty? || (puma_version == 'stable')
23
+ puma_version = { github: 'puma/puma' } if puma_version == 'head'
24
+ gem 'puma', puma_version
25
+
21
26
  gem 'minitest', '~> 5.0'
22
27
  gem 'rack-test', github: 'rack/rack-test'
23
28
  gem 'rubocop', '~> 1.32.0', require: false
@@ -26,6 +31,12 @@ gem 'yard'
26
31
  gem 'rack-protection', path: 'rack-protection'
27
32
  gem 'sinatra-contrib', path: 'sinatra-contrib'
28
33
 
34
+ # traces 0.10.0 started to use Ruby 2.7 syntax without specifying required Ruby version
35
+ # https://github.com/socketry/traces/pull/8#discussion_r1237988182
36
+ # async-http 0.60.2 added traces 0.10.0 as dependency
37
+ # https://github.com/socketry/async-http/pull/124/files#r1237988899
38
+ gem 'traces', '< 0.10.0' if RUBY_VERSION >= '2.6.0' && RUBY_VERSION < '2.7.0'
39
+
29
40
  gem 'activesupport', '~> 6.1'
30
41
 
31
42
  gem 'asciidoctor'
@@ -34,18 +45,18 @@ gem 'commonmarker', '~> 0.23.4', platforms: [:ruby]
34
45
  gem 'erubi'
35
46
  gem 'eventmachine'
36
47
  gem 'falcon', '~> 0.40', platforms: [:ruby]
37
- gem 'haml', '~> 5'
48
+ gem 'haml', '~> 6'
38
49
  gem 'kramdown'
39
50
  gem 'liquid'
40
51
  gem 'markaby'
41
52
  gem 'nokogiri', '> 1.5.0'
42
53
  gem 'pandoc-ruby', '~> 2.0.2'
43
- gem 'puma'
44
54
  gem 'rabl'
45
55
  gem 'rainbows', platforms: [:mri] # uses #fork
46
56
  gem 'rdiscount', platforms: [:ruby]
47
57
  gem 'rdoc'
48
58
  gem 'redcarpet', platforms: [:ruby]
59
+ gem 'sass-embedded', '~> 1.54'
49
60
  gem 'simplecov', require: false
50
61
  gem 'slim', '~> 4'
51
62
  gem 'yajl-ruby', platforms: [:ruby]
data/MAINTENANCE.md CHANGED
@@ -4,13 +4,13 @@
4
4
 
5
5
  ### Releases
6
6
 
7
- The next major version of Sinatra will be released from the master branch. Each version will be tagged so it will be possible to branch of should there be a need for bug fixes and other updates.
7
+ The next major version of Sinatra will be released from the main branch. Each version will be tagged so it will be possible to branch of should there be a need for bug fixes and other updates.
8
8
 
9
9
  ## Issues
10
10
 
11
11
  ### New features
12
12
 
13
- New features will only be added to the master branch and will not be made available in point releases.
13
+ New features will only be added to the main branch and will not be made available in point releases.
14
14
 
15
15
  ### Bug fixes
16
16
 
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
 
@@ -938,7 +974,7 @@ __END__
938
974
 
939
975
  @@ layout
940
976
  %html
941
- = yield
977
+ != yield
942
978
 
943
979
  @@ index
944
980
  %div.title Hello world.
@@ -984,7 +1020,7 @@ To associate a file extension with a template engine, use
984
1020
  `tt` for Haml templates, you can do the following:
985
1021
 
986
1022
  ```ruby
987
- Tilt.register :tt, Tilt[:haml]
1023
+ Tilt.register Tilt[:haml], :tt
988
1024
  ```
989
1025
 
990
1026
  ### Adding Your Own Template Engine
@@ -992,7 +1028,7 @@ Tilt.register :tt, Tilt[:haml]
992
1028
  First, register your engine with Tilt, then create a rendering method:
993
1029
 
994
1030
  ```ruby
995
- Tilt.register :myat, MyAwesomeTemplateEngine
1031
+ Tilt.register MyAwesomeTemplateEngine, :myat
996
1032
 
997
1033
  helpers do
998
1034
  def myat(*args) render(:myat, *args) end
@@ -1933,7 +1969,7 @@ end
1933
1969
  ### Configuring attack protection
1934
1970
 
1935
1971
  Sinatra is using
1936
- [Rack::Protection](https://github.com/sinatra/sinatra/tree/master/rack-protection#readme) to
1972
+ [Rack::Protection](https://github.com/sinatra/sinatra/tree/main/rack-protection#readme) to
1937
1973
  defend your application against common, opportunistic attacks. You can
1938
1974
  easily disable this behavior (which will open up your application to tons
1939
1975
  of common vulnerabilities):
@@ -2089,9 +2125,13 @@ set :protection, :session => true
2089
2125
 
2090
2126
  <dt>raise_errors</dt>
2091
2127
  <dd>
2092
- Raise exceptions (will stop application). Enabled by default when
2128
+ Raise unhandled errors (will stop application). Enabled by default when
2093
2129
  <tt>environment</tt> is set to <tt>"test"</tt>, disabled otherwise.
2094
2130
  </dd>
2131
+ <dd>
2132
+ Any explicitly defined error handlers always override this setting. See
2133
+ the "Error" section below.
2134
+ </dd>
2095
2135
 
2096
2136
  <dt>run</dt>
2097
2137
  <dd>
@@ -2184,6 +2224,24 @@ set :protection, :session => true
2184
2224
  </dd>
2185
2225
  </dl>
2186
2226
 
2227
+ ## Lifecycle Events
2228
+
2229
+ There are 2 lifecycle events currently exposed by Sinatra. One when the server starts and one when it stops.
2230
+
2231
+ They can be used like this:
2232
+
2233
+ ```ruby
2234
+ on_start do
2235
+ puts "===== Booting up ====="
2236
+ end
2237
+
2238
+ on_stop do
2239
+ puts "===== Shutting down ====="
2240
+ end
2241
+ ```
2242
+
2243
+ Note that these callbacks only work when using Sinatra to start the web server.
2244
+
2187
2245
  ## Environments
2188
2246
 
2189
2247
  There are three predefined `environments`: `"development"`,
@@ -2240,6 +2298,14 @@ show exceptions option to `:after_handler`:
2240
2298
  set :show_exceptions, :after_handler
2241
2299
  ```
2242
2300
 
2301
+ A catch-all error handler can be defined with `error` and a block:
2302
+
2303
+ ```ruby
2304
+ error do
2305
+ 'Sorry there was a nasty error'
2306
+ end
2307
+ ```
2308
+
2243
2309
  The exception object can be obtained from the `sinatra.error` Rack variable:
2244
2310
 
2245
2311
  ```ruby
@@ -2248,7 +2314,7 @@ error do
2248
2314
  end
2249
2315
  ```
2250
2316
 
2251
- Custom errors:
2317
+ Pass an error class as an argument to create handlers for custom errors:
2252
2318
 
2253
2319
  ```ruby
2254
2320
  error MyCustomError do
@@ -2294,6 +2360,51 @@ Sinatra installs special `not_found` and `error` handlers when
2294
2360
  running under the development environment to display nice stack traces
2295
2361
  and additional debugging information in your browser.
2296
2362
 
2363
+ ### Behavior with `raise_errors` option
2364
+
2365
+ When `raise_errors` option is `true`, errors that are unhandled are raised
2366
+ outside of the application. Additionally, any errors that would have been
2367
+ caught by the catch-all error handler are raised.
2368
+
2369
+ For example, consider the following configuration:
2370
+
2371
+ ```ruby
2372
+ # First handler
2373
+ error MyCustomError do
2374
+ 'A custom message'
2375
+ end
2376
+
2377
+ # Second handler
2378
+ error do
2379
+ 'A catch-all message'
2380
+ end
2381
+ ```
2382
+
2383
+ If `raise_errors` is `false`:
2384
+
2385
+ * When `MyCustomError` or descendant is raised, the first handler is invoked.
2386
+ The HTTP response body will contain `"A custom message"`.
2387
+ * When any other error is raised, the second handler is invoked. The HTTP
2388
+ response body will contain `"A catch-all message"`.
2389
+
2390
+ If `raise_errors` is `true`:
2391
+
2392
+ * When `MyCustomError` or descendant is raised, the behavior is identical to
2393
+ when `raise_errors` is `false`, described above.
2394
+ * When any other error is raised, the second handler is *not* invoked, and
2395
+ the error is raised outside of the application.
2396
+ * If the environment is `production`, the HTTP response body will contain
2397
+ a generic error message, e.g. `"An unhandled lowlevel error occurred. The
2398
+ application logs may have details."`
2399
+ * If the environment is not `production`, the HTTP response body will contain
2400
+ the verbose error backtrace.
2401
+ * Regardless of environment, if `show_exceptions` is set to `:after_handler`,
2402
+ the HTTP response body will contain the verbose error backtrace.
2403
+
2404
+ In the `test` environment, `raise_errors` is set to `true` by default. This
2405
+ means that in order to write a test for a catch-all error handler,
2406
+ `raise_errors` must temporarily be set to `false` for that particular test.
2407
+
2297
2408
  ## Rack Middleware
2298
2409
 
2299
2410
  Sinatra rides on [Rack](https://rack.github.io/), a minimal standard
@@ -2319,7 +2430,7 @@ end
2319
2430
  ```
2320
2431
 
2321
2432
  The semantics of `use` are identical to those defined for the
2322
- [Rack::Builder](http://www.rubydoc.info/github/rack/rack/master/Rack/Builder) DSL
2433
+ [Rack::Builder](https://www.rubydoc.info/github/rack/rack/main/Rack/Builder) DSL
2323
2434
  (most frequently used from rackup files). For example, the `use` method
2324
2435
  accepts multiple/variable args as well as blocks:
2325
2436
 
@@ -2335,7 +2446,7 @@ many of these components automatically based on configuration so you
2335
2446
  typically don't have to `use` them explicitly.
2336
2447
 
2337
2448
  You can find useful middleware in
2338
- [rack](https://github.com/rack/rack/tree/master/lib/rack),
2449
+ [rack](https://github.com/rack/rack/tree/main/lib/rack),
2339
2450
  [rack-contrib](https://github.com/rack/rack-contrib#readme),
2340
2451
  or in the [Rack wiki](https://github.com/rack/rack/wiki/List-of-Middleware).
2341
2452
 
@@ -2343,7 +2454,7 @@ or in the [Rack wiki](https://github.com/rack/rack/wiki/List-of-Middleware).
2343
2454
 
2344
2455
  Sinatra tests can be written using any Rack-based testing library or
2345
2456
  framework.
2346
- [Rack::Test](http://www.rubydoc.info/github/brynary/rack-test/master/frames)
2457
+ [Rack::Test](https://www.rubydoc.info/github/rack/rack-test/main/frames)
2347
2458
  is recommended:
2348
2459
 
2349
2460
  ```ruby
@@ -2838,7 +2949,7 @@ Running Sinatra on a not officially supported Ruby flavor means that if things o
2838
2949
  ## The Bleeding Edge
2839
2950
 
2840
2951
  If you would like to use Sinatra's latest bleeding-edge code, feel free
2841
- to run your application against the master branch, it should be rather
2952
+ to run your application against the main branch, it should be rather
2842
2953
  stable.
2843
2954
 
2844
2955
  We also push out prerelease gems from time to time, so you can do a
@@ -2887,20 +2998,19 @@ SemVerTag.
2887
2998
 
2888
2999
  ## Further Reading
2889
3000
 
2890
- * [Project Website](http://www.sinatrarb.com/) - Additional documentation,
3001
+ * [Project Website](https://sinatrarb.com/) - Additional documentation,
2891
3002
  news, and links to other resources.
2892
- * [Contributing](http://www.sinatrarb.com/contributing) - Find a bug? Need
3003
+ * [Contributing](https://sinatrarb.com/contributing) - Find a bug? Need
2893
3004
  help? Have a patch?
2894
3005
  * [Issue tracker](https://github.com/sinatra/sinatra/issues)
2895
3006
  * [Twitter](https://twitter.com/sinatra)
2896
3007
  * [Mailing List](https://groups.google.com/forum/#!forum/sinatrarb)
2897
3008
  * IRC: [#sinatra](irc://chat.freenode.net/#sinatra) on [Freenode](https://freenode.net)
2898
- * [Sinatra & Friends](https://sinatrarb.slack.com) on Slack
2899
- ([get an invite](https://sinatra-slack.herokuapp.com/))
3009
+ * [Sinatra & Friends](https://discord.gg/ncjsfsNHh7) on Discord
2900
3010
  * [Sinatra Book](https://github.com/sinatra/sinatra-book) - Cookbook Tutorial
2901
3011
  * [Sinatra Recipes](http://recipes.sinatrarb.com/) - Community contributed
2902
3012
  recipes
2903
- * API documentation for the [latest release](http://www.rubydoc.info/gems/sinatra)
2904
- or the [current HEAD](http://www.rubydoc.info/github/sinatra/sinatra) on
2905
- [RubyDoc](http://www.rubydoc.info/)
2906
- * [CI server](https://travis-ci.org/sinatra/sinatra)
3013
+ * API documentation for the [latest release](https://www.rubydoc.info/gems/sinatra)
3014
+ or the [current HEAD](https://www.rubydoc.info/github/sinatra/sinatra) on
3015
+ [RubyDoc](https://www.rubydoc.info/)
3016
+ * [CI Actions](https://github.com/sinatra/sinatra/actions)
data/Rakefile CHANGED
@@ -1,14 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rake/clean'
4
- require 'rake/testtask'
4
+ require 'minitest/test_task'
5
5
  require 'fileutils'
6
6
  require 'date'
7
7
 
8
8
  task default: :test
9
- task spec: :test
10
-
11
- CLEAN.include '**/*.rbc'
12
9
 
13
10
  def source_version
14
11
  @source_version ||= File.read(File.expand_path('VERSION', __dir__)).strip
@@ -24,27 +21,20 @@ def prev_version
24
21
  source_version.gsub(/\d+$/) { |s| s.to_i - 1 }
25
22
  end
26
23
 
27
- # SPECS ===============================================================
24
+ # Tests ===============================================================
28
25
 
29
- Rake::TestTask.new(:test) do |t|
30
- t.test_files = FileList['test/*_test.rb']
31
- t.ruby_opts = ['-r rubygems'] if defined? Gem
26
+ Minitest::TestTask.create # Default `test` task
27
+ Minitest::TestTask.create(:'test:core') do |t|
32
28
  t.warning = true
33
- end
34
-
35
- Rake::TestTask.new(:'test:core') do |t|
36
- core_tests = %w[
29
+ t.test_globs = %w[
37
30
  base delegator encoding extensions filter
38
31
  helpers mapped_error middleware rdoc
39
32
  readme request response result route_added_hook
40
33
  routing server settings sinatra static templates
41
- ]
42
- t.test_files = core_tests.map { |n| "test/#{n}_test.rb" }
43
- t.ruby_opts = ['-r rubygems'] if defined? Gem
44
- t.warning = true
34
+ ].map { |n| "test/#{n}_test.rb" }
45
35
  end
46
36
 
47
- # Rcov ================================================================
37
+ # Test code coverage ==================================================
48
38
 
49
39
  namespace :test do
50
40
  desc 'Measures test coverage'
@@ -54,6 +44,7 @@ namespace :test do
54
44
  Rake::Task['test'].invoke
55
45
  end
56
46
  end
47
+ CLEAN.include('coverage')
57
48
 
58
49
  # Website =============================================================
59
50
 
@@ -208,11 +199,11 @@ if defined?(Gem)
208
199
  rack-protection/lib/rack/protection
209
200
  ].each do |path|
210
201
  path = File.join(path, 'version.rb')
211
- #File.write(path, File.read(path).sub(/VERSION = '(.+?)'/, "VERSION = '#{source_version}'"))
202
+ File.write(path, File.read(path).sub(/VERSION = '(.+?)'/, "VERSION = '#{source_version}'"))
212
203
  end
213
204
 
214
- #git commit --allow-empty -a -m '#{source_version} release' &&
215
205
  sh <<-SH
206
+ git commit --allow-empty -a -m '#{source_version} release' &&
216
207
  git tag -s v#{source_version} -m '#{source_version} release' &&
217
208
  git push && (git push origin || true) &&
218
209
  git push --tags && (git push origin --tags || true)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.0
1
+ 3.1.0
data/examples/chat.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  #!/usr/bin/env ruby -I ../lib -I lib
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative 'rainbows'
4
+ # This example does *not* work properly with WEBrick or other
5
+ # servers that buffer output. To shut down the server, close any
6
+ # open browser tabs that are connected to the chat server.
5
7
 
6
8
  require 'sinatra'
7
- set :server, :rainbows
8
- connections = []
9
+ set :server, :puma
10
+ connections = Set.new
9
11
 
10
12
  get '/' do
11
13
  halt erb(:login) unless params[:user]
@@ -14,13 +16,22 @@ end
14
16
 
15
17
  get '/stream', provides: 'text/event-stream' do
16
18
  stream :keep_open do |out|
17
- connections << out
18
- out.callback { connections.delete(out) }
19
+ if connections.add?(out)
20
+ out.callback { connections.delete(out) }
21
+ end
22
+ out << "heartbeat:\n"
23
+ sleep 1
24
+ rescue
25
+ out.close
19
26
  end
20
27
  end
21
28
 
22
29
  post '/' do
23
- connections.each { |out| out << "data: #{params[:msg]}\n\n" }
30
+ connections.each do |out|
31
+ out << "data: #{params[:msg]}\n\n"
32
+ rescue
33
+ out.close
34
+ end
24
35
  204 # response without entity body
25
36
  end
26
37
 
@@ -37,10 +48,10 @@ __END__
37
48
  </html>
38
49
 
39
50
  @@ login
40
- <form action='/'>
51
+ <form action="/">
41
52
  <label for='user'>User Name:</label>
42
- <input name='user' value='' />
43
- <input type='submit' value="GO!" />
53
+ <input name="user" value="" />
54
+ <input type="submit" value="GO!" />
44
55
  </form>
45
56
 
46
57
  @@ chat
@@ -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,7 +4,6 @@
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
9
  # rainbows -c rainbows.conf stream.ru # gem install rainbows eventmachine
data/lib/sinatra/base.rb CHANGED
@@ -19,7 +19,7 @@ require 'sinatra/version'
19
19
 
20
20
  module Sinatra
21
21
  # The request object. See Rack::Request for more info:
22
- # http://rubydoc.info/github/rack/rack/master/Rack/Request
22
+ # https://rubydoc.info/github/rack/rack/main/Rack/Request
23
23
  class Request < Rack::Request
24
24
  HEADER_PARAM = /\s*[\w.]+=(?:[\w.]+|"(?:[^"\\]|\\.)*")?\s*/.freeze
25
25
  HEADER_VALUE_WITH_PARAMS = %r{(?:(?:\w+|\*)/(?:\w+(?:\.|-|\+)?|\*)*)\s*(?:;#{HEADER_PARAM})*}.freeze
@@ -158,8 +158,8 @@ module Sinatra
158
158
 
159
159
  # The response object. See Rack::Response and Rack::Response::Helpers for
160
160
  # more info:
161
- # http://rubydoc.info/github/rack/rack/master/Rack/Response
162
- # http://rubydoc.info/github/rack/rack/master/Rack/Response/Helpers
161
+ # https://rubydoc.info/github/rack/rack/main/Rack/Response
162
+ # https://rubydoc.info/github/rack/rack/main/Rack/Response/Helpers
163
163
  class Response < Rack::Response
164
164
  DROP_BODY_RESPONSES = [204, 304].freeze
165
165
 
@@ -291,7 +291,7 @@ module Sinatra
291
291
  elsif value
292
292
  # Rack 2.0 returns a Rack::File::Iterator here instead of
293
293
  # Rack::File as it was in the previous API.
294
- unless request.head? || value.is_a?(Rack::File::Iterator) || value.is_a?(Stream)
294
+ unless request.head? || value.is_a?(Rack::Files::Iterator) || value.is_a?(Stream)
295
295
  headers.delete 'Content-Length'
296
296
  end
297
297
  response.body = value
@@ -317,7 +317,7 @@ module Sinatra
317
317
  # Generates the absolute URI for a given path in the app.
318
318
  # Takes Rack routers and reverse proxies into account.
319
319
  def uri(addr = nil, absolute = true, add_script_name = true)
320
- return addr if addr =~ /\A[a-z][a-z0-9+.\-]*:/i
320
+ return addr if addr.to_s =~ /\A[a-z][a-z0-9+.\-]*:/i
321
321
 
322
322
  uri = [host = String.new]
323
323
  if absolute
@@ -396,13 +396,20 @@ module Sinatra
396
396
  response['Content-Type'] = mime_type
397
397
  end
398
398
 
399
+ # https://html.spec.whatwg.org/#multipart-form-data
400
+ MULTIPART_FORM_DATA_REPLACEMENT_TABLE = {
401
+ '"' => '%22',
402
+ "\r" => '%0D',
403
+ "\n" => '%0A'
404
+ }.freeze
405
+
399
406
  # Set the Content-Disposition to "attachment" with the specified filename,
400
407
  # instructing the user agents to prompt to save.
401
408
  def attachment(filename = nil, disposition = :attachment)
402
409
  response['Content-Disposition'] = disposition.to_s.dup
403
410
  return unless filename
404
411
 
405
- params = format('; filename="%s"', File.basename(filename))
412
+ params = format('; filename="%s"', File.basename(filename).gsub(/["\r\n]/, MULTIPART_FORM_DATA_REPLACEMENT_TABLE))
406
413
  response['Content-Disposition'] << params
407
414
  ext = File.extname(filename)
408
415
  content_type(ext) unless response['Content-Type'] || ext.empty?
@@ -422,7 +429,7 @@ module Sinatra
422
429
 
423
430
  last_modified opts[:last_modified] if opts[:last_modified]
424
431
 
425
- file = Rack::File.new(File.dirname(settings.app_file))
432
+ file = Rack::Files.new(File.dirname(settings.app_file))
426
433
  result = file.serving(request, path)
427
434
 
428
435
  result[1].each { |k, v| headers[k] ||= v }
@@ -467,8 +474,9 @@ module Sinatra
467
474
  @back.call(self)
468
475
  rescue Exception => e
469
476
  @scheduler.schedule { raise e }
477
+ ensure
478
+ close unless @keep_open
470
479
  end
471
- close unless @keep_open
472
480
  end
473
481
  end
474
482
 
@@ -499,7 +507,16 @@ module Sinatra
499
507
  def stream(keep_open = false)
500
508
  scheduler = env['async.callback'] ? EventMachine : Stream
501
509
  current = @params.dup
502
- body Stream.new(scheduler, keep_open) { |out| with_params(current) { yield(out) } }
510
+ stream = if scheduler == Stream && keep_open
511
+ Stream.new(scheduler, false) do |out|
512
+ until out.closed?
513
+ with_params(current) { yield(out) }
514
+ end
515
+ end
516
+ else
517
+ Stream.new(scheduler, keep_open) { |out| with_params(current) { yield(out) } }
518
+ end
519
+ body stream
503
520
  end
504
521
 
505
522
  # Specify response freshness policy for HTTP caches (Cache-Control header).
@@ -709,7 +726,7 @@ module Sinatra
709
726
  # Possible options are:
710
727
  # :content_type The content type to use, same arguments as content_type.
711
728
  # :layout If set to something falsy, no layout is rendered, otherwise
712
- # the specified layout is used
729
+ # the specified layout is used (Ignored for `sass`)
713
730
  # :layout_engine Engine to use for rendering the layout.
714
731
  # :locals A hash with local variables that should be available
715
732
  # in the template
@@ -735,6 +752,20 @@ module Sinatra
735
752
  render(:haml, template, options, locals, &block)
736
753
  end
737
754
 
755
+ def sass(template, options = {}, locals = {})
756
+ options[:default_content_type] = :css
757
+ options[:exclude_outvar] = true
758
+ options[:layout] = nil
759
+ render :sass, template, options, locals
760
+ end
761
+
762
+ def scss(template, options = {}, locals = {})
763
+ options[:default_content_type] = :css
764
+ options[:exclude_outvar] = true
765
+ options[:layout] = nil
766
+ render :scss, template, options, locals
767
+ end
768
+
738
769
  def builder(template = nil, options = {}, locals = {}, &block)
739
770
  options[:default_content_type] = :xml
740
771
  render_ruby(:builder, template, options, locals, &block)
@@ -845,7 +876,11 @@ module Sinatra
845
876
  catch(:layout_missing) { return render(layout_engine, layout, options, locals) { output } }
846
877
  end
847
878
 
848
- output.extend(ContentTyped).content_type = content_type if content_type
879
+ if content_type
880
+ # sass-embedded returns a frozen string
881
+ output = +output
882
+ output.extend(ContentTyped).content_type = content_type
883
+ end
849
884
  output
850
885
  end
851
886
 
@@ -897,6 +932,35 @@ module Sinatra
897
932
  end
898
933
  end
899
934
 
935
+ # Extremely simple template cache implementation.
936
+ # * Not thread-safe.
937
+ # * Size is unbounded.
938
+ # * Keys are not copied defensively, and should not be modified after
939
+ # being passed to #fetch. More specifically, the values returned by
940
+ # key#hash and key#eql? should not change.
941
+ #
942
+ # Implementation copied from Tilt::Cache.
943
+ class TemplateCache
944
+ def initialize
945
+ @cache = {}
946
+ end
947
+
948
+ # Caches a value for key, or returns the previously cached value.
949
+ # If a value has been previously cached for key then it is
950
+ # returned. Otherwise, block is yielded to and its return value
951
+ # which may be nil, is cached under key and returned.
952
+ def fetch(*key)
953
+ @cache.fetch(key) do
954
+ @cache[key] = yield
955
+ end
956
+ end
957
+
958
+ # Clears the cache.
959
+ def clear
960
+ @cache = {}
961
+ end
962
+ end
963
+
900
964
  # Base class for all Sinatra applications and middleware.
901
965
  class Base
902
966
  include Rack::Utils
@@ -911,7 +975,7 @@ module Sinatra
911
975
  def initialize(app = nil, **_kwargs)
912
976
  super()
913
977
  @app = app
914
- @template_cache = Tilt::Cache.new
978
+ @template_cache = TemplateCache.new
915
979
  @pinned_response = nil # whether a before! filter pinned the content-type
916
980
  yield self if block_given?
917
981
  end
@@ -1209,10 +1273,15 @@ module Sinatra
1209
1273
  %r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks
1210
1274
  /active_support/, # active_support require hacks
1211
1275
  %r{bundler(/(?:runtime|inline))?\.rb}, # bundler require hacks
1212
- /<internal:/ # internal in ruby >= 1.9.2
1276
+ /<internal:/, # internal in ruby >= 1.9.2
1277
+ %r{zeitwerk/kernel\.rb} # Zeitwerk kernel#require decorator
1213
1278
  ].freeze
1214
1279
 
1215
- attr_reader :routes, :filters, :templates, :errors
1280
+ attr_reader :routes, :filters, :templates, :errors, :on_start_callback, :on_stop_callback
1281
+
1282
+ def callers_to_ignore
1283
+ CALLERS_TO_IGNORE
1284
+ end
1216
1285
 
1217
1286
  # Removes all routes, filters, middleware and extension hooks from the
1218
1287
  # current class (not routes/filters/... defined by its superclass).
@@ -1401,6 +1470,14 @@ module Sinatra
1401
1470
  filters[type] << compile!(type, path, block, **options)
1402
1471
  end
1403
1472
 
1473
+ def on_start(&on_start_callback)
1474
+ @on_start_callback = on_start_callback
1475
+ end
1476
+
1477
+ def on_stop(&on_stop_callback)
1478
+ @on_stop_callback = on_stop_callback
1479
+ end
1480
+
1404
1481
  # Add a route condition. The route is considered non-matching when the
1405
1482
  # block returns false.
1406
1483
  def condition(name = "#{caller.first[/`.*'/]} condition", &block)
@@ -1408,7 +1485,7 @@ module Sinatra
1408
1485
  end
1409
1486
 
1410
1487
  def public=(value)
1411
- warn ':public is no longer used to avoid overloading Module#public, use :public_folder or :public_dir instead'
1488
+ warn_for_deprecation ':public is no longer used to avoid overloading Module#public, use :public_folder or :public_dir instead'
1412
1489
  set(:public_folder, value)
1413
1490
  end
1414
1491
 
@@ -1490,12 +1567,14 @@ module Sinatra
1490
1567
  warn '== Sinatra has ended his set (crowd applauds)' unless suppress_messages?
1491
1568
  set :running_server, nil
1492
1569
  set :handler_name, nil
1570
+
1571
+ on_stop_callback.call unless on_stop_callback.nil?
1493
1572
  end
1494
1573
 
1495
1574
  alias stop! quit!
1496
1575
 
1497
1576
  # Run the Sinatra app as a self-hosted server using
1498
- # Puma, Falcon, Mongrel, or WEBrick (in that order). If given a block, will call
1577
+ # Puma, Falcon, or WEBrick (in that order). If given a block, will call
1499
1578
  # with the constructed handler once we have taken the stage.
1500
1579
  def run!(options = {}, &block)
1501
1580
  return if running?
@@ -1577,7 +1656,7 @@ module Sinatra
1577
1656
  set :running_server, server
1578
1657
  set :handler_name, handler_name
1579
1658
  server.threaded = settings.threaded if server.respond_to? :threaded=
1580
-
1659
+ on_start_callback.call unless on_start_callback.nil?
1581
1660
  yield server if block_given?
1582
1661
  end
1583
1662
  end
@@ -1772,15 +1851,15 @@ module Sinatra
1772
1851
  end
1773
1852
 
1774
1853
  # used for deprecation warnings
1775
- def warn(message)
1776
- super message + "\n\tfrom #{cleaned_caller.first.join(':')}"
1854
+ def warn_for_deprecation(message)
1855
+ warn message + "\n\tfrom #{cleaned_caller.first.join(':')}"
1777
1856
  end
1778
1857
 
1779
1858
  # Like Kernel#caller but excluding certain magic entries
1780
1859
  def cleaned_caller(keep = 3)
1781
1860
  caller(1)
1782
1861
  .map! { |line| line.split(/:(?=\d|in )/, 3)[0, keep] }
1783
- .reject { |file, *_| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
1862
+ .reject { |file, *_| callers_to_ignore.any? { |pattern| file =~ pattern } }
1784
1863
  end
1785
1864
  end
1786
1865
 
@@ -1826,8 +1905,9 @@ module Sinatra
1826
1905
  begin
1827
1906
  require 'securerandom'
1828
1907
  set :session_secret, SecureRandom.hex(64)
1829
- rescue LoadError, NotImplementedError
1908
+ rescue LoadError, NotImplementedError, RuntimeError
1830
1909
  # SecureRandom raises a NotImplementedError if no random device is available
1910
+ # RuntimeError raised due to broken openssl backend: https://bugs.ruby-lang.org/issues/19230
1831
1911
  set :session_secret, format('%064x', Kernel.rand((2**256) - 1))
1832
1912
  end
1833
1913
 
@@ -1847,11 +1927,10 @@ module Sinatra
1847
1927
 
1848
1928
  ruby_engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
1849
1929
 
1850
- server.unshift 'puma'
1851
- server.unshift 'falcon' if ruby_engine != 'jruby'
1852
- server.unshift 'mongrel' if ruby_engine.nil?
1853
1930
  server.unshift 'thin' if ruby_engine != 'jruby'
1931
+ server.unshift 'falcon' if ruby_engine != 'jruby'
1854
1932
  server.unshift 'trinidad' if ruby_engine == 'jruby'
1933
+ server.unshift 'puma'
1855
1934
 
1856
1935
  set :absolute_redirects, true
1857
1936
  set :prefixed_redirects, false
@@ -1968,7 +2047,7 @@ module Sinatra
1968
2047
  delegate :get, :patch, :put, :post, :delete, :head, :options, :link, :unlink,
1969
2048
  :template, :layout, :before, :after, :error, :not_found, :configure,
1970
2049
  :set, :mime_type, :enable, :disable, :use, :development?, :test?,
1971
- :production?, :helpers, :settings, :register
2050
+ :production?, :helpers, :settings, :register, :on_start, :on_stop
1972
2051
 
1973
2052
  class << self
1974
2053
  attr_accessor :target
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sinatra
4
- VERSION = '3.0.0'
4
+ VERSION = '3.1.0'
5
5
  end
data/sinatra.gemspec CHANGED
@@ -36,7 +36,7 @@ RubyGems 2.0 or newer is required to protect against public gem pushes. You can
36
36
 
37
37
  s.metadata = {
38
38
  'source_code_uri' => 'https://github.com/sinatra/sinatra',
39
- 'changelog_uri' => 'https://github.com/sinatra/sinatra/blob/master/CHANGELOG.md',
39
+ 'changelog_uri' => 'https://github.com/sinatra/sinatra/blob/main/CHANGELOG.md',
40
40
  'homepage_uri' => 'http://sinatrarb.com/',
41
41
  'bug_tracker_uri' => 'https://github.com/sinatra/sinatra/issues',
42
42
  'mailing_list_uri' => 'http://groups.google.com/group/sinatrarb',
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blake Mizerany
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2022-09-26 00:00:00.000000000 Z
14
+ date: 2023-08-07 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: mustermann
@@ -53,14 +53,14 @@ dependencies:
53
53
  requirements:
54
54
  - - '='
55
55
  - !ruby/object:Gem::Version
56
- version: 3.0.0
56
+ version: 3.1.0
57
57
  type: :runtime
58
58
  prerelease: false
59
59
  version_requirements: !ruby/object:Gem::Requirement
60
60
  requirements:
61
61
  - - '='
62
62
  - !ruby/object:Gem::Version
63
- version: 3.0.0
63
+ version: 3.1.0
64
64
  - !ruby/object:Gem::Dependency
65
65
  name: tilt
66
66
  requirement: !ruby/object:Gem::Requirement
@@ -110,6 +110,7 @@ files:
110
110
  - SECURITY.md
111
111
  - VERSION
112
112
  - examples/chat.rb
113
+ - examples/lifecycle_events.rb
113
114
  - examples/rainbows.conf
114
115
  - examples/rainbows.rb
115
116
  - examples/simple.rb
@@ -128,7 +129,7 @@ licenses:
128
129
  - MIT
129
130
  metadata:
130
131
  source_code_uri: https://github.com/sinatra/sinatra
131
- changelog_uri: https://github.com/sinatra/sinatra/blob/master/CHANGELOG.md
132
+ changelog_uri: https://github.com/sinatra/sinatra/blob/main/CHANGELOG.md
132
133
  homepage_uri: http://sinatrarb.com/
133
134
  bug_tracker_uri: https://github.com/sinatra/sinatra/issues
134
135
  mailing_list_uri: http://groups.google.com/group/sinatrarb
@@ -154,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
155
  - !ruby/object:Gem::Version
155
156
  version: '0'
156
157
  requirements: []
157
- rubygems_version: 3.2.3
158
+ rubygems_version: 3.4.18
158
159
  signing_key:
159
160
  specification_version: 4
160
161
  summary: Classy web-development dressed in a DSL