Repository: sinatra/sinatra (Ruby)

Issue:
Classic Style Application without a `config.ru` does not work with Ruby 3.3 and Bundler 2.5
Steps to reproduce.

Source files:

```ruby
# my_app.rb
require 'sinatra'

get "/ready" do
  "ready"
end
```

```ruby
# Gemfile
source 'https://rubygems.org'

gem "sinatra"
gem "webrick"
```

```ruby
# Gemfile.lock
GEM
  remote: https://rubygems.org/
  specs:
    mustermann (3.0.0)
      ruby2_keywords (~> 0.0.1)
    rack (2.2.8)
    rack-protection (3.1.0)
      rack (~> 2.2, >= 2.2.4)
    ruby2_keywords (0.0.5)
    sinatra (3.1.0)
      mustermann (~> 3.0)
      rack (~> 2.2, >= 2.2.4)
      rack-protection (= 3.1.0)
      tilt (~> 2.0)
    tilt (2.3.0)
    webrick (1.8.1)

PLATFORMS
  ruby
  x86_64-linux

DEPENDENCIES
  sinatra
  webrick

BUNDLED WITH
   2.5.3
```

Executing:

```shell
$ bundle
Bundle complete! 2 Gemfile dependencies, 8 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

$ bundle exec ruby my_app.rb 
<No response, the application exit>

$ ruby -v
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
```


Discussion: With Ruby 3.2.2 it works fine:

```shell
$ bundle exec ruby my_app.rb 
[2023-12-27 23:57:08] INFO  WEBrick 1.8.1
[2023-12-27 23:57:08] INFO  ruby 3.2.2 (2023-03-30) [x86_64-linux]
== Sinatra (v3.1.0) has taken the stage on 4567 for development with backup from WEBrick
[2023-12-27 23:57:08] INFO  WEBrick::HTTPServer#start: pid=668884 port=4567
^C== Sinatra has ended his set (crowd applauds)
[2023-12-27 23:57:12] INFO  going to shutdown ...
[2023-12-27 23:57:12] INFO  WEBrick::HTTPServer#start done.
```

I try Puma instead of Webrick, result is the same - application exit.
I see the same thing, thanks for providing sensible reproducible steps, maybe this is what https://github.com/sinatra/sinatra/pull/1966 was trying to say, and the culprit for https://github.com/sinatra/sinatra/pull/1971

Interestingly, `3.3.0-preview3` works fine (but not `3.3.0-rc1`)

```ruby
$ b
Bundler 2.5.0.dev is running, but your lockfile was generated with 2.5.3. Installing Bundler 2.5.3 and restarting using that version.
Fetching gem metadata from https://rubygems.org/.
Fetching bundler 2.5.3
Installing bundler 2.5.3
Fetching gem metadata from https://rubygems.org/....
Fetching webrick 1.8.1
Installing webrick 1.8.1
Bundle complete! 2 Gemfile dependencies, 8 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

$ b exec ruby my_app.rb
[2023-12-28 10:32:46] INFO  WEBrick 1.8.1
[2023-12-28 10:32:46] INFO  ruby 3.3.0 (2023-11-12) [arm64-darwin21]
== Sinatra (v3.1.0) has taken the stage on 4567 for development with backup from WEBrick
[2023-12-28 10:32:46] INFO  WEBrick::HTTPServer#start: pid=27201 port=4567
^C== Sinatra has ended his set (crowd applauds)
[2023-12-28 10:32:50] INFO  going to shutdown ...
[2023-12-28 10:32:50] INFO  WEBrick::HTTPServer#start done.
```
I adjusted the title here, Sinatra is working, what's not working is "Classic Style Application without a `config.ru`". Sinatra works perfectly fine when using `config.ru`: https://github.com/sinatra/sinatra#using-a-classic-style-application-with-a-configru

```ruby
$ cat config.ru
require_relative 'my_app'
run Sinatra::Application

$ bundle exec rackup
[2023-12-28 10:40:19] INFO  WEBrick 1.8.1
[2023-12-28 10:40:19] INFO  ruby 3.3.0 (2023-12-25) [arm64-darwin21]
[2023-12-28 10:40:19] INFO  WEBrick::HTTPServer#start: pid=29835 port=9292
^C[2023-12-28 10:40:29] INFO  going to shutdown ...
[2023-12-28 10:40:29] INFO  WEBrick::HTTPServer#start done.
```
Also `sinatra/base` without `config.ru` – https://github.com/sinatra/sinatra?tab=readme-ov-file#dynamic-application-creation – works:

```ruby
$ cat app.rb
require 'sinatra/base'
my_app = Sinatra.new { get('/') { "hi" } }
my_app.run!

$ cat Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

gem "sinatra", "~> 3.1"
gem "webrick", "~> 1.8"

$ b e ruby app.rb
[2023-12-28 11:09:36] INFO  WEBrick 1.8.1
[2023-12-28 11:09:36] INFO  ruby 3.3.0 (2023-12-25) [arm64-darwin21]
== Sinatra (v3.1.0) has taken the stage on 4567 for development with backup from WEBrick
[2023-12-28 11:09:36] INFO  WEBrick::HTTPServer#start: pid=38033 port=4567
^C== Sinatra has ended his set (crowd applauds)
[2023-12-28 11:09:43] INFO  going to shutdown ...
[2023-12-28 11:09:43] INFO  WEBrick::HTTPServer#start done.
```
It is the combination of Ruby 3.3 and Bundler 2.5 that doesn't work

Ruby 3.3 works when Bundler 2.4.22 is used

```ruby
$ bundler -v
Bundler version 2.4.22

$ bundle exec ruby my_app.rb
[2023-12-28 12:20:11] INFO  WEBrick 1.8.1
[2023-12-28 12:20:11] INFO  ruby 3.3.0 (2023-12-25) [arm64-darwin21]
== Sinatra (v3.1.0) has taken the stage on 4567 for development with backup from WEBrick
[2023-12-28 12:20:11] INFO  WEBrick::HTTPServer#start: pid=69122 port=4567
^C== Sinatra has ended his set (crowd applauds)
[2023-12-28 12:20:14] INFO  going to shutdown ...
[2023-12-28 12:20:14] INFO  WEBrick::HTTPServer#start done.
```
This fixes the problem

```diff
diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb
index 686d4d65..8fdfc935 100644
--- a/lib/sinatra/base.rb
+++ b/lib/sinatra/base.rb
@@ -1281,6 +1281,7 @@ module Sinatra
         %r{/sinatra(/(base|main|show_exceptions))?\.rb$},   # all sinatra code
         %r{lib/tilt.*\.rb$},                                # all tilt code
         /^\(.*\)$/,                                         # generated code
+        /\/bundled_gems.rb$/,                               # ruby >= 3.3 with bundler >= 2.5
         %r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks
         /active_support/,                                   # active_support require hacks
         %r{bundler(/(?:runtime|inline))?\.rb},              # bundler require hacks
```
with some debug printing (and the patch above)

### Ruby 3.3.0 and Bundler 2.5.3 (the problematic combo)

```shell
$ bundle exec ruby my_app.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? false file=my_app.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? false file=my_app.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? true file=/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/bundled_gems.rb
ignore caller? false file=my_app.rb
[2023-12-28 14:42:53] INFO  WEBrick 1.8.1
[2023-12-28 14:42:53] INFO  ruby 3.3.0 (2023-12-25) [arm64-darwin21]
== Sinatra (v3.1.0) has taken the stage on 4567 for development with backup from WEBrick
[2023-12-28 14:42:53] INFO  WEBrick::HTTPServer#start: pid=10727 port=4567
```

### Ruby 3.2.2 and Bundler 2.5.3

```shell
$ bundle exec ruby my_app.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? false file=my_app.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? false file=my_app.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>
ignore caller? false file=my_app.rb
[2023-12-28 14:50:02] INFO  WEBrick 1.8.1
[2023-12-28 14:50:02] INFO  ruby 3.2.2 (2023-03-30) [arm64-darwin21]
== Sinatra (v3.1.0) has taken the stage on 4567 for development with backup from WEBrick
[2023-12-28 14:50:02] INFO  WEBrick::HTTPServer#start: pid=13750 port=4567
```

### Ruby 3.3.0 and Bundler version 2.4.22

```shell
$ bundle exec ruby my_app.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? false file=my_app.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/main.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? false file=my_app.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra/base.rb
ignore caller? true file=/Users/dentarg/src/sinatra/sinatra/lib/sinatra.rb
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? true file=<internal:/Users/dentarg/.arm64_rubies/3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>
ignore caller? false file=my_app.rb
[2023-12-28 14:46:27] INFO  WEBrick 1.8.1
[2023-12-28 14:46:27] INFO  ruby 3.3.0 (2023-12-25) [arm64-darwin21]
== Sinatra (v3.1.0) has taken the stage on 4567 for development with backup from WEBrick
[2023-12-28 14:46:27] INFO  WEBrick::HTTPServer#start: pid=12602 port=4567
```
> Interestingly, `3.3.0-preview3` works fine (but not `3.3.0-rc1`)

https://github.com/ruby/ruby/commits/v3_3_0/lib/bundled_gems.rb changed a few times between preview-3 and rc1 so any change after 2023-11-07 (https://github.com/ruby/ruby/commit/76dc327eef) caused the change in behaviour 
> https://github.com/ruby/ruby/commits/v3_3_0/lib/bundled_gems.rb changed a few times between preview-3 and rc1 so any change after 2023-11-07 ([ruby/ruby@76dc327eef](https://github.com/ruby/ruby/commit/76dc327eef)) caused the change in behaviour

Probably https://github.com/ruby/ruby/commit/214f6d6598be8437284dede9eb9a041a3ebfb24e 



Fix (patch):
diff --git a/Gemfile b/Gemfile
index 24341b641..caf490ec6 100644
--- a/Gemfile
+++ b/Gemfile
@@ -39,6 +39,7 @@ gem 'traces', '< 0.10.0' if RUBY_VERSION >= '2.6.0' && RUBY_VERSION < '2.7.0'
 
 gem 'asciidoctor'
 gem 'builder'
+gem 'childprocess'
 gem 'commonmarker', '~> 0.23.4', platforms: [:ruby]
 gem 'erubi'
 gem 'eventmachine'
@@ -67,3 +68,4 @@ gem 'sass-embedded', '~> 1.54'
 gem 'simplecov', require: false
 gem 'slim', '~> 4'
 gem 'yajl-ruby', platforms: [:ruby]
+gem 'zeitwerk'
diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb
index 686d4d65a..8fdfc9357 100644
--- a/lib/sinatra/base.rb
+++ b/lib/sinatra/base.rb
@@ -1281,6 +1281,7 @@ class << self
         %r{/sinatra(/(base|main|show_exceptions))?\.rb$},   # all sinatra code
         %r{lib/tilt.*\.rb$},                                # all tilt code
         /^\(.*\)$/,                                         # generated code
+        /\/bundled_gems.rb$/,                               # ruby >= 3.3 with bundler >= 2.5
         %r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks
         /active_support/,                                   # active_support require hacks
         %r{bundler(/(?:runtime|inline))?\.rb},              # bundler require hacks
diff --git a/sinatra-contrib/lib/sinatra/runner.rb b/sinatra-contrib/lib/sinatra/runner.rb
index b2124618c..6a4578627 100644
--- a/sinatra-contrib/lib/sinatra/runner.rb
+++ b/sinatra-contrib/lib/sinatra/runner.rb
@@ -111,13 +111,13 @@ def command
       "bundle exec ruby #{app_file} -p #{port} -e production"
     end
 
-    def ping(timeout = 30)
+    def ping(timeout = 10)
       loop do
         return if alive?
 
         if Time.now - @started > timeout
           warn command, log
-          raise 'timeout'
+          raise "timeout starting server with command '#{command}'"
         else
           sleep 0.1
         end