infopark_component_cache 3.2.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 +0 -1
- data/.rubocop.yml +25 -0
- data/.rubocop_todo.yml +115 -0
- data/.travis.yml +24 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +206 -0
- data/Gemfile.rails51 +6 -0
- data/Gemfile.rails51.lock +206 -0
- data/Rakefile +7 -7
- data/app/helpers/infopark_component_cache_helper.rb +2 -2
- data/infopark_component_cache.gemspec +13 -11
- 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 +8 -6
- data/lib/infopark_component_cache/component_cache.rb +31 -30
- 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 +6 -5
- data/lib/infopark_component_cache/guards/last_changed.rb +5 -2
- data/lib/infopark_component_cache/guards/obj_count.rb +1 -1
- 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 -2
- data/spec/dummy/config/boot.rb +5 -5
- data/spec/dummy/config/environment.rb +1 -1
- 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 +8 -8
- data/spec/support/cache_switching_macros.rb +4 -4
- metadata +71 -23
- data/spec/lib/compontent_cache_spec.rb +0 -116
data/Rakefile
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
|
3
3
|
begin
|
4
|
-
require
|
4
|
+
require "bundler/setup"
|
5
5
|
rescue LoadError
|
6
|
-
puts
|
6
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
7
7
|
end
|
8
8
|
|
9
|
-
APP_RAKEFILE = File.expand_path("
|
9
|
+
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
10
10
|
|
11
|
-
#load 'rails/tasks/engine.rake'
|
11
|
+
# load 'rails/tasks/engine.rake'
|
12
12
|
|
13
13
|
Bundler::GemHelper.install_tasks
|
14
14
|
|
15
|
-
require
|
16
|
-
require
|
15
|
+
require "rspec/core"
|
16
|
+
require "rspec/core/rake_task"
|
17
17
|
desc "Run all specs in spec directory (excluding plugin specs)"
|
18
18
|
RSpec::Core::RakeTask.new(:spec)
|
19
|
-
task :
|
19
|
+
task default: :spec
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module InfoparkComponentCacheHelper
|
2
|
-
def cache_tagged_component(obj, component, params={}, &block)
|
2
|
+
def cache_tagged_component(obj, component, params = {}, &block)
|
3
3
|
InfoparkComponentCache::ComponentCache.new(obj, component, params).fetch do
|
4
4
|
capture(&block)
|
5
5
|
end
|
6
6
|
end
|
7
|
-
end
|
7
|
+
end
|
@@ -1,28 +1,30 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
3
|
+
require "infopark_component_cache/version"
|
5
4
|
|
6
5
|
Gem::Specification.new do |gem|
|
7
6
|
gem.name = "infopark_component_cache"
|
8
7
|
gem.version = InfoparkComponentCache::VERSION
|
9
8
|
gem.authors = ["Tomasz Przedmojski, sveninfo"]
|
10
9
|
gem.email = ["tomasz.przedmojski@infopark.de"]
|
11
|
-
gem.description =
|
12
|
-
gem.summary =
|
10
|
+
gem.description = "Easy and intelligent fragment caching for RailsConnector projects"
|
11
|
+
gem.summary = "Fragment caching with automatic dependency resolution and cache invalidation."
|
13
12
|
gem.homepage = ""
|
14
13
|
gem.license = "Nonstandard"
|
15
14
|
|
16
15
|
gem.files = `git ls-files`.split($/)
|
17
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
18
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
18
|
gem.require_paths = ["lib"]
|
20
19
|
|
21
|
-
gem.add_dependency
|
20
|
+
gem.add_dependency "rails", "~> 5.0"
|
22
21
|
|
23
|
-
gem.add_dependency
|
22
|
+
gem.add_dependency "infopark_fiona_connector", "~> 7.0.1.5.2.3.rc5"
|
24
23
|
|
25
|
-
gem.add_development_dependency
|
26
|
-
gem.add_development_dependency
|
27
|
-
gem.add_development_dependency
|
24
|
+
gem.add_development_dependency "pry-byebug"
|
25
|
+
gem.add_development_dependency "rspec-rails", "~> 3.5"
|
26
|
+
gem.add_development_dependency "rubocop", "~> 0.87.1"
|
27
|
+
gem.add_development_dependency "rubocop-performance"
|
28
|
+
gem.add_development_dependency "rubocop-rspec"
|
29
|
+
gem.add_development_dependency "sqlite3", "~> 1.3.6"
|
28
30
|
end
|
data/lib/engine.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
require "
|
1
|
+
require "rails_connector/core_extensions.rb"
|
2
|
+
require "rails_connector/date_attribute.rb"
|
2
3
|
require "active_support/core_ext/numeric/time"
|
3
4
|
|
4
|
-
#require "infopark_component_cache/guards/always_consistent"
|
5
|
-
#require "infopark_component_cache/guards/never_consistent"
|
5
|
+
# require "infopark_component_cache/guards/always_consistent"
|
6
|
+
# require "infopark_component_cache/guards/never_consistent"
|
6
7
|
require "infopark_component_cache/guards/value_present"
|
7
8
|
require "infopark_component_cache/guards/cms_state_guard"
|
8
9
|
|
@@ -30,19 +31,17 @@ module InfoparkComponentCache
|
|
30
31
|
|
31
32
|
# @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
|
32
33
|
class Engine < Rails::Engine
|
33
|
-
|
34
34
|
initializer "component_cache.helpers" do
|
35
35
|
[
|
36
36
|
InfoparkComponentCacheHelper
|
37
37
|
].each do |helper|
|
38
|
-
ActionView::Base.__send__(
|
38
|
+
ActionView::Base.__send__(:include, helper)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
initializer "set default obj_root_class" do
|
43
43
|
InfoparkComponentCache.obj_root_class ||= ::Obj
|
44
|
-
CmsStateGuard.obj_root_class = InfoparkComponentCache.obj_root_class
|
44
|
+
CmsStateGuard.obj_root_class = InfoparkComponentCache.obj_root_class
|
45
45
|
end
|
46
|
-
|
47
46
|
end
|
48
47
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "singleton"
|
2
2
|
|
3
3
|
module InfoparkComponentCache
|
4
4
|
# @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
|
@@ -18,10 +18,10 @@ module InfoparkComponentCache
|
|
18
18
|
|
19
19
|
def read(key)
|
20
20
|
# it is possible to read disabled cache!
|
21
|
-
backing_storage.read(key)
|
21
|
+
backing_storage.read(key)
|
22
22
|
end
|
23
23
|
|
24
|
-
def write(key, value, options={})
|
24
|
+
def write(key, value, options = {})
|
25
25
|
backing_storage.write(key, value, options) if enabled?
|
26
26
|
rescue Errno::ENOSPC => e
|
27
27
|
Rails.logger.error("Unable to write cache, cache full: #{e.message}")
|
@@ -33,6 +33,7 @@ module InfoparkComponentCache
|
|
33
33
|
end
|
34
34
|
|
35
35
|
protected
|
36
|
+
|
36
37
|
def backing_storage
|
37
38
|
raise TypeError, "Cannot use abstract cache storage. Please provide a concrete cache storage in #{self.class.name}"
|
38
39
|
end
|
@@ -7,15 +7,17 @@ module InfoparkComponentCache
|
|
7
7
|
class Component
|
8
8
|
attr_reader :obj, :component, :params
|
9
9
|
|
10
|
-
def initialize(obj, component, params={})
|
11
|
-
@obj
|
10
|
+
def initialize(obj, component, params = {})
|
11
|
+
@obj = obj
|
12
|
+
@component = component
|
13
|
+
@params = params
|
12
14
|
end
|
13
15
|
|
14
16
|
def name
|
15
|
-
|
17
|
+
component
|
16
18
|
end
|
17
19
|
|
18
|
-
def cache_key(meta_prefix=nil)
|
20
|
+
def cache_key(meta_prefix = nil)
|
19
21
|
if meta_prefix
|
20
22
|
meta_prefix + "_" + KeyGenerator.generate_key(identity_hash)
|
21
23
|
else
|
@@ -25,8 +27,8 @@ module InfoparkComponentCache
|
|
25
27
|
|
26
28
|
def identity_hash
|
27
29
|
@params
|
28
|
-
.except(:obj) #avoid the (ruby) object_id as part of the cache key (to_s), because it will change for each request
|
29
|
-
.merge({:
|
30
|
+
.except(:obj) # avoid the (ruby) object_id as part of the cache key (to_s), because it will change for each request
|
31
|
+
.merge({ obj_name: @obj.name, obj_id: @obj.id, obj_component: @component })
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
@@ -24,27 +24,27 @@ module InfoparkComponentCache
|
|
24
24
|
# @see Guard::ValuePresent
|
25
25
|
# @see Guard::LastChanged
|
26
26
|
# @see Guard::ObjCount
|
27
|
-
def initialize(obj, name, params={}, guards=[])
|
27
|
+
def initialize(obj, name, params = {}, guards = [])
|
28
28
|
@component = Component.new(obj, name, params)
|
29
|
-
if guards.empty?
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
29
|
+
@guards = if guards.empty?
|
30
|
+
[
|
31
|
+
Guards::ValuePresent.new(@component),
|
32
|
+
Guards::LastChanged.new(@component),
|
33
|
+
Guards::ObjCount.new(@component),
|
34
|
+
Guards::ValidFrom.new(@component),
|
35
|
+
Guards::ValidUntil.new(@component)
|
36
|
+
]
|
37
|
+
else
|
38
|
+
guards.map do |klass_or_hash|
|
39
|
+
if klass_or_hash.kind_of?(Hash)
|
40
|
+
klass = klass_or_hash.delete(:guard)
|
41
|
+
klass.new(@component, klass_or_hash)
|
42
|
+
else
|
43
|
+
klass = klass_or_hash
|
44
|
+
klass.new(@component)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
48
|
end
|
49
49
|
|
50
50
|
# Checks if cache is valid (in consistent state).
|
@@ -54,12 +54,13 @@ module InfoparkComponentCache
|
|
54
54
|
#
|
55
55
|
# @return true if cache is valid and in consistent state
|
56
56
|
def expired?
|
57
|
-
return true
|
58
|
-
|
57
|
+
return true unless cache.enabled?
|
58
|
+
|
59
|
+
!guards.all?(&:consistent?)
|
60
|
+
rescue StandardError => e
|
61
|
+
raise e if Rails.env.test?
|
59
62
|
|
60
|
-
|
61
|
-
raise exception if Rails.env.test?
|
62
|
-
return true
|
63
|
+
true
|
63
64
|
end
|
64
65
|
|
65
66
|
# Checks if the cache is in consistent state and cached value
|
@@ -70,7 +71,7 @@ module InfoparkComponentCache
|
|
70
71
|
# @see {#expired?}
|
71
72
|
# @yieldreturn value to be used in case of cache miss
|
72
73
|
# @return cached value or the return value of the block
|
73
|
-
def fetch(&
|
74
|
+
def fetch(&_block)
|
74
75
|
if expired?
|
75
76
|
value = yield
|
76
77
|
begin
|
@@ -78,11 +79,11 @@ module InfoparkComponentCache
|
|
78
79
|
cache.write(component.cache_key, value)
|
79
80
|
ensure_consistency!
|
80
81
|
end
|
81
|
-
|
82
|
+
value
|
83
|
+
rescue StandardError => e
|
84
|
+
raise e if Rails.env.test?
|
82
85
|
|
83
|
-
|
84
|
-
raise exception if Rails.env.test?
|
85
|
-
return value
|
86
|
+
value
|
86
87
|
end
|
87
88
|
else
|
88
89
|
cache.read(component.cache_key)
|
@@ -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(
|
41
|
-
|
42
|
-
|
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,
|
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
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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(
|
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
|
-
|
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
|
@@ -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
|
-
|
11
|
+
no_changes_since?
|
13
12
|
else
|
14
|
-
|
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(
|
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(
|
40
|
-
if str_value.
|
41
|
-
|
42
|
-
|
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
|
-
|
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
|