rails-brotli-cache 0.1.1 → 0.2.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: 16016a858334a3110d884e44bf6ce43fce75ac926c75973980f189a1477152b3
4
- data.tar.gz: 58756fbc6b6da6bde9144f07352302814d638664b567ad9f51ad069073ac0b35
3
+ metadata.gz: 44c290253b45a487daecc85b45026bd7d3f140644095c7f15cfb67dcee1299b8
4
+ data.tar.gz: d37323f26dda367401403714eb094dfd6a0e3274b7d88cb81eb2d5380ce91979
5
5
  SHA512:
6
- metadata.gz: 7276bf3a52a7861fc80c3be8772c190bbc153c26b26f88c152bce44083aae5cfb294b6720d23f40a0f6766905b6b17431d7c1295781604224af9f6738741a68a
7
- data.tar.gz: 4c784d5e0ce3fbe2c7242d875b4be25b87b2984148e54ab981d47069613d165b0065e57b0336f933e4bb7206453eb95cb66870dc2eb37d7b2bba005b52bf4e9f
6
+ metadata.gz: 537fe80385fbc5f8d339b56f789aaeefc45e2589456e2fb522afdcb3656af6254951654a0524b5136ad3cb25fb23c092ea6bc027377c39ed9f52645886a94fc0
7
+ data.tar.gz: a6057e3a65505003ee849e9f0a38a12963a78468c32275ca0e1d70ead490ddba7663d2a1d65b4359ca7fb626b27e15fc8552d77d9d35c353bbdf77f933fdb277
data/README.md CHANGED
@@ -1,78 +1,104 @@
1
1
  # Rails Brotli Cache [![Gem Version](https://badge.fury.io/rb/rails-brotli-cache.svg)](https://badge.fury.io/rb/rails-brotli-cache) [![CircleCI](https://circleci.com/gh/pawurb/rails-brotli-cache.svg?style=svg)](https://circleci.com/gh/pawurb/rails-brotli-cache)
2
2
 
3
- This gem enables support for compressing Ruby on Rails cache entries using the [Brotli compression algorithm](https://github.com/google/brotli). Brotli is a modern compression algorithm developed by Google that provides superior compression ratios and performance compared to the default Gzip algorithm.
3
+ This gem enables support for compressing Ruby on Rails cache entries using the [Brotli compression algorithm](https://github.com/google/brotli). `RailsBrotliCache` offers better compression and faster performance compared to the default `Rails.cache` regardless of the underlying data store.
4
4
 
5
5
  **The gem is currently in an early stage of development. Ideas on how to improve it and PRs are welcome.**
6
6
 
7
7
  ## Benchmarks
8
8
 
9
- Brotli offers a better compression and faster performance.
9
+ Brotli cache works as a proxy layer wrapping the underlying cache data store.
10
+
11
+ ```ruby
12
+ redis_cache = ActiveSupport::Cache::RedisCacheStore.new
13
+ brotli_redis_cache = RailsBrotliCache::Store.new(redis_cache)
14
+ ```
10
15
 
11
16
  **~25%** better compression of a sample JSON object:
12
17
 
13
18
  ```ruby
14
- json = File.read("sample.json") # sample 565kb JSON text
15
- json.size # => 562033
16
- Rails.cache.write("json", json)
17
- RailsBrotliCache.write("json", json)
19
+ json = File.read("sample.json") # sample 435kb JSON text
20
+ json.size # => 435662
21
+ redis_cache.write("json", json)
22
+ brotli_redis_cache.write("json", json)
18
23
 
19
24
  ## Check the size of cache entry stored in Redis
20
- $redis.get("json").size # => 41697
21
- $redis.get("br-json").size # => 31601
25
+ $redis.get("json").size # => 31698
26
+ $redis.get("br-json").size # => 24058
22
27
  ```
23
28
 
24
29
  **~20%** better compression of a sample ActiveRecord objects array:
25
30
 
26
31
  ```ruby
27
32
  users = User.limit(100).to_a # 100 ActiveRecord objects
28
- Rails.cache.write("users", users)
29
- RailsBrotliCache.write("users", users)
33
+ redis_cache.write("users", users)
34
+ brotli_redis_cache.write("users", users)
30
35
  $redis.get("users").size # => 12331
31
36
  $redis.get("br-users").size # => 10299
32
37
  ```
33
38
 
34
-
35
39
  **~25%** faster performance for reading/writing a larger JSON file:
36
40
 
37
41
  ```ruby
38
- json = File.read("sample.json") # sample 565kb JSON text
42
+ json = File.read("sample.json") # sample ~1mb JSON text
39
43
 
40
44
  Benchmark.bm do |x|
41
- x.report("Rails.cache") do
42
- 1000.times do
43
- Rails.cache.write("test", json)
44
- Rails.cache.read("test")
45
+ x.report("redis_cache") do
46
+ 100.times do
47
+ redis_cache.write("test", json)
48
+ redis_cache.read("test")
45
49
  end
46
50
  end
47
51
 
48
- x.report("RailsBrotliCache") do
49
- 1000.times do
50
- RailsBrotliCache.write("test", json)
51
- RailsBrotliCache.read("test")
52
+ x.report("brotli_redis_cache") do
53
+ 100.times do
54
+ brotli_redis_cache.write("test", json)
55
+ brotli_redis_cache.read("test")
52
56
  end
53
57
  end
58
+
59
+ # ...
54
60
  end
55
61
 
56
- # user system total real
57
- # Rails.cache 5.177678 0.216435 5.394113 ( 8.296072)
58
- # RailsBrotliCache 3.513312 0.323601 3.836913 ( 6.114179)
62
+ # memory_cache 2.081221 0.051615 2.132836 ( 2.132877)
63
+ # brotli_memory_cache 1.134411 0.032996 1.167407 ( 1.167418)
64
+ # redis_cache 1.782225 0.049936 1.832161 ( 2.523317)
65
+ # brotli_redis_cache 1.218365 0.051084 1.269449 ( 1.850894)
66
+ # memcached_cache 1.766268 0.045351 1.811619 ( 2.504233)
67
+ # brotli_memcached_cache 1.194646 0.051750 1.246396 ( 1.752982)
68
+ ```
69
+
70
+ Regardless of the underlying data store, Brotli cache offers between 20%-40% performance improvment.
71
+
72
+ You can run the benchmarks yourself by executing:
73
+
74
+ ```ruby
75
+ cp docker-compose.yml.sample docker-compose.yml
76
+ docker compose up -d
77
+ cd benchmarks
78
+ bundle install
79
+ ruby main.rb
59
80
  ```
60
81
 
61
- ## API
82
+ ## Configuration
62
83
 
63
- `RailsBrotliCache` module exposes methods that are compatible with the default `Rails.cache`. Values are stored in the underlying `Rails.cache` store but precompressed with Brotli algorithm.
84
+ Gem works as a drop-in replacement for a standard Rails cache store. Here's how you can configure it with different store types:
64
85
 
65
- You can use it just like the default `Rails.cache` API:
86
+ ```ruby
87
+ config.cache_store = RailsBrotliCache::Store.new(
88
+ ActiveSupport::Cache::RedisCacheStore.new(redis: $redis)
89
+ )
90
+ ```
66
91
 
67
92
  ```ruby
68
- RailsBrotliCache.read("test-key") # => nil
69
- RailsBrotliCache.fetch("test-key") { 123 } # => 123
70
- RailsBrotliCache.delete("test-key")
71
- RailsBrotliCache.read("test-key") # => nil
72
- RailsBrotliCache.write("test-key", 123, expires_in: 5.seconds)
73
- sleep 6
74
- RailsBrotliCache.read("test-key") # => nil
93
+ config.cache_store = RailsBrotliCache::Store.new(
94
+ ActiveSupport::Cache::MemoryStore.new
95
+ )
96
+ ```
75
97
 
98
+ ```ruby
99
+ config.cache_store = RailsBrotliCache::Store.new(
100
+ ActiveSupport::Cache::MemCacheStore.new("localhost:11211")
101
+ )
76
102
  ```
77
103
 
78
104
  Gem appends `br-` to the cache key names to prevent conflicts with previously saved cache entries. You can disable this behaviour by adding the following initializer file:
@@ -80,7 +106,7 @@ Gem appends `br-` to the cache key names to prevent conflicts with previously sa
80
106
  `app/config/initializers/rails-brotli-cache.rb`
81
107
 
82
108
  ```ruby
83
- RailsBrotliCache.disable_prefix!
109
+ Rails.cache.disable_prefix!
84
110
  ```
85
111
 
86
112
  ## Testing
data/Rakefile CHANGED
@@ -7,5 +7,5 @@ task default: :spec
7
7
 
8
8
  desc 'Test all cache_stores'
9
9
  task :test_all do
10
- system("TEST_CACHE_STORE=redis_cache_store bundle exec rspec spec/ && TEST_CACHE_STORE=mem_cache_store bundle exec rspec spec/ && bundle exec rspec spec/")
10
+ system("RAILS_CACHE_STORE=redis_cache_store bundle exec rspec spec/ && RAILS_CACHE_STORE=brotli_cache_store bundle exec rspec spec/ && bundle exec rspec spec/")
11
11
  end
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails-brotli-cache'
@@ -0,0 +1,69 @@
1
+ require 'rails'
2
+ require 'net/http'
3
+ require 'rails-brotli-cache'
4
+
5
+ memory_cache = ActiveSupport::Cache::MemoryStore.new(compress: true) # memory store does not use compression by default
6
+ brotli_memory_cache = RailsBrotliCache::Store.new(memory_cache)
7
+ redis_cache = ActiveSupport::Cache::RedisCacheStore.new
8
+ brotli_redis_cache = RailsBrotliCache::Store.new(redis_cache)
9
+ memcached_cache = ActiveSupport::Cache::MemCacheStore.new
10
+ brotli_memcached_cache = RailsBrotliCache::Store.new(memcached_cache)
11
+
12
+ json_uri = URI("https://raw.githubusercontent.com/pawurb/rails-brotli-cache/main/spec/fixtures/sample.json")
13
+ json = Net::HTTP.get(json_uri)
14
+
15
+ puts "Uncompressed JSON size: #{json.size}"
16
+ redis_cache.write("gz-json", json)
17
+ gzip_json_size = redis_cache.redis.get("gz-json").size
18
+ puts "Gzip JSON size: #{gzip_json_size}"
19
+ brotli_redis_cache.write("json", json)
20
+ br_json_size = redis_cache.redis.get("br-json").size
21
+ puts "Brotli JSON size: #{br_json_size}"
22
+ puts "~#{((gzip_json_size - br_json_size).to_f / gzip_json_size.to_f * 100).round}% improvment"
23
+ puts ""
24
+
25
+ iterations = 100
26
+
27
+ Benchmark.bm do |x|
28
+ x.report("memory_cache") do
29
+ iterations.times do
30
+ memory_cache.write("test", json)
31
+ memory_cache.read("test")
32
+ end
33
+ end
34
+
35
+ x.report("brotli_memory_cache") do
36
+ iterations.times do
37
+ brotli_memory_cache.write("test", json)
38
+ brotli_memory_cache.read("test")
39
+ end
40
+ end
41
+
42
+ x.report("redis_cache") do
43
+ iterations.times do
44
+ redis_cache.write("test", json)
45
+ redis_cache.read("test")
46
+ end
47
+ end
48
+
49
+ x.report("brotli_redis_cache") do
50
+ iterations.times do
51
+ brotli_redis_cache.write("test", json)
52
+ brotli_redis_cache.read("test")
53
+ end
54
+ end
55
+
56
+ x.report("memcached_cache") do
57
+ iterations.times do
58
+ memcached_cache.write("test", json)
59
+ memcached_cache.read("test")
60
+ end
61
+ end
62
+
63
+ x.report("brotli_memcached_cache") do
64
+ iterations.times do
65
+ brotli_memcached_cache.write("test", json)
66
+ brotli_memcached_cache.read("test")
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/cache'
4
+ require 'brotli'
5
+
6
+ module RailsBrotliCache
7
+ class Store < ::ActiveSupport::Cache::Store
8
+ COMPRESS_THRESHOLD = ENV.fetch("BR_CACHE_COMPRESS_THRESHOLD", 1).to_f * 1024.0
9
+ COMPRESS_QUALITY = ENV.fetch("BR_CACHE_COMPRESS_QUALITY", 5).to_i
10
+ MARK_BR_COMPRESSED = "\x02".b
11
+
12
+ def initialize(core_store, options = {})
13
+ @core_store = core_store
14
+ @prefix = "br-"
15
+ end
16
+
17
+ def fetch(name, options = nil, &block)
18
+ value = read(name, options)
19
+
20
+ if value.present? && !options&.fetch(:force, false) == true
21
+ return value
22
+ end
23
+
24
+ if block_given?
25
+ value = block.call
26
+ write(name, value, options)
27
+
28
+ value
29
+ elsif options && options[:force]
30
+ raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
31
+ else
32
+ read(name, options)
33
+ end
34
+ end
35
+
36
+ def write(name, value, options = nil)
37
+ serialized = Marshal.dump(value)
38
+
39
+ payload = if serialized.bytesize >= COMPRESS_THRESHOLD
40
+ MARK_BR_COMPRESSED + ::Brotli.deflate(serialized, quality: COMPRESS_QUALITY)
41
+ else
42
+ serialized
43
+ end
44
+
45
+ @core_store.write(
46
+ cache_key(name),
47
+ payload,
48
+ (options || {}).merge(compress: false)
49
+ )
50
+ end
51
+
52
+ def read(name, options = nil)
53
+ payload = @core_store.read(
54
+ cache_key(name),
55
+ options
56
+ )
57
+
58
+ return nil unless payload.present?
59
+
60
+ serialized = if payload.start_with?(MARK_BR_COMPRESSED)
61
+ ::Brotli.inflate(payload.byteslice(1..-1))
62
+ else
63
+ payload
64
+ end
65
+
66
+ Marshal.load(serialized)
67
+ end
68
+
69
+ def delete(name, options = nil)
70
+ @core_store.delete(cache_key(name), options)
71
+ end
72
+
73
+ def clear(options = nil)
74
+ @core_store.clear
75
+ end
76
+
77
+ def disable_prefix!
78
+ @prefix = nil
79
+ end
80
+
81
+ private
82
+
83
+ def cache_key(name)
84
+ "#{@prefix}#{name}"
85
+ end
86
+ end
87
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsBrotliCache
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.1"
5
5
  end
@@ -1,73 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails-brotli-cache/version'
4
- require 'brotli'
3
+ require 'rails-brotli-cache/store'
5
4
 
6
5
  module RailsBrotliCache
7
- COMPRESS_THRESHOLD = ENV.fetch("BR_CACHE_COMPRESS_THRESHOLD", 1).to_f * 1024.0
8
- COMPRESS_QUALITY = ENV.fetch("BR_CACHE_COMPRESS_QUALITY", 5).to_i
9
- MARK_BR_COMPRESSED = "\x02".b
10
- @@prefix = "br-"
11
-
12
- def self.fetch(name, options = nil, &block)
13
- value = read(name, options)
14
- return value if value.present?
15
-
16
- if block_given?
17
- value = block.call
18
- write(name, value, options)
19
-
20
- value
21
- elsif options && options[:force]
22
- raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
23
- else
24
- read(name, options)
25
- end
26
- end
27
-
28
- def self.write(name, value, options = nil)
29
- serialized = Marshal.dump(value)
30
-
31
- payload = if serialized.bytesize >= COMPRESS_THRESHOLD
32
- MARK_BR_COMPRESSED + ::Brotli.deflate(serialized, quality: COMPRESS_QUALITY)
33
- else
34
- serialized
35
- end
36
-
37
- Rails.cache.write(
38
- cache_key(name),
39
- payload,
40
- (options || {}).merge(compress: false)
41
- )
42
- end
43
-
44
- def self.read(name, options = nil)
45
- payload = Rails.cache.read(
46
- cache_key(name),
47
- options
48
- )
49
-
50
- return nil unless payload.present?
51
-
52
- serialized = if payload.start_with?(MARK_BR_COMPRESSED)
53
- ::Brotli.inflate(payload.byteslice(1..-1))
54
- else
55
- payload
56
- end
57
-
58
- Marshal.load(serialized)
59
- end
60
-
61
- def self.delete(name, options = nil)
62
- Rails.cache.delete(cache_key(name), options)
63
- end
64
-
65
- def self.disable_prefix!
66
- @@prefix = nil
67
- end
68
-
69
- def self.cache_key(name)
70
- "#{@@prefix}#{name}"
71
- end
72
6
  end
73
7
 
@@ -19,7 +19,7 @@ Rails.application.configure do
19
19
 
20
20
  # Enable/disable caching. By default caching is disabled.
21
21
  # Run rails dev:cache to toggle caching.
22
- config.cache_store = (ENV["TEST_CACHE_STORE"] || :memory_store).to_sym
22
+ config.cache_store = $rails_cache_store
23
23
 
24
24
  # Print deprecation notices to the Rails logger.
25
25
  config.active_support.deprecation = :log
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ return unless ENV['RAILS_CACHE_STORE'] == 'brotli_cache_store'
6
+
7
+ describe RailsBrotliCache do
8
+ subject(:cache_store) do
9
+ Rails.cache
10
+ end
11
+
12
+ it "sets the correct Rails.cache store" do
13
+ expect(Rails.cache.class).to eq RailsBrotliCache::Store
14
+ end
15
+
16
+ describe "#fetch" do
17
+ it "stores value in the configured Rails.cache with a prefix" do
18
+ cache_store.fetch("test-key") { 123 }
19
+ expect(cache_store.read("test-key")).to eq 123
20
+ end
21
+
22
+ it "returns nil for missing entries if block is not provided" do
23
+ expect(cache_store.fetch("missing-key")).to eq nil
24
+ end
25
+
26
+ it "executes block only once" do
27
+ counter = 0
28
+ cache_store.fetch("forced-key") { counter += 1 }
29
+ cache_store.fetch("forced-key") { counter += 1 }
30
+ expect(cache_store.read("forced-key")).to eq 1
31
+ end
32
+
33
+ context "{ force: true }" do
34
+ it "raises an error if block is not provided" do
35
+ expect {
36
+ cache_store.fetch("missing-key", force: true)
37
+ }.to raise_error(ArgumentError)
38
+ end
39
+
40
+ it "always refreshes cached entry if block is provided" do
41
+ counter = 0
42
+ cache_store.fetch("forced-key", force: true) { counter += 1 }
43
+ cache_store.fetch("forced-key", force: true) { counter += 1 }
44
+ expect(cache_store.read("forced-key")).to eq 2
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "#read and #write" do
50
+ it "reads values stored in Rails cache with a prefix" do
51
+ expect(cache_store.read("test-key")).to eq nil
52
+ expect(cache_store.write("test-key", 1234))
53
+ expect(cache_store.read("test-key")).to eq 1234
54
+ end
55
+
56
+ context "payloads smaller then 1kb" do
57
+ before do
58
+ expect(Brotli).not_to receive(:deflate)
59
+ end
60
+
61
+ it "does not apply compression" do
62
+ cache_store.write("test-key", 123)
63
+ expect(cache_store.read("test-key")).to eq 123
64
+ end
65
+ end
66
+ end
67
+
68
+ describe "#delete" do
69
+ it "removes the previously stored cache entry" do
70
+ expect(cache_store.write("test-key", 1234))
71
+ expect(cache_store.read("test-key")).to eq 1234
72
+ cache_store.delete("test-key")
73
+ expect(cache_store.read("test-key")).to eq nil
74
+ end
75
+ end
76
+ end
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
- require 'redis'
5
4
 
6
- return unless ENV["TEST_CACHE_STORE"] == "redis_cache_store"
7
- $redis = Redis.new
5
+ return unless ENV['RAILS_CACHE_STORE'] == 'redis_cache_store'
8
6
 
9
7
  describe RailsBrotliCache do
10
- it "sets correct cache store based on ENV variable" do
11
- expect(Rails.cache.class).to eq ActiveSupport::Cache::RedisCacheStore
8
+ subject(:cache_store) do
9
+ RailsBrotliCache::Store.new(
10
+ ActiveSupport::Cache::RedisCacheStore.new(redis: $redis)
11
+ )
12
12
  end
13
13
 
14
14
  describe "#fetch" do
15
15
  it "stores value in the configured redis cache store" do
16
- RailsBrotliCache.fetch("test-key") { 123 }
16
+ cache_store.fetch("test-key") { 123 }
17
17
  expect($redis.get("br-test-key")).to be_present
18
18
  end
19
19
  end
@@ -24,18 +24,20 @@ describe RailsBrotliCache do
24
24
 
25
25
  it "applies more efficient brotli compression" do
26
26
  Rails.cache.write("gz-test-key", json)
27
- RailsBrotliCache.write("test-key", json)
27
+ cache_store.write("test-key", json)
28
28
  expect($redis.get("gz-test-key").size > $redis.get("br-test-key").size).to eq true
29
29
  end
30
30
 
31
- context "payloads smaller then 1kb" do
32
- before do
33
- # expect(Brotli).not_to receive(:deflate)
34
- end
35
-
36
- it "does not apply compression" do
37
- RailsBrotliCache.write("test-key", 123)
38
- expect(RailsBrotliCache.read("test-key")).to eq 123
31
+ describe "disable_prefix!" do
32
+ it "saves brotli cache entries without `br-` prefix" do
33
+ cache_store.fetch("test-key") { 123 }
34
+ expect($redis.get("test-key")).to eq nil
35
+ expect($redis.get("br-test-key")).to be_present
36
+ cache_store.disable_prefix!
37
+ cache_store.fetch("test-key-2") { 123 }
38
+ expect($redis.get("br-test-key-2")).to eq nil
39
+ expect($redis.get("test-key-2")).to be_present
40
+ cache_store.instance_variable_set(:@prefix, "br-")
39
41
  end
40
42
  end
41
43
  end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe RailsBrotliCache do
6
+ subject(:cache_store) do
7
+ RailsBrotliCache::Store.new(ActiveSupport::Cache::MemoryStore.new)
8
+ end
9
+
10
+ describe "#fetch" do
11
+ it "stores value in the configured Rails.cache with a prefix" do
12
+ cache_store.fetch("test-key") { 123 }
13
+ expect(cache_store.read("test-key")).to eq 123
14
+ end
15
+
16
+ it "returns nil for missing entries if block is not provided" do
17
+ expect(cache_store.fetch("missing-key")).to eq nil
18
+ end
19
+
20
+ it "executes block only once" do
21
+ counter = 0
22
+ cache_store.fetch("forced-key") { counter += 1 }
23
+ cache_store.fetch("forced-key") { counter += 1 }
24
+ expect(cache_store.read("forced-key")).to eq 1
25
+ end
26
+
27
+ context "{ force: true }" do
28
+ it "raises an error if block is not provided" do
29
+ expect {
30
+ cache_store.fetch("missing-key", force: true)
31
+ }.to raise_error(ArgumentError)
32
+ end
33
+
34
+ it "always refreshes cached entry if block is provided" do
35
+ counter = 0
36
+ cache_store.fetch("forced-key", force: true) { counter += 1 }
37
+ cache_store.fetch("forced-key", force: true) { counter += 1 }
38
+ expect(cache_store.read("forced-key")).to eq 2
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "#read and #write" do
44
+ it "reads values stored in Rails cache with a prefix" do
45
+ expect(cache_store.read("test-key")).to eq nil
46
+ expect(cache_store.write("test-key", 1234))
47
+ expect(cache_store.read("test-key")).to eq 1234
48
+ end
49
+
50
+ context "payloads smaller then 1kb" do
51
+ before do
52
+ expect(Brotli).not_to receive(:deflate)
53
+ end
54
+
55
+ it "does not apply compression" do
56
+ cache_store.write("test-key", 123)
57
+ expect(cache_store.read("test-key")).to eq 123
58
+ end
59
+ end
60
+ end
61
+
62
+ describe "#delete" do
63
+ it "removes the previously stored cache entry" do
64
+ expect(cache_store.write("test-key", 1234))
65
+ expect(cache_store.read("test-key")).to eq 1234
66
+ cache_store.delete("test-key")
67
+ expect(cache_store.read("test-key")).to eq nil
68
+ end
69
+ end
70
+
71
+ describe "disable_prefix!" do
72
+ it "saves brotli cache entries without `br-` prefix" do
73
+ cache_store.disable_prefix!
74
+ cache_store.fetch("test-key") { 123 }
75
+ cache_store.instance_variable_set(:@prefix, "br-")
76
+ end
77
+ end
78
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,19 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
3
  require 'rails'
4
+ require 'redis'
4
5
 
5
6
  require_relative '../lib/rails-brotli-cache'
7
+
8
+ $redis = Redis.new
9
+ $rails_cache_store = if ENV['RAILS_CACHE_STORE'] == 'redis_cache_store'
10
+ ActiveSupport::Cache::RedisCacheStore.new(redis: $redis)
11
+ elsif ENV['RAILS_CACHE_STORE'] == 'brotli_cache_store'
12
+ RailsBrotliCache::Store.new(ActiveSupport::Cache::MemoryStore.new)
13
+ else
14
+ ActiveSupport::Cache::MemoryStore.new
15
+ end
16
+
6
17
  require_relative '../spec/dummy/config/environment'
7
18
  ENV['RAILS_ROOT'] ||= "#{File.dirname(__FILE__)}../../../spec/dummy"
8
19
 
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.1.1
4
+ version: 0.2.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-17 00:00:00.000000000 Z
11
+ date: 2023-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -108,8 +108,11 @@ files:
108
108
  - LICENSE.txt
109
109
  - README.md
110
110
  - Rakefile
111
+ - benchmarks/Gemfile
112
+ - benchmarks/main.rb
111
113
  - docker-compose.yml.sample
112
114
  - lib/rails-brotli-cache.rb
115
+ - lib/rails-brotli-cache/store.rb
113
116
  - lib/rails-brotli-cache/version.rb
114
117
  - rails-brotli-cache.gemspec
115
118
  - spec/dummy/Gemfile
@@ -155,8 +158,9 @@ files:
155
158
  - spec/dummy/public/robots.txt
156
159
  - spec/dummy/vendor/.keep
157
160
  - spec/fixtures/sample.json
158
- - spec/rails-brotli-cache/common_spec.rb
161
+ - spec/rails-brotli-cache/rails_store_spec.rb
159
162
  - spec/rails-brotli-cache/redis_spec.rb
163
+ - spec/rails-brotli-cache/store_spec.rb
160
164
  - spec/spec_helper.rb
161
165
  homepage: https://github.com/pawurb/rails-brotli-cache
162
166
  licenses:
@@ -225,6 +229,7 @@ test_files:
225
229
  - spec/dummy/public/robots.txt
226
230
  - spec/dummy/vendor/.keep
227
231
  - spec/fixtures/sample.json
228
- - spec/rails-brotli-cache/common_spec.rb
232
+ - spec/rails-brotli-cache/rails_store_spec.rb
229
233
  - spec/rails-brotli-cache/redis_spec.rb
234
+ - spec/rails-brotli-cache/store_spec.rb
230
235
  - spec/spec_helper.rb
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe RailsBrotliCache do
6
- context "without prepending Rails.cache" do
7
- describe "#fetch" do
8
- it "stores value in the configured Rails.cache with a prefix" do
9
- RailsBrotliCache.fetch("test-key") { 123 }
10
- expect(RailsBrotliCache.read("test-key")).to eq 123
11
- expect(Rails.cache.read("br-test-key")).to be_present
12
- end
13
-
14
- it "returns nil for missing entries if block is not provided" do
15
- expect(RailsBrotliCache.fetch("missing-key")).to eq nil
16
- end
17
-
18
- context "{ force: true }" do
19
- it "raises an error if block is not provided" do
20
- expect {
21
- RailsBrotliCache.fetch("missing-key", force: true)
22
- }.to raise_error(ArgumentError)
23
- end
24
-
25
- it "always refreshes cached entry if block is provided" do
26
-
27
- end
28
- end
29
- end
30
-
31
- describe "#read and #write" do
32
- it "reads values stored in Rails cache with a prefix" do
33
- expect(RailsBrotliCache.read("test-key")).to eq nil
34
- expect(RailsBrotliCache.write("test-key", 1234))
35
- expect(RailsBrotliCache.read("test-key")).to eq 1234
36
- end
37
- end
38
-
39
- describe "#delete" do
40
- it "removes the previously stored cache entry" do
41
- expect(RailsBrotliCache.write("test-key", 1234))
42
- expect(RailsBrotliCache.read("test-key")).to eq 1234
43
- RailsBrotliCache.delete("test-key")
44
- expect(RailsBrotliCache.read("test-key")).to eq nil
45
- end
46
- end
47
-
48
- describe "disable_prefix!" do
49
- it "saves brotli cache entries without `br-` prefix" do
50
- RailsBrotliCache.disable_prefix!
51
- RailsBrotliCache.fetch("test-key") { 123 }
52
- expect(Rails.cache.read("br-test-key")).to eq nil
53
- expect(Rails.cache.read("test-key")).to be_present
54
- RailsBrotliCache.class_variable_set(:@@prefix, "br-")
55
- end
56
- end
57
- end
58
- end