infopark_component_cache 3.1.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
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)