rack-bug 0.2.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 (77) hide show
  1. data/.gitignore +3 -0
  2. data/History.txt +0 -0
  3. data/MIT-LICENSE.txt +19 -0
  4. data/README.rdoc +29 -0
  5. data/Rakefile +36 -0
  6. data/VERSION +1 -0
  7. data/lib/rack/bug.rb +43 -0
  8. data/lib/rack/bug/options.rb +89 -0
  9. data/lib/rack/bug/panel.rb +50 -0
  10. data/lib/rack/bug/panel_app.rb +33 -0
  11. data/lib/rack/bug/panels/active_record_panel.rb +45 -0
  12. data/lib/rack/bug/panels/active_record_panel/activerecord_extensions.rb +18 -0
  13. data/lib/rack/bug/panels/cache_panel.rb +50 -0
  14. data/lib/rack/bug/panels/cache_panel/memcache_extension.rb +129 -0
  15. data/lib/rack/bug/panels/cache_panel/panel_app.rb +48 -0
  16. data/lib/rack/bug/panels/cache_panel/stats.rb +97 -0
  17. data/lib/rack/bug/panels/log_panel.rb +39 -0
  18. data/lib/rack/bug/panels/log_panel/rails_extension.rb +11 -0
  19. data/lib/rack/bug/panels/memory_panel.rb +27 -0
  20. data/lib/rack/bug/panels/rails_info_panel.rb +23 -0
  21. data/lib/rack/bug/panels/redis_panel.rb +44 -0
  22. data/lib/rack/bug/panels/redis_panel/redis_extension.rb +14 -0
  23. data/lib/rack/bug/panels/redis_panel/stats.rb +48 -0
  24. data/lib/rack/bug/panels/request_variables_panel.rb +25 -0
  25. data/lib/rack/bug/panels/sql_panel.rb +55 -0
  26. data/lib/rack/bug/panels/sql_panel/panel_app.rb +37 -0
  27. data/lib/rack/bug/panels/sql_panel/query.rb +73 -0
  28. data/lib/rack/bug/panels/sql_panel/sql_extension.rb +11 -0
  29. data/lib/rack/bug/panels/templates_panel.rb +44 -0
  30. data/lib/rack/bug/panels/templates_panel/actionview_extension.rb +12 -0
  31. data/lib/rack/bug/panels/templates_panel/rendering.rb +67 -0
  32. data/lib/rack/bug/panels/templates_panel/trace.rb +34 -0
  33. data/lib/rack/bug/panels/timer_panel.rb +40 -0
  34. data/lib/rack/bug/params_signature.rb +65 -0
  35. data/lib/rack/bug/public/__rack_bug__/bookmarklet.html +10 -0
  36. data/lib/rack/bug/public/__rack_bug__/bookmarklet.js +215 -0
  37. data/lib/rack/bug/public/__rack_bug__/bug.css +211 -0
  38. data/lib/rack/bug/public/__rack_bug__/bug.js +84 -0
  39. data/lib/rack/bug/public/__rack_bug__/jquery-1.3.2.js +4376 -0
  40. data/lib/rack/bug/public/__rack_bug__/jquery.tablesorter.min.js +1 -0
  41. data/lib/rack/bug/public/__rack_bug__/spinner.gif +0 -0
  42. data/lib/rack/bug/render.rb +66 -0
  43. data/lib/rack/bug/toolbar.rb +137 -0
  44. data/lib/rack/bug/views/error.html.erb +16 -0
  45. data/lib/rack/bug/views/panels/active_record.html.erb +17 -0
  46. data/lib/rack/bug/views/panels/cache.html.erb +93 -0
  47. data/lib/rack/bug/views/panels/execute_sql.html.erb +32 -0
  48. data/lib/rack/bug/views/panels/explain_sql.html.erb +32 -0
  49. data/lib/rack/bug/views/panels/log.html.erb +23 -0
  50. data/lib/rack/bug/views/panels/profile_sql.html.erb +32 -0
  51. data/lib/rack/bug/views/panels/rails_info.html.erb +19 -0
  52. data/lib/rack/bug/views/panels/redis.html.erb +32 -0
  53. data/lib/rack/bug/views/panels/request_variables.html.erb +107 -0
  54. data/lib/rack/bug/views/panels/sql.html.erb +43 -0
  55. data/lib/rack/bug/views/panels/templates.html.erb +7 -0
  56. data/lib/rack/bug/views/panels/timer.html.erb +19 -0
  57. data/lib/rack/bug/views/panels/view_cache.html.erb +19 -0
  58. data/lib/rack/bug/views/redirect.html.erb +16 -0
  59. data/lib/rack/bug/views/toolbar.html.erb +42 -0
  60. data/rack-bug.gemspec +126 -0
  61. data/spec/fixtures/config.ru +8 -0
  62. data/spec/fixtures/dummy_panel.rb +2 -0
  63. data/spec/fixtures/sample_app.rb +29 -0
  64. data/spec/rack/bug/panels/active_record_panel_spec.rb +30 -0
  65. data/spec/rack/bug/panels/cache_panel_spec.rb +159 -0
  66. data/spec/rack/bug/panels/log_panel_spec.rb +25 -0
  67. data/spec/rack/bug/panels/memory_panel_spec.rb +21 -0
  68. data/spec/rack/bug/panels/rails_info_panel_spec.rb +25 -0
  69. data/spec/rack/bug/panels/redis_panel_spec.rb +57 -0
  70. data/spec/rack/bug/panels/sql_panel_spec.rb +136 -0
  71. data/spec/rack/bug/panels/templates_panel_spec.rb +71 -0
  72. data/spec/rack/bug/panels/timer_panel_spec.rb +38 -0
  73. data/spec/rack/toolbar_spec.rb +100 -0
  74. data/spec/rcov.opts +1 -0
  75. data/spec/spec.opts +1 -0
  76. data/spec/spec_helper.rb +70 -0
  77. metadata +143 -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,66 @@
1
+ require "erb"
2
+
3
+ module Rack
4
+ module 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,137 @@
1
+ require "ipaddr"
2
+ require "digest"
3
+
4
+ module Rack
5
+ module Bug
6
+ class RackStaticBugAvoider
7
+ def initialize(app, static_app)
8
+ @app = app
9
+ @static_app = static_app
10
+ end
11
+
12
+ def call(env)
13
+ if env["PATH_INFO"]
14
+ @static_app.call(env)
15
+ else
16
+ @app.call(env)
17
+ end
18
+ end
19
+ end
20
+
21
+ class Toolbar
22
+ include Options
23
+ include Render
24
+
25
+ MIME_TYPES = ["text/html", "application/xhtml+xml"]
26
+
27
+ def initialize(app, options = {})
28
+ @app = asset_server(app)
29
+ initialize_options options
30
+ instance_eval(&block) if block_given?
31
+ end
32
+
33
+ def asset_server(app)
34
+ RackStaticBugAvoider.new(app, Rack::Static.new(app, :urls => ["/__rack_bug__"], :root => public_path))
35
+ end
36
+
37
+ def public_path
38
+ ::File.expand_path(::File.dirname(__FILE__) + "/../bug/public")
39
+ end
40
+
41
+ def call(env)
42
+ env.replace @default_options.merge(env)
43
+ @env = env
44
+ @original_request = Request.new(@env)
45
+
46
+ if toolbar_requested? && ip_authorized? && password_authorized?
47
+ dispatch
48
+ else
49
+ pass
50
+ end
51
+ end
52
+
53
+ def pass
54
+ @app.call(@env)
55
+ end
56
+
57
+ def dispatch
58
+ @env["rack-bug.panels"] = []
59
+
60
+ Rack::Bug.enable
61
+ status, headers, body = builder.call(@env)
62
+ Rack::Bug.disable
63
+
64
+ @response = Rack::Response.new(body, status, headers)
65
+
66
+ if @response.redirect? && options["rack-bug.intercept_redirects"]
67
+ intercept_redirect
68
+ elsif modify?
69
+ inject_toolbar
70
+ end
71
+
72
+ return @response.to_a
73
+ end
74
+
75
+ def intercept_redirect
76
+ redirect_to = @response.location
77
+ new_body = render_template("redirect", :redirect_to => @response.location)
78
+ new_response = Rack::Response.new(new_body, 200, { "Content-Type" => "text/html" })
79
+ new_response["Content-Length"] = new_body.size.to_s
80
+ @response = new_response
81
+ end
82
+
83
+ def toolbar_requested?
84
+ @original_request.cookies["rack_bug_enabled"]
85
+ end
86
+
87
+ def ip_authorized?
88
+ return true unless options["rack-bug.ip_masks"]
89
+
90
+ options["rack-bug.ip_masks"].any? do |ip_mask|
91
+ ip_mask.include?(IPAddr.new(@original_request.ip))
92
+ end
93
+ end
94
+
95
+ def password_authorized?
96
+ return true unless options["rack-bug.password"]
97
+
98
+ expected_sha = Digest::SHA1.hexdigest ["rack_bug", options["rack-bug.password"]].join(":")
99
+ actual_sha = @original_request.cookies["rack_bug_password"]
100
+
101
+ actual_sha == expected_sha
102
+ end
103
+
104
+ def modify?
105
+ @response.ok? &&
106
+ @env["X-Requested-With"] != "XMLHttpRequest" &&
107
+ MIME_TYPES.include?(@response.content_type.split(";").first)
108
+ end
109
+
110
+ def builder
111
+ builder = Rack::Builder.new
112
+
113
+ options["rack-bug.panel_classes"].each do |panel_class|
114
+ builder.use panel_class
115
+ end
116
+
117
+ builder.run @app
118
+
119
+ return builder
120
+ end
121
+
122
+ def inject_toolbar
123
+ full_body = @response.body.join
124
+ full_body.sub! /<\/body>/, render + "</body>"
125
+
126
+ @response["Content-Length"] = full_body.size.to_s
127
+ @response.body = [full_body]
128
+ end
129
+
130
+ def render
131
+ render_template("toolbar", :panels => @env["rack-bug.panels"].reverse)
132
+ end
133
+
134
+ end
135
+
136
+ end
137
+ 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,23 @@
1
+ <h3>Log Messages</h3>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <th>Level</th>
6
+ <th>Time</th>
7
+ <th>Message</th>
8
+ <th>Location</th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <% i = 1 %>
13
+ <% logs.each do |log| %>
14
+ <tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
15
+ <td></td>
16
+ <td></td>
17
+ <td><%= log.to_s.gsub(/\e\[[;\d]+m/, "") %></td>
18
+ <td></td>
19
+ </tr>
20
+ <% i += 1 %>
21
+ <% end %>
22
+ </tbody>
23
+ </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>