ghazel-rack-bug 0.3.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.
Files changed (86) hide show
  1. data/.gitignore +3 -0
  2. data/History.txt +45 -0
  3. data/MIT-LICENSE.txt +19 -0
  4. data/README.md +118 -0
  5. data/Rakefile +23 -0
  6. data/Thorfile +113 -0
  7. data/lib/rack/bug.rb +83 -0
  8. data/lib/rack/bug/autoloading.rb +24 -0
  9. data/lib/rack/bug/filtered_backtrace.rb +38 -0
  10. data/lib/rack/bug/options.rb +89 -0
  11. data/lib/rack/bug/panel.rb +50 -0
  12. data/lib/rack/bug/panel_app.rb +33 -0
  13. data/lib/rack/bug/panels/active_record_panel.rb +45 -0
  14. data/lib/rack/bug/panels/active_record_panel/activerecord_extensions.rb +18 -0
  15. data/lib/rack/bug/panels/cache_panel.rb +51 -0
  16. data/lib/rack/bug/panels/cache_panel/dalli_extension.rb +16 -0
  17. data/lib/rack/bug/panels/cache_panel/memcache_extension.rb +129 -0
  18. data/lib/rack/bug/panels/cache_panel/panel_app.rb +48 -0
  19. data/lib/rack/bug/panels/cache_panel/stats.rb +97 -0
  20. data/lib/rack/bug/panels/log_panel.rb +56 -0
  21. data/lib/rack/bug/panels/log_panel/logger_extension.rb +24 -0
  22. data/lib/rack/bug/panels/memory_panel.rb +27 -0
  23. data/lib/rack/bug/panels/rails_info_panel.rb +23 -0
  24. data/lib/rack/bug/panels/redis_panel.rb +44 -0
  25. data/lib/rack/bug/panels/redis_panel/redis_extension.rb +28 -0
  26. data/lib/rack/bug/panels/redis_panel/stats.rb +52 -0
  27. data/lib/rack/bug/panels/request_variables_panel.rb +52 -0
  28. data/lib/rack/bug/panels/sphinx_panel.rb +44 -0
  29. data/lib/rack/bug/panels/sphinx_panel/sphinx_extension.rb +25 -0
  30. data/lib/rack/bug/panels/sphinx_panel/stats.rb +96 -0
  31. data/lib/rack/bug/panels/sql_panel.rb +55 -0
  32. data/lib/rack/bug/panels/sql_panel/panel_app.rb +37 -0
  33. data/lib/rack/bug/panels/sql_panel/query.rb +63 -0
  34. data/lib/rack/bug/panels/sql_panel/sql_extension.rb +11 -0
  35. data/lib/rack/bug/panels/templates_panel.rb +44 -0
  36. data/lib/rack/bug/panels/templates_panel/actionview_extension.rb +12 -0
  37. data/lib/rack/bug/panels/templates_panel/rendering.rb +67 -0
  38. data/lib/rack/bug/panels/templates_panel/trace.rb +34 -0
  39. data/lib/rack/bug/panels/timer_panel.rb +40 -0
  40. data/lib/rack/bug/params_signature.rb +63 -0
  41. data/lib/rack/bug/public/__rack_bug__/bookmarklet.html +10 -0
  42. data/lib/rack/bug/public/__rack_bug__/bookmarklet.js +217 -0
  43. data/lib/rack/bug/public/__rack_bug__/bug.css +216 -0
  44. data/lib/rack/bug/public/__rack_bug__/bug.js +84 -0
  45. data/lib/rack/bug/public/__rack_bug__/jquery-1.3.2.js +4376 -0
  46. data/lib/rack/bug/public/__rack_bug__/jquery.tablesorter.min.js +1 -0
  47. data/lib/rack/bug/public/__rack_bug__/spinner.gif +0 -0
  48. data/lib/rack/bug/rack_static_bug_avoider.rb +16 -0
  49. data/lib/rack/bug/redirect_interceptor.rb +27 -0
  50. data/lib/rack/bug/render.rb +66 -0
  51. data/lib/rack/bug/toolbar.rb +66 -0
  52. data/lib/rack/bug/views/error.html.erb +16 -0
  53. data/lib/rack/bug/views/panels/active_record.html.erb +17 -0
  54. data/lib/rack/bug/views/panels/cache.html.erb +93 -0
  55. data/lib/rack/bug/views/panels/execute_sql.html.erb +32 -0
  56. data/lib/rack/bug/views/panels/explain_sql.html.erb +32 -0
  57. data/lib/rack/bug/views/panels/log.html.erb +21 -0
  58. data/lib/rack/bug/views/panels/profile_sql.html.erb +32 -0
  59. data/lib/rack/bug/views/panels/rails_info.html.erb +19 -0
  60. data/lib/rack/bug/views/panels/redis.html.erb +46 -0
  61. data/lib/rack/bug/views/panels/request_variables.html.erb +29 -0
  62. data/lib/rack/bug/views/panels/sphinx.html.erb +32 -0
  63. data/lib/rack/bug/views/panels/sql.html.erb +43 -0
  64. data/lib/rack/bug/views/panels/templates.html.erb +7 -0
  65. data/lib/rack/bug/views/panels/timer.html.erb +19 -0
  66. data/lib/rack/bug/views/panels/view_cache.html.erb +19 -0
  67. data/lib/rack/bug/views/redirect.html.erb +16 -0
  68. data/lib/rack/bug/views/toolbar.html.erb +42 -0
  69. data/rack-bug.gemspec +147 -0
  70. data/spec/fixtures/config.ru +8 -0
  71. data/spec/fixtures/dummy_panel.rb +2 -0
  72. data/spec/fixtures/sample_app.rb +46 -0
  73. data/spec/rack/bug/panels/active_record_panel_spec.rb +30 -0
  74. data/spec/rack/bug/panels/cache_panel_spec.rb +167 -0
  75. data/spec/rack/bug/panels/log_panel_spec.rb +43 -0
  76. data/spec/rack/bug/panels/memory_panel_spec.rb +22 -0
  77. data/spec/rack/bug/panels/rails_info_panel_spec.rb +40 -0
  78. data/spec/rack/bug/panels/redis_panel_spec.rb +69 -0
  79. data/spec/rack/bug/panels/sql_panel_spec.rb +146 -0
  80. data/spec/rack/bug/panels/templates_panel_spec.rb +71 -0
  81. data/spec/rack/bug/panels/timer_panel_spec.rb +38 -0
  82. data/spec/rack/bug_spec.rb +137 -0
  83. data/spec/rcov.opts +1 -0
  84. data/spec/spec.opts +1 -0
  85. data/spec/spec_helper.rb +44 -0
  86. metadata +201 -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,66 @@
1
+ require "erb"
2
+
3
+ module Rack
4
+ class Bug
5
+
6
+ module Render
7
+ include ERB::Util
8
+
9
+ def signed_params(hash)
10
+ ParamsSignature.sign(request, hash)
11
+ end
12
+
13
+ module CompiledTemplates
14
+ end
15
+ include CompiledTemplates
16
+
17
+ def render_template(filename, local_assigns = {})
18
+ compile(filename, local_assigns)
19
+ render_symbol = method_name(filename, local_assigns)
20
+ send(render_symbol, local_assigns)
21
+ end
22
+
23
+ def compile(filename, local_assigns)
24
+ render_symbol = method_name(filename, local_assigns)
25
+
26
+ if !CompiledTemplates.instance_methods.include?(render_symbol.to_s)
27
+ compile!(filename, local_assigns)
28
+ end
29
+ end
30
+
31
+ def compile!(filename, local_assigns)
32
+ render_symbol = method_name(filename, local_assigns)
33
+ locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
34
+
35
+ source = <<-end_src
36
+ def #{render_symbol}(local_assigns)
37
+ #{locals_code}
38
+ #{compiled_source(filename)}
39
+ end
40
+ end_src
41
+
42
+ CompiledTemplates.module_eval(source, filename, 0)
43
+ end
44
+
45
+ def compiled_source(filename)
46
+ ::ERB.new(::File.read(::File.dirname(__FILE__) + "/../bug/views/#{filename}.html.erb"), nil, "-").src
47
+ end
48
+
49
+ def method_name(filename, local_assigns)
50
+ if local_assigns && local_assigns.any?
51
+ method_name = method_name_without_locals(filename).dup
52
+ method_name << "_locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
53
+ else
54
+ method_name = method_name_without_locals(filename)
55
+ end
56
+ method_name.to_sym
57
+ end
58
+
59
+ def method_name_without_locals(filename)
60
+ filename.split("/").join("_")
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,66 @@
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
+ @env.delete("HTTP_IF_NONE_MATCH")
17
+
18
+ Rack::Bug.enable
19
+ status, headers, body = builder.call(@env)
20
+ Rack::Bug.disable
21
+
22
+ @response = Rack::Response.new(body, status, headers)
23
+
24
+ inject_toolbar if response_type_okay_to_modify?
25
+
26
+ return @response.to_a
27
+ end
28
+
29
+ def response_type_okay_to_modify?
30
+ content_type, charset = @response.content_type.split(";")
31
+ @response.ok? && MIME_TYPES.include?(content_type)
32
+ end
33
+
34
+ def builder
35
+ builder = Rack::Builder.new
36
+
37
+ @env["rack-bug.panel_classes"].each do |panel_class|
38
+ builder.use panel_class
39
+ end
40
+
41
+ builder.run @app
42
+
43
+ return builder
44
+ end
45
+
46
+ def inject_toolbar
47
+ full_body = @response.body.join
48
+ full_body.sub! /<\/body>/, render + "</body>"
49
+
50
+ @response["Content-Length"] = full_body.size.to_s
51
+
52
+ # Ensure that browser does
53
+ @response["Etag"] = ""
54
+ @response["Cache-Control"] = "no-cache"
55
+
56
+ @response.body = [full_body]
57
+ end
58
+
59
+ def render
60
+ render_template("toolbar", :panels => @env["rack-bug.panels"].reverse)
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+ 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 class="<%= i % 2 == 0 ? "even" : "odd" %>">
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,32 @@
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
+ <% result.fetch_fields.each do |field| %>
17
+ <th><%= field.name.upcase %></th>
18
+ <% end %>
19
+ </tr>
20
+ </thead>
21
+ <tbody>
22
+ <% i = 1 %>
23
+ <% result.each do |row| %>
24
+ <tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
25
+ <% row.each do |value| %>
26
+ <td><%= value %></td>
27
+ <% end %>
28
+ </tr>
29
+ <% i += 1 %>
30
+ <% end %>
31
+ </tbody>
32
+ </table>
@@ -0,0 +1,32 @@
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
+ <% result.fetch_fields.each do |field| %>
17
+ <th><%= field.name.upcase %></th>
18
+ <% end %>
19
+ </tr>
20
+ </thead>
21
+ <tbody>
22
+ <% i = 1 %>
23
+ <% result.each do |row| %>
24
+ <tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
25
+ <% row.each do |value| %>
26
+ <td><%= value %></td>
27
+ <% end %>
28
+ </tr>
29
+ <% i += 1 %>
30
+ <% end %>
31
+ </tbody>
32
+ </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 class="<%= i % 2 == 0 ? "even" : "odd" %>">
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
+ <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
+ <% result.fetch_fields.each do |field| %>
17
+ <th><%= field.name.upcase %></th>
18
+ <% end %>
19
+ </tr>
20
+ </thead>
21
+ <tbody>
22
+ <% i = 1 %>
23
+ <% result.each do |row| %>
24
+ <tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
25
+ <% row.each do |value| %>
26
+ <td><%= value %></td>
27
+ <% end %>
28
+ </tr>
29
+ <% i += 1 %>
30
+ <% end %>
31
+ </tbody>
32
+ </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 class="<%= i % 2 == 0 ? "even" : "odd" %>">
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>