rails-brotli-cache 0.3.14 → 0.4.1

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: cceeb82eb8c194ea2b8acd9fbdcf5a55d53fd6dbdf0f4f9aaf20ae2577fcab2c
4
- data.tar.gz: 6c2bcade2408e81a303091e782d01239c625c288f63def2a6c40618fedf2bc4d
3
+ metadata.gz: 01a0f784d05c6228ab9f4305fddda0b0622a3b0a1dfaba079e952c051064a535
4
+ data.tar.gz: c12edd70df133be76fb09c2fdc179d83257307874d57f4f06fbe101fc639bc4a
5
5
  SHA512:
6
- metadata.gz: 04bc2568e39f8f398f5cd71fd169570a07ec972d506baf33202738145e48009f6064da385b521671627e058c7fec1115db28b9dd806c0cc123ae0811af9dce5e
7
- data.tar.gz: f62f95df44c1acb1ceb734299291a68323a7c093b15f7762651faf43a49f83d5e7d80054444d2d63ff38bb2758fc2909836b15b93b50f54c3e0638b2c5456ec1
6
+ metadata.gz: 7a7cc8c87363e93b947bc606f1c0811199ff47ac574fd0bf329ef6248e6305661d0f305874c950bc4c02ee86327b2029c6d22ab01be7de81ab1e94af54d111cd
7
+ data.tar.gz: 842e6e543337486dd313f65491ba9b56ca6fa15fcd8c94ed201d702d767d9ae41c777e240a6fd5791cbaa3d235f293a9d21281a76c8569271b7f1605b29377fe
data/benchmarks/Gemfile CHANGED
@@ -1,5 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'rails-brotli-cache'
3
+ gem 'rails-brotli-cache', path: "../"
4
4
  gem 'redis'
5
5
  gem 'dalli'
@@ -6,9 +6,25 @@ require 'brotli'
6
6
  module RailsBrotliCache
7
7
  class Store < ::ActiveSupport::Cache::Store
8
8
  COMPRESS_THRESHOLD = ENV.fetch("BR_CACHE_COMPRESS_THRESHOLD", 1).to_f * 1024.0
9
- BR_COMPRESS_QUALITY = ENV.fetch("BR_CACHE_COMPRESS_QUALITY", 5).to_i
9
+ BR_COMPRESS_QUALITY = ENV.fetch("BR_CACHE_COMPRESS_QUALITY", 6).to_i
10
10
  MARK_BR_COMPRESSED = "\x02".b
11
11
 
12
+ class BrotliCompressor
13
+ def self.deflate(payload)
14
+ ::Brotli.deflate(payload, quality: BR_COMPRESS_QUALITY)
15
+ end
16
+
17
+ def self.inflate(payload)
18
+ ::Brotli.inflate(payload)
19
+ end
20
+ end
21
+
22
+ DEFAULT_OPTIONS = {
23
+ compress_threshold: COMPRESS_THRESHOLD,
24
+ compress: true,
25
+ compressor_class: BrotliCompressor
26
+ }
27
+
12
28
  attr_reader :core_store
13
29
 
14
30
  def initialize(core_store, options = {})
@@ -19,11 +35,11 @@ module RailsBrotliCache
19
35
  "br-"
20
36
  end
21
37
 
22
- @compressor_class = compressor_class(options, default: BrotliCompressor)
38
+ @init_options = options.reverse_merge(DEFAULT_OPTIONS)
23
39
  end
24
40
 
25
41
  def fetch(name, options = nil, &block)
26
- options ||= {}
42
+ options = (options || {}).reverse_merge(@init_options)
27
43
 
28
44
  if !block_given? && options[:force]
29
45
  raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
@@ -42,7 +58,7 @@ module RailsBrotliCache
42
58
  end
43
59
 
44
60
  def write(name, value, options = nil)
45
- options = (options || {}).reverse_merge(compress: true)
61
+ options = (options || {}).reverse_merge(@init_options)
46
62
  payload = compressed(value, options)
47
63
 
48
64
  @core_store.write(
@@ -53,6 +69,8 @@ module RailsBrotliCache
53
69
  end
54
70
 
55
71
  def read(name, options = nil)
72
+ options = (options || {}).reverse_merge(@init_options)
73
+
56
74
  payload = @core_store.read(
57
75
  cache_key(name),
58
76
  options
@@ -62,7 +80,7 @@ module RailsBrotliCache
62
80
  end
63
81
 
64
82
  def write_multi(hash, options = nil)
65
- options ||= {}
83
+ options = (options || {}).reverse_merge(@init_options)
66
84
  new_hash = hash.map do |key, val|
67
85
  [
68
86
  cache_key(key),
@@ -79,6 +97,7 @@ module RailsBrotliCache
79
97
  def read_multi(*names)
80
98
  options = names.extract_options!
81
99
  names = names.map { |name| cache_key(name) }
100
+ options = options.reverse_merge(@init_options)
82
101
 
83
102
  Hash[core_store.read_multi(*names, options).map do |key, val|
84
103
  [source_cache_key(key), uncompressed(val, options)]
@@ -88,6 +107,7 @@ module RailsBrotliCache
88
107
  def fetch_multi(*names)
89
108
  options = names.extract_options!
90
109
  names = names.map { |name| cache_key(name) }
110
+ options = options.reverse_merge(@init_options)
91
111
 
92
112
  @core_store.fetch_multi(
93
113
  *names, options.merge(compress: false)
@@ -125,13 +145,11 @@ module RailsBrotliCache
125
145
  private
126
146
 
127
147
  def compressed(value, options)
128
- options ||= {}
129
-
130
148
  return value if value.is_a?(Integer)
131
149
  serialized = Marshal.dump(value)
132
150
 
133
- if serialized.bytesize >= COMPRESS_THRESHOLD && !options.fetch(:compress, true) == false
134
- compressor = compressor_class(options, default: @compressor_class)
151
+ if serialized.bytesize >= options.fetch(:compress_threshold) && !options.fetch(:compress) == false
152
+ compressor = options.fetch(:compressor_class)
135
153
  compressed_payload = compressor.deflate(serialized)
136
154
  if compressed_payload.bytesize < serialized.bytesize
137
155
  MARK_BR_COMPRESSED + compressed_payload
@@ -144,14 +162,12 @@ module RailsBrotliCache
144
162
  end
145
163
 
146
164
  def uncompressed(payload, options)
147
- options ||= {}
148
-
149
165
  return nil unless payload.present?
150
166
 
151
167
  return payload if payload.is_a?(Integer)
152
168
 
153
169
  serialized = if payload.start_with?(MARK_BR_COMPRESSED)
154
- compressor = compressor_class(options, default: @compressor_class)
170
+ compressor = options.fetch(:compressor_class)
155
171
  compressor.inflate(payload.byteslice(1..-1))
156
172
  else
157
173
  payload
@@ -160,15 +176,6 @@ module RailsBrotliCache
160
176
  Marshal.load(serialized)
161
177
  end
162
178
 
163
- def compressor_class(options, default:)
164
- options = options || {}
165
- if (klass = options[:compressor_class])
166
- klass
167
- else
168
- default
169
- end
170
- end
171
-
172
179
  def cache_key(name)
173
180
  "#{@prefix}#{name}"
174
181
  end
@@ -176,15 +183,5 @@ module RailsBrotliCache
176
183
  def source_cache_key(name)
177
184
  name.delete_prefix(@prefix.to_s)
178
185
  end
179
-
180
- class BrotliCompressor
181
- def self.deflate(payload)
182
- ::Brotli.deflate(payload, quality: BR_COMPRESS_QUALITY)
183
- end
184
-
185
- def self.inflate(payload)
186
- ::Brotli.inflate(payload)
187
- end
188
- end
189
186
  end
190
187
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsBrotliCache
4
- VERSION = "0.3.14"
4
+ VERSION = "0.4.1"
5
5
  end
@@ -4,16 +4,6 @@ require 'spec_helper'
4
4
 
5
5
  return unless ENV['RAILS_CACHE_STORE'] == 'redis_cache_store'
6
6
 
7
- class DummyCompressor
8
- def self.deflate(payload)
9
- payload
10
- end
11
-
12
- def self.inflate(payload)
13
- payload
14
- end
15
- end
16
-
17
7
  describe RailsBrotliCache do
18
8
  let(:options) do
19
9
  {}
@@ -49,12 +39,6 @@ describe RailsBrotliCache do
49
39
  expect($redis.get("gz-test-key").size < $redis.get("br-test-key").size).to eq true
50
40
  end
51
41
 
52
- it "allows specyfing custom compressor class" do
53
- Rails.cache.write("gz-test-key", json)
54
- cache_store.write("test-key", json, compressor_class: DummyCompressor)
55
- expect($redis.get("gz-test-key").size < $redis.get("br-test-key").size).to eq true
56
- end
57
-
58
42
  describe "disable_prefix" do
59
43
  context "default prefix" do
60
44
  it "appends 'br-' prefix" do
@@ -4,7 +4,28 @@ require 'spec_helper'
4
4
 
5
5
  describe RailsBrotliCache do
6
6
  subject(:cache_store) do
7
- RailsBrotliCache::Store.new(ActiveSupport::Cache::MemoryStore.new)
7
+ RailsBrotliCache::Store.new(
8
+ ActiveSupport::Cache::MemoryStore.new,
9
+ options
10
+ )
11
+ end
12
+
13
+ let(:big_enough_to_compress_value) do
14
+ SecureRandom.hex(2048)
15
+ end
16
+
17
+ let(:options) do
18
+ {}
19
+ end
20
+
21
+ class DummyCompressor
22
+ def self.deflate(payload)
23
+ Zlib::Deflate.deflate(payload)
24
+ end
25
+
26
+ def self.inflate(payload)
27
+ Zlib::Inflate.inflate(payload)
28
+ end
8
29
  end
9
30
 
10
31
  describe "#fetch" do
@@ -40,12 +61,30 @@ describe RailsBrotliCache do
40
61
  end
41
62
 
42
63
  it "stores value in the configured Rails.cache when options passed" do
43
- big_enough_to_compress_value = SecureRandom.hex(2048)
44
64
  cache_store.fetch("test-key", expires_in: 5.seconds) { big_enough_to_compress_value }
45
65
  expect(cache_store.read("test-key")).to eq big_enough_to_compress_value
46
66
  end
47
67
  end
48
68
 
69
+ describe "#write_multi and #read_multi" do
70
+ it "works" do
71
+ values = {
72
+ "key_1" => big_enough_to_compress_value,
73
+ "key_2" => 123
74
+ }
75
+
76
+ cache_store.write_multi(values, expires_in: 5.seconds)
77
+ expect(cache_store.read_multi("key_1", "key_2")).to eq values
78
+ end
79
+ end
80
+
81
+ describe "fetch_multi" do
82
+ it "works" do
83
+ cache_store.fetch_multi("key_1", "key_2", expires_in: 5.seconds) { big_enough_to_compress_value }
84
+ expect(cache_store.read("key_1")).to eq big_enough_to_compress_value
85
+ end
86
+ end
87
+
49
88
  describe "#increment and #decrement" do
50
89
  it "works" do
51
90
  cache_store.write("integer-key", 0)
@@ -78,20 +117,60 @@ describe RailsBrotliCache do
78
117
  end
79
118
 
80
119
  describe "#read and #write" do
120
+ let(:one_kb_value) do
121
+ SecureRandom.hex(512)
122
+ end
123
+
81
124
  it "reads values stored in Rails cache with a prefix" do
82
125
  expect(cache_store.read("test-key")).to eq nil
83
- expect(cache_store.write("test-key", 1234))
84
- expect(cache_store.read("test-key")).to eq 1234
126
+ expect(cache_store.write("test-key", big_enough_to_compress_value))
127
+ expect(cache_store.read("test-key")).to eq big_enough_to_compress_value
85
128
  end
86
129
 
87
- context "payloads smaller then 1kb" do
88
- before do
89
- expect(Brotli).not_to receive(:deflate)
130
+ describe ":compressor_class option" do
131
+ context "as an init config" do
132
+ let(:options) do
133
+ { compressor_class: DummyCompressor }
134
+ end
135
+
136
+ it "calls the custom compressor_class" do
137
+ expect(DummyCompressor).to receive(:deflate).and_call_original
138
+ cache_store.write("test-key", one_kb_value)
139
+ expect(DummyCompressor).to receive(:inflate).and_call_original
140
+ cache_store.read("test-key")
141
+ end
142
+ end
143
+
144
+ context "as an method call" do
145
+ it "calls the custom compressor_class" do
146
+ expect(DummyCompressor).to receive(:deflate).and_call_original
147
+ cache_store.write("test-key", one_kb_value, compressor_class: DummyCompressor)
148
+ expect(DummyCompressor).to receive(:inflate).and_call_original
149
+ cache_store.read("test-key", compressor_class: DummyCompressor)
150
+ end
151
+ end
152
+ end
153
+
154
+ describe ":compress_threshold option" do
155
+ it "applies compression for larger objects" do
156
+ expect(Brotli).to receive(:deflate).and_call_original
157
+ cache_store.write("test-key", one_kb_value)
90
158
  end
91
159
 
92
- it "does not apply compression" do
160
+ it "does not apply compression for smaller objects" do
161
+ expect(Brotli).not_to receive(:deflate)
93
162
  cache_store.write("test-key", 123)
94
- expect(cache_store.read("test-key")).to eq 123
163
+ end
164
+
165
+ context "custom :compress_threshold value" do
166
+ let(:options) do
167
+ { compress_threshold: 2.kilobyte }
168
+ end
169
+
170
+ it "does not apply compression for objects smaller then custom threshold" do
171
+ expect(Brotli).not_to receive(:deflate)
172
+ cache_store.write("test-key", one_kb_value)
173
+ end
95
174
  end
96
175
  end
97
176
  end
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.3.14
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - pawurb
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-31 00:00:00.000000000 Z
11
+ date: 2023-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails