infopark_component_cache 2.0.0 → 4.0.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/.gitignore +1 -1
- data/.rubocop.yml +25 -0
- data/.rubocop_todo.yml +115 -0
- data/.ruby-version +1 -1
- data/.travis.yml +24 -0
- data/Gemfile +2 -4
- data/Gemfile.lock +206 -0
- data/Gemfile.rails51 +6 -0
- data/Gemfile.rails51.lock +206 -0
- data/README.md +8 -0
- data/Rakefile +7 -7
- data/app/helpers/infopark_component_cache_helper.rb +2 -2
- data/infopark_component_cache.gemspec +15 -12
- data/lib/engine.rb +6 -7
- data/lib/infopark_component_cache.rb +1 -2
- data/lib/infopark_component_cache/abstract_cache_storage.rb +4 -3
- data/lib/infopark_component_cache/cache_storage.rb +1 -0
- data/lib/infopark_component_cache/component.rb +14 -6
- data/lib/infopark_component_cache/component_cache.rb +35 -31
- data/lib/infopark_component_cache/consistency_guard.rb +1 -1
- data/lib/infopark_component_cache/delayed_guard.rb +7 -7
- data/lib/infopark_component_cache/guards/cms_state_guard.rb +7 -6
- data/lib/infopark_component_cache/guards/last_changed.rb +5 -2
- data/lib/infopark_component_cache/guards/obj_count.rb +3 -3
- data/lib/infopark_component_cache/guards/valid_from.rb +7 -10
- data/lib/infopark_component_cache/guards/valid_until.rb +7 -9
- data/lib/infopark_component_cache/key_generator.rb +3 -3
- data/lib/infopark_component_cache/version.rb +1 -1
- data/lib/infopark_component_cache/volatile_cache.rb +1 -1
- data/lib/infopark_component_cache/volatile_cache_storage.rb +1 -0
- data/spec/dummy/Rakefile +1 -1
- data/spec/dummy/config.ru +1 -1
- data/spec/dummy/config/application.rb +1 -4
- data/spec/dummy/config/boot.rb +5 -5
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/environments/development.rb +1 -35
- data/spec/dummy/config/environments/test.rb +2 -8
- data/spec/dummy/config/initializers/secret_token.rb +1 -1
- data/spec/dummy/config/initializers/session_store.rb +1 -1
- data/spec/dummy/db/schema.rb +1 -2
- data/spec/lib/infopark_component_cache/component_cache_spec.rb +118 -0
- data/spec/lib/{delayed_guard_spec.rb → infopark_component_cache/delayed_guard_spec.rb} +3 -3
- data/spec/lib/{guards → infopark_component_cache/guards}/always_consistent_spec.rb +7 -6
- data/spec/lib/{guards → infopark_component_cache/guards}/last_changed_spec.rb +20 -12
- data/spec/lib/{guards → infopark_component_cache/guards}/never_consistent_spec.rb +7 -6
- data/spec/lib/{guards → infopark_component_cache/guards}/obj_count_spec.rb +20 -12
- data/spec/lib/{guards → infopark_component_cache/guards}/valid_from_spec.rb +20 -12
- data/spec/lib/{guards → infopark_component_cache/guards}/valid_until_spec.rb +23 -14
- data/spec/spec_helper.rb +10 -7
- data/spec/support/cache_switching_macros.rb +4 -4
- metadata +81 -30
@@ -9,9 +9,9 @@ module InfoparkComponentCache
|
|
9
9
|
class ValidUntil < CmsStateGuard
|
10
10
|
def consistent?
|
11
11
|
if min_valid_until_known?
|
12
|
-
|
12
|
+
no_changes_since?
|
13
13
|
else
|
14
|
-
|
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(
|
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(
|
40
|
-
if str_value.
|
41
|
-
|
42
|
-
|
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
|
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
|
@@ -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(
|
5
|
+
require File.expand_path("config/application", __dir__)
|
6
6
|
|
7
7
|
Dummy::Application.load_tasks
|
data/spec/dummy/config.ru
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
require File.expand_path(
|
1
|
+
require File.expand_path("boot", __dir__)
|
2
2
|
|
3
3
|
# Pick the frameworks you want:
|
4
4
|
require "active_record/railtie"
|
5
5
|
require "action_controller/railtie"
|
6
|
-
require "active_resource/railtie"
|
7
6
|
|
8
7
|
Bundler.require(*Rails.groups)
|
9
8
|
require "infopark_component_cache"
|
@@ -13,7 +12,5 @@ module Dummy
|
|
13
12
|
config.encoding = "utf-8"
|
14
13
|
config.filter_parameters += [:password]
|
15
14
|
config.active_support.escape_html_entities_in_json = true
|
16
|
-
config.active_record.whitelist_attributes = true
|
17
15
|
end
|
18
16
|
end
|
19
|
-
|
data/spec/dummy/config/boot.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
2
|
-
gemfile = File.expand_path(
|
1
|
+
require "rubygems"
|
2
|
+
gemfile = File.expand_path("../../../Gemfile", __dir__)
|
3
3
|
|
4
4
|
if File.exist?(gemfile)
|
5
|
-
ENV[
|
6
|
-
require
|
5
|
+
ENV["BUNDLE_GEMFILE"] = gemfile
|
6
|
+
require "bundler"
|
7
7
|
Bundler.setup
|
8
8
|
end
|
9
9
|
|
10
|
-
$:.unshift File.expand_path(
|
10
|
+
$:.unshift File.expand_path("../../../lib", __dir__)
|
@@ -1,37 +1,3 @@
|
|
1
1
|
Dummy::Application.configure do
|
2
|
-
|
3
|
-
|
4
|
-
# In the development environment your application's code is reloaded on
|
5
|
-
# every request. This slows down response time but is perfect for development
|
6
|
-
# since you don't have to restart the web server when you make code changes.
|
7
|
-
config.cache_classes = false
|
8
|
-
|
9
|
-
# Log error messages when you accidentally call methods on nil.
|
10
|
-
config.whiny_nils = true
|
11
|
-
|
12
|
-
# Show full error reports and disable caching
|
13
|
-
config.consider_all_requests_local = true
|
14
|
-
config.action_controller.perform_caching = false
|
15
|
-
|
16
|
-
# Don't care if the mailer can't send
|
17
|
-
config.action_mailer.raise_delivery_errors = false
|
18
|
-
|
19
|
-
# Print deprecation notices to the Rails logger
|
20
|
-
config.active_support.deprecation = :log
|
21
|
-
|
22
|
-
# Only use best-standards-support built into browsers
|
23
|
-
config.action_dispatch.best_standards_support = :builtin
|
24
|
-
|
25
|
-
# Raise exception on mass assignment protection for Active Record models
|
26
|
-
config.active_record.mass_assignment_sanitizer = :strict
|
27
|
-
|
28
|
-
# Log the query plan for queries taking more than this (works
|
29
|
-
# with SQLite, MySQL, and PostgreSQL)
|
30
|
-
config.active_record.auto_explain_threshold_in_seconds = 0.5
|
31
|
-
|
32
|
-
# Do not compress assets
|
33
|
-
config.assets.compress = false
|
34
|
-
|
35
|
-
# Expands the lines which load the assets
|
36
|
-
config.assets.debug = true
|
2
|
+
config.eager_load = false
|
37
3
|
end
|
@@ -1,10 +1,4 @@
|
|
1
1
|
Dummy::Application.configure do
|
2
|
-
config.
|
3
|
-
config.
|
4
|
-
config.consider_all_requests_local = true
|
5
|
-
config.action_controller.perform_caching = false
|
6
|
-
config.action_dispatch.show_exceptions = false
|
7
|
-
config.action_controller.allow_forgery_protection = false
|
8
|
-
config.active_record.mass_assignment_sanitizer = :strict
|
9
|
-
config.active_support.deprecation = :stderr
|
2
|
+
config.cache_store = :memory_store
|
3
|
+
config.eager_load = false
|
10
4
|
end
|
@@ -1 +1 @@
|
|
1
|
-
Dummy::Application.config.secret_token =
|
1
|
+
Dummy::Application.config.secret_token = "4806ad3606eea6388c0428912c8c8b37266f29c4c45fa5ecd233316cd5b6a0016aea879cfa603059a7c00296daef192955e26ae3298830bd904c8ff6a791feb1"
|
@@ -1 +1 @@
|
|
1
|
-
Dummy::Application.config.session_store :cookie_store, key:
|
1
|
+
Dummy::Application.config.session_store :cookie_store, key: "_dummy_session"
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -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
|
2
|
-
require
|
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)
|
@@ -1,19 +1,20 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "spec_helper"
|
2
|
+
require "infopark_component_cache/guards/always_consistent"
|
3
3
|
|
4
4
|
describe InfoparkComponentCache::Guards::AlwaysConsistent do
|
5
|
-
{"with cache disabled" => :disable_cache, "with cache enabled" => :enable_cache}.each do |context_description, macro|
|
5
|
+
{ "with cache disabled" => :disable_cache, "with cache enabled" => :enable_cache }.each do |context_description, macro|
|
6
6
|
context context_description do
|
7
|
-
|
7
|
+
send(macro)
|
8
8
|
|
9
|
-
subject { described_class.new(double) }
|
9
|
+
subject(:guard) { described_class.new(double) }
|
10
10
|
|
11
11
|
context "without a call to guard!" do
|
12
12
|
it { is_expected.to be_consistent }
|
13
13
|
end
|
14
14
|
|
15
15
|
context "with a call to guard!" do
|
16
|
-
before {
|
16
|
+
before { guard.guard! }
|
17
|
+
|
17
18
|
it { is_expected.to be_consistent }
|
18
19
|
end
|
19
20
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe InfoparkComponentCache::Guards::LastChanged do
|
4
|
+
subject(:guard) { described_class.new(cache_component_stub) }
|
5
|
+
|
4
6
|
let(:cache_component_stub) do
|
5
7
|
double.tap do |cache_component_stub|
|
6
8
|
cache_component_stub.stub(:cache_key) do |input|
|
@@ -9,7 +11,7 @@ describe InfoparkComponentCache::Guards::LastChanged do
|
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
12
|
-
let(:maximum_last_changed) { 10.minutes.ago
|
14
|
+
let(:maximum_last_changed) { 10.minutes.ago }
|
13
15
|
|
14
16
|
let(:obj_stub) do
|
15
17
|
double.tap do |obj_stub|
|
@@ -23,8 +25,6 @@ describe InfoparkComponentCache::Guards::LastChanged do
|
|
23
25
|
|
24
26
|
before { InfoparkComponentCache::CmsStateGuard.obj_root_class = obj_stub }
|
25
27
|
|
26
|
-
subject { described_class.new(cache_component_stub) }
|
27
|
-
|
28
28
|
context "with cache disabled" do
|
29
29
|
disable_cache
|
30
30
|
|
@@ -33,7 +33,8 @@ describe InfoparkComponentCache::Guards::LastChanged do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
context "with a call to guard!" do
|
36
|
-
before {
|
36
|
+
before { guard.guard! }
|
37
|
+
|
37
38
|
it { is_expected.not_to be_consistent }
|
38
39
|
end
|
39
40
|
end
|
@@ -47,19 +48,26 @@ describe InfoparkComponentCache::Guards::LastChanged do
|
|
47
48
|
end
|
48
49
|
|
49
50
|
context "with a call to guard!" do
|
50
|
-
before {
|
51
|
+
before { guard.guard! }
|
52
|
+
|
51
53
|
it { is_expected.to be_consistent }
|
52
54
|
end
|
53
55
|
|
54
|
-
context "after maximum last change changes" do
|
55
|
-
before
|
56
|
-
|
56
|
+
context "when after maximum last change changes" do
|
57
|
+
before do
|
58
|
+
guard.guard!
|
59
|
+
obj_stub.stub(:maximum).and_return(Time.now.to_iso)
|
60
|
+
end
|
61
|
+
|
57
62
|
it { is_expected.not_to be_consistent }
|
58
63
|
end
|
59
64
|
|
60
|
-
context "after maximum last change changes to a past date" do
|
61
|
-
before
|
62
|
-
|
65
|
+
context "when after maximum last change changes to a past date" do
|
66
|
+
before do
|
67
|
+
guard.guard!
|
68
|
+
obj_stub.stub(:maximum).and_return(1.month.ago.to_iso)
|
69
|
+
end
|
70
|
+
|
63
71
|
it { is_expected.to be_consistent }
|
64
72
|
end
|
65
73
|
end
|
@@ -1,19 +1,20 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "spec_helper"
|
2
|
+
require "infopark_component_cache/guards/never_consistent"
|
3
3
|
|
4
4
|
describe InfoparkComponentCache::Guards::NeverConsistent do
|
5
|
-
{"cache disabled" => :disable_cache, "cache enabled" => :enable_cache}.each do |context_description, macro|
|
5
|
+
{ "cache disabled" => :disable_cache, "cache enabled" => :enable_cache }.each do |context_description, macro|
|
6
6
|
context context_description do
|
7
|
-
|
7
|
+
send(macro)
|
8
8
|
|
9
|
-
subject { described_class.new(double) }
|
9
|
+
subject(:guard) { described_class.new(double) }
|
10
10
|
|
11
11
|
context "without a call to guard!" do
|
12
12
|
it { is_expected.not_to be_consistent }
|
13
13
|
end
|
14
14
|
|
15
15
|
context "with a call to guard!" do
|
16
|
-
before {
|
16
|
+
before { guard.guard! }
|
17
|
+
|
17
18
|
it { is_expected.not_to be_consistent }
|
18
19
|
end
|
19
20
|
end
|