cached-models 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|