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
@@ -0,0 +1,18 @@
1
+ require "infopark_component_cache/delayed_guard"
2
+ require "infopark_component_cache/guards/obj_count"
3
+
4
+ module InfoparkComponentCache
5
+ module Guards
6
+ # @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
7
+ #
8
+ # This class is a delayed version of ObjCount guard.
9
+ # The preconfigured delay is 10 seconds.
10
+ #
11
+ # @see DelayedGuard
12
+ # @see ObjCount
13
+ class DelayedObjCount < ObjCount
14
+ include DelayedGuard
15
+ delay :current_count, for: 10.seconds
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require "infopark_component_cache/delayed_guard"
2
+ require "infopark_component_cache/guards/valid_from"
3
+
4
+ module InfoparkComponentCache
5
+ module Guards
6
+ # @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
7
+ #
8
+ # This class is a delayed version of ValidFrom guard.
9
+ # The preconfigured delay is 10 seconds.
10
+ #
11
+ # @see DelayedGuard
12
+ # @see ValidFrom
13
+ class DelayedValidFrom < ValidFrom
14
+ include DelayedGuard
15
+ delay :current_min_valid_from, for: 10.seconds
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require "infopark_component_cache/delayed_guard"
2
+ require "infopark_component_cache/guards/valid_until"
3
+
4
+ module InfoparkComponentCache
5
+ module Guards
6
+ # @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
7
+ #
8
+ # This class is a delayed version of ValidUntil guard.
9
+ # The preconfigured delay is 10 seconds.
10
+ #
11
+ # @see DelayedGuard
12
+ # @see ValidUntil
13
+ class DelayedValidUntil < ValidUntil
14
+ include DelayedGuard
15
+ delay :current_min_valid_until, for: 10.seconds
16
+ end
17
+ end
18
+ end
@@ -1,4 +1,4 @@
1
- require 'infopark_component_cache/consistency_guard'
1
+ require "infopark_component_cache/guards/cms_state_guard"
2
2
 
3
3
  module InfoparkComponentCache
4
4
  module Guards
@@ -6,7 +6,7 @@ module InfoparkComponentCache
6
6
  #
7
7
  # This Guard class ensures that the objects in database do not change inbetween.
8
8
  # (It caches the newest timestamp and compares it to the current value)
9
- class LastChanged < ConsistencyGuard
9
+ class LastChanged < CmsStateGuard
10
10
  def consistent?
11
11
  last_changed_known? && no_changes_since?
12
12
  end
@@ -32,7 +32,7 @@ module InfoparkComponentCache
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(RailsConnector::Obj.maximum(:last_changed))
35
+ RailsConnector::DateAttribute.parse(scoped_relation.maximum(:last_changed))
36
36
  end
37
37
  end
38
38
  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
@@ -1,4 +1,4 @@
1
- require 'infopark_component_cache/consistency_guard'
1
+ require "infopark_component_cache/guards/cms_state_guard"
2
2
 
3
3
  module InfoparkComponentCache
4
4
  module Guards
@@ -7,7 +7,7 @@ module InfoparkComponentCache
7
7
  # This Guard class ensures that the total count of Objs in the database
8
8
  # does not change inbetween. (It caches the number of Objs and compares
9
9
  # it to the current count)
10
- class ObjCount < ConsistencyGuard
10
+ class ObjCount < CmsStateGuard
11
11
  def consistent?
12
12
  count_known? && no_changes_since?
13
13
  end
@@ -33,7 +33,7 @@ module InfoparkComponentCache
33
33
 
34
34
  # @return [Fixnum] the number of Objs in the database
35
35
  def current_count
36
- RailsConnector::Obj.count
36
+ scoped_relation.count
37
37
  end
38
38
  end
39
39
  end
@@ -1,4 +1,4 @@
1
- require 'infopark_component_cache/consistency_guard'
1
+ require "infopark_component_cache/guards/cms_state_guard"
2
2
 
3
3
  module InfoparkComponentCache
4
4
  module Guards
@@ -6,7 +6,7 @@ module InfoparkComponentCache
6
6
  #
7
7
  # This guard ensures that any object that becomes valid (through valid_from)
8
8
  # will cause inconsistency
9
- class ValidFrom < ConsistencyGuard
9
+ class ValidFrom < CmsStateGuard
10
10
  def consistent?
11
11
  if min_valid_from_known?
12
12
  return no_changes_since?
@@ -36,7 +36,7 @@ module InfoparkComponentCache
36
36
 
37
37
  # @return [Time] the timestamp of the most recent valid_from, or nil if none found
38
38
  def current_min_valid_from
39
- str_value = RailsConnector::Obj.where('valid_from > ?', Time.now.to_iso).minimum(:valid_from)
39
+ str_value = scoped_relation.where('valid_from > ?', Time.now.to_iso).minimum(:valid_from)
40
40
  if str_value.present?
41
41
  RailsConnector::DateAttribute.parse(str_value)
42
42
  else
@@ -1,4 +1,4 @@
1
- require 'infopark_component_cache/consistency_guard'
1
+ require "infopark_component_cache/guards/cms_state_guard"
2
2
 
3
3
  module InfoparkComponentCache
4
4
  module Guards
@@ -6,7 +6,7 @@ module InfoparkComponentCache
6
6
  #
7
7
  # This guard ensures that any object, whose valid until date has been passed
8
8
  # will cause inconsistency.
9
- class ValidUntil < ConsistencyGuard
9
+ class ValidUntil < CmsStateGuard
10
10
  def consistent?
11
11
  if min_valid_until_known?
12
12
  return no_changes_since?
@@ -36,7 +36,7 @@ module InfoparkComponentCache
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 = RailsConnector::Obj.where('valid_until > ?', Time.now.to_iso).minimum(:valid_until)
39
+ str_value = scoped_relation.where('valid_until > ?', Time.now.to_iso).minimum(:valid_until)
40
40
  if str_value.present?
41
41
  RailsConnector::DateAttribute.parse(str_value)
42
42
  else
@@ -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
@@ -1,3 +1,3 @@
1
1
  module InfoparkComponentCache
2
- VERSION = "1.1.0"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -0,0 +1,13 @@
1
+ require "infopark_component_cache/volatile_cache_storage"
2
+
3
+ module InfoparkComponentCache
4
+ # @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
5
+ #
6
+ # This module provides quick an convieniet access to
7
+ # VolatileCacheStorage in any class that includes it.
8
+ module VolatileCache
9
+ def volatile_cache
10
+ @__volatile_cache ||= VolatileCacheStorage.instance
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ require "infopark_component_cache/abstract_cache_storage"
2
+
3
+ module InfoparkComponentCache
4
+ # @author Tomasz Przedmojski <tomasz.przedmojski@infopark.de>
5
+ #
6
+ # This class has the exact same interface as CacheStorage
7
+ # but it does not offer any guarantees regarding persistence
8
+ # of the cache.
9
+ # It should be not regarded any more safe than a NullCache.
10
+ # The primasy use case here is to provide caching where
11
+ # it is "nice to have" but also has to be extremely quick.
12
+ class VolatileCacheStorage < AbstractCacheStorage
13
+ protected
14
+ def backing_storage
15
+ @@backing_storage ||= ActiveSupport::Cache::MemoryStore.new({ size: 10.megabytes })
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
3
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
+
5
+ require File.expand_path('../config/application', __FILE__)
6
+
7
+ Dummy::Application.load_tasks
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,2 @@
1
+ class Obj
2
+ end
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run Dummy::Application
@@ -0,0 +1,19 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ # Pick the frameworks you want:
4
+ require "active_record/railtie"
5
+ require "action_controller/railtie"
6
+ require "active_resource/railtie"
7
+
8
+ Bundler.require(*Rails.groups)
9
+ require "infopark_component_cache"
10
+
11
+ module Dummy
12
+ class Application < Rails::Application
13
+ config.encoding = "utf-8"
14
+ config.filter_parameters += [:password]
15
+ config.active_support.escape_html_entities_in_json = true
16
+ config.active_record.whitelist_attributes = true
17
+ end
18
+ end
19
+
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ gemfile = File.expand_path('../../../../Gemfile', __FILE__)
3
+
4
+ if File.exist?(gemfile)
5
+ ENV['BUNDLE_GEMFILE'] = gemfile
6
+ require 'bundler'
7
+ Bundler.setup
8
+ end
9
+
10
+ $:.unshift File.expand_path('../../../../lib', __FILE__)
@@ -0,0 +1,11 @@
1
+ development: &dummy
2
+ adapter: sqlite3
3
+ database: db/development.sqlite3
4
+ pool: 5
5
+ timeout: 5000
6
+
7
+ test:
8
+ <<: *dummy
9
+
10
+ cms:
11
+ <<: *dummy
@@ -0,0 +1,5 @@
1
+ # Load the rails application
2
+ require File.expand_path('../application', __FILE__)
3
+
4
+ # Initialize the rails application
5
+ Dummy::Application.initialize!
@@ -0,0 +1,37 @@
1
+ Dummy::Application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb
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
37
+ end
@@ -0,0 +1,10 @@
1
+ Dummy::Application.configure do
2
+ config.cache_classes = true
3
+ config.whiny_nils = true
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
10
+ end
@@ -0,0 +1 @@
1
+ Dummy::Application.config.secret_token = '4806ad3606eea6388c0428912c8c8b37266f29c4c45fa5ecd233316cd5b6a0016aea879cfa603059a7c00296daef192955e26ae3298830bd904c8ff6a791feb1'
@@ -0,0 +1 @@
1
+ Dummy::Application.config.session_store :cookie_store, key: '_dummy_session'
@@ -0,0 +1,8 @@
1
+ ActiveSupport.on_load(:action_controller) do
2
+ wrap_parameters format: [:json]
3
+ end
4
+
5
+ # Disable root element in JSON by default.
6
+ ActiveSupport.on_load(:active_record) do
7
+ self.include_root_in_json = false
8
+ end
@@ -0,0 +1,58 @@
1
+ Dummy::Application.routes.draw do
2
+ # The priority is based upon order of creation:
3
+ # first created -> highest priority.
4
+
5
+ # Sample of regular route:
6
+ # match 'products/:id' => 'catalog#view'
7
+ # Keep in mind you can assign values other than :controller and :action
8
+
9
+ # Sample of named route:
10
+ # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
11
+ # This route can be invoked with purchase_url(:id => product.id)
12
+
13
+ # Sample resource route (maps HTTP verbs to controller actions automatically):
14
+ # resources :products
15
+
16
+ # Sample resource route with options:
17
+ # resources :products do
18
+ # member do
19
+ # get 'short'
20
+ # post 'toggle'
21
+ # end
22
+ #
23
+ # collection do
24
+ # get 'sold'
25
+ # end
26
+ # end
27
+
28
+ # Sample resource route with sub-resources:
29
+ # resources :products do
30
+ # resources :comments, :sales
31
+ # resource :seller
32
+ # end
33
+
34
+ # Sample resource route with more complex sub-resources
35
+ # resources :products do
36
+ # resources :comments
37
+ # resources :sales do
38
+ # get 'recent', :on => :collection
39
+ # end
40
+ # end
41
+
42
+ # Sample resource route within a namespace:
43
+ # namespace :admin do
44
+ # # Directs /admin/products/* to Admin::ProductsController
45
+ # # (app/controllers/admin/products_controller.rb)
46
+ # resources :products
47
+ # end
48
+
49
+ # You can have the root of your site routed with "root"
50
+ # just remember to delete public/index.html.
51
+ # root :to => 'welcome#index'
52
+
53
+ # See how all your routes lay out with "rake routes"
54
+
55
+ # This is a legacy wild controller route that's not recommended for RESTful applications.
56
+ # Note: This route will make all actions in every controller accessible via GET requests.
57
+ # match ':controller(/:action(/:id))(.:format)'
58
+ end
Binary file
@@ -0,0 +1,3 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+
3
+ end
File without changes
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'infopark_component_cache/delayed_guard'
3
+
4
+ describe InfoparkComponentCache::DelayedGuard do
5
+ let(:base_class_with_options) do
6
+ Class.new do
7
+ def options
8
+ {}
9
+ end
10
+ end
11
+ end
12
+
13
+ let(:undelayed_class) do
14
+ Class.new(base_class_with_options) do
15
+ def simple_counter
16
+ @simple_counter ||= 0
17
+ @simple_counter += 1
18
+ end
19
+ end
20
+ end
21
+
22
+ let(:delayed_class) do
23
+ Class.new(undelayed_class) do
24
+ include InfoparkComponentCache::DelayedGuard
25
+ delay :simple_counter, for: 1.second
26
+ end
27
+ end
28
+
29
+ let(:undelayed_subject) { undelayed_class.new }
30
+ let(:delayed_subject) { delayed_class.new }
31
+
32
+ context "with caching disabled" do
33
+ disable_cache
34
+
35
+ specify "the calls are not delayed" do
36
+ 10.times do
37
+ expect(undelayed_subject.simple_counter).to eq(delayed_subject.simple_counter)
38
+ end
39
+ end
40
+ end
41
+
42
+ context "with caching enabled" do
43
+ enable_cache
44
+ before { InfoparkComponentCache::VolatileCacheStorage.instance.send(:backing_storage).send(:clear) }
45
+
46
+ specify "first call returns the same value" do
47
+ expect(undelayed_subject.simple_counter).to eq(delayed_subject.simple_counter)
48
+ end
49
+
50
+ specify "following call does return the same value" do
51
+ first_value = delayed_subject.simple_counter
52
+ expect(first_value).to eq(undelayed_subject.simple_counter)
53
+ 10.times do
54
+ expect(delayed_subject.simple_counter).to eq(first_value)
55
+ expect(undelayed_subject.simple_counter).not_to eq(first_value)
56
+ end
57
+ end
58
+
59
+ context "after the delay has passed" do
60
+ specify "the calls returns new value" do
61
+ first_value = delayed_subject.simple_counter
62
+ expect(first_value).to eq(undelayed_subject.simple_counter)
63
+
64
+ sleep 1
65
+
66
+ second_value = delayed_subject.simple_counter
67
+ expect(second_value).not_to eq(first_value)
68
+ expect(second_value).to eq(undelayed_subject.simple_counter)
69
+ end
70
+ end
71
+ end
72
+ end