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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.rubocop.yml +25 -0
  4. data/.rubocop_todo.yml +115 -0
  5. data/.ruby-version +1 -1
  6. data/.travis.yml +24 -0
  7. data/Gemfile +2 -4
  8. data/Gemfile.lock +206 -0
  9. data/Gemfile.rails51 +6 -0
  10. data/Gemfile.rails51.lock +206 -0
  11. data/README.md +8 -0
  12. data/Rakefile +7 -7
  13. data/app/helpers/infopark_component_cache_helper.rb +2 -2
  14. data/infopark_component_cache.gemspec +15 -12
  15. data/lib/engine.rb +6 -7
  16. data/lib/infopark_component_cache.rb +1 -2
  17. data/lib/infopark_component_cache/abstract_cache_storage.rb +4 -3
  18. data/lib/infopark_component_cache/cache_storage.rb +1 -0
  19. data/lib/infopark_component_cache/component.rb +14 -6
  20. data/lib/infopark_component_cache/component_cache.rb +35 -31
  21. data/lib/infopark_component_cache/consistency_guard.rb +1 -1
  22. data/lib/infopark_component_cache/delayed_guard.rb +7 -7
  23. data/lib/infopark_component_cache/guards/cms_state_guard.rb +7 -6
  24. data/lib/infopark_component_cache/guards/last_changed.rb +5 -2
  25. data/lib/infopark_component_cache/guards/obj_count.rb +3 -3
  26. data/lib/infopark_component_cache/guards/valid_from.rb +7 -10
  27. data/lib/infopark_component_cache/guards/valid_until.rb +7 -9
  28. data/lib/infopark_component_cache/key_generator.rb +3 -3
  29. data/lib/infopark_component_cache/version.rb +1 -1
  30. data/lib/infopark_component_cache/volatile_cache.rb +1 -1
  31. data/lib/infopark_component_cache/volatile_cache_storage.rb +1 -0
  32. data/spec/dummy/Rakefile +1 -1
  33. data/spec/dummy/config.ru +1 -1
  34. data/spec/dummy/config/application.rb +1 -4
  35. data/spec/dummy/config/boot.rb +5 -5
  36. data/spec/dummy/config/environment.rb +1 -1
  37. data/spec/dummy/config/environments/development.rb +1 -35
  38. data/spec/dummy/config/environments/test.rb +2 -8
  39. data/spec/dummy/config/initializers/secret_token.rb +1 -1
  40. data/spec/dummy/config/initializers/session_store.rb +1 -1
  41. data/spec/dummy/db/schema.rb +1 -2
  42. data/spec/lib/infopark_component_cache/component_cache_spec.rb +118 -0
  43. data/spec/lib/{delayed_guard_spec.rb → infopark_component_cache/delayed_guard_spec.rb} +3 -3
  44. data/spec/lib/{guards → infopark_component_cache/guards}/always_consistent_spec.rb +7 -6
  45. data/spec/lib/{guards → infopark_component_cache/guards}/last_changed_spec.rb +20 -12
  46. data/spec/lib/{guards → infopark_component_cache/guards}/never_consistent_spec.rb +7 -6
  47. data/spec/lib/{guards → infopark_component_cache/guards}/obj_count_spec.rb +20 -12
  48. data/spec/lib/{guards → infopark_component_cache/guards}/valid_from_spec.rb +20 -12
  49. data/spec/lib/{guards → infopark_component_cache/guards}/valid_until_spec.rb +23 -14
  50. data/spec/spec_helper.rb +10 -7
  51. data/spec/support/cache_switching_macros.rb +4 -4
  52. metadata +81 -30
data/README.md CHANGED
@@ -16,6 +16,14 @@ Or install it yourself as:
16
16
 
17
17
  $ gem install infopark_component_cache
18
18
 
19
+ ## Tests
20
+
21
+ To run the test suite just execute:
22
+
23
+ $ bundle exec rspec spec/
24
+
25
+ No setup neccessary.
26
+
19
27
  ## Usage
20
28
 
21
29
  Set up Rails catching (see [http://guides.rubyonrails.org/caching_with_rails.html](http://guides.rubyonrails.org/caching_with_rails.html)) and
data/Rakefile CHANGED
@@ -1,19 +1,19 @@
1
1
  #!/usr/bin/env rake
2
2
 
3
3
  begin
4
- require 'bundler/setup'
4
+ require "bundler/setup"
5
5
  rescue LoadError
6
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
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("../spec/dummy/Rakefile", __FILE__)
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 'rspec/core'
16
- require 'rspec/core/rake_task'
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 :default => :spec
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,27 +1,30 @@
1
- # -*- encoding: utf-8 -*-
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 'infopark_component_cache/version'
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
- gem.authors = ["Tomasz Przedmojski"]
8
+ gem.authors = ["Tomasz Przedmojski, sveninfo"]
10
9
  gem.email = ["tomasz.przedmojski@infopark.de"]
11
- gem.description = %q{Easy and intelligent fragment caching for RailsConnector projects}
12
- gem.summary = %q{Fragment caching with automatic dependency resolution and cache invalidation.}
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 = ""
13
+ gem.license = "Nonstandard"
14
14
 
15
15
  gem.files = `git ls-files`.split($/)
16
- 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) }
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', '> 3.0.0'
20
+ gem.add_dependency "rails", "~> 5.0"
21
21
 
22
- gem.add_dependency 'infopark_fiona_connector'
22
+ gem.add_dependency "infopark_fiona_connector", "~> 7.0.1.5.2.3.rc5"
23
23
 
24
- gem.add_development_dependency 'rspec-rails'
25
- gem.add_development_dependency 'sqlite3'
26
- gem.add_development_dependency 'byebug'
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"
27
30
  end
@@ -1,8 +1,9 @@
1
- require "infopark_fiona_connector"
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__( :include, helper)
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,7 +1,6 @@
1
1
  require "infopark_component_cache/version"
2
2
 
3
3
  module InfoparkComponentCache
4
-
5
4
  end
6
5
 
7
- require File.expand_path('../engine', __FILE__) if defined?(Rails)
6
+ require File.expand_path("engine", __dir__) if defined?(Rails)
@@ -1,4 +1,4 @@
1
- require 'singleton'
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
@@ -9,6 +9,7 @@ module InfoparkComponentCache
9
9
  # Rails cache (Rails.application.config.cache_store).
10
10
  class CacheStorage < AbstractCacheStorage
11
11
  protected
12
+
12
13
  def backing_storage
13
14
  Rails.cache
14
15
  end
@@ -5,13 +5,19 @@ module InfoparkComponentCache
5
5
  # and some parameters (hash). It should be used to point
6
6
  # to some data stored in a particular context
7
7
  class Component
8
- attr_reader :obj, :name, :params
8
+ attr_reader :obj, :component, :params
9
9
 
10
- def initialize(obj, component, params={})
11
- @obj, @component, @params = obj, component, params
10
+ def initialize(obj, component, params = {})
11
+ @obj = obj
12
+ @component = component
13
+ @params = params
12
14
  end
13
15
 
14
- def cache_key(meta_prefix=nil)
16
+ def name
17
+ component
18
+ end
19
+
20
+ def cache_key(meta_prefix = nil)
15
21
  if meta_prefix
16
22
  meta_prefix + "_" + KeyGenerator.generate_key(identity_hash)
17
23
  else
@@ -20,7 +26,9 @@ module InfoparkComponentCache
20
26
  end
21
27
 
22
28
  def identity_hash
23
- @params.merge({:obj_name=>@obj.name, :obj_id=>@obj.id, :obj_component=>@component})
29
+ @params
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 })
24
32
  end
25
33
  end
26
- end
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
- @guards = [
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 = 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
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,11 +54,13 @@ module InfoparkComponentCache
54
54
  #
55
55
  # @return true if cache is valid and in consistent state
56
56
  def expired?
57
- return !guards.all?(&:consistent?)
57
+ return true unless cache.enabled?
58
+
59
+ !guards.all?(&:consistent?)
60
+ rescue StandardError => e
61
+ raise e if Rails.env.test?
58
62
 
59
- rescue => exception
60
- raise exception if Rails.env.test?
61
- return true
63
+ true
62
64
  end
63
65
 
64
66
  # Checks if the cache is in consistent state and cached value
@@ -69,17 +71,19 @@ module InfoparkComponentCache
69
71
  # @see {#expired?}
70
72
  # @yieldreturn value to be used in case of cache miss
71
73
  # @return cached value or the return value of the block
72
- def fetch(&block)
74
+ def fetch(&_block)
73
75
  if expired?
74
76
  value = yield
75
77
  begin
76
- cache.write(component.cache_key, value)
77
- ensure_consistency!
78
- return value
78
+ if cache.enabled?
79
+ cache.write(component.cache_key, value)
80
+ ensure_consistency!
81
+ end
82
+ value
83
+ rescue StandardError => e
84
+ raise e if Rails.env.test?
79
85
 
80
- rescue => exception
81
- raise exception if Rails.env.test?
82
- return value
86
+ value
83
87
  end
84
88
  else
85
89
  cache.read(component.cache_key)
@@ -15,7 +15,7 @@ module InfoparkComponentCache
15
15
  class ConsistencyGuard
16
16
  attr_reader :component, :options
17
17
 
18
- def initialize(component, options={})
18
+ def initialize(component, options = {})
19
19
  @component = component
20
20
  @options = options
21
21
  end
@@ -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(self.options.merge({
41
- delayed_method_name: method_name,
42
- delayed_class_name: self.class.name
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, self.send(:"delayed_#{method_name}"), expiration)
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,16 +17,17 @@ 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 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)
25
+ conditions = if options[:obj_classes].present?
26
+ { obj_class: options[:obj_classes] }
27
+ else
28
+ {}
29
+ end
30
+ CmsStateGuard.obj_root_class.where(conditions)
30
31
  end
31
32
  end
32
33
  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('last_changed')
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
- RailsConnector::DateAttribute.parse(scoped_relation.maximum(:last_changed))
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
@@ -18,7 +18,7 @@ module InfoparkComponentCache
18
18
 
19
19
  # @return true if obj count can be read from cache with {#cache_key}
20
20
  def count_known?
21
- cache.exist?(cache_key) && cache.read(cache_key).kind_of?(Fixnum)
21
+ cache.exist?(cache_key) && cache.read(cache_key).kind_of?(Integer)
22
22
  end
23
23
 
24
24
  # @return true if no obj has been deleted or added since last {#guard!}
@@ -28,10 +28,10 @@ module InfoparkComponentCache
28
28
 
29
29
  # @return [String] the cache key for storing {#current_count}
30
30
  def cache_key
31
- component.cache_key('obj_count')
31
+ component.cache_key("obj_count")
32
32
  end
33
33
 
34
- # @return [Fixnum] the number of Objs in the database
34
+ # @return [Integer] the number of Objs in the database
35
35
  def current_count
36
36
  scoped_relation.count
37
37
  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
- return no_changes_since?
11
+ no_changes_since?
13
12
  else
14
- return current_min_valid_from.nil?
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('min_valid_from')
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('valid_from > ?', Time.now.to_iso).minimum(:valid_from)
40
- if str_value.present?
41
- RailsConnector::DateAttribute.parse(str_value)
42
- else
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