cache_json 1.1.1 → 1.2.4

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: cbcbf754cd566cb8a11b52307d9ad70e68cc9690d2f880755f9ab55623541d55
4
- data.tar.gz: f7e7a36a74934e904f577d363464e85c8d2279f5d265d58173e8ed62d343176f
3
+ metadata.gz: 5a2871967748d37f7dcca4cc282329618481c1a94e927a91d0edef8dd261e787
4
+ data.tar.gz: 7bf987cd4de3a9a6067ba22e138fec40dd445fa84fbc3770cb78ccb14f409a5b
5
5
  SHA512:
6
- metadata.gz: 2d554661775ccfbdb4cda88e23c62dbde1f1e59ea76aa1658c667e79319bc0065fa1371e995bbb90c0ad1b97633bbe40ee1ba7fcc07582a3522fb049a0ba5658
7
- data.tar.gz: efbce041a5a4128c576d254f4219074087428d3dd0a46cd241b710fe5c81d7420cd269164698fd247ad7090cec094dc8cfe3aea9c0cf6b19b12ec7a534c71187
6
+ metadata.gz: 55429caa296c0ff0e0ec826a1de86be8cbad241f4957a1bb7d90498c36dfa3e8cb8a215725271a3c540bcf3e8a87b26198d3460697d1c24015ddc7f89989948d
7
+ data.tar.gz: 7fa105bcbffc4400dbd949b8c64b0b885b868d0e031a2d4047dc33ec8060ec7b40459a55879c6475581836d35ec5d198adc4f8e6e676077d8b97507cc6680e6f
@@ -1,14 +1,41 @@
1
- Style/GlobalVars:
2
- Enabled: false
3
-
4
- Style/Documentation:
5
- Enabled: false
1
+ Metrics/BlockLength:
2
+ Enabled: true
3
+ Exclude:
4
+ - "spec/**/*"
6
5
 
7
- Metrics/LineLength:
6
+ Layout/LineLength:
8
7
  Enabled: true
9
8
  Max: 100
10
9
 
11
- Metrics/BlockLength:
10
+ Layout/EmptyLinesAroundAttributeAccessor:
12
11
  Enabled: true
13
- Exclude:
14
- - "spec/**/*"
12
+
13
+ Layout/SpaceAroundMethodCallOperator:
14
+ Enabled: true
15
+
16
+ Lint/RaiseException:
17
+ Enabled: true
18
+
19
+ Lint/StructNewOverride:
20
+ Enabled: true
21
+
22
+ Style/ExponentialNotation:
23
+ Enabled: true
24
+
25
+ Style/HashEachMethods:
26
+ Enabled: true
27
+
28
+ Style/HashTransformKeys:
29
+ Enabled: true
30
+
31
+ Style/HashTransformValues:
32
+ Enabled: true
33
+
34
+ Style/SlicingWithRange:
35
+ Enabled: true
36
+
37
+ Style/GlobalVars:
38
+ Enabled: false
39
+
40
+ Style/Documentation:
41
+ Enabled: false
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cache_json (1.1.1)
4
+ cache_json (1.2.4)
5
5
  redis (>= 3.3.5, < 5)
6
6
 
7
7
  GEM
@@ -10,45 +10,47 @@ GEM
10
10
  ast (2.4.0)
11
11
  connection_pool (2.2.2)
12
12
  diff-lcs (1.3)
13
- jaro_winkler (1.5.3)
13
+ jaro_winkler (1.5.4)
14
14
  mock_redis (0.21.0)
15
- parallel (1.17.0)
16
- parser (2.6.3.0)
15
+ parallel (1.19.1)
16
+ parser (2.7.0.3)
17
17
  ast (~> 2.4.0)
18
- rack (2.0.7)
19
- rack-protection (2.0.5)
18
+ rack (2.2.3)
19
+ rack-protection (2.0.8.1)
20
20
  rack
21
21
  rainbow (3.0.0)
22
- rake (10.5.0)
23
- redis (4.1.2)
24
- rspec (3.8.0)
25
- rspec-core (~> 3.8.0)
26
- rspec-expectations (~> 3.8.0)
27
- rspec-mocks (~> 3.8.0)
28
- rspec-core (3.8.2)
29
- rspec-support (~> 3.8.0)
30
- rspec-expectations (3.8.4)
22
+ rake (13.0.1)
23
+ redis (4.1.3)
24
+ rexml (3.2.4)
25
+ rspec (3.9.0)
26
+ rspec-core (~> 3.9.0)
27
+ rspec-expectations (~> 3.9.0)
28
+ rspec-mocks (~> 3.9.0)
29
+ rspec-core (3.9.1)
30
+ rspec-support (~> 3.9.1)
31
+ rspec-expectations (3.9.0)
31
32
  diff-lcs (>= 1.2.0, < 2.0)
32
- rspec-support (~> 3.8.0)
33
- rspec-mocks (3.8.1)
33
+ rspec-support (~> 3.9.0)
34
+ rspec-mocks (3.9.1)
34
35
  diff-lcs (>= 1.2.0, < 2.0)
35
- rspec-support (~> 3.8.0)
36
- rspec-support (3.8.2)
37
- rubocop (0.72.0)
36
+ rspec-support (~> 3.9.0)
37
+ rspec-support (3.9.2)
38
+ rubocop (0.80.1)
38
39
  jaro_winkler (~> 1.5.1)
39
40
  parallel (~> 1.10)
40
- parser (>= 2.6)
41
+ parser (>= 2.7.0.1)
41
42
  rainbow (>= 2.2.2, < 4.0)
43
+ rexml
42
44
  ruby-progressbar (~> 1.7)
43
45
  unicode-display_width (>= 1.4.0, < 1.7)
44
46
  ruby-progressbar (1.10.1)
45
- sidekiq (5.2.7)
46
- connection_pool (~> 2.2, >= 2.2.2)
47
- rack (>= 1.5.0)
48
- rack-protection (>= 1.5.0)
49
- redis (>= 3.3.5, < 5)
47
+ sidekiq (6.0.5)
48
+ connection_pool (>= 2.2.2)
49
+ rack (~> 2.0)
50
+ rack-protection (>= 2.0.0)
51
+ redis (>= 4.1.0)
50
52
  timecop (0.9.1)
51
- unicode-display_width (1.6.0)
53
+ unicode-display_width (1.6.1)
52
54
 
53
55
  PLATFORMS
54
56
  ruby
@@ -57,11 +59,11 @@ DEPENDENCIES
57
59
  bundler (~> 2.0)
58
60
  cache_json!
59
61
  mock_redis (~> 0.21.0)
60
- rake (~> 10.0)
62
+ rake (~> 13.0)
61
63
  rspec (~> 3.0)
62
64
  rubocop (~> 0.72)
63
65
  sidekiq (>= 3.0, < 7)
64
66
  timecop (~> 0.9.1)
65
67
 
66
68
  BUNDLED WITH
67
- 2.0.2
69
+ 2.1.4
data/README.md CHANGED
@@ -54,6 +54,44 @@ CacheJSON.configure do |config|
54
54
  end
55
55
  ```
56
56
 
57
+ ## Automatic refreshing (Sidekiq)
58
+
59
+ There is a simple Sidekiq job that lets you pre-compute selected classes with specified ranges of arguments. All you have to do is add a `refresh` option:
60
+
61
+ ```ruby
62
+ class ExpensiveJob
63
+
64
+ include CacheJSON::Base
65
+
66
+
67
+ cache_json_options(
68
+ time_to_expire: 1.hour,
69
+ refresh: {
70
+ buffer: 5.minutes,
71
+ arguments: {
72
+ first: (5..10),
73
+ second: ['one option', 'another option'],
74
+ third: 'the only option',
75
+ fourth: -> { ['proc result'] }
76
+ }
77
+ }
78
+ )
79
+ ...
80
+ end
81
+ ```
82
+
83
+ The Sidekiq job will take the Cartesian product of all the argument ranges/arrays (all the combinations).
84
+
85
+ We leave it to you to schedule the job. If you're using https://github.com/moove-it/sidekiq-scheduler, you can do something like this:
86
+
87
+ ```yml
88
+ cache_json_worker:
89
+ every: "20s"
90
+ class: CacheJSON::Worker
91
+ ```
92
+
93
+ Whenever the worker runs, it checks which results have expired, and refreshes only those. If you pass in the `buffer` option, it will actually refresh keys that are that far away from expiring. In the example above, the worker will refresh the cache 5 minutes before it expires. This is good if you want to avoid cache misses altogether.
94
+
57
95
  ## Development
58
96
 
59
97
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency 'redis', '>= 3.3.5', '< 5'
31
31
  spec.add_development_dependency 'bundler', '~> 2.0'
32
32
  spec.add_development_dependency 'mock_redis', '~> 0.21.0'
33
- spec.add_development_dependency 'rake', '~> 10.0'
33
+ spec.add_development_dependency 'rake', '~> 13.0'
34
34
  spec.add_development_dependency 'rspec', '~> 3.0'
35
35
  spec.add_development_dependency 'rubocop', '~> 0.72'
36
36
  spec.add_development_dependency 'sidekiq', '>= 3.0', '< 7'
@@ -31,6 +31,10 @@ module CacheJSON
31
31
  $redis.del(class_key)
32
32
  end
33
33
 
34
+ def cache_expiring_soon?
35
+ $redis.ttl(full_key) < options[:refresh][:buffer].to_i
36
+ end
37
+
34
38
  private
35
39
 
36
40
  def full_key
@@ -8,7 +8,7 @@ module CacheJSON
8
8
  base.extend(ClassMethods)
9
9
  end
10
10
 
11
- def results(args)
11
+ def results(args = {})
12
12
  raise ArgumentError, 'Must use keyword arguments' unless args.is_a?(Hash)
13
13
 
14
14
  options = self.class.cache_json_full_options
@@ -17,13 +17,18 @@ module CacheJSON
17
17
  JSON.parse(refresh_cache!(args: args, cache: cache).to_json) # stringify keys
18
18
  end
19
19
 
20
+ def cache_expiring_soon?(args:, cache: nil)
21
+ cache ||= Cache.new(args: args, options: self.class.cache_json_full_options)
22
+ cache.cache_expiring_soon?
23
+ end
24
+
20
25
  def clear_cache!
21
26
  Cache.new(options: self.class.cache_json_full_options).clear_cache!
22
27
  end
23
28
 
24
29
  def refresh_cache!(args:, cache: nil)
25
30
  cache ||= Cache.new(args: args, options: self.class.cache_json_full_options)
26
- results = compute_results(args)
31
+ results = compute_results(**args)
27
32
  cache.cached_results = results
28
33
  results
29
34
  end
@@ -54,6 +59,10 @@ module CacheJSON
54
59
  adapter.clear_cache!
55
60
  end
56
61
 
62
+ def cache_expiring_soon?
63
+ adapter.cache_expiring_soon?
64
+ end
65
+
57
66
  def adapter
58
67
  @adapter ||= CacheJSON::Adapters::Redis.new(args: args, options: options)
59
68
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CacheJSON
4
- VERSION = '1.1.1'
4
+ VERSION = '1.2.4'
5
5
  end
@@ -22,62 +22,71 @@ module CacheJSON
22
22
  if klass
23
23
  klass.new.refresh_cache!(args: args)
24
24
  else
25
- generate_workers
25
+ AllPermutations.new.results.each do |perm|
26
+ if should_refresh?(perm[:klass], perm[:args])
27
+ CacheJSON::Worker.new.perform(klass: perm[:klass], args: perm[:args])
28
+ end
29
+ end
26
30
  end
27
31
  end
28
32
 
29
33
  private
30
34
 
31
- def generate_workers
32
- all_cache_classes.each do |klass|
33
- all_argument_permutations(klass).each do |args|
34
- CacheJSON::Worker.new.perform(klass: klass, args: args) if should_refresh?(klass, args)
35
- end
36
- end
35
+ def should_refresh?(klass, args)
36
+ !klass.new.check_cache(args: args) || klass.new.cache_expiring_soon?(args: args)
37
37
  end
38
38
 
39
- def all_cache_classes
40
- # TODO: make this more efficient
41
- ObjectSpace.each_object(Class).select do |klass|
42
- klass.included_modules.include? CacheJSON::Base
39
+ class AllPermutations
40
+ def results
41
+ all_cache_classes.flat_map do |klass|
42
+ all_argument_permutations(klass).map do |args|
43
+ {
44
+ klass: klass,
45
+ args: args
46
+ }
47
+ end
48
+ end
43
49
  end
44
- end
45
50
 
46
- def all_argument_permutations(klass)
47
- refresh_options = klass.cache_json_full_options[:refresh]
48
- if refresh_options
49
- all_combinations_with_fixed_points({}, refresh_options[:arguments])
50
- else
51
- []
51
+ def all_cache_classes
52
+ # TODO: make this more efficient
53
+ ObjectSpace.each_object(Class).select do |klass|
54
+ klass.included_modules.include? CacheJSON::Base
55
+ end
52
56
  end
53
- end
54
57
 
55
- def all_combinations_with_fixed_points(fixed_points, full_hash)
56
- non_fixed_points = full_hash.dup.delete_if { |k, _| fixed_points.key?(k) }
57
- if non_fixed_points.empty?
58
- [fixed_points]
59
- else
60
- pivot_key = non_fixed_points.keys.first
61
- values_for_key(non_fixed_points, pivot_key).flat_map do |pivot_key_value|
62
- new_fixed_points = fixed_points.merge(Hash[pivot_key, pivot_key_value])
63
- all_combinations_with_fixed_points(new_fixed_points, full_hash)
58
+ def all_argument_permutations(klass)
59
+ refresh_options = klass.cache_json_full_options[:refresh]
60
+ if refresh_options
61
+ all_combinations_with_fixed_points({}, refresh_options[:arguments])
62
+ else
63
+ []
64
64
  end
65
65
  end
66
- end
67
66
 
68
- def values_for_key(hsh, key)
69
- pivot_key_values = hsh[key]
70
- if pivot_key_values.is_a?(Proc)
71
- pivot_key_values.call
72
- elsif pivot_key_values.is_a?(Range) || pivot_key_values.is_a?(Array)
73
- pivot_key_values
74
- else
75
- [pivot_key_values]
67
+ def all_combinations_with_fixed_points(fixed_points, full_hash)
68
+ non_fixed_points = full_hash.dup.delete_if { |k, _| fixed_points.key?(k) }
69
+ if non_fixed_points.empty?
70
+ [fixed_points]
71
+ else
72
+ pivot_key = non_fixed_points.keys.first
73
+ values_for_key(non_fixed_points, pivot_key).flat_map do |pivot_key_value|
74
+ new_fixed_points = fixed_points.merge(Hash[pivot_key, pivot_key_value])
75
+ all_combinations_with_fixed_points(new_fixed_points, full_hash)
76
+ end
77
+ end
76
78
  end
77
- end
78
79
 
79
- def should_refresh?(klass, args)
80
- !klass.new.check_cache(args: args)
80
+ def values_for_key(hsh, key)
81
+ pivot_key_values = hsh[key]
82
+ if pivot_key_values.is_a?(Proc)
83
+ pivot_key_values.call
84
+ elsif pivot_key_values.is_a?(Range) || pivot_key_values.is_a?(Array)
85
+ pivot_key_values
86
+ else
87
+ [pivot_key_values]
88
+ end
89
+ end
81
90
  end
82
91
  end
83
92
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cache_json
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Gut
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-16 00:00:00.000000000 Z
11
+ date: 2020-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -64,14 +64,14 @@ dependencies:
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '10.0'
67
+ version: '13.0'
68
68
  type: :development
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '10.0'
74
+ version: '13.0'
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: rspec
77
77
  requirement: !ruby/object:Gem::Requirement
@@ -181,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
181
  - !ruby/object:Gem::Version
182
182
  version: '0'
183
183
  requirements: []
184
- rubygems_version: 3.0.3
184
+ rubygems_version: 3.1.2
185
185
  signing_key:
186
186
  specification_version: 4
187
187
  summary: Extremely simple Redis caching for any Ruby class