counter_culture 1.8.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +65 -0
  3. data/.travis.yml +27 -9
  4. data/Appraisals +22 -0
  5. data/CHANGELOG.md +169 -0
  6. data/Gemfile +6 -41
  7. data/README.md +142 -21
  8. data/Rakefile +7 -34
  9. data/counter_culture.gemspec +39 -168
  10. data/gemfiles/rails_4.2.gemfile +10 -0
  11. data/gemfiles/rails_5.0.gemfile +10 -0
  12. data/gemfiles/rails_5.1.gemfile +10 -0
  13. data/gemfiles/rails_5.2.gemfile +10 -0
  14. data/gemfiles/rails_6.0.gemfile +10 -0
  15. data/lib/counter_culture.rb +1 -1
  16. data/lib/counter_culture/counter.rb +56 -38
  17. data/lib/counter_culture/extensions.rb +58 -48
  18. data/lib/counter_culture/reconciler.rb +83 -13
  19. data/lib/counter_culture/version.rb +3 -0
  20. data/lib/generators/counter_culture_generator.rb +7 -1
  21. data/lib/generators/templates/counter_culture_migration.rb.erb +6 -12
  22. data/run_tests_locally.sh +20 -0
  23. metadata +100 -131
  24. data/VERSION +0 -1
  25. data/spec/counter_culture_spec.rb +0 -1857
  26. data/spec/models/another_post.rb +0 -13
  27. data/spec/models/another_post_comment.rb +0 -4
  28. data/spec/models/candidate.rb +0 -3
  29. data/spec/models/candidate_profile.rb +0 -3
  30. data/spec/models/categ.rb +0 -13
  31. data/spec/models/category.rb +0 -3
  32. data/spec/models/company.rb +0 -11
  33. data/spec/models/conditional_dependent.rb +0 -7
  34. data/spec/models/conditional_main.rb +0 -3
  35. data/spec/models/conversation.rb +0 -4
  36. data/spec/models/has_string_id.rb +0 -4
  37. data/spec/models/industry.rb +0 -2
  38. data/spec/models/person.rb +0 -4
  39. data/spec/models/poly_employee.rb +0 -3
  40. data/spec/models/poly_image.rb +0 -15
  41. data/spec/models/poly_product.rb +0 -4
  42. data/spec/models/post.rb +0 -10
  43. data/spec/models/post_comment.rb +0 -6
  44. data/spec/models/product.rb +0 -7
  45. data/spec/models/review.rb +0 -33
  46. data/spec/models/simple_dependent.rb +0 -5
  47. data/spec/models/simple_main.rb +0 -3
  48. data/spec/models/simple_review.rb +0 -3
  49. data/spec/models/soft_delete.rb +0 -6
  50. data/spec/models/subcateg.rb +0 -14
  51. data/spec/models/transaction.rb +0 -15
  52. data/spec/models/twitter_review.rb +0 -6
  53. data/spec/models/user.rb +0 -40
  54. data/spec/rails_app/.gitignore +0 -15
  55. data/spec/rails_app/Gemfile +0 -41
  56. data/spec/rails_app/Gemfile.lock +0 -150
  57. data/spec/rails_app/README.rdoc +0 -261
  58. data/spec/rails_app/Rakefile +0 -7
  59. data/spec/rails_app/app/assets/images/rails.png +0 -0
  60. data/spec/rails_app/app/assets/javascripts/application.js +0 -15
  61. data/spec/rails_app/app/assets/stylesheets/application.css +0 -13
  62. data/spec/rails_app/app/controllers/application_controller.rb +0 -3
  63. data/spec/rails_app/app/helpers/application_helper.rb +0 -2
  64. data/spec/rails_app/app/mailers/.gitkeep +0 -0
  65. data/spec/rails_app/app/models/.gitkeep +0 -0
  66. data/spec/rails_app/app/views/layouts/application.html.erb +0 -14
  67. data/spec/rails_app/config.ru +0 -4
  68. data/spec/rails_app/config/application.rb +0 -58
  69. data/spec/rails_app/config/boot.rb +0 -6
  70. data/spec/rails_app/config/database.yml +0 -25
  71. data/spec/rails_app/config/environment.rb +0 -5
  72. data/spec/rails_app/config/environments/development.rb +0 -32
  73. data/spec/rails_app/config/environments/test.rb +0 -31
  74. data/spec/rails_app/config/initializers/backtrace_silencers.rb +0 -7
  75. data/spec/rails_app/config/initializers/inflections.rb +0 -15
  76. data/spec/rails_app/config/initializers/mime_types.rb +0 -5
  77. data/spec/rails_app/config/initializers/paper_trail.rb +0 -1
  78. data/spec/rails_app/config/initializers/secret_token.rb +0 -7
  79. data/spec/rails_app/config/initializers/session_store.rb +0 -8
  80. data/spec/rails_app/config/initializers/wrap_parameters.rb +0 -14
  81. data/spec/rails_app/config/locales/en.yml +0 -5
  82. data/spec/rails_app/config/routes.rb +0 -58
  83. data/spec/rails_app/db/seeds.rb +0 -7
  84. data/spec/rails_app/lib/assets/.gitkeep +0 -0
  85. data/spec/rails_app/lib/tasks/.gitkeep +0 -0
  86. data/spec/rails_app/log/.gitkeep +0 -0
  87. data/spec/rails_app/public/404.html +0 -26
  88. data/spec/rails_app/public/422.html +0 -26
  89. data/spec/rails_app/public/500.html +0 -25
  90. data/spec/rails_app/public/favicon.ico +0 -0
  91. data/spec/rails_app/public/index.html +0 -241
  92. data/spec/rails_app/public/robots.txt +0 -5
  93. data/spec/rails_app/script/rails +0 -6
  94. data/spec/rails_app/test/fixtures/.gitkeep +0 -0
  95. data/spec/rails_app/test/functional/.gitkeep +0 -0
  96. data/spec/rails_app/test/integration/.gitkeep +0 -0
  97. data/spec/rails_app/test/performance/browsing_test.rb +0 -12
  98. data/spec/rails_app/test/test_helper.rb +0 -13
  99. data/spec/rails_app/test/unit/.gitkeep +0 -0
  100. data/spec/rails_app/vendor/assets/javascripts/.gitkeep +0 -0
  101. data/spec/rails_app/vendor/assets/stylesheets/.gitkeep +0 -0
  102. data/spec/rails_app/vendor/plugins/.gitkeep +0 -0
  103. data/spec/schema.rb +0 -227
  104. data/spec/spec_helper.rb +0 -32
  105. data/test_rails_versions.sh +0 -13
@@ -15,14 +15,30 @@ module CounterCulture
15
15
  # called to configure counter caches
16
16
  def counter_culture(relation, options = {})
17
17
  unless @after_commit_counter_cache
18
- include AfterCommitAction unless include?(AfterCommitAction)
19
-
20
18
  # initialize callbacks only once
21
19
  after_create :_update_counts_after_create
22
- after_destroy :_update_counts_after_destroy
23
- after_update :_update_counts_after_update
24
- if respond_to?(:after_restore)
25
- after_restore :_update_counts_after_create
20
+
21
+ before_destroy :_update_counts_after_destroy, unless: :destroyed_for_counter_culture?
22
+
23
+ if respond_to?(:before_real_destroy) &&
24
+ instance_methods.include?(:paranoia_destroyed?)
25
+ before_real_destroy :_update_counts_after_destroy,
26
+ if: -> (model) { !model.paranoia_destroyed? }
27
+ end
28
+
29
+ after_update :_update_counts_after_update, unless: :destroyed_for_counter_culture?
30
+
31
+ if respond_to?(:before_restore)
32
+ before_restore :_update_counts_after_create,
33
+ if: -> (model) { model.deleted? }
34
+ end
35
+
36
+ if defined?(Discard::Model) && include?(Discard::Model)
37
+ before_discard :_update_counts_after_destroy,
38
+ if: ->(model) { !model.discarded? }
39
+
40
+ before_undiscard :_update_counts_after_create,
41
+ if: ->(model) { model.discarded? }
26
42
  end
27
43
 
28
44
  # we keep a list of all counter caches we must maintain
@@ -43,7 +59,8 @@ module CounterCulture
43
59
  #
44
60
  # options:
45
61
  # { :exclude => list of relations to skip when fixing counts,
46
- # :only => only these relations will have their counts fixed }
62
+ # :only => only these relations will have their counts fixed,
63
+ # :column_name => only this column will have its count fixed }
47
64
  # returns: a list of fixed record as an array of hashes of the form:
48
65
  # { :entity => which model the count was fixed on,
49
66
  # :id => the id of the model that had the incorrect count,
@@ -63,7 +80,9 @@ module CounterCulture
63
80
  next if options[:exclude] && options[:exclude].include?(counter.relation)
64
81
  next if options[:only] && !options[:only].include?(counter.relation)
65
82
 
66
- reconciler = CounterCulture::Reconciler.new(counter, options.slice(:skip_unsupported))
83
+ reconciler_options = %i(batch_size column_name finish skip_unsupported start touch verbose where)
84
+
85
+ reconciler = CounterCulture::Reconciler.new(counter, options.slice(*reconciler_options))
67
86
  reconciler.reconcile!
68
87
  reconciler.changes
69
88
  end.compact
@@ -71,61 +90,52 @@ module CounterCulture
71
90
  end
72
91
 
73
92
  private
74
- # need to make sure counter_culture is only activated once
75
- # per commit; otherwise, if we do an update in an after_create,
76
- # we would be triggered twice within the same transaction -- once
77
- # for the create, once for the update
78
- def _wrap_in_counter_culture_active(&block)
79
- if @_counter_culture_active
80
- # don't do anything; we are already active for this transaction
81
- else
82
- @_counter_culture_active = true
83
- block.call
84
- execute_after_commit { @_counter_culture_active = false}
85
- end
86
- end
87
-
88
93
  # called by after_create callback
89
94
  def _update_counts_after_create
90
- _wrap_in_counter_culture_active do
91
- self.class.after_commit_counter_cache.each do |counter|
92
- # increment counter cache
93
- counter.change_counter_cache(self, :increment => true)
94
- end
95
+ self.class.after_commit_counter_cache.each do |counter|
96
+ # increment counter cache
97
+ counter.change_counter_cache(self, :increment => true)
95
98
  end
96
99
  end
97
100
 
98
101
  # called by after_destroy callback
99
102
  def _update_counts_after_destroy
100
- _wrap_in_counter_culture_active do
101
- self.class.after_commit_counter_cache.each do |counter|
102
- # decrement counter cache
103
- counter.change_counter_cache(self, :increment => false)
104
- end
103
+ self.class.after_commit_counter_cache.each do |counter|
104
+ # decrement counter cache
105
+ counter.change_counter_cache(self, :increment => false)
105
106
  end
106
107
  end
107
108
 
108
109
  # called by after_update callback
109
110
  def _update_counts_after_update
110
- _wrap_in_counter_culture_active do
111
- self.class.after_commit_counter_cache.each do |counter|
112
- # figure out whether the applicable counter cache changed (this can happen
113
- # with dynamic column names)
114
- counter_cache_name_was = counter.counter_cache_name_for(counter.previous_model(self))
115
- counter_cache_name = counter.counter_cache_name_for(self)
116
-
117
- if counter.first_level_relation_changed?(self) ||
118
- (counter.delta_column && counter.attribute_changed?(self, counter.delta_column)) ||
119
- counter_cache_name != counter_cache_name_was
120
-
121
- # increment the counter cache of the new value
122
- counter.change_counter_cache(self, :increment => true, :counter_column => counter_cache_name)
123
- # decrement the counter cache of the old value
124
- counter.change_counter_cache(self, :increment => false, :was => true, :counter_column => counter_cache_name_was)
125
- end
111
+ self.class.after_commit_counter_cache.each do |counter|
112
+ # figure out whether the applicable counter cache changed (this can happen
113
+ # with dynamic column names)
114
+ counter_cache_name_was = counter.counter_cache_name_for(counter.previous_model(self))
115
+ counter_cache_name = counter.counter_cache_name_for(self)
116
+
117
+ if counter.first_level_relation_changed?(self) ||
118
+ (counter.delta_column && counter.attribute_changed?(self, counter.delta_column)) ||
119
+ counter_cache_name != counter_cache_name_was
120
+
121
+ # increment the counter cache of the new value
122
+ counter.change_counter_cache(self, :increment => true, :counter_column => counter_cache_name)
123
+ # decrement the counter cache of the old value
124
+ counter.change_counter_cache(self, :increment => false, :was => true, :counter_column => counter_cache_name_was)
126
125
  end
127
126
  end
128
127
  end
129
128
 
129
+ # check if record is soft-deleted
130
+ def destroyed_for_counter_culture?
131
+ if respond_to?(:paranoia_destroyed?)
132
+ paranoia_destroyed?
133
+ elsif defined?(Discard::Model) && self.class.include?(Discard::Model)
134
+ discarded?
135
+ else
136
+ false
137
+ end
138
+ end
139
+
130
140
  end
131
141
  end
@@ -3,6 +3,8 @@ require 'active_support/core_ext/module/attribute_accessors'
3
3
 
4
4
  module CounterCulture
5
5
  class Reconciler
6
+ ACTIVE_RECORD_VERSION = Gem.loaded_specs["activerecord"].version
7
+
6
8
  attr_reader :counter, :options, :changes
7
9
 
8
10
  delegate :model, :relation, :full_primary_key, :relation_reflect, :polymorphic?, :to => :counter
@@ -45,7 +47,7 @@ module CounterCulture
45
47
 
46
48
  def polymorphic_associated_model_classes
47
49
  foreign_type_field = relation_reflect(relation).foreign_type
48
- model.pluck("DISTINCT #{foreign_type_field}").compact.map(&:constantize)
50
+ model.pluck(Arel.sql("DISTINCT #{foreign_type_field}")).compact.map(&:constantize)
49
51
  end
50
52
 
51
53
  def associated_model_class
@@ -65,6 +67,7 @@ module CounterCulture
65
67
  end
66
68
 
67
69
  def perform
70
+ log "Performing reconciling of #{counter.model}##{counter.relation.to_sentence}."
68
71
  # if we're provided a custom set of column names with conditions, use them; just use the
69
72
  # column name otherwise
70
73
  # which class does this relation ultimately point to? that's where we have to start
@@ -73,6 +76,10 @@ module CounterCulture
73
76
 
74
77
  counter_column_names = column_names || {nil => counter_cache_name}
75
78
 
79
+ if options[:column_name]
80
+ counter_column_names = counter_column_names.select{ |_, v| options[:column_name].to_s == v }
81
+ end
82
+
76
83
  # iterate over all the possible counter cache column names
77
84
  counter_column_names.each do |where, column_name|
78
85
  # if the column name is nil, that means those records don't affect
@@ -84,7 +91,12 @@ module CounterCulture
84
91
  relation_class_table_name = quote_table_name(relation_class.table_name)
85
92
 
86
93
  # select join column and count (from above) as well as cache column ('column_name') for later comparison
87
- counts_query = scope.select("#{relation_class_table_name}.#{relation_class.primary_key}, #{relation_class_table_name}.#{relation_reflect(relation).association_primary_key(relation_class)}, #{count_select} AS count, #{relation_class_table_name}.#{column_name}")
94
+ counts_query = scope.select(
95
+ "#{relation_class_table_name}.#{relation_class.primary_key}, " \
96
+ "#{relation_class_table_name}.#{relation_reflect(relation).association_primary_key(relation_class)}, " \
97
+ "#{count_select} AS count, " \
98
+ "MAX(#{relation_class_table_name}.#{column_name}) AS #{column_name}"
99
+ )
88
100
 
89
101
  # we need to join together tables until we get back to the table this class itself lives in
90
102
  join_clauses(where).each do |join|
@@ -95,24 +107,70 @@ module CounterCulture
95
107
  # instances and we try to load all their counts at once
96
108
  batch_size = options.fetch(:batch_size, CounterCulture.config.batch_size)
97
109
 
98
- counts_query.group(full_primary_key(relation_class)).find_in_batches(batch_size: batch_size) do |records|
110
+ counts_query = counts_query.where(options[:where]).group(full_primary_key(relation_class))
111
+
112
+ find_in_batches_args = { batch_size: batch_size }
113
+ find_in_batches_args[:start] = options[:start] if options[:start].present?
114
+ find_in_batches_args[:finish] = options[:finish] if options[:finish].present?
115
+
116
+ counts_query.find_in_batches(**find_in_batches_args).with_index(1) do |records, index|
117
+ log "Processing batch ##{index}."
99
118
  # now iterate over all the models and see whether their counts are right
100
- ActiveRecord::Base.transaction do
101
- records.each do |record|
102
- count = record.read_attribute('count') || 0
103
- next if record.read_attribute(column_name) == count
119
+ update_count_for_batch(column_name, records)
120
+ log "Finished batch ##{index}."
121
+ end
122
+ end
123
+ log_without_newline "\n"
124
+ log "Finished reconciling of #{counter.model}##{counter.relation.to_sentence}."
125
+ end
104
126
 
105
- track_change(record, column_name, count)
127
+ private
106
128
 
107
- # use update_all because it's faster and because a fixed counter-cache shouldn't update the timestamp
108
- relation_class.where(relation_class.primary_key => record.send(relation_class.primary_key)).update_all(column_name => count)
129
+ def update_count_for_batch(column_name, records)
130
+ ActiveRecord::Base.transaction do
131
+ records.each do |record|
132
+ count = record.read_attribute('count') || 0
133
+ next if record.read_attribute(column_name) == count
134
+
135
+ track_change(record, column_name, count)
136
+
137
+ updates = []
138
+ # this updates the actual counter
139
+ updates << "#{column_name} = #{count}"
140
+ # and here we update the timestamp, if so desired
141
+ if options[:touch]
142
+ current_time = record.send(:current_time_from_proper_timezone)
143
+ timestamp_columns = record.send(:timestamp_attributes_for_update_in_model)
144
+ if options[:touch] != true
145
+ # starting in Rails 6 this is frozen
146
+ timestamp_columns = timestamp_columns.dup
147
+ timestamp_columns << options[:touch]
148
+ end
149
+ timestamp_columns.each do |timestamp_column|
150
+ updates << "#{timestamp_column} = '#{current_time.to_formatted_s(:db)}'"
109
151
  end
110
152
  end
153
+
154
+ relation_class.where(relation_class.primary_key => record.send(relation_class.primary_key)).update_all(updates.join(', '))
111
155
  end
112
156
  end
113
157
  end
114
158
 
115
- private
159
+ def log(message)
160
+ return unless log?
161
+
162
+ Rails.logger.info(message)
163
+ end
164
+
165
+ def log_without_newline(message)
166
+ return unless log?
167
+
168
+ Rails.logger << message if Rails.logger.info?
169
+ end
170
+
171
+ def log?
172
+ options[:verbose] && Rails.logger
173
+ end
116
174
 
117
175
  # keep track of what we fixed, e.g. for a notification email
118
176
  def track_change(record, column_name, count)
@@ -202,12 +260,24 @@ module CounterCulture
202
260
  if index == reverse_relation.size - 1
203
261
  # conditions must be applied to the join on which we are counting
204
262
  if where
205
- joins_sql += " AND (#{model.send(:sanitize_sql_for_conditions, where)})"
263
+ if where.respond_to?(:to_sql)
264
+ joins_sql += " AND #{target_table_alias}.#{model.primary_key} IN (#{where.select(model.primary_key).to_sql})"
265
+ else
266
+ joins_sql += " AND (#{model.send(:sanitize_sql_for_conditions, where)})"
267
+ end
206
268
  end
207
269
  # respect the deleted_at column if it exists
208
270
  if model.column_names.include?('deleted_at')
209
271
  joins_sql += " AND #{target_table_alias}.deleted_at IS NULL"
210
272
  end
273
+
274
+ # respect the discard column if it exists
275
+ if defined?(Discard::Model) &&
276
+ model.include?(Discard::Model) &&
277
+ model.column_names.include?(model.discard_column.to_s)
278
+
279
+ joins_sql += " AND #{target_table_alias}.#{model.discard_column} IS NULL"
280
+ end
211
281
  end
212
282
  joins_sql
213
283
  end
@@ -221,7 +291,7 @@ module CounterCulture
221
291
  end
222
292
 
223
293
  def parameterize(string)
224
- if Rails.version < '5.0'
294
+ if ACTIVE_RECORD_VERSION < Gem::Version.new("5.0")
225
295
  string.parameterize('_')
226
296
  else
227
297
  string.parameterize(separator: '_')
@@ -0,0 +1,3 @@
1
+ module CounterCulture
2
+ VERSION = '2.7.0'.freeze
3
+ end
@@ -11,7 +11,7 @@ class CounterCultureGenerator < ActiveRecord::Generators::Base
11
11
  source_root File.expand_path("../templates", __FILE__)
12
12
 
13
13
  def generate_migration
14
- migration_template "counter_culture_migration.rb.erb", "db/migrate/#{migration_file_name}"
14
+ migration_template "counter_culture_migration.rb.erb", "db/migrate/#{migration_file_name}", migration_version: migration_version
15
15
  end
16
16
 
17
17
  def migration_name
@@ -26,4 +26,10 @@ class CounterCultureGenerator < ActiveRecord::Generators::Base
26
26
  migration_name.camelize
27
27
  end
28
28
 
29
+ def migration_version
30
+ if Gem::Version.new(Rails.version) >= Gem::Version.new('5.0.0')
31
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
32
+ end
33
+ end
34
+
29
35
  end
@@ -1,15 +1,9 @@
1
- class <%= migration_class_name %> < ActiveRecord::Migration
1
+ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version %>
2
+ def self.up<% counter_cache_columns.each do |column| %>
3
+ add_column :<%= table_name %>, :<%= column %>, :integer, null: false, default: 0
4
+ <% end %> end
2
5
 
3
- def self.up
4
- <% counter_cache_columns.each do |column| %>
5
- add_column :<%= table_name %>, :<%= column %>, :integer, :null => false, :default => 0
6
- <% end %>
7
- end
8
-
9
- def self.down
10
- <% counter_cache_columns.each do |column| %>
6
+ def self.down<% counter_cache_columns.each do |column| %>
11
7
  remove_column :<%= table_name %>, :<%= column %>
12
- <% end %>
13
- end
14
-
8
+ <% end %> end
15
9
  end
@@ -0,0 +1,20 @@
1
+ #! /bin/bash
2
+
3
+ set -e
4
+ source /usr/local/share/chruby/chruby.sh
5
+
6
+ for RUBY_VERSION in 2.5.7 2.6.5 2.7.0; do
7
+ chruby $RUBY_VERSION
8
+ ruby --version
9
+
10
+ gem install bundler -v '1.17.3'
11
+
12
+ (bundle _1.17.3_ check > /dev/null || bundle _1.17.3_ install)
13
+ gem install appraisal
14
+ bundle exec appraisal install
15
+
16
+ for DB in mysql2 postgresql sqlite3; do
17
+ echo "RUBY $RUBY_VERSION; DB $DB"
18
+ DB=$DB bundle exec appraisal rspec spec/counter_culture_spec.rb
19
+ done
20
+ done
metadata CHANGED
@@ -1,59 +1,59 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: counter_culture
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Magnus von Koeller
8
- autorequire:
9
- bindir: bin
8
+ autorequire:
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2017-08-30 00:00:00.000000000 Z
11
+ date: 2020-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: after_commit_action
14
+ name: activerecord
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '4.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '4.2'
27
27
  - !ruby/object:Gem::Dependency
28
- name: activerecord
28
+ name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 3.0.0
33
+ version: '4.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 3.0.0
40
+ version: '4.2'
41
41
  - !ruby/object:Gem::Dependency
42
- name: activesupport
42
+ name: appraisal
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - ">"
46
46
  - !ruby/object:Gem::Version
47
- version: 3.0.0
48
- type: :runtime
47
+ version: 2.0.0
48
+ type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - ">"
53
53
  - !ruby/object:Gem::Version
54
- version: 3.0.0
54
+ version: 2.0.0
55
55
  - !ruby/object:Gem::Dependency
56
- name: rake
56
+ name: awesome_print
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,35 +67,35 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rails
70
+ name: bundler
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 3.1.0
75
+ version: '1.17'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 3.1.0
82
+ version: '1.17'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rspec
84
+ name: database_cleaner
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '3.0'
89
+ version: 1.1.1
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '3.0'
96
+ version: 1.1.1
97
97
  - !ruby/object:Gem::Dependency
98
- name: awesome_print
98
+ name: discard
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: timecop
112
+ name: paper_trail
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
@@ -137,66 +137,109 @@ dependencies:
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: paper_trail
140
+ name: rails
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - ">="
144
144
  - !ruby/object:Gem::Version
145
- version: '0'
145
+ version: '4.2'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
- version: '0'
152
+ version: '4.2'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rake
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '10.0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '10.0'
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: rdoc
155
169
  requirement: !ruby/object:Gem::Requirement
156
170
  requirements:
157
171
  - - "~>"
158
172
  - !ruby/object:Gem::Version
159
- version: '3.12'
173
+ version: 5.0.0
160
174
  type: :development
161
175
  prerelease: false
162
176
  version_requirements: !ruby/object:Gem::Requirement
163
177
  requirements:
164
178
  - - "~>"
165
179
  - !ruby/object:Gem::Version
166
- version: '3.12'
180
+ version: 5.0.0
167
181
  - !ruby/object:Gem::Dependency
168
- name: bundler
182
+ name: rspec
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '3.0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '3.0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: rspec-extra-formatters
169
197
  requirement: !ruby/object:Gem::Requirement
170
198
  requirements:
171
199
  - - ">="
172
200
  - !ruby/object:Gem::Version
173
- version: 1.2.0
201
+ version: '0'
174
202
  type: :development
175
203
  prerelease: false
176
204
  version_requirements: !ruby/object:Gem::Requirement
177
205
  requirements:
178
206
  - - ">="
179
207
  - !ruby/object:Gem::Version
180
- version: 1.2.0
208
+ version: '0'
181
209
  - !ruby/object:Gem::Dependency
182
- name: jeweler
210
+ name: simplecov
183
211
  requirement: !ruby/object:Gem::Requirement
184
212
  requirements:
185
213
  - - "~>"
186
214
  - !ruby/object:Gem::Version
187
- version: '2.1'
215
+ version: 0.16.1
188
216
  type: :development
189
217
  prerelease: false
190
218
  version_requirements: !ruby/object:Gem::Requirement
191
219
  requirements:
192
220
  - - "~>"
193
221
  - !ruby/object:Gem::Version
194
- version: '2.1'
222
+ version: 0.16.1
223
+ - !ruby/object:Gem::Dependency
224
+ name: timecop
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
195
237
  description: counter_culture provides turbo-charged counter caches that are kept up-to-date
196
238
  not just on create and destroy, that support multiple levels of indirection through
197
239
  relationships, allow dynamic column names and that avoid deadlocks by updating in
198
240
  the after_commit callback.
199
- email: magnus@vonkoeller.de
241
+ email:
242
+ - magnus@vonkoeller.de
200
243
  executables: []
201
244
  extensions: []
202
245
  extra_rdoc_files:
@@ -204,108 +247,35 @@ extra_rdoc_files:
204
247
  - README.md
205
248
  files:
206
249
  - ".document"
250
+ - ".gitignore"
207
251
  - ".rspec"
208
252
  - ".travis.yml"
253
+ - Appraisals
209
254
  - CHANGELOG.md
210
255
  - Gemfile
211
256
  - LICENSE.txt
212
257
  - README.md
213
258
  - Rakefile
214
- - VERSION
215
259
  - circle.yml
216
260
  - counter_culture.gemspec
261
+ - gemfiles/rails_4.2.gemfile
262
+ - gemfiles/rails_5.0.gemfile
263
+ - gemfiles/rails_5.1.gemfile
264
+ - gemfiles/rails_5.2.gemfile
265
+ - gemfiles/rails_6.0.gemfile
217
266
  - lib/counter_culture.rb
218
267
  - lib/counter_culture/counter.rb
219
268
  - lib/counter_culture/extensions.rb
220
269
  - lib/counter_culture/reconciler.rb
270
+ - lib/counter_culture/version.rb
221
271
  - lib/generators/counter_culture_generator.rb
222
272
  - lib/generators/templates/counter_culture_migration.rb.erb
223
- - spec/counter_culture_spec.rb
224
- - spec/models/another_post.rb
225
- - spec/models/another_post_comment.rb
226
- - spec/models/candidate.rb
227
- - spec/models/candidate_profile.rb
228
- - spec/models/categ.rb
229
- - spec/models/category.rb
230
- - spec/models/company.rb
231
- - spec/models/conditional_dependent.rb
232
- - spec/models/conditional_main.rb
233
- - spec/models/conversation.rb
234
- - spec/models/has_string_id.rb
235
- - spec/models/industry.rb
236
- - spec/models/person.rb
237
- - spec/models/poly_employee.rb
238
- - spec/models/poly_image.rb
239
- - spec/models/poly_product.rb
240
- - spec/models/post.rb
241
- - spec/models/post_comment.rb
242
- - spec/models/product.rb
243
- - spec/models/review.rb
244
- - spec/models/simple_dependent.rb
245
- - spec/models/simple_main.rb
246
- - spec/models/simple_review.rb
247
- - spec/models/soft_delete.rb
248
- - spec/models/subcateg.rb
249
- - spec/models/transaction.rb
250
- - spec/models/twitter_review.rb
251
- - spec/models/user.rb
252
- - spec/rails_app/.gitignore
253
- - spec/rails_app/Gemfile
254
- - spec/rails_app/Gemfile.lock
255
- - spec/rails_app/README.rdoc
256
- - spec/rails_app/Rakefile
257
- - spec/rails_app/app/assets/images/rails.png
258
- - spec/rails_app/app/assets/javascripts/application.js
259
- - spec/rails_app/app/assets/stylesheets/application.css
260
- - spec/rails_app/app/controllers/application_controller.rb
261
- - spec/rails_app/app/helpers/application_helper.rb
262
- - spec/rails_app/app/mailers/.gitkeep
263
- - spec/rails_app/app/models/.gitkeep
264
- - spec/rails_app/app/views/layouts/application.html.erb
265
- - spec/rails_app/config.ru
266
- - spec/rails_app/config/application.rb
267
- - spec/rails_app/config/boot.rb
268
- - spec/rails_app/config/database.yml
269
- - spec/rails_app/config/environment.rb
270
- - spec/rails_app/config/environments/development.rb
271
- - spec/rails_app/config/environments/test.rb
272
- - spec/rails_app/config/initializers/backtrace_silencers.rb
273
- - spec/rails_app/config/initializers/inflections.rb
274
- - spec/rails_app/config/initializers/mime_types.rb
275
- - spec/rails_app/config/initializers/paper_trail.rb
276
- - spec/rails_app/config/initializers/secret_token.rb
277
- - spec/rails_app/config/initializers/session_store.rb
278
- - spec/rails_app/config/initializers/wrap_parameters.rb
279
- - spec/rails_app/config/locales/en.yml
280
- - spec/rails_app/config/routes.rb
281
- - spec/rails_app/db/seeds.rb
282
- - spec/rails_app/lib/assets/.gitkeep
283
- - spec/rails_app/lib/tasks/.gitkeep
284
- - spec/rails_app/log/.gitkeep
285
- - spec/rails_app/public/404.html
286
- - spec/rails_app/public/422.html
287
- - spec/rails_app/public/500.html
288
- - spec/rails_app/public/favicon.ico
289
- - spec/rails_app/public/index.html
290
- - spec/rails_app/public/robots.txt
291
- - spec/rails_app/script/rails
292
- - spec/rails_app/test/fixtures/.gitkeep
293
- - spec/rails_app/test/functional/.gitkeep
294
- - spec/rails_app/test/integration/.gitkeep
295
- - spec/rails_app/test/performance/browsing_test.rb
296
- - spec/rails_app/test/test_helper.rb
297
- - spec/rails_app/test/unit/.gitkeep
298
- - spec/rails_app/vendor/assets/javascripts/.gitkeep
299
- - spec/rails_app/vendor/assets/stylesheets/.gitkeep
300
- - spec/rails_app/vendor/plugins/.gitkeep
301
- - spec/schema.rb
302
- - spec/spec_helper.rb
303
- - test_rails_versions.sh
304
- homepage: http://github.com/magnusvk/counter_culture
273
+ - run_tests_locally.sh
274
+ homepage: https://github.com/magnusvk/counter_culture
305
275
  licenses:
306
276
  - MIT
307
277
  metadata: {}
308
- post_install_message:
278
+ post_install_message:
309
279
  rdoc_options: []
310
280
  require_paths:
311
281
  - lib
@@ -313,16 +283,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
313
283
  requirements:
314
284
  - - ">="
315
285
  - !ruby/object:Gem::Version
316
- version: '0'
286
+ version: 2.3.0
317
287
  required_rubygems_version: !ruby/object:Gem::Requirement
318
288
  requirements:
319
289
  - - ">="
320
290
  - !ruby/object:Gem::Version
321
291
  version: '0'
322
292
  requirements: []
323
- rubyforge_project:
324
- rubygems_version: 2.5.1
325
- signing_key:
293
+ rubygems_version: 3.1.4
294
+ signing_key:
326
295
  specification_version: 4
327
296
  summary: Turbo-charged counter caches for your Rails app.
328
297
  test_files: []