flyerhzm-bullet 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -150,7 +150,11 @@ $ script/plugin install git://github.com/flyerhzm/bullet.git
150
150
  6. enable the bullet plugin in development, add a line to <code>config/environments/development.rb</code>
151
151
 
152
152
  <pre><code>
153
- Bullet.enable = true
153
+ config.after_initialize do
154
+ Bullet.enable = true
155
+ Bullet::Association.alert = true
156
+ Bullet::Association.bullet_logger = true
157
+ end
154
158
  </code></pre>
155
159
 
156
160
  7. start server
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.0
1
+ 1.3.0
data/bullet.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{bullet}
8
- s.version = "1.2.0"
8
+ s.version = "1.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Richard Huang"]
12
- s.date = %q{2009-08-29}
12
+ s.date = %q{2009-08-31}
13
13
  s.description = %q{The Bullet plugin 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) or when you're using eager loading that isn't necessary.}
14
14
  s.email = %q{flyerhzm@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -38,8 +38,8 @@ Gem::Specification.new do |s|
38
38
  s.rubygems_version = %q{1.3.5}
39
39
  s.summary = %q{A plugin to kill N+1 queries and unused eager loading}
40
40
  s.test_files = [
41
- "spec/spec_helper.rb",
42
- "spec/bullet_association_spec.rb"
41
+ "spec/bullet_association_spec.rb",
42
+ "spec/spec_helper.rb"
43
43
  ]
44
44
 
45
45
  if s.respond_to? :specification_version then
@@ -3,11 +3,11 @@ module Bullet
3
3
  def self.enable
4
4
  ::ActiveRecord::Base.class_eval do
5
5
  class << self
6
- alias_method :bullet_find_every, :find_every
6
+ alias_method :origin_find_every, :find_every
7
7
  # if select a collection of objects, then these objects have possible to cause N+1 query
8
8
  # if select only one object, then the only one object has impossible to cause N+1 query
9
9
  def find_every(options)
10
- records = bullet_find_every(options)
10
+ records = origin_find_every(options)
11
11
 
12
12
  if records
13
13
  if records.size > 1
@@ -23,7 +23,7 @@ module Bullet
23
23
  end
24
24
 
25
25
  ::ActiveRecord::AssociationPreload::ClassMethods.class_eval do
26
- alias_method :bullet_preload_associations, :preload_associations
26
+ alias_method :origin_preload_associations, :preload_associations
27
27
  # add include for one to many associations query
28
28
  def preload_associations(records, associations, preload_options={})
29
29
  records = [records].flatten.compact.uniq
@@ -31,34 +31,35 @@ module Bullet
31
31
  records.each do |record|
32
32
  Bullet::Association.add_association(record, associations)
33
33
  end
34
- bullet_preload_associations(records, associations, preload_options={})
34
+ Bullet::Association.add_eager_loadings(records, associations)
35
+ origin_preload_associations(records, associations, preload_options={})
35
36
  end
36
37
  end
37
38
 
38
39
  ::ActiveRecord::Associations::ClassMethods.class_eval do
39
40
  # define one to many associations
40
- alias_method :bullet_collection_reader_method, :collection_reader_method
41
+ alias_method :origin_collection_reader_method, :collection_reader_method
41
42
  def collection_reader_method(reflection, association_proxy_class)
42
43
  Bullet::Association.define_association(self, reflection.name)
43
- bullet_collection_reader_method(reflection, association_proxy_class)
44
+ origin_collection_reader_method(reflection, association_proxy_class)
44
45
  end
45
46
  end
46
47
 
47
48
  ::ActiveRecord::Associations::AssociationCollection.class_eval do
48
49
  # call one to many associations
49
- alias_method :bullet_load_target, :load_target
50
+ alias_method :origin_load_target, :load_target
50
51
  def load_target
51
52
  Bullet::Association.call_association(@owner, @reflection.name)
52
- bullet_load_target
53
+ origin_load_target
53
54
  end
54
55
  end
55
56
 
56
57
  ::ActiveRecord::Associations::AssociationProxy.class_eval do
57
- # call has_one association
58
- alias_method :bullet_load_target, :load_target
58
+ # call has_one and belong_to association
59
+ alias_method :origin_load_target, :load_target
59
60
  def load_target
60
61
  Bullet::Association.call_association(@owner, @reflection.name)
61
- bullet_load_target
62
+ origin_load_target
62
63
  end
63
64
  end
64
65
  end
@@ -24,6 +24,7 @@ module Bullet
24
24
  @@possible_objects = nil
25
25
  @@impossible_objects = nil
26
26
  @@call_object_associations = nil
27
+ @@eager_loadings = nil
27
28
  end
28
29
 
29
30
  def alert=(alert)
@@ -64,8 +65,10 @@ module Bullet
64
65
 
65
66
  def check_unused_preload_associations
66
67
  object_associations.each do |object, association|
67
- call_object_association = call_object_associations[object] || []
68
- add_unused_preload_associations(object.class, association - call_object_association) unless (association - call_object_association).empty?
68
+ related_objects = eager_loadings.select {|key, value| key.include?(object) and value == association}.collect(&:first).flatten
69
+ call_object_association = related_objects.collect { |related_object| call_object_associations[related_object] }.compact.flatten.uniq
70
+ diff_object_association = (association - call_object_association).reject {|a| a.is_a? Hash}
71
+ add_unused_preload_associations(object.class, diff_object_association) unless diff_object_association.empty?
69
72
  end
70
73
  end
71
74
 
@@ -88,11 +91,11 @@ module Bullet
88
91
  response = []
89
92
  if has_unused_preload_associations?
90
93
  response.push("Unused eager loadings detected:\n")
91
- response.push(*@@unused_preload_associations.to_a.collect{|klazz, associations| klazz_associations_str(klazz, associations)}.join('\n'))
94
+ response.push(*@@unused_preload_associations.to_a.collect{|klazz, associations| klazz_associations_str(klazz, associations)}.join("\n"))
92
95
  end
93
96
  if has_unpreload_associations?
94
97
  response.push("#{"\n" unless response.empty?}N+1 queries detected:\n")
95
- response.push(*@@unpreload_associations.to_a.collect{|klazz, associations| " #{klazz} => [#{associations.map(&:inspect).join(', ')}]"}.join('\n'))
98
+ response.push(*@@unpreload_associations.to_a.collect{|klazz, associations| " #{klazz} => [#{associations.map(&:inspect).join(', ')}]"}.join("\n"))
96
99
  end
97
100
  end
98
101
  if @@alert
@@ -143,7 +146,7 @@ module Bullet
143
146
 
144
147
  def bad_associations_str(bad_associations)
145
148
  # puts bad_associations.inspect
146
- bad_associations.to_a.collect{|klazz, associations| klazz_associations_str(klazz, associations)}.join('\\n')
149
+ bad_associations.to_a.collect{|klazz, associations| klazz_associations_str(klazz, associations)}.join("\n")
147
150
  end
148
151
 
149
152
  def klazz_associations_str(klazz, associations)
@@ -229,6 +232,14 @@ module Bullet
229
232
  klazz_associations[klazz] << associations
230
233
  unique(klazz_associations[klazz])
231
234
  end
235
+
236
+ def add_eager_loadings(objects, associations)
237
+ # puts "add eager loadings, #{objects.inspect} => #{associations.inspect}"
238
+ objects = Array(objects)
239
+ eager_loadings[objects] ||= []
240
+ eager_loadings[objects] << associations
241
+ unique(eager_loadings[objects])
242
+ end
232
243
 
233
244
  def unique(array)
234
245
  array.flatten!
@@ -262,6 +273,10 @@ module Bullet
262
273
  def klazz_associations
263
274
  @@klazz_associations ||= {}
264
275
  end
276
+
277
+ def eager_loadings
278
+ @@eager_loadings ||= {}
279
+ end
265
280
 
266
281
  VENDOR_ROOT = File.join(RAILS_ROOT, 'vendor')
267
282
  def caller_in_project
@@ -56,8 +56,6 @@ describe Bullet::Association, 'has_many' do
56
56
 
57
57
  post1 = category1.posts.create(:name => 'first')
58
58
  post2 = category1.posts.create(:name => 'second')
59
- post3 = category2.posts.create(:name => 'third')
60
- post4 = category2.posts.create(:name => 'fourth')
61
59
 
62
60
  comment1 = post1.comments.create(:name => 'first')
63
61
  comment2 = post1.comments.create(:name => 'second')
@@ -228,12 +226,36 @@ describe Bullet::Association, 'has_many' do
228
226
  end
229
227
 
230
228
  context "no preload" do
229
+ it "should no preload only display only one post => comment" do
230
+ Post.find(:all, :include => :comments).each do |post|
231
+ post.comments.first.name
232
+ end
233
+ Bullet::Association.should_not be_has_unpreload_associations
234
+ end
235
+
231
236
  it "should no preload only one post => commnets" do
232
237
  Post.first.comments.collect(&:name)
233
238
  Bullet::Association.should_not be_has_unpreload_associations
234
239
  end
235
240
  end
236
241
 
242
+ context "no unused" do
243
+ it "should no unused only display only one post => comment" do
244
+ Post.find(:all, :include => :comments).each do |post|
245
+ i = 0
246
+ post.comments.each do |comment|
247
+ if i == 0
248
+ comment.name
249
+ else
250
+ i += 1
251
+ end
252
+ end
253
+ end
254
+ Bullet::Association.check_unused_preload_associations
255
+ Bullet::Association.should_not be_has_unused_preload_associations
256
+ end
257
+ end
258
+
237
259
  context "belongs_to" do
238
260
  it "should preload comments => post" do
239
261
  Comment.find(:all).each do |comment|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flyerhzm-bullet
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-29 00:00:00 -07:00
12
+ date: 2009-08-31 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -39,7 +39,6 @@ files:
39
39
  - tasks/bullet_tasks.rake
40
40
  has_rdoc: false
41
41
  homepage: http://github.com/flyerhzm/bullet
42
- licenses:
43
42
  post_install_message:
44
43
  rdoc_options:
45
44
  - --charset=UTF-8
@@ -60,10 +59,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
59
  requirements: []
61
60
 
62
61
  rubyforge_project:
63
- rubygems_version: 1.3.5
62
+ rubygems_version: 1.2.0
64
63
  signing_key:
65
64
  specification_version: 3
66
65
  summary: A plugin to kill N+1 queries and unused eager loading
67
66
  test_files:
68
- - spec/spec_helper.rb
69
67
  - spec/bullet_association_spec.rb
68
+ - spec/spec_helper.rb