rails-brotli-cache 0.1.0 → 0.2.0
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 +4 -4
- data/README.md +41 -29
- data/Rakefile +1 -1
- data/lib/rails-brotli-cache/store.rb +87 -0
- data/lib/rails-brotli-cache/version.rb +1 -1
- data/lib/rails-brotli-cache.rb +1 -67
- data/rails-brotli-cache.gemspec +2 -2
- data/spec/dummy/config/environments/development.rb +1 -1
- data/spec/rails-brotli-cache/rails_store_spec.rb +84 -0
- data/spec/rails-brotli-cache/redis_spec.rb +7 -18
- data/spec/rails-brotli-cache/store_spec.rb +78 -0
- data/spec/spec_helper.rb +11 -0
- metadata +9 -6
- data/spec/rails-brotli-cache/common_spec.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01d8f09dfdea5ea7f2c19ce63e44b88322b319bfcda33f9efeeb679710e78f87
|
4
|
+
data.tar.gz: bd6df6fadfd6206ed598dab1ced924d59e5c27da6f1c8a0eaeed434f934219c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7919aaad175395d8494f20f1e40b6b5d96e6bd68a3aa60036dd0aa9682b8251e06139fa56748cfe4a5660be3aea5f09f9b7609806336b47b954cefadca227c1d
|
7
|
+
data.tar.gz: 41ddc8e815662f7f0e9037e5b0beaeacf48cb62eac1c05380b3be44664ed951256cf185d2ecc730f406f7b8a7ee615cad782e68f037907a37b56a1a658766f1d
|
data/README.md
CHANGED
@@ -1,75 +1,87 @@
|
|
1
1
|
# Rails Brotli Cache [](https://badge.fury.io/rb/rails-brotli-cache) [](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).
|
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
|
9
|
+
Brotli cache works as a proxy layer wrapping the underlying cache data store.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
default_cache = ActiveSupport::Cache::RedisCacheStore.new(redis: $redis)
|
13
|
+
brotli_cache = RailsBrotliCache::Store.new(default_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
|
15
|
-
json.size # =>
|
16
|
-
|
17
|
-
|
19
|
+
json = File.read("sample.json") # sample 435kb JSON text
|
20
|
+
json.size # => 435662
|
21
|
+
default_cache.write("json", json)
|
22
|
+
brotli_cache.write("json", json)
|
18
23
|
|
19
24
|
## Check the size of cache entry stored in Redis
|
20
|
-
$redis.get("json").size # =>
|
21
|
-
$redis.get("br-json").size # =>
|
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
|
-
|
29
|
-
|
33
|
+
default_cache.write("users", users)
|
34
|
+
brotli_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
|
42
|
+
json = File.read("sample.json") # sample 435kb JSON text
|
39
43
|
|
40
44
|
Benchmark.bm do |x|
|
41
|
-
x.report("
|
45
|
+
x.report("default_cache") do
|
42
46
|
1000.times do
|
43
|
-
|
44
|
-
|
47
|
+
default_cache.write("test", json)
|
48
|
+
default_cache.read("test")
|
45
49
|
end
|
46
|
-
|
47
50
|
end
|
48
|
-
|
51
|
+
|
52
|
+
x.report("brotli_cache") do
|
49
53
|
1000.times do
|
50
|
-
|
51
|
-
|
54
|
+
brotli_cache.write("test", json)
|
55
|
+
brotli_cache.read("test")
|
52
56
|
end
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
60
|
# user system total real
|
57
|
-
#
|
58
|
-
#
|
61
|
+
# default_cache 5.177678 0.216435 5.394113 ( 8.296072)
|
62
|
+
# brotli_cache 3.513312 0.323601 3.836913 ( 6.114179)
|
59
63
|
```
|
60
64
|
|
61
|
-
##
|
65
|
+
## Configuration
|
62
66
|
|
63
|
-
|
67
|
+
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
68
|
|
65
|
-
|
69
|
+
```ruby
|
70
|
+
config.cache_store = RailsBrotliCache::Store.new(
|
71
|
+
ActiveSupport::Cache::RedisCacheStore.new(redis: $redis)
|
72
|
+
)
|
73
|
+
```
|
66
74
|
|
67
75
|
```ruby
|
68
|
-
RailsBrotliCache.
|
69
|
-
|
70
|
-
|
71
|
-
|
76
|
+
config.cache_store = RailsBrotliCache::Store.new(
|
77
|
+
ActiveSupport::Cache::MemoryStore.new
|
78
|
+
)
|
79
|
+
```
|
72
80
|
|
81
|
+
```ruby
|
82
|
+
config.cache_store = RailsBrotliCache::Store.new(
|
83
|
+
ActiveSupport::Cache::MemCacheStore.new("localhost:11211")
|
84
|
+
)
|
73
85
|
```
|
74
86
|
|
75
87
|
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:
|
@@ -77,7 +89,7 @@ Gem appends `br-` to the cache key names to prevent conflicts with previously sa
|
|
77
89
|
`app/config/initializers/rails-brotli-cache.rb`
|
78
90
|
|
79
91
|
```ruby
|
80
|
-
|
92
|
+
Rails.cache.disable_prefix!
|
81
93
|
```
|
82
94
|
|
83
95
|
## 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("
|
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,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
|
data/lib/rails-brotli-cache.rb
CHANGED
@@ -1,73 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'rails-brotli-cache/
|
4
|
-
require 'brotli'
|
3
|
+
require 'rails-brotli-cache/store'
|
5
4
|
|
6
5
|
module RailsBrotliCache
|
7
|
-
COMPRESS_THRESHOLD = ENV.fetch("BR_CACHE_COMPRESS_THRESHOLD", 0).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
|
|
data/rails-brotli-cache.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.version = RailsBrotliCache::VERSION
|
9
9
|
gem.authors = ["pawurb"]
|
10
10
|
gem.email = ["contact@pawelurbanek.com"]
|
11
|
-
gem.summary = %q{ Rails cache using Brotli compression
|
12
|
-
gem.description = %q{ rails-brotli-cache allows to reduce storage needed for Rails cache by using Brotli compression which can produce outputs smaller by ~20
|
11
|
+
gem.summary = %q{ Rails cache using Brotli algorithm offers better compression and performance. }
|
12
|
+
gem.description = %q{ rails-brotli-cache allows to reduce storage needed for Rails cache by using Brotli compression which can produce outputs smaller by ~20%. }
|
13
13
|
gem.homepage = "https://github.com/pawurb/rails-brotli-cache"
|
14
14
|
gem.files = `git ls-files`.split("\n")
|
15
15
|
gem.test_files = gem.files.grep(%r{^(spec)/})
|
@@ -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 =
|
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,84 @@
|
|
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
|
+
|
77
|
+
describe "disable_prefix!" do
|
78
|
+
it "saves brotli cache entries without `br-` prefix" do
|
79
|
+
cache_store.disable_prefix!
|
80
|
+
cache_store.fetch("test-key") { 123 }
|
81
|
+
cache_store.instance_variable_set(:@prefix, "br-")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
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[
|
7
|
-
$redis = Redis.new
|
5
|
+
return unless ENV['RAILS_CACHE_STORE'] == 'redis_cache_store'
|
8
6
|
|
9
7
|
describe RailsBrotliCache do
|
10
|
-
|
11
|
-
|
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
|
-
|
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,7 @@ describe RailsBrotliCache do
|
|
24
24
|
|
25
25
|
it "applies more efficient brotli compression" do
|
26
26
|
Rails.cache.write("gz-test-key", json)
|
27
|
-
|
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
|
-
|
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
|
39
|
-
end
|
40
|
-
end
|
41
30
|
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.
|
4
|
+
version: 0.2.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-
|
11
|
+
date: 2023-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -95,7 +95,7 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
description: " rails-brotli-cache allows to reduce storage needed for Rails cache
|
98
|
-
by using Brotli compression which can produce outputs smaller by ~20
|
98
|
+
by using Brotli compression which can produce outputs smaller by ~20%. "
|
99
99
|
email:
|
100
100
|
- contact@pawelurbanek.com
|
101
101
|
executables: []
|
@@ -110,6 +110,7 @@ files:
|
|
110
110
|
- Rakefile
|
111
111
|
- docker-compose.yml.sample
|
112
112
|
- lib/rails-brotli-cache.rb
|
113
|
+
- lib/rails-brotli-cache/store.rb
|
113
114
|
- lib/rails-brotli-cache/version.rb
|
114
115
|
- rails-brotli-cache.gemspec
|
115
116
|
- spec/dummy/Gemfile
|
@@ -155,8 +156,9 @@ files:
|
|
155
156
|
- spec/dummy/public/robots.txt
|
156
157
|
- spec/dummy/vendor/.keep
|
157
158
|
- spec/fixtures/sample.json
|
158
|
-
- spec/rails-brotli-cache/
|
159
|
+
- spec/rails-brotli-cache/rails_store_spec.rb
|
159
160
|
- spec/rails-brotli-cache/redis_spec.rb
|
161
|
+
- spec/rails-brotli-cache/store_spec.rb
|
160
162
|
- spec/spec_helper.rb
|
161
163
|
homepage: https://github.com/pawurb/rails-brotli-cache
|
162
164
|
licenses:
|
@@ -180,7 +182,7 @@ requirements: []
|
|
180
182
|
rubygems_version: 3.1.6
|
181
183
|
signing_key:
|
182
184
|
specification_version: 4
|
183
|
-
summary: Rails cache using Brotli compression
|
185
|
+
summary: Rails cache using Brotli algorithm offers better compression and performance.
|
184
186
|
test_files:
|
185
187
|
- spec/dummy/Gemfile
|
186
188
|
- spec/dummy/README.md
|
@@ -225,6 +227,7 @@ test_files:
|
|
225
227
|
- spec/dummy/public/robots.txt
|
226
228
|
- spec/dummy/vendor/.keep
|
227
229
|
- spec/fixtures/sample.json
|
228
|
-
- spec/rails-brotli-cache/
|
230
|
+
- spec/rails-brotli-cache/rails_store_spec.rb
|
229
231
|
- spec/rails-brotli-cache/redis_spec.rb
|
232
|
+
- spec/rails-brotli-cache/store_spec.rb
|
230
233
|
- 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
|