kasket 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/kasket.rb CHANGED
@@ -5,7 +5,6 @@ require 'active_support'
5
5
  require 'kasket/active_record_patches'
6
6
 
7
7
  module Kasket
8
- autoload :Cache, 'kasket/cache'
9
8
  autoload :ConfigurationMixin, 'kasket/configuration_mixin'
10
9
  autoload :ReloadAssociationMixin, 'kasket/reload_association_mixin'
11
10
  autoload :RackMiddleware, 'kasket/rack_middleware'
@@ -15,17 +14,13 @@ module Kasket
15
14
 
16
15
  class Version
17
16
  MAJOR = 0
18
- MINOR = 6
19
- PATCH = 4
17
+ MINOR = 7
18
+ PATCH = 0
20
19
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
21
20
  end
22
21
 
23
22
  module_function
24
23
 
25
- def cache
26
- Thread.current["kasket_cache"] ||= Cache.new
27
- end
28
-
29
24
  def setup(options = {})
30
25
  CONFIGURATION[:max_collection_size] = options[:max_collection_size] if options[:max_collection_size]
31
26
 
@@ -33,34 +28,11 @@ module Kasket
33
28
  ActiveRecord::Associations::BelongsToAssociation.send(:include, Kasket::ReloadAssociationMixin)
34
29
  ActiveRecord::Associations::BelongsToPolymorphicAssociation.send(:include, Kasket::ReloadAssociationMixin)
35
30
  ActiveRecord::Associations::HasOneThroughAssociation.send(:include, Kasket::ReloadAssociationMixin)
31
+ end
36
32
 
37
- #sets up local cache clearing before each request.
38
- #this is done to make it work for non rack rails and for functional tests
39
- begin
40
- ApplicationController.before_filter do
41
- Kasket.cache.clear_local
42
- end
43
- rescue NameError => e
44
- puts('WARNING: The kasket before filter did not register (this is OK in the test environment)')
45
- end
46
-
47
- #sets up local cache clearing on rack
48
- begin
49
- ActionController::Dispatcher.middleware.use(Kasket::RackMiddleware)
50
- rescue NameError => e
51
- puts('WARNING: The kasket rack middleware is not in your rack stack (this is OK in the test environment)')
52
- end
53
-
54
- #sets up local cache clearing after each test case
55
- begin
56
- ActiveSupport::TestCase.class_eval do
57
- setup :clear_cache
58
- def clear_cache
59
- Kasket.cache.clear_local
60
- Rails.cache.clear if Rails.cache.respond_to?(:clear)
61
- end
62
- end
63
- rescue NameError => e
33
+ def clear_local
34
+ if Rails.cache.respond_to?(:with_local_cache)
35
+ Rails.cache.send(:local_cache).try(:clear)
64
36
  end
65
37
  end
66
38
  end
@@ -11,8 +11,8 @@ module Kasket
11
11
  sql = sanitize_sql(sql)
12
12
  query = kasket_parser.parse(sql) if use_kasket?
13
13
  if query && has_kasket_index_on?(query[:index])
14
- if value = Kasket.cache.read(query[:key])
15
- Array.wrap(value).collect! { |record| instantiate(record.clone) }
14
+ if value = Rails.cache.read(query[:key])
15
+ Array.wrap(value).collect! { |record| instantiate(record.dup) }
16
16
  else
17
17
  store_in_kasket(query[:key], find_by_sql_without_kasket(sql))
18
18
  end
@@ -25,14 +25,14 @@ module Kasket
25
25
 
26
26
  def store_in_kasket(key, records)
27
27
  if records.size == 1
28
- Kasket.cache.write(key, records.first.instance_variable_get(:@attributes))
29
- else
28
+ Rails.cache.write(key, records.first.instance_variable_get(:@attributes).dup)
29
+ elsif records.size <= Kasket::CONFIGURATION[:max_collection_size]
30
30
  keys = records.map do |record|
31
31
  key = kasket_key_for_id(record.id)
32
- Kasket.cache.write(key, record.instance_variable_get(:@attributes))
32
+ Rails.cache.write(key, record.instance_variable_get(:@attributes).dup)
33
33
  key
34
34
  end
35
- Kasket.cache.write(key, keys)
35
+ Rails.cache.write(key, keys)
36
36
  end
37
37
  records
38
38
  end
@@ -2,7 +2,7 @@ module Kasket
2
2
  module ReloadAssociationMixin
3
3
  def reload_with_kasket_clearing(*args)
4
4
  if loaded?
5
- clear_local_kasket_indices if respond_to?(:clear_local_kasket_indices)
5
+ Kasket.clear_local if include?(WriteMixin)
6
6
  else
7
7
  target_class = proxy_reflection.options[:polymorphic] ? association_class : proxy_reflection.klass
8
8
  Kasket.cache.delete_matched_local(/^#{target_class.kasket_key_prefix}/) if target_class.respond_to?(:kasket_key_prefix)
@@ -4,7 +4,7 @@ module Kasket
4
4
  module ClassMethods
5
5
  def remove_from_kasket(ids)
6
6
  Array(ids).each do |id|
7
- Kasket.cache.delete(kasket_key_for_id(id))
7
+ Rails.cache.delete(kasket_key_for_id(id))
8
8
  end
9
9
  end
10
10
 
@@ -21,7 +21,7 @@ module Kasket
21
21
 
22
22
  def store_in_kasket
23
23
  if !readonly? && kasket_key
24
- Kasket.cache.write(kasket_key, @attributes)
24
+ Rails.cache.write(kasket_key, @attributes.dup)
25
25
  end
26
26
  end
27
27
 
@@ -48,18 +48,12 @@ module Kasket
48
48
 
49
49
  def clear_kasket_indices
50
50
  kasket_keys.each do |key|
51
- Kasket.cache.delete(key)
52
- end
53
- end
54
-
55
- def clear_local_kasket_indices
56
- kasket_keys.each do |key|
57
- Kasket.cache.delete_local(key)
51
+ Rails.cache.delete(key)
58
52
  end
59
53
  end
60
54
 
61
55
  def reload_with_kasket_clearing(*args)
62
- clear_local_kasket_indices
56
+ Kasket.clear_local
63
57
  reload_without_kasket_clearing(*args)
64
58
  end
65
59
  end
@@ -17,11 +17,11 @@ class CacheExpiryTest < ActiveSupport::TestCase
17
17
  end
18
18
 
19
19
  should "clear all indices for instance when deleted" do
20
- Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "id=#{@post.id}")
21
- Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'")
22
- Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'/first")
23
- Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "blog_id=#{@post.blog_id}/id=#{@post.id}")
24
- Kasket.cache.expects(:delete).never
20
+ Rails.cache.expects(:delete).with(Post.kasket_key_prefix + "id=#{@post.id}")
21
+ Rails.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'")
22
+ Rails.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'/first")
23
+ Rails.cache.expects(:delete).with(Post.kasket_key_prefix + "blog_id=#{@post.blog_id}/id=#{@post.id}")
24
+ Rails.cache.expects(:delete).never
25
25
 
26
26
  @post.destroy
27
27
  end
@@ -33,13 +33,13 @@ class CacheExpiryTest < ActiveSupport::TestCase
33
33
  end
34
34
 
35
35
  should "clear all indices for instance when updated" do
36
- Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "id=#{@post.id}")
37
- Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'")
38
- Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'/first")
39
- Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='new title'")
40
- Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "title='new title'/first")
41
- Kasket.cache.expects(:delete).with(Post.kasket_key_prefix + "blog_id=#{@post.blog_id}/id=#{@post.id}")
42
- Kasket.cache.expects(:delete).never
36
+ Rails.cache.expects(:delete).with(Post.kasket_key_prefix + "id=#{@post.id}")
37
+ Rails.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'")
38
+ Rails.cache.expects(:delete).with(Post.kasket_key_prefix + "title='#{@post.title}'/first")
39
+ Rails.cache.expects(:delete).with(Post.kasket_key_prefix + "title='new title'")
40
+ Rails.cache.expects(:delete).with(Post.kasket_key_prefix + "title='new title'/first")
41
+ Rails.cache.expects(:delete).with(Post.kasket_key_prefix + "blog_id=#{@post.blog_id}/id=#{@post.id}")
42
+ Rails.cache.expects(:delete).never
43
43
 
44
44
  @post.title = "new title"
45
45
  @post.save
@@ -13,11 +13,11 @@ class FindOneTest < ActiveSupport::TestCase
13
13
  end
14
14
 
15
15
  should "only cache on indexed attributes" do
16
- Kasket.cache.expects(:read).twice
16
+ Rails.cache.expects(:read).twice
17
17
  Post.find_by_id(1)
18
18
  Post.find_by_id(1, :conditions => {:blog_id => 2})
19
19
 
20
- Kasket.cache.expects(:read).never
20
+ Rails.cache.expects(:read).never
21
21
  Post.first :conditions => {:blog_id => 2}
22
22
  end
23
23
 
@@ -31,10 +31,10 @@ class FindOneTest < ActiveSupport::TestCase
31
31
  Post.find(post.id)
32
32
  assert(Rails.cache.read(post.kasket_key))
33
33
 
34
- Kasket.cache.expects(:read)
34
+ Rails.cache.expects(:read)
35
35
  Post.find(post.id, :select => nil)
36
36
 
37
- Kasket.cache.expects(:read).never
37
+ Rails.cache.expects(:read).never
38
38
  Post.find(post.id, :select => 'title')
39
39
  end
40
40
 
data/test/helper.rb CHANGED
@@ -34,6 +34,11 @@ class ActiveSupport::TestCase
34
34
  self.use_transactional_fixtures = true
35
35
 
36
36
  self.use_instantiated_fixtures = false
37
+
38
+ setup :clear_cache
39
+ def clear_cache
40
+ Rails.cache.clear
41
+ end
37
42
  end
38
43
 
39
44
  ActiveSupport::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
@@ -10,24 +10,25 @@ class ReadMixinTest < ActiveSupport::TestCase
10
10
  end
11
11
 
12
12
  should "handle unsupported sql" do
13
+ Rails.cache.expects(:read).never
14
+ Rails.cache.expects(:write).never
13
15
  assert_equal @records, Post.find_by_sql_with_kasket('select unsupported sql statement')
14
- assert Kasket.cache.local.empty?
15
16
  end
16
17
 
17
18
  should "read results" do
18
- Kasket.cache.write("kasket-#{Kasket::Version::STRING}/posts/version=3558/id=1", @database_results.first)
19
- assert_equal [ @records.first ], Post.find_by_sql('SELECT * FROM `posts` WHERE (id = 1)'), Kasket.cache.inspect
19
+ Rails.cache.write("kasket-#{Kasket::Version::STRING}/posts/version=3558/id=1", @database_results.first)
20
+ assert_equal [ @records.first ], Post.find_by_sql('SELECT * FROM `posts` WHERE (id = 1)')
20
21
  end
21
22
 
22
23
  should "store results in kasket" do
23
24
  Post.find_by_sql('SELECT * FROM `posts` WHERE (id = 1)')
24
25
 
25
- assert_equal @database_results.first, Kasket.cache.read("kasket-#{Kasket::Version::STRING}/posts/version=3558/id=1"), Kasket.cache.inspect
26
+ assert_equal @database_results.first, Rails.cache.read("kasket-#{Kasket::Version::STRING}/posts/version=3558/id=1")
26
27
  end
27
28
 
28
29
  context "modifying results" do
29
30
  setup do
30
- Kasket.cache.write("kasket-#{Kasket::Version::STRING}/posts/version=3558/id=1", @database_results.first)
31
+ Rails.cache.write("kasket-#{Kasket::Version::STRING}/posts/version=3558/id=1", @database_results.first)
31
32
  @record = Post.find_by_sql('SELECT * FROM `posts` WHERE (id = 1)').first
32
33
  @record.instance_variable_get(:@attributes)['id'] = 3
33
34
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kasket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mick Staugaard
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-12-09 00:00:00 -08:00
13
+ date: 2010-01-04 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -70,16 +70,13 @@ files:
70
70
  - Rakefile
71
71
  - lib/kasket.rb
72
72
  - lib/kasket/active_record_patches.rb
73
- - lib/kasket/cache.rb
74
73
  - lib/kasket/configuration_mixin.rb
75
74
  - lib/kasket/dirty_mixin.rb
76
75
  - lib/kasket/query_parser.rb
77
- - lib/kasket/rack_middleware.rb
78
76
  - lib/kasket/read_mixin.rb
79
77
  - lib/kasket/reload_association_mixin.rb
80
78
  - lib/kasket/write_mixin.rb
81
79
  - test/cache_expiry_test.rb
82
- - test/cache_test.rb
83
80
  - test/database.yml
84
81
  - test/dirty_test.rb
85
82
  - test/find_one_test.rb
@@ -121,7 +118,6 @@ specification_version: 3
121
118
  summary: A write back caching layer on active record
122
119
  test_files:
123
120
  - test/cache_expiry_test.rb
124
- - test/cache_test.rb
125
121
  - test/dirty_test.rb
126
122
  - test/find_one_test.rb
127
123
  - test/find_some_test.rb
data/lib/kasket/cache.rb DELETED
@@ -1,77 +0,0 @@
1
- module Kasket
2
- class Cache
3
- def initialize
4
- clear_local
5
- end
6
-
7
- def read(*args)
8
- result = @local_cache[args[0]] || Rails.cache.read(*args)
9
- if result.is_a?(Array) && result.first.is_a?(String)
10
- models = get_multi(result)
11
- result = result.map { |key| models[key] }
12
- end
13
-
14
- @local_cache[args[0]] = result if result
15
- result
16
- end
17
-
18
- def get_multi(keys)
19
- map = Hash[*keys.zip(keys.map { |key| @local_cache[key] }).flatten]
20
- missing_keys = map.select { |key, value| value.nil? }.map(&:first)
21
-
22
- unless missing_keys.empty?
23
- if Rails.cache.respond_to?(:read_multi)
24
- missing_map = Rails.cache.read_multi(missing_keys)
25
- missing_map.each do |key, value|
26
- missing_map[key] = @local_cache[key] = value
27
- end
28
- map.merge!(missing_map)
29
- else
30
- missing_keys.each do |key|
31
- map[key] = read(key)
32
- end
33
- end
34
- end
35
-
36
- map
37
- end
38
-
39
- def write(key, value)
40
- if storable?(value)
41
- @local_cache[key] = value.duplicable? ? value.dup : value
42
- Rails.cache.write(key, value.duplicable? ? value.dup : value) # Fix due to Rails.cache freezing values in 2.3.4
43
- end
44
- value
45
- end
46
-
47
- def delete(*args)
48
- @local_cache.delete(args[0])
49
- Rails.cache.delete(*args)
50
- end
51
-
52
- def delete_local(*keys)
53
- keys.each do |key|
54
- @local_cache.delete(key)
55
- end
56
- end
57
-
58
- def delete_matched_local(matcher)
59
- @local_cache.delete_if { |k,v| k =~ matcher }
60
- end
61
-
62
- def clear_local
63
- @local_cache = {}
64
- end
65
-
66
- def local
67
- @local_cache
68
- end
69
-
70
- protected
71
-
72
- def storable?(value)
73
- !value.is_a?(Array) || value.size <= Kasket::CONFIGURATION[:max_collection_size]
74
- end
75
-
76
- end
77
- end
@@ -1,13 +0,0 @@
1
- module Kasket
2
- class RackMiddleware
3
- def initialize(app)
4
- @app = app
5
- end
6
-
7
- def call(env)
8
- @app.call(env)
9
- ensure
10
- Kasket.cache.clear_local
11
- end
12
- end
13
- end
data/test/cache_test.rb DELETED
@@ -1,102 +0,0 @@
1
- require File.dirname(__FILE__) + '/helper'
2
-
3
- class CacheTest < ActiveSupport::TestCase
4
-
5
- context "Cache" do
6
- setup do
7
- @cache = Kasket::Cache.new
8
- end
9
-
10
- context "reading" do
11
-
12
- should "work with non collection values" do
13
- @cache.write('key', 'value')
14
- assert_equal 'value', @cache.read('key')
15
- end
16
-
17
- should "fetch original results of stored collections" do
18
- @cache.write('key1', 'value1')
19
- @cache.write('key2', 'value2')
20
- @cache.write('key3', 'value3')
21
- @cache.write('collection_key', [ 'key1', 'key2', 'key3'])
22
-
23
- assert_equal [ 'value1', 'value2', 'value3'], @cache.read('collection_key')
24
- end
25
-
26
- should "not impact original object" do
27
- record = { 'id' => 1, 'color' => 'red' }
28
- @cache.write('key', record)
29
- record['id'] = 2
30
-
31
- assert_not_equal record, @cache.read('key')
32
- end
33
-
34
- end
35
-
36
- context "writing" do
37
- setup do
38
- @cache.write('key', 'value')
39
- end
40
-
41
- should "store the object locally" do
42
- assert_equal 'value', @cache.local['key']
43
- end
44
-
45
- should "persist the object" do
46
- @cache.clear_local
47
- assert_equal 'value', @cache.read('key')
48
- end
49
-
50
- should "respect max collection size" do
51
- original_max = Kasket::CONFIGURATION[:max_collection_size]
52
- Kasket::CONFIGURATION[:max_collection_size] = 2
53
-
54
- @cache.write('key', [ 'a', 'b'])
55
- assert_equal 2, @cache.read('key').size
56
-
57
- @cache.write('key2', ['a', 'b', 'c'])
58
- assert_equal nil, @cache.read('key2')
59
-
60
- Kasket::CONFIGURATION[:max_collection_size] = original_max
61
- end
62
-
63
- end
64
-
65
- should "delete" do
66
- @cache.write('key', 'value')
67
- @cache.delete('key')
68
-
69
- assert_equal nil, @cache.local['key']
70
- assert_equal nil, @cache.read('key')
71
- end
72
-
73
- should "delete matched local" do
74
- @cache.write('key1', 'value1')
75
- @cache.write('key2', 'value2')
76
- @cache.delete_matched_local(/2/)
77
-
78
- assert_equal nil, @cache.local['key2']
79
- assert_equal 'value1', @cache.local['key1']
80
- assert_equal 'value2', @cache.read('key2')
81
- end
82
-
83
- should "delete local" do
84
- @cache.write('key1', 'value1')
85
- @cache.write('key2', 'value2')
86
- @cache.delete_local('key1', 'key2')
87
-
88
- assert_equal nil, @cache.local['key1']
89
- assert_equal nil, @cache.local['key2']
90
- assert_equal 'value1', @cache.read('key1')
91
- assert_equal 'value2', @cache.read('key2')
92
- end
93
-
94
- should "clear local" do
95
- @cache.write('key1', 'value1')
96
- @cache.clear_local
97
-
98
- assert @cache.local.blank?
99
- end
100
-
101
- end
102
- end