sinatra 3.0.4 → 3.1.0

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7596f4ab9a68b8aeebf1a916c1cd752a3e7dd2714dd7fa09b8def139f5b2b8f9
4
- data.tar.gz: 38ee8094ab7b9bf06a30c4bbefa2b915af6a8c1d1c4c2ec4b97918e07e8dce25
3
+ metadata.gz: 315dee3d85d7778ffa48e041bd60370e9e89ecd3c01dbf0cf9450e41c62dc0d8
4
+ data.tar.gz: '083a914c0b520684471e2715ec091c67ca8121bfb8b5d4cf410307d6e14e4ac5'
5
5
  SHA512:
6
- metadata.gz: 1f2f27088c9dfb616693cbac0bfc80a2c831e8c4126c3fc86d9b9888e0b5a20bab767d0120a1ef1045466e7d4228d265503b91cb23e2c4502d5dea494017cbda
7
- data.tar.gz: 1e941fdfd3658202725a247ca4d363fb2d2026a9aa1176f61ca170620317e75dccca16b702ca377f65169a8633e43e9c724076581777e46a13e053b717b8212e
6
+ metadata.gz: 2790a4d58595f0f89667c5fd4530dde2de532ddaf02628f373162cc47d393732b1c9475ab59775c756750dfb52e60e7091118936ac8e70739fb266b46f82d3bd
7
+ data.tar.gz: eb74f34bf0b9a681557809c656754312eb266e66c3b68fcabbf95699c3273cf4d998e3969224b09df9127ff90f5d34fba5bc93b1ff0c321b4a7646ddfcc0b6b7
data/CHANGELOG.md CHANGED
@@ -2,6 +2,40 @@
2
2
 
3
3
  * _Your new feature here._
4
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
+
5
39
  ## 3.0.4 / 2022-11-25
6
40
 
7
41
  * Fix: Escape filename in the Content-Disposition header. [#1841](https://github.com/sinatra/sinatra/pull/1841) by Kunpei Sakai
@@ -66,6 +100,12 @@
66
100
 
67
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
68
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
+
69
109
  ## 2.2.2 / 2022-07-23
70
110
 
71
111
  * Update mustermann dependency to version 2.
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,12 +15,12 @@ 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 == 'latest'
18
+ rack_version = { github: 'rack/rack' } if rack_version == 'head'
19
19
  gem 'rack', rack_version
20
20
 
21
21
  puma_version = ENV['puma'].to_s
22
22
  puma_version = nil if puma_version.empty? || (puma_version == 'stable')
23
- puma_version = { github: 'puma/puma' } if puma_version == 'latest'
23
+ puma_version = { github: 'puma/puma' } if puma_version == 'head'
24
24
  gem 'puma', puma_version
25
25
 
26
26
  gem 'minitest', '~> 5.0'
@@ -31,6 +31,12 @@ gem 'yard'
31
31
  gem 'rack-protection', path: 'rack-protection'
32
32
  gem 'sinatra-contrib', path: 'sinatra-contrib'
33
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
+
34
40
  gem 'activesupport', '~> 6.1'
35
41
 
36
42
  gem 'asciidoctor'
@@ -39,7 +45,7 @@ gem 'commonmarker', '~> 0.23.4', platforms: [:ruby]
39
45
  gem 'erubi'
40
46
  gem 'eventmachine'
41
47
  gem 'falcon', '~> 0.40', platforms: [:ruby]
42
- gem 'haml', '~> 5'
48
+ gem 'haml', '~> 6'
43
49
  gem 'kramdown'
44
50
  gem 'liquid'
45
51
  gem 'markaby'
@@ -50,6 +56,7 @@ gem 'rainbows', platforms: [:mri] # uses #fork
50
56
  gem 'rdiscount', platforms: [:ruby]
51
57
  gem 'rdoc'
52
58
  gem 'redcarpet', platforms: [:ruby]
59
+ gem 'sass-embedded', '~> 1.54'
53
60
  gem 'simplecov', require: false
54
61
  gem 'slim', '~> 4'
55
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
 
@@ -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/)
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/)
2906
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
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.4
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
@@ -429,7 +429,7 @@ module Sinatra
429
429
 
430
430
  last_modified opts[:last_modified] if opts[:last_modified]
431
431
 
432
- file = Rack::File.new(File.dirname(settings.app_file))
432
+ file = Rack::Files.new(File.dirname(settings.app_file))
433
433
  result = file.serving(request, path)
434
434
 
435
435
  result[1].each { |k, v| headers[k] ||= v }
@@ -474,8 +474,9 @@ module Sinatra
474
474
  @back.call(self)
475
475
  rescue Exception => e
476
476
  @scheduler.schedule { raise e }
477
+ ensure
478
+ close unless @keep_open
477
479
  end
478
- close unless @keep_open
479
480
  end
480
481
  end
481
482
 
@@ -506,7 +507,16 @@ module Sinatra
506
507
  def stream(keep_open = false)
507
508
  scheduler = env['async.callback'] ? EventMachine : Stream
508
509
  current = @params.dup
509
- 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
510
520
  end
511
521
 
512
522
  # Specify response freshness policy for HTTP caches (Cache-Control header).
@@ -716,7 +726,7 @@ module Sinatra
716
726
  # Possible options are:
717
727
  # :content_type The content type to use, same arguments as content_type.
718
728
  # :layout If set to something falsy, no layout is rendered, otherwise
719
- # the specified layout is used
729
+ # the specified layout is used (Ignored for `sass`)
720
730
  # :layout_engine Engine to use for rendering the layout.
721
731
  # :locals A hash with local variables that should be available
722
732
  # in the template
@@ -742,6 +752,20 @@ module Sinatra
742
752
  render(:haml, template, options, locals, &block)
743
753
  end
744
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
+
745
769
  def builder(template = nil, options = {}, locals = {}, &block)
746
770
  options[:default_content_type] = :xml
747
771
  render_ruby(:builder, template, options, locals, &block)
@@ -852,7 +876,11 @@ module Sinatra
852
876
  catch(:layout_missing) { return render(layout_engine, layout, options, locals) { output } }
853
877
  end
854
878
 
855
- 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
856
884
  output
857
885
  end
858
886
 
@@ -904,6 +932,35 @@ module Sinatra
904
932
  end
905
933
  end
906
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
+
907
964
  # Base class for all Sinatra applications and middleware.
908
965
  class Base
909
966
  include Rack::Utils
@@ -918,7 +975,7 @@ module Sinatra
918
975
  def initialize(app = nil, **_kwargs)
919
976
  super()
920
977
  @app = app
921
- @template_cache = Tilt::Cache.new
978
+ @template_cache = TemplateCache.new
922
979
  @pinned_response = nil # whether a before! filter pinned the content-type
923
980
  yield self if block_given?
924
981
  end
@@ -1216,10 +1273,15 @@ module Sinatra
1216
1273
  %r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks
1217
1274
  /active_support/, # active_support require hacks
1218
1275
  %r{bundler(/(?:runtime|inline))?\.rb}, # bundler require hacks
1219
- /<internal:/ # internal in ruby >= 1.9.2
1276
+ /<internal:/, # internal in ruby >= 1.9.2
1277
+ %r{zeitwerk/kernel\.rb} # Zeitwerk kernel#require decorator
1220
1278
  ].freeze
1221
1279
 
1222
- 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
1223
1285
 
1224
1286
  # Removes all routes, filters, middleware and extension hooks from the
1225
1287
  # current class (not routes/filters/... defined by its superclass).
@@ -1408,6 +1470,14 @@ module Sinatra
1408
1470
  filters[type] << compile!(type, path, block, **options)
1409
1471
  end
1410
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
+
1411
1481
  # Add a route condition. The route is considered non-matching when the
1412
1482
  # block returns false.
1413
1483
  def condition(name = "#{caller.first[/`.*'/]} condition", &block)
@@ -1497,12 +1567,14 @@ module Sinatra
1497
1567
  warn '== Sinatra has ended his set (crowd applauds)' unless suppress_messages?
1498
1568
  set :running_server, nil
1499
1569
  set :handler_name, nil
1570
+
1571
+ on_stop_callback.call unless on_stop_callback.nil?
1500
1572
  end
1501
1573
 
1502
1574
  alias stop! quit!
1503
1575
 
1504
1576
  # Run the Sinatra app as a self-hosted server using
1505
- # 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
1506
1578
  # with the constructed handler once we have taken the stage.
1507
1579
  def run!(options = {}, &block)
1508
1580
  return if running?
@@ -1584,7 +1656,7 @@ module Sinatra
1584
1656
  set :running_server, server
1585
1657
  set :handler_name, handler_name
1586
1658
  server.threaded = settings.threaded if server.respond_to? :threaded=
1587
-
1659
+ on_start_callback.call unless on_start_callback.nil?
1588
1660
  yield server if block_given?
1589
1661
  end
1590
1662
  end
@@ -1787,7 +1859,7 @@ module Sinatra
1787
1859
  def cleaned_caller(keep = 3)
1788
1860
  caller(1)
1789
1861
  .map! { |line| line.split(/:(?=\d|in )/, 3)[0, keep] }
1790
- .reject { |file, *_| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
1862
+ .reject { |file, *_| callers_to_ignore.any? { |pattern| file =~ pattern } }
1791
1863
  end
1792
1864
  end
1793
1865
 
@@ -1833,8 +1905,9 @@ module Sinatra
1833
1905
  begin
1834
1906
  require 'securerandom'
1835
1907
  set :session_secret, SecureRandom.hex(64)
1836
- rescue LoadError, NotImplementedError
1908
+ rescue LoadError, NotImplementedError, RuntimeError
1837
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
1838
1911
  set :session_secret, format('%064x', Kernel.rand((2**256) - 1))
1839
1912
  end
1840
1913
 
@@ -1854,11 +1927,10 @@ module Sinatra
1854
1927
 
1855
1928
  ruby_engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
1856
1929
 
1857
- server.unshift 'puma'
1858
- server.unshift 'falcon' if ruby_engine != 'jruby'
1859
- server.unshift 'mongrel' if ruby_engine.nil?
1860
1930
  server.unshift 'thin' if ruby_engine != 'jruby'
1931
+ server.unshift 'falcon' if ruby_engine != 'jruby'
1861
1932
  server.unshift 'trinidad' if ruby_engine == 'jruby'
1933
+ server.unshift 'puma'
1862
1934
 
1863
1935
  set :absolute_redirects, true
1864
1936
  set :prefixed_redirects, false
@@ -1975,7 +2047,7 @@ module Sinatra
1975
2047
  delegate :get, :patch, :put, :post, :delete, :head, :options, :link, :unlink,
1976
2048
  :template, :layout, :before, :after, :error, :not_found, :configure,
1977
2049
  :set, :mime_type, :enable, :disable, :use, :development?, :test?,
1978
- :production?, :helpers, :settings, :register
2050
+ :production?, :helpers, :settings, :register, :on_start, :on_stop
1979
2051
 
1980
2052
  class << self
1981
2053
  attr_accessor :target
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sinatra
4
- VERSION = '3.0.3'
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.4
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-11-25 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.4
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.4
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