infopark_component_cache 3.1.0 → 4.1.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.
Files changed (55) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -1
  3. data/.rubocop.yml +25 -0
  4. data/.rubocop_todo.yml +115 -0
  5. data/.ruby-version +1 -1
  6. data/.travis.yml +24 -0
  7. data/Gemfile +3 -1
  8. data/Gemfile.lock +214 -0
  9. data/Gemfile.rails50 +6 -0
  10. data/Gemfile.rails50.lock +206 -0
  11. data/Gemfile.rails51 +6 -0
  12. data/Gemfile.rails51.lock +206 -0
  13. data/README.md +1 -1
  14. data/Rakefile +7 -7
  15. data/app/helpers/infopark_component_cache_helper.rb +2 -2
  16. data/infopark_component_cache.gemspec +16 -13
  17. data/lib/engine.rb +6 -7
  18. data/lib/infopark_component_cache.rb +1 -2
  19. data/lib/infopark_component_cache/abstract_cache_storage.rb +4 -3
  20. data/lib/infopark_component_cache/cache_storage.rb +1 -0
  21. data/lib/infopark_component_cache/component.rb +9 -5
  22. data/lib/infopark_component_cache/component_cache.rb +31 -30
  23. data/lib/infopark_component_cache/consistency_guard.rb +1 -1
  24. data/lib/infopark_component_cache/delayed_guard.rb +7 -7
  25. data/lib/infopark_component_cache/guards/cms_state_guard.rb +6 -5
  26. data/lib/infopark_component_cache/guards/last_changed.rb +5 -2
  27. data/lib/infopark_component_cache/guards/obj_count.rb +3 -3
  28. data/lib/infopark_component_cache/guards/valid_from.rb +7 -10
  29. data/lib/infopark_component_cache/guards/valid_until.rb +7 -9
  30. data/lib/infopark_component_cache/key_generator.rb +3 -3
  31. data/lib/infopark_component_cache/version.rb +1 -1
  32. data/lib/infopark_component_cache/volatile_cache.rb +1 -1
  33. data/lib/infopark_component_cache/volatile_cache_storage.rb +1 -0
  34. data/spec/dummy/Rakefile +1 -1
  35. data/spec/dummy/config.ru +1 -1
  36. data/spec/dummy/config/application.rb +4 -2
  37. data/spec/dummy/config/boot.rb +5 -5
  38. data/spec/dummy/config/environment.rb +1 -1
  39. data/spec/dummy/config/environments/development.rb +1 -0
  40. data/spec/dummy/config/environments/test.rb +1 -0
  41. data/spec/dummy/config/initializers/secret_token.rb +1 -1
  42. data/spec/dummy/config/initializers/session_store.rb +1 -1
  43. data/spec/dummy/db/schema.rb +1 -2
  44. data/spec/lib/infopark_component_cache/component_cache_spec.rb +118 -0
  45. data/spec/lib/{delayed_guard_spec.rb → infopark_component_cache/delayed_guard_spec.rb} +3 -3
  46. data/spec/lib/{guards → infopark_component_cache/guards}/always_consistent_spec.rb +7 -6
  47. data/spec/lib/{guards → infopark_component_cache/guards}/last_changed_spec.rb +20 -12
  48. data/spec/lib/{guards → infopark_component_cache/guards}/never_consistent_spec.rb +7 -6
  49. data/spec/lib/{guards → infopark_component_cache/guards}/obj_count_spec.rb +20 -12
  50. data/spec/lib/{guards → infopark_component_cache/guards}/valid_from_spec.rb +20 -12
  51. data/spec/lib/{guards → infopark_component_cache/guards}/valid_until_spec.rb +23 -14
  52. data/spec/spec_helper.rb +8 -8
  53. data/spec/support/cache_switching_macros.rb +4 -4
  54. metadata +96 -40
  55. data/spec/lib/compontent_cache_spec.rb +0 -116
@@ -15,7 +15,7 @@ module InfoparkComponentCache
15
15
  class ConsistencyGuard
16
16
  attr_reader :component, :options
17
17
 
18
- def initialize(component, options={})
18
+ def initialize(component, options = {})
19
19
  @component = component
20
20
  @options = options
21
21
  end
@@ -21,6 +21,7 @@ module InfoparkComponentCache
21
21
  end
22
22
 
23
23
  protected
24
+
24
25
  include VolatileCache
25
26
 
26
27
  def delayed_value(method_name)
@@ -30,17 +31,17 @@ module InfoparkComponentCache
30
31
  def still_delayed?(method_name)
31
32
  volatile_cache.exist?(delayed_value_key(method_name))
32
33
  end
33
-
34
+
34
35
  def delay_value(method_name, value, expiration)
35
36
  volatile_cache.write(delayed_value_key(method_name), value, expires_in: expiration)
36
37
  value
37
38
  end
38
39
 
39
40
  def delayed_value_key(method_name)
40
- KeyGenerator.generate_key(self.options.merge({
41
- delayed_method_name: method_name,
42
- delayed_class_name: self.class.name
43
- }))
41
+ KeyGenerator.generate_key(options.merge({
42
+ delayed_method_name: method_name,
43
+ delayed_class_name: self.class.name
44
+ }))
44
45
  end
45
46
 
46
47
  module ClassMethods
@@ -55,11 +56,10 @@ module InfoparkComponentCache
55
56
  if still_delayed?(method_name)
56
57
  value
57
58
  else
58
- delay_value(method_name, self.send(:"delayed_#{method_name}"), expiration)
59
+ delay_value(method_name, send(:"delayed_#{method_name}"), expiration)
59
60
  end
60
61
  end
61
62
  end
62
63
  end
63
-
64
64
  end
65
65
  end
@@ -17,15 +17,16 @@ module InfoparkComponentCache
17
17
  end
18
18
 
19
19
  protected
20
+
20
21
  # This method implements scoping on the root Obj class
21
22
  # and additional constraints for limiting object classes
22
23
  # used for lookup
23
24
  def scoped_relation
24
- if self.options[:obj_classes].present?
25
- conditions = {obj_class: self.options[:obj_classes]}
26
- else
27
- conditions = {}
28
- end
25
+ conditions = if options[:obj_classes].present?
26
+ { obj_class: options[:obj_classes] }
27
+ else
28
+ {}
29
+ end
29
30
  CmsStateGuard.obj_root_class.where(conditions)
30
31
  end
31
32
  end
@@ -27,12 +27,15 @@ module InfoparkComponentCache
27
27
 
28
28
  # @return [String] the cache key for storing {#current_last_changed}
29
29
  def cache_key
30
- component.cache_key('last_changed')
30
+ component.cache_key("last_changed")
31
31
  end
32
32
 
33
33
  # @return [Time] the timestamp of the most recent change to any Obj
34
34
  def current_last_changed
35
- RailsConnector::DateAttribute.parse(scoped_relation.maximum(:last_changed))
35
+ str_value = scoped_relation.maximum(:last_changed)
36
+ return str_value if str_value.kind_of? Time
37
+
38
+ RailsConnector::DateAttribute.parse(str_value)
36
39
  end
37
40
  end
38
41
  end
@@ -18,7 +18,7 @@ module InfoparkComponentCache
18
18
 
19
19
  # @return true if obj count can be read from cache with {#cache_key}
20
20
  def count_known?
21
- cache.exist?(cache_key) && cache.read(cache_key).kind_of?(Fixnum)
21
+ cache.exist?(cache_key) && cache.read(cache_key).kind_of?(Integer)
22
22
  end
23
23
 
24
24
  # @return true if no obj has been deleted or added since last {#guard!}
@@ -28,10 +28,10 @@ module InfoparkComponentCache
28
28
 
29
29
  # @return [String] the cache key for storing {#current_count}
30
30
  def cache_key
31
- component.cache_key('obj_count')
31
+ component.cache_key("obj_count")
32
32
  end
33
33
 
34
- # @return [Fixnum] the number of Objs in the database
34
+ # @return [Integer] the number of Objs in the database
35
35
  def current_count
36
36
  scoped_relation.count
37
37
  end
@@ -1,5 +1,4 @@
1
1
  require "infopark_component_cache/guards/cms_state_guard"
2
-
3
2
  module InfoparkComponentCache
4
3
  module Guards
5
4
  # @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
@@ -9,9 +8,9 @@ module InfoparkComponentCache
9
8
  class ValidFrom < CmsStateGuard
10
9
  def consistent?
11
10
  if min_valid_from_known?
12
- return no_changes_since?
11
+ no_changes_since?
13
12
  else
14
- return current_min_valid_from.nil?
13
+ current_min_valid_from.nil?
15
14
  end
16
15
  end
17
16
 
@@ -31,17 +30,15 @@ module InfoparkComponentCache
31
30
 
32
31
  # @return [String] the cache key for storing {#current_min_valid_from}
33
32
  def cache_key
34
- component.cache_key('min_valid_from')
33
+ component.cache_key("min_valid_from")
35
34
  end
36
35
 
37
36
  # @return [Time] the timestamp of the most recent valid_from, or nil if none found
38
37
  def current_min_valid_from
39
- str_value = scoped_relation.where('valid_from > ?', Time.now.to_iso).minimum(:valid_from)
40
- if str_value.present?
41
- RailsConnector::DateAttribute.parse(str_value)
42
- else
43
- nil
44
- end
38
+ str_value = scoped_relation.where("valid_from > ?", Time.now.to_iso).minimum(:valid_from)
39
+ return str_value if str_value.kind_of? Time
40
+
41
+ RailsConnector::DateAttribute.parse(str_value) if str_value.present?
45
42
  end
46
43
  end
47
44
  end
@@ -9,9 +9,9 @@ module InfoparkComponentCache
9
9
  class ValidUntil < CmsStateGuard
10
10
  def consistent?
11
11
  if min_valid_until_known?
12
- return no_changes_since?
12
+ no_changes_since?
13
13
  else
14
- return current_min_valid_until.nil?
14
+ current_min_valid_until.nil?
15
15
  end
16
16
  end
17
17
 
@@ -31,17 +31,15 @@ module InfoparkComponentCache
31
31
 
32
32
  # @return [String] the cache key for storing {#current_min_valid_until}
33
33
  def cache_key
34
- component.cache_key('min_valid_until')
34
+ component.cache_key("min_valid_until")
35
35
  end
36
36
 
37
37
  # @return [Time] the timestamp of the the object that will be deactivated in nearest future
38
38
  def current_min_valid_until
39
- str_value = scoped_relation.where('valid_until > ?', Time.now.to_iso).minimum(:valid_until)
40
- if str_value.present?
41
- RailsConnector::DateAttribute.parse(str_value)
42
- else
43
- nil
44
- end
39
+ str_value = scoped_relation.where("valid_until > ?", Time.now.to_iso).minimum(:valid_until)
40
+ return str_value if str_value.kind_of? Time
41
+
42
+ RailsConnector::DateAttribute.parse(str_value) if str_value.present?
45
43
  end
46
44
  end
47
45
  end
@@ -1,4 +1,4 @@
1
- require 'digest/sha2'
1
+ require "digest/sha2"
2
2
 
3
3
  module InfoparkComponentCache
4
4
  module KeyGenerator
@@ -19,7 +19,7 @@ module InfoparkComponentCache
19
19
  # uses some kind of hashing algorithm and therefore has the same
20
20
  # characteristics: equal inputs yield equal outputs, but different
21
21
  # inputs can yield same outputs (although it is very very unlikely)
22
- #
22
+ #
23
23
  # @param [String] string input string to be encoded
24
24
  # @return [String] string that is guaranteed to
25
25
  # consist only of alphanumeric characters,
@@ -28,4 +28,4 @@ module InfoparkComponentCache
28
28
  Digest::SHA2.hexdigest(string)
29
29
  end
30
30
  end
31
- end
31
+ end
@@ -1,3 +1,3 @@
1
1
  module InfoparkComponentCache
2
- VERSION = "3.1.0"
2
+ VERSION = "4.1.0".freeze
3
3
  end
@@ -3,7 +3,7 @@ require "infopark_component_cache/volatile_cache_storage"
3
3
  module InfoparkComponentCache
4
4
  # @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
5
5
  #
6
- # This module provides quick an convieniet access to
6
+ # This module provides quick an convieniet access to
7
7
  # VolatileCacheStorage in any class that includes it.
8
8
  module VolatileCache
9
9
  def volatile_cache
@@ -11,6 +11,7 @@ module InfoparkComponentCache
11
11
  # it is "nice to have" but also has to be extremely quick.
12
12
  class VolatileCacheStorage < AbstractCacheStorage
13
13
  protected
14
+
14
15
  def backing_storage
15
16
  @@backing_storage ||= ActiveSupport::Cache::MemoryStore.new({ size: 10.megabytes })
16
17
  end
data/spec/dummy/Rakefile CHANGED
@@ -2,6 +2,6 @@
2
2
  # Add your own tasks in files placed in lib/tasks ending in .rake,
3
3
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
4
 
5
- require File.expand_path('../config/application', __FILE__)
5
+ require File.expand_path("config/application", __dir__)
6
6
 
7
7
  Dummy::Application.load_tasks
data/spec/dummy/config.ru CHANGED
@@ -1,4 +1,4 @@
1
1
  # This file is used by Rack-based servers to start the application.
2
2
 
3
- require ::File.expand_path('../config/environment', __FILE__)
3
+ require ::File.expand_path("config/environment", __dir__)
4
4
  run Dummy::Application
@@ -1,4 +1,4 @@
1
- require File.expand_path('../boot', __FILE__)
1
+ require File.expand_path("boot", __dir__)
2
2
 
3
3
  # Pick the frameworks you want:
4
4
  require "active_record/railtie"
@@ -12,6 +12,8 @@ module Dummy
12
12
  config.encoding = "utf-8"
13
13
  config.filter_parameters += [:password]
14
14
  config.active_support.escape_html_entities_in_json = true
15
+ if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR == 2
16
+ config.active_record.sqlite3.represent_boolean_as_integer = true
17
+ end
15
18
  end
16
19
  end
17
-
@@ -1,10 +1,10 @@
1
- require 'rubygems'
2
- gemfile = File.expand_path('../../../../Gemfile', __FILE__)
1
+ require "rubygems"
2
+ gemfile = File.expand_path("../../../Gemfile", __dir__)
3
3
 
4
4
  if File.exist?(gemfile)
5
- ENV['BUNDLE_GEMFILE'] = gemfile
6
- require 'bundler'
5
+ ENV["BUNDLE_GEMFILE"] = gemfile
6
+ require "bundler"
7
7
  Bundler.setup
8
8
  end
9
9
 
10
- $:.unshift File.expand_path('../../../../lib', __FILE__)
10
+ $:.unshift File.expand_path("../../../lib", __dir__)
@@ -1,5 +1,5 @@
1
1
  # Load the rails application
2
- require File.expand_path('../application', __FILE__)
2
+ require File.expand_path("application", __dir__)
3
3
 
4
4
  # Initialize the rails application
5
5
  Dummy::Application.initialize!
@@ -1,2 +1,3 @@
1
1
  Dummy::Application.configure do
2
+ config.eager_load = false
2
3
  end
@@ -1,3 +1,4 @@
1
1
  Dummy::Application.configure do
2
2
  config.cache_store = :memory_store
3
+ config.eager_load = false
3
4
  end
@@ -1 +1 @@
1
- Dummy::Application.config.secret_token = '4806ad3606eea6388c0428912c8c8b37266f29c4c45fa5ecd233316cd5b6a0016aea879cfa603059a7c00296daef192955e26ae3298830bd904c8ff6a791feb1'
1
+ Dummy::Application.config.secret_token = "4806ad3606eea6388c0428912c8c8b37266f29c4c45fa5ecd233316cd5b6a0016aea879cfa603059a7c00296daef192955e26ae3298830bd904c8ff6a791feb1"
@@ -1 +1 @@
1
- Dummy::Application.config.session_store :cookie_store, key: '_dummy_session'
1
+ Dummy::Application.config.session_store :cookie_store, key: "_dummy_session"
@@ -1,3 +1,2 @@
1
- ActiveRecord::Schema.define(:version => 0) do
2
-
1
+ ActiveRecord::Schema.define(version: 0) do
3
2
  end
@@ -0,0 +1,118 @@
1
+ require "spec_helper"
2
+
3
+ describe InfoparkComponentCache::ComponentCache do
4
+ subject(:component_cache) { described_class.new(obj, name, params, [guard]) }
5
+
6
+ let(:obj) { double(name: "spec_obj", id: 2001) }
7
+ let(:name) { "spec_cached_component" }
8
+ let(:params) { { some: "additional", params: "supplied" } }
9
+ let(:guard) { Class.new(Struct.new(:component)) }
10
+
11
+ context "with caching disabled" do
12
+ before { allow(Rails.application.config.action_controller).to receive(:perform_caching).and_return(false) }
13
+
14
+ describe "#fetch" do
15
+ let(:value) { "very_hard_computation_required_for_this_string" }
16
+ let(:specific_guard) { component_cache.guards.first }
17
+
18
+ it "returns the passed the block value" do
19
+ expect(component_cache.fetch { value }).to eq(value)
20
+ end
21
+
22
+ it "never calls any methods on the guard" do
23
+ expect(specific_guard).not_to receive(:consistent?)
24
+ expect(specific_guard).not_to receive(:guard!)
25
+
26
+ component_cache.fetch { value }
27
+ end
28
+ end
29
+ end
30
+
31
+ context "with caching enabled" do
32
+ before { allow(Rails.application.config.action_controller).to receive(:perform_caching).and_return(true) }
33
+
34
+ let(:guard) do
35
+ Class.new(InfoparkComponentCache::ConsistencyGuard) do
36
+ def consistent?
37
+ cache.exist?(:guard_called)
38
+ end
39
+
40
+ def guard!
41
+ cache.write(:guard_called, 1)
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "#fetch" do
47
+ let(:value) { "very_hard_computation_required_for_this_string" }
48
+ let(:specific_guard) { component_cache.guards.first }
49
+ let(:computer) { double }
50
+
51
+ it "returns the passed the block value" do
52
+ expect(component_cache.fetch { value }).to eq(value)
53
+ end
54
+
55
+ it "calls the required methods on the guard" do
56
+ expect(specific_guard).to receive(:consistent?).exactly(3).times
57
+ expect(specific_guard).to receive(:guard!).exactly(3).times
58
+
59
+ 3.times { component_cache.fetch { value } }
60
+ end
61
+
62
+ it "only evalues the block once" do
63
+ expect(computer).to receive(:compute).and_return(value).once
64
+
65
+ 3.times { expect(component_cache.fetch { computer.compute }).to eq(value) }
66
+ end
67
+ end
68
+ end
69
+
70
+ describe "#compontent" do
71
+ subject(:component_cache) { described_class.new(obj, name, params).component }
72
+
73
+ it "stores the passed obj" do
74
+ expect(component_cache.obj).to eq(obj)
75
+ end
76
+
77
+ it "stores the passed name" do
78
+ expect(component_cache.name).to eq(name)
79
+ end
80
+
81
+ it "stores the passed params" do
82
+ expect(component_cache.params).to eq(params)
83
+ end
84
+ end
85
+
86
+ describe "#guards" do
87
+ subject(:component_cache) { described_class.new(obj, name, params, [guard_class1, guard_params]).guards }
88
+
89
+ let(:guard_class1) { Struct.new(:component) }
90
+ let(:guard_class2) { Struct.new(:compontent, :extra) }
91
+ let(:guard_params) { { guard: guard_class2, something: "more" } }
92
+
93
+ it "contains an array of passed guards" do
94
+ expect(component_cache).to match_array([
95
+ an_instance_of(guard_class1),
96
+ an_instance_of(guard_class2)
97
+ ])
98
+ end
99
+
100
+ it "preserves the extra params" do
101
+ expect(component_cache.last.extra).to eq(guard_params)
102
+ end
103
+
104
+ context "with no guards specified in the constructors" do
105
+ subject(:component_cache) { described_class.new(obj, name, params).guards }
106
+
107
+ it "contains standard guards" do
108
+ expect(component_cache).to match_array([
109
+ an_instance_of(InfoparkComponentCache::Guards::ValuePresent),
110
+ an_instance_of(InfoparkComponentCache::Guards::LastChanged),
111
+ an_instance_of(InfoparkComponentCache::Guards::ObjCount),
112
+ an_instance_of(InfoparkComponentCache::Guards::ValidFrom),
113
+ an_instance_of(InfoparkComponentCache::Guards::ValidUntil)
114
+ ])
115
+ end
116
+ end
117
+ end
118
+ end
@@ -1,5 +1,5 @@
1
- require 'spec_helper'
2
- require 'infopark_component_cache/delayed_guard'
1
+ require "spec_helper"
2
+ require "infopark_component_cache/delayed_guard"
3
3
 
4
4
  describe InfoparkComponentCache::DelayedGuard do
5
5
  let(:base_class_with_options) do
@@ -56,7 +56,7 @@ describe InfoparkComponentCache::DelayedGuard do
56
56
  end
57
57
  end
58
58
 
59
- context "after the delay has passed" do
59
+ context "when after the delay has passed" do
60
60
  specify "the calls returns new value" do
61
61
  first_value = delayed_subject.simple_counter
62
62
  expect(first_value).to eq(undelayed_subject.simple_counter)