ar-resque-counter-cache 2.1.0 → 3.0.0.rc1

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.
@@ -4,7 +4,7 @@ require "ar-resque-counter-cache/version"
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "ar-resque-counter-cache"
7
- s.version = ArAsyncCounterCache::VERSION
7
+ s.version = ArResqueCounterCache::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Aaron Gibralter"]
10
10
  s.email = ["aaron.gibralter@gmail.com"]
@@ -1,5 +1,3 @@
1
1
  require 'active_record'
2
2
  require 'ar-resque-counter-cache/increment_counters_worker'
3
3
  require 'ar-resque-counter-cache/active_record'
4
-
5
- ActiveRecord::Base.send(:include, ArAsyncCounterCache::ActiveRecord)
@@ -1,72 +1,130 @@
1
- module ArAsyncCounterCache
1
+ module ArResqueCounterCache
2
2
 
3
3
  module ActiveRecord
4
4
 
5
- def update_async_counters(dir, *association_ids)
6
- association_ids.each do |association_id|
7
- reflection = self.class.reflect_on_association(association_id)
8
- parent_class = reflection.klass
9
- column = self.class.async_counter_types[association_id]
10
- if parent_id = send(reflection.foreign_key)
11
- ArAsyncCounterCache::IncrementCountersWorker.cache_and_enqueue(parent_class, parent_id, column, dir)
5
+ ORIG_BT = ::ActiveRecord::Associations::BelongsToAssociation
6
+ ORIG_BTP = ::ActiveRecord::Associations::BelongsToPolymorphicAssociation
7
+
8
+ module Associations
9
+
10
+ module AsyncUpdateCounters
11
+ def update_counters_with_async(record)
12
+ # TODO make async?
13
+ update_counters_without_async(record)
12
14
  end
13
- end
14
- end
15
15
 
16
- module ClassMethods
17
-
18
- def belongs_to(association_id, options={})
19
- column = async_counter_cache_column(options.delete(:async_counter_cache))
20
- raise "Please don't use both async_counter_cache and counter_cache." if column && options[:counter_cache]
21
- super(association_id, options)
22
- if column
23
- # Store the async_counter_cache column for the update_async_counters
24
- # helper method.
25
- self.async_counter_types[association_id] = column
26
- # Fetch the reflection.
27
- reflection = self.reflect_on_association(association_id)
28
- parent_class = reflection.klass
29
- # Let's make the column read-only like the normal belongs_to
30
- # counter_cache.
31
- parent_class.send(:attr_readonly, column.to_sym) if defined?(parent_class) && parent_class.respond_to?(:attr_readonly)
32
- parent_id_column = reflection.foreign_key
33
- add_callbacks(parent_class.to_s, parent_id_column, column)
16
+ def self.included(base)
17
+ base.class_eval do
18
+ alias_method_chain :update_counters, :async
19
+ end
34
20
  end
35
21
  end
36
22
 
37
- def async_counter_types
38
- @async_counter_types ||= {}
23
+ class AsyncBelongsToAssociation < ORIG_BT
24
+ include AsyncUpdateCounters
39
25
  end
40
26
 
41
- private
27
+ class AsyncBelongsToPolymorphicAssociation < ORIG_BTP
28
+ include AsyncUpdateCounters
29
+ end
30
+ end
42
31
 
43
- def add_callbacks(parent_class, parent_id_column, column)
44
- base_method_name = "async_counter_cache_#{parent_class}_#{column}"
45
- # Define after_create callback method.
46
- method_name = "#{base_method_name}_after_create".to_sym
47
- define_method(method_name) do
48
- if parent_id = send(parent_id_column)
49
- ArAsyncCounterCache::IncrementCountersWorker.cache_and_enqueue(parent_class, parent_id, column, :increment)
32
+ module AssociationReflectionTweaks
33
+ def association_class_with_async
34
+ if macro == :belongs_to && options[:async_counter_cache]
35
+ if options[:polymorphic]
36
+ Associations::AsyncBelongsToPolymorphicAssociation
37
+ else
38
+ Associations::AsyncBelongsToAssociation
50
39
  end
40
+ else
41
+ association_class_without_async
51
42
  end
52
- after_commit(method_name, :on => :create)
53
- # Define after_destroy callback method.
54
- method_name = "#{base_method_name}_after_destroy".to_sym
55
- define_method(method_name) do
56
- if parent_id = send(parent_id_column)
57
- ArAsyncCounterCache::IncrementCountersWorker.cache_and_enqueue(parent_class, parent_id, column, :decrement)
58
- end
43
+ end
44
+
45
+ def counter_cache_column_with_async
46
+ if options[:async_counter_cache] == true
47
+ "#{active_record.name.demodulize.underscore.pluralize}_count"
48
+ elsif options[:async_counter_cache]
49
+ options[:async_counter_cache].to_s
50
+ else
51
+ counter_cache_column_without_async
59
52
  end
60
- after_commit(method_name, :on => :destroy)
61
53
  end
62
54
 
63
- def async_counter_cache_column(opt)
64
- opt === true ? "#{self.table_name}_count" : opt
55
+ def self.included(base)
56
+ base.class_eval do
57
+ alias_method_chain :association_class, :async
58
+ alias_method_chain :counter_cache_column, :async
59
+ end
65
60
  end
66
61
  end
67
62
 
68
- def self.included(base)
69
- base.extend(ClassMethods)
63
+ module AsyncBuilderBehavior
64
+ def build_with_async
65
+ reflection = build_without_async
66
+ if options[:async_counter_cache] && options[:counter_cache]
67
+ raise 'Do not mix `:async_counter_cache` and `:counter_cache`.'
68
+ end
69
+ if options[:async_counter_cache]
70
+ add_async_counter_cache_callbacks(reflection)
71
+ end
72
+ reflection
73
+ end
74
+
75
+ def self.included(base)
76
+ base.class_eval do
77
+ alias_method_chain :build, :async
78
+ self.valid_options += [:async_counter_cache]
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def add_async_counter_cache_callbacks(reflection)
85
+ cache_column = reflection.counter_cache_column
86
+ name = self.name
87
+
88
+ method_name = "belongs_to_async_counter_cache_on_create_for_#{name}"
89
+ model.redefine_method(method_name) do
90
+ record = send(name)
91
+ ArResqueCounterCache::IncrementCountersWorker.cache_and_enqueue(
92
+ record.class.to_s,
93
+ record.id,
94
+ cache_column,
95
+ :increment
96
+ ) unless record.nil?
97
+ end
98
+ model.after_commit(method_name, :on => :create)
99
+
100
+ method_name = "belongs_to_async_counter_cache_on_destroy_for_#{name}"
101
+ model.redefine_method(method_name) do
102
+ record = send(name)
103
+ ArResqueCounterCache::IncrementCountersWorker.cache_and_enqueue(
104
+ record.class.to_s,
105
+ record.id,
106
+ cache_column,
107
+ :decrement
108
+ ) unless record.nil?
109
+ end
110
+ model.after_commit(method_name, :on => :destroy)
111
+
112
+ model.send(
113
+ :module_eval,
114
+ "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)",
115
+ __FILE__,
116
+ __LINE__
117
+ )
118
+ end
70
119
  end
71
120
  end
72
121
  end
122
+
123
+ ActiveRecord::Reflection::AssociationReflection.send(
124
+ :include,
125
+ ArResqueCounterCache::ActiveRecord::AssociationReflectionTweaks
126
+ )
127
+ ActiveRecord::Associations::Builder::BelongsTo.send(
128
+ :include,
129
+ ArResqueCounterCache::ActiveRecord::AsyncBuilderBehavior
130
+ )
@@ -1,7 +1,7 @@
1
1
  require 'resque'
2
2
  require 'resque-lock-timeout'
3
3
 
4
- module ArAsyncCounterCache
4
+ module ArResqueCounterCache
5
5
 
6
6
  # The default Resque queue is :counter_caches.
7
7
  def self.resque_job_queue=(queue)
@@ -25,7 +25,7 @@ module ArAsyncCounterCache
25
25
  end
26
26
  end
27
27
 
28
- # ArAsyncCounterCache will very quickly increment a counter cache in Redis,
28
+ # ArResqueCounterCache will very quickly increment a counter cache in Redis,
29
29
  # which will then later be updated by a Resque job. Using
30
30
  # require-lock-timeout, we can ensure that only one job per ___ is running
31
31
  # at a time.
@@ -43,7 +43,7 @@ module ArAsyncCounterCache
43
43
  elsif direction == :decrement
44
44
  redis.decr(key)
45
45
  else
46
- raise ArgumentError, "Must call ArAsyncCounterCache::IncrementCountersWorker with :increment or :decrement"
46
+ raise ArgumentError, "Must call ArResqueCounterCache::IncrementCountersWorker with :increment or :decrement"
47
47
  end
48
48
  ::Resque.enqueue(self, parent_class, id, column)
49
49
  end
@@ -1,3 +1,3 @@
1
- module ArAsyncCounterCache
2
- VERSION = "2.1.0"
1
+ module ArResqueCounterCache
2
+ VERSION = '3.0.0.rc1'
3
3
  end
@@ -1,20 +1,20 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ArAsyncCounterCache::ActiveRecord do
3
+ describe ArResqueCounterCache::ActiveRecord do
4
4
 
5
5
  context "callbacks" do
6
6
 
7
7
  subject { User.create(:name => "Susan") }
8
8
 
9
9
  it "should increment" do
10
- ArAsyncCounterCache::IncrementCountersWorker.should_receive(:cache_and_enqueue).with("User", subject.id, "posts_count", :increment)
10
+ ArResqueCounterCache::IncrementCountersWorker.should_receive(:cache_and_enqueue).with("User", subject.id, "posts_count", :increment)
11
11
  subject.posts.create(:body => "I have a cat!")
12
12
  end
13
13
 
14
14
  it "should increment" do
15
- ArAsyncCounterCache::IncrementCountersWorker.stub(:cache_and_enqueue)
15
+ ArResqueCounterCache::IncrementCountersWorker.stub(:cache_and_enqueue)
16
16
  post = subject.posts.create(:body => "I have a cat!")
17
- ArAsyncCounterCache::IncrementCountersWorker.should_receive(:cache_and_enqueue).with("User", subject.id, "posts_count", :decrement)
17
+ ArResqueCounterCache::IncrementCountersWorker.should_receive(:cache_and_enqueue).with("User", subject.id, "posts_count", :decrement)
18
18
  post.destroy
19
19
  end
20
20
  end
@@ -28,7 +28,7 @@ describe "integration" do
28
28
  # 3 for comments incrementing posts' comments counts
29
29
  Resque.size(:testing).should == 8
30
30
 
31
- # [ArAsyncCounterCache::IncrementCountersWorker, "User", 1, "posts_count"]
31
+ # [ArResqueCounterCache::IncrementCountersWorker, "User", 1, "posts_count"]
32
32
  perform_next_job
33
33
  @user1.reload.posts_count.should == 2
34
34
  @user1.reload.comments_count.should == 0
@@ -37,7 +37,7 @@ describe "integration" do
37
37
  @post1.reload.count_of_comments.should == 0
38
38
  @post2.reload.count_of_comments.should == 0
39
39
 
40
- # [ArAsyncCounterCache::IncrementCountersWorker, "Post", 1, "count_of_comments"]
40
+ # [ArResqueCounterCache::IncrementCountersWorker, "Post", 1, "count_of_comments"]
41
41
  perform_next_job
42
42
  @user1.reload.posts_count.should == 2
43
43
  @user1.reload.comments_count.should == 0
@@ -46,7 +46,7 @@ describe "integration" do
46
46
  @post1.reload.count_of_comments.should == 2
47
47
  @post2.reload.count_of_comments.should == 0
48
48
 
49
- # [ArAsyncCounterCache::IncrementCountersWorker, "User", 2, "comments_count"]
49
+ # [ArResqueCounterCache::IncrementCountersWorker, "User", 2, "comments_count"]
50
50
  perform_next_job
51
51
  @user1.reload.posts_count.should == 2
52
52
  @user1.reload.comments_count.should == 0
@@ -55,7 +55,7 @@ describe "integration" do
55
55
  @post1.reload.count_of_comments.should == 2
56
56
  @post2.reload.count_of_comments.should == 0
57
57
 
58
- # [ArAsyncCounterCache::IncrementCountersWorker, "User", 1, "comments_count"]
58
+ # [ArResqueCounterCache::IncrementCountersWorker, "User", 1, "comments_count"]
59
59
  perform_next_job
60
60
  @user1.reload.posts_count.should == 2
61
61
  @user1.reload.comments_count.should == 1
@@ -64,7 +64,7 @@ describe "integration" do
64
64
  @post1.reload.count_of_comments.should == 2
65
65
  @post2.reload.count_of_comments.should == 0
66
66
 
67
- # [ArAsyncCounterCache::IncrementCountersWorker, "Post", 2, "count_of_comments"]
67
+ # [ArResqueCounterCache::IncrementCountersWorker, "Post", 2, "count_of_comments"]
68
68
  perform_next_job
69
69
  @user1.reload.posts_count.should == 2
70
70
  @user1.reload.comments_count.should == 1
@@ -32,7 +32,7 @@ Resque.redis = '127.0.0.1:9736'
32
32
 
33
33
  RSpec.configure do |config|
34
34
  config.before(:all) do
35
- ArAsyncCounterCache.resque_job_queue = :testing
35
+ ArResqueCounterCache.resque_job_queue = :testing
36
36
  end
37
37
  config.before(:each) do
38
38
  ActiveRecord::Base.silence { CreateModelsForTest.migrate(:up) }
metadata CHANGED
@@ -1,19 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ar-resque-counter-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
5
- prerelease:
4
+ version: 3.0.0.rc1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Aaron Gibralter
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-07 00:00:00.000000000Z
12
+ date: 2012-01-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
16
- requirement: &2153292200 !ruby/object:Gem::Requirement
16
+ requirement: &70293402116900 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.1'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2153292200
24
+ version_requirements: *70293402116900
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: resque
27
- requirement: &2153291700 !ruby/object:Gem::Requirement
27
+ requirement: &70293402116100 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '1.0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2153291700
35
+ version_requirements: *70293402116100
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: resque-lock-timeout
38
- requirement: &2153291220 !ruby/object:Gem::Requirement
38
+ requirement: &70293402115180 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 0.3.1
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *2153291220
46
+ version_requirements: *70293402115180
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &2153290740 !ruby/object:Gem::Requirement
49
+ requirement: &70293402114700 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 2.4.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2153290740
57
+ version_requirements: *70293402114700
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: sqlite3-ruby
60
- requirement: &2153290280 !ruby/object:Gem::Requirement
60
+ requirement: &70293402114200 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: 1.3.3
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2153290280
68
+ version_requirements: *70293402114200
69
69
  description: Increment ActiveRecord's counter cache column asynchronously using Resque
70
70
  (and resque-lock-timeout).
71
71
  email:
@@ -104,9 +104,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
104
  required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
- - - ! '>='
107
+ - - ! '>'
108
108
  - !ruby/object:Gem::Version
109
- version: '0'
109
+ version: 1.3.1
110
110
  requirements: []
111
111
  rubyforge_project: ar-resque-counter-cache
112
112
  rubygems_version: 1.8.10