infopark_component_cache 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/README.md +8 -0
- data/Rakefile +17 -9
- data/app/helpers/infopark_component_cache_helper.rb +1 -7
- data/infopark_component_cache.gemspec +6 -3
- data/lib/engine.rb +35 -1
- data/lib/infopark_component_cache.rb +0 -14
- data/lib/infopark_component_cache/abstract_cache_storage.rb +40 -0
- data/lib/infopark_component_cache/cache_storage.rb +10 -24
- data/lib/infopark_component_cache/component.rb +1 -3
- data/lib/infopark_component_cache/component_cache.rb +9 -12
- data/lib/infopark_component_cache/consistency_guard.rb +3 -4
- data/lib/infopark_component_cache/delayed_guard.rb +65 -0
- data/lib/infopark_component_cache/guards/always_consistent.rb +1 -1
- data/lib/infopark_component_cache/guards/cms_state_guard.rb +32 -0
- data/lib/infopark_component_cache/guards/delayed_last_changed.rb +18 -0
- data/lib/infopark_component_cache/guards/delayed_obj_count.rb +18 -0
- data/lib/infopark_component_cache/guards/delayed_valid_from.rb +18 -0
- data/lib/infopark_component_cache/guards/delayed_valid_until.rb +18 -0
- data/lib/infopark_component_cache/guards/last_changed.rb +3 -3
- data/lib/infopark_component_cache/guards/never_consistent.rb +1 -1
- data/lib/infopark_component_cache/guards/obj_count.rb +3 -3
- data/lib/infopark_component_cache/guards/valid_from.rb +3 -3
- data/lib/infopark_component_cache/guards/valid_until.rb +3 -3
- data/lib/infopark_component_cache/guards/value_present.rb +1 -1
- data/lib/infopark_component_cache/version.rb +1 -1
- data/lib/infopark_component_cache/volatile_cache.rb +13 -0
- data/lib/infopark_component_cache/volatile_cache_storage.rb +18 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/models/obj.rb +2 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +19 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +11 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/test.rb +10 -0
- data/spec/dummy/config/initializers/secret_token.rb +1 -0
- data/spec/dummy/config/initializers/session_store.rb +1 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +8 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +3 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/lib/delayed_guard_spec.rb +72 -0
- data/spec/lib/guards/always_consistent_spec.rb +21 -0
- data/spec/lib/guards/last_changed_spec.rb +66 -0
- data/spec/lib/guards/never_consistent_spec.rb +21 -0
- data/spec/lib/guards/obj_count_spec.rb +64 -0
- data/spec/lib/guards/valid_from_spec.rb +66 -0
- data/spec/lib/guards/valid_until_spec.rb +73 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/cache_switching_macros.rb +29 -0
- metadata +147 -79
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4c9951c7ea10085ae1cd14375a86ca566f3fcad1
|
4
|
+
data.tar.gz: adad2fd6542596562b972efd2dd8796f040cec53
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4ddbcdc5cd1d85e677ddf264e2044b82ad59d899eb9ecc7d6b55310de7ec23922151dfbe1fce2f27afb79d093cc8a1f4f3d9063d69b7c9373244030c097d56c4
|
7
|
+
data.tar.gz: 95256ba30f389cdb5d4984a67a231f68cd1a79bbb97839bec1250103cb03418b5485cf49c6efcec960fd9e456a458223ae0f2eda694f6ca8de205ad6116c5b1f
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.6
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -33,6 +33,14 @@ Alternatively you could use component cache directly:
|
|
33
33
|
This content will be cached
|
34
34
|
<% end %>
|
35
35
|
|
36
|
+
Most guard also provide an option to limit the lookup to specific object classes, for example:
|
37
|
+
|
38
|
+
<%= cache_tagged_component(@gallery, 'gallery', {}, [{guard: InfoparkComponentCache::ObjCount, obj_classes: ['Image']}]) do %>
|
39
|
+
This content will be cached
|
40
|
+
<% end %>
|
41
|
+
|
42
|
+
will only get invalidated when the number of objects of the class 'Image' changes in the CMS.
|
43
|
+
|
36
44
|
## Contributing
|
37
45
|
|
38
46
|
1. Fork it
|
data/Rakefile
CHANGED
@@ -1,11 +1,19 @@
|
|
1
|
-
|
2
|
-
require 'rubygems'
|
3
|
-
require 'bundler/setup'
|
4
|
-
require 'rspec/core/rake_task'
|
1
|
+
#!/usr/bin/env rake
|
5
2
|
|
6
|
-
|
7
|
-
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
10
|
+
|
11
|
+
#load 'rails/tasks/engine.rake'
|
8
12
|
|
9
|
-
|
10
|
-
|
11
|
-
|
13
|
+
Bundler::GemHelper.install_tasks
|
14
|
+
|
15
|
+
require 'rspec/core'
|
16
|
+
require 'rspec/core/rake_task'
|
17
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
18
|
+
RSpec::Core::RakeTask.new(:spec)
|
19
|
+
task :default => :spec
|
@@ -4,10 +4,4 @@ module InfoparkComponentCacheHelper
|
|
4
4
|
capture(&block)
|
5
5
|
end
|
6
6
|
end
|
7
|
-
|
8
|
-
def cache_guarded_component(obj, component, guards, params, &block)
|
9
|
-
InfoparkComponentCache::ComponentCache.new(obj, component, params, guards).fetch do
|
10
|
-
capture(&block)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
7
|
+
end
|
@@ -17,8 +17,11 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
|
20
|
-
gem.add_dependency 'rails'
|
20
|
+
gem.add_dependency 'rails', '> 3.0.0'
|
21
21
|
|
22
|
-
gem.add_dependency '
|
23
|
-
|
22
|
+
gem.add_dependency 'infopark_fiona_connector'
|
23
|
+
|
24
|
+
gem.add_development_dependency 'rspec-rails'
|
25
|
+
gem.add_development_dependency 'sqlite3'
|
26
|
+
gem.add_development_dependency 'byebug'
|
24
27
|
end
|
data/lib/engine.rb
CHANGED
@@ -1,5 +1,34 @@
|
|
1
|
+
require "infopark_fiona_connector"
|
2
|
+
require "active_support/core_ext/numeric/time"
|
3
|
+
|
4
|
+
#require "infopark_component_cache/guards/always_consistent"
|
5
|
+
#require "infopark_component_cache/guards/never_consistent"
|
6
|
+
require "infopark_component_cache/guards/value_present"
|
7
|
+
require "infopark_component_cache/guards/cms_state_guard"
|
8
|
+
|
9
|
+
require "infopark_component_cache/guards/last_changed"
|
10
|
+
require "infopark_component_cache/guards/obj_count"
|
11
|
+
require "infopark_component_cache/guards/valid_from"
|
12
|
+
require "infopark_component_cache/guards/valid_until"
|
13
|
+
|
14
|
+
require "infopark_component_cache/guards/delayed_last_changed"
|
15
|
+
require "infopark_component_cache/guards/delayed_obj_count"
|
16
|
+
require "infopark_component_cache/guards/delayed_valid_from"
|
17
|
+
require "infopark_component_cache/guards/delayed_valid_until"
|
18
|
+
|
19
|
+
require "infopark_component_cache/key_generator"
|
20
|
+
require "infopark_component_cache/consistency_guard"
|
21
|
+
require "infopark_component_cache/cache_storage"
|
22
|
+
require "infopark_component_cache/component"
|
23
|
+
require "infopark_component_cache/component_cache"
|
24
|
+
|
1
25
|
module InfoparkComponentCache
|
26
|
+
# @!scope class
|
27
|
+
# This parameter should be initialized to the root object
|
28
|
+
# class of the project. It defaults to "::Obj".
|
29
|
+
mattr_accessor :obj_root_class
|
2
30
|
|
31
|
+
# @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
|
3
32
|
class Engine < Rails::Engine
|
4
33
|
|
5
34
|
initializer "component_cache.helpers" do
|
@@ -9,6 +38,11 @@ module InfoparkComponentCache
|
|
9
38
|
ActionView::Base.__send__( :include, helper)
|
10
39
|
end
|
11
40
|
end
|
12
|
-
end
|
13
41
|
|
42
|
+
initializer "set default obj_root_class" do
|
43
|
+
InfoparkComponentCache.obj_root_class ||= ::Obj
|
44
|
+
CmsStateGuard.obj_root_class = InfoparkComponentCache.obj_root_class
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
14
48
|
end
|
@@ -1,19 +1,5 @@
|
|
1
1
|
require "infopark_component_cache/version"
|
2
2
|
|
3
|
-
#require "infopark_component_cache/guards/always_consistent"
|
4
|
-
#require "infopark_component_cache/guards/never_consistent"
|
5
|
-
require "infopark_component_cache/guards/value_present"
|
6
|
-
require "infopark_component_cache/guards/last_changed"
|
7
|
-
require "infopark_component_cache/guards/obj_count"
|
8
|
-
require "infopark_component_cache/guards/valid_from"
|
9
|
-
require "infopark_component_cache/guards/valid_until"
|
10
|
-
|
11
|
-
require "infopark_component_cache/key_generator"
|
12
|
-
require "infopark_component_cache/consistency_guard"
|
13
|
-
require "infopark_component_cache/cache_storage"
|
14
|
-
require "infopark_component_cache/component"
|
15
|
-
require "infopark_component_cache/component_cache"
|
16
|
-
|
17
3
|
module InfoparkComponentCache
|
18
4
|
|
19
5
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module InfoparkComponentCache
|
4
|
+
# @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
|
5
|
+
#
|
6
|
+
# This abstract base class represents a very thin wrapper
|
7
|
+
# around the underlying cache storage.
|
8
|
+
#
|
9
|
+
# @note Any valid implementation *must* respect
|
10
|
+
# Rails.application.config.action_controller.perform_caching
|
11
|
+
# setting.
|
12
|
+
class AbstractCacheStorage
|
13
|
+
include Singleton
|
14
|
+
|
15
|
+
def exist?(key)
|
16
|
+
enabled? && backing_storage.exist?(key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def read(key)
|
20
|
+
# it is possible to read disabled cache!
|
21
|
+
backing_storage.read(key)
|
22
|
+
end
|
23
|
+
|
24
|
+
def write(key, value, options={})
|
25
|
+
backing_storage.write(key, value, options) if enabled?
|
26
|
+
rescue Errno::ENOSPC => e
|
27
|
+
Rails.logger.error("Unable to write cache, cache full: #{e.message}")
|
28
|
+
end
|
29
|
+
|
30
|
+
# @private
|
31
|
+
def enabled?
|
32
|
+
Rails.application.config.action_controller.perform_caching
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
def backing_storage
|
37
|
+
raise TypeError, "Cannot use abstract cache storage. Please provide a concrete cache storage in #{self.class.name}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,30 +1,16 @@
|
|
1
|
-
require
|
1
|
+
require "infopark_component_cache/abstract_cache_storage"
|
2
2
|
|
3
3
|
module InfoparkComponentCache
|
4
4
|
# @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
class CacheStorage
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
enabled? && Rails.cache.exist?(key)
|
15
|
-
end
|
16
|
-
|
17
|
-
def read(key)
|
18
|
-
Rails.cache.read(key) # you can still read the cache if you wish...
|
19
|
-
end
|
20
|
-
|
21
|
-
def write(key, value)
|
22
|
-
Rails.cache.write(key, value) if enabled?
|
23
|
-
end
|
24
|
-
|
25
|
-
# @private
|
26
|
-
def enabled?
|
27
|
-
Rails.application.config.action_controller.perform_caching
|
6
|
+
# This class implements a persistent cache storage, that
|
7
|
+
# it a cache which will probably persists between requests.
|
8
|
+
# In the current version it relies on the preconfigured
|
9
|
+
# Rails cache (Rails.application.config.cache_store).
|
10
|
+
class CacheStorage < AbstractCacheStorage
|
11
|
+
protected
|
12
|
+
def backing_storage
|
13
|
+
Rails.cache
|
28
14
|
end
|
29
15
|
end
|
30
|
-
end
|
16
|
+
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'infopark_component_cache/key_generator'
|
2
|
-
|
3
1
|
module InfoparkComponentCache
|
4
2
|
# @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
|
5
3
|
#
|
@@ -25,4 +23,4 @@ module InfoparkComponentCache
|
|
25
23
|
@params.merge({:obj_name=>@obj.name, :obj_id=>@obj.id, :obj_component=>@component})
|
26
24
|
end
|
27
25
|
end
|
28
|
-
end
|
26
|
+
end
|
@@ -1,12 +1,3 @@
|
|
1
|
-
require 'infopark_component_cache/component'
|
2
|
-
require 'infopark_component_cache/cache_storage'
|
3
|
-
|
4
|
-
require 'infopark_component_cache/guards/value_present'
|
5
|
-
require 'infopark_component_cache/guards/last_changed'
|
6
|
-
require 'infopark_component_cache/guards/obj_count'
|
7
|
-
require 'infopark_component_cache/guards/valid_from'
|
8
|
-
require 'infopark_component_cache/guards/valid_until'
|
9
|
-
|
10
1
|
module InfoparkComponentCache
|
11
2
|
# @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
|
12
3
|
# This class provides user-level access to component cache.
|
@@ -27,7 +18,7 @@ module InfoparkComponentCache
|
|
27
18
|
# the component
|
28
19
|
# @see Component
|
29
20
|
#
|
30
|
-
# @param [Array<Class>] guards list of guard
|
21
|
+
# @param [Array<Class>, Array<Hash>] guards list of guard
|
31
22
|
# classes used when deciding whether cache is valid
|
32
23
|
# when left empty the default set is used:
|
33
24
|
# @see Guard::ValuePresent
|
@@ -44,8 +35,14 @@ module InfoparkComponentCache
|
|
44
35
|
Guards::ValidUntil.new(@component)
|
45
36
|
]
|
46
37
|
else
|
47
|
-
@guards = guards.map do |
|
48
|
-
|
38
|
+
@guards = 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
|
49
46
|
end
|
50
47
|
end
|
51
48
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'infopark_component_cache/cache_storage'
|
2
|
-
|
3
1
|
module InfoparkComponentCache
|
4
2
|
# @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
|
5
3
|
#
|
@@ -15,10 +13,11 @@ module InfoparkComponentCache
|
|
15
13
|
# This consistency is crucial for the function of cache, because
|
16
14
|
# inconsistent cache is (automatically) invalidated.
|
17
15
|
class ConsistencyGuard
|
18
|
-
attr_reader :component
|
16
|
+
attr_reader :component, :options
|
19
17
|
|
20
|
-
def initialize(component)
|
18
|
+
def initialize(component, options={})
|
21
19
|
@component = component
|
20
|
+
@options = options
|
22
21
|
end
|
23
22
|
|
24
23
|
# @return [CacheStorage] instance of CacheStorage
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "infopark_component_cache/volatile_cache"
|
2
|
+
require "infopark_component_cache/key_generator"
|
3
|
+
|
4
|
+
module InfoparkComponentCache
|
5
|
+
# @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
|
6
|
+
#
|
7
|
+
# This module provides an easy way to create delayed guards
|
8
|
+
# by using meta programming.
|
9
|
+
#
|
10
|
+
# @example Delaying an ObjectCount which guards on :object_count
|
11
|
+
# class DelayedObjectCount < ObjectCount
|
12
|
+
# include DelayedGuard
|
13
|
+
# delay :object_count, for: 10.minutes
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# @note Including classes must implement options method which
|
17
|
+
# completely described the object state and returns a hash.
|
18
|
+
module DelayedGuard
|
19
|
+
def self.included(base)
|
20
|
+
base.send(:extend, ClassMethods)
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
include VolatileCache
|
25
|
+
|
26
|
+
def delayed_value(method_name)
|
27
|
+
volatile_cache.read(delayed_value_key(method_name))
|
28
|
+
end
|
29
|
+
|
30
|
+
def still_delayed?(method_name)
|
31
|
+
volatile_cache.exist?(delayed_value_key(method_name))
|
32
|
+
end
|
33
|
+
|
34
|
+
def delay_value(method_name, value, expiration)
|
35
|
+
volatile_cache.write(delayed_value_key(method_name), value, expires_in: expiration)
|
36
|
+
value
|
37
|
+
end
|
38
|
+
|
39
|
+
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
|
+
}))
|
44
|
+
end
|
45
|
+
|
46
|
+
module ClassMethods
|
47
|
+
def delay(method_name, options)
|
48
|
+
expiration = options[:for]
|
49
|
+
return unless expiration
|
50
|
+
|
51
|
+
# allow to overwrite the delays
|
52
|
+
alias_method :"delayed_#{method_name}", method_name unless method_defined?(:"delayed_#{method_name}")
|
53
|
+
define_method method_name do
|
54
|
+
value = delayed_value(method_name)
|
55
|
+
if still_delayed?(method_name)
|
56
|
+
value
|
57
|
+
else
|
58
|
+
delay_value(method_name, self.send(:"delayed_#{method_name}"), expiration)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "infopark_component_cache/consistency_guard"
|
2
|
+
|
3
|
+
module InfoparkComponentCache
|
4
|
+
# @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
|
5
|
+
#
|
6
|
+
# @abstract
|
7
|
+
# This abstract class enables the implementing classes
|
8
|
+
# to access the cms and read the current state.
|
9
|
+
#
|
10
|
+
# It also provides the option to limit the object classes
|
11
|
+
# used for lookup.
|
12
|
+
class CmsStateGuard < ConsistencyGuard
|
13
|
+
class << self
|
14
|
+
# This parameter should be initialized to the root Obj
|
15
|
+
# class of the project
|
16
|
+
attr_accessor :obj_root_class
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
# This method implements scoping on the root Obj class
|
21
|
+
# and additional constraints for limiting object classes
|
22
|
+
# used for lookup
|
23
|
+
def scoped_relation
|
24
|
+
if self.options[:obj_classes].present?
|
25
|
+
conditions = {obj_class: self.options[:obj_classes]}
|
26
|
+
else
|
27
|
+
conditions = {}
|
28
|
+
end
|
29
|
+
CmsStateGuard.obj_root_class.scoped.where(conditions)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "infopark_component_cache/delayed_guard"
|
2
|
+
require "infopark_component_cache/guards/last_changed"
|
3
|
+
|
4
|
+
module InfoparkComponentCache
|
5
|
+
module Guards
|
6
|
+
# @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
|
7
|
+
#
|
8
|
+
# This class is a delayed version of LastChanged guard.
|
9
|
+
# The preconfigured delay is 10 seconds.
|
10
|
+
#
|
11
|
+
# @see DelayedGuard
|
12
|
+
# @see LastChanged
|
13
|
+
class DelayedLastChanged < LastChanged
|
14
|
+
include DelayedGuard
|
15
|
+
delay :current_last_changed, for: 10.seconds
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|