infopark_component_cache 1.1.0 → 2.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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +1 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/README.md +8 -0
  6. data/Rakefile +17 -9
  7. data/app/helpers/infopark_component_cache_helper.rb +1 -7
  8. data/infopark_component_cache.gemspec +6 -3
  9. data/lib/engine.rb +35 -1
  10. data/lib/infopark_component_cache.rb +0 -14
  11. data/lib/infopark_component_cache/abstract_cache_storage.rb +40 -0
  12. data/lib/infopark_component_cache/cache_storage.rb +10 -24
  13. data/lib/infopark_component_cache/component.rb +1 -3
  14. data/lib/infopark_component_cache/component_cache.rb +9 -12
  15. data/lib/infopark_component_cache/consistency_guard.rb +3 -4
  16. data/lib/infopark_component_cache/delayed_guard.rb +65 -0
  17. data/lib/infopark_component_cache/guards/always_consistent.rb +1 -1
  18. data/lib/infopark_component_cache/guards/cms_state_guard.rb +32 -0
  19. data/lib/infopark_component_cache/guards/delayed_last_changed.rb +18 -0
  20. data/lib/infopark_component_cache/guards/delayed_obj_count.rb +18 -0
  21. data/lib/infopark_component_cache/guards/delayed_valid_from.rb +18 -0
  22. data/lib/infopark_component_cache/guards/delayed_valid_until.rb +18 -0
  23. data/lib/infopark_component_cache/guards/last_changed.rb +3 -3
  24. data/lib/infopark_component_cache/guards/never_consistent.rb +1 -1
  25. data/lib/infopark_component_cache/guards/obj_count.rb +3 -3
  26. data/lib/infopark_component_cache/guards/valid_from.rb +3 -3
  27. data/lib/infopark_component_cache/guards/valid_until.rb +3 -3
  28. data/lib/infopark_component_cache/guards/value_present.rb +1 -1
  29. data/lib/infopark_component_cache/version.rb +1 -1
  30. data/lib/infopark_component_cache/volatile_cache.rb +13 -0
  31. data/lib/infopark_component_cache/volatile_cache_storage.rb +18 -0
  32. data/spec/dummy/Rakefile +7 -0
  33. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  34. data/spec/dummy/app/models/obj.rb +2 -0
  35. data/spec/dummy/config.ru +4 -0
  36. data/spec/dummy/config/application.rb +19 -0
  37. data/spec/dummy/config/boot.rb +10 -0
  38. data/spec/dummy/config/database.yml +11 -0
  39. data/spec/dummy/config/environment.rb +5 -0
  40. data/spec/dummy/config/environments/development.rb +37 -0
  41. data/spec/dummy/config/environments/test.rb +10 -0
  42. data/spec/dummy/config/initializers/secret_token.rb +1 -0
  43. data/spec/dummy/config/initializers/session_store.rb +1 -0
  44. data/spec/dummy/config/initializers/wrap_parameters.rb +8 -0
  45. data/spec/dummy/config/routes.rb +58 -0
  46. data/spec/dummy/db/development.sqlite3 +0 -0
  47. data/spec/dummy/db/schema.rb +3 -0
  48. data/spec/dummy/log/.gitkeep +0 -0
  49. data/spec/lib/delayed_guard_spec.rb +72 -0
  50. data/spec/lib/guards/always_consistent_spec.rb +21 -0
  51. data/spec/lib/guards/last_changed_spec.rb +66 -0
  52. data/spec/lib/guards/never_consistent_spec.rb +21 -0
  53. data/spec/lib/guards/obj_count_spec.rb +64 -0
  54. data/spec/lib/guards/valid_from_spec.rb +66 -0
  55. data/spec/lib/guards/valid_until_spec.rb +73 -0
  56. data/spec/spec_helper.rb +25 -0
  57. data/spec/support/cache_switching_macros.rb +29 -0
  58. 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
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in infopark_component_cache.gemspec
4
4
  gemspec
5
+
6
+ gem 'rails', '3.2.21'
7
+ gem 'infopark_fiona_connector', '6.9.4'
8
+ gem 'infopark_rails_connector', '6.9.4'
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
- require "bundler/gem_tasks"
2
- require 'rubygems'
3
- require 'bundler/setup'
4
- require 'rspec/core/rake_task'
1
+ #!/usr/bin/env rake
5
2
 
6
- desc "Run all specs in spec directory"
7
- RSpec::Core::RakeTask.new(:spec)
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
- # Remove release task
10
- task :release do ; end
11
- task(:release).clear_prerequisites.clear_actions
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 'infopark_rails_connector'
23
- gem.add_development_dependency 'rspec'
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 'singleton'
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
- # Trivial wrapper around underlying cache storages.
7
- # This class or any other class that inherits it *must*
8
- # respect Rails.application.config.action_controller.perform_caching
9
- # setting.
10
- class CacheStorage
11
- include Singleton
12
-
13
- def exist?(key)
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 |klass|
48
- klass.new(@component)
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
@@ -1,4 +1,4 @@
1
- require 'infopark_component_cache/consistency_guard'
1
+ require "infopark_component_cache/consistency_guard"
2
2
 
3
3
  module InfoparkComponentCache
4
4
  module Guards
@@ -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