gentooboontoo-rack-bug 0.3.0.edge

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.
Files changed (92) hide show
  1. data/.gitignore +3 -0
  2. data/History.txt +46 -0
  3. data/MIT-LICENSE.txt +19 -0
  4. data/README.md +120 -0
  5. data/Rakefile +23 -0
  6. data/Thorfile +113 -0
  7. data/lib/rack/bug/autoloading.rb +25 -0
  8. data/lib/rack/bug/filtered_backtrace.rb +38 -0
  9. data/lib/rack/bug/options.rb +89 -0
  10. data/lib/rack/bug/panel.rb +50 -0
  11. data/lib/rack/bug/panel_app.rb +33 -0
  12. data/lib/rack/bug/panels/active_record_panel/activerecord_extensions.rb +18 -0
  13. data/lib/rack/bug/panels/active_record_panel.rb +45 -0
  14. data/lib/rack/bug/panels/cache_panel/dalli_extension.rb +16 -0
  15. data/lib/rack/bug/panels/cache_panel/memcache_extension.rb +129 -0
  16. data/lib/rack/bug/panels/cache_panel/panel_app.rb +48 -0
  17. data/lib/rack/bug/panels/cache_panel/stats.rb +97 -0
  18. data/lib/rack/bug/panels/cache_panel.rb +51 -0
  19. data/lib/rack/bug/panels/log_panel/logger_extension.rb +24 -0
  20. data/lib/rack/bug/panels/log_panel.rb +56 -0
  21. data/lib/rack/bug/panels/memory_panel.rb +27 -0
  22. data/lib/rack/bug/panels/mongo_panel/mongo_extension.rb +27 -0
  23. data/lib/rack/bug/panels/mongo_panel/stats.rb +48 -0
  24. data/lib/rack/bug/panels/mongo_panel.rb +44 -0
  25. data/lib/rack/bug/panels/rails_info_panel.rb +23 -0
  26. data/lib/rack/bug/panels/redis_panel/redis_extension.rb +28 -0
  27. data/lib/rack/bug/panels/redis_panel/stats.rb +52 -0
  28. data/lib/rack/bug/panels/redis_panel.rb +44 -0
  29. data/lib/rack/bug/panels/request_variables_panel.rb +52 -0
  30. data/lib/rack/bug/panels/sphinx_panel/sphinx_extension.rb +25 -0
  31. data/lib/rack/bug/panels/sphinx_panel/stats.rb +96 -0
  32. data/lib/rack/bug/panels/sphinx_panel.rb +44 -0
  33. data/lib/rack/bug/panels/sql_panel/panel_app.rb +37 -0
  34. data/lib/rack/bug/panels/sql_panel/query.rb +63 -0
  35. data/lib/rack/bug/panels/sql_panel/sql_extension.rb +11 -0
  36. data/lib/rack/bug/panels/sql_panel.rb +55 -0
  37. data/lib/rack/bug/panels/templates_panel/actionview_extension.rb +12 -0
  38. data/lib/rack/bug/panels/templates_panel/rendering.rb +67 -0
  39. data/lib/rack/bug/panels/templates_panel/trace.rb +34 -0
  40. data/lib/rack/bug/panels/templates_panel.rb +47 -0
  41. data/lib/rack/bug/panels/timer_panel.rb +40 -0
  42. data/lib/rack/bug/params_signature.rb +63 -0
  43. data/lib/rack/bug/public/__rack_bug__/bookmarklet.html +10 -0
  44. data/lib/rack/bug/public/__rack_bug__/bookmarklet.js +217 -0
  45. data/lib/rack/bug/public/__rack_bug__/bug.css +220 -0
  46. data/lib/rack/bug/public/__rack_bug__/bug.js +84 -0
  47. data/lib/rack/bug/public/__rack_bug__/jquery-1.3.2.js +4376 -0
  48. data/lib/rack/bug/public/__rack_bug__/jquery.tablesorter.min.js +1 -0
  49. data/lib/rack/bug/public/__rack_bug__/spinner.gif +0 -0
  50. data/lib/rack/bug/rack_static_bug_avoider.rb +16 -0
  51. data/lib/rack/bug/redirect_interceptor.rb +27 -0
  52. data/lib/rack/bug/render.rb +67 -0
  53. data/lib/rack/bug/toolbar.rb +64 -0
  54. data/lib/rack/bug/views/error.html.erb +16 -0
  55. data/lib/rack/bug/views/panels/active_record.html.erb +17 -0
  56. data/lib/rack/bug/views/panels/cache.html.erb +93 -0
  57. data/lib/rack/bug/views/panels/execute_sql.html.erb +38 -0
  58. data/lib/rack/bug/views/panels/explain_sql.html.erb +38 -0
  59. data/lib/rack/bug/views/panels/log.html.erb +21 -0
  60. data/lib/rack/bug/views/panels/mongo.html.erb +32 -0
  61. data/lib/rack/bug/views/panels/profile_sql.html.erb +38 -0
  62. data/lib/rack/bug/views/panels/rails_info.html.erb +19 -0
  63. data/lib/rack/bug/views/panels/redis.html.erb +46 -0
  64. data/lib/rack/bug/views/panels/request_variables.html.erb +29 -0
  65. data/lib/rack/bug/views/panels/sphinx.html.erb +32 -0
  66. data/lib/rack/bug/views/panels/sql.html.erb +41 -0
  67. data/lib/rack/bug/views/panels/templates.html.erb +7 -0
  68. data/lib/rack/bug/views/panels/timer.html.erb +19 -0
  69. data/lib/rack/bug/views/panels/view_cache.html.erb +19 -0
  70. data/lib/rack/bug/views/redirect.html.erb +16 -0
  71. data/lib/rack/bug/views/toolbar.html.erb +42 -0
  72. data/lib/rack/bug.rb +82 -0
  73. data/rack-bug.gemspec +155 -0
  74. data/spec/custom_matchers.rb +21 -0
  75. data/spec/fixtures/config.ru +8 -0
  76. data/spec/fixtures/dummy_panel.rb +2 -0
  77. data/spec/fixtures/sample_app.rb +46 -0
  78. data/spec/rack/bug/panels/active_record_panel_spec.rb +30 -0
  79. data/spec/rack/bug/panels/cache_panel_spec.rb +167 -0
  80. data/spec/rack/bug/panels/log_panel_spec.rb +43 -0
  81. data/spec/rack/bug/panels/memory_panel_spec.rb +22 -0
  82. data/spec/rack/bug/panels/mongo_panel_spec.rb +51 -0
  83. data/spec/rack/bug/panels/rails_info_panel_spec.rb +40 -0
  84. data/spec/rack/bug/panels/redis_panel_spec.rb +69 -0
  85. data/spec/rack/bug/panels/sql_panel_spec.rb +146 -0
  86. data/spec/rack/bug/panels/templates_panel_spec.rb +71 -0
  87. data/spec/rack/bug/panels/timer_panel_spec.rb +38 -0
  88. data/spec/rack/bug_spec.rb +137 -0
  89. data/spec/rcov.opts +1 -0
  90. data/spec/spec.opts +1 -0
  91. data/spec/spec_helper.rb +44 -0
  92. metadata +245 -0
@@ -0,0 +1 @@
1
+ (function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'.',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,cells[i]);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,node){var l=parsers.length;for(var i=1;i<l;i++){if(parsers[i].is($.trim(getElementText(table.config,node)),table,node)){return parsers[i];}}return parsers[0];}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=table.tBodies[0].rows[i],cols=[];cache.row.push($(c));for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));}cols.push(i);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){if(!node)return"";var t="";if(config.textExtraction=="simple"){if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){t=node.childNodes[0].innerHTML;}else{t=node.innerHTML;}}else{if(typeof(config.textExtraction)=="function"){t=config.textExtraction(node);}else{t=$(node).text();}}return t;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){rows.push(r[n[i][checkCell]]);if(!table.config.appender){var o=r[n[i][checkCell]];var l=o.length;for(var j=0;j<l;j++){tableBody[0].appendChild(o[j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false,tableHeadersRows=[];for(var i=0;i<table.tHead.rows.length;i++){tableHeadersRows[i]=0;};$tableHeaders=$("thead th",table);$tableHeaders.each(function(index){this.count=0;this.column=index;this.order=formatSortingOrder(table.config.sortInitialOrder);if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(!this.sortDisabled){$(this).addClass(table.config.cssHeader);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){i=(v.toLowerCase()=="desc")?1:0;}else{i=(v==(0||1))?v:0;}return i;}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(getCachedSortType(table.config.parsers,c)=="text")?((order==0)?"sortText":"sortTextDesc"):((order==0)?"sortNumeric":"sortNumericDesc");var e="e"+i;dynamicExp+="var "+e+" = "+s+"(a["+c+"],b["+c+"]); ";dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function sortText(a,b){return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){$this.trigger("sortStart");var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){var $cell=$(this);var i=this.column;this.order=this.count++%2;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){var DECIMAL='\\'+config.decimal;var exp='/(^[+]?0('+DECIMAL+'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)'+DECIMAL+'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*'+DECIMAL+'0+$)/';return RegExp(exp).test($.trim(s));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}$("tr:visible",table.tBodies[0]).filter(':even').removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0]).end().filter(':odd').removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery);
@@ -0,0 +1,16 @@
1
+ class Rack::Bug
2
+ class RackStaticBugAvoider
3
+ def initialize(app, static_app)
4
+ @app = app
5
+ @static_app = static_app
6
+ end
7
+
8
+ def call(env)
9
+ if env["PATH_INFO"]
10
+ @static_app.call(env)
11
+ else
12
+ @app.call(env)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ module Rack
2
+ class Bug
3
+ class RedirectInterceptor
4
+ include Render
5
+
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ status, headers, body = @app.call(env)
12
+ @response = Rack::Response.new(body, status, headers)
13
+ if @response.redirect? && env["rack-bug.intercept_redirects"]
14
+ intercept_redirect
15
+ end
16
+ @response.to_a
17
+ end
18
+
19
+ def intercept_redirect
20
+ new_body = render_template("redirect", :redirect_to => @response.location)
21
+ new_headers = { "Content-Type" => "text/html", "Content-Length" => new_body.size.to_s }
22
+ @response = Rack::Response.new(new_body, 200, new_headers)
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+ require "erb"
3
+
4
+ module Rack
5
+ class Bug
6
+
7
+ module Render
8
+ include ERB::Util
9
+
10
+ def signed_params(hash)
11
+ ParamsSignature.sign(request, hash)
12
+ end
13
+
14
+ module CompiledTemplates
15
+ end
16
+ include CompiledTemplates
17
+
18
+ def render_template(filename, local_assigns = {})
19
+ compile(filename, local_assigns)
20
+ render_symbol = method_name(filename, local_assigns)
21
+ send(render_symbol, local_assigns)
22
+ end
23
+
24
+ def compile(filename, local_assigns)
25
+ render_symbol = method_name(filename, local_assigns)
26
+
27
+ if !CompiledTemplates.instance_methods.include?(render_symbol.to_s)
28
+ compile!(filename, local_assigns)
29
+ end
30
+ end
31
+
32
+ def compile!(filename, local_assigns)
33
+ render_symbol = method_name(filename, local_assigns)
34
+ locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
35
+
36
+ source = <<-end_src
37
+ def #{render_symbol}(local_assigns)
38
+ #{locals_code}
39
+ #{compiled_source(filename)}
40
+ end
41
+ end_src
42
+
43
+ CompiledTemplates.module_eval(source, filename, 0)
44
+ end
45
+
46
+ def compiled_source(filename)
47
+ ::ERB.new(::File.read(::File.dirname(__FILE__) + "/../bug/views/#{filename}.html.erb"), nil, "-").src
48
+ end
49
+
50
+ def method_name(filename, local_assigns)
51
+ if local_assigns && local_assigns.any?
52
+ method_name = method_name_without_locals(filename).dup
53
+ method_name << "_locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
54
+ else
55
+ method_name = method_name_without_locals(filename)
56
+ end
57
+ method_name.to_sym
58
+ end
59
+
60
+ def method_name_without_locals(filename)
61
+ filename.split("/").join("_")
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,64 @@
1
+ module Rack
2
+ class Bug
3
+ class Toolbar
4
+ include Render
5
+
6
+ MIME_TYPES = ["text/html", "application/xhtml+xml"]
7
+
8
+ def initialize(app)
9
+ @app = app
10
+ end
11
+
12
+ def call(env)
13
+ @env = env
14
+ @env["rack-bug.panels"] = []
15
+
16
+ Rack::Bug.enable
17
+ status, headers, body = builder.call(@env)
18
+ Rack::Bug.disable
19
+
20
+ @response = Rack::Response.new(body, status, headers)
21
+
22
+ inject_toolbar if response_type_okay_to_modify?
23
+
24
+ return @response.to_a
25
+ end
26
+
27
+ def response_type_okay_to_modify?
28
+ content_type, charset = @response.content_type.split(";")
29
+ @response.ok? && MIME_TYPES.include?(content_type)
30
+ end
31
+
32
+ def builder
33
+ builder = Rack::Builder.new
34
+
35
+ @env["rack-bug.panel_classes"].each do |panel_class|
36
+ builder.use panel_class
37
+ end
38
+
39
+ builder.run @app
40
+
41
+ return builder
42
+ end
43
+
44
+ def inject_toolbar
45
+ full_body = @response.body.join
46
+ full_body.sub! /<\/body>/, render + "</body>"
47
+
48
+ @response["Content-Length"] = full_body.size.to_s
49
+
50
+ # Ensure that browser does
51
+ @response["Etag"] = ""
52
+ @response["Cache-Control"] = "no-cache"
53
+
54
+ @response.body = [full_body]
55
+ end
56
+
57
+ def render
58
+ render_template("toolbar", :panels => @env["rack-bug.panels"].reverse)
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,16 @@
1
+ <script type="text/javascript" charset="utf-8">
2
+ if (typeof jQuery == 'undefined') {
3
+ var jquery_url = '/__rack_bug__/jquery-1.3.2.js';
4
+ document.write(unescape('%3Cscript src="' + jquery_url + '" type="text/javascript"%3E%3C/script%3E'));
5
+ }
6
+ </script>
7
+ <script type="text/javascript" src="/__rack_bug__/bug.js"></script>
8
+ <style type="text/css" media="screen">
9
+ @import url(/__rack_bug__/bug.css);
10
+ </style>
11
+
12
+ <div id="rack_bug" class="rack_bug_error">
13
+ <div id="rack_bug_toolbar">
14
+ <p>There was an error within Rack::Bug!</p>
15
+ </div>
16
+ </div>
@@ -0,0 +1,17 @@
1
+ <h3>ActiveRecord Objects</h3>
2
+ <table class="sortable">
3
+ <thead>
4
+ <tr>
5
+ <th>Count</th>
6
+ <th>Class</th>
7
+ </tr>
8
+ </thead>
9
+ <tbody>
10
+ <% records.each do |class_name, count| %>
11
+ <tr>
12
+ <td><%= count %></td>
13
+ <td><%= class_name %></td>
14
+ </tr>
15
+ <% end %>
16
+ </tbody>
17
+ </table>
@@ -0,0 +1,93 @@
1
+ <h3>Cache Usage</h3>
2
+ <table id="cache_usage">
3
+ <colgroup>
4
+ <col width="12%"/>
5
+ <col width="12%"/>
6
+ <col width="12%"/>
7
+ <col width="12%"/>
8
+ <col width="12%"/>
9
+ <col width="12%"/>
10
+ <col width="12%"/>
11
+ <col width="12%"/>
12
+ </colgroup>
13
+ <tr>
14
+ <th>Total Calls</th>
15
+ <td><%= stats.calls %></td>
16
+
17
+ <th>Total Time</th>
18
+ <td><%= stats.display_time %></td>
19
+
20
+ <th>Hits</th>
21
+ <td><%= stats.hits %></td>
22
+
23
+ <th>Misses</th>
24
+ <td><%= stats.misses %></td>
25
+ </tr>
26
+ <tr>
27
+ <th>gets</th>
28
+ <td><%= stats.gets %></td>
29
+
30
+ <th>sets</th>
31
+ <td><%= stats.sets %></td>
32
+
33
+ <th>deletes</th>
34
+ <td><%= stats.deletes %></td>
35
+
36
+ <th>get_multis</th>
37
+ <td><%= stats.get_multis %></td>
38
+ </tr>
39
+ </table>
40
+
41
+ <% if stats.queries.any? %>
42
+ <h3>Breakdown</h3>
43
+ <table id="cache_breakdown" class="sortable">
44
+ <thead>
45
+ <tr>
46
+ <th>Time&nbsp;(ms)</th>
47
+ <th>Type</th>
48
+ <th>Parameters</th>
49
+ <th>Function</th>
50
+ <th>
51
+ <a href="/__rack_bug__/delete_cache_list?<%= signed_params(stats.queries_to_param) %>" class="rb_delete_cache">
52
+ Delete All
53
+ </a>
54
+ </th>
55
+ </tr>
56
+ </thead>
57
+ <tbody>
58
+ <% i = 1 %>
59
+ <% stats.queries.each do |query| %>
60
+ <tr>
61
+ <td><%= query.display_time %></td>
62
+ <td><%= query.method %></td>
63
+ <td><%= query.display_keys %></td>
64
+ <td></td>
65
+ <td>
66
+ <a href="/__rack_bug__/view_cache?<%= signed_params("key" => query.keys.first) %>" class="remote_call">View</a> |
67
+ <a href="/__rack_bug__/delete_cache?<%= signed_params("key" => query.keys.first) %>" class="rb_delete_cache">Delete</a>
68
+ </td>
69
+ </tr>
70
+ <% i += 1 %>
71
+ <% end %>
72
+ </tbody>
73
+ </table>
74
+ <% end %>
75
+
76
+ <script type="text/javascript" charset="utf-8">
77
+ jQuery(function () {
78
+ jQuery("#rack_bug .rb_delete_cache").click(function (evt) {
79
+ jQuery.ajax({
80
+ url: this.href,
81
+ beforeSend: function() {
82
+ jQuery(evt.target).parent("td, th").addClass("rack_bug_spinner");
83
+ },
84
+ success: function () {
85
+ jQuery(evt.target).parent("td, th").removeClass("rack_bug_spinner");
86
+ jQuery(evt.target).replaceWith("Deleted");
87
+ }
88
+ });
89
+
90
+ return false;
91
+ });
92
+ });
93
+ </script>
@@ -0,0 +1,38 @@
1
+ <a class="back" href="">&laquo;&nbsp;Back</a>
2
+
3
+ <h3>SQL Results</h3>
4
+
5
+ <dl>
6
+ <dt>Executed SQL</dt>
7
+ <dd><pre><%=h query %></pre></dd>
8
+
9
+ <dt>Time</dt>
10
+ <dd><%=h "%.2f" % (time * 1_000) %>ms</dd>
11
+ </dl>
12
+
13
+ <table class="sortable">
14
+ <thead>
15
+ <tr>
16
+ <% if defined?(Mysql2) || defined?(PGresult) %>
17
+ <% result.fields.each do |field| %>
18
+ <th><%= field.upcase %></th>
19
+ <% end %>
20
+ <% else %>
21
+ <% result.fetch_fields.each do |field| %>
22
+ <th><%= field.name.upcase %></th>
23
+ <% end %>
24
+ <% end %>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <% i = 1 %>
29
+ <% result.each do |row| %>
30
+ <tr>
31
+ <% row.each do |value| %>
32
+ <td><%= value %></td>
33
+ <% end %>
34
+ </tr>
35
+ <% i += 1 %>
36
+ <% end %>
37
+ </tbody>
38
+ </table>
@@ -0,0 +1,38 @@
1
+ <a class="back" href="">&laquo;&nbsp;Back</a>
2
+
3
+ <h3>SQL Explained</h3>
4
+
5
+ <dl>
6
+ <dt>Executed SQL</dt>
7
+ <dd><pre><%=h query %></pre></dd>
8
+
9
+ <dt>Time</dt>
10
+ <dd><%=h "%.2f" % (time * 1_000) %>ms</dd>
11
+ </dl>
12
+
13
+ <table class="sortable">
14
+ <thead>
15
+ <tr>
16
+ <% if defined?(Mysql2) || defined?(PGresult) %>
17
+ <% result.fields.each do |field| %>
18
+ <th><%= field.upcase %></th>
19
+ <% end %>
20
+ <% else %>
21
+ <% result.fetch_fields.each do |field| %>
22
+ <th><%= field.name.upcase %></th>
23
+ <% end %>
24
+ <% end %>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <% i = 1 %>
29
+ <% result.each do |row| %>
30
+ <tr>
31
+ <% row.each do |value| %>
32
+ <td><%= value %></td>
33
+ <% end %>
34
+ </tr>
35
+ <% i += 1 %>
36
+ <% end %>
37
+ </tbody>
38
+ </table>
@@ -0,0 +1,21 @@
1
+ <h3>Log Messages</h3>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <th>Level</th>
6
+ <th>Time</th>
7
+ <th>Message</th>
8
+ </tr>
9
+ </thead>
10
+ <tbody>
11
+ <% i = 1 %>
12
+ <% logs.each do |entry| %>
13
+ <tr>
14
+ <td><%= entry.level %></td>
15
+ <td><%= entry.time %>ms</td>
16
+ <td><%= entry.cleaned_message %></td>
17
+ </tr>
18
+ <% i += 1 %>
19
+ <% end %>
20
+ </tbody>
21
+ </table>
@@ -0,0 +1,32 @@
1
+ <h3>Mongo Usage</h3>
2
+ <table id="mongo_usage">
3
+ <tr>
4
+ <th>Total Calls</th>
5
+ <td><%= stats.calls %></td>
6
+
7
+ <th>Total Time</th>
8
+ <td><%= stats.display_time %></td>
9
+ </tr>
10
+ </table>
11
+
12
+ <% if stats.queries.any? %>
13
+ <h3>Breakdown</h3>
14
+ <table id="mongo_breakdown">
15
+ <thead>
16
+ <tr>
17
+ <th>Time&nbsp;(ms)</th>
18
+ <th>Command</th>
19
+ </tr>
20
+ </thead>
21
+ <tbody>
22
+ <% i = 1 %>
23
+ <% stats.queries.each do |query| %>
24
+ <tr>
25
+ <td><%= query.display_time %></td>
26
+ <td><%= query.command %></td>
27
+ </tr>
28
+ <% i += 1 %>
29
+ <% end %>
30
+ </tbody>
31
+ </table>
32
+ <% end %>
@@ -0,0 +1,38 @@
1
+ <a class="back" href="">&laquo;&nbsp;Back</a>
2
+
3
+ <h3>SQL Profiled</h3>
4
+
5
+ <dl>
6
+ <dt>Executed SQL</dt>
7
+ <dd><pre><%=h query %></pre></dd>
8
+
9
+ <dt>Time</dt>
10
+ <dd><%=h "%.2f" % (time * 1_000) %>ms</dd>
11
+ </dl>
12
+
13
+ <table class="sortable">
14
+ <thead>
15
+ <tr>
16
+ <% if defined?(Mysql2) || defined?(PGresult) %>
17
+ <% result.fields.each do |field| %>
18
+ <th><%= field.upcase %></th>
19
+ <% end %>
20
+ <% else %>
21
+ <% result.fetch_fields.each do |field| %>
22
+ <th><%= field.name.upcase %></th>
23
+ <% end %>
24
+ <% end %>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <% i = 1 %>
29
+ <% result.each do |row| %>
30
+ <tr>
31
+ <% row.each do |value| %>
32
+ <td><%= value %></td>
33
+ <% end %>
34
+ </tr>
35
+ <% i += 1 %>
36
+ <% end %>
37
+ </tbody>
38
+ </table>
@@ -0,0 +1,19 @@
1
+ <h3>Rails Environment</h3>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <th>Variable</th>
6
+ <th>Value</th>
7
+ </tr>
8
+ </thead>
9
+ <tbody>
10
+ <% i = 1 %>
11
+ <% Rails::Info.properties.each do |key, val| %>
12
+ <tr>
13
+ <td><%=h key %></td>
14
+ <td class="code"><div><%=h val %></div></td>
15
+ </tr>
16
+ <% i += 1 %>
17
+ <% end %>
18
+ </tbody>
19
+ </table>
@@ -0,0 +1,46 @@
1
+ <h3>Redis Usage</h3>
2
+ <table id="redis_usage">
3
+ <tr>
4
+ <th>Total Calls</th>
5
+ <td><%= stats.calls %></td>
6
+
7
+ <th>Total Time</th>
8
+ <td><%= stats.display_time %></td>
9
+ </tr>
10
+ </table>
11
+
12
+ <% if stats.queries.any? %>
13
+ <h3>Breakdown</h3>
14
+ <table id="redis_breakdown">
15
+ <thead>
16
+ <tr>
17
+ <th>Time&nbsp;(ms)</th>
18
+ <th>Command</th>
19
+ <th class="backtrace"></th>
20
+ </tr>
21
+ </thead>
22
+ <tbody>
23
+ <% i = 1 %>
24
+ <% stats.queries.each do |query| %>
25
+ <tr>
26
+ <td><%= query.display_time %></td>
27
+ <td><%= query.command %></td>
28
+ <td><%= "<a href='#' class='reveal_backtrace'>Show Backtrace</a>" if query.has_backtrace? %></td>
29
+ </tr>
30
+ <% if query.has_backtrace? %>
31
+ <tr style="display:none">
32
+ <td></td>
33
+ <td colspan="2">
34
+ <ul>
35
+ <% query.filtered_backtrace.each do |line| %>
36
+ <li><%=h line %></li>
37
+ <% end %>
38
+ </ul>
39
+ </td>
40
+ </tr>
41
+ <% end %>
42
+ <% i += 1 %>
43
+ <% end %>
44
+ </tbody>
45
+ </table>
46
+ <% end %>
@@ -0,0 +1,29 @@
1
+ <% ["GET", "POST", "Session", "Cookies", "SERVER VARIABLES", "Rack ENV"].each do |header|
2
+ next unless sections.has_key?(header)
3
+ %>
4
+ <h3><%=header%></h3>
5
+ <table id="request_variables">
6
+ <thead>
7
+ <tr>
8
+ <th>Variable</th>
9
+ <th>Value</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ <% i = 1 %>
14
+ <% sections[header].each do |key, val| %>
15
+ <tr>
16
+ <td><%=h key %></td>
17
+ <td class="code"><div>
18
+ <% if val.is_a?(Hash) %>
19
+ <%=h val.inspect %>
20
+ <% else %>
21
+ <%=h val.to_s %>
22
+ <% end %>
23
+ </div></td>
24
+ </tr>
25
+ <% i += 1 %>
26
+ <% end %>
27
+ </tbody>
28
+ </table>
29
+ <% end %>
@@ -0,0 +1,32 @@
1
+ <h3>Sphinx Usage</h3>
2
+ <table id="Sphinx_usage">
3
+ <tr>
4
+ <th>Total Calls</th>
5
+ <td><%= stats.calls %></td>
6
+
7
+ <th>Total Time</th>
8
+ <td><%= stats.display_time %></td>
9
+ </tr>
10
+ </table>
11
+
12
+ <% if stats.queries.any? %>
13
+ <h3>Breakdown</h3>
14
+ <table id="Sphinx_breakdown">
15
+ <thead>
16
+ <tr>
17
+ <th>Time&nbsp;(ms)</th>
18
+ <th>Command</th>
19
+ </tr>
20
+ </thead>
21
+ <tbody>
22
+ <% i = 1 %>
23
+ <% stats.queries.each do |query| %>
24
+ <tr>
25
+ <td><%= query.display_time %></td>
26
+ <td><%= query.command %></td>
27
+ </tr>
28
+ <% i += 1 %>
29
+ <% end %>
30
+ </tbody>
31
+ </table>
32
+ <% end %>