bullet 4.5.0 → 4.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +7 -5
- data/bullet.gemspec +2 -2
- data/lib/bullet.rb +5 -15
- data/lib/bullet/active_record3.rb +8 -0
- data/lib/bullet/active_record3x.rb +10 -0
- data/lib/bullet/active_record4.rb +10 -0
- data/lib/bullet/dependency.rb +8 -21
- data/lib/bullet/detector/n_plus_one_query.rb +5 -3
- data/lib/bullet/rack.rb +17 -7
- data/lib/bullet/version.rb +1 -1
- data/spec/integration/association_spec.rb +13 -0
- data/spec/models/comment.rb +1 -1
- data/spec/models/post.rb +5 -12
- data/spec/spec_helper.rb +1 -7
- data/test.sh +0 -1
- metadata +5 -13
- data/Gemfile.rails-2.3.17 +0 -14
- data/README_for_rails2.textile +0 -400
- data/lib/bullet/action_controller2.rb +0 -50
- data/lib/bullet/active_record2.rb +0 -121
- data/spec/integration/rails2/association_spec.rb +0 -593
- data/spec/integration/rails2/counter_cache_spec.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe2535f7177504dcbcc4363536c000861f12baa3
|
4
|
+
data.tar.gz: ac0fb20bc77d0cdcdb8326f64ac2b886c7b2d86b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f289dfa1fdd7c8ebf49f85c1799eb6803fc94885a0d4c3c9677e8017b0cb61f32830e4e483db17713a2e9fe69b902ffa93c645ceb9986a89311d18a43312bc77
|
7
|
+
data.tar.gz: 741e58068a37666795caa4283a58bfb33b19e1d3af17fa8e67312f292b311886fd7ab82118666cac050b39e9d6bab313ffde78c6cf6fcc1a95f9daa04b08132a
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
# Bullet
|
2
2
|
|
3
|
-
!https://secure.travis-ci.org/flyerhzm/bullet.png
|
3
|
+
[![Build Status](https://secure.travis-ci.org/flyerhzm/bullet.png)](http://travis-ci.org/flyerhzm/bullet)
|
4
4
|
|
5
|
-
!http://api.coderwall.com/flyerhzm/endorsecount.png
|
5
|
+
[![Coderwall Endorse](http://api.coderwall.com/flyerhzm/endorsecount.png)](http://coderwall.com/flyerhzm)
|
6
6
|
|
7
7
|
The Bullet gem is designed to help you increase your application's performance by reducing the number of queries it makes. It will watch your queries while you develop your application and notify you when you should add eager loading (N+1 queries), when you're using eager loading that isn't necessary and when you should use counter cache.
|
8
8
|
|
9
9
|
Best practice is to use Bullet in development mode or custom mode (staging, profile, etc.). The last thing you want is your clients getting alerts about how lazy you are.
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
Bullet gem now supports **activerecord** 3.0, 3.1, 3.2, 4.0 and **mongoid** >= 2.4.1.
|
12
|
+
|
13
|
+
If you use activercord 2.x, please use bullet <= 4.5.0
|
13
14
|
|
14
15
|
## External Introduction
|
15
16
|
|
@@ -42,7 +43,8 @@ Bullet won't do ANYTHING unless you tell it to explicitly. Append to
|
|
42
43
|
```ruby
|
43
44
|
config.after_initialize do
|
44
45
|
Bullet.enable = true
|
45
|
-
Bullet.alert = true
|
46
|
+
Bullet.alert = true
|
47
|
+
Bullet.bullet_logger = true
|
46
48
|
Bullet.console = true
|
47
49
|
Bullet.growl = true
|
48
50
|
Bullet.xmpp = { :account => 'bullets_account@jabber.org',
|
data/bullet.gemspec
CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.authors = ["Richard Huang"]
|
11
11
|
s.email = ["flyerhzm@gmail.com"]
|
12
12
|
s.homepage = "http://github.com/flyerhzm/bullet"
|
13
|
-
s.summary = "
|
14
|
-
s.description = "
|
13
|
+
s.summary = "help to kill N+1 queries and unused eager loading."
|
14
|
+
s.description = "help to kill N+1 queries and unused eager loading."
|
15
15
|
|
16
16
|
s.required_rubygems_version = ">= 1.3.6"
|
17
17
|
|
data/lib/bullet.rb
CHANGED
@@ -7,13 +7,8 @@ require 'bullet/dependency'
|
|
7
7
|
module Bullet
|
8
8
|
extend Dependency
|
9
9
|
|
10
|
-
if active_record?
|
11
|
-
|
12
|
-
autoload :ActionController, 'bullet/action_controller2' if active_record2?
|
13
|
-
end
|
14
|
-
if mongoid?
|
15
|
-
autoload :Mongoid, "bullet/#{mongoid_version}"
|
16
|
-
end
|
10
|
+
autoload :ActiveRecord, "bullet/#{active_record_version}" if active_record?
|
11
|
+
autoload :Mongoid, "bullet/#{mongoid_version}" if mongoid?
|
17
12
|
autoload :Rack, 'bullet/rack'
|
18
13
|
autoload :BulletLogger, 'bullet/logger'
|
19
14
|
autoload :Notification, 'bullet/notification'
|
@@ -43,13 +38,8 @@ module Bullet
|
|
43
38
|
@enable = @n_plus_one_query_enable = @unused_eager_loading_enable = @counter_cache_enable = enable
|
44
39
|
if enable?
|
45
40
|
reset_whitelist
|
46
|
-
if mongoid?
|
47
|
-
|
48
|
-
end
|
49
|
-
if active_record?
|
50
|
-
Bullet::ActiveRecord.enable
|
51
|
-
Bullet::ActionController.enable if active_record2?
|
52
|
-
end
|
41
|
+
Bullet::Mongoid.enable if mongoid?
|
42
|
+
Bullet::ActiveRecord.enable if active_record?
|
53
43
|
end
|
54
44
|
end
|
55
45
|
|
@@ -84,7 +74,7 @@ module Bullet
|
|
84
74
|
|
85
75
|
def bullet_logger=(active)
|
86
76
|
if active
|
87
|
-
bullet_log_file = File.open("#{
|
77
|
+
bullet_log_file = File.open("#{rails? ? Rails.root.to_s : Dir.pwd}/log/bullet.log", 'a+')
|
88
78
|
bullet_log_file.sync = true
|
89
79
|
UniformNotifier.customized_logger = bullet_log_file
|
90
80
|
end
|
@@ -91,6 +91,14 @@ module Bullet
|
|
91
91
|
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
92
92
|
result
|
93
93
|
end
|
94
|
+
|
95
|
+
alias_method :origin_set_inverse_instance, :set_inverse_instance
|
96
|
+
def set_inverse_instance(record, instance)
|
97
|
+
if record && we_can_set_the_inverse_on_this?(record)
|
98
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
|
99
|
+
end
|
100
|
+
origin_set_inverse_instance(record, instance)
|
101
|
+
end
|
94
102
|
end
|
95
103
|
|
96
104
|
::ActiveRecord::Associations::HasManyAssociation.class_eval do
|
@@ -80,6 +80,16 @@ module Bullet
|
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
|
+
::ActiveRecord::Associations::Association.class_eval do
|
84
|
+
alias_method :origin_set_inverse_instance, :set_inverse_instance
|
85
|
+
def set_inverse_instance(record)
|
86
|
+
if record && invertible_for?(record)
|
87
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
|
88
|
+
end
|
89
|
+
origin_set_inverse_instance(record)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
83
93
|
::ActiveRecord::Associations::HasManyAssociation.class_eval do
|
84
94
|
alias_method :origin_has_cached_counter?, :has_cached_counter?
|
85
95
|
|
@@ -80,6 +80,16 @@ module Bullet
|
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
|
+
::ActiveRecord::Associations::Association.class_eval do
|
84
|
+
alias_method :origin_set_inverse_instance, :set_inverse_instance
|
85
|
+
def set_inverse_instance(record)
|
86
|
+
if record && invertible_for?(record)
|
87
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
|
88
|
+
end
|
89
|
+
origin_set_inverse_instance(record)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
83
93
|
::ActiveRecord::Associations::HasManyAssociation.class_eval do
|
84
94
|
alias_method :origin_has_cached_counter?, :has_cached_counter?
|
85
95
|
|
data/lib/bullet/dependency.rb
CHANGED
@@ -20,9 +20,7 @@ module Bullet
|
|
20
20
|
|
21
21
|
def active_record_version
|
22
22
|
@active_record_version ||= begin
|
23
|
-
if
|
24
|
-
'active_record2'
|
25
|
-
elsif active_record30?
|
23
|
+
if active_record30?
|
26
24
|
'active_record3'
|
27
25
|
elsif active_record31? || active_record32?
|
28
26
|
'active_record3x'
|
@@ -42,22 +40,6 @@ module Bullet
|
|
42
40
|
end
|
43
41
|
end
|
44
42
|
|
45
|
-
def active_record2?
|
46
|
-
::ActiveRecord::VERSION::MAJOR == 2
|
47
|
-
end
|
48
|
-
|
49
|
-
def active_record23?
|
50
|
-
active_record2? && ::ActiveRecord::VERSION::MINOR == 3
|
51
|
-
end
|
52
|
-
|
53
|
-
def active_record22?
|
54
|
-
active_record2? && ::ActiveRecord::VERSION::MINOR == 2
|
55
|
-
end
|
56
|
-
|
57
|
-
def active_record21?
|
58
|
-
active_record2? && ::ActiveRecord::VERSION::MINOR == 1
|
59
|
-
end
|
60
|
-
|
61
43
|
def active_record3?
|
62
44
|
::ActiveRecord::VERSION::MAJOR == 3
|
63
45
|
end
|
@@ -86,8 +68,13 @@ module Bullet
|
|
86
68
|
::Mongoid::VERSION =~ /\A3/
|
87
69
|
end
|
88
70
|
|
89
|
-
def
|
90
|
-
|
71
|
+
def rails?
|
72
|
+
@rails ||= begin
|
73
|
+
require 'rails'
|
74
|
+
true
|
75
|
+
rescue LoadError
|
76
|
+
false
|
77
|
+
end
|
91
78
|
end
|
92
79
|
end
|
93
80
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Bullet
|
2
2
|
module Detector
|
3
3
|
class NPlusOneQuery < Association
|
4
|
+
extend Dependency
|
5
|
+
|
4
6
|
class <<self
|
5
7
|
# executed when object.assocations is called.
|
6
8
|
# first, it keeps this method call for object.association.
|
@@ -46,9 +48,9 @@ module Bullet
|
|
46
48
|
end
|
47
49
|
|
48
50
|
def caller_in_project
|
49
|
-
|
50
|
-
vendor_root =
|
51
|
-
caller.select { |c| c.include?(
|
51
|
+
app_root = rails? ? Rails.root.to_s : Dir.pwd
|
52
|
+
vendor_root = app_root + "/vendor"
|
53
|
+
caller.select { |c| c.include?(app_root) && !c.include?(vendor_root) }
|
52
54
|
end
|
53
55
|
|
54
56
|
def possible?(bullet_ar_key)
|
data/lib/bullet/rack.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Bullet
|
2
2
|
class Rack
|
3
|
+
include Dependency
|
4
|
+
|
3
5
|
def initialize(app)
|
4
6
|
@app = app
|
5
7
|
end
|
@@ -13,8 +15,8 @@ module Bullet
|
|
13
15
|
|
14
16
|
response_body = nil
|
15
17
|
if Bullet.notification?
|
16
|
-
if status == 200 && !response.
|
17
|
-
response_body = response
|
18
|
+
if status == 200 && !response_body(response).frozen? && html_request?(headers, response)
|
19
|
+
response_body = response_body(response) << Bullet.gather_inline_notifications
|
18
20
|
headers['Content-Length'] = response_body.bytesize.to_s
|
19
21
|
end
|
20
22
|
Bullet.perform_out_of_channel_notifications(env)
|
@@ -26,10 +28,14 @@ module Bullet
|
|
26
28
|
# fix issue if response's body is a Proc
|
27
29
|
def empty?(response)
|
28
30
|
# response may be ["Not Found"], ["Move Permanently"], etc.
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
if rails?
|
32
|
+
(response.is_a?(Array) && response.size <= 1) ||
|
33
|
+
!response.respond_to?(:body) ||
|
34
|
+
!response_body(response).respond_to?(:empty?) ||
|
35
|
+
response_body(response).empty?
|
36
|
+
else
|
37
|
+
response_body(response).empty?
|
38
|
+
end
|
33
39
|
end
|
34
40
|
|
35
41
|
# if send file?
|
@@ -38,7 +44,11 @@ module Bullet
|
|
38
44
|
end
|
39
45
|
|
40
46
|
def html_request?(headers, response)
|
41
|
-
headers['Content-Type'] && headers['Content-Type'].include?('text/html') && response.
|
47
|
+
headers['Content-Type'] && headers['Content-Type'].include?('text/html') && response_body(response).include?("<html")
|
48
|
+
end
|
49
|
+
|
50
|
+
def response_body(response)
|
51
|
+
rails? ? response.body : response.first
|
42
52
|
end
|
43
53
|
end
|
44
54
|
end
|
data/lib/bullet/version.rb
CHANGED
@@ -47,6 +47,19 @@ if active_record3? || active_record4?
|
|
47
47
|
|
48
48
|
Bullet::Detector::Association.should be_completely_preloading_associations
|
49
49
|
end
|
50
|
+
|
51
|
+
it "should detect non preload comment => post with inverse_of" do
|
52
|
+
Post.includes(:comments).each do |post|
|
53
|
+
post.comments.each do |comment|
|
54
|
+
comment.name
|
55
|
+
comment.post.name
|
56
|
+
end
|
57
|
+
end
|
58
|
+
Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
|
59
|
+
Bullet::Detector::Association.should_not be_has_unused_preload_associations
|
60
|
+
|
61
|
+
Bullet::Detector::Association.should be_completely_preloading_associations
|
62
|
+
end
|
50
63
|
end
|
51
64
|
|
52
65
|
context "category => posts => comments" do
|
data/spec/models/comment.rb
CHANGED
data/spec/models/post.rb
CHANGED
@@ -3,17 +3,10 @@ class Post < ActiveRecord::Base
|
|
3
3
|
|
4
4
|
belongs_to :category
|
5
5
|
belongs_to :writer
|
6
|
-
has_many :comments
|
6
|
+
has_many :comments, :inverse_of => :post
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
}
|
13
|
-
else
|
14
|
-
scope :preload_comments, lambda { includes(:comments) }
|
15
|
-
scope :in_category_name, lambda { |name|
|
16
|
-
where(['categories.name = ?', name]).includes(:category)
|
17
|
-
}
|
18
|
-
end
|
8
|
+
scope :preload_comments, lambda { includes(:comments) }
|
9
|
+
scope :in_category_name, lambda { |name|
|
10
|
+
where(['categories.name = ?', name]).includes(:category)
|
11
|
+
}
|
19
12
|
end
|
data/spec/spec_helper.rb
CHANGED
data/test.sh
CHANGED
@@ -2,5 +2,4 @@ bundle && bundle exec rspec spec
|
|
2
2
|
BUNDLE_GEMFILE=Gemfile.rails-3.2.12 bundle && BUNDLE_GEMFILE=Gemfile.rails-3.2.12 bundle exec rspec spec
|
3
3
|
BUNDLE_GEMFILE=Gemfile.rails-3.1.11 bundle && BUNDLE_GEMFILE=Gemfile.rails-3.1.11 bundle exec rspec spec
|
4
4
|
BUNDLE_GEMFILE=Gemfile.rails-3.0.20 bundle && BUNDLE_GEMFILE=Gemfile.rails-3.0.20 bundle exec rspec spec
|
5
|
-
BUNDLE_GEMFILE=Gemfile.rails-2.3.17 bundle && BUNDLE_GEMFILE=Gemfile.rails-2.3.17 bundle exec rspec spec
|
6
5
|
BUNDLE_GEMFILE=Gemfile.rails-4-beta bundle && BUNDLE_GEMFILE=Gemfile.rails-4-beta bundle exec rspec spec
|
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: 4.
|
4
|
+
version: 4.6.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: 2013-
|
11
|
+
date: 2013-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: uniform_notifier
|
@@ -24,7 +24,7 @@ dependencies:
|
|
24
24
|
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
description:
|
27
|
+
description: help to kill N+1 queries and unused eager loading.
|
28
28
|
email:
|
29
29
|
- flyerhzm@gmail.com
|
30
30
|
executables: []
|
@@ -38,7 +38,6 @@ files:
|
|
38
38
|
- .travis.yml
|
39
39
|
- CHANGELOG.md
|
40
40
|
- Gemfile
|
41
|
-
- Gemfile.rails-2.3.17
|
42
41
|
- Gemfile.rails-3.0.20
|
43
42
|
- Gemfile.rails-3.1.11
|
44
43
|
- Gemfile.rails-3.2.12
|
@@ -47,12 +46,9 @@ files:
|
|
47
46
|
- Hacking.md
|
48
47
|
- MIT-LICENSE
|
49
48
|
- README.md
|
50
|
-
- README_for_rails2.textile
|
51
49
|
- Rakefile
|
52
50
|
- bullet.gemspec
|
53
51
|
- lib/bullet.rb
|
54
|
-
- lib/bullet/action_controller2.rb
|
55
|
-
- lib/bullet/active_record2.rb
|
56
52
|
- lib/bullet/active_record3.rb
|
57
53
|
- lib/bullet/active_record3x.rb
|
58
54
|
- lib/bullet/active_record4.rb
|
@@ -100,8 +96,6 @@ files:
|
|
100
96
|
- spec/integration/association_spec.rb
|
101
97
|
- spec/integration/counter_cache_spec.rb
|
102
98
|
- spec/integration/mongoid/association_spec.rb
|
103
|
-
- spec/integration/rails2/association_spec.rb
|
104
|
-
- spec/integration/rails2/counter_cache_spec.rb
|
105
99
|
- spec/models/address.rb
|
106
100
|
- spec/models/author.rb
|
107
101
|
- spec/models/base_user.rb
|
@@ -159,10 +153,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
153
|
version: 1.3.6
|
160
154
|
requirements: []
|
161
155
|
rubyforge_project:
|
162
|
-
rubygems_version: 2.0.
|
156
|
+
rubygems_version: 2.0.3
|
163
157
|
signing_key:
|
164
158
|
specification_version: 4
|
165
|
-
summary:
|
159
|
+
summary: help to kill N+1 queries and unused eager loading.
|
166
160
|
test_files:
|
167
161
|
- spec/bullet/detector/association_spec.rb
|
168
162
|
- spec/bullet/detector/base_spec.rb
|
@@ -183,8 +177,6 @@ test_files:
|
|
183
177
|
- spec/integration/association_spec.rb
|
184
178
|
- spec/integration/counter_cache_spec.rb
|
185
179
|
- spec/integration/mongoid/association_spec.rb
|
186
|
-
- spec/integration/rails2/association_spec.rb
|
187
|
-
- spec/integration/rails2/counter_cache_spec.rb
|
188
180
|
- spec/models/address.rb
|
189
181
|
- spec/models/author.rb
|
190
182
|
- spec/models/base_user.rb
|
data/Gemfile.rails-2.3.17
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# Use `bundle install` in order to install these gems
|
2
|
-
# Use `bundle exec rake` in order to run the specs using the bundle
|
3
|
-
source "http://rubygems.org"
|
4
|
-
|
5
|
-
gemspec
|
6
|
-
|
7
|
-
gem 'rails', '2.3.17'
|
8
|
-
gem 'sqlite3'
|
9
|
-
gem 'mysql2'
|
10
|
-
gem 'bson_ext'
|
11
|
-
|
12
|
-
gem "rspec"
|
13
|
-
gem "guard"
|
14
|
-
gem "guard-rspec"
|