rails3-footnotes 4.0.0.pre.2 → 4.0.0.pre.3
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.
- data/CHANGELOG +7 -0
- data/README.md +1 -1
- data/Rakefile +3 -0
- data/lib/rails-footnotes/footnotes.rb +1 -1
- data/lib/rails-footnotes/notes/controller_note.rb +1 -1
- data/lib/rails-footnotes/notes/partials_note.rb +44 -28
- data/lib/rails-footnotes/notes/queries_note.rb +55 -120
- data/lib/rails-footnotes/notes/routes_note.rb +1 -1
- data/lib/rails-footnotes/notes/view_note.rb +59 -19
- data/lib/rails-footnotes/version.rb +1 -1
- metadata +18 -4
- data/lib/rails-footnotes/notes/general_note.rb +0 -19
data/CHANGELOG
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== Footnotes v4.0.0.pre.3 (March 30, 2011)
|
2
|
+
* Merge in contributions from irjudson and jackkinsella
|
3
|
+
* fixes for partials note
|
4
|
+
* fixes for views note
|
5
|
+
* fixes for queries note
|
6
|
+
* fix a warning on routes note
|
7
|
+
|
1
8
|
== Footnotes v4.0.0.pre.2 (February 21, 2011)
|
2
9
|
* add a Railtie so the plugin will load in Rails 3 apps
|
3
10
|
* remove some internal rails3 ivars from the assigns note
|
data/README.md
CHANGED
@@ -56,7 +56,7 @@ If you have New Relic RPM installed, you may want to turn off query explains
|
|
56
56
|
|
57
57
|
Finally, you can control which notes you want to show. The default are:
|
58
58
|
|
59
|
-
Footnotes::Filter.notes = [:session, :cookies, :params, :filters, :routes, :env, :queries, :log
|
59
|
+
Footnotes::Filter.notes = [:session, :cookies, :params, :filters, :routes, :env, :queries, :log]
|
60
60
|
|
61
61
|
|
62
62
|
## Creating your own notes
|
data/Rakefile
CHANGED
@@ -27,7 +27,7 @@ module Footnotes
|
|
27
27
|
# Edit notes
|
28
28
|
@@notes = [ :controller, :view, :layout, :partials, :stylesheets, :javascripts ]
|
29
29
|
# Show notes
|
30
|
-
@@notes += [ :assigns, :session, :cookies, :params, :filters, :routes, :env, :queries, :log
|
30
|
+
@@notes += [ :assigns, :session, :cookies, :params, :filters, :routes, :env, :queries, :log ]
|
31
31
|
|
32
32
|
# Change queries for rpm note when available
|
33
33
|
# if defined?(NewRelic)
|
@@ -38,7 +38,7 @@ module Footnotes
|
|
38
38
|
else
|
39
39
|
@controller_filename=File.join(File.expand_path(Rails.root), 'app', 'controllers', "#{controller_name}.rb").sub('/controllers/controllers/', '/controllers/')
|
40
40
|
end
|
41
|
-
@controller_filename
|
41
|
+
@controller_filename if File.exist?(@controller_filename)
|
42
42
|
end
|
43
43
|
|
44
44
|
def controller_text
|
@@ -3,54 +3,70 @@ require "#{File.dirname(__FILE__)}/log_note"
|
|
3
3
|
module Footnotes
|
4
4
|
module Notes
|
5
5
|
class PartialsNote < LogNote
|
6
|
+
@@partial_subscriber = nil
|
7
|
+
cattr_accessor :partial_subscriber
|
8
|
+
|
6
9
|
def initialize(controller)
|
7
10
|
super
|
8
11
|
@controller = controller
|
9
12
|
end
|
13
|
+
|
14
|
+
def self.start!(controller)
|
15
|
+
@@partial_subscriber = Footnotes::Notes::PartialSubscriber.new
|
16
|
+
ActiveSupport::LogSubscriber.attach_to(:action_view, @@partial_subscriber)
|
17
|
+
end
|
18
|
+
|
10
19
|
def row
|
11
20
|
:edit
|
12
21
|
end
|
22
|
+
|
13
23
|
def title
|
14
24
|
"Partials (#{partials.size})"
|
15
25
|
end
|
26
|
+
|
16
27
|
def content
|
17
28
|
rows = partials.map do |filename|
|
18
29
|
href = Footnotes::Filter.prefix(filename,1,1)
|
19
30
|
shortened_name=filename.gsub(File.join(Rails.root,"app/views/"),"")
|
20
|
-
[%{<a href="#{href}">#{shortened_name}</a>},"#{@partial_times[filename].sum}ms"
|
31
|
+
[%{<a href="#{href}">#{shortened_name}</a>},"#{@partial_times[filename].sum}ms", @partial_counts[filename]]
|
21
32
|
end
|
22
33
|
mount_table(rows.unshift(%w(Partial Time Count)), :summary => "Partials for #{title}")
|
23
34
|
end
|
24
35
|
|
36
|
+
def self.load
|
37
|
+
self.loaded = true unless loaded
|
38
|
+
end
|
39
|
+
|
25
40
|
protected
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
for file in files
|
41
|
-
#TODO figure out what format got rendered if theres multiple
|
42
|
-
@partial_times[file] ||= []
|
43
|
-
@partial_times[file] << $2.to_f
|
44
|
-
@partial_counts[file] ||= 0
|
45
|
-
@partial_counts[file] += 1
|
46
|
-
partials << file unless partials.include?(file)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
partials.reverse
|
41
|
+
#Generate a list of partials that were rendered, also build up render times and counts.
|
42
|
+
#This is memoized so we can use its information in the title easily.
|
43
|
+
def partials
|
44
|
+
@partials ||= begin
|
45
|
+
partials = []
|
46
|
+
@partial_counts = {}
|
47
|
+
@partial_times = {}
|
48
|
+
@@partial_subscriber.events.each do |event|
|
49
|
+
partial = event.payload[:identifier]
|
50
|
+
@partial_times[partial] ||= []
|
51
|
+
@partial_times[partial] << event.duration
|
52
|
+
@partial_counts[partial] ||= 0
|
53
|
+
@partial_counts[partial] += 1
|
54
|
+
partials << partial unless partials.include?(partial)
|
52
55
|
end
|
56
|
+
partials.reverse
|
53
57
|
end
|
54
|
-
|
58
|
+
end
|
59
|
+
end
|
60
|
+
class PartialSubscriber < ActiveSupport::LogSubscriber
|
61
|
+
attr_accessor :events
|
62
|
+
def initialize
|
63
|
+
@events = Array.new
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
def render_partial(event)
|
68
|
+
@events << event.dup
|
69
|
+
end
|
70
|
+
end
|
55
71
|
end
|
56
72
|
end
|
@@ -3,22 +3,26 @@ require "#{File.dirname(__FILE__)}/abstract_note"
|
|
3
3
|
module Footnotes
|
4
4
|
module Notes
|
5
5
|
class QueriesNote < AbstractNote
|
6
|
-
@@alert_db_time = 0
|
6
|
+
@@alert_db_time = 16.0
|
7
7
|
@@alert_sql_number = 8
|
8
8
|
@@sql = []
|
9
9
|
@@include_when_new_relic_installed = false
|
10
10
|
@@loaded = false
|
11
|
-
|
11
|
+
@@query_subscriber = nil
|
12
12
|
cattr_accessor :sql, :alert_db_time, :alert_sql_number, :alert_explain, :loaded, :sql_explain, :instance_writter => false
|
13
13
|
cattr_reader :include_when_new_relic_installed
|
14
|
-
|
14
|
+
|
15
15
|
def self.include_when_new_relic_installed=(include_me)
|
16
16
|
@@include_when_new_relic_installed = include_me
|
17
17
|
load if include_me
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def self.start!(controller)
|
21
21
|
@@sql = []
|
22
|
+
@@query_subscriber = Footnotes::Notes::QuerySubscriber.new
|
23
|
+
# There appears to be nothing wrong with registering with a non-existant notifier, so we just attach to both :-).
|
24
|
+
ActiveSupport::LogSubscriber.attach_to(:data_mapper, @@query_subscriber)
|
25
|
+
ActiveSupport::LogSubscriber.attach_to(:active_record, @@query_subscriber)
|
22
26
|
end
|
23
27
|
|
24
28
|
def self.to_sym
|
@@ -26,161 +30,92 @@ module Footnotes
|
|
26
30
|
end
|
27
31
|
|
28
32
|
def title
|
29
|
-
|
30
|
-
|
31
|
-
|
33
|
+
queries = @@query_subscriber.events.length
|
34
|
+
total_time = @@query_subscriber.events.inject(0){|sum, item| sum += item.payload[:duration]} / 1000.0
|
35
|
+
query_color = generate_red_color(@@query_subscriber.events.length, alert_sql_number)
|
36
|
+
db_color = generate_red_color(total_time, alert_db_time)
|
32
37
|
|
33
38
|
<<-TITLE
|
34
|
-
|
35
|
-
|
39
|
+
<span style="background-color:#{query_color}">Queries (#{queries})</span>
|
40
|
+
<span style="background-color:#{db_color}">DB (#{"%.3f" % total_time}ms)</span>
|
36
41
|
TITLE
|
37
42
|
end
|
38
43
|
|
39
44
|
def stylesheet
|
40
45
|
<<-STYLESHEET
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
46
|
+
#queries_debug_info table td, #queries_debug_info table th{border:1px solid #A00; padding:0 3px; text-align:center;}
|
47
|
+
#queries_debug_info table thead, #queries_debug_info table tbody {color:#A00;}
|
48
|
+
#queries_debug_info p {background-color:#F3F3FF; border:1px solid #CCC; margin:12px; padding:4px 6px;}
|
49
|
+
#queries_debug_info a:hover {text-decoration:underline;}
|
45
50
|
STYLESHEET
|
46
51
|
end
|
47
52
|
|
48
53
|
def content
|
49
54
|
html = ''
|
50
55
|
|
51
|
-
@@
|
52
|
-
sql_links = []
|
53
|
-
sql_links << "<a href=\"javascript:Footnotes.toggle('qtable_#{i}')\" style=\"color:#A00;\">explain</a>" if item.explain
|
54
|
-
sql_links << "<a href=\"javascript:Footnotes.toggle('qtrace_#{i}')\" style=\"color:#00A;\">trace</a>" if item.trace
|
55
|
-
|
56
|
+
@@query_subscriber.events.each_with_index do |item, i|
|
56
57
|
html << <<-HTML
|
57
|
-
|
58
|
-
|
59
|
-
<span id="explain_#{i}">#{print_query(item.query)}</span><br />
|
60
|
-
#{print_explain(i, item.explain) if item.explain}
|
61
|
-
<p id="qtrace_#{i}" style="display:none;">#{parse_trace(item.trace) if item.trace}</p><br />
|
58
|
+
#{print_name_and_time(item.payload[:name], item.payload[:duration] / 1000.0)}
|
59
|
+
<span id="explain_#{i}">#{print_query(item.payload[:sql])}</span><br />
|
62
60
|
HTML
|
63
61
|
end
|
64
62
|
|
65
63
|
return html
|
66
64
|
end
|
67
|
-
|
65
|
+
|
68
66
|
def self.load
|
69
|
-
|
70
|
-
if !loaded and included? and defined?(ActiveRecord)
|
71
|
-
ActiveRecord::ConnectionAdapters::AbstractAdapter.send :include, Footnotes::Extensions::AbstractAdapter
|
72
|
-
ActiveRecord::ConnectionAdapters.local_constants.each do |adapter|
|
73
|
-
next unless adapter =~ /.*[^Abstract]Adapter$/
|
74
|
-
next if adapter =~ /(SQLite|Salesforce)Adapter$/
|
75
|
-
eval("ActiveRecord::ConnectionAdapters::#{adapter}").send :include, Footnotes::Extensions::QueryAnalyzer
|
76
|
-
self.loaded = true
|
77
|
-
end
|
78
|
-
end
|
67
|
+
self.loaded = true unless loaded
|
79
68
|
end
|
80
|
-
|
81
|
-
protected
|
82
|
-
def parse_explain(results)
|
83
|
-
table = []
|
84
|
-
table << results.fetch_fields.map(&:name)
|
85
|
-
results.each do |row|
|
86
|
-
table << row
|
87
|
-
end
|
88
|
-
table
|
89
|
-
end
|
90
|
-
|
91
|
-
def parse_trace(trace)
|
92
|
-
trace.map do |t|
|
93
|
-
s = t.split(':')
|
94
|
-
%[<a href="#{escape(Footnotes::Filter.prefix("#{Rails.root.to_s}/#{s[0]}", s[1].to_i, 1))}">#{escape(t)}</a><br />]
|
95
|
-
end.join
|
96
|
-
end
|
97
|
-
|
98
|
-
def print_name_and_time(name, time)
|
99
|
-
"<span style='background-color:#{generate_red_color(time, alert_ratio)}'>#{escape(name || 'SQL')} (#{sprintf('%f', time)}s)</span>"
|
100
|
-
end
|
101
69
|
|
102
|
-
|
103
|
-
|
104
|
-
|
70
|
+
protected
|
71
|
+
def print_name_and_time(name, time)
|
72
|
+
"<span style='background-color:#{generate_red_color(time, alert_ratio)}'>#{escape(name || 'SQL')} (#{'%.3fms' % time})</span>"
|
73
|
+
end
|
105
74
|
|
106
|
-
|
107
|
-
|
108
|
-
|
75
|
+
def print_query(query)
|
76
|
+
escape(query.to_s.gsub(/(\s)+/, ' ').gsub('`', ''))
|
77
|
+
end
|
109
78
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
79
|
+
def generate_red_color(value, alert)
|
80
|
+
c = ((value.to_f/alert).to_i - 1) * 16
|
81
|
+
c = 0 if c < 0
|
82
|
+
c = 15 if c > 15
|
114
83
|
|
115
|
-
|
116
|
-
|
117
|
-
|
84
|
+
c = (15-c).to_s(16)
|
85
|
+
"#ff#{c*4}"
|
86
|
+
end
|
118
87
|
|
119
|
-
|
120
|
-
|
121
|
-
|
88
|
+
def alert_ratio
|
89
|
+
alert_db_time / alert_sql_number
|
90
|
+
end
|
122
91
|
|
123
92
|
end
|
124
|
-
end
|
125
|
-
|
126
|
-
module Extensions
|
127
|
-
class Sql
|
128
|
-
attr_accessor :type, :name, :time, :query, :explain, :trace
|
129
93
|
|
130
|
-
|
131
|
-
|
132
|
-
@name = name
|
133
|
-
@time = time
|
134
|
-
@query = query
|
135
|
-
@explain = explain
|
94
|
+
class QuerySubscriber < ActiveSupport::LogSubscriber
|
95
|
+
attr_accessor :events
|
136
96
|
|
137
|
-
|
138
|
-
|
139
|
-
@trace = Kernel.caller.collect(&:strip).select{|i| i.gsub!(/^#{Rails.root}\//im, '') }[2..-1]
|
97
|
+
def self.runtime=(value)
|
98
|
+
Thread.current["orm_sql_runtime"] = value
|
140
99
|
end
|
141
|
-
end
|
142
100
|
|
143
|
-
|
144
|
-
|
145
|
-
base.class_eval do
|
146
|
-
alias_method_chain :execute, :analyzer
|
147
|
-
end
|
101
|
+
def self.runtime
|
102
|
+
Thread.current["orm_sql_runtime"] ||= 0
|
148
103
|
end
|
149
104
|
|
150
|
-
def
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
if query =~ /^(select|create|update|delete)\b/i
|
155
|
-
type = $&.downcase.to_sym
|
156
|
-
explain = nil
|
157
|
-
|
158
|
-
if adapter_name == 'MySQL' && type == :select && Footnotes::Notes::QueriesNote.sql_explain
|
159
|
-
log_silence do
|
160
|
-
explain = execute_without_analyzer("EXPLAIN #{query}", name)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
Footnotes::Notes::QueriesNote.sql << Footnotes::Extensions::Sql.new(type, name, time, query, explain)
|
164
|
-
end
|
105
|
+
def self.reset_runtime
|
106
|
+
rt, self.runtime = runtime, 0
|
107
|
+
rt
|
108
|
+
end
|
165
109
|
|
166
|
-
|
110
|
+
def initialize
|
111
|
+
@events = Array.new
|
112
|
+
super
|
167
113
|
end
|
168
|
-
end
|
169
114
|
|
170
|
-
|
171
|
-
|
172
|
-
result = nil
|
173
|
-
if @logger
|
174
|
-
@logger.silence do
|
175
|
-
result = yield
|
176
|
-
end
|
177
|
-
else
|
178
|
-
result = yield
|
179
|
-
end
|
180
|
-
result
|
115
|
+
def sql(event)
|
116
|
+
@events << event.dup
|
181
117
|
end
|
182
118
|
end
|
183
|
-
|
184
119
|
end
|
185
120
|
end
|
186
121
|
|
@@ -48,7 +48,7 @@ module Footnotes
|
|
48
48
|
#
|
49
49
|
def filtered_routes(filter = {})
|
50
50
|
return [] unless filter.is_a?(Hash)
|
51
|
-
return routes.reject do |r|
|
51
|
+
return routes.reject do |r|
|
52
52
|
filter_diff = filter.diff(r.requirements)
|
53
53
|
route_diff = r.requirements.diff(filter)
|
54
54
|
(filter_diff == filter) || (filter_diff != route_diff)
|
@@ -3,33 +3,73 @@ require "#{File.dirname(__FILE__)}/abstract_note"
|
|
3
3
|
module Footnotes
|
4
4
|
module Notes
|
5
5
|
class ViewNote < AbstractNote
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
6
|
+
@@alert_time = 500.0
|
7
|
+
@@loaded = false
|
8
|
+
@@view_subscriber = nil
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
def initialize(controller)
|
11
|
+
super
|
12
|
+
@controller = controller
|
13
|
+
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
def self.start!(controller)
|
16
|
+
@@view_subscriber = Footnotes::Notes::ViewSubscriber.new
|
17
|
+
ActiveSupport::LogSubscriber.attach_to(:action_view, @@view_subscriber)
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
def self.to_sym
|
21
|
+
:views
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
+
def title
|
25
|
+
total_time = @@view_subscriber.events.select{ |e| e.name =~ /render_template/ }[0].duration
|
26
|
+
"<span style=\"background-color:#{generate_red_color(total_time)}\">View Render (#{"%.3f" % total_time}ms)</span>"
|
27
|
+
end
|
24
28
|
|
25
|
-
|
26
|
-
|
27
|
-
|
29
|
+
def content
|
30
|
+
html = ''
|
31
|
+
page = @@view_subscriber.events.select{ |e| e.name =~ /render_template/ }[0]
|
32
|
+
partials = @@view_subscriber.events.select{ |e| e.name =~ /render_partial/ }
|
33
|
+
partial_time = partials.inject(0) {|sum, item| sum += item.duration}
|
34
|
+
|
35
|
+
view = page.payload[:identifier].gsub(File.join(Rails.root,"app/views/"),"")
|
36
|
+
layout = page.payload[:layout].gsub(File.join(Rails.root,"app/views/"),"")
|
28
37
|
|
29
|
-
|
30
|
-
|
38
|
+
rows = [["View", "Layout", "View Render (ms)", "Partial(s) Render (ms)", "Total Render (ms)"],
|
39
|
+
[escape(view), escape(layout), "#{'%.3f' % (page.duration - partial_time)}",
|
40
|
+
"<a href=\"#\" onclick=\"Footnotes.hideAllAndToggle('partials_debug_info');return false;\">#{'%.3f' % partial_time}</a>",
|
41
|
+
"#{'%.3f' % page.duration}"]]
|
42
|
+
|
43
|
+
puts rows.inspect
|
44
|
+
|
45
|
+
mount_table(rows)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.load
|
49
|
+
self.loaded = true unless loaded
|
50
|
+
end
|
51
|
+
|
52
|
+
def generate_red_color(value)
|
53
|
+
if value > @@alert_time
|
54
|
+
"#f00"
|
55
|
+
else
|
56
|
+
"#aaa"
|
57
|
+
end
|
58
|
+
end
|
31
59
|
end
|
32
60
|
|
61
|
+
class ViewSubscriber < ActiveSupport::LogSubscriber
|
62
|
+
attr_accessor :events
|
63
|
+
def initialize
|
64
|
+
@events = Array.new
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
def render_template(event)
|
69
|
+
@events << event.dup
|
70
|
+
end
|
71
|
+
alias :render_partial :render_template
|
72
|
+
alias :render_collection :render_template
|
33
73
|
end
|
34
74
|
end
|
35
75
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails3-footnotes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 1923831855
|
5
5
|
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 4
|
8
8
|
- 0
|
9
9
|
- 0
|
10
10
|
- pre
|
11
|
-
-
|
12
|
-
version: 4.0.0.pre.
|
11
|
+
- 3
|
12
|
+
version: 4.0.0.pre.3
|
13
13
|
platform: ruby
|
14
14
|
authors:
|
15
15
|
- "Andr\xC3\xA9 Arko"
|
@@ -35,6 +35,21 @@ dependencies:
|
|
35
35
|
version: "3.0"
|
36
36
|
type: :runtime
|
37
37
|
version_requirements: *id001
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: bundler
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: 15
|
47
|
+
segments:
|
48
|
+
- 1
|
49
|
+
- 0
|
50
|
+
version: "1.0"
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
38
53
|
description: Adds footnotes to each page in your Rails app, containing useful development information as well as links to edit the controllers and views in your editor.
|
39
54
|
email: andre@arko.net
|
40
55
|
executables: []
|
@@ -57,7 +72,6 @@ files:
|
|
57
72
|
- lib/rails-footnotes/notes/env_note.rb
|
58
73
|
- lib/rails-footnotes/notes/files_note.rb
|
59
74
|
- lib/rails-footnotes/notes/filters_note.rb
|
60
|
-
- lib/rails-footnotes/notes/general_note.rb
|
61
75
|
- lib/rails-footnotes/notes/javascripts_note.rb
|
62
76
|
- lib/rails-footnotes/notes/layout_note.rb
|
63
77
|
- lib/rails-footnotes/notes/log_note.rb
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require "#{File.dirname(__FILE__)}/abstract_note"
|
2
|
-
|
3
|
-
module Footnotes
|
4
|
-
module Notes
|
5
|
-
class GeneralNote < AbstractNote
|
6
|
-
def title
|
7
|
-
'General Debug'
|
8
|
-
end
|
9
|
-
|
10
|
-
def legend
|
11
|
-
'General (id="general_debug_info")'
|
12
|
-
end
|
13
|
-
|
14
|
-
def content
|
15
|
-
'You can use this tab to debug other parts of your application, for example Javascript.'
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|