bullet 2.0.0.beta.2 → 2.0.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.
- data/MIT-LICENSE +1 -1
- data/README.textile +38 -8
- data/README_for_rails2.textile +19 -3
- 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/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/detector.rb +9 -0
- data/lib/bullet/notification/base.rb +57 -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.rb +4 -79
- data/lib/bullet/notification_collector.rb +25 -0
- data/lib/bullet/rack.rb +44 -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/lib/bullet/registry.rb +7 -0
- data/lib/bullet/version.rb +5 -0
- data/lib/bullet.rb +63 -42
- metadata +60 -42
- data/Rakefile +0 -34
- data/VERSION +0 -1
- data/bullet.gemspec +0 -67
- 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/rails/init.rb +0 -1
- data/spec/bullet/association_for_chris_spec.rb +0 -96
- data/spec/bullet/association_for_peschkaj_spec.rb +0 -86
- data/spec/bullet/association_spec.rb +0 -1043
- data/spec/bullet/counter_spec.rb +0 -136
- data/spec/spec.opts +0 -3
- data/spec/spec_helper.rb +0 -45
- data/tasks/bullet_tasks.rake +0 -9
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Bullet
|
|
2
|
+
module Notification
|
|
3
|
+
class Base
|
|
4
|
+
attr_accessor :notifier
|
|
5
|
+
attr_reader :base_class, :associations, :path
|
|
6
|
+
|
|
7
|
+
def initialize( base_class, associations, path = nil )
|
|
8
|
+
@base_class = base_class
|
|
9
|
+
@associations = associations.is_a?( Array ) ? associations : [ associations ]
|
|
10
|
+
@path = path
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def title
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def body_with_caller
|
|
20
|
+
body
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def standard_notice
|
|
24
|
+
@standard_notifice ||= title + "\n" + body
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def full_notice
|
|
28
|
+
@full_notice ||= title + "\n" + body_with_caller
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def notify_inline
|
|
32
|
+
self.notifier.inline_notify( self.full_notice )
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def notify_out_of_channel
|
|
36
|
+
self.notifier.out_of_channel_notify( self.full_notice )
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def eql?( other )
|
|
40
|
+
klazz_associations_str == other.klazz_associations_str
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def hash
|
|
44
|
+
klazz_associations_str.hash
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
protected
|
|
48
|
+
def klazz_associations_str
|
|
49
|
+
" #{@base_class} => [#{@associations.map(&:inspect).join(', ')}]"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def associations_str
|
|
53
|
+
":include => #{@associations.map{|a| a.to_s.to_sym unless a.is_a? Hash}.inspect}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Bullet
|
|
2
|
+
module Notification
|
|
3
|
+
class NPlusOneQuery < Base
|
|
4
|
+
def initialize( callers, base_class, associations, path = nil )
|
|
5
|
+
super( base_class, associations, path )
|
|
6
|
+
|
|
7
|
+
@callers = callers
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def body_with_caller
|
|
11
|
+
"#{body}\n#{call_stack_messages}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def body
|
|
15
|
+
"#{klazz_associations_str}\n Add to your finder: #{associations_str}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def title
|
|
19
|
+
"N+1 Query #{@path ? "in #{@path}" : 'detected'}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
protected
|
|
23
|
+
def call_stack_messages
|
|
24
|
+
@callers.collect do |c|
|
|
25
|
+
[ 'N+1 Query method call stack',
|
|
26
|
+
c.collect {|line| " #{line}"} ].flatten
|
|
27
|
+
end.join( "\n" )
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Bullet
|
|
2
|
+
module Notification
|
|
3
|
+
class UnusedEagerLoading < Base
|
|
4
|
+
def body
|
|
5
|
+
"#{klazz_associations_str}\n Remove from your finder: #{associations_str}"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def title
|
|
9
|
+
"Unused Eager Loading #{@path ? "in #{@path}" : 'detected'}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/bullet/notification.rb
CHANGED
|
@@ -1,83 +1,8 @@
|
|
|
1
1
|
module Bullet
|
|
2
|
-
class NotificationError < StandardError
|
|
3
|
-
end
|
|
4
|
-
|
|
5
2
|
module Notification
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def console_title
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def log_message(path = nil)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def javascript_notification
|
|
19
|
-
str = ''
|
|
20
|
-
if Bullet.alert || Bullet.console
|
|
21
|
-
response = notification_response
|
|
22
|
-
end
|
|
23
|
-
unless response.blank?
|
|
24
|
-
if Bullet.alert
|
|
25
|
-
str << wrap_js_association("alert(#{response.join("\n").inspect});")
|
|
26
|
-
end
|
|
27
|
-
if Bullet.console
|
|
28
|
-
code = <<-CODE
|
|
29
|
-
if (typeof(console) !== 'undefined') {
|
|
30
|
-
|
|
31
|
-
if (console.groupCollapsed && console.groupEnd && console.log) {
|
|
32
|
-
|
|
33
|
-
console.groupCollapsed(#{console_title.join(', ').inspect});
|
|
34
|
-
console.log(#{response.join("\n").inspect});
|
|
35
|
-
console.log(#{call_stack_messages.join("\n").inspect});
|
|
36
|
-
console.groupEnd();
|
|
37
|
-
|
|
38
|
-
} else if (console.log) {
|
|
39
|
-
|
|
40
|
-
console.log(#{response.join("\n").inspect});
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
CODE
|
|
44
|
-
str << wrap_js_association(code)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
str
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def growl_notification
|
|
51
|
-
if Bullet.growl
|
|
52
|
-
response = notification_response
|
|
53
|
-
unless response.blank?
|
|
54
|
-
begin
|
|
55
|
-
growl = Growl.new('localhost', 'ruby-growl', ['Bullet Notification'], nil, Bullet.growl_password)
|
|
56
|
-
growl.notify('Bullet Notification', 'Bullet Notification', response.join("\n"))
|
|
57
|
-
rescue
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def log_notification(path)
|
|
64
|
-
if Bullet.bullet_logger || Bullet.rails_logger
|
|
65
|
-
Rails.logger.warn '' if Bullet.rails_logger
|
|
66
|
-
messages = log_messages(path)
|
|
67
|
-
messages.each do |message|
|
|
68
|
-
Bullet.logger.info(message.join("\n")) if Bullet.bullet_logger
|
|
69
|
-
Rails.logger.warn(message.join("\n")) if Bullet.rails_logger
|
|
70
|
-
end
|
|
71
|
-
Bullet.logger_file.flush if Bullet.bullet_logger
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
private
|
|
76
|
-
def wrap_js_association(message)
|
|
77
|
-
str = ''
|
|
78
|
-
str << "<script type=\"text/javascript\">/*<![CDATA[*/"
|
|
79
|
-
str << message
|
|
80
|
-
str << "/*]]>*/</script>\n"
|
|
81
|
-
end
|
|
3
|
+
autoload :Base, 'bullet/notification/base'
|
|
4
|
+
autoload :UnusedEagerLoading, 'bullet/notification/unused_eager_loading'
|
|
5
|
+
autoload :NPlusOneQuery, 'bullet/notification/n_plus_one_query'
|
|
6
|
+
autoload :CounterCache, 'bullet/notification/counter_cache'
|
|
82
7
|
end
|
|
83
8
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
|
|
3
|
+
module Bullet
|
|
4
|
+
class NotificationCollector
|
|
5
|
+
attr_reader :collection
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
reset
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def reset
|
|
12
|
+
@collection = Set.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def add( value )
|
|
16
|
+
@collection << value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def notifications_present?
|
|
20
|
+
!@collection.empty?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
data/lib/bullet/rack.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Bullet
|
|
2
|
+
class Rack
|
|
3
|
+
def initialize(app)
|
|
4
|
+
@app = app
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def call(env)
|
|
8
|
+
return @app.call(env) unless Bullet.enable?
|
|
9
|
+
|
|
10
|
+
Bullet.start_request
|
|
11
|
+
status, headers, response = @app.call(env)
|
|
12
|
+
return [status, headers, response] if empty?(response)
|
|
13
|
+
|
|
14
|
+
if Bullet.notification?
|
|
15
|
+
if status == 200 and !response.body.frozen? and check_html?(headers, response)
|
|
16
|
+
response_body = response.body << Bullet.gather_inline_notifications
|
|
17
|
+
headers['Content-Length'] = response_body.length.to_s
|
|
18
|
+
end
|
|
19
|
+
Bullet.perform_out_of_channel_notifications
|
|
20
|
+
end
|
|
21
|
+
response_body ||= response.body
|
|
22
|
+
Bullet.end_request
|
|
23
|
+
no_browser_cache(headers) if Bullet.disable_browser_cache
|
|
24
|
+
[status, headers, [response_body]]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# fix issue if response's body is a Proc
|
|
28
|
+
def empty?(response)
|
|
29
|
+
# response may be ["Not Found"], ["Move Permanently"], etc.
|
|
30
|
+
(response.is_a?(Array) && response.size <= 1) ||
|
|
31
|
+
!response.body.is_a?(String) || response.body.empty?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def check_html?(headers, response)
|
|
35
|
+
headers['Content-Type'] and headers['Content-Type'].include? 'text/html' and response.body =~ %r{<html.*</html>}m
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def no_browser_cache(headers)
|
|
39
|
+
headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
|
|
40
|
+
headers["Pragma"] = "no-cache"
|
|
41
|
+
headers["Expires"] = "Wed, 09 Sep 2009 09:09:09 GMT"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Bullet
|
|
2
|
+
module Registry
|
|
3
|
+
class Association < Base
|
|
4
|
+
def merge( base, associations )
|
|
5
|
+
@registry.merge!( { base => associations } )
|
|
6
|
+
unique( @registry[base] )
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def similarly_associated( base, associations )
|
|
10
|
+
@registry.select do |key, value|
|
|
11
|
+
key.include?( base ) and value == associations
|
|
12
|
+
end.collect( &:first ).flatten!
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Bullet
|
|
2
|
+
module Registry
|
|
3
|
+
class Base
|
|
4
|
+
attr_reader :registry
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
@registry = {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def [](key)
|
|
11
|
+
@registry[key]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def each( &block )
|
|
15
|
+
@registry.each( &block )
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def delete( base )
|
|
19
|
+
@registry.delete( base )
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def select( *args, &block )
|
|
23
|
+
@registry.select( *args, &block )
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def add( key, value )
|
|
27
|
+
@registry[key] ||= []
|
|
28
|
+
@registry[key] << value
|
|
29
|
+
unique( @registry[key] )
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
def unique( array )
|
|
34
|
+
array.flatten!
|
|
35
|
+
array.uniq!
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Bullet
|
|
2
|
+
module Registry
|
|
3
|
+
class Object < Base
|
|
4
|
+
def add( object_or_objects )
|
|
5
|
+
klazz = object_or_objects.is_a?( Array ) ? object_or_objects.first.class :
|
|
6
|
+
object_or_objects.class
|
|
7
|
+
super( klazz, object_or_objects )
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def contains?( object )
|
|
11
|
+
@registry[object.class] and @registry[object.class].include?( object )
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/bullet.rb
CHANGED
|
@@ -1,31 +1,47 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'set'
|
|
2
|
+
require 'uniform_notifier'
|
|
2
3
|
|
|
3
4
|
module Bullet
|
|
5
|
+
class NotificationError < StandardError; end
|
|
6
|
+
|
|
4
7
|
if Rails.version =~ /^3.0/
|
|
5
8
|
autoload :ActiveRecord, 'bullet/active_record3'
|
|
6
9
|
else
|
|
7
10
|
autoload :ActiveRecord, 'bullet/active_record2'
|
|
8
11
|
autoload :ActionController, 'bullet/action_controller2'
|
|
9
12
|
end
|
|
10
|
-
autoload :
|
|
11
|
-
autoload :Counter, 'bullet/counter'
|
|
13
|
+
autoload :Rack, 'bullet/rack'
|
|
12
14
|
autoload :BulletLogger, 'bullet/logger'
|
|
13
15
|
autoload :Notification, 'bullet/notification'
|
|
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, :
|
|
30
|
+
attr_accessor :enable, :disable_browser_cache
|
|
31
|
+
attr_reader :notification_collector
|
|
32
|
+
|
|
33
|
+
delegate :alert=, :console=, :growl=, :rails_logger=, :xmpp=, :to => UniformNotifier
|
|
34
|
+
|
|
35
|
+
DETECTORS = [ Bullet::Detector::NPlusOneQuery,
|
|
36
|
+
Bullet::Detector::UnusedEagerAssociation,
|
|
37
|
+
Bullet::Detector::Counter ]
|
|
17
38
|
|
|
18
39
|
def enable=(enable)
|
|
19
40
|
@enable = enable
|
|
20
|
-
if enable?
|
|
41
|
+
if enable?
|
|
21
42
|
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/
|
|
43
|
+
if Rails.version =~ /^2./
|
|
26
44
|
Bullet::ActionController.enable
|
|
27
|
-
require 'action_controller/dispatcher'
|
|
28
|
-
::ActionController::Dispatcher.middleware.use Bulletware
|
|
29
45
|
end
|
|
30
46
|
end
|
|
31
47
|
end
|
|
@@ -34,54 +50,59 @@ module Bullet
|
|
|
34
50
|
@enable == true
|
|
35
51
|
end
|
|
36
52
|
|
|
37
|
-
def
|
|
38
|
-
if
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def bullet_logger=(bullet_logger)
|
|
51
|
-
if @bullet_logger = bullet_logger
|
|
52
|
-
@logger_file = File.open(Bullet::BulletLogger::LOG_FILE, 'a+')
|
|
53
|
-
@logger = Bullet::BulletLogger.new(@logger_file)
|
|
53
|
+
def bullet_logger=(active)
|
|
54
|
+
if active
|
|
55
|
+
bullet_log_file = File.open( 'log/bullet.log', 'a+' )
|
|
56
|
+
bullet_log_file.sync
|
|
57
|
+
UniformNotifier.customized_logger = bullet_log_file
|
|
54
58
|
end
|
|
55
59
|
end
|
|
56
60
|
|
|
57
|
-
BULLETS = [Bullet::Association, Bullet::Counter]
|
|
58
|
-
|
|
59
61
|
def start_request
|
|
60
|
-
|
|
62
|
+
notification_collector.reset
|
|
63
|
+
DETECTORS.each {|bullet| bullet.start_request}
|
|
61
64
|
end
|
|
62
65
|
|
|
63
66
|
def end_request
|
|
64
|
-
|
|
67
|
+
DETECTORS.each {|bullet| bullet.end_request}
|
|
65
68
|
end
|
|
66
|
-
|
|
69
|
+
|
|
67
70
|
def clear
|
|
68
|
-
|
|
71
|
+
DETECTORS.each {|bullet| bullet.clear}
|
|
69
72
|
end
|
|
70
73
|
|
|
71
|
-
def
|
|
72
|
-
|
|
74
|
+
def notification_collector
|
|
75
|
+
@notification_collector ||= Bullet::NotificationCollector.new
|
|
73
76
|
end
|
|
74
77
|
|
|
75
|
-
def
|
|
76
|
-
|
|
78
|
+
def notification?
|
|
79
|
+
Bullet::Detector::UnusedEagerAssociation.check_unused_preload_associations
|
|
80
|
+
notification_collector.notifications_present?
|
|
77
81
|
end
|
|
78
82
|
|
|
79
|
-
def
|
|
80
|
-
|
|
83
|
+
def gather_inline_notifications
|
|
84
|
+
responses = []
|
|
85
|
+
for_each_active_notifier_with_notification do |notification|
|
|
86
|
+
responses << notification.notify_inline
|
|
87
|
+
end
|
|
88
|
+
responses.join( "\n" )
|
|
81
89
|
end
|
|
82
90
|
|
|
83
|
-
def
|
|
84
|
-
|
|
91
|
+
def perform_out_of_channel_notifications
|
|
92
|
+
for_each_active_notifier_with_notification do |notification|
|
|
93
|
+
notification.notify_out_of_channel
|
|
94
|
+
end
|
|
85
95
|
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
def for_each_active_notifier_with_notification
|
|
99
|
+
UniformNotifier.active_notifiers.each do |notifier|
|
|
100
|
+
notification_collector.collection.each do |notification|
|
|
101
|
+
notification.notifier = notifier
|
|
102
|
+
yield notification
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
86
106
|
end
|
|
107
|
+
|
|
87
108
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bullet
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
|
|
4
|
+
hash: 13
|
|
5
|
+
prerelease: false
|
|
5
6
|
segments:
|
|
6
7
|
- 2
|
|
7
8
|
- 0
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
- 2
|
|
11
|
-
version: 2.0.0.beta.2
|
|
9
|
+
- 1
|
|
10
|
+
version: 2.0.1
|
|
12
11
|
platform: ruby
|
|
13
12
|
authors:
|
|
14
13
|
- Richard Huang
|
|
@@ -16,78 +15,97 @@ autorequire:
|
|
|
16
15
|
bindir: bin
|
|
17
16
|
cert_chain: []
|
|
18
17
|
|
|
19
|
-
date: 2010-
|
|
18
|
+
date: 2010-11-19 00:00:00 +08:00
|
|
20
19
|
default_executable:
|
|
21
|
-
dependencies:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
dependencies:
|
|
21
|
+
- !ruby/object:Gem::Dependency
|
|
22
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
|
23
|
+
none: false
|
|
24
|
+
requirements:
|
|
25
|
+
- - ~>
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
hash: 23
|
|
28
|
+
segments:
|
|
29
|
+
- 1
|
|
30
|
+
- 0
|
|
31
|
+
- 0
|
|
32
|
+
version: 1.0.0
|
|
33
|
+
requirement: *id001
|
|
34
|
+
name: uniform_notifier
|
|
35
|
+
prerelease: false
|
|
36
|
+
type: :runtime
|
|
37
|
+
description: A rails plugin to kill N+1 queries and unused eager loading.
|
|
38
|
+
email:
|
|
39
|
+
- flyerhzm@gmail.com
|
|
25
40
|
executables: []
|
|
26
41
|
|
|
27
42
|
extensions: []
|
|
28
43
|
|
|
29
44
|
extra_rdoc_files:
|
|
30
|
-
- README.textile
|
|
31
|
-
- README_for_rails2.textile
|
|
32
|
-
files:
|
|
33
45
|
- MIT-LICENSE
|
|
34
46
|
- README.textile
|
|
35
47
|
- README_for_rails2.textile
|
|
36
|
-
|
|
37
|
-
- VERSION
|
|
38
|
-
- bullet.gemspec
|
|
39
|
-
- lib/bullet.rb
|
|
48
|
+
files:
|
|
40
49
|
- lib/bullet/action_controller2.rb
|
|
41
50
|
- lib/bullet/active_record2.rb
|
|
42
51
|
- lib/bullet/active_record3.rb
|
|
43
|
-
- lib/bullet/association.rb
|
|
44
|
-
- lib/bullet/
|
|
45
|
-
- lib/bullet/
|
|
52
|
+
- lib/bullet/detector/association.rb
|
|
53
|
+
- lib/bullet/detector/base.rb
|
|
54
|
+
- lib/bullet/detector/counter.rb
|
|
55
|
+
- lib/bullet/detector/n_plus_one_query.rb
|
|
56
|
+
- lib/bullet/detector/unused_eager_association.rb
|
|
57
|
+
- lib/bullet/detector.rb
|
|
58
|
+
- lib/bullet/notification/base.rb
|
|
59
|
+
- lib/bullet/notification/counter_cache.rb
|
|
60
|
+
- lib/bullet/notification/n_plus_one_query.rb
|
|
61
|
+
- lib/bullet/notification/unused_eager_loading.rb
|
|
46
62
|
- lib/bullet/notification.rb
|
|
47
|
-
- lib/
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
63
|
+
- lib/bullet/notification_collector.rb
|
|
64
|
+
- lib/bullet/rack.rb
|
|
65
|
+
- lib/bullet/registry/association.rb
|
|
66
|
+
- lib/bullet/registry/base.rb
|
|
67
|
+
- lib/bullet/registry/object.rb
|
|
68
|
+
- lib/bullet/registry.rb
|
|
69
|
+
- lib/bullet/version.rb
|
|
70
|
+
- lib/bullet.rb
|
|
71
|
+
- MIT-LICENSE
|
|
72
|
+
- README.textile
|
|
73
|
+
- README_for_rails2.textile
|
|
56
74
|
has_rdoc: true
|
|
57
75
|
homepage: http://github.com/flyerhzm/bullet
|
|
58
76
|
licenses: []
|
|
59
77
|
|
|
60
78
|
post_install_message:
|
|
61
|
-
rdoc_options:
|
|
62
|
-
|
|
79
|
+
rdoc_options: []
|
|
80
|
+
|
|
63
81
|
require_paths:
|
|
64
82
|
- lib
|
|
65
83
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
84
|
+
none: false
|
|
66
85
|
requirements:
|
|
67
86
|
- - ">="
|
|
68
87
|
- !ruby/object:Gem::Version
|
|
88
|
+
hash: 3
|
|
69
89
|
segments:
|
|
70
90
|
- 0
|
|
71
91
|
version: "0"
|
|
72
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
|
+
none: false
|
|
73
94
|
requirements:
|
|
74
|
-
- - "
|
|
95
|
+
- - ">="
|
|
75
96
|
- !ruby/object:Gem::Version
|
|
97
|
+
hash: 23
|
|
76
98
|
segments:
|
|
77
99
|
- 1
|
|
78
100
|
- 3
|
|
79
|
-
-
|
|
80
|
-
version: 1.3.
|
|
101
|
+
- 6
|
|
102
|
+
version: 1.3.6
|
|
81
103
|
requirements: []
|
|
82
104
|
|
|
83
105
|
rubyforge_project:
|
|
84
|
-
rubygems_version: 1.3.
|
|
106
|
+
rubygems_version: 1.3.7
|
|
85
107
|
signing_key:
|
|
86
108
|
specification_version: 3
|
|
87
|
-
summary: A plugin to kill N+1 queries and unused eager loading
|
|
88
|
-
test_files:
|
|
89
|
-
|
|
90
|
-
- spec/bullet/counter_spec.rb
|
|
91
|
-
- spec/bullet/association_spec.rb
|
|
92
|
-
- spec/bullet/association_for_chris_spec.rb
|
|
93
|
-
- spec/bullet/association_for_peschkaj_spec.rb
|
|
109
|
+
summary: A rails plugin to kill N+1 queries and unused eager loading.
|
|
110
|
+
test_files: []
|
|
111
|
+
|