counter-cache 0.0.1 → 0.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 381fdac0060611f59b5314096aa953310c927a98
4
- data.tar.gz: 94cfd0f2f7f91c8e7fd3e6c2f2579d26fee90904
3
+ metadata.gz: 005de7af8ad6de2ac4db333a51a0b69037b415da
4
+ data.tar.gz: 82e11a2ff62767df0275d60e12ef8f6208f76dc3
5
5
  SHA512:
6
- metadata.gz: 41ac6baff5ade8a503c71244efcbfd584982e0ec9ea00bde813c0797100f30044e9304c922e3f20afbab0a3e82b3c5e4c9efb5cc90125cadab6d52901b85e0b8
7
- data.tar.gz: aa2e8b95531190a0cddcc33d5f88f4a7a332a2646f8ff39784db5ecaea567e431a6fb7af23ab06375172b613d6f28c24081cc6f5b9b043bd7f65bf7066cbd041
6
+ metadata.gz: a19850cde42e9e3d8413bc8d2b0f8ab134736c16df4171c788c2cc611363429d6830191d29027084bd93d2466d64dcda731949d2313d0f07311db87faa96dbce
7
+ data.tar.gz: e90d15bae6c2de8781dcb792e90f9b7f1e40fe4fdbefa7d83b9a5bc91515dbc01ced62ff68f3f3450716f0e23319e845a38767528a8e5b3bd221bcbd72da8460
data/.gitignore CHANGED
@@ -7,7 +7,6 @@ Gemfile.lock
7
7
  InstalledFiles
8
8
  _yardoc
9
9
  coverage
10
- doc/
11
10
  lib/bundler/man
12
11
  pkg
13
12
  rdoc
@@ -1,10 +1,10 @@
1
- language: ruby
2
1
  rvm:
3
- - 2.1.1
4
- - 2.1.0
5
- - 2.0.0
6
- - 1.9.3
2
+ - "1.9.3"
3
+ - "2.1.1"
4
+ gemfile:
5
+ - gemfiles/activerecord_3.gemfile
6
+ - gemfiles/activerecord_4.0.gemfile
7
+ - gemfiles/activerecord_4.1.gemfile
7
8
  notifications:
8
- email:
9
- on_success: never
10
- webhooks: "http://ci.wanelo.com/projects/2f4c3438-a0bc-434e-a9fb-30c0c335b432/status"
9
+ email: false
10
+ webhooks: "http://ci.wanelo.com/projects/d6108a07-a333-487a-97ed-0df78d8464c0/status"
@@ -0,0 +1,11 @@
1
+ appraise "activerecord-3" do
2
+ gem "activerecord", "~> 3.2.19"
3
+ end
4
+
5
+ appraise "activerecord-4.0" do
6
+ gem "activerecord", "~> 4.0.8"
7
+ end
8
+
9
+ appraise "activerecord-4.1" do
10
+ gem "activerecord", "~> 4.1.4"
11
+ end
data/README.md CHANGED
@@ -1,6 +1,82 @@
1
1
  # Counter::Cache
2
2
 
3
- TODO: Write a gem description
3
+ [![Build Status](https://travis-ci.org/wanelo/counter-cache.svg?branch=master)](https://travis-ci.org/wanelo/counter-cache)
4
+
5
+ Counting things is hard, counting them at scale is even harder, so control when things are counted.
6
+
7
+ [Rails Counter Caches](http://railscasts.com/episodes/23-counter-cache-column) are a convenient way to keep counters on
8
+ models that have many children. Without them, you always do live counts, which do not scale. But at high scale, Rails
9
+ counter caches create update contention on singe models, especially for social sites where any single model might become
10
+ extremely popular. Many web requests trying to update the same row creates database deadlocks and kills performance due
11
+ to locking and an uncontrollable increase in iops.
12
+
13
+ This library provides all the benefits of rails counter cache, without the penalty of the contention on updates,
14
+ by serializing, buffering, and delaying updates via a queue. Counts becoming slightly less realtime, but with a guarantee that
15
+ single models will never be updated more than once in certain time periods.
16
+
17
+ ![Counter Cache Flow](doc/counter-cache-flow.png)
18
+
19
+ By default, a Buffer Counter is used which implements two modes of counting. The two modes are deferred and recalculation.
20
+
21
+ IMPORTANT: If Sidekiq is to be used as the delayed job framework, using `sidekiq-unique-jobs` is essential: https://github.com/mhenrixon/sidekiq-unique-jobs
22
+
23
+ ### Mode: Deferred
24
+
25
+ Initial mode that is used to provide roughly realtime counters.
26
+
27
+ This mode is meant to provide very reasonably up to date counters using values buffered into Redis, without asking the database
28
+ for the count at all. An example of how this works is described:
29
+
30
+ Scenario: User has many posts. We want to keep track of the number of posts on the user model (posts_count column).
31
+
32
+ When a post is created:
33
+
34
+ 1. Increment a key in Redis that corresponds to the field and user that relates to the post.
35
+ 2. Enqueue a delayed job that will later reconcile the counter column based on the key in redis.
36
+ 3. When the job runs, it picks up the value from redis (which can be zero or more) and adds the value to user.posts_count
37
+ column on the associated model.
38
+
39
+ ```ruby
40
+ user = User.find_by_id(100)
41
+ user.posts_count # 10
42
+ user.posts.create(...) # => Job is enqueued
43
+ user.posts.create(...) # => Job is already enqueued
44
+
45
+ # come back later (after a delay)
46
+ user = User.find_by_id(100)
47
+ user.posts_count # 12
48
+ ```
49
+
50
+ ### Mode: Recalculation
51
+
52
+ Runs later and ensures values are completely up to date.
53
+
54
+ This mode is used to compensate for transient errors that may cause the deferred counters to drift from the actual
55
+ values. The exact reasons this happens are undefined, redis could hang, go away, the universe could skip ahead in time,
56
+ who knows.
57
+
58
+ Using the same scenario as above:
59
+
60
+ Scenario: User has many posts. We want to keep track of the number of posts on the user model (posts_count column).
61
+
62
+ 1. Enqueue a job that is delayed by many hours (customizable)
63
+ 2. When the job runs, run a full count query to find the true count from the database and save the value to the database.
64
+
65
+ ```ruby
66
+ user = User.find_by_id(100)
67
+ user.posts_count # 10
68
+ user.posts.create(...)
69
+ user.posts.create(...)
70
+
71
+ # redis crashes, world explodes, etc.. we miss on deferred update.
72
+
73
+ user = User.find_by_id(100)
74
+ user.posts_count # 11, due to only one deferred update having run.
75
+
76
+ # come back later in a couple hours
77
+ user = User.find_by_id(100)
78
+ user.posts_count # 12
79
+ ```
4
80
 
5
81
  ## Installation
6
82
 
@@ -18,7 +94,163 @@ Or install it yourself as:
18
94
 
19
95
  ## Usage
20
96
 
21
- TODO: Write usage instructions here
97
+ Counter caches are configured on the models from the perspective of the child model to the parent that contains the counter.
98
+
99
+ #### Basic Counter with recalculation:
100
+
101
+ ```ruby
102
+ class Post
103
+ include Counter::Cache
104
+
105
+ counter_cache_on column: :posts_count, # users.posts_count
106
+ relation: :user,
107
+ relation_class_name: "User",
108
+ method: :calculate_posts_count, # This is a method on the user.
109
+ end
110
+ ```
111
+
112
+ #### To control when recalculation happens:
113
+
114
+ ```ruby
115
+ class Post
116
+ include Counter::Cache
117
+
118
+ counter_cache_on column: :posts_count, # users.posts_count
119
+ relation: :user,
120
+ relation_class_name: "User",
121
+ method: :calculate_posts_count, # This is a method on the user.
122
+ recalculation: true|false, # whether to ever recalculate this counter.
123
+ recalculation_delay: 10.seconds # Only a hard value that defines when to perform a full recalculation.
124
+ end
125
+ ```
126
+
127
+ #### To control when the deferred job runs:
128
+
129
+ ```ruby
130
+ class Post
131
+ include Counter::Cache
132
+
133
+ counter_cache_on column: :posts_count, # users.posts_count
134
+ relation: :user,
135
+ relation_class_name: "User",
136
+ method: :calculate_posts_count, # This is a method on the user.
137
+ wait: 10.seconds # This can be a hard value
138
+
139
+ counter_cache_on column: :posts_count, # users.posts_count
140
+ relation: :user,
141
+ relation_class_name: "User",
142
+ method: :calculate_posts_count, # This is a method on the user.
143
+ wait: ->(user) { user.posts_count * 10 } # .. or a proc, in this case, the more posts a user has, the less frequently it will be updated.
144
+ end
145
+ ```
146
+
147
+ #### To control if an update should even happen:
148
+
149
+ ```ruby
150
+ class Post
151
+ include Counter::Cache
152
+
153
+ counter_cache_on column: :posts_count, # users.posts_count
154
+ relation: :user,
155
+ relation_class_name: "User",
156
+ method: :calculate_posts_count, # This is a method on the user.
157
+ if: ->(post) { post.public? ? false : true }
158
+ end
159
+ ```
160
+
161
+ #### Polymorphism (because YAY)
162
+
163
+ Setting `polymorphic: true`, will ask ActiveRecord what the class is (User, Store), based on followee_type, and update
164
+ the appropriate model. So if a user is followed, then that users followers_count will increment.
165
+
166
+ ```ruby
167
+ class User
168
+ attr_accessible :followers_count
169
+ end
170
+
171
+ class Store
172
+ attr_accessible :followers_count
173
+ end
174
+
175
+ class Follow
176
+ attr_accessible :user_id, :followee_id, :followee_type
177
+
178
+ belongs_to :followee, polymorphic: true
179
+
180
+ include Counter::Cache
181
+
182
+ counter_cache_on column: :followers_count,
183
+ relation: :followee,
184
+ polymorphic: true
185
+ end
186
+ ```
187
+
188
+ ## Configuration
189
+
190
+ In an initializer such as `config/initializers/counter_cache.rb`, write the configuration as:
191
+
192
+ ```ruby
193
+ Counter::Cache.configure do |c|
194
+ c.default_worker_adapter = MyCustomWorkAdapter
195
+ c.recalculation_delay = 6.hours # Default delay for recalculations
196
+ c.redis_pool = Redis.new
197
+ c.counting_data_store = MyCustomDataStore # Default is Counter::Cache::Redis
198
+ end
199
+ ```
200
+
201
+ ### default_worker_adapter
202
+
203
+ The worker adapter allows you to control how jobs are delayed/enqueued for later execution. Three options are passed:
204
+
205
+ - delay: This is the delay in seconds that the execution should be delayed. Can be ignored or adjusted. We pass this to
206
+ sidekiq.
207
+ - base_class: This is the class name of the source object.
208
+ - options: This will be a hash of options that should be passed to the instance of the counter.
209
+
210
+ An example of a dummy adapter is like so:
211
+
212
+ ```ruby
213
+ class TestWorkerAdapter
214
+ def enqueue(delay, base_class, options)
215
+ options[:source_object_class_name] = base_class.constantize
216
+ counter_class = options[:counter].constantize # options[:counter] is the class name of the counter that called the adapter.
217
+ counter = counter_class.new(nil, options)
218
+ counter.save!
219
+ end
220
+ end
221
+ ```
222
+
223
+ An example of a dummy adapter that uses Sidekiq is like so:
224
+
225
+ ```ruby
226
+ class CounterWorker
227
+ include Sidekiq::Worker
228
+
229
+ def perform(base_class, options)
230
+ options.symbolize_keys! # From ActiveSupport, Sidekiq looses symbol information from hashes.
231
+ options[:source_object_class_name] = base_class.constantize
232
+ counter_class = options[:counter].constantize # options[:counter] is the class name of the counter that called the adapter.
233
+ counter = counter_class.new(nil, options)
234
+ counter.save!
235
+ end
236
+
237
+ def self.enqueue(delay, base_class, options)
238
+ perform_in(delay, base_class, options)
239
+ end
240
+ end
241
+ ```
242
+
243
+ ### recalculation_delay
244
+
245
+ This should be set to the default delay for recalculations, in seconds.
246
+
247
+ ### redis_pool
248
+
249
+ This can either be a single redis connection or a ConnectionPool instance (https://github.com/mperham/connection_pool).
250
+
251
+ ### counting_data_store
252
+
253
+ This defaults to Counter::Cache::Redis but can be set to anything. The Redis store describes what the API would be.
22
254
 
23
255
  ## Contributing
24
256
 
@@ -27,3 +259,15 @@ TODO: Write usage instructions here
27
259
  3. Commit your changes (`git commit -am 'Add some feature'`)
28
260
  4. Push to the branch (`git push origin my-new-feature`)
29
261
  5. Create a new Pull Request
262
+
263
+ ### Running specs:
264
+
265
+ Appraisal is used to test against multiple versions of activerecord. 3.2, 4.0, and 4.1 are currently supported.
266
+
267
+ To install dependencies:
268
+
269
+ $ bundle exec appraisal install
270
+
271
+ To run specs across versions:
272
+
273
+ $ bundle exec appraisal rspec
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency "activerecord", ">= 3.0"
22
22
 
23
+ spec.add_development_dependency "appraisal"
23
24
  spec.add_development_dependency "bundler", "~> 1.6"
24
25
  spec.add_development_dependency "rake"
25
26
  spec.add_development_dependency "rspec", ">= 3.0"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 3.2.19"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,92 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ counter-cache (0.0.2)
5
+ activerecord (>= 3.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (3.2.19)
11
+ activesupport (= 3.2.19)
12
+ builder (~> 3.0.0)
13
+ activerecord (3.2.19)
14
+ activemodel (= 3.2.19)
15
+ activesupport (= 3.2.19)
16
+ arel (~> 3.0.2)
17
+ tzinfo (~> 0.3.29)
18
+ activesupport (3.2.19)
19
+ i18n (~> 0.6, >= 0.6.4)
20
+ multi_json (~> 1.0)
21
+ appraisal (1.0.0)
22
+ bundler
23
+ rake
24
+ thor (>= 0.14.0)
25
+ arel (3.0.3)
26
+ builder (3.0.4)
27
+ celluloid (0.15.2)
28
+ timers (~> 1.1.0)
29
+ coderay (1.1.0)
30
+ diff-lcs (1.2.5)
31
+ fakeredis (0.5.0)
32
+ redis (~> 3.0)
33
+ ffi (1.9.3)
34
+ formatador (0.2.5)
35
+ guard (2.6.1)
36
+ formatador (>= 0.2.4)
37
+ listen (~> 2.7)
38
+ lumberjack (~> 1.0)
39
+ pry (>= 0.9.12)
40
+ thor (>= 0.18.1)
41
+ guard-rspec (4.3.1)
42
+ guard (~> 2.1)
43
+ rspec (>= 2.14, < 4.0)
44
+ i18n (0.6.11)
45
+ listen (2.7.9)
46
+ celluloid (>= 0.15.2)
47
+ rb-fsevent (>= 0.9.3)
48
+ rb-inotify (>= 0.9)
49
+ lumberjack (1.0.9)
50
+ method_source (0.8.2)
51
+ multi_json (1.10.1)
52
+ pry (0.10.0)
53
+ coderay (~> 1.1.0)
54
+ method_source (~> 0.8.1)
55
+ slop (~> 3.4)
56
+ rake (10.3.2)
57
+ rb-fsevent (0.9.4)
58
+ rb-inotify (0.9.5)
59
+ ffi (>= 0.5.0)
60
+ redis (3.1.0)
61
+ rspec (3.0.0)
62
+ rspec-core (~> 3.0.0)
63
+ rspec-expectations (~> 3.0.0)
64
+ rspec-mocks (~> 3.0.0)
65
+ rspec-core (3.0.3)
66
+ rspec-support (~> 3.0.0)
67
+ rspec-expectations (3.0.3)
68
+ diff-lcs (>= 1.2.0, < 2.0)
69
+ rspec-support (~> 3.0.0)
70
+ rspec-mocks (3.0.3)
71
+ rspec-support (~> 3.0.0)
72
+ rspec-support (3.0.3)
73
+ slop (3.6.0)
74
+ sqlite3 (1.3.9)
75
+ thor (0.19.1)
76
+ timers (1.1.0)
77
+ tzinfo (0.3.39)
78
+
79
+ PLATFORMS
80
+ ruby
81
+
82
+ DEPENDENCIES
83
+ activerecord (~> 3.2.19)
84
+ appraisal
85
+ bundler (~> 1.6)
86
+ counter-cache!
87
+ fakeredis
88
+ guard
89
+ guard-rspec
90
+ rake
91
+ rspec (>= 3.0)
92
+ sqlite3
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.0.8"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,98 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ counter-cache (0.0.2)
5
+ activerecord (>= 3.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (4.0.8)
11
+ activesupport (= 4.0.8)
12
+ builder (~> 3.1.0)
13
+ activerecord (4.0.8)
14
+ activemodel (= 4.0.8)
15
+ activerecord-deprecated_finders (~> 1.0.2)
16
+ activesupport (= 4.0.8)
17
+ arel (~> 4.0.0)
18
+ activerecord-deprecated_finders (1.0.3)
19
+ activesupport (4.0.8)
20
+ i18n (~> 0.6, >= 0.6.9)
21
+ minitest (~> 4.2)
22
+ multi_json (~> 1.3)
23
+ thread_safe (~> 0.1)
24
+ tzinfo (~> 0.3.37)
25
+ appraisal (1.0.0)
26
+ bundler
27
+ rake
28
+ thor (>= 0.14.0)
29
+ arel (4.0.2)
30
+ builder (3.1.4)
31
+ celluloid (0.15.2)
32
+ timers (~> 1.1.0)
33
+ coderay (1.1.0)
34
+ diff-lcs (1.2.5)
35
+ fakeredis (0.5.0)
36
+ redis (~> 3.0)
37
+ ffi (1.9.3)
38
+ formatador (0.2.5)
39
+ guard (2.6.1)
40
+ formatador (>= 0.2.4)
41
+ listen (~> 2.7)
42
+ lumberjack (~> 1.0)
43
+ pry (>= 0.9.12)
44
+ thor (>= 0.18.1)
45
+ guard-rspec (4.3.1)
46
+ guard (~> 2.1)
47
+ rspec (>= 2.14, < 4.0)
48
+ i18n (0.6.11)
49
+ listen (2.7.9)
50
+ celluloid (>= 0.15.2)
51
+ rb-fsevent (>= 0.9.3)
52
+ rb-inotify (>= 0.9)
53
+ lumberjack (1.0.9)
54
+ method_source (0.8.2)
55
+ minitest (4.7.5)
56
+ multi_json (1.10.1)
57
+ pry (0.10.0)
58
+ coderay (~> 1.1.0)
59
+ method_source (~> 0.8.1)
60
+ slop (~> 3.4)
61
+ rake (10.3.2)
62
+ rb-fsevent (0.9.4)
63
+ rb-inotify (0.9.5)
64
+ ffi (>= 0.5.0)
65
+ redis (3.1.0)
66
+ rspec (3.0.0)
67
+ rspec-core (~> 3.0.0)
68
+ rspec-expectations (~> 3.0.0)
69
+ rspec-mocks (~> 3.0.0)
70
+ rspec-core (3.0.3)
71
+ rspec-support (~> 3.0.0)
72
+ rspec-expectations (3.0.3)
73
+ diff-lcs (>= 1.2.0, < 2.0)
74
+ rspec-support (~> 3.0.0)
75
+ rspec-mocks (3.0.3)
76
+ rspec-support (~> 3.0.0)
77
+ rspec-support (3.0.3)
78
+ slop (3.6.0)
79
+ sqlite3 (1.3.9)
80
+ thor (0.19.1)
81
+ thread_safe (0.3.4)
82
+ timers (1.1.0)
83
+ tzinfo (0.3.40)
84
+
85
+ PLATFORMS
86
+ ruby
87
+
88
+ DEPENDENCIES
89
+ activerecord (~> 4.0.8)
90
+ appraisal
91
+ bundler (~> 1.6)
92
+ counter-cache!
93
+ fakeredis
94
+ guard
95
+ guard-rspec
96
+ rake
97
+ rspec (>= 3.0)
98
+ sqlite3
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.1.4"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,97 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ counter-cache (0.0.2)
5
+ activerecord (>= 3.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (4.1.4)
11
+ activesupport (= 4.1.4)
12
+ builder (~> 3.1)
13
+ activerecord (4.1.4)
14
+ activemodel (= 4.1.4)
15
+ activesupport (= 4.1.4)
16
+ arel (~> 5.0.0)
17
+ activesupport (4.1.4)
18
+ i18n (~> 0.6, >= 0.6.9)
19
+ json (~> 1.7, >= 1.7.7)
20
+ minitest (~> 5.1)
21
+ thread_safe (~> 0.1)
22
+ tzinfo (~> 1.1)
23
+ appraisal (1.0.0)
24
+ bundler
25
+ rake
26
+ thor (>= 0.14.0)
27
+ arel (5.0.1.20140414130214)
28
+ builder (3.2.2)
29
+ celluloid (0.15.2)
30
+ timers (~> 1.1.0)
31
+ coderay (1.1.0)
32
+ diff-lcs (1.2.5)
33
+ fakeredis (0.5.0)
34
+ redis (~> 3.0)
35
+ ffi (1.9.3)
36
+ formatador (0.2.5)
37
+ guard (2.6.1)
38
+ formatador (>= 0.2.4)
39
+ listen (~> 2.7)
40
+ lumberjack (~> 1.0)
41
+ pry (>= 0.9.12)
42
+ thor (>= 0.18.1)
43
+ guard-rspec (4.3.1)
44
+ guard (~> 2.1)
45
+ rspec (>= 2.14, < 4.0)
46
+ i18n (0.6.11)
47
+ json (1.8.1)
48
+ listen (2.7.9)
49
+ celluloid (>= 0.15.2)
50
+ rb-fsevent (>= 0.9.3)
51
+ rb-inotify (>= 0.9)
52
+ lumberjack (1.0.9)
53
+ method_source (0.8.2)
54
+ minitest (5.4.0)
55
+ pry (0.10.0)
56
+ coderay (~> 1.1.0)
57
+ method_source (~> 0.8.1)
58
+ slop (~> 3.4)
59
+ rake (10.3.2)
60
+ rb-fsevent (0.9.4)
61
+ rb-inotify (0.9.5)
62
+ ffi (>= 0.5.0)
63
+ redis (3.1.0)
64
+ rspec (3.0.0)
65
+ rspec-core (~> 3.0.0)
66
+ rspec-expectations (~> 3.0.0)
67
+ rspec-mocks (~> 3.0.0)
68
+ rspec-core (3.0.3)
69
+ rspec-support (~> 3.0.0)
70
+ rspec-expectations (3.0.3)
71
+ diff-lcs (>= 1.2.0, < 2.0)
72
+ rspec-support (~> 3.0.0)
73
+ rspec-mocks (3.0.3)
74
+ rspec-support (~> 3.0.0)
75
+ rspec-support (3.0.3)
76
+ slop (3.6.0)
77
+ sqlite3 (1.3.9)
78
+ thor (0.19.1)
79
+ thread_safe (0.3.4)
80
+ timers (1.1.0)
81
+ tzinfo (1.2.1)
82
+ thread_safe (~> 0.1)
83
+
84
+ PLATFORMS
85
+ ruby
86
+
87
+ DEPENDENCIES
88
+ activerecord (~> 4.1.4)
89
+ appraisal
90
+ bundler (~> 1.6)
91
+ counter-cache!
92
+ fakeredis
93
+ guard
94
+ guard-rspec
95
+ rake
96
+ rspec (>= 3.0)
97
+ sqlite3
@@ -20,7 +20,7 @@ module Counter
20
20
  end
21
21
 
22
22
  def reflection_type
23
- source_object.reflections[options.relation.to_sym].class_name.to_s.camelize # let AR give us the correct class name :)
23
+ source_object.class.reflections[options.relation.to_sym].class_name.to_s.camelize # let AR give us the correct class name :)
24
24
  end
25
25
  end
26
26
  end
@@ -1,5 +1,5 @@
1
1
  module Counter
2
2
  module Cache
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
@@ -6,7 +6,7 @@ require 'fakeredis'
6
6
  RSpec.describe "Counting" do
7
7
 
8
8
  before do
9
- ActiveRecord::Base.silence { CreateModelsForTest.migrate(:up) }
9
+ CreateModelsForTest.migrate(:up)
10
10
  Counter::Cache.configure do |c|
11
11
  c.redis_pool = Redis.new
12
12
  c.default_worker_adapter = TestWorkerAdapter.new
@@ -14,7 +14,7 @@ RSpec.describe "Counting" do
14
14
  end
15
15
 
16
16
  after do
17
- ActiveRecord::Base.silence { CreateModelsForTest.migrate(:down) }
17
+ CreateModelsForTest.migrate(:down)
18
18
  end
19
19
 
20
20
  let(:user) { User.create }
@@ -29,7 +29,7 @@ RSpec.describe Counter::Cache::Counters::BufferCounter::RelationFinder do
29
29
  before do
30
30
  reflection = double
31
31
  expect(reflection).to receive_message_chain("class_name.to_s.camelize") { "Boo" }
32
- expect(source_object).to receive(:reflections).and_return({:boo => reflection})
32
+ expect(source_object.class).to receive(:reflections).and_return({:boo => reflection})
33
33
  end
34
34
 
35
35
  it 'asks active record for the class name' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: counter-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Henry & Matt Camuto
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-17 00:00:00.000000000 Z
11
+ date: 2014-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: appraisal
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -132,12 +146,20 @@ files:
132
146
  - ".gitignore"
133
147
  - ".rspec"
134
148
  - ".travis.yml"
149
+ - Appraisals
135
150
  - Gemfile
136
151
  - Guardfile
137
152
  - LICENSE.txt
138
153
  - README.md
139
154
  - Rakefile
140
155
  - counter-cache.gemspec
156
+ - doc/counter-cache-flow.png
157
+ - gemfiles/activerecord_3.gemfile
158
+ - gemfiles/activerecord_3.gemfile.lock
159
+ - gemfiles/activerecord_4.0.gemfile
160
+ - gemfiles/activerecord_4.0.gemfile.lock
161
+ - gemfiles/activerecord_4.1.gemfile
162
+ - gemfiles/activerecord_4.1.gemfile.lock
141
163
  - lib/counter/cache.rb
142
164
  - lib/counter/cache/active_record_updater.rb
143
165
  - lib/counter/cache/config.rb
@@ -185,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
207
  version: '0'
186
208
  requirements: []
187
209
  rubyforge_project:
188
- rubygems_version: 2.2.2
210
+ rubygems_version: 2.2.0
189
211
  signing_key:
190
212
  specification_version: 4
191
213
  summary: Counting is hard.