rails-brotli-cache 0.1.1 → 0.2.1

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: 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