garner 0.4.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +35 -0
  5. data/.travis.yml +13 -0
  6. data/CHANGELOG.md +130 -0
  7. data/CONTRIBUTING.md +118 -0
  8. data/Gemfile +3 -0
  9. data/README.md +1 -0
  10. data/Rakefile +39 -0
  11. data/UPGRADING.md +118 -0
  12. data/garner.gemspec +44 -0
  13. data/lib/garner.rb +21 -21
  14. data/lib/garner/cache.rb +13 -6
  15. data/lib/garner/cache/binding.rb +6 -14
  16. data/lib/garner/cache/context.rb +11 -12
  17. data/lib/garner/cache/identity.rb +1 -1
  18. data/lib/garner/config.rb +12 -7
  19. data/lib/garner/mixins/active_record.rb +3 -3
  20. data/lib/garner/mixins/active_record/base.rb +2 -2
  21. data/lib/garner/mixins/mongoid.rb +4 -4
  22. data/lib/garner/mixins/mongoid/document.rb +8 -12
  23. data/lib/garner/mixins/mongoid/identity.rb +5 -6
  24. data/lib/garner/mixins/rack.rb +1 -2
  25. data/lib/garner/strategies/binding/invalidation/base.rb +2 -4
  26. data/lib/garner/strategies/binding/invalidation/binding_index.rb +1 -3
  27. data/lib/garner/strategies/binding/invalidation/touch.rb +0 -2
  28. data/lib/garner/strategies/binding/key/base.rb +1 -3
  29. data/lib/garner/strategies/binding/key/binding_index.rb +3 -4
  30. data/lib/garner/strategies/binding/key/cache_key.rb +0 -2
  31. data/lib/garner/strategies/binding/key/safe_cache_key.rb +2 -3
  32. data/lib/garner/strategies/context/key/base.rb +1 -3
  33. data/lib/garner/strategies/context/key/caller.rb +9 -12
  34. data/lib/garner/strategies/context/key/jsonp.rb +3 -6
  35. data/lib/garner/strategies/context/key/request_get.rb +2 -4
  36. data/lib/garner/strategies/context/key/request_path.rb +1 -3
  37. data/lib/garner/strategies/context/key/request_post.rb +2 -4
  38. data/lib/garner/version.rb +1 -1
  39. data/spec/garner/cache/context_spec.rb +38 -0
  40. data/spec/garner/cache/identity_spec.rb +68 -0
  41. data/spec/garner/cache_spec.rb +49 -0
  42. data/spec/garner/config_spec.rb +17 -0
  43. data/spec/garner/mixins/mongoid/document_spec.rb +80 -0
  44. data/spec/garner/mixins/mongoid/identity_spec.rb +140 -0
  45. data/spec/garner/mixins/rack_spec.rb +48 -0
  46. data/spec/garner/strategies/binding/invalidation/binding_index_spec.rb +14 -0
  47. data/spec/garner/strategies/binding/invalidation/touch_spec.rb +23 -0
  48. data/spec/garner/strategies/binding/key/binding_index_spec.rb +245 -0
  49. data/spec/garner/strategies/binding/key/cache_key_spec.rb +29 -0
  50. data/spec/garner/strategies/binding/key/safe_cache_key_spec.rb +61 -0
  51. data/spec/garner/strategies/context/key/caller_spec.rb +106 -0
  52. data/spec/garner/strategies/context/key/jsonp_spec.rb +22 -0
  53. data/spec/garner/strategies/context/key/request_get_spec.rb +33 -0
  54. data/spec/garner/strategies/context/key/request_path_spec.rb +28 -0
  55. data/spec/garner/strategies/context/key/request_post_spec.rb +34 -0
  56. data/spec/garner/version_spec.rb +11 -0
  57. data/spec/integration/active_record_spec.rb +43 -0
  58. data/spec/integration/grape_spec.rb +33 -0
  59. data/spec/integration/mongoid_spec.rb +355 -0
  60. data/spec/integration/rack_spec.rb +77 -0
  61. data/spec/integration/sinatra_spec.rb +29 -0
  62. data/spec/performance/strategy_benchmark.rb +59 -0
  63. data/spec/performance/support/benchmark_context.rb +31 -0
  64. data/spec/performance/support/benchmark_context_wrapper.rb +67 -0
  65. data/spec/shared/binding_invalidation_strategy.rb +17 -0
  66. data/spec/shared/binding_key_strategy.rb +35 -0
  67. data/spec/shared/conditional_get.rb +48 -0
  68. data/spec/shared/context_key_strategy.rb +24 -0
  69. data/spec/spec_helper.rb +24 -0
  70. data/spec/spec_support.rb +5 -0
  71. data/spec/support/active_record.rb +36 -0
  72. data/spec/support/cache.rb +15 -0
  73. data/spec/support/garner.rb +5 -0
  74. data/spec/support/mongoid.rb +71 -0
  75. metadata +155 -157
@@ -0,0 +1,44 @@
1
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
2
+ require 'garner/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'garner'
6
+ s.version = Garner::VERSION
7
+ s.authors = ['Daniel Doubrovkine', 'Frank Macreery']
8
+ s.summary = 'Garner is a cache layer for Ruby and Rack applications, supporting model and instance binding and hierarchical invalidation.'
9
+ s.email = ['dblock@dblock.org', 'frank.macreery@gmail.com']
10
+ s.homepage = 'https://github.com/artsy/garner'
11
+ s.license = 'MIT'
12
+
13
+ s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
14
+ s.test_files = s.files.grep(/^(spec)\//)
15
+ s.extra_rdoc_files = Dir['*.md']
16
+ s.require_paths = ['lib']
17
+
18
+ s.post_install_message = File.read('UPGRADING') if File.exist?('UPGRADING')
19
+
20
+ s.add_runtime_dependency 'rack'
21
+ s.add_runtime_dependency 'json'
22
+ s.add_runtime_dependency 'multi_json', '>= 1.3.0'
23
+ s.add_runtime_dependency 'activesupport'
24
+
25
+ s.add_development_dependency 'rake'
26
+ s.add_development_dependency 'rspec', '~> 2.10'
27
+ s.add_development_dependency 'bundler'
28
+ s.add_development_dependency 'grape', '~> 0.8.0'
29
+ s.add_development_dependency 'sinatra'
30
+ s.add_development_dependency 'rack-test'
31
+ s.add_development_dependency 'mongoid', '>= 3.0.0'
32
+ s.add_development_dependency 'mongoid_slug'
33
+ s.add_development_dependency 'activerecord'
34
+ if RUBY_PLATFORM =~ /java/
35
+ s.add_development_dependency 'jdbc-sqlite3'
36
+ s.add_development_dependency 'activerecord-jdbcsqlite3-adapter'
37
+ else
38
+ s.add_development_dependency 'sqlite3'
39
+ end
40
+ s.add_development_dependency 'coveralls'
41
+ s.add_development_dependency 'yard'
42
+ s.add_development_dependency 'dalli'
43
+ s.add_development_dependency 'rubocop', '0.24.1'
44
+ end
@@ -1,31 +1,31 @@
1
- require "multi_json"
2
- require "active_support"
1
+ require 'multi_json'
2
+ require 'active_support'
3
3
 
4
4
  # Garner core
5
- require "garner/version"
6
- require "garner/config"
5
+ require 'garner/version'
6
+ require 'garner/config'
7
7
 
8
8
  # Key strategies
9
- require "garner/strategies/context/key/base"
10
- require "garner/strategies/context/key/caller"
11
- require "garner/strategies/context/key/request_path"
12
- require "garner/strategies/context/key/request_get"
13
- require "garner/strategies/context/key/request_post"
14
- require "garner/strategies/context/key/jsonp"
9
+ require 'garner/strategies/context/key/base'
10
+ require 'garner/strategies/context/key/caller'
11
+ require 'garner/strategies/context/key/request_path'
12
+ require 'garner/strategies/context/key/request_get'
13
+ require 'garner/strategies/context/key/request_post'
14
+ require 'garner/strategies/context/key/jsonp'
15
15
 
16
16
  # Binding strategies
17
- require "garner/strategies/binding/key/base"
18
- require "garner/strategies/binding/key/cache_key"
19
- require "garner/strategies/binding/key/safe_cache_key"
20
- require "garner/strategies/binding/key/binding_index"
17
+ require 'garner/strategies/binding/key/base'
18
+ require 'garner/strategies/binding/key/cache_key'
19
+ require 'garner/strategies/binding/key/safe_cache_key'
20
+ require 'garner/strategies/binding/key/binding_index'
21
21
 
22
22
  # Invalidation strategies
23
- require "garner/strategies/binding/invalidation/base"
24
- require "garner/strategies/binding/invalidation/touch"
25
- require "garner/strategies/binding/invalidation/binding_index"
23
+ require 'garner/strategies/binding/invalidation/base'
24
+ require 'garner/strategies/binding/invalidation/touch'
25
+ require 'garner/strategies/binding/invalidation/binding_index'
26
26
 
27
27
  # Cache
28
- require "garner/cache"
29
- require "garner/cache/identity"
30
- require "garner/cache/context"
31
- require "garner/cache/binding"
28
+ require 'garner/cache'
29
+ require 'garner/cache/identity'
30
+ require 'garner/cache/context'
31
+ require 'garner/cache/binding'
@@ -1,5 +1,6 @@
1
1
  module Garner
2
2
  module Cache
3
+ class NilBinding < StandardError; end
3
4
 
4
5
  # Fetch a result from cache.
5
6
  #
@@ -7,7 +8,7 @@ module Garner
7
8
  # bound. These objects' keys are injected into the compound cache key.
8
9
  # @param key_hash [Hash] Hash to comprise the compound cache key.
9
10
  # @param options_hash [Hash] Options to be passed to Garner.config.cache.
10
- def self.fetch(bindings, key_hash, options_hash, &block)
11
+ def self.fetch(bindings, key_hash, options_hash, &_block)
11
12
  if (compound_key = compound_key(bindings, key_hash))
12
13
  result = Garner.config.cache.fetch(compound_key, options_hash) do
13
14
  yield
@@ -19,15 +20,13 @@ module Garner
19
20
  result
20
21
  end
21
22
 
22
- private
23
23
  def self.compound_key(bindings, key_hash)
24
- binding_keys = bindings.map(&:garner_cache_key).compact
25
-
24
+ binding_keys = bindings.map { |binding| key_for(binding) }.compact
26
25
  if binding_keys.size == bindings.size
27
26
  # All bindings have non-nil cache keys, proceed.
28
27
  {
29
- :binding_keys => binding_keys,
30
- :context_keys => key_hash
28
+ binding_keys: binding_keys,
29
+ context_keys: key_hash
31
30
  }
32
31
  else
33
32
  # A nil cache key was generated. Skip caching.
@@ -37,5 +36,13 @@ module Garner
37
36
  end
38
37
  end
39
38
 
39
+ def self.key_for(binding)
40
+ if binding.nil?
41
+ return nil unless Garner.config.whiny_nils?
42
+ fail NilBinding
43
+ else
44
+ binding.garner_cache_key
45
+ end
46
+ end
40
47
  end
41
48
  end
@@ -1,21 +1,13 @@
1
1
  # Set up Garner configuration parameters
2
- Garner.config.option(:binding_key_strategy, {
3
- :default => Garner::Strategies::Binding::Key::SafeCacheKey
4
- })
5
- Garner.config.option(:binding_invalidation_strategy, {
6
- :default => Garner::Strategies::Binding::Invalidation::Touch
7
- })
8
- Garner.config.option(:mongoid_identity_fields, {
9
- :default => [:_id]
10
- })
11
- Garner.config.option(:invalidate_mongoid_root, {
12
- :default => true
13
- })
2
+
3
+ Garner.config.option(:binding_key_strategy, default: Garner::Strategies::Binding::Key::SafeCacheKey)
4
+ Garner.config.option(:binding_invalidation_strategy, default: Garner::Strategies::Binding::Invalidation::Touch)
5
+ Garner.config.option(:mongoid_identity_fields, default: [:_id])
6
+ Garner.config.option(:invalidate_mongoid_root, default: true)
14
7
 
15
8
  module Garner
16
9
  module Cache
17
10
  module Binding
18
-
19
11
  # Override this method to use a custom key strategy.
20
12
  #
21
13
  # @return [Object] The strategy to be used for instances of this class.
@@ -46,6 +38,7 @@ module Garner
46
38
  end
47
39
 
48
40
  protected
41
+
49
42
  def _invalidate
50
43
  invalidation_strategy.apply(self)
51
44
  end
@@ -61,7 +54,6 @@ module Garner
61
54
  def _garner_after_destroy
62
55
  _invalidate if invalidation_strategy.apply_on_callback?(:destroy)
63
56
  end
64
-
65
57
  end
66
58
  end
67
59
  end
@@ -1,20 +1,19 @@
1
1
  # Set up Garner configuration parameters
2
- Garner.config.option(:context_key_strategies, {
3
- :default => [Garner::Strategies::Context::Key::Caller]
4
- })
5
- Garner.config.option(:rack_context_key_strategies, {
6
- :default => [
7
- Garner::Strategies::Context::Key::Caller,
8
- Garner::Strategies::Context::Key::RequestGet,
9
- Garner::Strategies::Context::Key::RequestPost,
10
- Garner::Strategies::Context::Key::RequestPath
11
- ]
12
- })
2
+ Garner.config.option(:context_key_strategies,
3
+ default: [Garner::Strategies::Context::Key::Caller]
4
+ )
5
+ Garner.config.option(:rack_context_key_strategies,
6
+ default: [
7
+ Garner::Strategies::Context::Key::Caller,
8
+ Garner::Strategies::Context::Key::RequestGet,
9
+ Garner::Strategies::Context::Key::RequestPost,
10
+ Garner::Strategies::Context::Key::RequestPath
11
+ ]
12
+ )
13
13
 
14
14
  module Garner
15
15
  module Cache
16
16
  module Context
17
-
18
17
  # Instantiate a context-appropriate cache identity.
19
18
  #
20
19
  # @example
@@ -12,7 +12,7 @@ module Garner
12
12
 
13
13
  # Set up options hash with defaults
14
14
  @options_hash = Garner.config.global_cache_options || {}
15
- @options_hash.merge!({ :expires_in => Garner.config.expires_in })
15
+ @options_hash.merge!(expires_in: Garner.config.expires_in)
16
16
  end
17
17
 
18
18
  def fetch(&block)
@@ -1,5 +1,4 @@
1
1
  module Garner
2
-
3
2
  class << self
4
3
  # Set the configuration options. Best used by passing a block.
5
4
  #
@@ -12,7 +11,7 @@ module Garner
12
11
  def configure
13
12
  block_given? ? yield(Garner::Config) : Garner::Config
14
13
  end
15
- alias :config :configure
14
+ alias_method :config, :configure
16
15
  end
17
16
 
18
17
  module Config
@@ -77,7 +76,7 @@ module Garner
77
76
  #
78
77
  # @return [Cache] The configured cache or a default cache instance.
79
78
  def cache
80
- settings[:cache] = default_cache unless settings.has_key?(:cache)
79
+ settings[:cache] = default_cache unless settings.key?(:cache)
81
80
  settings[:cache]
82
81
  end
83
82
 
@@ -103,7 +102,7 @@ module Garner
103
102
  #
104
103
  # @return [String] The configured caller_root or a default.
105
104
  def caller_root
106
- settings[:caller_root] = default_caller_root unless settings.has_key?(:caller_root)
105
+ settings[:caller_root] = default_caller_root unless settings.key?(:caller_root)
107
106
  settings[:caller_root]
108
107
  end
109
108
 
@@ -123,10 +122,16 @@ module Garner
123
122
  end
124
123
 
125
124
  # Default cache options
126
- option(:global_cache_options, :default => {})
125
+ option(:global_cache_options, default: {})
127
126
 
128
127
  # Default cache expiration time.
129
- option(:expires_in, :default => nil)
128
+ option(:expires_in, default: nil)
129
+
130
+ # Default behavior on nil bindings
131
+ option(:whiny_nils, default: true)
132
+
133
+ def whiny_nils?
134
+ whiny_nils
135
+ end
130
136
  end
131
137
  end
132
-
@@ -1,4 +1,4 @@
1
- require "garner"
2
- require "active_record"
1
+ require 'garner'
2
+ require 'active_record'
3
3
 
4
- require "garner/mixins/active_record/base"
4
+ require 'garner/mixins/active_record/base'
@@ -1,5 +1,5 @@
1
- require "garner"
2
- require "active_record"
1
+ require 'garner'
2
+ require 'active_record'
3
3
 
4
4
  module Garner
5
5
  module Mixins
@@ -1,5 +1,5 @@
1
- require "garner"
2
- require "mongoid"
1
+ require 'garner'
2
+ require 'mongoid'
3
3
 
4
- require "garner/mixins/mongoid/document"
5
- require "garner/mixins/mongoid/identity"
4
+ require 'garner/mixins/mongoid/document'
5
+ require 'garner/mixins/mongoid/identity'
@@ -58,30 +58,26 @@ module Garner
58
58
  binding = identify(arg)
59
59
  identity = identity.bind(binding)
60
60
  end
61
- identity.key({ :garnered_find_args => args }) do
61
+ identity.key(garnered_find_args: args) do
62
62
  find(*args)
63
63
  end
64
64
  end
65
65
 
66
- after_create :_garner_after_create
67
- after_update :_garner_after_update
68
- after_destroy :_garner_after_destroy
66
+ after_create :_garner_after_create
67
+ after_update :_garner_after_update
68
+ after_destroy :_garner_after_destroy
69
69
 
70
70
  protected
71
+
71
72
  def self._latest_by_updated_at
72
73
  # Only find the latest if we can order by :updated_at
73
- return nil unless fields["updated_at"]
74
- only(:_id, :_type, :updated_at).order_by({
75
- :updated_at => :desc
76
- }).first
74
+ return nil unless fields['updated_at']
75
+ only(:_id, :_type, :updated_at).order_by(updated_at: :desc).first
77
76
  end
78
77
 
79
78
  def _invalidate
80
79
  invalidation_strategy.apply(self)
81
-
82
- if _root != self && Garner.config.invalidate_mongoid_root
83
- invalidation_strategy.apply(_root)
84
- end
80
+ invalidation_strategy.apply(_root) if _root != self && Garner.config.invalidate_mongoid_root
85
81
  end
86
82
 
87
83
  end
@@ -15,7 +15,7 @@ module Garner
15
15
  def self.from_class_and_handle(klass, handle)
16
16
  validate_class!(klass)
17
17
 
18
- self.new.tap do |identity|
18
+ new.tap do |identity|
19
19
  identity.klass = klass
20
20
  identity.handle = handle
21
21
  identity.conditions = conditions_for(klass, handle)
@@ -41,21 +41,20 @@ module Garner
41
41
  "#{self.class.name}/klass=#{klass},handle=#{handle}"
42
42
  end
43
43
 
44
- private
45
44
  def self.validate_class!(klass)
46
45
  if !klass.include?(::Mongoid::Document)
47
- raise "Must instantiate from a Mongoid class"
46
+ fail 'Must instantiate from a Mongoid class'
48
47
  elsif klass.embedded?
49
- raise "Cannot instantiate from an embedded document class"
48
+ fail 'Cannot instantiate from an embedded document class'
50
49
  end
51
50
  end
52
51
 
53
52
  def self.conditions_for(klass, handle)
54
53
  # Multiple-ID conditions
55
54
  conditions = {
56
- "$or" => Garner.config.mongoid_identity_fields.map { |field|
55
+ '$or' => Garner.config.mongoid_identity_fields.map do |field|
57
56
  { field => handle }
58
- }
57
+ end
59
58
  }
60
59
 
61
60
  # _type conditions
@@ -1,9 +1,8 @@
1
- require "garner"
1
+ require 'garner'
2
2
 
3
3
  module Garner
4
4
  module Mixins
5
5
  module Rack
6
-
7
6
  # Override this method to conditionally disable the cache.
8
7
  #
9
8
  # @return [Boolean]
@@ -3,11 +3,10 @@ module Garner
3
3
  module Binding
4
4
  module Invalidation
5
5
  class Base
6
-
7
6
  # Specifies whether invalidation should happen on callbacks.
8
7
  #
9
8
  # @param kind [Symbol] One of :create, :update, :destroy
10
- def self.apply_on_callback?(kind = nil)
9
+ def self.apply_on_callback?(_kind = nil)
11
10
  true
12
11
  end
13
12
 
@@ -16,10 +15,9 @@ module Garner
16
15
  #
17
16
  # @param binding [Object] The binding whose caches are to be
18
17
  # invalidated.
19
- def self.apply(binding)
18
+ def self.apply(_binding)
20
19
  end
21
20
  end
22
-
23
21
  end
24
22
  end
25
23
  end
@@ -3,11 +3,10 @@ module Garner
3
3
  module Binding
4
4
  module Invalidation
5
5
  class BindingIndex < Base
6
-
7
6
  # Specifies whether invalidation should happen on callbacks.
8
7
  #
9
8
  # @param kind [Symbol] One of :create, :update, :destroy
10
- def self.apply_on_callback?(kind = nil)
9
+ def self.apply_on_callback?(_kind = nil)
11
10
  true
12
11
  end
13
12
 
@@ -29,7 +28,6 @@ module Garner
29
28
  end
30
29
  end
31
30
  end
32
-
33
31
  end
34
32
  end
35
33
  end
@@ -3,7 +3,6 @@ module Garner
3
3
  module Binding
4
4
  module Invalidation
5
5
  class Touch < Base
6
-
7
6
  # Specifies whether invalidation should happen on callbacks.
8
7
  #
9
8
  # @param kind [Symbol] One of :create, :update, :destroy
@@ -35,7 +34,6 @@ module Garner
35
34
  end
36
35
  end
37
36
  end
38
-
39
37
  end
40
38
  end
41
39
  end