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