bullet 2.0.0.beta.2 → 2.0.0.beta.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/Hacking.textile +100 -0
- data/README.textile +36 -5
- data/README_for_rails2.textile +17 -0
- data/Rakefile +33 -16
- data/VERSION +1 -1
- data/autotest/discover.rb +1 -0
- data/bullet.gemspec +32 -9
- data/lib/bullet.rb +69 -38
- data/lib/bullet/action_controller2.rb +4 -4
- data/lib/bullet/active_record2.rb +16 -16
- data/lib/bullet/active_record3.rb +16 -25
- data/lib/bullet/detector.rb +9 -0
- data/lib/bullet/detector/association.rb +135 -0
- data/lib/bullet/detector/base.rb +19 -0
- data/lib/bullet/detector/counter.rb +43 -0
- data/lib/bullet/detector/n_plus_one_query.rb +39 -0
- data/lib/bullet/detector/unused_eager_association.rb +39 -0
- data/lib/bullet/notification.rb +4 -79
- data/lib/bullet/notification/base.rb +59 -0
- data/lib/bullet/notification/counter_cache.rb +13 -0
- data/lib/bullet/notification/n_plus_one_query.rb +32 -0
- data/lib/bullet/notification/unused_eager_loading.rb +14 -0
- data/lib/bullet/notification_collector.rb +25 -0
- data/lib/bullet/presenter.rb +13 -0
- data/lib/bullet/presenter/base.rb +9 -0
- data/lib/bullet/presenter/bullet_logger.rb +28 -0
- data/lib/bullet/presenter/growl.rb +40 -0
- data/lib/bullet/presenter/javascript_alert.rb +15 -0
- data/lib/bullet/presenter/javascript_console.rb +28 -0
- data/lib/bullet/presenter/javascript_helpers.rb +13 -0
- data/lib/bullet/presenter/rails_logger.rb +15 -0
- data/lib/bullet/presenter/xmpp.rb +56 -0
- data/lib/bullet/rack.rb +42 -0
- data/lib/bullet/registry.rb +7 -0
- data/lib/bullet/registry/association.rb +16 -0
- data/lib/bullet/registry/base.rb +39 -0
- data/lib/bullet/registry/object.rb +15 -0
- data/spec/bullet/association_for_chris_spec.rb +6 -6
- data/spec/bullet/association_for_peschkaj_spec.rb +6 -6
- data/spec/bullet/association_spec.rb +118 -262
- data/spec/bullet/counter_spec.rb +10 -10
- data/spec/spec_helper.rb +51 -17
- metadata +32 -9
- data/lib/bullet/association.rb +0 -294
- data/lib/bullet/counter.rb +0 -101
- data/lib/bullet/logger.rb +0 -9
- data/lib/bulletware.rb +0 -42
- data/spec/spec.opts +0 -3
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format d
|
data/Hacking.textile
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
h1. Bullet Overview for Developers
|
2
|
+
This file aims to give developers a quick tour of the bullet internals, making
|
3
|
+
it (hopefully) easier to extend or enhance the Bullet gem.
|
4
|
+
|
5
|
+
h2. General Control Flow aka. 10000 Meter View
|
6
|
+
When Rails is initialized, Bullet will extend ActiveRecord (and if you're using
|
7
|
+
Rails 2.x ActiveController too) with the relevant modules and methods found
|
8
|
+
in lib/bullet/active_recordX.rb and lib/bullet/action_controller2.rb. If you're
|
9
|
+
running Rails 3, Bullet will integrate itself as a middleware into the Rack
|
10
|
+
stack, so ActionController does not need to be extended.
|
11
|
+
|
12
|
+
The ActiveRecord extensions will call methods in a given detector class, when
|
13
|
+
certain methods are called.
|
14
|
+
|
15
|
+
Detector classes contain all the logic to recognize
|
16
|
+
a noteworthy event. If such an event is detected, an instance of the
|
17
|
+
corresponding Notification class is created and stored in a Set instance in the
|
18
|
+
main Bullet module (the 'notification collector').
|
19
|
+
|
20
|
+
Notification instances contain the message that will be displayed, and will
|
21
|
+
use a Presenter class to display their message to the user.
|
22
|
+
|
23
|
+
Each Presenter knows how to present the message either "inline" (as in: the
|
24
|
+
message text will be inlined into the request response, such as javascript
|
25
|
+
alerts) or "out-of-channel" (completely independent of the request response,
|
26
|
+
such as growl or xmpp).
|
27
|
+
|
28
|
+
So the flow of a request goes like this:
|
29
|
+
1. Bullet.start_request is called, which resets all the detectors and empties
|
30
|
+
the notification collector
|
31
|
+
2. The request is handled by Rails, and the installed ActiveRecord extensions
|
32
|
+
trigger Detector callbacks
|
33
|
+
3. Detectors once called, will determine whether something noteworthy happend.
|
34
|
+
If yes, then a Notification is created and stored in the notification collector.
|
35
|
+
4. Rails finishes handling the request
|
36
|
+
5. For each notification in the collector, Bullet will iterate over each
|
37
|
+
Presenter and will try to generate an inline message that will be appended to
|
38
|
+
the generated reponse body.
|
39
|
+
6. The response is returned to the client.
|
40
|
+
7. Bullet will try to generate an out-of-channel message for each notification.
|
41
|
+
8. Bullet calls end_request for each detector.
|
42
|
+
9. Goto 1.
|
43
|
+
|
44
|
+
h2. Adding Presenters
|
45
|
+
To add a presenter, you will need to:
|
46
|
+
* Add the class to the PRESENTERS constant in the main Bullet module
|
47
|
+
* Add an autoload directive to lib/bullet/presenter.rb
|
48
|
+
* Create your presenter class in the Bullet::Presenter namespace
|
49
|
+
|
50
|
+
Presenter classes will need the following class methods:
|
51
|
+
* .active? which returns a boolean to indicate if the presenter is active (so
|
52
|
+
* that presenters the user doesn't want can be skipped).
|
53
|
+
|
54
|
+
and at least one of:
|
55
|
+
* .out_of_channel( notification ) which will display the notification to the
|
56
|
+
user outside of the request response
|
57
|
+
or
|
58
|
+
* .inline( notification ) which will generate the notification presentation fit
|
59
|
+
to be appended to the generated HTML request response (if you want to inject
|
60
|
+
content on the result page, such as a javascript alert).
|
61
|
+
|
62
|
+
Have a look at lib/bullet/javascript_alert.rb as a trivial example for an
|
63
|
+
inline presenter and lib/bullet/rails_logger.rb to see how a minimal
|
64
|
+
out-of-channel presenter looks like.
|
65
|
+
|
66
|
+
h2. Adding Notification Types
|
67
|
+
If you want to add more kinds of things that Bullet can detect, a little more
|
68
|
+
work is needed than if you were just adding a Presenter, but the concepts are
|
69
|
+
similar.
|
70
|
+
|
71
|
+
* Add the class to the DETECTORS constant in the main Bullet module
|
72
|
+
* Add (if needed) Rails monkey patches to Bullet.enable
|
73
|
+
* Create your presenter class in the Bullet::Detector namespace
|
74
|
+
* Add an autoload directive to lib/bullet/detector.rb
|
75
|
+
* Create a corresponding notification class in the Bullet::Notification namespace
|
76
|
+
* Add an autoload directive to lib/bullet/notification.rb
|
77
|
+
|
78
|
+
As a rule of thumb, you can assume that each Detector will have its own
|
79
|
+
Notification class. If you follow the principle of Separation of Concerns I
|
80
|
+
can't really think of an example where one would deviate from this rule.
|
81
|
+
|
82
|
+
Since the detection of pathological associations is a bit hairy, I'd recommend
|
83
|
+
having a look at the counter cache detector and associated notification to get
|
84
|
+
a feel for what is needed to get off the ground.
|
85
|
+
|
86
|
+
h3. Detectors
|
87
|
+
The only things you'll need to consider when building your Detector class is
|
88
|
+
that it will need to supply the .start_request, .end_request and .clear class
|
89
|
+
methods.
|
90
|
+
|
91
|
+
Simple implementations are provided by Bullet::Detector::Base for start_request
|
92
|
+
and end_request, you will have to supply your own clear method.
|
93
|
+
|
94
|
+
h3. Notifications
|
95
|
+
For notifications you will want to supply a #title and #body instance method,
|
96
|
+
and check to see if the #initialize and #full_notice methods in the
|
97
|
+
Bullet::Notification::Base class fit your needs.
|
98
|
+
|
99
|
+
The interaction with the presenters encapsulated in the Base class, so you
|
100
|
+
won't have to worry about that.
|
data/README.textile
CHANGED
@@ -17,6 +17,7 @@ You can install it as a gem:
|
|
17
17
|
<pre><code>
|
18
18
|
sudo gem install bullet --pre
|
19
19
|
</code></pre>
|
20
|
+
|
20
21
|
****************************************************************************
|
21
22
|
|
22
23
|
h2. Configuration
|
@@ -29,6 +30,10 @@ config.after_initialize do
|
|
29
30
|
Bullet.bullet_logger = true
|
30
31
|
Bullet.console = true
|
31
32
|
Bullet.growl = true
|
33
|
+
Bullet.xmpp = { :account => 'bullets_account@jabber.org',
|
34
|
+
:password => 'bullets_password_for_jabber',
|
35
|
+
:receiver => 'your_account@jabber.org',
|
36
|
+
:show_online_status => true }
|
32
37
|
Bullet.rails_logger = true
|
33
38
|
Bullet.disable_browser_cache = true
|
34
39
|
end
|
@@ -43,13 +48,27 @@ It is recommended to config growl notification as follows if your collaborators
|
|
43
48
|
end
|
44
49
|
</code></pre>
|
45
50
|
|
46
|
-
|
51
|
+
and similarly for XMPP:
|
52
|
+
<pre><code>
|
53
|
+
begin
|
54
|
+
require 'xmpp4r'
|
55
|
+
Bullet.xmpp = { :account => 'bullets_account@jabber.org',
|
56
|
+
:password => 'bullets_password_for_jabber',
|
57
|
+
:receiver => 'your_account@jabber.org',
|
58
|
+
:show_online_status => true }
|
59
|
+
rescue MissingSourceFile
|
60
|
+
end
|
61
|
+
</code></pre>
|
62
|
+
|
63
|
+
|
64
|
+
The code above will enable all six of the Bullet notification systems:
|
47
65
|
* <code>Bullet.enable</code>: enable Bullet plugin/gem, otherwise do nothing
|
48
66
|
* <code>Bullet.alert</code>: pop up a JavaScript alert in the browser
|
49
67
|
* <code>Bullet.bullet_logger</code>: log to the Bullet log file (Rails.root/log/bullet.log)
|
50
68
|
* <code>Bullet.rails_logger</code>: add warnings directly to the Rails log
|
51
69
|
* <code>Bullet.console</code>: log warnings to your browser's console.log (Safari/Webkit browsers or Firefox w/Firebug installed)
|
52
70
|
* <code>Bullet.growl</code>: pop up Growl warnings if your system has Growl installed. Requires a little bit of configuration
|
71
|
+
* <code>Bullet.xmpp</code>: send XMPP/Jabber notifications to the receiver indicated. Note that the code will currently not handle the adding of contacts, so you will need to make both accounts indicated know each other manually before you will receive any notifications. If you restart the development server frequently, the 'coming online' sound for the bullet account may start to annoy - in this case set :show_online_status to false; you will still get notifications, but the bullet account won't announce it's online status anymore.
|
53
72
|
* <code>Bullet.disable_browser_cache</code>: disable browser cache which usually causes unexpected problems
|
54
73
|
|
55
74
|
****************************************************************************
|
@@ -105,6 +124,17 @@ ruby-growl gem has an issue about md5 in ruby 1.9, if you use growl and ruby 1.9
|
|
105
124
|
|
106
125
|
****************************************************************************
|
107
126
|
|
127
|
+
h2. XMPP/Jabber Support
|
128
|
+
|
129
|
+
To get XMPP support up-and-running for Bullet, follow the steps below:
|
130
|
+
* Install the xmpp4r gem: <code>sudo gem install xmpp4r</code>
|
131
|
+
* Make both the bullet and the receipient account add each other as contacts.
|
132
|
+
This will require you to manually log into both accounts, add each other
|
133
|
+
as contact and confirm each others contact request.
|
134
|
+
* Boot up your application. Bullet will automatically send an XMPP notification when XMPP is turned on.
|
135
|
+
|
136
|
+
****************************************************************************
|
137
|
+
|
108
138
|
h2. Important
|
109
139
|
|
110
140
|
If you find bullet does not work for you, *please disable your browser's cache*.
|
@@ -155,6 +185,7 @@ h2. Links
|
|
155
185
|
|
156
186
|
h2. Contributors
|
157
187
|
|
188
|
+
sriedel did a lot of awesome refactors, added xmpp notification support, and added Hacking.textile about how to extend to bullet plugin.
|
158
189
|
flipsasser added Growl, console.log and Rails.log support, very awesome. And he also improved README.
|
159
190
|
rainux added group style console.log.
|
160
191
|
2collegebums added some great specs to generate red bar.
|
@@ -203,7 +234,7 @@ post2.comments.create(:name => 'fourth')
|
|
203
234
|
<pre><code>
|
204
235
|
<% @posts.each do |post| %>
|
205
236
|
<tr>
|
206
|
-
<td><%=
|
237
|
+
<td><%= post.name %></td>
|
207
238
|
<td><%= post.comments.collect(&:name) %></td>
|
208
239
|
<td><%= link_to 'Show', post %></td>
|
209
240
|
<td><%= link_to 'Edit', edit_post_path(post) %></td>
|
@@ -315,7 +346,7 @@ a N+1 query fixed. Cool!
|
|
315
346
|
<pre><code>
|
316
347
|
<% @posts.each do |post| %>
|
317
348
|
<tr>
|
318
|
-
<td><%=
|
349
|
+
<td><%= post.name %></td>
|
319
350
|
<td><%= link_to 'Show', post %></td>
|
320
351
|
<td><%= link_to 'Edit', edit_post_path(post) %></td>
|
321
352
|
<td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
|
@@ -355,8 +386,8 @@ Remove from your finder: :include => [:comments]
|
|
355
386
|
<pre><code>
|
356
387
|
<% @posts.each do |post| %>
|
357
388
|
<tr>
|
358
|
-
<td><%=
|
359
|
-
<td><%=
|
389
|
+
<td><%= post.name %></td>
|
390
|
+
<td><%= post.comments.size %></td>
|
360
391
|
<td><%= link_to 'Show', post %></td>
|
361
392
|
<td><%= link_to 'Edit', edit_post_path(post) %></td>
|
362
393
|
<td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
|
data/README_for_rails2.textile
CHANGED
@@ -18,6 +18,7 @@ There is a large refactor from gem 1.4 to 1.5, so if you upgrade to 1.5 gem, ple
|
|
18
18
|
|
19
19
|
h2. Contributors
|
20
20
|
|
21
|
+
sriedel did a lot of awesome refactors, added xmpp notification support, and added Hacking.textile about how to extend to bullet plugin.
|
21
22
|
flipsasser added Growl, console.log and Rails.log support, very awesome. And he also improved README.
|
22
23
|
rainux added group style console.log.
|
23
24
|
2collegebums added some great specs to generate red bar.
|
@@ -52,6 +53,10 @@ config.after_initialize do
|
|
52
53
|
Bullet.growl = true
|
53
54
|
Bullet.rails_logger = true
|
54
55
|
Bullet.disable_browser_cache = true
|
56
|
+
Bullet.xmpp = { :account => 'bullets_account@jabber.org',
|
57
|
+
:password => 'bullets_password_for_jabber',
|
58
|
+
:receiver => 'your_account@jabber.org',
|
59
|
+
:show_online_status => true }
|
55
60
|
end
|
56
61
|
</code></pre>
|
57
62
|
|
@@ -64,6 +69,18 @@ It is recommended to config growl notification as follows if your collaborators
|
|
64
69
|
end
|
65
70
|
</code></pre>
|
66
71
|
|
72
|
+
and similarly for XMPP:
|
73
|
+
<pre><code>
|
74
|
+
begin
|
75
|
+
require 'xmpp4r'
|
76
|
+
Bullet.xmpp = { :account => 'bullets_account@jabber.org',
|
77
|
+
:password => 'bullets_password_for_jabber',
|
78
|
+
:receiver => 'your_account@jabber.org',
|
79
|
+
:show_online_status => true }
|
80
|
+
rescue MissingSourceFile
|
81
|
+
end
|
82
|
+
</code></pre>
|
83
|
+
|
67
84
|
The code above will enable all five of the Bullet notification systems:
|
68
85
|
* <code>Bullet.enable</code>: enable Bullet plugin/gem, otherwise do nothing
|
69
86
|
* <code>Bullet.alert</code>: pop up a JavaScript alert in the browser
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'jeweler'
|
|
6
6
|
desc 'Default: run unit tests.'
|
7
7
|
task :default => :spec
|
8
8
|
|
9
|
-
desc 'Generate documentation for the
|
9
|
+
desc 'Generate documentation for the bullet plugin.'
|
10
10
|
Rake::RDocTask.new(:rdoc) do |rdoc|
|
11
11
|
rdoc.rdoc_dir = 'rdoc'
|
12
12
|
rdoc.title = 'Bullet'
|
@@ -15,20 +15,37 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
15
15
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
#desc "Run all specs in spec directory"
|
20
|
-
#Rspec::Core::RakeTask.new(:spec) do |t|
|
21
|
-
#t.pattern = FileList['spec/**/*_spec.rb']
|
22
|
-
#end
|
18
|
+
RSpec::Core::RakeTask.new(:spec)
|
23
19
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
20
|
+
desc "Run all examples using rcov"
|
21
|
+
RSpec::Core::RakeTask.new :rcov => :cleanup_rcov_files do |t|
|
22
|
+
t.rcov = true
|
23
|
+
t.rcov_opts = %[-Ilib -Ispec --exclude "gems/*,spec/spec_helper.rb"]
|
24
|
+
t.rcov_opts << %[--no-html --aggregate coverage.data]
|
25
|
+
end
|
26
|
+
|
27
|
+
task :cleanup_rcov_files do
|
28
|
+
rm_rf 'coverage.data'
|
29
|
+
end
|
30
|
+
|
31
|
+
task :clobber do
|
32
|
+
rm_rf 'pkg'
|
33
|
+
rm_rf 'tmp'
|
34
|
+
rm_rf 'coverage'
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
Jeweler::Tasks.new do |gemspec|
|
39
|
+
gemspec.name = "bullet"
|
40
|
+
gemspec.summary = "A rails plugin to kill N+1 queries and unused eager loading"
|
41
|
+
gemspec.description = "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."
|
42
|
+
gemspec.email = "flyerhzm@gmail.com"
|
43
|
+
gemspec.homepage = "http://github.com/flyerhzm/bullet"
|
44
|
+
gemspec.authors = ["Richard Huang"]
|
45
|
+
gemspec.files.exclude '.gitignore'
|
46
|
+
gemspec.files.exclude 'log/*'
|
47
|
+
end
|
48
|
+
Jeweler::GemcutterTasks.new
|
49
|
+
rescue LoadError
|
50
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
33
51
|
end
|
34
|
-
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0.0.beta.
|
1
|
+
2.0.0.beta.3
|
@@ -0,0 +1 @@
|
|
1
|
+
Autotest.add_discovery { "rspec2" }
|
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 = "2.0.0.beta.
|
8
|
+
s.version = "2.0.0.beta.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Richard Huang"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-07-14}
|
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 = [
|
@@ -17,27 +17,50 @@ Gem::Specification.new do |s|
|
|
17
17
|
"README_for_rails2.textile"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
|
-
"
|
20
|
+
".rspec",
|
21
|
+
"Hacking.textile",
|
22
|
+
"MIT-LICENSE",
|
21
23
|
"README.textile",
|
22
24
|
"README_for_rails2.textile",
|
23
25
|
"Rakefile",
|
24
26
|
"VERSION",
|
27
|
+
"autotest/discover.rb",
|
25
28
|
"bullet.gemspec",
|
26
29
|
"lib/bullet.rb",
|
27
30
|
"lib/bullet/action_controller2.rb",
|
28
31
|
"lib/bullet/active_record2.rb",
|
29
32
|
"lib/bullet/active_record3.rb",
|
30
|
-
"lib/bullet/
|
31
|
-
"lib/bullet/
|
32
|
-
"lib/bullet/
|
33
|
+
"lib/bullet/detector.rb",
|
34
|
+
"lib/bullet/detector/association.rb",
|
35
|
+
"lib/bullet/detector/base.rb",
|
36
|
+
"lib/bullet/detector/counter.rb",
|
37
|
+
"lib/bullet/detector/n_plus_one_query.rb",
|
38
|
+
"lib/bullet/detector/unused_eager_association.rb",
|
33
39
|
"lib/bullet/notification.rb",
|
34
|
-
"lib/
|
40
|
+
"lib/bullet/notification/base.rb",
|
41
|
+
"lib/bullet/notification/counter_cache.rb",
|
42
|
+
"lib/bullet/notification/n_plus_one_query.rb",
|
43
|
+
"lib/bullet/notification/unused_eager_loading.rb",
|
44
|
+
"lib/bullet/notification_collector.rb",
|
45
|
+
"lib/bullet/presenter.rb",
|
46
|
+
"lib/bullet/presenter/base.rb",
|
47
|
+
"lib/bullet/presenter/bullet_logger.rb",
|
48
|
+
"lib/bullet/presenter/growl.rb",
|
49
|
+
"lib/bullet/presenter/javascript_alert.rb",
|
50
|
+
"lib/bullet/presenter/javascript_console.rb",
|
51
|
+
"lib/bullet/presenter/javascript_helpers.rb",
|
52
|
+
"lib/bullet/presenter/rails_logger.rb",
|
53
|
+
"lib/bullet/presenter/xmpp.rb",
|
54
|
+
"lib/bullet/rack.rb",
|
55
|
+
"lib/bullet/registry.rb",
|
56
|
+
"lib/bullet/registry/association.rb",
|
57
|
+
"lib/bullet/registry/base.rb",
|
58
|
+
"lib/bullet/registry/object.rb",
|
35
59
|
"rails/init.rb",
|
36
60
|
"spec/bullet/association_for_chris_spec.rb",
|
37
61
|
"spec/bullet/association_for_peschkaj_spec.rb",
|
38
62
|
"spec/bullet/association_spec.rb",
|
39
63
|
"spec/bullet/counter_spec.rb",
|
40
|
-
"spec/spec.opts",
|
41
64
|
"spec/spec_helper.rb",
|
42
65
|
"tasks/bullet_tasks.rake"
|
43
66
|
]
|
@@ -45,7 +68,7 @@ Gem::Specification.new do |s|
|
|
45
68
|
s.rdoc_options = ["--charset=UTF-8"]
|
46
69
|
s.require_paths = ["lib"]
|
47
70
|
s.rubygems_version = %q{1.3.6}
|
48
|
-
s.summary = %q{A plugin to kill N+1 queries and unused eager loading}
|
71
|
+
s.summary = %q{A rails plugin to kill N+1 queries and unused eager loading}
|
49
72
|
s.test_files = [
|
50
73
|
"spec/spec_helper.rb",
|
51
74
|
"spec/bullet/counter_spec.rb",
|
data/lib/bullet.rb
CHANGED
@@ -1,31 +1,52 @@
|
|
1
|
-
require '
|
1
|
+
require 'set'
|
2
2
|
|
3
3
|
module Bullet
|
4
|
+
class NotificationError < StandardError; end
|
5
|
+
|
4
6
|
if Rails.version =~ /^3.0/
|
5
7
|
autoload :ActiveRecord, 'bullet/active_record3'
|
6
8
|
else
|
7
9
|
autoload :ActiveRecord, 'bullet/active_record2'
|
8
10
|
autoload :ActionController, 'bullet/action_controller2'
|
9
11
|
end
|
10
|
-
autoload :
|
11
|
-
autoload :Counter, 'bullet/counter'
|
12
|
+
autoload :Rack, 'bullet/rack'
|
12
13
|
autoload :BulletLogger, 'bullet/logger'
|
13
14
|
autoload :Notification, 'bullet/notification'
|
15
|
+
autoload :Presenter, 'bullet/presenter'
|
16
|
+
autoload :Detector, 'bullet/detector'
|
17
|
+
autoload :Registry, 'bullet/registry'
|
18
|
+
autoload :NotificationCollector, 'bullet/notification_collector'
|
19
|
+
|
20
|
+
if defined? Rails::Railtie
|
21
|
+
# compatible with rails 3.0.0.beta4
|
22
|
+
class BulletRailtie < Rails::Railtie
|
23
|
+
initializer "bullet.configure_rails_initialization" do |app|
|
24
|
+
app.middleware.use Bullet::Rack
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
14
28
|
|
15
29
|
class <<self
|
16
|
-
attr_accessor :enable, :alert, :console, :growl, :growl_password, :rails_logger, :bullet_logger, :
|
30
|
+
attr_accessor :enable, :alert, :console, :growl, :growl_password, :rails_logger, :bullet_logger, :disable_browser_cache, :xmpp
|
31
|
+
attr_reader :notification_collector
|
32
|
+
|
33
|
+
DETECTORS = [ Bullet::Detector::NPlusOneQuery,
|
34
|
+
Bullet::Detector::UnusedEagerAssociation,
|
35
|
+
Bullet::Detector::Counter ]
|
17
36
|
|
37
|
+
PRESENTERS = [ Bullet::Presenter::JavascriptAlert,
|
38
|
+
Bullet::Presenter::JavascriptConsole,
|
39
|
+
Bullet::Presenter::Growl,
|
40
|
+
Bullet::Presenter::Xmpp,
|
41
|
+
Bullet::Presenter::RailsLogger,
|
42
|
+
Bullet::Presenter::BulletLogger ]
|
43
|
+
|
18
44
|
def enable=(enable)
|
19
45
|
@enable = enable
|
20
46
|
if enable?
|
21
47
|
Bullet::ActiveRecord.enable
|
22
|
-
if Rails.version =~ /^
|
23
|
-
require 'action_controller/metal'
|
24
|
-
::ActionController::Metal.middleware_stack.use Bulletware
|
25
|
-
elsif Rails.version =~/^2.3/
|
48
|
+
if Rails.version =~ /^2./
|
26
49
|
Bullet::ActionController.enable
|
27
|
-
require 'action_controller/dispatcher'
|
28
|
-
::ActionController::Dispatcher.middleware.use Bulletware
|
29
50
|
end
|
30
51
|
end
|
31
52
|
end
|
@@ -35,53 +56,63 @@ module Bullet
|
|
35
56
|
end
|
36
57
|
|
37
58
|
def growl=(growl)
|
38
|
-
if growl
|
39
|
-
begin
|
40
|
-
require 'ruby-growl'
|
41
|
-
growl = Growl.new('localhost', 'ruby-growl', ['Bullet Notification'], nil, @growl_password)
|
42
|
-
growl.notify('Bullet Notification', 'Bullet Notification', 'Bullet Growl notifications have been turned on')
|
43
|
-
rescue MissingSourceFile
|
44
|
-
raise NotificationError.new('You must install the ruby-growl gem to use Growl notifications: `sudo gem install ruby-growl`')
|
45
|
-
end
|
46
|
-
end
|
47
|
-
@growl = growl
|
59
|
+
Bullet::Presenter::Growl.setup_connection( self.growl_password ) if growl
|
48
60
|
end
|
49
61
|
|
50
|
-
def
|
51
|
-
|
52
|
-
@logger_file = File.open(Bullet::BulletLogger::LOG_FILE, 'a+')
|
53
|
-
@logger = Bullet::BulletLogger.new(@logger_file)
|
54
|
-
end
|
62
|
+
def xmpp=(xmpp)
|
63
|
+
Bullet::Presenter::Xmpp.setup_connection( xmpp ) if xmpp
|
55
64
|
end
|
56
65
|
|
57
|
-
|
66
|
+
def bullet_logger=(bullet_logger)
|
67
|
+
Bullet::Presenter::BulletLogger.setup if bullet_logger
|
68
|
+
end
|
58
69
|
|
59
70
|
def start_request
|
60
|
-
|
71
|
+
@notification_collector ||= Bullet::NotificationCollector.new
|
72
|
+
@notification_collector.reset
|
73
|
+
DETECTORS.each {|bullet| bullet.start_request}
|
61
74
|
end
|
62
75
|
|
63
76
|
def end_request
|
64
|
-
|
77
|
+
DETECTORS.each {|bullet| bullet.end_request}
|
65
78
|
end
|
66
79
|
|
67
80
|
def clear
|
68
|
-
|
81
|
+
DETECTORS.each {|bullet| bullet.clear}
|
69
82
|
end
|
70
83
|
|
71
|
-
def
|
72
|
-
|
84
|
+
def active_presenters
|
85
|
+
PRESENTERS.select { |presenter| presenter.send :active? }
|
73
86
|
end
|
74
87
|
|
75
|
-
def
|
76
|
-
|
88
|
+
def notification?
|
89
|
+
Bullet::Detector::UnusedEagerAssociation.check_unused_preload_associations
|
90
|
+
@notification_collector.notifications_present?
|
77
91
|
end
|
78
92
|
|
79
|
-
def
|
80
|
-
|
93
|
+
def gather_inline_notifications
|
94
|
+
responses = []
|
95
|
+
for_each_active_presenter_with_notification do |notification|
|
96
|
+
responses << notification.present_inline
|
97
|
+
end
|
98
|
+
responses.join( "\n" )
|
81
99
|
end
|
82
100
|
|
83
|
-
def
|
84
|
-
|
101
|
+
def perform_out_of_channel_notifications
|
102
|
+
for_each_active_presenter_with_notification do |notification|
|
103
|
+
notification.present_out_of_channel
|
104
|
+
end
|
85
105
|
end
|
106
|
+
|
107
|
+
private
|
108
|
+
def for_each_active_presenter_with_notification
|
109
|
+
active_presenters.each do |presenter|
|
110
|
+
@notification_collector.collection.each do |notification|
|
111
|
+
notification.presenter = presenter
|
112
|
+
yield notification
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
86
116
|
end
|
87
|
-
|
117
|
+
|
118
|
+
end
|