rails-brotli-cache 0.6.2 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6267cfdccacd5e402e500f1df681e16e8d0be371718e499d0abde30c64822dbd
4
- data.tar.gz: 4648a2053526200a231c8cd36632715700a6ee197f672431ed2de1c150e036eb
3
+ metadata.gz: deb7fb5b6df5533b08e76b59062ff0a1897822e74031108ae45efbff9612cc74
4
+ data.tar.gz: cbfe23f39e63c70e30d3ac1dc412d38ab9a0b725e6da63f6a724423774d6c99b
5
5
  SHA512:
6
- metadata.gz: 3dfdbc83794444e9be00962b4b5f6470f5c8803340cabbe3535f7143c87cc3bb21af6340d226e8b4b647cf6fd02a1318376daf98f4c50baa4707c70bcacca463
7
- data.tar.gz: a8baf1bb1409642f3ea7e6251970a9fb8fbf1b3bbf6dade72a77f288d24de3f58fa2d00b36f24b4c82908a8f6e510564f9265b106297dcc1ddd7500b9c4f7306
6
+ metadata.gz: 9e28ac7994f28b176b086f80ae3bdd163a72c285a094d0b51bfa55ffee4f75b845414ed6a30487db60a158ad2e66795eae17ccde70a5f06cf4a1f84d0d5e7e3c
7
+ data.tar.gz: 2490251b4a3f29f0121132b18b127c23c152b07a7e187844fb061aacb76e448342de0cf8f1c5b20ea203371c7da9d6dc3b26fe4332f2f862c2bcf8726f316137
@@ -19,7 +19,7 @@ jobs:
19
19
  strategy:
20
20
  fail-fast: false
21
21
  matrix:
22
- ruby-version: ['3.2', '3.1', '3.0', '2.7', '2.6']
22
+ ruby-version: ['3.2', '3.1', '3.0', '2.7']
23
23
  steps:
24
24
  - uses: actions/checkout@v3
25
25
  - name: Set up Ruby ${{ matrix.ruby-version }}
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec
data/README.md CHANGED
@@ -134,7 +134,7 @@ By default gem uses a Brotli compression, but you can customize the algorithm. Y
134
134
  ```ruby
135
135
  config.cache_store = RailsBrotliCache::Store.new(
136
136
  ActiveSupport::Cache::RedisCacheStore.new,
137
- { compressor_class: Snappy }
137
+ { compressor_class: ZSTDCompressor }
138
138
  )
139
139
  ```
140
140
 
@@ -142,7 +142,7 @@ config.cache_store = RailsBrotliCache::Store.new(
142
142
 
143
143
  class ZSTDCompressor
144
144
  def self.deflate(payload)
145
- ::Zstd.compress(payload, 10)
145
+ ::Zstd.compress(payload, level: 10)
146
146
  end
147
147
 
148
148
  def self.inflate(payload)
@@ -150,7 +150,7 @@ class ZSTDCompressor
150
150
  end
151
151
  end
152
152
 
153
- Rails.cache.write('test-key', json, compressor_class: Snappy)
153
+ Rails.cache.write('test-key', json, compressor_class: ZSTDCompressor)
154
154
  ```
155
155
 
156
156
  This config expects a class that defines two methods, `inflate` and `deflate`. It allows to use, for example, a [ZSTD by Facebook](https://github.com/SpringMT/zstd-ruby), offering even better performance and compression.
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
1
  require "bundler/gem_tasks"
2
- require 'rspec/core/rake_task'
2
+ require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
6
  task default: :spec
7
7
 
8
- desc 'Test all cache_stores'
8
+ desc "Test all cache_stores"
9
9
  task :test_all do
10
10
  system("TEST_RAILS_CACHE_STORE=redis_cache_store bundle exec rspec spec && TEST_RAILS_CACHE_STORE=brotli_cache_store bundle exec rspec spec && TEST_RAILS_CACHE_STORE=mem_cache_store bundle exec rspec spec && bundle exec rspec spec")
11
11
  end
data/benchmarks/Gemfile CHANGED
@@ -1,7 +1,8 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
- gem 'brotli'
4
- gem 'rails-brotli-cache', path: "../"
5
- gem 'redis'
6
- gem 'dalli'
7
- gem 'zstd-ruby'
3
+ gem "brotli"
4
+ gem "rails-brotli-cache", path: "../"
5
+ gem "redis"
6
+ gem "dalli"
7
+ gem "zstd-ruby"
8
+ gem "lz4-ruby"
data/benchmarks/main.rb CHANGED
@@ -1,14 +1,15 @@
1
- require 'active_support'
2
- require 'active_support/core_ext/hash'
3
- require 'net/http'
4
- require 'brotli'
5
- require 'rails-brotli-cache'
6
- require 'benchmark'
7
- require 'zstd-ruby'
1
+ require "active_support"
2
+ require "active_support/core_ext/hash"
3
+ require "net/http"
4
+ require "brotli"
5
+ require "rails-brotli-cache"
6
+ require "benchmark"
7
+ require "zstd-ruby"
8
+ require "lz4-ruby"
8
9
 
9
10
  class ZSTDCompressor
10
11
  def self.deflate(payload)
11
- ::Zstd.compress(payload, 10)
12
+ ::Zstd.compress(payload, level: 10)
12
13
  end
13
14
 
14
15
  def self.inflate(payload)
@@ -16,21 +17,49 @@ class ZSTDCompressor
16
17
  end
17
18
  end
18
19
 
20
+ class LZ4Compressor
21
+ def self.deflate(payload)
22
+ ::LZ4::compress(payload)
23
+ end
24
+
25
+ def self.inflate(payload)
26
+ ::LZ4::uncompress(payload)
27
+ end
28
+ end
29
+
30
+ class LZ4HCCompressor
31
+ def self.deflate(payload)
32
+ ::LZ4::compressHC(payload)
33
+ end
34
+
35
+ def self.inflate(payload)
36
+ ::LZ4::uncompress(payload)
37
+ end
38
+ end
39
+
19
40
  memory_cache = ActiveSupport::Cache::MemoryStore.new(compress: true) # memory store does not use compression by default
20
41
  brotli_memory_cache = RailsBrotliCache::Store.new(memory_cache)
21
42
  zstd_memory_cache = RailsBrotliCache::Store.new(memory_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
43
+ lz4_memory_cache = RailsBrotliCache::Store.new(memory_cache, compressor_class: LZ4Compressor, prefix: "lz4-")
44
+ lz4hc_memory_cache = RailsBrotliCache::Store.new(memory_cache, compressor_class: LZ4HCCompressor, prefix: "lz4hc-")
22
45
 
23
46
  redis_cache = ActiveSupport::Cache::RedisCacheStore.new
24
47
  brotli_redis_cache = RailsBrotliCache::Store.new(redis_cache)
25
48
  zstd_redis_cache = RailsBrotliCache::Store.new(redis_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
49
+ lz4_redis_cache = RailsBrotliCache::Store.new(redis_cache, compressor_class: LZ4Compressor, prefix: "lz4-")
50
+ lz4hc_redis_cache = RailsBrotliCache::Store.new(redis_cache, compressor_class: LZ4HCCompressor, prefix: "lz4hc-")
26
51
 
27
52
  memcached_cache = ActiveSupport::Cache::MemCacheStore.new
28
53
  brotli_memcached_cache = RailsBrotliCache::Store.new(memcached_cache)
29
54
  zstd_memcached_cache = RailsBrotliCache::Store.new(memcached_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
55
+ lz4_memcached_cache = RailsBrotliCache::Store.new(memcached_cache, compressor_class: LZ4Compressor, prefix: "lz4-")
56
+ lz4hc_memcached_cache = RailsBrotliCache::Store.new(memcached_cache, compressor_class: LZ4HCCompressor, prefix: "lz4hc-")
30
57
 
31
- file_cache = ActiveSupport::Cache::FileStore.new('/tmp')
58
+ file_cache = ActiveSupport::Cache::FileStore.new("/tmp")
32
59
  brotli_file_cache = RailsBrotliCache::Store.new(file_cache)
33
60
  zstd_file_cache = RailsBrotliCache::Store.new(file_cache, compressor_class: ZSTDCompressor, prefix: "zs-")
61
+ lz4_file_cache = RailsBrotliCache::Store.new(file_cache, compressor_class: LZ4Compressor, prefix: "lz4-")
62
+ lz4hc_file_cache = RailsBrotliCache::Store.new(file_cache, compressor_class: LZ4HCCompressor, prefix: "lz4hc-")
34
63
 
35
64
  json_uri = URI("https://raw.githubusercontent.com/pawurb/rails-brotli-cache/main/spec/fixtures/sample.json")
36
65
  json = Net::HTTP.get(json_uri)
@@ -46,7 +75,7 @@ br_json_size = redis_cache.redis.with do |conn|
46
75
  conn.get("br-json").size
47
76
  end
48
77
  puts "Brotli JSON size: #{br_json_size}"
49
- puts "~#{((gzip_json_size - br_json_size).to_f / gzip_json_size.to_f * 100).round}% improvment"
78
+ puts "~#{((gzip_json_size - br_json_size).to_f / gzip_json_size.to_f * 100).round}% difference"
50
79
  puts ""
51
80
 
52
81
  zstd_redis_cache.write("json", json)
@@ -54,7 +83,23 @@ zs_json_size = redis_cache.redis.with do |conn|
54
83
  conn.get("zs-json").size
55
84
  end
56
85
  puts "ZSTD JSON size: #{zs_json_size}"
57
- puts "~#{((gzip_json_size - zs_json_size).to_f / gzip_json_size.to_f * 100).round}% improvment"
86
+ puts "~#{((gzip_json_size - zs_json_size).to_f / gzip_json_size.to_f * 100).round}% difference"
87
+ puts ""
88
+
89
+ lz4_redis_cache.write("json", json)
90
+ lz4_json_size = redis_cache.redis.with do |conn|
91
+ conn.get("lz4-json").size
92
+ end
93
+ puts "LZ4 JSON size: #{lz4_json_size}"
94
+ puts "~#{((gzip_json_size - lz4_json_size).to_f / gzip_json_size.to_f * 100).round}% difference"
95
+ puts ""
96
+
97
+ lz4hc_redis_cache.write("json", json)
98
+ lz4hc_json_size = redis_cache.redis.with do |conn|
99
+ conn.get("lz4hc-json").size
100
+ end
101
+ puts "LZ4HC JSON size: #{lz4hc_json_size}"
102
+ puts "~#{((gzip_json_size - lz4hc_json_size).to_f / gzip_json_size.to_f * 100).round}% difference"
58
103
  puts ""
59
104
 
60
105
  iterations = 100
@@ -81,6 +126,20 @@ Benchmark.bm do |x|
81
126
  end
82
127
  end
83
128
 
129
+ x.report("lz4_memory_cache") do
130
+ iterations.times do
131
+ lz4_memory_cache.write("test", json)
132
+ lz4_memory_cache.read("test")
133
+ end
134
+ end
135
+
136
+ x.report("lz4hc_memory_cache") do
137
+ iterations.times do
138
+ lz4hc_memory_cache.write("test", json)
139
+ lz4hc_memory_cache.read("test")
140
+ end
141
+ end
142
+
84
143
  x.report("redis_cache") do
85
144
  iterations.times do
86
145
  redis_cache.write("test", json)
@@ -102,6 +161,20 @@ Benchmark.bm do |x|
102
161
  end
103
162
  end
104
163
 
164
+ x.report("lz4_redis_cache") do
165
+ iterations.times do
166
+ lz4_redis_cache.write("test", json)
167
+ lz4_redis_cache.read("test")
168
+ end
169
+ end
170
+
171
+ x.report("lz4hc_redis_cache") do
172
+ iterations.times do
173
+ lz4hc_redis_cache.write("test", json)
174
+ lz4hc_redis_cache.read("test")
175
+ end
176
+ end
177
+
105
178
  x.report("memcached_cache") do
106
179
  iterations.times do
107
180
  memcached_cache.write("test", json)
@@ -123,6 +196,20 @@ Benchmark.bm do |x|
123
196
  end
124
197
  end
125
198
 
199
+ x.report("lz4_memcached_cache") do
200
+ iterations.times do
201
+ lz4_memcached_cache.write("test", json)
202
+ lz4_memcached_cache.read("test")
203
+ end
204
+ end
205
+
206
+ x.report("lz4hc_memcached_cache") do
207
+ iterations.times do
208
+ lz4hc_memcached_cache.write("test", json)
209
+ lz4hc_memcached_cache.read("test")
210
+ end
211
+ end
212
+
126
213
  x.report("file_cache") do
127
214
  iterations.times do
128
215
  file_cache.write("test", json)
@@ -143,4 +230,18 @@ Benchmark.bm do |x|
143
230
  zstd_file_cache.read("test")
144
231
  end
145
232
  end
233
+
234
+ x.report("lz4_file_cache") do
235
+ iterations.times do
236
+ lz4_file_cache.write("test", json)
237
+ lz4_file_cache.read("test")
238
+ end
239
+ end
240
+
241
+ x.report("lz4hc_file_cache") do
242
+ iterations.times do
243
+ lz4hc_file_cache.write("test", json)
244
+ lz4hc_file_cache.read("test")
245
+ end
246
+ end
146
247
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/cache'
3
+ require "active_support/cache"
4
4
  begin
5
- require 'brotli'
5
+ require "brotli"
6
6
  rescue LoadError
7
7
  end
8
8
 
@@ -25,7 +25,7 @@ module RailsBrotliCache
25
25
  DEFAULT_OPTIONS = {
26
26
  compress_threshold: COMPRESS_THRESHOLD,
27
27
  compress: true,
28
- compressor_class: BrotliCompressor
28
+ compressor_class: BrotliCompressor,
29
29
  }
30
30
 
31
31
  attr_reader :core_store
@@ -33,10 +33,10 @@ module RailsBrotliCache
33
33
  def initialize(core_store, options = {})
34
34
  @core_store = core_store
35
35
  @prefix = if options.key?(:prefix)
36
- options.fetch(:prefix)
37
- else
38
- "br-"
39
- end
36
+ options.fetch(:prefix)
37
+ else
38
+ "br-"
39
+ end
40
40
 
41
41
  @init_options = options.reverse_merge(DEFAULT_OPTIONS)
42
42
  end
@@ -87,9 +87,9 @@ module RailsBrotliCache
87
87
  new_hash = hash.map do |key, val|
88
88
  [
89
89
  expanded_cache_key(key),
90
- compressed(val, options)
90
+ compressed(val, options),
91
91
  ]
92
- end
92
+ end.to_h
93
93
 
94
94
  @core_store.write_multi(
95
95
  new_hash,
@@ -107,17 +107,24 @@ module RailsBrotliCache
107
107
  end.to_h
108
108
  end
109
109
 
110
+ def delete_multi(names, options = nil)
111
+ options = (options || {}).reverse_merge(@init_options)
112
+ names = names.map { |name| expanded_cache_key(name) }
113
+
114
+ core_store.delete_multi(names, options)
115
+ end
116
+
110
117
  def fetch_multi(*names)
111
118
  options = names.extract_options!
112
119
  expanded_names = names.map { |name| expanded_cache_key(name) }
113
120
  options = options.reverse_merge(@init_options)
114
121
 
115
- reads = core_store.send(:read_multi_entries, expanded_names, **options)
122
+ reads = core_store.send(:read_multi_entries, expanded_names, **options)
116
123
  reads.map do |key, val|
117
124
  [source_cache_key(key), uncompressed(val, options)]
118
125
  end.to_h
119
126
 
120
- writes = {}
127
+ writes = {}
121
128
  ordered = names.index_with do |name|
122
129
  reads.fetch(name) { writes[name] = yield(name) }
123
130
  end
@@ -175,11 +182,11 @@ module RailsBrotliCache
175
182
  return payload if payload.is_a?(Integer)
176
183
 
177
184
  serialized = if payload.start_with?(MARK_BR_COMPRESSED)
178
- compressor = options.fetch(:compressor_class)
179
- compressor.inflate(payload.byteslice(1..-1))
180
- else
181
- payload
182
- end
185
+ compressor = options.fetch(:compressor_class)
186
+ compressor.inflate(payload.byteslice(1..-1))
187
+ else
188
+ payload
189
+ end
183
190
 
184
191
  Marshal.load(serialized)
185
192
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsBrotliCache
4
- VERSION = "0.6.2"
4
+ VERSION = "0.6.3"
5
5
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails-brotli-cache/store'
3
+ require "rails-brotli-cache/store"
4
4
 
5
5
  module RailsBrotliCache
6
6
  end
7
-
@@ -1,20 +1,20 @@
1
1
  # -*- encoding: utf-8 -*-
2
- lib = File.expand_path('../lib', __FILE__)
2
+ lib = File.expand_path("../lib", __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'rails-brotli-cache/version'
4
+ require "rails-brotli-cache/version"
5
5
 
6
6
  Gem::Specification.new do |gem|
7
- gem.name = "rails-brotli-cache"
8
- gem.version = RailsBrotliCache::VERSION
9
- gem.authors = ["pawurb"]
10
- gem.email = ["contact@pawelurbanek.com"]
11
- gem.summary = %q{ Drop-in enhancement for Rails cache, offering better performance and compression with Brotli algorithm. }
12
- gem.description = %q{ This gem reduces storage needed for Rails cache by using Brotli compression, which can produce outputs smaller by ~20% and offers better performance than Gzip. }
13
- gem.homepage = "https://github.com/pawurb/rails-brotli-cache"
14
- gem.files = `git ls-files`.split("\n")
15
- gem.test_files = gem.files.grep(%r{^(spec)/})
7
+ gem.name = "rails-brotli-cache"
8
+ gem.version = RailsBrotliCache::VERSION
9
+ gem.authors = ["pawurb"]
10
+ gem.email = ["contact@pawelurbanek.com"]
11
+ gem.summary = %q{ Drop-in enhancement for Rails cache, offering better performance and compression with Brotli algorithm. }
12
+ gem.description = %q{ This gem reduces storage needed for Rails cache by using Brotli compression, which can produce outputs smaller by ~20% and offers better performance than Gzip. }
13
+ gem.homepage = "https://github.com/pawurb/rails-brotli-cache"
14
+ gem.files = `git ls-files`.split("\n")
15
+ gem.test_files = gem.files.grep(%r{^(spec)/})
16
16
  gem.require_paths = ["lib"]
17
- gem.license = "MIT"
17
+ gem.license = "MIT"
18
18
  gem.add_dependency "activesupport"
19
19
  gem.add_development_dependency "brotli"
20
20
  gem.add_development_dependency "rspec"
@@ -24,6 +24,7 @@ Gem::Specification.new do |gem|
24
24
  gem.add_development_dependency "redis"
25
25
  gem.add_development_dependency "dalli"
26
26
  gem.add_development_dependency "byebug"
27
+ gem.add_development_dependency "rufo"
27
28
 
28
29
  if gem.respond_to?(:metadata=)
29
30
  gem.metadata = { "rubygems_mfa_required" => "true" }
data/spec/dummy/Gemfile CHANGED
@@ -42,4 +42,3 @@ group :development do
42
42
  # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
43
43
  # gem "spring"
44
44
  end
45
-
@@ -22,7 +22,7 @@ module Dummy
22
22
  class Application < Rails::Application
23
23
  # Initialize configuration defaults for originally generated Rails version.
24
24
 
25
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7')
25
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7")
26
26
  config.load_defaults 7.0
27
27
  else
28
28
  config.load_defaults 6.0
@@ -13,7 +13,7 @@ Rails.application.configure do
13
13
  config.eager_load = true
14
14
 
15
15
  # Full error reports are disabled and caching is turned on.
16
- config.consider_all_requests_local = false
16
+ config.consider_all_requests_local = false
17
17
  config.action_controller.perform_caching = true
18
18
 
19
19
  # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
@@ -45,7 +45,7 @@ Rails.application.configure do
45
45
  config.log_level = :info
46
46
 
47
47
  # Prepend all log lines with the following tags.
48
- config.log_tags = [ :request_id ]
48
+ config.log_tags = [:request_id]
49
49
 
50
50
  # Use a different cache store in production.
51
51
  # config.cache_store = :mem_cache_store
@@ -65,8 +65,8 @@ Rails.application.configure do
65
65
  # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name")
66
66
 
67
67
  if ENV["RAILS_LOG_TO_STDOUT"].present?
68
- logger = ActiveSupport::Logger.new(STDOUT)
68
+ logger = ActiveSupport::Logger.new(STDOUT)
69
69
  logger.formatter = config.log_formatter
70
- config.logger = ActiveSupport::TaggedLogging.new(logger)
70
+ config.logger = ActiveSupport::TaggedLogging.new(logger)
71
71
  end
72
72
  end
@@ -19,11 +19,11 @@ Rails.application.configure do
19
19
  # Configure public file server for tests with Cache-Control for performance.
20
20
  config.public_file_server.enabled = true
21
21
  config.public_file_server.headers = {
22
- "Cache-Control" => "public, max-age=#{1.hour.to_i}"
22
+ "Cache-Control" => "public, max-age=#{1.hour.to_i}",
23
23
  }
24
24
 
25
25
  # Show full error reports and disable caching.
26
- config.consider_all_requests_local = true
26
+ config.consider_all_requests_local = true
27
27
  config.action_controller.perform_caching = false
28
28
  config.cache_store = :null_store
29
29
 
@@ -4,5 +4,5 @@
4
4
  # sensitive information. See the ActiveSupport::ParameterFilter documentation for supported
5
5
  # notations and behaviors.
6
6
  Rails.application.config.filter_parameters += [
7
- :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
7
+ :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn,
8
8
  ]
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
- return unless ENV['TEST_RAILS_CACHE_STORE'] == 'redis_cache_store'
5
+ return unless ENV["TEST_RAILS_CACHE_STORE"] == "redis_cache_store"
6
6
 
7
7
  describe RailsBrotliCache do
8
8
  class Post
@@ -60,7 +60,7 @@ describe RailsBrotliCache do
60
60
  context "custom namespace string is not duplicated" do
61
61
  let(:options) do
62
62
  {
63
- namespace: "myapp"
63
+ namespace: "myapp",
64
64
  }
65
65
  end
66
66
 
@@ -77,7 +77,7 @@ describe RailsBrotliCache do
77
77
  context "custom namespace proc" do
78
78
  let(:options) do
79
79
  {
80
- namespace: -> { "myapp" }
80
+ namespace: -> { "myapp" },
81
81
  }
82
82
  end
83
83
 
@@ -1,15 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
5
  describe RailsBrotliCache do
6
-
7
6
  CACHE_STORE_TYPES = [
8
7
  [ActiveSupport::Cache::MemoryStore.new, ActiveSupport::Cache::MemoryStore.new],
9
8
  [ActiveSupport::Cache::RedisCacheStore.new, ActiveSupport::Cache::RedisCacheStore.new],
10
9
  [ActiveSupport::Cache::MemCacheStore.new, ActiveSupport::Cache::MemCacheStore.new],
11
- [ActiveSupport::Cache::FileStore.new('./tmp'), ActiveSupport::Cache::FileStore.new('./tmp')],
12
- [ActiveSupport::Cache::NullStore.new, ActiveSupport::Cache::NullStore.new]
10
+ [ActiveSupport::Cache::FileStore.new("./tmp"), ActiveSupport::Cache::FileStore.new("./tmp")],
11
+ [ActiveSupport::Cache::NullStore.new, ActiveSupport::Cache::NullStore.new],
13
12
  ]
14
13
 
15
14
  CACHE_STORE_TYPES.each do |cache_store_types|
@@ -72,7 +71,7 @@ describe RailsBrotliCache do
72
71
  it "for #write_multi and #read_multi" do
73
72
  values = {
74
73
  "key_1" => big_enough_to_compress_value,
75
- "key_2" => "val_2"
74
+ "key_2" => "val_2",
76
75
  }
77
76
 
78
77
  brotli_store.write_multi(values)
@@ -87,7 +86,7 @@ describe RailsBrotliCache do
87
86
  it "for #fetch_multi" do
88
87
  values = {
89
88
  "key_1" => big_enough_to_compress_value,
90
- "key_2" => "val_2"
89
+ "key_2" => "val_2",
91
90
  }
92
91
 
93
92
  brotli_store.fetch_multi("key_1", "key_2") do |key|
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
- return unless ENV['TEST_RAILS_CACHE_STORE'] == 'brotli_cache_store'
5
+ return unless ENV["TEST_RAILS_CACHE_STORE"] == "brotli_cache_store"
6
6
 
7
7
  describe RailsBrotliCache do
8
8
  subject(:cache_store) do
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
- return unless ENV['TEST_RAILS_CACHE_STORE'] == 'redis_cache_store'
5
+ return unless ENV["TEST_RAILS_CACHE_STORE"] == "redis_cache_store"
6
6
 
7
7
  describe RailsBrotliCache do
8
8
  let(:options) do
@@ -24,7 +24,7 @@ describe RailsBrotliCache do
24
24
  end
25
25
 
26
26
  let(:json) do
27
- File.read('spec/fixtures/sample.json')
27
+ File.read("spec/fixtures/sample.json")
28
28
  end
29
29
 
30
30
  it "applies more efficient brotli compression" do
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
5
  describe RailsBrotliCache do
6
6
  subject(:cache_store) do
@@ -89,7 +89,7 @@ describe RailsBrotliCache do
89
89
  it "works" do
90
90
  values = {
91
91
  "key_1" => big_enough_to_compress_value,
92
- "key_2" => 123
92
+ "key_2" => 123,
93
93
  }
94
94
 
95
95
  cache_store.write_multi(values, expires_in: 5.seconds)
@@ -107,8 +107,8 @@ describe RailsBrotliCache do
107
107
  let(:keys) { %w[key_1 key_2] }
108
108
  let(:response) do
109
109
  {
110
- 'key_1' => big_enough_to_compress_value + 'key_1',
111
- 'key_2' => big_enough_to_compress_value + 'key_2'
110
+ "key_1" => big_enough_to_compress_value + "key_1",
111
+ "key_2" => big_enough_to_compress_value + "key_2",
112
112
  }
113
113
  end
114
114
 
@@ -120,7 +120,7 @@ describe RailsBrotliCache do
120
120
  end).to eq response
121
121
  end
122
122
 
123
- context 'with a complex object that responds to #cache_key' do
123
+ context "with a complex object that responds to #cache_key" do
124
124
  subject do
125
125
  cache_store.fetch_multi(*keys) do |key|
126
126
  big_enough_to_compress_value + key.id
@@ -129,14 +129,14 @@ describe RailsBrotliCache do
129
129
 
130
130
  let(:keys) do
131
131
  [
132
- OpenStruct.new(cache_key: 'key_1', id: '12345'),
133
- OpenStruct.new(cache_key: 'key_2', id: '54321')
132
+ OpenStruct.new(cache_key: "key_1", id: "12345"),
133
+ OpenStruct.new(cache_key: "key_2", id: "54321"),
134
134
  ]
135
135
  end
136
136
  let(:response) do
137
137
  {
138
- keys[0] => big_enough_to_compress_value + '12345',
139
- keys[1] => big_enough_to_compress_value + '54321'
138
+ keys[0] => big_enough_to_compress_value + "12345",
139
+ keys[1] => big_enough_to_compress_value + "54321",
140
140
  }
141
141
  end
142
142
 
@@ -258,6 +258,58 @@ describe RailsBrotliCache do
258
258
  end
259
259
  end
260
260
 
261
+ describe "#delete_multi" do
262
+ it "removes multiple previously stored cache entries" do
263
+ cache_store.write("key_1", 1234)
264
+ cache_store.write("key_2", 5678)
265
+ cache_store.write("key_3", 9012)
266
+
267
+ expect(cache_store.read("key_1")).to eq 1234
268
+ expect(cache_store.read("key_2")).to eq 5678
269
+ expect(cache_store.read("key_3")).to eq 9012
270
+
271
+ cache_store.delete_multi(["key_1", "key_3"])
272
+
273
+ expect(cache_store.read("key_1")).to eq nil
274
+ expect(cache_store.read("key_2")).to eq 5678
275
+ expect(cache_store.read("key_3")).to eq nil
276
+ end
277
+
278
+ it "works with complex objects as cache keys" do
279
+ collection1 = [Post.new(id: 1), Post.new(id: 2)]
280
+ collection2 = [Post.new(id: 3), Post.new(id: 4)]
281
+
282
+ cache_store.write([:views, "controller/action", collection1], "fragment1")
283
+ cache_store.write([:views, "controller/action", collection2], "fragment2")
284
+
285
+ expect(cache_store.read([:views, "controller/action", collection1])).to eq "fragment1"
286
+ expect(cache_store.read([:views, "controller/action", collection2])).to eq "fragment2"
287
+
288
+ cache_store.delete_multi([[:views, "controller/action", collection1]])
289
+
290
+ expect(cache_store.read([:views, "controller/action", collection1])).to eq nil
291
+ expect(cache_store.read([:views, "controller/action", collection2])).to eq "fragment2"
292
+ end
293
+
294
+ it "handles empty array gracefully" do
295
+ cache_store.write("test-key", 1234)
296
+ expect(cache_store.read("test-key")).to eq 1234
297
+
298
+ cache_store.delete_multi([])
299
+
300
+ expect(cache_store.read("test-key")).to eq 1234
301
+ end
302
+
303
+ it "handles non-existent keys gracefully" do
304
+ cache_store.write("existing-key", 1234)
305
+ expect(cache_store.read("existing-key")).to eq 1234
306
+
307
+ cache_store.delete_multi(["existing-key", "non-existent-key"])
308
+
309
+ expect(cache_store.read("existing-key")).to eq nil
310
+ end
311
+ end
312
+
261
313
  describe "#clear" do
262
314
  it "clears the cache" do
263
315
  expect(cache_store.write("test-key", 1234))
data/spec/spec_helper.rb CHANGED
@@ -1,28 +1,27 @@
1
- require 'rubygems'
2
- require 'bundler/setup'
1
+ require "rubygems"
2
+ require "bundler/setup"
3
3
  require "active_support"
4
4
  require "active_support/core_ext/hash"
5
- require 'redis'
5
+ require "redis"
6
6
 
7
- require_relative '../lib/rails-brotli-cache'
7
+ require_relative "../lib/rails-brotli-cache"
8
8
 
9
9
  $redis = Redis.new
10
- $test_rails_cache_store = if ENV['TEST_RAILS_CACHE_STORE'] == 'redis_cache_store'
11
- ActiveSupport::Cache::RedisCacheStore.new(redis: $redis)
12
- elsif ENV['TEST_RAILS_CACHE_STORE'] == 'brotli_cache_store'
13
- RailsBrotliCache::Store.new(ActiveSupport::Cache::MemoryStore.new)
14
- elsif ENV['TEST_RAILS_CACHE_STORE'] == 'memcache_cache_store'
15
- ActiveSupport::Cache::ActiveSupport::Cache::MemCacheStore.new
16
- else
17
- ActiveSupport::Cache::MemoryStore.new
18
- end
10
+ $test_rails_cache_store = if ENV["TEST_RAILS_CACHE_STORE"] == "redis_cache_store"
11
+ ActiveSupport::Cache::RedisCacheStore.new(redis: $redis)
12
+ elsif ENV["TEST_RAILS_CACHE_STORE"] == "brotli_cache_store"
13
+ RailsBrotliCache::Store.new(ActiveSupport::Cache::MemoryStore.new)
14
+ elsif ENV["TEST_RAILS_CACHE_STORE"] == "memcache_cache_store"
15
+ ActiveSupport::Cache::ActiveSupport::Cache::MemCacheStore.new
16
+ else
17
+ ActiveSupport::Cache::MemoryStore.new
18
+ end
19
19
 
20
- require_relative '../spec/dummy/config/environment'
21
- ENV['RAILS_ROOT'] ||= "#{File.dirname(__FILE__)}../../../spec/dummy"
20
+ require_relative "../spec/dummy/config/environment"
21
+ ENV["RAILS_ROOT"] ||= "#{File.dirname(__FILE__)}../../../spec/dummy"
22
22
 
23
23
  RSpec.configure do |config|
24
24
  config.before(:each) do
25
25
  Rails.cache.clear
26
26
  end
27
27
  end
28
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-brotli-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - pawurb
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-13 00:00:00.000000000 Z
11
+ date: 2025-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -136,6 +136,20 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rufo
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
139
153
  description: " This gem reduces storage needed for Rails cache by using Brotli compression,
140
154
  which can produce outputs smaller by ~20% and offers better performance than Gzip. "
141
155
  email:
@@ -226,7 +240,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
226
240
  - !ruby/object:Gem::Version
227
241
  version: '0'
228
242
  requirements: []
229
- rubygems_version: 3.3.7
243
+ rubygems_version: 3.5.16
230
244
  signing_key:
231
245
  specification_version: 4
232
246
  summary: Drop-in enhancement for Rails cache, offering better performance and compression