bullet 5.6.1 → 5.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 32281988136558818e4c3ae98c4059d88b6baf79
4
- data.tar.gz: eb9281de70a51206eddebfe0eb70fa681b7bff51
3
+ metadata.gz: 7c9650d2dbc870d2ac04be4ca0e19723ef6a85c2
4
+ data.tar.gz: 35839d605fb1e11687836dbcbe12572b1eb07775
5
5
  SHA512:
6
- metadata.gz: 49d6dba2f3881bd6c129ff12b2c241627431602804010a2a09cc11e5a1912c636f75b1f286e863117426faa830a7486b17b29b37fe6aa706f241e18eb3df282e
7
- data.tar.gz: a24b68afef28189f25406b8233d50e1b14a002d71749d4bfa85a0fff40a9d9a927140e133d2f11aaf5878b126da70544a4e335ddedb6db99ce1f1fa3b10569af
6
+ metadata.gz: 5064948ab9db44cc9b4082397990a3d91e93dc6986db2767a528a4a05734b1d1ba9231af337624d79d7e312d13e075afb53217191d017a3c511a0889c436d0a0
7
+ data.tar.gz: 2c12bd045e5e41b4db0761b07562a763d3be089231d5e420fc3d7d8d27a40f184216c9090667883a606e35fcdfd2eda3f276838e60696c642bff0939ab35e85f
data/CHANGELOG.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # Next Release
2
2
 
3
- ## 5.6.1 (08/01/2017)
3
+ ## 5.7.0 (12/03/2017)
4
4
 
5
+ * Support rails 5.2
6
+ * Implement Bullet.delete_whitelist to delete a specific whitelist definition
5
7
  * Fix caller_path in the case of nil
6
8
 
7
9
  ## 5.6.0 (07/16/2017)
data/Gemfile.rails-5.2 ADDED
@@ -0,0 +1,15 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'rails', '~> 5.2.0.beta1'
6
+ gem 'sqlite3'
7
+ gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
+ gem 'activerecord-import'
9
+
10
+ gem "rspec"
11
+
12
+ platforms :rbx do
13
+ gem 'rubysl', '~> 2.0'
14
+ gem 'rubinius-developer_tools'
15
+ end
data/Rakefile CHANGED
@@ -34,7 +34,6 @@ RSpec::Core::RakeTask.new('spec:progress') do |spec|
34
34
  spec.pattern = 'spec/**/*_spec.rb'
35
35
  end
36
36
 
37
-
38
37
  begin
39
38
  require 'rdoc/task'
40
39
 
data/lib/bullet.rb CHANGED
@@ -38,12 +38,12 @@ module Bullet
38
38
  delegate *available_notifiers
39
39
 
40
40
  def raise=(should_raise)
41
- UniformNotifier.raise=(should_raise ? Notification::UnoptimizedQueryError : false)
41
+ UniformNotifier.raise = (should_raise ? Notification::UnoptimizedQueryError : false)
42
42
  end
43
43
 
44
- DETECTORS = [ Bullet::Detector::NPlusOneQuery,
44
+ DETECTORS = [Bullet::Detector::NPlusOneQuery,
45
45
  Bullet::Detector::UnusedEagerLoading,
46
- Bullet::Detector::CounterCache ].freeze
46
+ Bullet::Detector::CounterCache].freeze
47
47
 
48
48
  def enable=(enable)
49
49
  @enable = @n_plus_one_query_enable = @unused_eager_loading_enable = @counter_cache_enable = enable
@@ -87,12 +87,19 @@ module Bullet
87
87
  @whitelist[options[:type]][options[:class_name]] << options[:association].to_sym
88
88
  end
89
89
 
90
+ def delete_whitelist(options)
91
+ reset_whitelist
92
+ @whitelist[options[:type]][options[:class_name]] ||= []
93
+ @whitelist[options[:type]][options[:class_name]].delete(options[:association].to_sym)
94
+ @whitelist[options[:type]].delete_if { |key, val| val.empty? }
95
+ end
96
+
90
97
  def get_whitelist_associations(type, class_name)
91
98
  Array(@whitelist[type][class_name])
92
99
  end
93
100
 
94
101
  def reset_whitelist
95
- @whitelist ||= {:n_plus_one_query => {}, :unused_eager_loading => {}, :counter_cache => {}}
102
+ @whitelist ||= { :n_plus_one_query => {}, :unused_eager_loading => {}, :counter_cache => {} }
96
103
  end
97
104
 
98
105
  def clear_whitelist
@@ -163,7 +170,7 @@ module Bullet
163
170
  for_each_active_notifier_with_notification do |notification|
164
171
  responses << notification.notify_inline
165
172
  end
166
- responses.join( "\n" )
173
+ responses.join("\n")
167
174
  end
168
175
 
169
176
  def perform_out_of_channel_notifications(env = {})
@@ -211,6 +218,7 @@ module Bullet
211
218
  end
212
219
 
213
220
  private
221
+
214
222
  def for_each_active_notifier_with_notification
215
223
  UniformNotifier.active_notifiers.each do |notifier|
216
224
  notification_collector.collection.each do |notification|
@@ -0,0 +1,225 @@
1
+ module Bullet
2
+ module SaveWithBulletSupport
3
+ def save(*args)
4
+ was_new_record = new_record?
5
+ super(*args).tap do |result|
6
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
7
+ end
8
+ end
9
+
10
+ def save!(*args)
11
+ was_new_record = new_record?
12
+ super(*args).tap do |result|
13
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
14
+ end
15
+ end
16
+ end
17
+
18
+ module ActiveRecord
19
+ def self.enable
20
+ require 'active_record'
21
+ ::ActiveRecord::Base.extend(Module.new {
22
+ def find_by_sql(sql, binds = [], preparable: nil, &block)
23
+ result = super
24
+ if Bullet.start?
25
+ if result.is_a? Array
26
+ if result.size > 1
27
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
28
+ Bullet::Detector::CounterCache.add_possible_objects(result)
29
+ elsif result.size == 1
30
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
31
+ Bullet::Detector::CounterCache.add_impossible_object(result.first)
32
+ end
33
+ elsif result.is_a? ::ActiveRecord::Base
34
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
35
+ Bullet::Detector::CounterCache.add_impossible_object(result)
36
+ end
37
+ end
38
+ result
39
+ end
40
+ })
41
+
42
+ ::ActiveRecord::Base.prepend(SaveWithBulletSupport)
43
+
44
+ ::ActiveRecord::Relation.prepend(Module.new {
45
+ # if select a collection of objects, then these objects have possible to cause N+1 query.
46
+ # if select only one object, then the only one object has impossible to cause N+1 query.
47
+ def records
48
+ result = super
49
+ if Bullet.start?
50
+ if result.first.class.name !~ /^HABTM_/
51
+ if result.size > 1
52
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
53
+ Bullet::Detector::CounterCache.add_possible_objects(result)
54
+ elsif result.size == 1
55
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
56
+ Bullet::Detector::CounterCache.add_impossible_object(result.first)
57
+ end
58
+ end
59
+ end
60
+ result
61
+ end
62
+ })
63
+
64
+ ::ActiveRecord::Associations::Preloader.prepend(Module.new {
65
+ def preloaders_for_one(association, records, scope)
66
+ if Bullet.start?
67
+ records.compact!
68
+ if records.first.class.name !~ /^HABTM_/
69
+ records.each do |record|
70
+ Bullet::Detector::Association.add_object_associations(record, association)
71
+ end
72
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
73
+ end
74
+ end
75
+ super
76
+ end
77
+ })
78
+
79
+ ::ActiveRecord::FinderMethods.prepend(Module.new {
80
+ # add includes in scope
81
+ def find_with_associations
82
+ return super { |r| yield r } if block_given?
83
+ records = super
84
+ if Bullet.start?
85
+ associations = (eager_load_values + includes_values).uniq
86
+ records.each do |record|
87
+ Bullet::Detector::Association.add_object_associations(record, associations)
88
+ end
89
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
90
+ end
91
+ records
92
+ end
93
+ })
94
+
95
+ ::ActiveRecord::Associations::JoinDependency.prepend(Module.new {
96
+ def instantiate(result_set, &block)
97
+ @bullet_eager_loadings = {}
98
+ records = super
99
+
100
+ if Bullet.start?
101
+ @bullet_eager_loadings.each do |klazz, eager_loadings_hash|
102
+ objects = eager_loadings_hash.keys
103
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
104
+ end
105
+ end
106
+ records
107
+ end
108
+
109
+ def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
110
+ if Bullet.start?
111
+ unless ar_parent.nil?
112
+ parent.children.each do |node|
113
+ key = aliases.column_alias(node, node.primary_key)
114
+ id = row[key]
115
+ if id.nil?
116
+ associations = node.reflection.name
117
+ Bullet::Detector::Association.add_object_associations(ar_parent, associations)
118
+ Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
119
+ @bullet_eager_loadings[ar_parent.class] ||= {}
120
+ @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
121
+ @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ super
128
+ end
129
+
130
+ # call join associations
131
+ def construct_model(record, node, row, model_cache, id, aliases)
132
+ result = super
133
+
134
+ if Bullet.start?
135
+ associations = node.reflection.name
136
+ Bullet::Detector::Association.add_object_associations(record, associations)
137
+ Bullet::Detector::NPlusOneQuery.call_association(record, associations)
138
+ @bullet_eager_loadings[record.class] ||= {}
139
+ @bullet_eager_loadings[record.class][record] ||= Set.new
140
+ @bullet_eager_loadings[record.class][record] << associations
141
+ end
142
+
143
+ result
144
+ end
145
+ })
146
+
147
+ ::ActiveRecord::Associations::CollectionAssociation.prepend(Module.new {
148
+ def load_target
149
+ records = super
150
+
151
+ if Bullet.start?
152
+ if self.is_a? ::ActiveRecord::Associations::ThroughAssociation
153
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
154
+ association = self.owner.association self.through_reflection.name
155
+ Array(association.target).each do |through_record|
156
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
157
+ end
158
+ end
159
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
160
+ if records.first.class.name !~ /^HABTM_/
161
+ if records.size > 1
162
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
163
+ Bullet::Detector::CounterCache.add_possible_objects(records)
164
+ elsif records.size == 1
165
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
166
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
167
+ end
168
+ end
169
+ end
170
+ records
171
+ end
172
+
173
+ def empty?
174
+ if Bullet.start? && !reflection.has_cached_counter?
175
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
176
+ end
177
+ super
178
+ end
179
+
180
+ def include?(object)
181
+ if Bullet.start?
182
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
183
+ end
184
+ super
185
+ end
186
+ })
187
+
188
+ ::ActiveRecord::Associations::SingularAssociation.prepend(Module.new {
189
+ # call has_one and belongs_to associations
190
+ def target
191
+ result = super()
192
+ if Bullet.start?
193
+ if owner.class.name !~ /^HABTM_/ && !@inversed
194
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
195
+ if Bullet::Detector::NPlusOneQuery.impossible?(owner)
196
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
197
+ else
198
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
199
+ end
200
+ end
201
+ end
202
+ result
203
+ end
204
+ })
205
+
206
+ ::ActiveRecord::Associations::HasManyAssociation.prepend(Module.new {
207
+ def empty?
208
+ result = super
209
+ if Bullet.start? && !reflection.has_cached_counter?
210
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
211
+ end
212
+ result
213
+ end
214
+
215
+ def count_records
216
+ result = reflection.has_cached_counter?
217
+ if Bullet.start? && !result && !self.is_a?(::ActiveRecord::Associations::ThroughAssociation)
218
+ Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
219
+ end
220
+ super
221
+ end
222
+ })
223
+ end
224
+ end
225
+ end
@@ -24,6 +24,8 @@ module Bullet
24
24
  'active_record5'
25
25
  elsif active_record51?
26
26
  'active_record5'
27
+ elsif active_record52?
28
+ 'active_record52'
27
29
  else
28
30
  raise "Bullet does not support active_record #{::ActiveRecord::VERSION} yet"
29
31
  end
@@ -72,6 +74,10 @@ module Bullet
72
74
  active_record5? && ::ActiveRecord::VERSION::MINOR == 1
73
75
  end
74
76
 
77
+ def active_record52?
78
+ active_record5? && ::ActiveRecord::VERSION::MINOR == 2
79
+ end
80
+
75
81
  def mongoid4x?
76
82
  mongoid? && ::Mongoid::VERSION =~ /\A4/
77
83
  end
@@ -37,6 +37,7 @@ module Bullet
37
37
  end
38
38
 
39
39
  private
40
+
40
41
  # object_associations keep the object relationships
41
42
  # that the object has many associations.
42
43
  # e.g. { "Post:1" => [:comments] }
@@ -45,6 +45,7 @@ module Bullet
45
45
  end
46
46
 
47
47
  private
48
+
48
49
  def create_notification(klazz, associations)
49
50
  notify_associations = Array(associations) - Bullet.get_whitelist_associations(:counter_cache, klazz)
50
51
 
@@ -81,6 +81,7 @@ module Bullet
81
81
  end
82
82
 
83
83
  private
84
+
84
85
  def create_notification(callers, klazz, associations)
85
86
  notify_associations = Array(associations) - Bullet.get_whitelist_associations(:n_plus_one_query, klazz)
86
87
 
@@ -40,7 +40,7 @@ module Bullet
40
40
  if key_objects_overlap == k
41
41
  to_add << [k, associations]
42
42
  else
43
- to_merge << [key_objects_overlap, ( eager_loadings[k].dup << associations )]
43
+ to_merge << [key_objects_overlap, (eager_loadings[k].dup << associations)]
44
44
 
45
45
  keys_without_objects = k - key_objects_overlap
46
46
  to_merge << [keys_without_objects, eager_loadings[k]]
@@ -56,6 +56,7 @@ module Bullet
56
56
  end
57
57
 
58
58
  private
59
+
59
60
  def create_notification(callers, klazz, associations)
60
61
  notify_associations = Array(associations) - Bullet.get_whitelist_associations(:unused_eager_loading, klazz)
61
62
 
@@ -21,7 +21,7 @@ module Bullet
21
21
  end
22
22
 
23
23
  def each(&block)
24
- records = query.map{ |doc| ::Mongoid::Factory.from_db(klass, doc) }
24
+ records = query.map { |doc| ::Mongoid::Factory.from_db(klass, doc) }
25
25
  if records.length > 1
26
26
  Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
27
27
  elsif records.size == 1
@@ -21,7 +21,7 @@ module Bullet
21
21
  end
22
22
 
23
23
  def each(&block)
24
- records = view.map{ |doc| ::Mongoid::Factory.from_db(klass, doc) }
24
+ records = view.map { |doc| ::Mongoid::Factory.from_db(klass, doc) }
25
25
  if records.length > 1
26
26
  Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
27
27
  elsif records.size == 1
@@ -21,7 +21,7 @@ module Bullet
21
21
  end
22
22
 
23
23
  def each(&block)
24
- records = view.map{ |doc| ::Mongoid::Factory.from_db(klass, doc) }
24
+ records = view.map { |doc| ::Mongoid::Factory.from_db(klass, doc) }
25
25
  if records.length > 1
26
26
  Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
27
27
  elsif records.size == 1
@@ -6,7 +6,7 @@ module Bullet
6
6
 
7
7
  def initialize(base_class, association_or_associations, path = nil)
8
8
  @base_class = base_class
9
- @associations = association_or_associations.is_a?(Array) ? association_or_associations : [association_or_associations]
9
+ @associations = association_or_associations.is_a?(Array) ? association_or_associations : [association_or_associations]
10
10
  @path = path
11
11
  end
12
12
 
@@ -65,12 +65,13 @@ module Bullet
65
65
  end
66
66
 
67
67
  protected
68
+
68
69
  def klazz_associations_str
69
70
  " #{@base_class} => [#{@associations.map(&:inspect).join(', '.freeze)}]"
70
71
  end
71
72
 
72
73
  def associations_str
73
- ":includes => #{@associations.map{ |a| a.to_s.to_sym unless a.is_a? Hash }.inspect}"
74
+ ":includes => #{@associations.map { |a| a.to_s.to_sym unless a.is_a? Hash }.inspect}"
74
75
  end
75
76
  end
76
77
  end
@@ -22,8 +22,9 @@ module Bullet
22
22
  end
23
23
 
24
24
  protected
25
+
25
26
  def call_stack_messages
26
- (['Call stack'] + @callers).join( "\n " )
27
+ (['Call stack'] + @callers).join("\n ")
27
28
  end
28
29
  end
29
30
  end
@@ -22,8 +22,9 @@ module Bullet
22
22
  end
23
23
 
24
24
  protected
25
+
25
26
  def call_stack_messages
26
- (['Call stack'] + @callers).join( "\n " )
27
+ (['Call stack'] + @callers).join("\n ")
27
28
  end
28
29
  end
29
30
  end
data/lib/bullet/rack.rb CHANGED
@@ -14,7 +14,7 @@ module Bullet
14
14
  response_body = nil
15
15
  if Bullet.notification?
16
16
  if !file?(headers) && !sse?(headers) && !empty?(response) &&
17
- status == 200 && !response_body(response).frozen? && html_request?(headers, response)
17
+ status == 200 && !response_body(response).frozen? && html_request?(headers, response)
18
18
  response_body = response_body(response)
19
19
  append_to_html_body(response_body, footer_note) if Bullet.add_footer
20
20
  append_to_html_body(response_body, Bullet.gather_inline_notifications)
@@ -1,4 +1,4 @@
1
1
 
2
2
  module Bullet
3
- VERSION = '5.6.1'.freeze
3
+ VERSION = '5.7.0'.freeze
4
4
  end
data/perf/benchmark.rb CHANGED
@@ -53,7 +53,7 @@ end
53
53
 
54
54
  users_size = 100
55
55
  posts_size = 1000
56
- comments_size = 10000
56
+ comments_size = 10_000
57
57
  users = []
58
58
  users_size.times do |i|
59
59
  users << User.new(:name => "user#{i}")
@@ -63,20 +63,19 @@ users = User.all
63
63
 
64
64
  posts = []
65
65
  posts_size.times do |i|
66
- posts << Post.new(:title => "Title #{i}", :body => "Body #{i}", :user => users[i%100])
66
+ posts << Post.new(:title => "Title #{i}", :body => "Body #{i}", :user => users[i % 100])
67
67
  end
68
68
  Post.import posts
69
69
  posts = Post.all
70
70
 
71
71
  comments = []
72
72
  comments_size.times do |i|
73
- comments << Comment.new(:body => "Comment #{i}", :post => posts[i%1000], :user => users[i%100])
73
+ comments << Comment.new(:body => "Comment #{i}", :post => posts[i % 1000], :user => users[i % 100])
74
74
  end
75
75
  Comment.import comments
76
76
 
77
77
  puts 'Start benchmarking...'
78
78
 
79
-
80
79
  Bullet.enable = true
81
80
 
82
81
  Benchmark.bm(70) do |bm|
@@ -98,7 +97,6 @@ end
98
97
 
99
98
  puts 'End benchmarking...'
100
99
 
101
-
102
100
  # Run benchmark with bundler
103
101
  #
104
102
  # bundle exec ruby perf/benchmark.rb
@@ -87,7 +87,7 @@ module Bullet
87
87
  end
88
88
 
89
89
  context 'stacktrace_excludes' do
90
- before { Bullet.stacktrace_excludes = [ /def/ ] }
90
+ before { Bullet.stacktrace_excludes = [/def/] }
91
91
  after { Bullet.stacktrace_excludes = nil }
92
92
 
93
93
  it 'should not create notification when stacktrace contains paths that are in the exclude list' do
@@ -114,7 +114,7 @@ module Bullet
114
114
  end
115
115
 
116
116
  context 'stacktrace_includes' do
117
- before { Bullet.stacktrace_includes = [ 'def', /xyz/ ] }
117
+ before { Bullet.stacktrace_includes = ['def', /xyz/] }
118
118
  after { Bullet.stacktrace_includes = nil }
119
119
 
120
120
  it 'should include paths that are in the stacktrace_include list' do
@@ -50,7 +50,6 @@ module Bullet
50
50
  ensure
51
51
  ENV[name] = old_value
52
52
  end
53
-
54
53
  end
55
54
 
56
55
  context '#body_with_caller' do
@@ -6,7 +6,7 @@ module Bullet
6
6
  subject { NPlusOneQuery.new([['caller1', 'caller2']], Post, [:comments, :votes], 'path') }
7
7
 
8
8
  it { expect(subject.body_with_caller).to eq(" Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nCall stack\n caller1\n caller2\n") }
9
- it { expect([subject.body_with_caller, subject.body_with_caller]).to eq([ " Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nCall stack\n caller1\n caller2\n", " Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nCall stack\n caller1\n caller2\n" ]) }
9
+ it { expect([subject.body_with_caller, subject.body_with_caller]).to eq([" Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nCall stack\n caller1\n caller2\n", " Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nCall stack\n caller1\n caller2\n"]) }
10
10
  it { expect(subject.body).to eq(" Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]") }
11
11
  it { expect(subject.title).to eq('USE eager loading in path') }
12
12
  end
@@ -8,13 +8,13 @@ module Bullet
8
8
 
9
9
  context '#html_request?' do
10
10
  it 'should be true if Content-Type is text/html and http body contains html tag' do
11
- headers = {'Content-Type' => 'text/html'}
11
+ headers = { 'Content-Type' => 'text/html' }
12
12
  response = double(:body => '<html><head></head><body></body></html>')
13
13
  expect(middleware).to be_html_request(headers, response)
14
14
  end
15
15
 
16
16
  it 'should be true if Content-Type is text/html and http body contains html tag with attributes' do
17
- headers = {'Content-Type' => 'text/html'}
17
+ headers = { 'Content-Type' => 'text/html' }
18
18
  response = double(:body => "<html attr='hello'><head></head><body></body></html>")
19
19
  expect(middleware).to be_html_request(headers, response)
20
20
  end
@@ -26,13 +26,13 @@ module Bullet
26
26
  end
27
27
 
28
28
  it 'should be false if Content-Type is javascript' do
29
- headers = {'Content-Type' => 'text/javascript'}
29
+ headers = { 'Content-Type' => 'text/javascript' }
30
30
  response = double(:body => '<html><head></head><body></body></html>')
31
31
  expect(middleware).not_to be_html_request(headers, response)
32
32
  end
33
33
 
34
34
  it "should be false if response body doesn't contain html tag" do
35
- headers = {'Content-Type' => 'text/html'}
35
+ headers = { 'Content-Type' => 'text/html' }
36
36
  response = double(:body => '<div>Partial</div>')
37
37
  expect(middleware).not_to be_html_request(headers, response)
38
38
  end
@@ -68,7 +68,7 @@ module Bullet
68
68
  expect(Bullet).to receive(:notification?).and_return(true)
69
69
  expect(Bullet).to receive(:gather_inline_notifications).and_return('<bullet></bullet>')
70
70
  expect(Bullet).to receive(:perform_out_of_channel_notifications)
71
- status, headers, response = middleware.call({'Content-Type' => 'text/html'})
71
+ status, headers, response = middleware.call({ 'Content-Type' => 'text/html' })
72
72
  expect(headers['Content-Length']).to eq('56')
73
73
  expect(response).to eq(['<html><head></head><body><bullet></bullet></body></html>'])
74
74
  end
@@ -79,7 +79,7 @@ module Bullet
79
79
  app.response = response
80
80
  expect(Bullet).to receive(:notification?).and_return(true)
81
81
  expect(Bullet).to receive(:gather_inline_notifications).and_return('<bullet></bullet>')
82
- status, headers, response = middleware.call({'Content-Type' => 'text/html'})
82
+ status, headers, response = middleware.call({ 'Content-Type' => 'text/html' })
83
83
  expect(headers['Content-Length']).to eq('58')
84
84
  end
85
85
  end
data/spec/bullet_spec.rb CHANGED
@@ -4,7 +4,6 @@ describe Bullet, focused: true do
4
4
  subject { Bullet }
5
5
 
6
6
  describe '#enable' do
7
-
8
7
  context 'enable Bullet' do
9
8
  before do
10
9
  # Bullet.enable
@@ -95,6 +94,26 @@ describe Bullet, focused: true do
95
94
  end
96
95
  end
97
96
 
97
+ describe '#delete_whitelist' do
98
+ context "for 'special' class names" do
99
+ it 'is deleted from the whitelist successfully' do
100
+ Bullet.add_whitelist(:type => :n_plus_one_query, :class_name => 'Klass', :association => :department)
101
+ Bullet.delete_whitelist(:type => :n_plus_one_query, :class_name => 'Klass', :association => :department)
102
+ expect(Bullet.whitelist[:n_plus_one_query]).to eq({})
103
+ end
104
+ end
105
+
106
+ context 'when exists multiple definitions' do
107
+ it 'is deleted from the whitelist successfully' do
108
+ Bullet.add_whitelist(:type => :n_plus_one_query, :class_name => 'Klass', :association => :department)
109
+ Bullet.add_whitelist(:type => :n_plus_one_query, :class_name => 'Klass', :association => :team)
110
+ Bullet.delete_whitelist(:type => :n_plus_one_query, :class_name => 'Klass', :association => :team)
111
+ expect(Bullet.get_whitelist_associations(:n_plus_one_query, 'Klass')).to include :department
112
+ expect(Bullet.get_whitelist_associations(:n_plus_one_query, 'Klass')).to_not include :team
113
+ end
114
+ end
115
+ end
116
+
98
117
  describe '#perform_out_of_channel_notifications' do
99
118
  let(:notification) { double }
100
119
 
@@ -122,7 +122,7 @@ if active_record?
122
122
  end
123
123
 
124
124
  it 'should detect preload with category => posts => comments' do
125
- Category.includes({:posts => :comments}).each do |category|
125
+ Category.includes({ :posts => :comments }).each do |category|
126
126
  category.posts.each do |post|
127
127
  post.comments.map(&:name)
128
128
  end
@@ -134,7 +134,7 @@ if active_record?
134
134
  end
135
135
 
136
136
  it 'should detect preload with category => posts => comments with posts.id > 0' do
137
- Category.includes({:posts => :comments}).where('posts.id > 0').references(:posts).each do |category|
137
+ Category.includes({ :posts => :comments }).where('posts.id > 0').references(:posts).each do |category|
138
138
  category.posts.each do |post|
139
139
  post.comments.map(&:name)
140
140
  end
@@ -146,7 +146,7 @@ if active_record?
146
146
  end
147
147
 
148
148
  it 'should detect unused preload with category => posts => comments' do
149
- Category.includes({:posts => :comments}).map(&:name)
149
+ Category.includes({ :posts => :comments }).map(&:name)
150
150
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
151
151
  expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Post, :comments)
152
152
 
@@ -154,7 +154,7 @@ if active_record?
154
154
  end
155
155
 
156
156
  it 'should detect unused preload with post => commnets, no category => posts' do
157
- Category.includes({:posts => :comments}).each do |category|
157
+ Category.includes({ :posts => :comments }).each do |category|
158
158
  category.posts.map(&:name)
159
159
  end
160
160
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
@@ -257,7 +257,7 @@ if active_record?
257
257
 
258
258
  context 'category => posts => writer' do
259
259
  it 'should not detect unused preload associations' do
260
- category = Category.includes({:posts => :writer}).order('id DESC').find_by_name('first')
260
+ category = Category.includes({ :posts => :writer }).order('id DESC').find_by_name('first')
261
261
  category.posts.map do |post|
262
262
  post.name
263
263
  post.writer.name
@@ -409,7 +409,7 @@ if active_record?
409
409
  end
410
410
 
411
411
  it 'should detect unused preload with comment => author' do
412
- Comment.includes([:author, {:post => :writer}]).where(['base_users.id = ?', BaseUser.first]).references(:base_users).each do |comment|
412
+ Comment.includes([:author, { :post => :writer }]).where(['base_users.id = ?', BaseUser.first]).references(:base_users).each do |comment|
413
413
  comment.post.writer.name
414
414
  end
415
415
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
@@ -430,7 +430,7 @@ if active_record?
430
430
 
431
431
  it 'should not raise a stack error from posts to category' do
432
432
  expect {
433
- Comment.includes({:post => :category}).each do |com|
433
+ Comment.includes({ :post => :category }).each do |com|
434
434
  com.post.category
435
435
  end
436
436
  }.not_to raise_error()
data/spec/spec_helper.rb CHANGED
@@ -28,7 +28,7 @@ Bullet.enable = true
28
28
  MODELS = File.join(File.dirname(__FILE__), 'models')
29
29
  $LOAD_PATH.unshift(MODELS)
30
30
  SUPPORT = File.join(File.dirname(__FILE__), 'support')
31
- Dir[ File.join(SUPPORT, '*.rb') ].reject { |filename| filename =~ /_seed.rb$/ }.sort.each { |file| require file }
31
+ Dir[File.join(SUPPORT, '*.rb')].reject { |filename| filename =~ /_seed.rb$/ }.sort.each { |file| require file }
32
32
 
33
33
  RSpec.configure do |config|
34
34
  config.extend Bullet::Dependency
@@ -41,7 +41,7 @@ if active_record?
41
41
  ActiveRecord::Migration.verbose = false
42
42
 
43
43
  # Autoload every active_record model for the test suite that sits in spec/models.
44
- Dir[ File.join(MODELS, '*.rb') ].sort.each do |filename|
44
+ Dir[File.join(MODELS, '*.rb')].sort.each do |filename|
45
45
  name = File.basename(filename, '.rb')
46
46
  autoload name.camelize.to_sym, name
47
47
  end
@@ -71,7 +71,7 @@ end
71
71
 
72
72
  if mongoid?
73
73
  # Autoload every mongoid model for the test suite that sits in spec/models.
74
- Dir[ File.join(MODELS, 'mongoid', '*.rb') ].sort.each { |file| require file }
74
+ Dir[File.join(MODELS, 'mongoid', '*.rb')].sort.each { |file| require file }
75
75
  require File.join(SUPPORT, 'mongo_seed.rb')
76
76
 
77
77
  RSpec.configure do |config|
@@ -39,7 +39,7 @@ module Support
39
39
  sessions: {
40
40
  default: {
41
41
  database: 'bullet',
42
- hosts: [ 'localhost:27017' ]
42
+ hosts: ['localhost:27017']
43
43
  }
44
44
  }
45
45
  )
@@ -50,7 +50,7 @@ module Support
50
50
  clients: {
51
51
  default: {
52
52
  database: 'bullet',
53
- hosts: [ 'localhost:27017' ]
53
+ hosts: ['localhost:27017']
54
54
  }
55
55
  }
56
56
  )
@@ -2,7 +2,7 @@ module Support
2
2
  class AppDouble
3
3
  def call env
4
4
  env = @env
5
- [ status, headers, response ]
5
+ [status, headers, response]
6
6
  end
7
7
 
8
8
  def status= status
@@ -14,7 +14,7 @@ module Support
14
14
  end
15
15
 
16
16
  def headers
17
- @headers ||= {'Content-Type' => 'text/html'}
17
+ @headers ||= { 'Content-Type' => 'text/html' }
18
18
  @headers
19
19
  end
20
20
 
@@ -23,6 +23,7 @@ module Support
23
23
  end
24
24
 
25
25
  private
26
+
26
27
  def status
27
28
  @status || 200
28
29
  end
@@ -9,7 +9,6 @@ module Support
9
9
  user1 = BaseUser.create(:name => 'third', :newspaper => newspaper1)
10
10
  user2 = BaseUser.create(:name => 'fourth', :newspaper => newspaper2)
11
11
 
12
-
13
12
  category1 = Category.create(:name => 'first')
14
13
  category2 = Category.create(:name => 'second')
15
14
 
data/test.sh CHANGED
@@ -1,5 +1,7 @@
1
1
  #bundle update rails && bundle exec rspec spec
2
2
  #BUNDLE_GEMFILE=Gemfile.mongoid bundle update mongoid && BUNDLE_GEMFILE=Gemfile.mongoid bundle exec rspec spec
3
+ BUNDLE_GEMFILE=Gemfile.rails-5.2 bundle && BUNDLE_GEMFILE=Gemfile.rails-5.2 bundle exec rspec spec
4
+ BUNDLE_GEMFILE=Gemfile.rails-5.1 bundle && BUNDLE_GEMFILE=Gemfile.rails-5.1 bundle exec rspec spec
3
5
  BUNDLE_GEMFILE=Gemfile.rails-5.0 bundle && BUNDLE_GEMFILE=Gemfile.rails-5.0 bundle exec rspec spec
4
6
  BUNDLE_GEMFILE=Gemfile.rails-4.2 bundle && BUNDLE_GEMFILE=Gemfile.rails-4.2 bundle exec rspec spec
5
7
  BUNDLE_GEMFILE=Gemfile.rails-4.1 bundle && BUNDLE_GEMFILE=Gemfile.rails-4.1 bundle exec rspec spec
data/update.sh CHANGED
@@ -1,3 +1,5 @@
1
+ BUNDLE_GEMFILE=Gemfile.rails-5.2 bundle update
2
+ BUNDLE_GEMFILE=Gemfile.rails-5.1 bundle update
1
3
  BUNDLE_GEMFILE=Gemfile.rails-5.0 bundle update
2
4
  BUNDLE_GEMFILE=Gemfile.rails-4.2 bundle update
3
5
  BUNDLE_GEMFILE=Gemfile.rails-4.1 bundle update
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.6.1
4
+ version: 5.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-01 00:00:00.000000000 Z
11
+ date: 2017-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -59,6 +59,7 @@ files:
59
59
  - Gemfile.rails-4.2
60
60
  - Gemfile.rails-5.0
61
61
  - Gemfile.rails-5.1
62
+ - Gemfile.rails-5.2
62
63
  - Guardfile
63
64
  - Hacking.md
64
65
  - MIT-LICENSE
@@ -70,6 +71,7 @@ files:
70
71
  - lib/bullet/active_record41.rb
71
72
  - lib/bullet/active_record42.rb
72
73
  - lib/bullet/active_record5.rb
74
+ - lib/bullet/active_record52.rb
73
75
  - lib/bullet/dependency.rb
74
76
  - lib/bullet/detector.rb
75
77
  - lib/bullet/detector/association.rb
@@ -178,7 +180,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
178
180
  version: 1.3.6
179
181
  requirements: []
180
182
  rubyforge_project:
181
- rubygems_version: 2.6.12
183
+ rubygems_version: 2.6.13
182
184
  signing_key:
183
185
  specification_version: 4
184
186
  summary: help to kill N+1 queries and unused eager loading.