rails-brotli-cache 0.3.13 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b682e9036d04afd87ca6369b612d524f65cf698ad53f23f06828d7e74690cd3a
4
- data.tar.gz: 55a11863fc1e5027be392685beb2cdcb39ed12ea3b66f2761dc4ecfacea49eaa
3
+ metadata.gz: 9f95297d5e14bdcdef5195541bdcde94c2c0cbbf91cf4cb546f77edce9e67c5b
4
+ data.tar.gz: 7c0d650a47162ecc053fa3dca2c7824f3b9de173289321212c57d600afa87897
5
5
  SHA512:
6
- metadata.gz: bfc5e4b2224c5525c91ec7061263dac04cb6f4d0b045000977cd9c1ca90bcf2e07579e08083c4fc3621760b4cc887645c4408d0695da6a98dc54a170a6200f0d
7
- data.tar.gz: 2fc5a1e3773b7d310e4b34b46f9209169dab055f02a8cbd7403ad8db467c399a517c7ca66d3a69e0feb89109a0596c8c1a9cd91f24ac533b05890921f6d7bfba
6
+ metadata.gz: c5fcbc3d4605329e227ca69fe94d320e16ea3f825babb6fa547e384df51b15879553800960615e1db9f24b3123747a07a9411837b6a5d9ff03591564f09a7840
7
+ data.tar.gz: 8e9200b30e53bdabee4f4f803384c84247aea22fb4e42d838e7eedd09fb8843b06b336f0ed4de401687a61a9dcd5ec37f51ade8daf3af8c322be1aace241e53d
@@ -9,6 +9,22 @@ module RailsBrotliCache
9
9
  BR_COMPRESS_QUALITY = ENV.fetch("BR_CACHE_COMPRESS_QUALITY", 5).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) == 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.13"
4
+ VERSION = "0.4.0"
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
@@ -38,6 +59,30 @@ describe RailsBrotliCache do
38
59
  expect(cache_store.read("forced-key")).to eq 2
39
60
  end
40
61
  end
62
+
63
+ it "stores value in the configured Rails.cache when options passed" do
64
+ cache_store.fetch("test-key", expires_in: 5.seconds) { big_enough_to_compress_value }
65
+ expect(cache_store.read("test-key")).to eq big_enough_to_compress_value
66
+ end
67
+ end
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
41
86
  end
42
87
 
43
88
  describe "#increment and #decrement" do
@@ -72,20 +117,60 @@ describe RailsBrotliCache do
72
117
  end
73
118
 
74
119
  describe "#read and #write" do
120
+ let(:one_kb_value) do
121
+ SecureRandom.hex(512)
122
+ end
123
+
75
124
  it "reads values stored in Rails cache with a prefix" do
76
125
  expect(cache_store.read("test-key")).to eq nil
77
- expect(cache_store.write("test-key", 1234))
78
- 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
79
128
  end
80
129
 
81
- context "payloads smaller then 1kb" do
82
- before do
83
- 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
84
142
  end
85
143
 
86
- it "does not apply compression" do
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)
158
+ end
159
+
160
+ it "does not apply compression for smaller objects" do
161
+ expect(Brotli).not_to receive(:deflate)
87
162
  cache_store.write("test-key", 123)
88
- 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
89
174
  end
90
175
  end
91
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.13
4
+ version: 0.4.0
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-29 00:00:00.000000000 Z
11
+ date: 2023-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails