sinatra 2.0.7 → 3.0.6

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.
data/README.md CHANGED
@@ -1,8 +1,7 @@
1
1
  # Sinatra
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/sinatra.svg)](http://badge.fury.io/rb/sinatra)
4
- [![Build Status](https://secure.travis-ci.org/sinatra/sinatra.svg)](https://travis-ci.org/sinatra/sinatra)
5
- [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=sinatra&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=sinatra&package-manager=bundler&version-scheme=semver)
3
+ [![Gem Version](https://badge.fury.io/rb/sinatra.svg)](https://badge.fury.io/rb/sinatra)
4
+ [![Testing](https://github.com/sinatra/sinatra/actions/workflows/test.yml/badge.svg)](https://github.com/sinatra/sinatra/actions/workflows/test.yml)
6
5
 
7
6
  Sinatra is a [DSL](https://en.wikipedia.org/wiki/Domain-specific_language) for
8
7
  quickly creating web applications in Ruby with minimal effort:
@@ -20,6 +19,7 @@ Install the gem:
20
19
 
21
20
  ```shell
22
21
  gem install sinatra
22
+ gem install puma # or any other server
23
23
  ```
24
24
 
25
25
  And run with:
@@ -31,101 +31,92 @@ ruby myapp.rb
31
31
  View at: [http://localhost:4567](http://localhost:4567)
32
32
 
33
33
  The code you changed will not take effect until you restart the server.
34
- Please restart the server every time you change or use
35
- [sinatra/reloader](http://www.sinatrarb.com/contrib/reloader).
34
+ Please restart the server every time you change or use a code reloader
35
+ like [rerun](https://github.com/alexch/rerun) or
36
+ [rack-unreloader](https://github.com/jeremyevans/rack-unreloader).
36
37
 
37
- It is recommended to also run `gem install thin`, which Sinatra will
38
+ It is recommended to also run `gem install puma`, which Sinatra will
38
39
  pick up if available.
39
40
 
40
41
  ## Table of Contents
41
42
 
42
- * [Sinatra](#sinatra)
43
- * [Table of Contents](#table-of-contents)
44
- * [Routes](#routes)
45
- * [Conditions](#conditions)
46
- * [Return Values](#return-values)
47
- * [Custom Route Matchers](#custom-route-matchers)
48
- * [Static Files](#static-files)
49
- * [Views / Templates](#views--templates)
50
- * [Literal Templates](#literal-templates)
51
- * [Available Template Languages](#available-template-languages)
52
- * [Haml Templates](#haml-templates)
53
- * [Erb Templates](#erb-templates)
54
- * [Builder Templates](#builder-templates)
55
- * [Nokogiri Templates](#nokogiri-templates)
56
- * [Sass Templates](#sass-templates)
57
- * [SCSS Templates](#scss-templates)
58
- * [Less Templates](#less-templates)
59
- * [Liquid Templates](#liquid-templates)
60
- * [Markdown Templates](#markdown-templates)
61
- * [Textile Templates](#textile-templates)
62
- * [RDoc Templates](#rdoc-templates)
63
- * [AsciiDoc Templates](#asciidoc-templates)
64
- * [Radius Templates](#radius-templates)
65
- * [Markaby Templates](#markaby-templates)
66
- * [RABL Templates](#rabl-templates)
67
- * [Slim Templates](#slim-templates)
68
- * [Creole Templates](#creole-templates)
69
- * [MediaWiki Templates](#mediawiki-templates)
70
- * [CoffeeScript Templates](#coffeescript-templates)
71
- * [Stylus Templates](#stylus-templates)
72
- * [Yajl Templates](#yajl-templates)
73
- * [WLang Templates](#wlang-templates)
74
- * [Accessing Variables in Templates](#accessing-variables-in-templates)
75
- * [Templates with `yield` and nested layouts](#templates-with-yield-and-nested-layouts)
76
- * [Inline Templates](#inline-templates)
77
- * [Named Templates](#named-templates)
78
- * [Associating File Extensions](#associating-file-extensions)
79
- * [Adding Your Own Template Engine](#adding-your-own-template-engine)
80
- * [Using Custom Logic for Template Lookup](#using-custom-logic-for-template-lookup)
81
- * [Filters](#filters)
82
- * [Helpers](#helpers)
83
- * [Using Sessions](#using-sessions)
84
- * [Session Secret Security](#session-secret-security)
85
- * [Session Config](#session-config)
86
- * [Choosing Your Own Session Middleware](#choosing-your-own-session-middleware)
87
- * [Halting](#halting)
88
- * [Passing](#passing)
89
- * [Triggering Another Route](#triggering-another-route)
90
- * [Setting Body, Status Code and Headers](#setting-body-status-code-and-headers)
91
- * [Streaming Responses](#streaming-responses)
92
- * [Logging](#logging)
93
- * [Mime Types](#mime-types)
94
- * [Generating URLs](#generating-urls)
95
- * [Browser Redirect](#browser-redirect)
96
- * [Cache Control](#cache-control)
97
- * [Sending Files](#sending-files)
98
- * [Accessing the Request Object](#accessing-the-request-object)
99
- * [Attachments](#attachments)
100
- * [Dealing with Date and Time](#dealing-with-date-and-time)
101
- * [Looking Up Template Files](#looking-up-template-files)
102
- * [Configuration](#configuration)
103
- * [Configuring attack protection](#configuring-attack-protection)
104
- * [Available Settings](#available-settings)
105
- * [Environments](#environments)
106
- * [Error Handling](#error-handling)
107
- * [Not Found](#not-found)
108
- * [Error](#error)
109
- * [Rack Middleware](#rack-middleware)
110
- * [Testing](#testing)
111
- * [Sinatra::Base - Middleware, Libraries, and Modular Apps](#sinatrabase---middleware-libraries-and-modular-apps)
112
- * [Modular vs. Classic Style](#modular-vs-classic-style)
113
- * [Serving a Modular Application](#serving-a-modular-application)
114
- * [Using a Classic Style Application with a config.ru](#using-a-classic-style-application-with-a-configru)
115
- * [When to use a config.ru?](#when-to-use-a-configru)
116
- * [Using Sinatra as Middleware](#using-sinatra-as-middleware)
117
- * [Dynamic Application Creation](#dynamic-application-creation)
118
- * [Scopes and Binding](#scopes-and-binding)
119
- * [Application/Class Scope](#applicationclass-scope)
120
- * [Request/Instance Scope](#requestinstance-scope)
121
- * [Delegation Scope](#delegation-scope)
122
- * [Command Line](#command-line)
123
- * [Multi-threading](#multi-threading)
124
- * [Requirement](#requirement)
125
- * [The Bleeding Edge](#the-bleeding-edge)
126
- * [With Bundler](#with-bundler)
127
- * [Versioning](#versioning)
128
- * [Further Reading](#further-reading)
43
+ - [Sinatra](#sinatra)
44
+ - [Table of Contents](#table-of-contents)
45
+ - [Routes](#routes)
46
+ - [Conditions](#conditions)
47
+ - [Return Values](#return-values)
48
+ - [Custom Route Matchers](#custom-route-matchers)
49
+ - [Static Files](#static-files)
50
+ - [Views / Templates](#views--templates)
51
+ - [Literal Templates](#literal-templates)
52
+ - [Available Template Languages](#available-template-languages)
53
+ - [Haml Templates](#haml-templates)
54
+ - [Erb Templates](#erb-templates)
55
+ - [Builder Templates](#builder-templates)
56
+ - [Nokogiri Templates](#nokogiri-templates)
57
+ - [Liquid Templates](#liquid-templates)
58
+ - [Markdown Templates](#markdown-templates)
59
+ - [RDoc Templates](#rdoc-templates)
60
+ - [AsciiDoc Templates](#asciidoc-templates)
61
+ - [Markaby Templates](#markaby-templates)
62
+ - [RABL Templates](#rabl-templates)
63
+ - [Slim Templates](#slim-templates)
64
+ - [Yajl Templates](#yajl-templates)
65
+ - [Accessing Variables in Templates](#accessing-variables-in-templates)
66
+ - [Templates with `yield` and nested layouts](#templates-with-yield-and-nested-layouts)
67
+ - [Inline Templates](#inline-templates)
68
+ - [Named Templates](#named-templates)
69
+ - [Associating File Extensions](#associating-file-extensions)
70
+ - [Adding Your Own Template Engine](#adding-your-own-template-engine)
71
+ - [Using Custom Logic for Template Lookup](#using-custom-logic-for-template-lookup)
72
+ - [Filters](#filters)
73
+ - [Helpers](#helpers)
74
+ - [Using Sessions](#using-sessions)
75
+ - [Session Secret Security](#session-secret-security)
76
+ - [Session Config](#session-config)
77
+ - [Choosing Your Own Session Middleware](#choosing-your-own-session-middleware)
78
+ - [Halting](#halting)
79
+ - [Passing](#passing)
80
+ - [Triggering Another Route](#triggering-another-route)
81
+ - [Setting Body, Status Code, and Headers](#setting-body-status-code-and-headers)
82
+ - [Streaming Responses](#streaming-responses)
83
+ - [Logging](#logging)
84
+ - [Mime Types](#mime-types)
85
+ - [Generating URLs](#generating-urls)
86
+ - [Browser Redirect](#browser-redirect)
87
+ - [Cache Control](#cache-control)
88
+ - [Sending Files](#sending-files)
89
+ - [Accessing the Request Object](#accessing-the-request-object)
90
+ - [Attachments](#attachments)
91
+ - [Dealing with Date and Time](#dealing-with-date-and-time)
92
+ - [Looking Up Template Files](#looking-up-template-files)
93
+ - [Configuration](#configuration)
94
+ - [Configuring attack protection](#configuring-attack-protection)
95
+ - [Available Settings](#available-settings)
96
+ - [Environments](#environments)
97
+ - [Error Handling](#error-handling)
98
+ - [Not Found](#not-found)
99
+ - [Error](#error)
100
+ - [Rack Middleware](#rack-middleware)
101
+ - [Testing](#testing)
102
+ - [Sinatra::Base - Middleware, Libraries, and Modular Apps](#sinatrabase---middleware-libraries-and-modular-apps)
103
+ - [Modular vs. Classic Style](#modular-vs-classic-style)
104
+ - [Serving a Modular Application](#serving-a-modular-application)
105
+ - [Using a Classic Style Application with a config.ru](#using-a-classic-style-application-with-a-configru)
106
+ - [When to use a config.ru?](#when-to-use-a-configru)
107
+ - [Using Sinatra as Middleware](#using-sinatra-as-middleware)
108
+ - [Dynamic Application Creation](#dynamic-application-creation)
109
+ - [Scopes and Binding](#scopes-and-binding)
110
+ - [Application/Class Scope](#applicationclass-scope)
111
+ - [Request/Instance Scope](#requestinstance-scope)
112
+ - [Delegation Scope](#delegation-scope)
113
+ - [Command Line](#command-line)
114
+ - [Multi-threading](#multi-threading)
115
+ - [Requirement](#requirement)
116
+ - [The Bleeding Edge](#the-bleeding-edge)
117
+ - [With Bundler](#with-bundler)
118
+ - [Versioning](#versioning)
119
+ - [Further Reading](#further-reading)
129
120
 
130
121
  ## Routes
131
122
 
@@ -344,11 +335,11 @@ end
344
335
  ## Return Values
345
336
 
346
337
  The return value of a route block determines at least the response body
347
- passed on to the HTTP client, or at least the next middleware in the
338
+ passed on to the HTTP client or at least the next middleware in the
348
339
  Rack stack. Most commonly, this is a string, as in the above examples.
349
340
  But other values are also accepted.
350
341
 
351
- You can return any object that would either be a valid Rack response, Rack
342
+ You can return an object that would either be a valid Rack response, Rack
352
343
  body object or HTTP status code:
353
344
 
354
345
  * An Array with three elements: `[status (Integer), headers (Hash), response
@@ -372,7 +363,7 @@ get('/') { Stream.new }
372
363
  ```
373
364
 
374
365
  You can also use the `stream` helper method ([described below](#streaming-responses)) to reduce
375
- boiler plate and embed the streaming logic in the route.
366
+ boilerplate and embed the streaming logic in the route.
376
367
 
377
368
  ## Custom Route Matchers
378
369
 
@@ -382,15 +373,16 @@ stop there. You can easily define your own matchers:
382
373
 
383
374
  ```ruby
384
375
  class AllButPattern
385
- Match = Struct.new(:captures)
386
-
387
376
  def initialize(except)
388
- @except = except
389
- @captures = Match.new([])
377
+ @except = except
378
+ end
379
+
380
+ def to_pattern(options)
381
+ return self
390
382
  end
391
383
 
392
- def match(str)
393
- @captures unless @except === str
384
+ def params(route)
385
+ return {} unless @except === route
394
386
  end
395
387
  end
396
388
 
@@ -407,27 +399,19 @@ Note that the above example might be over-engineered, as it can also be
407
399
  expressed as:
408
400
 
409
401
  ```ruby
410
- get // do
402
+ get /.*/ do
411
403
  pass if request.path_info == "/index"
412
404
  # ...
413
405
  end
414
406
  ```
415
407
 
416
- Or, using negative look ahead:
417
-
418
- ```ruby
419
- get %r{(?!/index)} do
420
- # ...
421
- end
422
- ```
423
-
424
408
  ## Static Files
425
409
 
426
410
  Static files are served from the `./public` directory. You can specify
427
411
  a different location by setting the `:public_folder` option:
428
412
 
429
413
  ```ruby
430
- set :public_folder, File.dirname(__FILE__) + '/static'
414
+ set :public_folder, __dir__ + '/static'
431
415
  ```
432
416
 
433
417
  Note that the public directory name is not included in the URL. A file
@@ -584,7 +568,7 @@ Some languages have multiple implementations. To specify what implementation
584
568
  to use (and to be thread-safe), you should simply require it first:
585
569
 
586
570
  ```ruby
587
- require 'rdiscount' # or require 'bluecloth'
571
+ require 'rdiscount'
588
572
  get('/') { markdown :index }
589
573
  ```
590
574
 
@@ -612,14 +596,12 @@ get('/') { markdown :index }
612
596
  <td>Dependency</td>
613
597
  <td>
614
598
  <a href="https://github.com/jeremyevans/erubi" title="erubi">erubi</a>
615
- or <a href="http://www.kuwata-lab.com/erubis/" title="erubis">erubis</a>
616
599
  or erb (included in Ruby)
617
600
  </td>
618
601
  </tr>
619
602
  <tr>
620
603
  <td>File Extensions</td>
621
- <td><tt>.erb</tt>, <tt>.rhtml</tt> or <tt>.erubi</tt> (Erubi only)
622
- or <tt>.erubis</tt> (Erubis only)</td>
604
+ <td><tt>.erb</tt>, <tt>.rhtml</tt> or <tt>.erubi</tt> (Erubi only)</td>
623
605
  </tr>
624
606
  <tr>
625
607
  <td>Example</td>
@@ -667,56 +649,6 @@ It also takes a block for inline templates (see [example](#inline-templates)).
667
649
 
668
650
  It also takes a block for inline templates (see [example](#inline-templates)).
669
651
 
670
- #### Sass Templates
671
-
672
- <table>
673
- <tr>
674
- <td>Dependency</td>
675
- <td><a href="https://sass-lang.com/" title="sass">sass</a></td>
676
- </tr>
677
- <tr>
678
- <td>File Extension</td>
679
- <td><tt>.sass</tt></td>
680
- </tr>
681
- <tr>
682
- <td>Example</td>
683
- <td><tt>sass :stylesheet, :style => :expanded</tt></td>
684
- </tr>
685
- </table>
686
-
687
- #### SCSS Templates
688
-
689
- <table>
690
- <tr>
691
- <td>Dependency</td>
692
- <td><a href="https://sass-lang.com/" title="sass">sass</a></td>
693
- </tr>
694
- <tr>
695
- <td>File Extension</td>
696
- <td><tt>.scss</tt></td>
697
- </tr>
698
- <tr>
699
- <td>Example</td>
700
- <td><tt>scss :stylesheet, :style => :expanded</tt></td>
701
- </tr>
702
- </table>
703
-
704
- #### Less Templates
705
-
706
- <table>
707
- <tr>
708
- <td>Dependency</td>
709
- <td><a href="http://lesscss.org/" title="less">less</a></td>
710
- </tr>
711
- <tr>
712
- <td>File Extension</td>
713
- <td><tt>.less</tt></td>
714
- </tr>
715
- <tr>
716
- <td>Example</td>
717
- <td><tt>less :stylesheet</tt></td>
718
- </tr>
719
- </table>
720
652
 
721
653
  #### Liquid Templates
722
654
 
@@ -747,9 +679,7 @@ template, you almost always want to pass locals to it.
747
679
  Anyone of:
748
680
  <a href="https://github.com/davidfstr/rdiscount" title="RDiscount">RDiscount</a>,
749
681
  <a href="https://github.com/vmg/redcarpet" title="RedCarpet">RedCarpet</a>,
750
- <a href="https://github.com/ged/bluecloth" title="BlueCloth">BlueCloth</a>,
751
682
  <a href="https://kramdown.gettalong.org/" title="kramdown">kramdown</a>,
752
- <a href="https://github.com/bhollis/maruku" title="maruku">maruku</a>
753
683
  <a href="https://github.com/gjtorikian/commonmarker" title="commonmarker">commonmarker</a>
754
684
  <a href="https://github.com/alphabetum/pandoc-ruby" title="pandoc">pandoc</a>
755
685
  </td>
@@ -784,42 +714,6 @@ Since you cannot call Ruby from Markdown, you cannot use layouts written in
784
714
  Markdown. However, it is possible to use another rendering engine for the
785
715
  template than for the layout by passing the `:layout_engine` option.
786
716
 
787
- #### Textile Templates
788
-
789
- <table>
790
- <tr>
791
- <td>Dependency</td>
792
- <td><a href="http://redcloth.org/" title="RedCloth">RedCloth</a></td>
793
- </tr>
794
- <tr>
795
- <td>File Extension</td>
796
- <td><tt>.textile</tt></td>
797
- </tr>
798
- <tr>
799
- <td>Example</td>
800
- <td><tt>textile :index, :layout_engine => :erb</tt></td>
801
- </tr>
802
- </table>
803
-
804
- It is not possible to call methods from Textile, nor to pass locals to
805
- it. You therefore will usually use it in combination with another
806
- rendering engine:
807
-
808
- ```ruby
809
- erb :overview, :locals => { :text => textile(:introduction) }
810
- ```
811
-
812
- Note that you may also call the `textile` method from within other templates:
813
-
814
- ```ruby
815
- %h1 Hello From Haml!
816
- %p= textile(:greetings)
817
- ```
818
-
819
- Since you cannot call Ruby from Textile, you cannot use layouts written in
820
- Textile. However, it is possible to use another rendering engine for the
821
- template than for the layout by passing the `:layout_engine` option.
822
-
823
717
  #### RDoc Templates
824
718
 
825
719
  <table>
@@ -875,26 +769,6 @@ template than for the layout by passing the `:layout_engine` option.
875
769
  Since you cannot call Ruby methods directly from an AsciiDoc template, you
876
770
  almost always want to pass locals to it.
877
771
 
878
- #### Radius Templates
879
-
880
- <table>
881
- <tr>
882
- <td>Dependency</td>
883
- <td><a href="https://github.com/jlong/radius" title="Radius">Radius</a></td>
884
- </tr>
885
- <tr>
886
- <td>File Extension</td>
887
- <td><tt>.radius</tt></td>
888
- </tr>
889
- <tr>
890
- <td>Example</td>
891
- <td><tt>radius :index, :locals => { :key => 'value' }</tt></td>
892
- </tr>
893
- </table>
894
-
895
- Since you cannot call Ruby methods directly from a Radius template, you
896
- almost always want to pass locals to it.
897
-
898
772
  #### Markaby Templates
899
773
 
900
774
  <table>
@@ -948,139 +822,6 @@ It also takes a block for inline templates (see [example](#inline-templates)).
948
822
  </tr>
949
823
  </table>
950
824
 
951
- #### Creole Templates
952
-
953
- <table>
954
- <tr>
955
- <td>Dependency</td>
956
- <td><a href="https://github.com/minad/creole" title="Creole">Creole</a></td>
957
- </tr>
958
- <tr>
959
- <td>File Extension</td>
960
- <td><tt>.creole</tt></td>
961
- </tr>
962
- <tr>
963
- <td>Example</td>
964
- <td><tt>creole :wiki, :layout_engine => :erb</tt></td>
965
- </tr>
966
- </table>
967
-
968
- It is not possible to call methods from Creole, nor to pass locals to it. You
969
- therefore will usually use it in combination with another rendering engine:
970
-
971
- ```ruby
972
- erb :overview, :locals => { :text => creole(:introduction) }
973
- ```
974
-
975
- Note that you may also call the `creole` method from within other templates:
976
-
977
- ```ruby
978
- %h1 Hello From Haml!
979
- %p= creole(:greetings)
980
- ```
981
-
982
- Since you cannot call Ruby from Creole, you cannot use layouts written in
983
- Creole. However, it is possible to use another rendering engine for the
984
- template than for the layout by passing the `:layout_engine` option.
985
-
986
- #### MediaWiki Templates
987
-
988
- <table>
989
- <tr>
990
- <td>Dependency</td>
991
- <td><a href="https://github.com/nricciar/wikicloth" title="WikiCloth">WikiCloth</a></td>
992
- </tr>
993
- <tr>
994
- <td>File Extension</td>
995
- <td><tt>.mediawiki</tt> and <tt>.mw</tt></td>
996
- </tr>
997
- <tr>
998
- <td>Example</td>
999
- <td><tt>mediawiki :wiki, :layout_engine => :erb</tt></td>
1000
- </tr>
1001
- </table>
1002
-
1003
- It is not possible to call methods from MediaWiki markup, nor to pass
1004
- locals to it. You therefore will usually use it in combination with
1005
- another rendering engine:
1006
-
1007
- ```ruby
1008
- erb :overview, :locals => { :text => mediawiki(:introduction) }
1009
- ```
1010
-
1011
- Note that you may also call the `mediawiki` method from within other
1012
- templates:
1013
-
1014
- ```ruby
1015
- %h1 Hello From Haml!
1016
- %p= mediawiki(:greetings)
1017
- ```
1018
-
1019
- Since you cannot call Ruby from MediaWiki, you cannot use layouts written in
1020
- MediaWiki. However, it is possible to use another rendering engine for the
1021
- template than for the layout by passing the `:layout_engine` option.
1022
-
1023
- #### CoffeeScript Templates
1024
-
1025
- <table>
1026
- <tr>
1027
- <td>Dependency</td>
1028
- <td>
1029
- <a href="https://github.com/josh/ruby-coffee-script" title="Ruby CoffeeScript">
1030
- CoffeeScript
1031
- </a> and a
1032
- <a href="https://github.com/sstephenson/execjs" title="ExecJS">
1033
- way to execute javascript
1034
- </a>
1035
- </td>
1036
- </tr>
1037
- <tr>
1038
- <td>File Extension</td>
1039
- <td><tt>.coffee</tt></td>
1040
- </tr>
1041
- <tr>
1042
- <td>Example</td>
1043
- <td><tt>coffee :index</tt></td>
1044
- </tr>
1045
- </table>
1046
-
1047
- #### Stylus Templates
1048
-
1049
- <table>
1050
- <tr>
1051
- <td>Dependency</td>
1052
- <td>
1053
- <a href="https://github.com/forgecrafted/ruby-stylus" title="Ruby Stylus">
1054
- Stylus
1055
- </a> and a
1056
- <a href="https://github.com/sstephenson/execjs" title="ExecJS">
1057
- way to execute javascript
1058
- </a>
1059
- </td>
1060
- </tr>
1061
- <tr>
1062
- <td>File Extension</td>
1063
- <td><tt>.styl</tt></td>
1064
- </tr>
1065
- <tr>
1066
- <td>Example</td>
1067
- <td><tt>stylus :index</tt></td>
1068
- </tr>
1069
- </table>
1070
-
1071
- Before being able to use Stylus templates, you need to load `stylus` and
1072
- `stylus/tilt` first:
1073
-
1074
- ```ruby
1075
- require 'sinatra'
1076
- require 'stylus'
1077
- require 'stylus/tilt'
1078
-
1079
- get '/' do
1080
- stylus :example
1081
- end
1082
- ```
1083
-
1084
825
  #### Yajl Templates
1085
826
 
1086
827
  <table>
@@ -1122,27 +863,6 @@ var resource = {"foo":"bar","baz":"qux"};
1122
863
  present(resource);
1123
864
  ```
1124
865
 
1125
- #### WLang Templates
1126
-
1127
- <table>
1128
- <tr>
1129
- <td>Dependency</td>
1130
- <td><a href="https://github.com/blambeau/wlang" title="WLang">WLang</a></td>
1131
- </tr>
1132
- <tr>
1133
- <td>File Extension</td>
1134
- <td><tt>.wlang</tt></td>
1135
- </tr>
1136
- <tr>
1137
- <td>Example</td>
1138
- <td><tt>wlang :index, :locals => { :key => 'value' }</tt></td>
1139
- </tr>
1140
- </table>
1141
-
1142
- Since calling ruby methods is not idiomatic in WLang, you almost always
1143
- want to pass locals to it. Layouts written in WLang and `yield` are
1144
- supported, though.
1145
-
1146
866
  ### Accessing Variables in Templates
1147
867
 
1148
868
  Templates are evaluated within the same context as route handlers. Instance
@@ -1201,7 +921,7 @@ end
1201
921
  ```
1202
922
 
1203
923
  Currently, the following rendering methods accept a block: `erb`, `haml`,
1204
- `liquid`, `slim `, `wlang`. Also the general `render` method accepts a block.
924
+ `liquid`, `slim `. Also, the general `render` method accepts a block.
1205
925
 
1206
926
  ### Inline Templates
1207
927
 
@@ -1218,13 +938,13 @@ __END__
1218
938
 
1219
939
  @@ layout
1220
940
  %html
1221
- = yield
941
+ != yield
1222
942
 
1223
943
  @@ index
1224
944
  %div.title Hello world.
1225
945
  ```
1226
946
 
1227
- NOTE: Inline templates defined in the source file that requires sinatra are
947
+ NOTE: Inline templates defined in the source file that requires Sinatra are
1228
948
  automatically loaded. Call `enable :inline_templates` explicitly if you
1229
949
  have inline templates in other source files.
1230
950
 
@@ -1261,10 +981,10 @@ end
1261
981
 
1262
982
  To associate a file extension with a template engine, use
1263
983
  `Tilt.register`. For instance, if you like to use the file extension
1264
- `tt` for Textile templates, you can do the following:
984
+ `tt` for Haml templates, you can do the following:
1265
985
 
1266
986
  ```ruby
1267
- Tilt.register :tt, Tilt[:textile]
987
+ Tilt.register Tilt[:haml], :tt
1268
988
  ```
1269
989
 
1270
990
  ### Adding Your Own Template Engine
@@ -1272,7 +992,7 @@ Tilt.register :tt, Tilt[:textile]
1272
992
  First, register your engine with Tilt, then create a rendering method:
1273
993
 
1274
994
  ```ruby
1275
- Tilt.register :myat, MyAwesomeTemplateEngine
995
+ Tilt.register MyAwesomeTemplateEngine, :myat
1276
996
 
1277
997
  helpers do
1278
998
  def myat(*args) render(:myat, *args) end
@@ -1293,7 +1013,7 @@ own `#find_template` method:
1293
1013
 
1294
1014
  ```ruby
1295
1015
  configure do
1296
- set :views [ './views/a', './views/b' ]
1016
+ set :views, [ './views/a', './views/b' ]
1297
1017
  end
1298
1018
 
1299
1019
  def find_template(views, name, engine, &block)
@@ -1434,7 +1154,7 @@ For better security and usability it's
1434
1154
  secret and store it in an environment variable on each host running your
1435
1155
  application so that all of your application instances will share the same
1436
1156
  secret. You should periodically rotate this session secret to a new value.
1437
- Here are some examples of how you might create a 64 byte secret and set it:
1157
+ Here are some examples of how you might create a 64-byte secret and set it:
1438
1158
 
1439
1159
  **Session Secret Generation**
1440
1160
 
@@ -1446,7 +1166,7 @@ $ ruby -e "require 'securerandom'; puts SecureRandom.hex(64)"
1446
1166
  **Session Secret Generation (Bonus Points)**
1447
1167
 
1448
1168
  Use the [sysrandom gem](https://github.com/cryptosphere/sysrandom#readme) to
1449
- prefer use of system RNG facilities to generate random values instead of
1169
+ use the system RNG facilities to generate random values instead of
1450
1170
  userspace `OpenSSL` which MRI Ruby currently defaults to:
1451
1171
 
1452
1172
  ```text
@@ -1472,7 +1192,7 @@ purposes only:
1472
1192
 
1473
1193
  **Session Secret App Config**
1474
1194
 
1475
- Setup your app config to fail-safe to a secure random secret
1195
+ Set up your app config to fail-safe to a secure random secret
1476
1196
  if the `SESSION_SECRET` environment variable is not available.
1477
1197
 
1478
1198
  For bonus points use the [sysrandom
@@ -1593,7 +1313,7 @@ matching route. If no matching route is found, a 404 is returned.
1593
1313
 
1594
1314
  ### Triggering Another Route
1595
1315
 
1596
- Sometimes `pass` is not what you want, instead you would like to get the
1316
+ Sometimes `pass` is not what you want, instead, you would like to get the
1597
1317
  result of calling another route. Simply use `call` to achieve this:
1598
1318
 
1599
1319
  ```ruby
@@ -1616,13 +1336,13 @@ than a duplicate, use `call!` instead of `call`.
1616
1336
 
1617
1337
  Check out the Rack specification if you want to learn more about `call`.
1618
1338
 
1619
- ### Setting Body, Status Code and Headers
1339
+ ### Setting Body, Status Code, and Headers
1620
1340
 
1621
1341
  It is possible and recommended to set the status code and response body with
1622
- the return value of the route block. However, in some scenarios you might
1342
+ the return value of the route block. However, in some scenarios, you might
1623
1343
  want to set the body at an arbitrary point in the execution flow. You can do
1624
1344
  so with the `body` helper method. If you do so, you can use that method from
1625
- there on to access the body:
1345
+ thereon to access the body:
1626
1346
 
1627
1347
  ```ruby
1628
1348
  get '/foo' do
@@ -1645,7 +1365,7 @@ get '/foo' do
1645
1365
  headers \
1646
1366
  "Allow" => "BREW, POST, GET, PROPFIND, WHEN",
1647
1367
  "Refresh" => "Refresh: 20; https://ietf.org/rfc/rfc2324.txt"
1648
- body "I'm a tea pot!"
1368
+ body "I'm a teapot!"
1649
1369
  end
1650
1370
  ```
1651
1371
 
@@ -1678,43 +1398,59 @@ also be used to increase throughput if some but not all content depends on a
1678
1398
  slow resource.
1679
1399
 
1680
1400
  Note that the streaming behavior, especially the number of concurrent
1681
- requests, highly depends on the web server used to serve the application.
1401
+ requests, highly depends on the webserver used to serve the application.
1682
1402
  Some servers might not even support streaming at all. If the server does not
1683
1403
  support streaming, the body will be sent all at once after the block passed
1684
1404
  to `stream` finishes executing. Streaming does not work at all with Shotgun.
1685
1405
 
1686
1406
  If the optional parameter is set to `keep_open`, it will not call `close` on
1687
1407
  the stream object, allowing you to close it at any later point in the
1688
- execution flow. This only works on evented servers, like Thin and Rainbows.
1408
+ execution flow. This only works on evented servers, like Rainbows.
1689
1409
  Other servers will still close the stream:
1690
1410
 
1691
1411
  ```ruby
1692
- # long polling
1693
-
1694
- set :server, :thin
1695
- connections = []
1412
+ # config.ru
1413
+ require 'sinatra/base'
1696
1414
 
1697
- get '/subscribe' do
1698
- # register a client's interest in server events
1699
- stream(:keep_open) do |out|
1700
- connections << out
1701
- # purge dead connections
1702
- connections.reject!(&:closed?)
1415
+ class App < Sinatra::Base
1416
+ connections = []
1417
+
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
1703
1425
  end
1704
- end
1705
1426
 
1706
- post '/:message' do
1707
- connections.each do |out|
1708
- # notify client that a new message has arrived
1709
- out << params['message'] << "\n"
1427
+ post '/' do
1428
+ connections.each do |out|
1429
+ # notify client that a new message has arrived
1430
+ out << "data: #{params[:msg]}\n\n"
1710
1431
 
1711
- # indicate client to connect again
1712
- out.close
1432
+ # indicate client to connect again
1433
+ out.close
1434
+ end
1435
+
1436
+ 204 # response without entity body
1713
1437
  end
1438
+ end
1714
1439
 
1715
- # acknowledge
1716
- "message received"
1440
+ run App
1441
+ ```
1442
+
1443
+ ```ruby
1444
+ # rainbows.conf
1445
+ Rainbows! do
1446
+ use :EventMachine
1717
1447
  end
1448
+ ````
1449
+
1450
+ Run:
1451
+
1452
+ ```shell
1453
+ rainbows -c rainbows.conf
1718
1454
  ```
1719
1455
 
1720
1456
  It's also possible for the client to close the connection when trying to
@@ -1747,7 +1483,7 @@ class MyApp < Sinatra::Base
1747
1483
  end
1748
1484
  ```
1749
1485
 
1750
- To avoid any logging middleware to be set up, set the `logging` setting to
1486
+ To avoid any logging middleware to be set up, set the `logging` option to
1751
1487
  `nil`. However, keep in mind that `logger` will in that case return `nil`. A
1752
1488
  common use case is when you want to set your own logger. Sinatra will use
1753
1489
  whatever it will find in `env['rack.logger']`.
@@ -1781,7 +1517,7 @@ Haml:
1781
1517
  %a{:href => url('/foo')} foo
1782
1518
  ```
1783
1519
 
1784
- It takes reverse proxies and Rack routers into account, if present.
1520
+ It takes reverse proxies and Rack routers into account - if present.
1785
1521
 
1786
1522
  This method is also aliased to `to` (see [below](#browser-redirect) for an example).
1787
1523
 
@@ -2120,7 +1856,7 @@ end
2120
1856
  Another example would be using different directories for different engines:
2121
1857
 
2122
1858
  ```ruby
2123
- set :views, :sass => 'views/sass', :haml => 'templates', :default => 'views'
1859
+ set :views, :haml => 'templates', :default => 'views'
2124
1860
 
2125
1861
  helpers do
2126
1862
  def find_template(views, name, engine, &block)
@@ -2131,7 +1867,7 @@ helpers do
2131
1867
  end
2132
1868
  ```
2133
1869
 
2134
- You can also easily wrap this up in an extension and share with others!
1870
+ You can also easily wrap this up in an extension and share it with others!
2135
1871
 
2136
1872
  Note that `find_template` does not check if the file really exists but
2137
1873
  rather calls the given block for all possible paths. This is not a
@@ -2197,7 +1933,7 @@ end
2197
1933
  ### Configuring attack protection
2198
1934
 
2199
1935
  Sinatra is using
2200
- [Rack::Protection](https://github.com/sinatra/sinatra/tree/master/rack-protection#readme) to
1936
+ [Rack::Protection](https://github.com/sinatra/sinatra/tree/main/rack-protection#readme) to
2201
1937
  defend your application against common, opportunistic attacks. You can
2202
1938
  easily disable this behavior (which will open up your application to tons
2203
1939
  of common vulnerabilities):
@@ -2220,7 +1956,7 @@ set :protection, :except => [:path_traversal, :session_hijacking]
2220
1956
  By default, Sinatra will only set up session based protection if `:sessions`
2221
1957
  have been enabled. See '[Using Sessions](#using-sessions)'. Sometimes you may want to set up
2222
1958
  sessions "outside" of the Sinatra app, such as in the config.ru or with a
2223
- separate `Rack::Builder` instance. In that case you can still set up session
1959
+ separate `Rack::Builder` instance. In that case, you can still set up session
2224
1960
  based protection by passing the `:session` option:
2225
1961
 
2226
1962
  ```ruby
@@ -2264,11 +2000,20 @@ set :protection, :session => true
2264
2000
  used for built-in server.
2265
2001
  </dd>
2266
2002
 
2003
+ <dt>default_content_type</dt>
2004
+ <dd>
2005
+ Content-Type to assume if unknown (defaults to <tt>"text/html"</tt>). Set
2006
+ to <tt>nil</tt> to not set a default Content-Type on every response; when
2007
+ configured so, you must set the Content-Type manually when emitting content
2008
+ or the user-agent will have to sniff it (or, if <tt>nosniff</tt> is enabled
2009
+ in Rack::Protection::XSSHeader, assume <tt>application/octet-stream</tt>).
2010
+ </dd>
2011
+
2267
2012
  <dt>default_encoding</dt>
2268
2013
  <dd>Encoding to assume if unknown (defaults to <tt>"utf-8"</tt>).</dd>
2269
2014
 
2270
2015
  <dt>dump_errors</dt>
2271
- <dd>Display errors in the log.</dd>
2016
+ <dd>Display errors in the log. Enabled by default unless environment is "test".</dd>
2272
2017
 
2273
2018
  <dt>environment</dt>
2274
2019
  <dd>
@@ -2368,7 +2113,7 @@ set :protection, :session => true
2368
2113
  If you are using a WEBrick web server, presumably for your development
2369
2114
  environment, you can pass a hash of options to <tt>server_settings</tt>,
2370
2115
  such as <tt>SSLEnable</tt> or <tt>SSLVerifyClient</tt>. However, web
2371
- servers such as Puma and Thin do not support this, so you can set
2116
+ servers such as Puma do not support this, so you can set
2372
2117
  <tt>server_settings</tt> by defining it as a method when you call
2373
2118
  <tt>configure</tt>.
2374
2119
  </dd>
@@ -2419,7 +2164,7 @@ set :protection, :session => true
2419
2164
 
2420
2165
  <dt>threaded</dt>
2421
2166
  <dd>
2422
- If set to <tt>true</tt>, will tell Thin to use
2167
+ If set to <tt>true</tt>, will tell server to use
2423
2168
  <tt>EventMachine.defer</tt> for processing the request.
2424
2169
  </dd>
2425
2170
 
@@ -2574,7 +2319,7 @@ end
2574
2319
  ```
2575
2320
 
2576
2321
  The semantics of `use` are identical to those defined for the
2577
- [Rack::Builder](http://www.rubydoc.info/github/rack/rack/master/Rack/Builder) DSL
2322
+ [Rack::Builder](https://www.rubydoc.info/github/rack/rack/main/Rack/Builder) DSL
2578
2323
  (most frequently used from rackup files). For example, the `use` method
2579
2324
  accepts multiple/variable args as well as blocks:
2580
2325
 
@@ -2590,7 +2335,7 @@ many of these components automatically based on configuration so you
2590
2335
  typically don't have to `use` them explicitly.
2591
2336
 
2592
2337
  You can find useful middleware in
2593
- [rack](https://github.com/rack/rack/tree/master/lib/rack),
2338
+ [rack](https://github.com/rack/rack/tree/main/lib/rack),
2594
2339
  [rack-contrib](https://github.com/rack/rack-contrib#readme),
2595
2340
  or in the [Rack wiki](https://github.com/rack/rack/wiki/List-of-Middleware).
2596
2341
 
@@ -2598,7 +2343,7 @@ or in the [Rack wiki](https://github.com/rack/rack/wiki/List-of-Middleware).
2598
2343
 
2599
2344
  Sinatra tests can be written using any Rack-based testing library or
2600
2345
  framework.
2601
- [Rack::Test](http://www.rubydoc.info/github/brynary/rack-test/master/frames)
2346
+ [Rack::Test](https://www.rubydoc.info/github/rack/rack-test/main/frames)
2602
2347
  is recommended:
2603
2348
 
2604
2349
  ```ruby
@@ -2692,7 +2437,7 @@ modular application.
2692
2437
  The main disadvantage of using the classic style rather than the modular
2693
2438
  style is that you will only have one Sinatra application per Ruby
2694
2439
  process. If you plan to use more than one, switch to the modular style.
2695
- There is no reason you cannot mix the modular and the classic styles.
2440
+ There is no reason you cannot mix the modular and classic styles.
2696
2441
 
2697
2442
  If switching from one style to the other, you should be aware of
2698
2443
  slightly different default settings:
@@ -2821,7 +2566,7 @@ style for running with a `config.ru`.**
2821
2566
  ### Using Sinatra as Middleware
2822
2567
 
2823
2568
  Not only is Sinatra able to use other Rack middleware, any Sinatra
2824
- application can in turn be added in front of any Rack endpoint as
2569
+ application can, in turn, be added in front of any Rack endpoint as
2825
2570
  middleware itself. This endpoint could be another Sinatra application,
2826
2571
  or any other Rack-based application (Rails/Hanami/Roda/...):
2827
2572
 
@@ -2912,7 +2657,7 @@ available.
2912
2657
  Every Sinatra application corresponds to a subclass of `Sinatra::Base`.
2913
2658
  If you are using the top-level DSL (`require 'sinatra'`), then this
2914
2659
  class is `Sinatra::Application`, otherwise it is the subclass you
2915
- created explicitly. At class level you have methods like `get` or
2660
+ created explicitly. At the class level, you have methods like `get` or
2916
2661
  `before`, but you cannot access the `request` or `session` objects, as
2917
2662
  there is only a single application class for all requests.
2918
2663
 
@@ -2935,7 +2680,7 @@ You have the application scope binding inside:
2935
2680
  * Your application class body
2936
2681
  * Methods defined by extensions
2937
2682
  * The block passed to `helpers`
2938
- * Procs/blocks used as value for `set`
2683
+ * Procs/blocks used as a value for `set`
2939
2684
  * The block passed to `Sinatra.new`
2940
2685
 
2941
2686
  You can reach the scope object (the class) like this:
@@ -2986,7 +2731,7 @@ do not share variables/state with the class scope (read: you have a different
2986
2731
 
2987
2732
  You have the delegate scope binding inside:
2988
2733
 
2989
- * The top level binding, if you did `require "sinatra"`
2734
+ * The top-level binding, if you did `require "sinatra"`
2990
2735
  * An object extended with the `Sinatra::Delegator` mixin
2991
2736
 
2992
2737
  Have a look at the code for yourself: here's the
@@ -3008,7 +2753,7 @@ Options are:
3008
2753
  -p # set the port (default is 4567)
3009
2754
  -o # set the host (default is 0.0.0.0)
3010
2755
  -e # set the environment (default is development)
3011
- -s # specify rack server/handler (default is thin)
2756
+ -s # specify rack server/handler (default is puma)
3012
2757
  -q # turn on quiet mode for server (default is off)
3013
2758
  -x # turn on the mutex lock (default is off)
3014
2759
  ```
@@ -3019,16 +2764,16 @@ _Paraphrasing from
3019
2764
  [this StackOverflow answer](https://stackoverflow.com/a/6282999/5245129)
3020
2765
  by Konstantin_
3021
2766
 
3022
- Sinatra doesn't impose any concurrency model, but leaves that to the
3023
- underlying Rack handler (server) like Thin, Puma or WEBrick. Sinatra
2767
+ Sinatra doesn't impose any concurrency model but leaves that to the
2768
+ underlying Rack handler (server) like Puma or WEBrick. Sinatra
3024
2769
  itself is thread-safe, so there won't be any problem if the Rack handler
3025
2770
  uses a threaded model of concurrency. This would mean that when starting
3026
2771
  the server, you'd have to specify the correct invocation method for the
3027
2772
  specific Rack handler. The following example is a demonstration of how
3028
- to start a multi-threaded Thin server:
2773
+ to start a multi-threaded Rainbows server:
3029
2774
 
3030
2775
  ```ruby
3031
- # app.rb
2776
+ # config.ru
3032
2777
 
3033
2778
  require 'sinatra/base'
3034
2779
 
@@ -3038,23 +2783,31 @@ class App < Sinatra::Base
3038
2783
  end
3039
2784
  end
3040
2785
 
3041
- App.run!
2786
+ run App
2787
+ ```
2788
+
2789
+ ```ruby
2790
+ # rainbows.conf
3042
2791
 
2792
+ # Rainbows configurator is based on Unicorn.
2793
+ Rainbows! do
2794
+ use :ThreadSpawn
2795
+ end
3043
2796
  ```
3044
2797
 
3045
2798
  To start the server, the command would be:
3046
2799
 
3047
2800
  ```shell
3048
- thin --threaded start
2801
+ rainbows -c rainbows.conf
3049
2802
  ```
3050
2803
 
3051
2804
  ## Requirement
3052
2805
 
3053
2806
  The following Ruby versions are officially supported:
3054
2807
  <dl>
3055
- <dt>Ruby 2.2</dt>
2808
+ <dt>Ruby 2.6</dt>
3056
2809
  <dd>
3057
- 2.2 is fully supported and recommended. There are currently no plans to
2810
+ 2.6 is fully supported and recommended. There are currently no plans to
3058
2811
  drop official support for it.
3059
2812
  </dd>
3060
2813
 
@@ -3072,37 +2825,20 @@ The following Ruby versions are officially supported:
3072
2825
  </dd>
3073
2826
  </dl>
3074
2827
 
3075
- Versions of Ruby prior to 2.2.2 are no longer supported as of Sinatra 2.0.
3076
-
3077
- We also keep an eye on upcoming Ruby versions.
3078
-
3079
- The following Ruby implementations are not officially supported but still are
3080
- known to run Sinatra:
2828
+ Versions of Ruby before 2.6 are no longer supported as of Sinatra 3.0.0.
3081
2829
 
3082
- * Older versions of JRuby and Rubinius
3083
- * Ruby Enterprise Edition
3084
- * MacRuby, Maglev, IronRuby
3085
- * Ruby 1.9.0 and 1.9.1 (but we do recommend against using those)
3086
-
3087
- Not being officially supported means if things only break there and not on a
3088
- supported platform, we assume it's not our issue but theirs.
3089
-
3090
- We also run our CI against ruby-head (future releases of MRI), but we
3091
- can't guarantee anything, since it is constantly moving. Expect upcoming
3092
- 2.x releases to be fully supported.
2830
+ We also keep an eye on upcoming Ruby versions. Expect upcoming
2831
+ 3.x releases to be fully supported.
3093
2832
 
3094
2833
  Sinatra should work on any operating system supported by the chosen Ruby
3095
2834
  implementation.
3096
2835
 
3097
- If you run MacRuby, you should `gem install control_tower`.
3098
-
3099
- Sinatra currently doesn't run on Cardinal, SmallRuby, BlueRuby or any
3100
- Ruby version prior to 2.2.
2836
+ Running Sinatra on a not officially supported Ruby flavor means that if things only break there we assume it's not our issue but theirs.
3101
2837
 
3102
2838
  ## The Bleeding Edge
3103
2839
 
3104
2840
  If you would like to use Sinatra's latest bleeding-edge code, feel free
3105
- to run your application against the master branch, it should be rather
2841
+ to run your application against the main branch, it should be rather
3106
2842
  stable.
3107
2843
 
3108
2844
  We also push out prerelease gems from time to time, so you can do a
@@ -3151,20 +2887,19 @@ SemVerTag.
3151
2887
 
3152
2888
  ## Further Reading
3153
2889
 
3154
- * [Project Website](http://www.sinatrarb.com/) - Additional documentation,
2890
+ * [Project Website](https://sinatrarb.com/) - Additional documentation,
3155
2891
  news, and links to other resources.
3156
- * [Contributing](http://www.sinatrarb.com/contributing) - Find a bug? Need
2892
+ * [Contributing](https://sinatrarb.com/contributing) - Find a bug? Need
3157
2893
  help? Have a patch?
3158
2894
  * [Issue tracker](https://github.com/sinatra/sinatra/issues)
3159
2895
  * [Twitter](https://twitter.com/sinatra)
3160
2896
  * [Mailing List](https://groups.google.com/forum/#!forum/sinatrarb)
3161
2897
  * IRC: [#sinatra](irc://chat.freenode.net/#sinatra) on [Freenode](https://freenode.net)
3162
- * [Sinatra & Friends](https://sinatrarb.slack.com) on Slack
3163
- ([get an invite](https://sinatra-slack.herokuapp.com/))
2898
+ * [Sinatra & Friends](https://discord.gg/ncjsfsNHh7) on Discord
3164
2899
  * [Sinatra Book](https://github.com/sinatra/sinatra-book) - Cookbook Tutorial
3165
2900
  * [Sinatra Recipes](http://recipes.sinatrarb.com/) - Community contributed
3166
2901
  recipes
3167
- * API documentation for the [latest release](http://www.rubydoc.info/gems/sinatra)
3168
- or the [current HEAD](http://www.rubydoc.info/github/sinatra/sinatra) on
3169
- [RubyDoc](http://www.rubydoc.info/)
3170
- * [CI server](https://travis-ci.org/sinatra/sinatra)
2902
+ * API documentation for the [latest release](https://www.rubydoc.info/gems/sinatra)
2903
+ or the [current HEAD](https://www.rubydoc.info/github/sinatra/sinatra) on
2904
+ [RubyDoc](https://www.rubydoc.info/)
2905
+ * [CI Actions](https://github.com/sinatra/sinatra/actions)