cached-models 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +58 -0
- data/README +1 -1
- data/Rakefile +1 -1
- data/about.yml +4 -4
- data/cached-models.gemspec +4 -5
- data/lib/activerecord/lib/active_record/associations.rb +35 -10
- data/lib/activerecord/lib/active_record/associations/association_collection.rb +44 -12
- data/lib/activerecord/lib/active_record/base.rb +7 -3
- data/tasks/cached_models_tasks.rake +32 -5
- data/test/active_record/associations/has_and_belongs_to_many_association_test.rb +12 -0
- data/test/active_record/associations/has_many_association_test.rb +119 -165
- data/test/active_record/associations/has_one_association_test.rb +12 -0
- data/test/fixtures/addresses.yml +7 -0
- data/test/fixtures/categories.yml +3 -0
- data/test/fixtures/categories_posts.yml +3 -0
- data/test/models/address.rb +3 -0
- data/test/models/author.rb +2 -0
- data/test/models/category.rb +3 -0
- data/test/models/post.rb +1 -0
- data/test/test_helper.rb +47 -1
- metadata +11 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,61 @@
|
|
1
|
+
*0.0.3 (October 22nd, 2008)*
|
2
|
+
|
3
|
+
* Tagged v0.0.3
|
4
|
+
|
5
|
+
* Test cases cleanup
|
6
|
+
|
7
|
+
* Sugar syntax for AssociationCollection#size
|
8
|
+
|
9
|
+
* Use loaded collection, instead of read from cache, when use scoped find form AssociationCollection
|
10
|
+
|
11
|
+
author.posts.find(1) # no cache read for #find
|
12
|
+
|
13
|
+
* Use loaded collection, instead of read from cache, when use #size, #empty? and #any? from AssociationCollection. Added support for :uniq option.
|
14
|
+
|
15
|
+
* Reduced cache overhead using read instead of fetch for access to AssociationCollection. Enhanced Mocha expectactions.
|
16
|
+
|
17
|
+
# BEFORE
|
18
|
+
author.posts # => cache fetch
|
19
|
+
|
20
|
+
# NOW
|
21
|
+
author.posts # => cache read
|
22
|
+
|
23
|
+
* Fixed typos in CHANGELOG and README
|
24
|
+
|
25
|
+
* Don't instantiate ivar when read from AssociationCollection if options[:cached] == true
|
26
|
+
|
27
|
+
* Reduced by half cache lookups when read from AssociationCollection
|
28
|
+
|
29
|
+
# BEFORE
|
30
|
+
author.posts # => cache read + cache fetch
|
31
|
+
|
32
|
+
# NOW
|
33
|
+
author.posts # => cache fetch
|
34
|
+
|
35
|
+
* Fixed Mocha expectations
|
36
|
+
|
37
|
+
* Fixed clear, delete and destroy cases for AssociationCollection
|
38
|
+
|
39
|
+
author.posts.delete(post)
|
40
|
+
author.posts.delete_all
|
41
|
+
author.posts.destroy
|
42
|
+
author.posts.destroy_all
|
43
|
+
author.posts.clear
|
44
|
+
|
45
|
+
* Fixed concurrency issues, using Thread#current to store cached_associations instead of ivar
|
46
|
+
|
47
|
+
* Make sure tests suite runs in 'test' environment. Introduced SKIP_MOCHA env variable, in order to run tests directly on cache
|
48
|
+
|
49
|
+
$ rake cached_models SKIP_MOCHA=true
|
50
|
+
|
51
|
+
* Bypass cache for will_paginate on association collection
|
52
|
+
|
53
|
+
author.posts.paginate(:all, :page => 1, :per_page => 10)
|
54
|
+
|
55
|
+
* Make sure habtm and has_one are safely used
|
56
|
+
|
57
|
+
|
58
|
+
|
1
59
|
*0.0.2 (October 10th, 2008)*
|
2
60
|
|
3
61
|
* Updated README with new installation instructions
|
data/README
CHANGED
data/Rakefile
CHANGED
data/about.yml
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
author: Luca Guidi
|
2
2
|
email: guidi.luca@gmail.com
|
3
3
|
homepage: http://lucaguidi.com/pages/cached_models
|
4
|
-
summary: CachedModels provides to your models a transparent approach to use
|
5
|
-
description: CachedModels provides to your models a transparent approach to use
|
4
|
+
summary: CachedModels provides to your ActiveRecord models a transparent approach to use ActiveSupport caching mechanism.
|
5
|
+
description: CachedModels provides to your ActiveRecord models a transparent approach to use ActiveSupport caching mechanism.
|
6
6
|
license: MIT
|
7
|
-
rails_version: 2.1.
|
8
|
-
version: 0.0.
|
7
|
+
rails_version: 2.1.0+
|
8
|
+
version: 0.0.3
|
data/cached-models.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "cached-models"
|
3
|
-
s.version = "0.0.
|
4
|
-
s.date = "2008-10-
|
3
|
+
s.version = "0.0.3"
|
4
|
+
s.date = "2008-10-22"
|
5
5
|
s.summary = "Transparent caching policy for your models"
|
6
6
|
s.author = "Luca Guidi"
|
7
7
|
s.email = "guidi.luca@gmail.com"
|
@@ -9,9 +9,8 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.description = "CachedModels provides to your ActiveRecord models a transparent approach to use ActiveSupport caching mechanism."
|
10
10
|
s.has_rdoc = true
|
11
11
|
s.rubyforge_project = %q{cached-models}
|
12
|
-
s.files = ["CHANGELOG", "MIT-LICENSE", "README", "Rakefile", "about.yml", "cached-models.gemspec", "init.rb", "install.rb", "lib/activerecord/lib/active_record.rb", "lib/activerecord/lib/active_record/associations.rb", "lib/activerecord/lib/active_record/associations/association_collection.rb", "lib/activerecord/lib/active_record/associations/association_proxy.rb", "lib/activerecord/lib/active_record/associations/has_many_association.rb", "lib/activerecord/lib/active_record/base.rb", "lib/cached-models.rb", "lib/cached_models.rb", "setup.rb", "tasks/cached_models_tasks.rake", "test/active_record/associations/has_many_association_test.rb", "test/active_record/base_test.rb", "test/fixtures/authors.yml", "test/fixtures/blogs.yml", "test/fixtures/comments.yml", "test/fixtures/posts.yml", "test/fixtures/tags.yml", "test/models/author.rb", "test/models/blog.rb", "test/models/comment.rb", "test/models/post.rb", "test/models/tag.rb", "test/test_helper.rb", "uninstall.rb"]
|
13
|
-
s.test_files = ["test/active_record/associations/has_many_association_test.rb",
|
14
|
-
"test/active_record/base_test.rb"]
|
12
|
+
s.files = ["CHANGELOG", "MIT-LICENSE", "README", "Rakefile", "about.yml", "cached-models.gemspec", "init.rb", "install.rb", "lib/activerecord/lib/active_record.rb", "lib/activerecord/lib/active_record/associations.rb", "lib/activerecord/lib/active_record/associations/association_collection.rb", "lib/activerecord/lib/active_record/associations/association_proxy.rb", "lib/activerecord/lib/active_record/associations/has_many_association.rb", "lib/activerecord/lib/active_record/base.rb", "lib/cached-models.rb", "lib/cached_models.rb", "setup.rb", "tasks/cached_models_tasks.rake", "test/active_record/associations/has_and_belongs_to_many_association_test.rb", "test/active_record/associations/has_many_association_test.rb", "test/active_record/associations/has_one_association_test.rb", "test/active_record/base_test.rb", "test/fixtures/addresses.yml", "test/fixtures/authors.yml", "test/fixtures/blogs.yml", "test/fixtures/categories.yml", "test/fixtures/categories_posts.yml", "test/fixtures/comments.yml", "test/fixtures/posts.yml", "test/fixtures/tags.yml", "test/models/address.rb", "test/models/author.rb", "test/models/blog.rb", "test/models/category.rb", "test/models/comment.rb", "test/models/post.rb", "test/models/tag.rb", "test/test_helper.rb", "uninstall.rb"]
|
13
|
+
s.test_files = ["test/active_record/associations/has_and_belongs_to_many_association_test.rb", "test/active_record/associations/has_many_association_test.rb", "test/active_record/associations/has_one_association_test.rb", "test/active_record/base_test.rb"]
|
15
14
|
s.extra_rdoc_files = ['README', 'CHANGELOG']
|
16
15
|
|
17
16
|
s.add_dependency("activesupport", ["> 2.1.0"])
|
@@ -251,11 +251,15 @@ module ActiveRecord
|
|
251
251
|
end
|
252
252
|
|
253
253
|
if options[:cached]
|
254
|
-
|
255
|
-
|
254
|
+
after_save_method_name = "belongs_to_after_save_for_#{reflection.name}".to_sym
|
255
|
+
after_destroy_method_name = "belongs_to_after_destroy_for_#{reflection.name}".to_sym
|
256
|
+
define_method(after_save_method_name) do
|
256
257
|
send(reflection.name).expire_cache_for(self.class.name)
|
257
258
|
end
|
258
|
-
|
259
|
+
|
260
|
+
alias_method after_destroy_method_name, after_save_method_name
|
261
|
+
after_save after_save_method_name
|
262
|
+
after_destroy after_destroy_method_name
|
259
263
|
end
|
260
264
|
|
261
265
|
add_single_associated_validation_callbacks(reflection.name) if options[:validate] == true
|
@@ -277,19 +281,19 @@ module ActiveRecord
|
|
277
281
|
|
278
282
|
unless association.respond_to?(:loaded?)
|
279
283
|
association = association_proxy_class.new(self, reflection)
|
280
|
-
|
284
|
+
if options[:cached]
|
285
|
+
cache_write(reflection, association)
|
286
|
+
else
|
287
|
+
instance_variable_set(ivar, association)
|
288
|
+
end
|
281
289
|
end
|
282
290
|
|
283
291
|
if force_reload
|
284
292
|
association.reload
|
285
|
-
|
293
|
+
cache_write(reflection, association) if options[:cached]
|
286
294
|
end
|
287
295
|
|
288
|
-
|
289
|
-
cache_fetch(reflection, association)
|
290
|
-
else
|
291
|
-
association
|
292
|
-
end
|
296
|
+
association
|
293
297
|
end
|
294
298
|
|
295
299
|
method_name = "#{reflection.name.to_s.singularize}_ids"
|
@@ -306,6 +310,27 @@ module ActiveRecord
|
|
306
310
|
end
|
307
311
|
end
|
308
312
|
|
313
|
+
def has_and_belongs_to_many(association_id, options = {}, &extension)
|
314
|
+
reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension)
|
315
|
+
|
316
|
+
add_multiple_associated_validation_callbacks(reflection.name) unless options[:validate] == false
|
317
|
+
add_multiple_associated_save_callbacks(reflection.name)
|
318
|
+
collection_accessor_methods(reflection, HasAndBelongsToManyAssociation, options)
|
319
|
+
|
320
|
+
# Don't use a before_destroy callback since users' before_destroy
|
321
|
+
# callbacks will be executed after the association is wiped out.
|
322
|
+
old_method = "destroy_without_habtm_shim_for_#{reflection.name}"
|
323
|
+
class_eval <<-end_eval unless method_defined?(old_method)
|
324
|
+
alias_method :#{old_method}, :destroy_without_callbacks
|
325
|
+
def destroy_without_callbacks
|
326
|
+
#{reflection.name}.clear
|
327
|
+
#{old_method}
|
328
|
+
end
|
329
|
+
end_eval
|
330
|
+
|
331
|
+
add_association_callbacks(reflection.name, options)
|
332
|
+
end
|
333
|
+
|
309
334
|
def collection_accessor_methods(reflection, association_proxy_class, options, writer = true)
|
310
335
|
collection_reader_method(reflection, association_proxy_class, options)
|
311
336
|
|
@@ -4,22 +4,18 @@ module ActiveRecord
|
|
4
4
|
module Associations
|
5
5
|
class AssociationCollection < AssociationProxy #:nodoc:
|
6
6
|
def find(*args)
|
7
|
+
options = args.extract_options!
|
7
8
|
expects_array = args.first.kind_of?(Array)
|
8
|
-
|
9
|
+
args = args.flatten.compact.uniq
|
9
10
|
|
10
|
-
if @reflection.options[:cached]
|
11
|
-
result =
|
12
|
-
|
13
|
-
result = result.select { |record| ids.include? record.id }
|
14
|
-
result = expects_array ? result : result.first
|
15
|
-
return result
|
16
|
-
end
|
11
|
+
if @reflection.options[:cached] && !args.first.is_a?(Symbol)
|
12
|
+
result = self.select { |record| args.map(&:to_i).include? record.id }
|
13
|
+
return expects_array ? result : result.first
|
17
14
|
end
|
18
15
|
|
19
|
-
options = args.extract_options!
|
20
|
-
|
21
16
|
# If using a custom finder_sql, scan the entire collection.
|
22
17
|
if @reflection.options[:finder_sql]
|
18
|
+
ids = args.flatten.compact.uniq.map(&:to_i)
|
23
19
|
if ids.size == 1
|
24
20
|
id = ids.first
|
25
21
|
record = load_target.detect { |r| id == r.id }
|
@@ -72,13 +68,49 @@ module ActiveRecord
|
|
72
68
|
result && self
|
73
69
|
end
|
74
70
|
|
71
|
+
# Remove +records+ from this association. Does not destroy +records+.
|
72
|
+
def delete(*records)
|
73
|
+
records = flatten_deeper(records)
|
74
|
+
records.each { |record| raise_on_type_mismatch(record) }
|
75
|
+
|
76
|
+
@owner.transaction do
|
77
|
+
records.each { |record| callback(:before_remove, record) }
|
78
|
+
|
79
|
+
old_records = records.reject {|r| r.new_record? }
|
80
|
+
delete_records(old_records) if old_records.any?
|
81
|
+
|
82
|
+
records.each do |record|
|
83
|
+
@target.delete(record)
|
84
|
+
callback(:after_remove, record)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
@owner.send(:cache_write, @reflection, self) if @reflection.options[:cached]
|
89
|
+
end
|
90
|
+
|
91
|
+
# Removes all records from this association. Returns +self+ so method calls may be chained.
|
92
|
+
def clear
|
93
|
+
return self if length.zero? # forces load_target if it hasn't happened already
|
94
|
+
|
95
|
+
if @reflection.options[:dependent] && @reflection.options[:dependent] == :destroy
|
96
|
+
destroy_all
|
97
|
+
else
|
98
|
+
delete_all
|
99
|
+
end
|
100
|
+
|
101
|
+
@owner.send(:cache_write, @reflection, self) if @reflection.options[:cached]
|
102
|
+
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
75
106
|
# Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been loaded and
|
76
107
|
# calling collection.size if it has. If it's more likely than not that the collection does have a size larger than zero
|
77
108
|
# and you need to fetch that collection afterwards, it'll take one less SELECT query if you use length.
|
78
109
|
def size
|
79
110
|
if @reflection.options[:cached]
|
80
|
-
result =
|
81
|
-
|
111
|
+
returning result = self.to_ary do
|
112
|
+
@reflection.options[:uniq] ? result.uniq.size : result.size
|
113
|
+
end
|
82
114
|
end
|
83
115
|
|
84
116
|
if @owner.new_record? || (loaded? && !@reflection.options[:uniq])
|
@@ -36,7 +36,10 @@ module ActiveRecord
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def cache_write(reflection, value)
|
39
|
-
|
39
|
+
# This is a workaround for:
|
40
|
+
# http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1239-railscachewrite-returns-false-with-memcachestore
|
41
|
+
rails_cache.write(reflection_cache_key(reflection), value)
|
42
|
+
cached_associations[reflection.name] = true
|
40
43
|
end
|
41
44
|
|
42
45
|
def cache_delete(reflection)
|
@@ -63,7 +66,8 @@ module ActiveRecord
|
|
63
66
|
end
|
64
67
|
|
65
68
|
def cached_associations
|
66
|
-
|
69
|
+
cached_associations = (Thread.current[:cached_associations] ||= {})
|
70
|
+
cached_associations[cache_key] ||= {}
|
67
71
|
end
|
68
72
|
end
|
69
|
-
end
|
73
|
+
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# RAILS_ENV = "test"
|
2
|
+
|
1
3
|
require 'rubygems'
|
2
4
|
require 'active_record'
|
3
5
|
require 'active_record/fixtures'
|
4
6
|
|
5
7
|
path_to_fixtures = File.dirname(__FILE__) + '/../test/fixtures'
|
6
|
-
fixtures = %w( authors blogs posts comments tags )
|
8
|
+
fixtures = %w( addresses authors blogs posts categories categories_posts comments tags )
|
7
9
|
|
8
10
|
desc 'Run default task (test)'
|
9
11
|
task :cached_models => 'cached_models:test'
|
@@ -21,6 +23,17 @@ namespace :cached_models do
|
|
21
23
|
desc 'Create CachedModels test database tables'
|
22
24
|
task :create_tables => :environment do
|
23
25
|
ActiveRecord::Schema.define do
|
26
|
+
create_table :addresses, :force => true do |t|
|
27
|
+
t.integer :author_id
|
28
|
+
t.string :street
|
29
|
+
t.string :zip
|
30
|
+
t.string :city
|
31
|
+
t.string :state
|
32
|
+
t.string :country
|
33
|
+
|
34
|
+
t.timestamps
|
35
|
+
end
|
36
|
+
|
24
37
|
create_table :authors, :force => true do |t|
|
25
38
|
t.integer :blog_id
|
26
39
|
t.string :first_name
|
@@ -32,7 +45,7 @@ namespace :cached_models do
|
|
32
45
|
|
33
46
|
create_table :blogs, :force => true do |t|
|
34
47
|
t.string :title
|
35
|
-
|
48
|
+
|
36
49
|
t.timestamps
|
37
50
|
end
|
38
51
|
|
@@ -46,19 +59,30 @@ namespace :cached_models do
|
|
46
59
|
t.timestamps
|
47
60
|
end
|
48
61
|
|
62
|
+
create_table :categories, :force => true do |t|
|
63
|
+
t.string :name
|
64
|
+
|
65
|
+
t.timestamps
|
66
|
+
end
|
67
|
+
|
68
|
+
create_table :categories_posts, :force => true do |t|
|
69
|
+
t.integer :category_id
|
70
|
+
t.integer :post_id
|
71
|
+
end
|
72
|
+
|
49
73
|
create_table :comments, :force => true do |t|
|
50
74
|
t.integer :post_id
|
51
75
|
t.string :email
|
52
76
|
t.text :text
|
53
|
-
|
77
|
+
|
54
78
|
t.timestamps
|
55
79
|
end
|
56
|
-
|
80
|
+
|
57
81
|
create_table :tags, :force => true do |t|
|
58
82
|
t.integer :taggable_id
|
59
83
|
t.string :taggable_type
|
60
84
|
t.string :name
|
61
|
-
|
85
|
+
|
62
86
|
t.timestamps
|
63
87
|
end
|
64
88
|
end
|
@@ -66,10 +90,13 @@ namespace :cached_models do
|
|
66
90
|
|
67
91
|
desc 'Drops CachedModels test database tables'
|
68
92
|
task :drop_tables => :environment do
|
93
|
+
ActiveRecord::Base.connection.drop_table :addresses
|
69
94
|
ActiveRecord::Base.connection.drop_table :authors
|
70
95
|
ActiveRecord::Base.connection.drop_table :posts
|
71
96
|
ActiveRecord::Base.connection.drop_table :comments
|
72
97
|
ActiveRecord::Base.connection.drop_table :tags
|
98
|
+
ActiveRecord::Base.connection.drop_table :categories
|
99
|
+
ActiveRecord::Base.connection.drop_table :categories_posts
|
73
100
|
end
|
74
101
|
|
75
102
|
desc 'Load fixtures'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
class HasAndBelongsToManyAssociationTest < Test::Unit::TestCase
|
4
|
+
include ActiveRecord::Associations
|
5
|
+
|
6
|
+
def test_should_not_raise_exception
|
7
|
+
assert_nothing_raised ArgumentError do
|
8
|
+
posts(:welcome).categories
|
9
|
+
categories(:announcements).posts
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -10,7 +10,7 @@ class HasManyAssociationTest < Test::Unit::TestCase
|
|
10
10
|
|
11
11
|
uses_mocha 'HasManyAssociationTest' do
|
12
12
|
def test_should_always_use_cache_for_all_instances_which_reference_the_same_record
|
13
|
-
cache.expects(:
|
13
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
14
14
|
expected = authors(:luca).cached_posts
|
15
15
|
actual = Author.first.cached_posts
|
16
16
|
assert_equal expected, actual
|
@@ -20,26 +20,10 @@ class HasManyAssociationTest < Test::Unit::TestCase
|
|
20
20
|
author = authors(:luca)
|
21
21
|
old_cache_key = author.cache_key
|
22
22
|
|
23
|
-
cache.expects(:
|
23
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
24
24
|
cache.expects(:delete).with("#{cache_key}/cached_posts").returns true
|
25
|
-
|
26
|
-
|
27
|
-
author.update_attributes :first_name => author.first_name.upcase
|
28
|
-
|
29
|
-
# assert_not_equal old_cache_key, author.cache_key
|
30
|
-
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_should_not_expire_cache_on_update_on_missing_updated_at
|
34
|
-
author = authors(:luca)
|
35
|
-
old_cache_key = author.cache_key
|
36
|
-
|
37
|
-
author.stubs(:[]).with(:updated_at).returns nil
|
38
|
-
author.expects(:[]).with('blog_id').returns author.blog_id
|
39
|
-
cache.expects(:fetch).with("#{cache_key}/cached_posts").times(2).returns association_proxy
|
40
|
-
cache.expects(:delete).with("#{cache_key}/cached_posts").never
|
41
|
-
cache.expects(:delete).with("#{cache_key}/cached_comments").never
|
42
|
-
cache.expects(:delete).with("#{cache_key}/cached_posts_with_comments").never
|
25
|
+
cache.expects(:delete).with("#{cache_key}/cached_comments").returns true
|
26
|
+
cache.expects(:delete).with("#{cache_key}/cached_posts_with_comments").returns true
|
43
27
|
|
44
28
|
author.cached_posts # force cache loading
|
45
29
|
author.update_attributes :first_name => author.first_name.upcase
|
@@ -49,90 +33,70 @@ class HasManyAssociationTest < Test::Unit::TestCase
|
|
49
33
|
end
|
50
34
|
|
51
35
|
def test_should_use_cache_when_find_with_scope
|
52
|
-
cache.expects(:
|
53
|
-
|
36
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
54
37
|
post = authors(:luca).cached_posts.find(posts(:welcome).id)
|
55
38
|
assert_equal posts(:welcome), post
|
56
39
|
end
|
57
40
|
|
58
41
|
def test_should_use_cache_when_find_with_scope_using_multiple_ids
|
59
|
-
cache.expects(:
|
60
|
-
|
42
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
61
43
|
ids = posts_by_author(:luca).map(&:id)
|
62
|
-
assert_equal posts_by_author(:luca),
|
63
|
-
authors(:luca).cached_posts.find(ids)
|
44
|
+
assert_equal posts_by_author(:luca), authors(:luca).cached_posts.find(ids)
|
64
45
|
end
|
65
46
|
|
66
47
|
def test_should_use_cache_when_fetch_first_from_collection
|
67
|
-
cache.expects(:
|
68
|
-
|
69
|
-
|
70
|
-
assert_equal [ posts_by_author(:luca).first ],
|
71
|
-
authors(:luca).cached_posts.first(1)
|
48
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
49
|
+
assert_equal [ posts_by_author(:luca).first ], authors(:luca).cached_posts.first(1)
|
72
50
|
end
|
73
51
|
|
74
52
|
def test_should_use_cache_when_fetch_last_from_collection
|
75
|
-
cache.expects(:
|
76
|
-
|
77
|
-
|
78
|
-
assert_equal [ posts_by_author(:luca).last ],
|
79
|
-
authors(:luca).cached_posts.last(1)
|
53
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
54
|
+
assert_equal [ posts_by_author(:luca).last ], authors(:luca).cached_posts.last(1)
|
80
55
|
end
|
81
56
|
|
82
|
-
def
|
83
|
-
cache.expects(:
|
84
|
-
|
57
|
+
def test_should_unload_cache_when_reset_collection
|
58
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").times(2).returns association_proxy
|
85
59
|
assert_false authors(:luca).cached_posts.reset
|
86
60
|
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
87
61
|
end
|
88
62
|
|
89
|
-
def
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
authors(:luca).cached_posts.delete_all
|
94
|
-
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
95
|
-
end
|
96
|
-
|
97
|
-
def test_should_expire_cache_when_destroy_all_elements_from_collection
|
98
|
-
cache.expects(:fetch).with("#{cache_key}/cached_posts").times(2).returns association_proxy
|
99
|
-
# cache.expects(:read).with("#{cache_key}/cached_posts").returns posts_by_author(:luca)
|
100
|
-
|
101
|
-
authors(:luca).cached_posts.destroy_all
|
102
|
-
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
103
|
-
end
|
104
|
-
|
105
|
-
def test_should_use_cache_on_collection_sum
|
106
|
-
cache.expects(:fetch).with("#{blogs(:weblog).cache_key}/authors").returns authors_association_proxy
|
107
|
-
|
108
|
-
assert_equal authors_by_blog(:weblog).map(&:age).sum,
|
109
|
-
blogs(:weblog).authors.sum(:age)
|
63
|
+
def test_should_not_use_cache_on_collection_sum
|
64
|
+
# calculations aren't supported for now
|
65
|
+
cache.expects(:read).with("#{blogs(:weblog).cache_key}/authors").never
|
66
|
+
assert_equal authors_by_blog(:weblog).map(&:age).sum, blogs(:weblog).authors.sum(:age)
|
110
67
|
end
|
111
68
|
|
112
69
|
def test_should_not_use_cache_on_false_cached_option
|
113
|
-
cache.expects(:
|
70
|
+
cache.expects(:read).never
|
114
71
|
authors(:luca).posts
|
115
72
|
authors(:luca).posts(true) # force reload
|
116
73
|
end
|
117
74
|
|
118
75
|
def test_should_cache_associated_objects
|
119
|
-
cache.expects(:
|
120
|
-
|
76
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").times(2).returns(posts_by_author(:luca))
|
121
77
|
posts = authors(:luca).cached_posts
|
122
78
|
assert_equal posts, authors(:luca).cached_posts
|
123
79
|
end
|
80
|
+
|
81
|
+
def test_should_safely_use_pagination
|
82
|
+
# pagination for now bypass cache and using database.
|
83
|
+
# the expectation is due to #cached_posts invocation.
|
84
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
85
|
+
posts = authors(:luca).cached_posts.paginate(:all, :page => 1, :per_page => 1)
|
86
|
+
assert_equal [ posts_by_author(:luca).first ], posts
|
87
|
+
end
|
124
88
|
|
125
89
|
def test_should_reload_association_and_refresh_the_cache_on_force_reload
|
126
|
-
cache.expects(:
|
127
|
-
|
90
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").times(2).returns(posts_by_author(:luca))
|
91
|
+
cache.expects(:write).times(3).returns true
|
128
92
|
reloaded_posts = authors(:luca).cached_posts(true)
|
129
93
|
assert_equal reloaded_posts, authors(:luca).cached_posts
|
130
94
|
end
|
131
95
|
|
132
96
|
def test_should_cache_associated_ids
|
133
|
-
|
134
|
-
cache.expects(:
|
135
|
-
|
97
|
+
ids = posts_by_author(:luca).map(&:id)
|
98
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns(posts_by_author(:luca))
|
99
|
+
cache.expects(:fetch).with("#{cache_key}/cached_post_ids").returns ids
|
136
100
|
assert_equal ids, authors(:luca).cached_post_ids
|
137
101
|
end
|
138
102
|
|
@@ -142,94 +106,67 @@ class HasManyAssociationTest < Test::Unit::TestCase
|
|
142
106
|
end
|
143
107
|
|
144
108
|
def test_should_cache_all_eager_loaded_objects
|
145
|
-
cache.expects(:
|
109
|
+
cache.expects(:read).with("#{cache_key}/cached_posts_with_comments").returns(posts_by_author(:luca, true))
|
146
110
|
posts = authors(:luca).cached_posts_with_comments
|
147
111
|
assert_equal posts, authors(:luca).cached_posts_with_comments
|
148
112
|
end
|
149
113
|
|
150
114
|
def test_should_not_cache_eager_loaded_objects_on_false_cached_option
|
151
|
-
cache.expects(:
|
115
|
+
cache.expects(:read).never
|
152
116
|
authors(:luca).posts_with_comments
|
153
117
|
end
|
154
118
|
|
155
119
|
def test_should_cache_polymorphic_associations
|
156
|
-
cache.expects(:
|
120
|
+
cache.expects(:read).with("#{posts(:cached_models).cache_key}/cached_tags").returns(tags_by_post(:cached_models))
|
157
121
|
tags = posts(:cached_models).cached_tags
|
158
122
|
assert_equal tags, posts(:cached_models).cached_tags
|
159
123
|
end
|
160
124
|
|
161
125
|
def test_should_not_cache_polymorphic_associations_on_false_cached_option
|
162
|
-
cache.expects(:
|
126
|
+
cache.expects(:read).never
|
163
127
|
posts(:cached_models).tags
|
164
128
|
end
|
165
129
|
|
166
130
|
def test_should_cache_habtm_associations
|
167
|
-
cache.expects(:
|
131
|
+
cache.expects(:read).with("#{cache_key}/cached_comments").returns(comments_by_author(:luca))
|
168
132
|
comments = authors(:luca).cached_comments
|
169
133
|
assert_equal comments, authors(:luca).cached_comments
|
170
134
|
end
|
171
135
|
|
172
136
|
def test_should_not_cache_habtm_associations_on_false_cached_option
|
173
|
-
cache.expects(:
|
137
|
+
cache.expects(:read).never
|
174
138
|
authors(:luca).comments
|
175
139
|
end
|
176
140
|
|
177
141
|
def test_should_refresh_cache_when_associated_elements_change
|
178
|
-
cache.expects(:
|
179
|
-
|
142
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").never
|
143
|
+
cache.expects(:delete).with("#{cache_key}/cached_posts").returns true
|
180
144
|
post = authors(:luca).cached_posts.last # force cache loading and fetch a post
|
181
145
|
post.update_attributes :title => 'Cached Models!'
|
182
|
-
|
183
146
|
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
184
147
|
end
|
185
148
|
|
186
149
|
def test_should_refresh_cache_when_pushing_element_to_association
|
187
|
-
cache.expects(:
|
150
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").times(2).returns association_proxy
|
188
151
|
cache.expects(:write).with("#{cache_key}/cached_posts", association_proxy).returns true
|
189
|
-
|
190
152
|
post = create_post :author_id => nil
|
191
153
|
authors(:luca).cached_posts << post
|
192
|
-
|
193
|
-
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
194
|
-
end
|
195
|
-
|
196
|
-
def test_should_refresh_caches_when_pushing_element_to_association_belonging_to_another_model
|
197
|
-
cache.expects(:fetch).with("#{authors(:chuck).cache_key}/cached_posts").times(2).returns association_proxy(:chuck)
|
198
|
-
cache.expects(:fetch).with("#{cache_key}/cached_posts").times(2).returns association_proxy
|
199
|
-
|
200
|
-
post = authors(:chuck).cached_posts.last
|
201
|
-
authors(:luca).cached_posts << post
|
202
|
-
|
203
154
|
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
204
|
-
assert_equal posts_by_author(:chuck), authors(:chuck).cached_posts
|
205
|
-
end
|
206
|
-
|
207
|
-
def test_should_refresh_caches_when_pushing_element_to_polymorphic_association_belonging_to_another_model
|
208
|
-
cache.expects(:fetch).with("#{posts(:welcome).cache_key}/cached_tags").times(2).returns tags_association_proxy
|
209
|
-
cache.expects(:fetch).with("#{posts(:cached_models).cache_key}/cached_tags").times(2).returns tags_association_proxy(:cached_models)
|
210
|
-
tag = posts(:welcome).cached_tags.last
|
211
|
-
|
212
|
-
posts(:cached_models).cached_tags << tag
|
213
|
-
|
214
|
-
# NOTE for some weird reason the assertion fails, even if the collections are equals.
|
215
|
-
# I forced the comparision between the ids.
|
216
|
-
assert_equal tags_by_post(:cached_models).map(&:id).sort,
|
217
|
-
posts(:cached_models).cached_tags.map(&:id).sort
|
218
|
-
assert_equal tags_by_post(:welcome), posts(:welcome).cached_tags
|
219
155
|
end
|
220
156
|
|
221
157
|
def test_should_not_use_cache_when_pushing_element_to_association_on_false_cached_option
|
222
158
|
cache.expects(:write).never
|
223
|
-
|
224
159
|
post = create_post :author_id => nil
|
225
160
|
authors(:luca).posts << post
|
226
161
|
end
|
227
162
|
|
228
163
|
def test_should_not_use_cache_when_pushing_element_to_association_belonging_to_anotner_model_on_false_cached_option
|
229
164
|
cache.expects(:delete).with("#{blogs(:weblog).cache_key}/posts").never
|
165
|
+
cache.expects(:delete).with("#{cache_key}/cached_posts_with_comments").never
|
166
|
+
cache.expects(:delete).with("#{cache_key}/cached_posts").returns true
|
167
|
+
cache.expects(:delete).with("#{posts(:cached_models).cache_key}/cached_tags").returns true
|
230
168
|
post = blogs(:weblog).posts.last
|
231
169
|
blogs(:blog).posts << post
|
232
|
-
|
233
170
|
assert_equal posts_by_blog(:blog), blogs(:blog).posts
|
234
171
|
end
|
235
172
|
|
@@ -237,109 +174,126 @@ class HasManyAssociationTest < Test::Unit::TestCase
|
|
237
174
|
cache.expects(:delete).never
|
238
175
|
tag = posts(:welcome).tags.last
|
239
176
|
posts(:cached_models).tags << tag
|
240
|
-
|
241
177
|
assert_equal tags_by_post(:cached_models), posts(:cached_models).tags
|
242
178
|
end
|
243
|
-
|
244
|
-
def test_should_update_cache_when_pushing_element_with_build
|
245
|
-
cache.expects(:fetch).with("#{cache_key}/cached_posts").times(2).returns association_proxy
|
246
179
|
|
180
|
+
def test_should_update_cache_when_directly_assigning_a_new_collection
|
181
|
+
posts = [ posts_by_author(:luca).first ]
|
182
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").times(2).returns association_proxy
|
183
|
+
authors(:luca).cached_posts = posts
|
184
|
+
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_should_use_cache_for_collection_size
|
188
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
189
|
+
assert_equal posts_by_author(:luca).size, authors(:luca).cached_posts.size
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_should_use_cache_and_return_uniq_records_for_collection_size_on_uniq_option
|
193
|
+
cache.expects(:read).with("#{cache_key}/uniq_cached_posts").never # wuh?!
|
194
|
+
assert_equal posts_by_author(:luca).size, authors(:luca).uniq_cached_posts.size
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_should_use_cache_for_collection_length
|
198
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
199
|
+
assert_equal posts_by_author(:luca).length, authors(:luca).cached_posts.length
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_should_use_cache_for_collection_empty
|
203
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
204
|
+
assert_equal posts_by_author(:luca).empty?, authors(:luca).cached_posts.empty?
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_should_use_cache_for_collection_any
|
208
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
209
|
+
assert_equal posts_by_author(:luca).any?, authors(:luca).cached_posts.any?
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_should_use_cache_for_collection_include
|
213
|
+
cache.expects(:read).with("#{cache_key}/cached_posts").returns association_proxy
|
214
|
+
post = posts_by_author(:luca).first
|
215
|
+
assert authors(:luca).cached_posts.include?(post)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
uses_memcached 'HasManyAssociationTest' do
|
220
|
+
def test_should_refresh_caches_when_pushing_element_to_association_belonging_to_another_model
|
221
|
+
post = authors(:chuck).cached_posts.last
|
222
|
+
authors(:luca).cached_posts << post
|
223
|
+
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
224
|
+
assert_equal posts_by_author(:chuck), authors(:chuck).cached_posts
|
225
|
+
end
|
226
|
+
|
227
|
+
def test_should_refresh_caches_when_pushing_element_to_polymorphic_association_belonging_to_another_model
|
228
|
+
tag = posts(:welcome).cached_tags.last
|
229
|
+
posts(:cached_models).cached_tags << tag
|
230
|
+
|
231
|
+
# NOTE for some weird reason the assertion fails, even if the collections are equals.
|
232
|
+
# I forced the comparision between the ids.
|
233
|
+
assert_equal tags_by_post(:cached_models).map(&:id).sort,
|
234
|
+
posts(:cached_models).cached_tags.map(&:id).sort
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_should_update_cache_when_pushing_element_with_build
|
247
238
|
author = authors(:luca)
|
248
239
|
post = author.cached_posts.build post_options
|
249
240
|
post.save
|
250
|
-
|
251
241
|
assert_equal posts_by_author(:luca), author.cached_posts
|
252
242
|
end
|
253
|
-
|
254
|
-
def test_should_update_cache_when_pushing_element_with_create
|
255
|
-
cache.expects(:fetch).with("#{cache_key}/cached_posts").times(2).returns association_proxy
|
256
243
|
|
244
|
+
def test_should_update_cache_when_pushing_element_with_create
|
257
245
|
author = authors(:luca)
|
258
246
|
author.cached_posts.create post_options(:title => "CM Overview")
|
259
|
-
|
260
247
|
assert_equal posts_by_author(:luca), author.cached_posts
|
261
248
|
end
|
262
249
|
|
263
250
|
def test_should_update_cache_when_pushing_element_with_create_bang_method
|
264
|
-
cache.expects(:fetch).with("#{cache_key}/cached_posts").times(2).returns association_proxy
|
265
|
-
|
266
251
|
author = authors(:luca)
|
267
252
|
author.cached_posts.create! post_options(:title => "CM Overview!!")
|
268
|
-
|
269
253
|
assert_equal posts_by_author(:luca), author.cached_posts
|
270
254
|
end
|
271
255
|
|
272
|
-
def
|
273
|
-
|
256
|
+
def test_should_expire_cache_when_delete_all_elements_from_collection
|
257
|
+
authors(:luca).cached_posts.delete_all
|
258
|
+
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
259
|
+
end
|
274
260
|
|
275
|
-
|
261
|
+
def test_should_expire_cache_when_destroy_all_elements_from_collection
|
262
|
+
authors(:luca).cached_posts.destroy_all
|
276
263
|
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
277
264
|
end
|
278
265
|
|
279
266
|
def test_should_update_cache_when_clearing_collection
|
280
|
-
|
281
|
-
authors(:luca).cached_posts.clear
|
282
|
-
|
267
|
+
authors(:luca).cached_posts.clear
|
283
268
|
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
284
269
|
end
|
285
270
|
|
286
271
|
def test_should_update_cache_when_clearing_collection_with_dependent_destroy_option
|
287
|
-
cache.expects(:fetch).with("#{cache_key}/cached_dependent_posts").times(2).returns association_proxy
|
288
272
|
authors(:luca).cached_dependent_posts.clear
|
289
|
-
|
290
273
|
assert_equal posts_by_author(:luca), authors(:luca).cached_dependent_posts
|
291
274
|
end
|
292
|
-
|
293
|
-
def test_should_update_cache_when_directly_assigning_a_new_collection
|
294
|
-
posts = [ posts_by_author(:luca).first ]
|
295
|
-
cache.expects(:fetch).with("#{cache_key}/cached_posts").times(2).returns association_proxy
|
296
|
-
authors(:luca).cached_posts = posts
|
297
275
|
|
276
|
+
def test_should_update_cache_when_deleting_element_from_collection
|
277
|
+
authors(:luca).cached_posts.delete(posts_by_author(:luca).first)
|
298
278
|
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
299
279
|
end
|
300
280
|
|
301
281
|
def test_should_update_cache_when_replace_collection
|
302
282
|
post = create_post; post.save
|
303
283
|
posts = [ posts_by_author(:luca).first, post ]
|
304
|
-
cache.expects(:fetch).with("#{cache_key}/cached_posts").times(2).returns association_proxy
|
305
284
|
authors(:luca).cached_posts.replace(posts)
|
306
|
-
|
307
285
|
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
308
286
|
end
|
309
287
|
|
310
|
-
def
|
311
|
-
|
312
|
-
|
313
|
-
assert_equal posts_by_author(:luca).size,
|
314
|
-
authors(:luca).cached_posts.size
|
315
|
-
end
|
316
|
-
|
317
|
-
def test_should_use_cache_for_collection_length
|
318
|
-
cache.expects(:fetch).with("#{cache_key}/cached_posts").returns association_proxy
|
319
|
-
|
320
|
-
assert_equal posts_by_author(:luca).length,
|
321
|
-
authors(:luca).cached_posts.length
|
322
|
-
end
|
323
|
-
|
324
|
-
def test_should_use_cache_for_collection_empty
|
325
|
-
cache.expects(:fetch).with("#{cache_key}/cached_posts").returns association_proxy
|
326
|
-
|
327
|
-
assert_equal posts_by_author(:luca).empty?,
|
328
|
-
authors(:luca).cached_posts.empty?
|
329
|
-
end
|
330
|
-
|
331
|
-
def test_should_use_cache_for_collection_any
|
332
|
-
cache.expects(:fetch).with("#{cache_key}/cached_posts").returns association_proxy
|
333
|
-
|
334
|
-
assert_equal posts_by_author(:luca).any?,
|
335
|
-
authors(:luca).cached_posts.any?
|
336
|
-
end
|
288
|
+
def test_should_not_expire_cache_on_update_on_missing_updated_at
|
289
|
+
author = authors(:luca)
|
290
|
+
old_cache_key = author.cache_key
|
337
291
|
|
338
|
-
|
339
|
-
|
292
|
+
author.cached_posts # force cache loading
|
293
|
+
author.update_attributes :first_name => author.first_name.upcase
|
340
294
|
|
341
|
-
|
342
|
-
|
295
|
+
# assert_not_equal old_cache_key, author.cache_key
|
296
|
+
assert_equal posts_by_author(:luca), authors(:luca).cached_posts
|
343
297
|
end
|
344
298
|
end
|
345
299
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
class HasOneAssociationTest < Test::Unit::TestCase
|
4
|
+
include ActiveRecord::Associations
|
5
|
+
|
6
|
+
def test_should_not_raise_exception_when_use_has_one
|
7
|
+
assert_nothing_raised ArgumentError do
|
8
|
+
authors(:luca).address
|
9
|
+
addresses(:luca).author
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/test/models/author.rb
CHANGED
@@ -2,9 +2,11 @@ class Author < ActiveRecord::Base
|
|
2
2
|
belongs_to :blog, :cached => true
|
3
3
|
has_many :posts
|
4
4
|
has_many :cached_posts, :cached => true, :class_name => 'Post'
|
5
|
+
has_many :uniq_cached_posts, :cached => true, :class_name => 'Post', :uniq => true
|
5
6
|
has_many :cached_dependent_posts, :cached => true, :class_name => 'Post', :dependent => :destroy
|
6
7
|
has_many :posts_with_comments, :class_name => 'Post', :include => :comments
|
7
8
|
has_many :cached_posts_with_comments, :class_name => 'Post', :include => :comments, :cached => true
|
8
9
|
has_many :comments, :through => :posts
|
9
10
|
has_many :cached_comments, :through => :posts, :source => :comments, :cached => true
|
11
|
+
has_one :address
|
10
12
|
end
|
data/test/models/post.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
RAILS_ENV = "test" unless defined? RAILS_ENV
|
2
2
|
|
3
3
|
require 'test/unit'
|
4
4
|
require 'rubygems'
|
@@ -17,6 +17,28 @@ require 'post'
|
|
17
17
|
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures"
|
18
18
|
ActionController::IntegrationTest.fixture_path = Test::Unit::TestCase.fixture_path
|
19
19
|
|
20
|
+
module WillPaginate #:nodoc:
|
21
|
+
def paginate(*args)
|
22
|
+
options = args.extract_options!
|
23
|
+
current_page, per_page = options[:page], options[:per_page]
|
24
|
+
offset = (current_page - 1) * per_page
|
25
|
+
|
26
|
+
count_options = options.except :page, :per_page
|
27
|
+
find_options = count_options.except(:count).update(:offset => offset, :limit => per_page)
|
28
|
+
|
29
|
+
args << find_options
|
30
|
+
@reflection.klass.find(*args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module ActiveRecord
|
35
|
+
module Associations
|
36
|
+
class AssociationCollection < AssociationProxy #:nodoc:
|
37
|
+
include WillPaginate
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
20
42
|
class Test::Unit::TestCase
|
21
43
|
self.use_transactional_fixtures = true
|
22
44
|
self.use_instantiated_fixtures = false
|
@@ -40,3 +62,27 @@ def uses_mocha(description)
|
|
40
62
|
rescue LoadError
|
41
63
|
$stderr.puts "Skipping #{description} tests. `gem install mocha` and try again."
|
42
64
|
end
|
65
|
+
|
66
|
+
def uses_memcached(description)
|
67
|
+
require 'memcache'
|
68
|
+
MemCache.new('localhost').stats
|
69
|
+
yield
|
70
|
+
rescue MemCache::MemCacheError
|
71
|
+
$stderr.puts "Skipping #{description} tests. Start memcached and try again."
|
72
|
+
end
|
73
|
+
|
74
|
+
if ENV['SKIP_MOCHA'] == 'true'
|
75
|
+
class Object
|
76
|
+
def expects(*args)
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def method_missing(method_name, *args, &block)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class NilClass
|
85
|
+
def method_missing(method_name, *args, &block)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cached-models
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-10-
|
12
|
+
date: 2008-10-22 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -60,15 +60,22 @@ files:
|
|
60
60
|
- lib/cached_models.rb
|
61
61
|
- setup.rb
|
62
62
|
- tasks/cached_models_tasks.rake
|
63
|
+
- test/active_record/associations/has_and_belongs_to_many_association_test.rb
|
63
64
|
- test/active_record/associations/has_many_association_test.rb
|
65
|
+
- test/active_record/associations/has_one_association_test.rb
|
64
66
|
- test/active_record/base_test.rb
|
67
|
+
- test/fixtures/addresses.yml
|
65
68
|
- test/fixtures/authors.yml
|
66
69
|
- test/fixtures/blogs.yml
|
70
|
+
- test/fixtures/categories.yml
|
71
|
+
- test/fixtures/categories_posts.yml
|
67
72
|
- test/fixtures/comments.yml
|
68
73
|
- test/fixtures/posts.yml
|
69
74
|
- test/fixtures/tags.yml
|
75
|
+
- test/models/address.rb
|
70
76
|
- test/models/author.rb
|
71
77
|
- test/models/blog.rb
|
78
|
+
- test/models/category.rb
|
72
79
|
- test/models/comment.rb
|
73
80
|
- test/models/post.rb
|
74
81
|
- test/models/tag.rb
|
@@ -101,5 +108,7 @@ signing_key:
|
|
101
108
|
specification_version: 2
|
102
109
|
summary: Transparent caching policy for your models
|
103
110
|
test_files:
|
111
|
+
- test/active_record/associations/has_and_belongs_to_many_association_test.rb
|
104
112
|
- test/active_record/associations/has_many_association_test.rb
|
113
|
+
- test/active_record/associations/has_one_association_test.rb
|
105
114
|
- test/active_record/base_test.rb
|