bullet 5.6.1 → 5.7.0

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: 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.