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