bullet 5.7.0 → 5.7.1

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -1
  3. data/Gemfile.rails-5.2 +1 -1
  4. data/Guardfile +1 -1
  5. data/README.md +3 -0
  6. data/Rakefile +4 -4
  7. data/bullet.gemspec +2 -3
  8. data/lib/bullet.rb +23 -23
  9. data/lib/bullet/active_record4.rb +3 -1
  10. data/lib/bullet/active_record41.rb +1 -1
  11. data/lib/bullet/active_record42.rb +8 -9
  12. data/lib/bullet/active_record5.rb +27 -28
  13. data/lib/bullet/active_record52.rb +27 -28
  14. data/lib/bullet/detector/association.rb +12 -12
  15. data/lib/bullet/detector/counter_cache.rb +7 -7
  16. data/lib/bullet/detector/n_plus_one_query.rb +6 -6
  17. data/lib/bullet/detector/unused_eager_loading.rb +23 -21
  18. data/lib/bullet/ext/object.rb +4 -4
  19. data/lib/bullet/ext/string.rb +1 -1
  20. data/lib/bullet/notification/base.rb +14 -14
  21. data/lib/bullet/notification/n_plus_one_query.rb +4 -4
  22. data/lib/bullet/notification/unused_eager_loading.rb +4 -4
  23. data/lib/bullet/notification_collector.rb +0 -1
  24. data/lib/bullet/version.rb +1 -2
  25. data/perf/benchmark.rb +7 -7
  26. data/spec/bullet/detector/n_plus_one_query_spec.rb +8 -8
  27. data/spec/bullet/ext/object_spec.rb +1 -1
  28. data/spec/bullet/notification/base_spec.rb +6 -6
  29. data/spec/bullet/notification/counter_cache_spec.rb +1 -1
  30. data/spec/bullet/notification/n_plus_one_query_spec.rb +1 -1
  31. data/spec/bullet/notification/unused_eager_loading_spec.rb +1 -1
  32. data/spec/bullet/rack_spec.rb +9 -10
  33. data/spec/bullet/registry/association_spec.rb +2 -2
  34. data/spec/bullet/registry/base_spec.rb +3 -3
  35. data/spec/bullet_spec.rb +7 -7
  36. data/spec/integration/active_record/association_spec.rb +16 -16
  37. data/spec/integration/counter_cache_spec.rb +2 -2
  38. data/spec/models/mongoid/address.rb +1 -1
  39. data/spec/models/mongoid/category.rb +2 -2
  40. data/spec/models/mongoid/comment.rb +1 -1
  41. data/spec/models/mongoid/company.rb +1 -1
  42. data/spec/models/mongoid/entry.rb +1 -1
  43. data/spec/models/mongoid/post.rb +4 -4
  44. data/spec/spec_helper.rb +1 -1
  45. data/spec/support/mongo_seed.rb +23 -23
  46. data/spec/support/rack_double.rb +7 -16
  47. data/spec/support/sqlite_seed.rb +73 -73
  48. metadata +5 -5
@@ -43,31 +43,31 @@ module Bullet
43
43
  # e.g. { "Post:1" => [:comments] }
44
44
  # the object_associations keep all associations that may be or may no be
45
45
  # unpreload associations or unused preload associations.
46
- def object_associations
47
- Thread.current[:bullet_object_associations]
48
- end
46
+ def object_associations
47
+ Thread.current[:bullet_object_associations]
48
+ end
49
49
 
50
50
  # call_object_associations keep the object relationships
51
51
  # that object.associations is called.
52
52
  # e.g. { "Post:1" => [:comments] }
53
53
  # they are used to detect unused preload associations.
54
- def call_object_associations
55
- Thread.current[:bullet_call_object_associations]
56
- end
54
+ def call_object_associations
55
+ Thread.current[:bullet_call_object_associations]
56
+ end
57
57
 
58
58
  # inversed_objects keeps object relationships
59
59
  # that association is inversed.
60
60
  # e.g. { "Comment:1" => ["post"] }
61
- def inversed_objects
62
- Thread.current[:bullet_inversed_objects]
63
- end
61
+ def inversed_objects
62
+ Thread.current[:bullet_inversed_objects]
63
+ end
64
64
 
65
65
  # eager_loadings keep the object relationships
66
66
  # that the associations are preloaded by find :include.
67
67
  # e.g. { ["Post:1", "Post:2"] => [:comments, :user] }
68
- def eager_loadings
69
- Thread.current[:bullet_eager_loadings]
70
- end
68
+ def eager_loadings
69
+ Thread.current[:bullet_eager_loadings]
70
+ end
71
71
  end
72
72
  end
73
73
  end
@@ -32,7 +32,7 @@ module Bullet
32
32
  impossible_objects.add object.bullet_key
33
33
  end
34
34
 
35
- def conditions_met?(object, associations)
35
+ def conditions_met?(object, _associations)
36
36
  possible_objects.include?(object.bullet_key) && !impossible_objects.include?(object.bullet_key)
37
37
  end
38
38
 
@@ -46,14 +46,14 @@ module Bullet
46
46
 
47
47
  private
48
48
 
49
- def create_notification(klazz, associations)
50
- notify_associations = Array(associations) - Bullet.get_whitelist_associations(:counter_cache, klazz)
49
+ def create_notification(klazz, associations)
50
+ notify_associations = Array(associations) - Bullet.get_whitelist_associations(:counter_cache, klazz)
51
51
 
52
- if notify_associations.present?
53
- notice = Bullet::Notification::CounterCache.new klazz, notify_associations
54
- Bullet.notification_collector.add notice
55
- end
52
+ if notify_associations.present?
53
+ notice = Bullet::Notification::CounterCache.new klazz, notify_associations
54
+ Bullet.notification_collector.add notice
56
55
  end
56
+ end
57
57
  end
58
58
  end
59
59
  end
@@ -82,14 +82,14 @@ module Bullet
82
82
 
83
83
  private
84
84
 
85
- def create_notification(callers, klazz, associations)
86
- notify_associations = Array(associations) - Bullet.get_whitelist_associations(:n_plus_one_query, klazz)
85
+ def create_notification(callers, klazz, associations)
86
+ notify_associations = Array(associations) - Bullet.get_whitelist_associations(:n_plus_one_query, klazz)
87
87
 
88
- if notify_associations.present?
89
- notice = Bullet::Notification::NPlusOneQuery.new(callers, klazz, notify_associations)
90
- Bullet.notification_collector.add(notice)
91
- end
88
+ if notify_associations.present?
89
+ notice = Bullet::Notification::NPlusOneQuery.new(callers, klazz, notify_associations)
90
+ Bullet.notification_collector.add(notice)
92
91
  end
92
+ end
93
93
  end
94
94
  end
95
95
  end
@@ -30,13 +30,15 @@ module Bullet
30
30
  Bullet.debug('Detector::UnusedEagerLoading#add_eager_loadings', "objects: #{objects.map(&:bullet_key).join(', ')}, associations: #{associations}")
31
31
  bullet_keys = objects.map(&:bullet_key)
32
32
 
33
- to_add, to_merge, to_delete = [], [], []
34
- eager_loadings.each do |k, v|
33
+ to_add = []
34
+ to_merge = []
35
+ to_delete = []
36
+ eager_loadings.each do |k, _v|
35
37
  key_objects_overlap = k & bullet_keys
36
38
 
37
39
  next if key_objects_overlap.empty?
38
40
 
39
- bullet_keys = bullet_keys - k
41
+ bullet_keys -= k
40
42
  if key_objects_overlap == k
41
43
  to_add << [k, associations]
42
44
  else
@@ -57,29 +59,29 @@ module Bullet
57
59
 
58
60
  private
59
61
 
60
- def create_notification(callers, klazz, associations)
61
- notify_associations = Array(associations) - Bullet.get_whitelist_associations(:unused_eager_loading, klazz)
62
+ def create_notification(callers, klazz, associations)
63
+ notify_associations = Array(associations) - Bullet.get_whitelist_associations(:unused_eager_loading, klazz)
62
64
 
63
- if notify_associations.present?
64
- notice = Bullet::Notification::UnusedEagerLoading.new(callers, klazz, notify_associations)
65
- Bullet.notification_collector.add(notice)
66
- end
65
+ if notify_associations.present?
66
+ notice = Bullet::Notification::UnusedEagerLoading.new(callers, klazz, notify_associations)
67
+ Bullet.notification_collector.add(notice)
67
68
  end
69
+ end
68
70
 
69
- def call_associations(bullet_key, associations)
70
- all = Set.new
71
- eager_loadings.similarly_associated(bullet_key, associations).each do |related_bullet_key|
72
- coa = call_object_associations[related_bullet_key]
73
- next if coa.nil?
74
- all.merge coa
75
- end
76
- all.to_a
71
+ def call_associations(bullet_key, associations)
72
+ all = Set.new
73
+ eager_loadings.similarly_associated(bullet_key, associations).each do |related_bullet_key|
74
+ coa = call_object_associations[related_bullet_key]
75
+ next if coa.nil?
76
+ all.merge coa
77
77
  end
78
+ all.to_a
79
+ end
78
80
 
79
- def diff_object_associations(bullet_key, associations)
80
- potential_associations = associations - call_associations(bullet_key, associations)
81
- potential_associations.reject { |a| a.is_a?(Hash) }
82
- end
81
+ def diff_object_associations(bullet_key, associations)
82
+ potential_associations = associations - call_associations(bullet_key, associations)
83
+ potential_associations.reject { |a| a.is_a?(Hash) }
84
+ end
83
85
  end
84
86
  end
85
87
  end
@@ -1,15 +1,15 @@
1
1
  class Object
2
2
  def bullet_key
3
- "#{self.class}:#{self.primary_key_value}"
3
+ "#{self.class}:#{primary_key_value}"
4
4
  end
5
5
 
6
6
  def primary_key_value
7
7
  if self.class.respond_to?(:primary_keys) && self.class.primary_keys
8
- self.class.primary_keys.map { |primary_key| self.send primary_key }.join(','.freeze)
8
+ self.class.primary_keys.map { |primary_key| send primary_key }.join(','.freeze)
9
9
  elsif self.class.respond_to?(:primary_key) && self.class.primary_key
10
- self.send self.class.primary_key
10
+ send self.class.primary_key
11
11
  else
12
- self.id
12
+ id
13
13
  end
14
14
  end
15
15
  end
@@ -1,5 +1,5 @@
1
1
  class String
2
2
  def bullet_class_name
3
- self.sub(/:[^:]*?$/, ''.freeze)
3
+ sub(/:[^:]*?$/, ''.freeze)
4
4
  end
5
5
  end
@@ -11,11 +11,11 @@ module Bullet
11
11
  end
12
12
 
13
13
  def title
14
- raise NoMethodError.new('no method title defined')
14
+ raise NoMethodError, 'no method title defined'
15
15
  end
16
16
 
17
17
  def body
18
- raise NoMethodError.new('no method body defined')
18
+ raise NoMethodError, 'no method body defined'
19
19
  end
20
20
 
21
21
  def call_stack_messages
@@ -36,11 +36,11 @@ module Bullet
36
36
  end
37
37
 
38
38
  def notify_inline
39
- self.notifier.inline_notify(notification_data)
39
+ notifier.inline_notify(notification_data)
40
40
  end
41
41
 
42
42
  def notify_out_of_channel
43
- self.notifier.out_of_channel_notify(notification_data)
43
+ notifier.out_of_channel_notify(notification_data)
44
44
  end
45
45
 
46
46
  def short_notice
@@ -49,10 +49,10 @@ module Bullet
49
49
 
50
50
  def notification_data
51
51
  {
52
- :user => whoami,
53
- :url => url,
54
- :title => title,
55
- :body => body_with_caller,
52
+ user: whoami,
53
+ url: url,
54
+ title: title,
55
+ body: body_with_caller
56
56
  }
57
57
  end
58
58
 
@@ -66,13 +66,13 @@ module Bullet
66
66
 
67
67
  protected
68
68
 
69
- def klazz_associations_str
70
- " #{@base_class} => [#{@associations.map(&:inspect).join(', '.freeze)}]"
71
- end
69
+ def klazz_associations_str
70
+ " #{@base_class} => [#{@associations.map(&:inspect).join(', '.freeze)}]"
71
+ end
72
72
 
73
- def associations_str
74
- ":includes => #{@associations.map { |a| a.to_s.to_sym unless a.is_a? Hash }.inspect}"
75
- end
73
+ def associations_str
74
+ ":includes => #{@associations.map { |a| a.to_s.to_sym unless a.is_a? Hash }.inspect}"
75
+ end
76
76
  end
77
77
  end
78
78
  end
@@ -17,15 +17,15 @@ module Bullet
17
17
 
18
18
  def notification_data
19
19
  super.merge(
20
- :backtrace => []
20
+ backtrace: []
21
21
  )
22
22
  end
23
23
 
24
24
  protected
25
25
 
26
- def call_stack_messages
27
- (['Call stack'] + @callers).join("\n ")
28
- end
26
+ def call_stack_messages
27
+ (['Call stack'] + @callers).join("\n ")
28
+ end
29
29
  end
30
30
  end
31
31
  end
@@ -17,15 +17,15 @@ module Bullet
17
17
 
18
18
  def notification_data
19
19
  super.merge(
20
- :backtrace => []
20
+ backtrace: []
21
21
  )
22
22
  end
23
23
 
24
24
  protected
25
25
 
26
- def call_stack_messages
27
- (['Call stack'] + @callers).join("\n ")
28
- end
26
+ def call_stack_messages
27
+ (['Call stack'] + @callers).join("\n ")
28
+ end
29
29
  end
30
30
  end
31
31
  end
@@ -21,4 +21,3 @@ module Bullet
21
21
  end
22
22
  end
23
23
  end
24
-
@@ -1,4 +1,3 @@
1
-
2
1
  module Bullet
3
- VERSION = '5.7.0'.freeze
2
+ VERSION = '5.7.1'.freeze
4
3
  end
@@ -1,4 +1,4 @@
1
- $: << 'lib'
1
+ $LOAD_PATH << 'lib'
2
2
  require 'benchmark'
3
3
  require 'rails'
4
4
  require 'active_record'
@@ -27,13 +27,13 @@ class User < ActiveRecord::Base
27
27
  end
28
28
 
29
29
  # create database bullet_benchmark;
30
- ActiveRecord::Base.establish_connection(:adapter => 'mysql2', :database => 'bullet_benchmark', :server => '/tmp/mysql.socket', :username => 'root')
30
+ ActiveRecord::Base.establish_connection(adapter: 'mysql2', database: 'bullet_benchmark', server: '/tmp/mysql.socket', username: 'root')
31
31
 
32
32
  ActiveRecord::Base.connection.tables.each do |table|
33
33
  ActiveRecord::Base.connection.drop_table(table)
34
34
  end
35
35
 
36
- ActiveRecord::Schema.define(:version => 1) do
36
+ ActiveRecord::Schema.define(version: 1) do
37
37
  create_table :posts do |t|
38
38
  t.column :title, :string
39
39
  t.column :body, :string
@@ -56,21 +56,21 @@ posts_size = 1000
56
56
  comments_size = 10_000
57
57
  users = []
58
58
  users_size.times do |i|
59
- users << User.new(:name => "user#{i}")
59
+ users << User.new(name: "user#{i}")
60
60
  end
61
61
  User.import users
62
62
  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
 
@@ -82,7 +82,7 @@ Benchmark.bm(70) do |bm|
82
82
  bm.report("Querying & Iterating #{posts_size} Posts with #{comments_size} Comments and #{users_size} Users") do
83
83
  10.times do
84
84
  Bullet.start_request
85
- Post.select('SQL_NO_CACHE *').includes(:user, :comments => :user).each do |p|
85
+ Post.select('SQL_NO_CACHE *').includes(:user, comments: :user).each do |p|
86
86
  p.title
87
87
  p.user.name
88
88
  p.comments.each do |c|
@@ -91,9 +91,9 @@ module Bullet
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
94
- in_project = OpenStruct.new(:absolute_path => File.join(Dir.pwd, 'abc', 'abc.rb'))
95
- included_path = OpenStruct.new(:absolute_path => '/ghi/ghi.rb')
96
- excluded_path = OpenStruct.new(:absolute_path => '/def/def.rb')
94
+ in_project = OpenStruct.new(absolute_path: File.join(Dir.pwd, 'abc', 'abc.rb'))
95
+ included_path = OpenStruct.new(absolute_path: '/ghi/ghi.rb')
96
+ excluded_path = OpenStruct.new(absolute_path: '/def/def.rb')
97
97
 
98
98
  expect(NPlusOneQuery).to receive(:caller_locations).and_return([in_project, included_path, excluded_path])
99
99
  expect(NPlusOneQuery).to_not receive(:create_notification)
@@ -104,8 +104,8 @@ module Bullet
104
104
 
105
105
  context '.caller_in_project' do
106
106
  it 'should include only paths that are in the project' do
107
- in_project = OpenStruct.new(:absolute_path => File.join(Dir.pwd, 'abc', 'abc.rb'))
108
- not_in_project = OpenStruct.new(:absolute_path => '/def/def.rb')
107
+ in_project = OpenStruct.new(absolute_path: File.join(Dir.pwd, 'abc', 'abc.rb'))
108
+ not_in_project = OpenStruct.new(absolute_path: '/def/def.rb')
109
109
 
110
110
  expect(NPlusOneQuery).to receive(:caller_locations).and_return([in_project, not_in_project])
111
111
  expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
@@ -118,9 +118,9 @@ module Bullet
118
118
  after { Bullet.stacktrace_includes = nil }
119
119
 
120
120
  it 'should include paths that are in the stacktrace_include list' do
121
- in_project = OpenStruct.new(:absolute_path => File.join(Dir.pwd, 'abc', 'abc.rb'))
122
- included_gems = [OpenStruct.new(:absolute_path => '/def/def.rb'), OpenStruct.new(:absolute_path => 'xyz/xyz.rb')]
123
- excluded_gem = OpenStruct.new(:absolute_path => '/ghi/ghi.rb')
121
+ in_project = OpenStruct.new(absolute_path: File.join(Dir.pwd, 'abc', 'abc.rb'))
122
+ included_gems = [OpenStruct.new(absolute_path: '/def/def.rb'), OpenStruct.new(absolute_path: 'xyz/xyz.rb')]
123
+ excluded_gem = OpenStruct.new(absolute_path: '/ghi/ghi.rb')
124
124
 
125
125
  expect(NPlusOneQuery).to receive(:caller_locations).and_return([in_project, *included_gems, excluded_gem])
126
126
  expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
@@ -30,7 +30,7 @@ describe Object do
30
30
 
31
31
  it 'should return value for multiple primary keys' do
32
32
  post = Post.first
33
- allow(Post).to receive(:primary_keys).and_return([:category_id, :writer_id])
33
+ allow(Post).to receive(:primary_keys).and_return(%i[category_id writer_id])
34
34
  expect(post.primary_key_value).to eq("#{post.category_id},#{post.writer_id}")
35
35
  end
36
36
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  module Bullet
4
4
  module Notification
5
5
  describe Base do
6
- subject { Base.new(Post, [:comments, :votes]) }
6
+ subject { Base.new(Post, %i[comments votes]) }
7
7
 
8
8
  context '#title' do
9
9
  it 'should raise NoMethodError' do
@@ -66,7 +66,7 @@ module Bullet
66
66
  allow(subject).to receive(:url).and_return('url')
67
67
  allow(subject).to receive(:title).and_return('title')
68
68
  allow(subject).to receive(:body_with_caller).and_return('body_with_caller')
69
- expect(subject.notification_data).to eq(:user => 'whoami', :url => 'url', :title => 'title', :body => 'body_with_caller')
69
+ expect(subject.notification_data).to eq(user: 'whoami', url: 'url', title: 'title', body: 'body_with_caller')
70
70
  end
71
71
  end
72
72
 
@@ -74,8 +74,8 @@ module Bullet
74
74
  it 'should send full_notice to notifier' do
75
75
  notifier = double
76
76
  allow(subject).to receive(:notifier).and_return(notifier)
77
- allow(subject).to receive(:notification_data).and_return(:foo => :bar)
78
- expect(notifier).to receive(:inline_notify).with(:foo => :bar)
77
+ allow(subject).to receive(:notification_data).and_return(foo: :bar)
78
+ expect(notifier).to receive(:inline_notify).with(foo: :bar)
79
79
  subject.notify_inline
80
80
  end
81
81
  end
@@ -84,8 +84,8 @@ module Bullet
84
84
  it 'should send full_out_of_channel to notifier' do
85
85
  notifier = double
86
86
  allow(subject).to receive(:notifier).and_return(notifier)
87
- allow(subject).to receive(:notification_data).and_return(:foo => :bar)
88
- expect(notifier).to receive(:out_of_channel_notify).with(:foo => :bar)
87
+ allow(subject).to receive(:notification_data).and_return(foo: :bar)
88
+ expect(notifier).to receive(:out_of_channel_notify).with(foo: :bar)
89
89
  subject.notify_out_of_channel
90
90
  end
91
91
  end