lib/bullet/association.rb in flyerhzm-bullet-1.4.0 vs lib/bullet/association.rb in flyerhzm-bullet-1.4.1
- old
+ new
@@ -9,37 +9,17 @@
@@console = nil
@@growl = nil
@@growl_password = nil
@@rails_logger = nil
- def start_request
- # puts "start request"
- end
-
- def end_request
- # puts "end request"
- @@object_associations = nil
- @@unpreload_associations = nil
- @@unused_preload_associations = nil
- @@callers = nil
- @@possible_objects = nil
- @@impossible_objects = nil
- @@call_object_associations = nil
- @@eager_loadings = nil
- end
-
+ ###################################################
+ # Configurations
+ ###################################################
def alert=(alert)
@@alert = alert
end
- def bullet_logger=(bullet_logger)
- if @@bullet_logger = bullet_logger
- @@logger_file = File.open(Bullet::BulletLogger::LOG_FILE, 'a+')
- @@logger = Bullet::BulletLogger.new(@@logger_file)
- end
- end
-
def console=(console)
@@console = console
end
def growl=(growl)
@@ -57,50 +37,81 @@
def growl_password=(growl_password)
@@growl_password = growl_password
end
+ def bullet_logger=(bullet_logger)
+ if @@bullet_logger = bullet_logger
+ @@logger_file = File.open(Bullet::BulletLogger::LOG_FILE, 'a+')
+ @@logger = Bullet::BulletLogger.new(@@logger_file)
+ end
+ end
+
def rails_logger=(rails_logger)
@@rails_logger = rails_logger
end
- def check_unused_preload_associations
- object_associations.each do |object, association|
- related_objects = eager_loadings.select {|key, value| key.include?(object) and value == association}.collect(&:first).flatten
- call_object_association = related_objects.collect { |related_object| call_object_associations[related_object] }.compact.flatten.uniq
- diff_object_association = (association - call_object_association).reject {|a| a.is_a? Hash}
- add_unused_preload_associations(object.class, diff_object_association) unless diff_object_association.empty?
- end
+ #####################################################
+ # login control interface
+ #####################################################
+ def start_request
+ # puts "start request"
end
-
+
+ def end_request
+ # puts "end request"
+ @@object_associations = nil
+ @@unpreload_associations = nil
+ @@unused_preload_associations = nil
+ @@callers = nil
+ @@possible_objects = nil
+ @@impossible_objects = nil
+ @@call_object_associations = nil
+ @@eager_loadings = nil
+ end
+
def has_bad_assocations?
check_unused_preload_associations
has_unpreload_associations? or has_unused_preload_associations?
end
- def has_unused_preload_associations?
- !unused_preload_associations.empty?
- end
-
- def has_unpreload_associations?
- !unpreload_associations.empty?
- end
-
+ ######################################################
+ # Notifications
+ ######################################################
def javascript_notification
str = ''
if @@alert || @@console
response = notification_response
end
if @@alert
str << wrap_js_association("alert(#{response.join("\n").inspect});")
end
if @@console
- str << wrap_js_association("if (typeof(console) != 'undefined' && console.log) console.log(#{response.join("\n").inspect});")
+ title = []
+ title << unused_preload_messages.first.first unless unused_preload_messages.empty?
+ title << unpreload_messages.first.first unless unpreload_messages.empty?
+ code = <<-CODE
+ if (typeof(console) !== 'undefined') {
+
+ if (console.groupCollapsed && console.groupEnd && console.log) {
+
+ console.groupCollapsed(#{title.join(', ').inspect});
+ console.log(#{response.join("\n").inspect});
+ console.log(#{call_stack_messages.join("\n").inspect});
+ console.groupEnd();
+
+ } else if (console.log) {
+
+ console.log(#{response.join("\n").inspect});
+ }
+ }
+ CODE
+ str << wrap_js_association(code)
end
str
end
-
+
def growl_notification
if @@growl
response = notification_response
begin
growl = Growl.new('localhost', 'ruby-growl', ['Bullet Notification'], nil, @@growl_password)
@@ -111,89 +122,33 @@
end
def log_notificatioin(path)
if (@@bullet_logger || @@rails_logger) && (!unpreload_associations.empty? || !unused_preload_associations.empty?)
Rails.logger.warn '' if @@rails_logger
- unused_preload_associations.each do |klazz, associations|
- log = ["Unused eager loadings: #{path}", klazz_associations_str(klazz, associations), " Remove from your finder: #{associations_str(associations)}"].join("\n")
- @@logger.info(log) if @@bullet_logger
- Rails.logger.warn(log) if @@rails_logger
+ unused_preload_messages(path).each do |message|
+ @@logger.info(message.join("\n")) if @@bullet_logger
+ Rails.logger.warn(message.join("\n")) if @@rails_logger
end
- unpreload_associations.each do |klazz, associations|
- log = ["N+1 Query in #{path}", klazz_associations_str(klazz, associations), " Add to your finder: #{associations_str(associations)}"].join("\n")
- @@logger.info(log) if @@bullet_logger
- Rails.logger.warn(log) if @@rails_logger
- end
- callers.each do |c|
- log = ["N+1 Query method call stack", c.map{|line| " #{line}"}].flatten.join("\n")
- @@logger.info(log) if @@bullet_logger
- Rails.logger.warn(log) if @@rails_logger
+ unpreload_messages(path).each do |message|
+ @@logger.info(message.join("\n")) if @@bullet_logger
+ Rails.logger.warn(message.join("\n")) if @@rails_logger
end
+ call_stack_messages.each do |message|
+ @@logger.info(message.join("\n")) if @@bullet_logger
+ Rails.logger.warn(message.join("\n")) if @@rails_logger
+ end
@@logger_file.flush if @@bullet_logger
end
end
-
- def klazz_associations_str(klazz, associations)
- " #{klazz} => [#{associations.map(&:inspect).join(', ')}]"
- end
-
- def associations_str(associations)
- ":include => #{associations.map{|a| a.to_sym unless a.is_a? Hash}.inspect}"
- end
- def notification_response
- response = []
- if has_unused_preload_associations?
- response.push("Unused eager loadings detected:\n")
- response.push(*@@unused_preload_associations.to_a.collect{|klazz, associations| klazz_associations_str(klazz, associations)}.join("\n"))
- end
- if has_unpreload_associations?
- response.push("#{"\n" unless response.empty?}N+1 queries detected:\n")
- response.push(*@@unpreload_associations.to_a.collect{|klazz, associations| " #{klazz} => [#{associations.map(&:inspect).join(', ')}]"}.join("\n"))
- end
- response
- end
-
- def wrap_js_association(message)
- str = ''
- str << "<script type=\"text/javascript\">/*<![CDATA[*/"
- str << message
- str << "/*]]>*/</script>\n"
- end
-
- def has_klazz_association(klazz)
- !klazz_associations[klazz].nil? and klazz_associations.keys.include?(klazz)
- end
-
- def define_association(klazz, associations)
- # puts "define association, #{klazz} => #{associations.inspect}"
- add_klazz_associations(klazz, associations)
- end
-
- def call_association(object, associations)
- # puts "call association, #{object} => #{associations.inspect}"
- add_call_object_associations(object, associations)
- if unpreload_associations?(object, associations)
- add_unpreload_associations(object.class, associations)
- caller_in_project
- end
- end
-
- def unpreload_associations?(object, associations)
- klazz = object.class
- (!possible_objects[klazz].nil? and possible_objects[klazz].include?(object)) and
- (impossible_objects[klazz].nil? or !impossible_objects[klazz].include?(object)) and
- (object_associations[object].nil? or !object_associations[object].include?(associations))
- end
-
def add_unpreload_associations(klazz, associations)
# puts "add unpreload associations, #{klazz} => #{associations.inspect}"
unpreload_associations[klazz] ||= []
unpreload_associations[klazz] << associations
unique(unpreload_associations[klazz])
end
-
+
def add_unused_preload_associations(klazz, associations)
# puts "add unused preload associations, #{klazz} => #{associations.inspect}"
unused_preload_associations[klazz] ||= []
unused_preload_associations[klazz] << associations
unique(unused_preload_associations[klazz])
@@ -204,10 +159,13 @@
object_associations[object] ||= []
object_associations[object] << associations
unique(object_associations[object])
end
+ ###################################################
+ # interface for active record
+ ###################################################
def add_call_object_associations(object, associations)
# puts "add call object associations, #{object} => #{associations.inspect}"
call_object_associations[object] ||= []
call_object_associations[object] << associations
unique(call_object_associations[object])
@@ -226,11 +184,11 @@
klazz = object.class
impossible_objects[klazz] ||= []
impossible_objects[klazz] << object
impossible_objects[klazz].uniq!
end
-
+
def add_klazz_associations(klazz, associations)
# puts "define associations, #{klazz} => #{associations.inspect}"
klazz_associations[klazz] ||= []
klazz_associations[klazz] << associations
unique(klazz_associations[klazz])
@@ -241,53 +199,152 @@
objects = Array(objects)
eager_loadings[objects] ||= []
eager_loadings[objects] << associations
unique(eager_loadings[objects])
end
+
+ def define_association(klazz, associations)
+ # puts "define association, #{klazz} => #{associations.inspect}"
+ add_klazz_associations(klazz, associations)
+ end
+
+ def call_association(object, associations)
+ # puts "call association, #{object} => #{associations.inspect}"
+ add_call_object_associations(object, associations)
+ if unpreload_associations?(object, associations)
+ add_unpreload_associations(object.class, associations)
+ caller_in_project
+ end
+ end
+
+ ############################################
+ # for rspec
+ ############################################
+ def check_unused_preload_associations
+ object_associations.each do |object, association|
+ related_objects = eager_loadings.select {|key, value| key.include?(object) and value == association}.collect(&:first).flatten
+ call_object_association = related_objects.collect { |related_object| call_object_associations[related_object] }.compact.flatten.uniq
+ diff_object_association = (association - call_object_association).reject {|a| a.is_a? Hash}
+ add_unused_preload_associations(object.class, diff_object_association) unless diff_object_association.empty?
+ end
+ end
+
+ def has_unused_preload_associations?
+ !unused_preload_associations.empty?
+ end
+
+ def has_unpreload_associations?
+ !unpreload_associations.empty?
+ end
+
+
+ private
+ def unpreload_associations?(object, associations)
+ klazz = object.class
+ (!possible_objects[klazz].nil? and possible_objects[klazz].include?(object)) and
+ (impossible_objects[klazz].nil? or !impossible_objects[klazz].include?(object)) and
+ (object_associations[object].nil? or !object_associations[object].include?(associations))
+ end
+
+ def notification_response
+ response = []
+ if has_unused_preload_associations?
+ response << unused_preload_messages.join("\n")
+ end
+ if has_unpreload_associations?
+ response << unpreload_messages.join("\n")
+ end
+ response
+ end
+
+ def unused_preload_messages(path = nil)
+ messages = []
+ unused_preload_associations.each do |klazz, associations|
+ messages << [
+ "Unused Eager Loading #{path ? "in #{path}" : 'detected'}",
+ klazz_associations_str(klazz, associations),
+ " Remove from your finder: #{associations_str(associations)}"
+ ]
+ end
+ messages
+ end
+
+ def unpreload_messages(path = nil)
+ messages = []
+ unpreload_associations.each do |klazz, associations|
+ messages << [
+ "N+1 Query #{path ? "in #{path}" : 'detected'}",
+ klazz_associations_str(klazz, associations),
+ " Add to your finder: #{associations_str(associations)}"
+ ]
+ end
+ messages
+ end
+
+ def klazz_associations_str(klazz, associations)
+ " #{klazz} => [#{associations.map(&:inspect).join(', ')}]"
+ end
+
+ def associations_str(associations)
+ ":include => #{associations.map{|a| a.to_sym unless a.is_a? Hash}.inspect}"
+ end
+
+ def wrap_js_association(message)
+ str = ''
+ str << "<script type=\"text/javascript\">/*<![CDATA[*/"
+ str << message
+ str << "/*]]>*/</script>\n"
+ end
+
+ def call_stack_messages
+ callers.inject([]) do |messages, c|
+ messages << ['N+1 Query method call stack', c.collect {|line| " #{line}"}].flatten
+ end
+ end
def unique(array)
array.flatten!
array.uniq!
end
-
+
def unpreload_associations
@@unpreload_associations ||= {}
end
-
+
def unused_preload_associations
@@unused_preload_associations ||= {}
end
-
+
def object_associations
@@object_associations ||= {}
end
-
+
def call_object_associations
@@call_object_associations ||= {}
end
-
+
def possible_objects
@@possible_objects ||= {}
end
def impossible_objects
@@impossible_objects ||= {}
end
-
+
def klazz_associations
@@klazz_associations ||= {}
end
def eager_loadings
@@eager_loadings ||= {}
end
-
+
VENDOR_ROOT = File.join(RAILS_ROOT, 'vendor')
def caller_in_project
callers << caller.select {|c| c =~ /#{RAILS_ROOT}/}.reject {|c| c =~ /#{VENDOR_ROOT}/}
callers.uniq!
end
-
+
def callers
@@callers ||= []
end
end
end