Repository: sinatra/sinatra (Ruby)

Issue:
Remove `Tilt::Cache` usage (needed for Tilt 3)
I'm [planning on deprecating `Tilt::Cache`](https://github.com/jeremyevans/tilt/commit/2a021538630138569532f1eb0fe62aec8edd0416) in the next release of tilt (2.2.0), as it isn't used internally, isn't thread safe, and doesn't add any real value (faster to use a plain hash).  Sinatra should either copy the Tilt::Cache implementation to somewhere internal to Sinatra, or (my recommendation) switch to using a plain hash, or if you really need API compatibility for the `#fetch` method:

```ruby
class Cache < Hash
  def fetch(*args)
    super(args) do
      self[args] = yield
    end
  end
end
``` 




Discussion:
Thanks for the heads-up! 

@jeremyevans Just to be clear, Tilt is not following https://semver.org/ and there will continue to be breaking changes in the 2.x series?

Looks like Sinatra (sinatra-contrib) isn't fully compatible with Tilt 2.1.0 that was just released: https://github.com/sinatra/sinatra/actions/runs/4235438155/jobs/7359051065#step:6:124 (any help you can contribute on this would be appreciated)
AFAIK, Tilt doesn't advertise semver support and has never (intentionally) followed it.  Going forward, as with all libraries I maintain, significant backwards incompatible changes will result in major version bumps.  Minor backwards incompatible changes may happen with minor version bumps.  As the saying goes, all bug fixes are incompatibilities.  While `Tilt::Cache` will be deprecated in the next release of tilt, it will not be removed until tilt 3.

The failure in the job you linked to appears unrelated to tilt.  You are installing slim 0.6.1, when the current version of slim is 5.0.0: https://github.com/sinatra/sinatra/actions/runs/4235438155/jobs/7359051065#step:6:64
Thanks for clarifying. 

> The failure in the job you linked to appears unrelated to tilt. You are installing slim 0.6.1, when the current version of slim is 5.0.0: https://github.com/sinatra/sinatra/actions/runs/4235438155/jobs/7359051065#step:6:64

Ah yes, I did look at this. It happens because the current version of Slim does not allow Tilt 2.1.0: https://rubygems.org/gems/slim So Bundler finds a very old version that didn't specify any requirements for Tilt



Patch:
diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb
index c3ebf61924..35e22161b7 100644
--- a/lib/sinatra/base.rb
+++ b/lib/sinatra/base.rb
@@ -914,6 +914,35 @@ def compile_block_template(template, options, &body)
     end
   end
 
+  # Extremely simple template cache implementation.
+  #   * Not thread-safe.
+  #   * Size is unbounded.
+  #   * Keys are not copied defensively, and should not be modified after
+  #     being passed to #fetch.  More specifically, the values returned by
+  #     key#hash and key#eql? should not change.
+  #
+  # Implementation copied from Tilt::Cache.
+  class TemplateCache
+    def initialize
+      @cache = {}
+    end
+
+    # Caches a value for key, or returns the previously cached value.
+    # If a value has been previously cached for key then it is
+    # returned. Otherwise, block is yielded to and its return value
+    # which may be nil, is cached under key and returned.
+    def fetch(*key)
+      @cache.fetch(key) do
+        @cache[key] = yield
+      end
+    end
+
+    # Clears the cache.
+    def clear
+      @cache = {}
+    end
+  end
+
   # Base class for all Sinatra applications and middleware.
   class Base
     include Rack::Utils
@@ -928,7 +957,7 @@ class Base
     def initialize(app = nil, **_kwargs)
       super()
       @app = app
-      @template_cache = Tilt::Cache.new
+      @template_cache = TemplateCache.new
       @pinned_response = nil # whether a before! filter pinned the content-type
       yield self if block_given?
     end
diff --git a/sinatra-contrib/lib/sinatra/namespace.rb b/sinatra-contrib/lib/sinatra/namespace.rb
index 6a00d3753f..80ed423db0 100644
--- a/sinatra-contrib/lib/sinatra/namespace.rb
+++ b/sinatra-contrib/lib/sinatra/namespace.rb
@@ -210,7 +210,7 @@ def settings
       end
 
       def template_cache
-        super.fetch(:nested, @namespace) { Tilt::Cache.new }
+        super.fetch(:nested, @namespace) { TemplateCache.new }
       end
 
       def redirect_to(uri, *args)


Test patch:
diff --git a/test/sinatra_test.rb b/test/sinatra_test.rb
index 92a30809aa..71a6257539 100644
--- a/test/sinatra_test.rb
+++ b/test/sinatra_test.rb
@@ -7,6 +7,6 @@ class SinatraTest < Minitest::Test
   end
 
   it "responds to #template_cache" do
-    assert_kind_of Tilt::Cache, Sinatra::Base.new!.template_cache
+    assert_kind_of Sinatra::TemplateCache, Sinatra::Base.new!.template_cache
   end
 end