cache_back 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.1
1
+ 0.5.0
@@ -5,7 +5,16 @@ module CacheBack
5
5
  end
6
6
 
7
7
  def read(*args)
8
- @local_cache[args[0]] ||= Rails.cache.read(*args)
8
+ result = @local_cache[args[0]] || Rails.cache.read(*args)
9
+ if result.is_a?(CachedModel)
10
+ result = result.instanciate_model
11
+ elsif result.is_a?(Array)
12
+ models = get_multi(result)
13
+ result = result.map { |key| models[key]}
14
+ end
15
+
16
+ @local_cache[args[0]] = result if result
17
+ result
9
18
  end
10
19
 
11
20
  def get_multi(keys)
@@ -16,7 +25,8 @@ module CacheBack
16
25
  if Rails.cache.respond_to?(:read_multi)
17
26
  missing_map = Rails.cache.read_multi(missing_keys)
18
27
  missing_map.each do |key, value|
19
- @local_cache[key] = value
28
+ value = value.instanciate_model if value.is_a?(CachedModel)
29
+ missing_map[key] = @local_cache[key] = value
20
30
  end
21
31
  map.merge!(missing_map)
22
32
  else
@@ -31,6 +41,11 @@ module CacheBack
31
41
 
32
42
  def write(*args)
33
43
  @local_cache[args[0]] = args[1]
44
+
45
+ if args[1].is_a?(ActiveRecord::Base)
46
+ args[1] = CachedModel.new(args[1])
47
+ end
48
+
34
49
  Rails.cache.write(*args)
35
50
  end
36
51
 
@@ -42,5 +57,16 @@ module CacheBack
42
57
  def reset!
43
58
  @local_cache = {}
44
59
  end
60
+
61
+ class CachedModel
62
+ def initialize(model)
63
+ @name = model.class.name
64
+ @attributes = model.instance_variable_get(:@attributes)
65
+ end
66
+
67
+ def instanciate_model
68
+ @name.constantize.send(:instantiate, @attributes)
69
+ end
70
+ end
45
71
  end
46
72
  end
@@ -0,0 +1,72 @@
1
+ module CacheBack
2
+ class ConditionsParser
3
+ def initialize(model_class)
4
+ @model_class = model_class
5
+ end
6
+
7
+ def attribute_value_pairs(options, scope)
8
+ from_scope = attribute_value_pairs_for_conditions((scope || {})[:conditions])
9
+ return nil unless from_scope
10
+
11
+ from_options = attribute_value_pairs_for_conditions(options[:conditions])
12
+ return nil unless from_options
13
+
14
+ pairs = from_scope.inject(from_options) do |memo, pair|
15
+ attribute = pair[0]
16
+ if memo_pair = memo.find{ |p| p[0] == attribute}
17
+ memo_pair[0] = Array(memo_pair[0])
18
+ memo_pair[0] << pair[1]
19
+ else
20
+ memo << pair
21
+ end
22
+ end
23
+
24
+ pairs.sort! { |pair1, pair2| pair1[0] <=> pair2[0] }
25
+
26
+ pairs.map do |attribute, value|
27
+ if value.is_a?(Array)
28
+ value.flatten!
29
+ if value.size == 1
30
+ [attribute.to_sym, value[0]]
31
+ else
32
+ [attribute.to_sym, value]
33
+ end
34
+ else
35
+ [attribute.to_sym, value]
36
+ end
37
+ end
38
+ end
39
+
40
+ def attribute_value_pairs_for_conditions(conditions)
41
+ case conditions
42
+ when Hash
43
+ conditions.to_a.collect { |key, value| [key.to_s, value] }
44
+ when String
45
+ parse_indices_from_condition(conditions)
46
+ when Array
47
+ parse_indices_from_condition(*conditions)
48
+ when NilClass
49
+ []
50
+ end
51
+ end
52
+
53
+ AND = /\s+AND\s+/i
54
+ TABLE_AND_COLUMN = /(?:(?:`|")?(\w+)(?:`|")?\.)?(?:`|")?(\w+)(?:`|")?/ # Matches: `users`.id, `users`.`id`, users.id, id
55
+ VALUE = /'?(\d+|\?|(?:(?:[^']|'')*))'?/ # Matches: 123, ?, '123', '12''3'
56
+ KEY_EQ_VALUE = /^\(?#{TABLE_AND_COLUMN}\s+=\s+#{VALUE}\)?$/ # Matches: KEY = VALUE, (KEY = VALUE)
57
+ ORDER = /^#{TABLE_AND_COLUMN}\s*(ASC|DESC)?$/i # Matches: COLUMN ASC, COLUMN DESC, COLUMN
58
+
59
+ def parse_indices_from_condition(conditions = '', *values)
60
+ values = values.dup
61
+ conditions.split(AND).inject([]) do |indices, condition|
62
+ matched, table_name, column_name, sql_value = *(KEY_EQ_VALUE.match(condition))
63
+ if matched
64
+ value = sql_value == '?' ? values.shift : @model_class.columns_hash[column_name].type_cast(sql_value)
65
+ indices << [column_name, value]
66
+ else
67
+ return nil
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,4 +1,4 @@
1
- require 'activesupport'
1
+ require 'active_support'
2
2
 
3
3
  module CacheBack
4
4
  autoload :ReadMixin, 'cache_back/read_mixin'
@@ -26,18 +26,54 @@ module CacheBack
26
26
  end
27
27
  end
28
28
 
29
- def cache_back_key_for(id)
30
- "cache_back/#{table_name}/version_#{inherited_cache_back_version}/#{id}"
29
+ def cache_back_key_for(attribute_value_pairs)
30
+ key = "cache_back/#{table_name}/version=#{inherited_cache_back_version}"
31
+ attribute_value_pairs.each do |attribute, value|
32
+ key << "/#{attribute}="
33
+ if value.is_a?(Array)
34
+ key << value.join(',')
35
+ else
36
+ key << value.to_s
37
+ end
38
+ end
39
+ key
40
+ end
41
+
42
+ def cache_back_key_for_id(id)
43
+ cache_back_key_for([['id', id]])
44
+ end
45
+
46
+ def cache_back_indices
47
+ result = @cache_back_indices || []
48
+ result += superclass.cache_back_indices unless self == ActiveRecord::Base
49
+ result.uniq
50
+ end
51
+
52
+ def has_cache_back_index_on?(sorted_attributes)
53
+ cache_back_indices.include?(sorted_attributes)
31
54
  end
32
55
 
33
56
  def has_cache_back(options = {})
34
- @cache_back_version = options.delete(:version) || '1'
35
- @cache_back_option = options
57
+ has_cache_back_on :id
58
+ end
59
+
60
+ def has_cache_back_on(*args)
61
+ options = args.extract_options!
62
+ attributes = args.sort! { |x, y| x.to_s <=> y.to_s }
63
+
64
+ @cache_back_version ||= options.delete(:version) || '1'
65
+ @cache_back_option ||= options
66
+
67
+ if attributes != [:id] && !cache_back_indices.include?([:id])
68
+ has_cache_back_on(:id)
69
+ end
70
+
71
+ @cache_back_indices ||= []
72
+ @cache_back_indices << attributes unless @cache_back_indices.include?(attributes)
36
73
 
37
74
  include WriteMixin unless instance_methods.include?('store_in_cache_back')
38
- extend ReadMixin unless methods.include?('find_one_with_cache_back')
75
+ extend ReadMixin unless methods.include?('without_cache_back')
39
76
  extend DirtyMixin unless methods.include?('cache_back_dirty_methods')
40
77
  end
41
-
42
78
  end
43
79
  end
@@ -6,7 +6,7 @@ module CacheBack
6
6
  alias_method("without_cache_back_update_#{method}", method)
7
7
  define_method(method) do |*args|
8
8
  result = send("without_cache_back_update_#{method}", *args)
9
- store_in_cache_back
9
+ clear_cache_back_indices
10
10
  result
11
11
  end
12
12
  end
@@ -1,29 +1,60 @@
1
+ require 'cache_back/conditions_parser'
2
+
1
3
  module CacheBack
2
4
  module ReadMixin
3
5
 
4
6
  def self.extended(model_class)
5
7
  class << model_class
6
- alias_method_chain :find_one, :cache_back
7
- alias_method_chain :find_some, :cache_back
8
+ alias_method_chain :find_some, :cache_back unless methods.include?('find_some_without_cache_back')
9
+ alias_method_chain :find_every, :cache_back unless methods.include?('find_every_without_cache_back')
8
10
  end
9
11
  end
10
12
 
11
- def find_one_with_cache_back(id, options)
12
- if cache_safe?(options)
13
- unless record = CacheBack.cache.read(cache_back_key_for(id))
14
- record = find_one_without_cache_back(id, options)
15
- record.store_in_cache_back if record
13
+ def without_cache_back(&block)
14
+ old_value = @use_cache_back || true
15
+ @use_cache_back = false
16
+ yield
17
+ ensure
18
+ @use_cache_back = old_value
19
+ end
20
+
21
+ def find_every_with_cache_back(options)
22
+ attribute_value_pairs = cache_back_conditions_parser.attribute_value_pairs(options, scope(:find)) if cache_safe?(options)
23
+
24
+ limit = (options[:limit] || (scope(:find) || {})[:limit])
25
+
26
+ if (limit.nil? || limit == 1) && attribute_value_pairs && has_cache_back_index_on?(attribute_value_pairs.map(&:first))
27
+ collection_key = cache_back_key_for(attribute_value_pairs)
28
+ collection_key << '/first' if limit == 1
29
+ unless records = CacheBack.cache.read(collection_key)
30
+ records = without_cache_back do
31
+ find_every_without_cache_back(options)
32
+ end
33
+
34
+ if records.size == 1
35
+ CacheBack.cache.write(collection_key, records[0])
36
+ elsif records.size <= CacheBack::CONFIGURATION[:max_collection_size]
37
+ records.each { |record| record.store_in_cache_back if record }
38
+ CacheBack.cache.write(collection_key, records.map(&:cache_back_key))
39
+ end
16
40
  end
17
41
 
18
- record
42
+ Array(records)
19
43
  else
20
- find_one_without_cache_back(id, options)
44
+ without_cache_back do
45
+ find_every_without_cache_back(options)
46
+ end
21
47
  end
22
48
  end
23
49
 
24
50
  def find_some_with_cache_back(ids, options)
25
- if cache_safe?(options)
26
- id_to_key_map = Hash[ids.uniq.map { |id| [id, cache_back_key_for(id)] }]
51
+ attribute_value_pairs = cache_back_conditions_parser.attribute_value_pairs(options, scope(:find)) if cache_safe?(options)
52
+ attribute_value_pairs << [:id, ids] if attribute_value_pairs
53
+
54
+ limit = (options[:limit] || (scope(:find) || {})[:limit])
55
+
56
+ if limit.nil? && attribute_value_pairs && has_cache_back_index_on?(attribute_value_pairs.map(&:first))
57
+ id_to_key_map = Hash[ids.uniq.map { |id| [id, cache_back_key_for_id(id)] }]
27
58
  cached_record_map = CacheBack.cache.get_multi(id_to_key_map.values)
28
59
 
29
60
  missing_keys = Hash[cached_record_map.select { |key, record| record.nil? }].keys
@@ -32,19 +63,30 @@ module CacheBack
32
63
 
33
64
  missing_ids = Hash[id_to_key_map.invert.select { |key, id| missing_keys.include?(key) }].values
34
65
 
35
- db_records = find_some_without_cache_back(missing_ids, options)
66
+ db_records = without_cache_back do
67
+ find_some_without_cache_back(missing_ids, options)
68
+ end
36
69
  db_records.each { |record| record.store_in_cache_back if record }
37
70
 
38
71
  (cached_record_map.values + db_records).compact.uniq.sort { |x, y| x.id <=> y.id}
39
72
  else
40
- find_some_without_cache_back(ids, options)
73
+ without_cache_back do
74
+ find_some_without_cache_back(ids, options)
75
+ end
41
76
  end
42
77
  end
43
78
 
44
79
  private
45
80
 
46
81
  def cache_safe?(options)
47
- options[:select].nil?
82
+ @use_cache_back != false && [options, scope(:find) || {}].all? do |hash|
83
+ result = hash[:select].nil? && hash[:joins].nil? && hash[:order].nil? && hash[:offset].nil?
84
+ result && (options[:limit].nil? || options[:limit] == 1)
85
+ end
86
+ end
87
+
88
+ def cache_back_conditions_parser
89
+ @cache_back_conditions_parser ||= CacheBack::ConditionsParser.new(self)
48
90
  end
49
91
 
50
92
  end
@@ -0,0 +1,15 @@
1
+ module CacheBack
2
+ module ReloadAssociationMixin
3
+ def reload_with_cache_back_clearing(*args)
4
+ # TODO we could calculate the right key to clear by parsing the association conditions.
5
+ # this would clear less keys, and we would not have to load the target
6
+ load_target
7
+ target.clear_cache_back_indices if target.respond_to?(:clear_cache_back_indices)
8
+ reload_without_cache_back_clearing(*args)
9
+ end
10
+
11
+ def self.included(base)
12
+ base.alias_method_chain :reload, :cache_back_clearing
13
+ end
14
+ end
15
+ end
@@ -3,7 +3,7 @@ module CacheBack
3
3
  module ClassMethods
4
4
  def remove_from_cache_back(ids)
5
5
  Array(ids).each do |id|
6
- CacheBack.cache.delete(cache_back_key_for(id))
6
+ CacheBack.cache.delete(cache_back_key_for_id(id))
7
7
  end
8
8
  end
9
9
 
@@ -14,29 +14,35 @@ module CacheBack
14
14
  end
15
15
 
16
16
  module InstanceMethods
17
- def shallow_clone
18
- clone = self.class.new
19
- clone.instance_variable_set("@attributes", instance_variable_get(:@attributes))
20
- clone.instance_variable_set("@new_record", new_record?)
21
- clone
22
- end
23
-
24
17
  def cache_back_key
25
- @cache_back_key ||= new_record? ? nil : self.class.cache_back_key_for(id)
18
+ @cache_back_key ||= new_record? ? nil : self.class.cache_back_key_for_id(id)
26
19
  end
27
20
 
28
21
  def store_in_cache_back
29
22
  if !readonly? && cache_back_key
30
- CacheBack.cache.write(cache_back_key, shallow_clone, self.class.inherited_cache_back_options)
23
+ CacheBack.cache.write(cache_back_key, self, self.class.inherited_cache_back_options)
31
24
  end
32
25
  end
33
26
 
34
- def remove_from_cache_back
35
- CacheBack.cache.delete(cache_back_key) if cache_back_key
27
+ def clear_cache_back_indices
28
+ new_attributes = attributes.symbolize_keys
29
+
30
+ old_attributes = Hash[changes.map {|attribute, values| [attribute, values[0]]}].symbolize_keys
31
+ old_attributes.reverse_merge!(new_attributes)
32
+
33
+ self.class.cache_back_indices.each do |index|
34
+ old_key = self.class.cache_back_key_for(index.map { |attribute| [attribute, old_attributes[attribute]]})
35
+ new_key = self.class.cache_back_key_for(index.map { |attribute| [attribute, new_attributes[attribute]]})
36
+
37
+ [old_key, new_key].uniq.each do |key|
38
+ CacheBack.cache.delete(key)
39
+ CacheBack.cache.delete("#{key}/first")
40
+ end
41
+ end
36
42
  end
37
43
 
38
44
  def reload_with_cache_back_clearing(*args)
39
- remove_from_cache_back
45
+ clear_cache_back_indices
40
46
  reload_without_cache_back_clearing(*args)
41
47
  end
42
48
  end
@@ -45,9 +51,9 @@ module CacheBack
45
51
  model_class.extend ClassMethods
46
52
  model_class.send :include, InstanceMethods
47
53
 
48
- #model_class.after_save :store_in_cache_back
49
- model_class.after_update :remove_from_cache_back
50
- model_class.after_destroy :remove_from_cache_back
54
+ model_class.after_save :clear_cache_back_indices
55
+ model_class.after_destroy :clear_cache_back_indices
56
+
51
57
  model_class.alias_method_chain :reload, :cache_back_clearing
52
58
 
53
59
  class << model_class
data/lib/cache_back.rb CHANGED
@@ -1,23 +1,48 @@
1
1
  require 'rubygems'
2
- require 'activerecord'
2
+ require 'active_record'
3
+ require 'active_support'
3
4
 
4
5
  require 'cache_back/configuration_mixin'
6
+ require 'cache_back/reload_association_mixin'
5
7
  require 'cache_back/cache'
6
8
  require 'cache_back/rack_middleware'
7
9
 
8
10
  module CacheBack
11
+ CONFIGURATION = {:max_collection_size => 100}
12
+
9
13
  module_function
10
14
 
11
15
  def cache
12
16
  Thread.current["cache_back_cache"] ||= Cache.new
13
17
  end
14
- end
15
18
 
16
- ActiveRecord::Base.extend(CacheBack::ConfigurationMixin)
19
+ def setup(options = {})
20
+ CONFIGURATION[:max_collection_size] = options[:max_collection_size] if options[:max_collection_size]
17
21
 
18
- begin
19
- ActionController::Dispatcher.middleware.use(CacheBack::RackMiddleware)
20
- rescue NameError => e
21
-
22
- end
22
+ ActiveRecord::Base.extend(CacheBack::ConfigurationMixin)
23
+ ActiveRecord::Associations::BelongsToAssociation.send(:include, CacheBack::ReloadAssociationMixin)
24
+ ActiveRecord::Associations::BelongsToPolymorphicAssociation.send(:include, CacheBack::ReloadAssociationMixin)
25
+ ActiveRecord::Associations::HasOneThroughAssociation.send(:include, CacheBack::ReloadAssociationMixin)
26
+
27
+ #sets up local cache clearing after each request
28
+ begin
29
+ ApplicationController.after_filter do
30
+ CacheBack.cache.reset!
31
+ end
32
+ rescue NameError => e
23
33
 
34
+ end
35
+
36
+ #sets up local cache clearing after each test case
37
+ begin
38
+ ActiveSupport::TestCase.class_eval do
39
+ setup :clear_cache
40
+ def clear_cache
41
+ CacheBack.cache.reset!
42
+ Rails.cache.clear if Rails.cache.respond_to?(:clear)
43
+ end
44
+ end
45
+ rescue NameError => e
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,55 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class CacheExpiryTest < ActiveSupport::TestCase
4
+ fixtures :blogs, :posts
5
+
6
+ Post.has_cache_back
7
+ Post.has_cache_back_on :title
8
+ Post.has_cache_back_on :blog_id
9
+
10
+ context "a cached object" do
11
+ setup do
12
+ post = Post.first
13
+ @post = Post.find(post.id)
14
+ assert(Rails.cache.read(@post.cache_back_key))
15
+ end
16
+
17
+ should "be removed from cache when deleted" do
18
+ @post.destroy
19
+ assert_nil(Rails.cache.read(@post.cache_back_key))
20
+ end
21
+
22
+ should "clear all indices for instance when deleted" do
23
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/id=#{@post.id}")
24
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/id=#{@post.id}/first")
25
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=#{@post.title}")
26
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=#{@post.title}/first")
27
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/blog_id=#{@post.blog_id}")
28
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/blog_id=#{@post.blog_id}/first")
29
+ CacheBack.cache.expects(:delete).never
30
+
31
+ @post.destroy
32
+ end
33
+
34
+ should "be removed from cache when updated" do
35
+ @post.title = "new title"
36
+ @post.save
37
+ assert_nil(Rails.cache.read(@post.cache_back_key))
38
+ end
39
+
40
+ should "clear all indices for instance when updated" do
41
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/id=#{@post.id}")
42
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/id=#{@post.id}/first")
43
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=#{@post.title}")
44
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=#{@post.title}/first")
45
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=new title")
46
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/title=new title/first")
47
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/blog_id=#{@post.blog_id}")
48
+ CacheBack.cache.expects(:delete).with("cache_back/posts/version=1/blog_id=#{@post.blog_id}/first")
49
+ CacheBack.cache.expects(:delete).never
50
+
51
+ @post.title = "new title"
52
+ @post.save
53
+ end
54
+ end
55
+ end
data/test/dirty_test.rb CHANGED
@@ -6,13 +6,14 @@ class DirtyTest < ActiveSupport::TestCase
6
6
  Post.has_cache_back
7
7
  Post.cache_back_dirty_methods :make_dirty!
8
8
 
9
- should "update the cache when a dirty method is called" do
9
+ should "clear the indices when a dirty method is called" do
10
10
  post = Post.first
11
11
 
12
12
  pots = Post.find(post.id)
13
13
  assert(Rails.cache.read(post.cache_back_key))
14
14
 
15
- CacheBack.cache.expects(:write)
16
15
  post.make_dirty!
16
+
17
+ assert_nil(Rails.cache.read(post.cache_back_key))
17
18
  end
18
19
  end
@@ -30,4 +30,15 @@ class FindOneTest < ActiveSupport::TestCase
30
30
  CacheBack.cache.expects(:read).never
31
31
  Post.find(post.id, :select => 'title')
32
32
  end
33
+
34
+ should "respect scope" do
35
+ post = Post.find(Post.first.id)
36
+ other_blog = Blog.first(:conditions => "id != #{post.blog_id}")
37
+
38
+ assert(Rails.cache.read(post.cache_back_key))
39
+
40
+ assert_raise(ActiveRecord::RecordNotFound) do
41
+ other_blog.posts.find(post.id)
42
+ end
43
+ end
33
44
  end
@@ -4,6 +4,7 @@ class FindSomeTest < ActiveSupport::TestCase
4
4
  fixtures :blogs, :posts
5
5
 
6
6
  Post.has_cache_back
7
+ Post.has_cache_back_on :blog_id
7
8
 
8
9
  should "cache find(id, id) calls" do
9
10
  post1 = Post.first
@@ -36,4 +37,13 @@ class FindSomeTest < ActiveSupport::TestCase
36
37
  found_posts = Post.find(post1.id, post2.id)
37
38
  assert_equal([post1, post2].map(&:id).sort, found_posts.map(&:id).sort)
38
39
  end
40
+
41
+ should "cache on index other than primary key" do
42
+ blog = blogs(:a_blog)
43
+ posts = Post.find_all_by_blog_id(blog.id)
44
+
45
+ Post.expects(:find_every_without_cache_back).never
46
+
47
+ assert_equal(posts, Post.find_all_by_blog_id(blog.id))
48
+ end
39
49
  end
@@ -1,2 +1,5 @@
1
1
  a_blog:
2
- name: My Blog
2
+ name: My Blog
3
+
4
+ other_blog:
5
+ name: Some Other Blog
@@ -6,6 +6,10 @@ has_two_comments:
6
6
  blog: a_blog
7
7
  title: This post has a few comments
8
8
 
9
+ on_other_blog:
10
+ blog: other_blog
11
+ title: This post has no comments
12
+
9
13
  has_many_comments:
10
14
  blog: a_blog
11
15
  title: A shit load of comments on this one
data/test/helper.rb CHANGED
@@ -16,12 +16,14 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
16
16
  $LOAD_PATH.unshift(File.dirname(__FILE__))
17
17
  require 'cache_back'
18
18
 
19
+ CacheBack.setup
20
+
19
21
  class ActiveSupport::TestCase
20
22
  include ActiveRecord::TestFixtures
21
23
 
22
24
  fixtures :all
23
25
 
24
- setup :clear_cache
26
+ #setup :clear_cache
25
27
 
26
28
  def create_fixtures(*table_names)
27
29
  if block_given?
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class SerializationTest < ActiveSupport::TestCase
4
+ fixtures :blogs, :posts
5
+
6
+ Post.has_cache_back
7
+
8
+ should "store a CachedModel" do
9
+ post = Post.first
10
+ post.store_in_cache_back
11
+ assert_instance_of(CacheBack::Cache::CachedModel, Rails.cache.read(post.cache_back_key))
12
+ end
13
+
14
+ should "bring convert CachedModel to model instances" do
15
+ post = Post.first
16
+ post.store_in_cache_back
17
+
18
+ post = CacheBack.cache.read(post.cache_back_key)
19
+ assert_instance_of(Post, post)
20
+ end
21
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cache_back
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mick Staugaard
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-26 00:00:00 -08:00
12
+ date: 2009-11-29 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -50,11 +50,14 @@ files:
50
50
  - VERSION
51
51
  - lib/cache_back.rb
52
52
  - lib/cache_back/cache.rb
53
+ - lib/cache_back/conditions_parser.rb
53
54
  - lib/cache_back/configuration_mixin.rb
54
55
  - lib/cache_back/dirty_mixin.rb
55
56
  - lib/cache_back/rack_middleware.rb
56
57
  - lib/cache_back/read_mixin.rb
58
+ - lib/cache_back/reload_association_mixin.rb
57
59
  - lib/cache_back/write_mixin.rb
60
+ - test/cache_expiry_test.rb
58
61
  - test/database.yml
59
62
  - test/dirty_test.rb
60
63
  - test/find_one_test.rb
@@ -64,6 +67,7 @@ files:
64
67
  - test/fixtures/posts.yml
65
68
  - test/helper.rb
66
69
  - test/schema.rb
70
+ - test/serialization_test.rb
67
71
  has_rdoc: true
68
72
  homepage: http://github.com/staugaard/cache_back
69
73
  licenses: []
@@ -93,8 +97,10 @@ signing_key:
93
97
  specification_version: 3
94
98
  summary: A write back caching layer on active record
95
99
  test_files:
100
+ - test/cache_expiry_test.rb
96
101
  - test/dirty_test.rb
97
102
  - test/find_one_test.rb
98
103
  - test/find_some_test.rb
99
104
  - test/helper.rb
100
105
  - test/schema.rb
106
+ - test/serialization_test.rb