artofmission-rails-footnotes 3.6.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +62 -0
- data/MIT-LICENSE +21 -0
- data/README +156 -0
- data/Rakefile +19 -0
- data/lib/rails-footnotes.rb +20 -0
- data/lib/rails-footnotes/backtracer.rb +34 -0
- data/lib/rails-footnotes/footnotes.rb +339 -0
- data/lib/rails-footnotes/notes/abstract_note.rb +174 -0
- data/lib/rails-footnotes/notes/assigns_note.rb +44 -0
- data/lib/rails-footnotes/notes/controller_note.rb +57 -0
- data/lib/rails-footnotes/notes/cookies_note.rb +19 -0
- data/lib/rails-footnotes/notes/env_note.rb +19 -0
- data/lib/rails-footnotes/notes/files_note.rb +44 -0
- data/lib/rails-footnotes/notes/filters_note.rb +53 -0
- data/lib/rails-footnotes/notes/general_note.rb +19 -0
- data/lib/rails-footnotes/notes/javascripts_note.rb +16 -0
- data/lib/rails-footnotes/notes/layout_note.rb +28 -0
- data/lib/rails-footnotes/notes/log_note.rb +36 -0
- data/lib/rails-footnotes/notes/params_note.rb +19 -0
- data/lib/rails-footnotes/notes/queries_note.rb +172 -0
- data/lib/rails-footnotes/notes/routes_note.rb +59 -0
- data/lib/rails-footnotes/notes/rpm_note.rb +24 -0
- data/lib/rails-footnotes/notes/session_note.rb +19 -0
- data/lib/rails-footnotes/notes/stylesheets_note.rb +16 -0
- data/lib/rails-footnotes/notes/view_note.rb +35 -0
- data/test/footnotes_test.rb +199 -0
- data/test/notes/abstract_note_test.rb +107 -0
- data/test/test_helper.rb +9 -0
- metadata +80 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/abstract_note"
|
2
|
+
|
3
|
+
module Footnotes
|
4
|
+
module Notes
|
5
|
+
class LayoutNote < AbstractNote
|
6
|
+
def initialize(controller)
|
7
|
+
@controller = controller
|
8
|
+
end
|
9
|
+
|
10
|
+
def row
|
11
|
+
:edit
|
12
|
+
end
|
13
|
+
|
14
|
+
def link
|
15
|
+
escape(Footnotes::Filter.prefix(filename, 1, 1))
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid?
|
19
|
+
prefix? && @controller.active_layout
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
def filename
|
24
|
+
File.join(File.expand_path(RAILS_ROOT), 'app', 'layouts', "#{@controller.active_layout.to_s.underscore}").sub('/layouts/layouts/', '/views/layouts/')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/abstract_note"
|
2
|
+
|
3
|
+
module Footnotes
|
4
|
+
module Notes
|
5
|
+
class LogNote < AbstractNote
|
6
|
+
def initialize(controller)
|
7
|
+
@controller = controller
|
8
|
+
end
|
9
|
+
|
10
|
+
def content
|
11
|
+
escape(log_tail).gsub("\n","<br />")
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
def log_tail
|
16
|
+
filename = if RAILS_DEFAULT_LOGGER.instance_variable_get('@log')
|
17
|
+
RAILS_DEFAULT_LOGGER.instance_variable_get('@log').path
|
18
|
+
else
|
19
|
+
RAILS_DEFAULT_LOGGER.instance_variable_get('@logdev').filename
|
20
|
+
end
|
21
|
+
file_string = File.open(filename).read.to_s
|
22
|
+
|
23
|
+
# We try to select the specified action from the log
|
24
|
+
# If we can't find it, we get the last 100 lines
|
25
|
+
#
|
26
|
+
if rindex = file_string.rindex('Processing '+@controller.controller_class_name+'#'+@controller.action_name)
|
27
|
+
file_string[rindex..-1].gsub(/\e\[.+?m/, '')
|
28
|
+
else
|
29
|
+
lines = file_string.split("\n")
|
30
|
+
index = [lines.size-100,0].max
|
31
|
+
lines[index..-1].join("\n")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/abstract_note"
|
2
|
+
|
3
|
+
module Footnotes
|
4
|
+
module Notes
|
5
|
+
class ParamsNote < AbstractNote
|
6
|
+
def initialize(controller)
|
7
|
+
@params = controller.params.symbolize_keys
|
8
|
+
end
|
9
|
+
|
10
|
+
def title
|
11
|
+
"Params (#{@params.length})"
|
12
|
+
end
|
13
|
+
|
14
|
+
def content
|
15
|
+
mount_table_for_hash(@params)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/abstract_note"
|
2
|
+
|
3
|
+
module Footnotes
|
4
|
+
module Notes
|
5
|
+
class QueriesNote < AbstractNote
|
6
|
+
@@alert_db_time = 0.16
|
7
|
+
@@alert_sql_number = 8
|
8
|
+
@@sql = []
|
9
|
+
cattr_accessor :sql, :alert_db_time, :alert_sql_number, :alert_explain, :instance_writter => false
|
10
|
+
|
11
|
+
def self.start!(controller)
|
12
|
+
@@sql = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.to_sym
|
16
|
+
:queries
|
17
|
+
end
|
18
|
+
|
19
|
+
def title
|
20
|
+
db_time = @@sql.inject(0){|sum, item| sum += item.time }
|
21
|
+
query_color = generate_red_color(@@sql.length, alert_sql_number)
|
22
|
+
db_color = generate_red_color(db_time, alert_db_time)
|
23
|
+
|
24
|
+
<<-TITLE
|
25
|
+
<span style="background-color:#{query_color}">Queries (#{@@sql.length})</span>
|
26
|
+
<span style="background-color:#{db_color}">DB (#{"%.6f" % db_time}s)</span>
|
27
|
+
TITLE
|
28
|
+
end
|
29
|
+
|
30
|
+
def stylesheet
|
31
|
+
<<-STYLESHEET
|
32
|
+
#queries_debug_info table td, #queries_debug_info table th{border:1px solid #A00; padding:0 3px; text-align:center;}
|
33
|
+
#queries_debug_info table thead, #queries_debug_info table tbody {color:#A00;}
|
34
|
+
#queries_debug_info p {background-color:#F3F3FF; border:1px solid #CCC; margin:12px; padding:4px 6px;}
|
35
|
+
#queries_debug_info a:hover {text-decoration:underline;}
|
36
|
+
STYLESHEET
|
37
|
+
end
|
38
|
+
|
39
|
+
def content
|
40
|
+
html = ''
|
41
|
+
|
42
|
+
@@sql.each_with_index do |item, i|
|
43
|
+
sql_links = []
|
44
|
+
sql_links << "<a href=\"javascript:Footnotes.toggle('qtable_#{i}')\" style=\"color:#A00;\">explain</a>" if item.explain
|
45
|
+
sql_links << "<a href=\"javascript:Footnotes.toggle('qtrace_#{i}')\" style=\"color:#00A;\">trace</a>" if item.trace
|
46
|
+
|
47
|
+
html << <<-HTML
|
48
|
+
<b id="qtitle_#{i}">#{escape(item.type.to_s.upcase)}</b> (#{sql_links.join(' | ')})<br />
|
49
|
+
#{print_name_and_time(item.name, item.time)}<br />
|
50
|
+
<span id="explain_#{i}">#{print_query(item.query)}</span><br />
|
51
|
+
#{print_explain(i, item.explain) if item.explain}
|
52
|
+
<p id="qtrace_#{i}" style="display:none;">#{parse_trace(item.trace) if item.trace}</p><br />
|
53
|
+
HTML
|
54
|
+
end
|
55
|
+
|
56
|
+
return html
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
def parse_explain(results)
|
61
|
+
table = []
|
62
|
+
table << results.fetch_fields.map(&:name)
|
63
|
+
results.each do |row|
|
64
|
+
table << row
|
65
|
+
end
|
66
|
+
table
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_trace(trace)
|
70
|
+
trace.map do |t|
|
71
|
+
s = t.split(':')
|
72
|
+
%[<a href="#{escape(Footnotes::Filter.prefix("#{RAILS_ROOT}/#{s[0]}", s[1].to_i, 1))}">#{escape(t)}</a><br />]
|
73
|
+
end.join
|
74
|
+
end
|
75
|
+
|
76
|
+
def print_name_and_time(name, time)
|
77
|
+
"<span style='background-color:#{generate_red_color(time, alert_ratio)}'>#{escape(name || 'SQL')} (#{sprintf('%f', time)}s)</span>"
|
78
|
+
end
|
79
|
+
|
80
|
+
def print_query(query)
|
81
|
+
escape(query.to_s.gsub(/(\s)+/, ' ').gsub('`', ''))
|
82
|
+
end
|
83
|
+
|
84
|
+
def print_explain(i, explain)
|
85
|
+
mount_table(parse_explain(explain), :id => "qtable_#{i}", :style => 'margin:10px;display:none;')
|
86
|
+
end
|
87
|
+
|
88
|
+
def generate_red_color(value, alert)
|
89
|
+
c = ((value.to_f/alert).to_i - 1) * 16
|
90
|
+
c = 0 if c < 0
|
91
|
+
c = 15 if c > 15
|
92
|
+
|
93
|
+
c = (15-c).to_s(16)
|
94
|
+
"#ff#{c*4}"
|
95
|
+
end
|
96
|
+
|
97
|
+
def alert_ratio
|
98
|
+
alert_db_time / alert_sql_number
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
module Extensions
|
105
|
+
class Sql
|
106
|
+
attr_accessor :type, :name, :time, :query, :explain, :trace
|
107
|
+
|
108
|
+
def initialize(type, name, time, query, explain)
|
109
|
+
@type = type
|
110
|
+
@name = name
|
111
|
+
@time = time
|
112
|
+
@query = query
|
113
|
+
@explain = explain
|
114
|
+
|
115
|
+
# Strip, select those ones from app and reject first two, because they
|
116
|
+
# are from the plugin
|
117
|
+
@trace = Kernel.caller.collect(&:strip).select{|i| i.gsub!(/^#{RAILS_ROOT}\//im, '') }[2..-1]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
module QueryAnalyzer
|
122
|
+
def self.included(base)
|
123
|
+
base.class_eval do
|
124
|
+
alias_method_chain :execute, :analyzer
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def execute_with_analyzer(query, name = nil)
|
129
|
+
query_results = nil
|
130
|
+
time = Benchmark.realtime { query_results = execute_without_analyzer(query, name) }
|
131
|
+
|
132
|
+
if query =~ /^(select|create|update|delete)\b/i
|
133
|
+
type = $&.downcase.to_sym
|
134
|
+
explain = nil
|
135
|
+
|
136
|
+
if adapter_name == 'MySQL' && type == :select
|
137
|
+
log_silence do
|
138
|
+
explain = execute_without_analyzer("EXPLAIN #{query}", name)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
Footnotes::Notes::QueriesNote.sql << Footnotes::Extensions::Sql.new(type, name, time, query, explain)
|
142
|
+
end
|
143
|
+
|
144
|
+
query_results
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
module AbstractAdapter
|
149
|
+
def log_silence
|
150
|
+
result = nil
|
151
|
+
if @logger
|
152
|
+
@logger.silence do
|
153
|
+
result = yield
|
154
|
+
end
|
155
|
+
else
|
156
|
+
result = yield
|
157
|
+
end
|
158
|
+
result
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
if Footnotes::Notes::QueriesNote.included?
|
166
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.send :include, Footnotes::Extensions::AbstractAdapter
|
167
|
+
ActiveRecord::ConnectionAdapters.local_constants.each do |adapter|
|
168
|
+
next unless adapter =~ /.*[^Abstract]Adapter$/
|
169
|
+
next if adapter =~ /SQLiteAdapter$/
|
170
|
+
eval("ActiveRecord::ConnectionAdapters::#{adapter}").send :include, Footnotes::Extensions::QueryAnalyzer
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/abstract_note"
|
2
|
+
|
3
|
+
module Footnotes
|
4
|
+
module Notes
|
5
|
+
class RoutesNote < AbstractNote
|
6
|
+
def initialize(controller)
|
7
|
+
@controller = controller
|
8
|
+
@parsed_routes = parse_routes
|
9
|
+
end
|
10
|
+
|
11
|
+
def legend
|
12
|
+
"Routes for #{@controller.class.to_s}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def content
|
16
|
+
mount_table(@parsed_routes.unshift([:path, :name, :options, :requirements]))
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
def parse_routes
|
21
|
+
routes_with_name = ActionController::Routing::Routes.named_routes.to_a.flatten
|
22
|
+
|
23
|
+
return ActionController::Routing::Routes.filtered_routes(:controller => @controller.controller_path).collect do |route|
|
24
|
+
# Catch routes name if exists
|
25
|
+
i = routes_with_name.index(route)
|
26
|
+
name = i ? routes_with_name[i-1].to_s : ''
|
27
|
+
|
28
|
+
# Catch segments requirements
|
29
|
+
req = {}
|
30
|
+
route.segments.each do |segment|
|
31
|
+
next unless segment.is_a?(ActionController::Routing::DynamicSegment) && segment.regexp
|
32
|
+
req[segment.key.to_sym] = segment.regexp
|
33
|
+
end
|
34
|
+
|
35
|
+
[escape(name), route.segments.join, route.requirements.reject{|key,value| key == :controller}.inspect, req.inspect]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Extensions
|
42
|
+
module Routes
|
43
|
+
# Filter routes according to the filter sent
|
44
|
+
#
|
45
|
+
def filtered_routes(filter = {})
|
46
|
+
return [] unless filter.is_a?(Hash)
|
47
|
+
return routes.reject do |r|
|
48
|
+
filter_diff = filter.diff(r.requirements)
|
49
|
+
route_diff = r.requirements.diff(filter)
|
50
|
+
(filter_diff == filter) || (filter_diff != route_diff)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if Footnotes::Notes::RoutesNote.included?
|
58
|
+
ActionController::Routing::RouteSet.send :include, Footnotes::Extensions::Routes
|
59
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/abstract_note"
|
2
|
+
|
3
|
+
module Footnotes
|
4
|
+
module Notes
|
5
|
+
class RpmNote < AbstractNote
|
6
|
+
def initialize(controller)
|
7
|
+
@rpm_id=NewRelic::Agent.instance.transaction_sampler.current_sample_id
|
8
|
+
end
|
9
|
+
|
10
|
+
def row
|
11
|
+
:edit
|
12
|
+
end
|
13
|
+
|
14
|
+
def link
|
15
|
+
#{:controller => 'newrelic', :action => 'show_sample_detail', :id => @rpm_id}
|
16
|
+
"/newrelic/show_sample_detail/#{@rpm_id}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid?
|
20
|
+
!NewRelic::Config.instance['skip_developer_route']
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/abstract_note"
|
2
|
+
|
3
|
+
module Footnotes
|
4
|
+
module Notes
|
5
|
+
class SessionNote < AbstractNote
|
6
|
+
def initialize(controller)
|
7
|
+
@session = (controller.session.data || {}).symbolize_keys
|
8
|
+
end
|
9
|
+
|
10
|
+
def title
|
11
|
+
"Session (#{@session.length})"
|
12
|
+
end
|
13
|
+
|
14
|
+
def content
|
15
|
+
mount_table_for_hash(@session)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/files_note"
|
2
|
+
|
3
|
+
module Footnotes
|
4
|
+
module Notes
|
5
|
+
class StylesheetsNote < FilesNote
|
6
|
+
def title
|
7
|
+
"Stylesheets (#{@files.length})"
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
def scan_text(text)
|
12
|
+
text.scan(/<link[^>]+href\s*=\s*['"]([^>?'"]+\.css)/im).flatten
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/abstract_note"
|
2
|
+
|
3
|
+
module Footnotes
|
4
|
+
module Notes
|
5
|
+
class ViewNote < AbstractNote
|
6
|
+
def initialize(controller)
|
7
|
+
@controller = controller
|
8
|
+
@template = controller.instance_variable_get(:@template)
|
9
|
+
end
|
10
|
+
|
11
|
+
def row
|
12
|
+
:edit
|
13
|
+
end
|
14
|
+
|
15
|
+
def link
|
16
|
+
escape(Footnotes::Filter.prefix(filename, 1, 1))
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid?
|
20
|
+
prefix? && first_render?
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def first_render?
|
26
|
+
@template.instance_variable_get(:@_first_render)
|
27
|
+
end
|
28
|
+
|
29
|
+
def filename
|
30
|
+
@filename ||= @template.instance_variable_get(:@_first_render).filename
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
require 'action_controller'
|
4
|
+
require 'action_controller/test_case'
|
5
|
+
require 'action_controller/test_process'
|
6
|
+
|
7
|
+
class FootnotesController < ActionController::Base; attr_accessor :template, :performed_render; end
|
8
|
+
|
9
|
+
module Footnotes::Notes
|
10
|
+
class TestNote < AbstractNote
|
11
|
+
def self.to_sym; :test; end
|
12
|
+
def valid?; true; end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class FootnotesTest < Test::Unit::TestCase
|
17
|
+
def setup
|
18
|
+
@controller = FootnotesController.new
|
19
|
+
@controller.request = ActionController::TestRequest.new
|
20
|
+
@controller.response = ActionController::TestResponse.new
|
21
|
+
@controller.response.body = $html.dup
|
22
|
+
|
23
|
+
Footnotes::Filter.notes = [ :test ]
|
24
|
+
Footnotes::Filter.multiple_notes = false
|
25
|
+
@footnotes = Footnotes::Filter.new(@controller)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_footnotes_controller
|
29
|
+
index = @controller.response.body.index(/This is the HTML page/)
|
30
|
+
assert_equal 334, index
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_foonotes_included
|
34
|
+
footnotes_perform!
|
35
|
+
assert_not_equal $html, @controller.response.body
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_footnotes_not_included_when_request_is_xhr
|
39
|
+
@controller.request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
40
|
+
@controller.request.env['HTTP_ACCEPT'] = 'text/javascript, text/html, application/xml, text/xml, */*'
|
41
|
+
|
42
|
+
footnotes_perform!
|
43
|
+
assert_equal $html, @controller.response.body
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_footnotes_not_included_when_content_type_is_javascript
|
47
|
+
@controller.response.headers['Content-Type'] = 'text/javascript'
|
48
|
+
|
49
|
+
footnotes_perform!
|
50
|
+
assert_equal $html, @controller.response.body
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_footnotes_included_when_content_type_is_html
|
54
|
+
@controller.response.headers['Content-Type'] = 'text/html'
|
55
|
+
|
56
|
+
footnotes_perform!
|
57
|
+
assert_not_equal $html, @controller.response.body
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_footnotes_included_when_content_type_is_nil
|
61
|
+
footnotes_perform!
|
62
|
+
assert_not_equal $html, @controller.response.body
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_not_included_when_body_is_not_a_string
|
66
|
+
@controller.response.body = Proc.new{ Time.now }
|
67
|
+
assert_nothing_raised do
|
68
|
+
footnotes_perform!
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_footnotes_prefix
|
73
|
+
assert_equal 'txmt://open?url=file://%s&line=%d&column=%d', Footnotes::Filter.prefix
|
74
|
+
assert_equal 'txmt://open?url=file://file&line=0&column=0', Footnotes::Filter.prefix('file', 0, 0)
|
75
|
+
assert_equal 'txmt://open?url=file://file&line=10&column=10', Footnotes::Filter.prefix('file', 10, 10)
|
76
|
+
assert_equal 'txmt://open?url=file://file&line=10&column=10', Footnotes::Filter.prefix('file', 10, 10, 10)
|
77
|
+
assert_equal 'txmt://open?url=file://file&line=10&column=10', Footnotes::Filter.prefix('file', '10', '10')
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_notes_are_initialized
|
81
|
+
footnotes_perform!
|
82
|
+
test_note = @footnotes.instance_variable_get('@notes').first
|
83
|
+
assert 'Footnotes::Notes::TestNote', test_note.class
|
84
|
+
assert :test, test_note.to_sym
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_notes_links
|
88
|
+
note = Footnotes::Notes::TestNote.new
|
89
|
+
note.expects(:row).times(2)
|
90
|
+
@footnotes.instance_variable_set(:@notes, [note])
|
91
|
+
footnotes_perform!
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_notes_fieldset
|
95
|
+
note = Footnotes::Notes::TestNote.new
|
96
|
+
note.expects(:has_fieldset?).times(3)
|
97
|
+
@footnotes.instance_variable_set(:@notes, [note])
|
98
|
+
footnotes_perform!
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_multiple_notes
|
102
|
+
Footnotes::Filter.multiple_notes = true
|
103
|
+
note = Footnotes::Notes::TestNote.new
|
104
|
+
note.expects(:has_fieldset?).times(2)
|
105
|
+
@footnotes.instance_variable_set(:@notes, [note])
|
106
|
+
footnotes_perform!
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_notes_are_reset
|
110
|
+
note = Footnotes::Notes::TestNote.new
|
111
|
+
note.class.expects(:close!)
|
112
|
+
@footnotes.instance_variable_set(:@notes, [note])
|
113
|
+
@footnotes.send(:close!, @controller)
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_links_helper
|
117
|
+
note = Footnotes::Notes::TestNote.new
|
118
|
+
assert_equal '<a href="#" onclick="">Test</a>', @footnotes.send(:link_helper, note)
|
119
|
+
|
120
|
+
note.expects(:link).times(1).returns(:link)
|
121
|
+
assert_equal '<a href="link" onclick="">Test</a>', @footnotes.send(:link_helper, note)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_links_helper_has_fieldset?
|
125
|
+
note = Footnotes::Notes::TestNote.new
|
126
|
+
note.expects(:has_fieldset?).times(1).returns(true)
|
127
|
+
assert_equal '<a href="#" onclick="Footnotes.hideAllAndToggle(\'test_debug_info\');return false;">Test</a>', @footnotes.send(:link_helper, note)
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_links_helper_onclick
|
131
|
+
note = Footnotes::Notes::TestNote.new
|
132
|
+
note.expects(:onclick).times(2).returns(:onclick)
|
133
|
+
assert_equal '<a href="#" onclick="onclick">Test</a>', @footnotes.send(:link_helper, note)
|
134
|
+
|
135
|
+
note.expects(:has_fieldset?).times(1).returns(true)
|
136
|
+
assert_equal '<a href="#" onclick="onclick">Test</a>', @footnotes.send(:link_helper, note)
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_insert_style
|
140
|
+
@controller.response.body = "<head></head><split><body></body>"
|
141
|
+
@footnotes = Footnotes::Filter.new(@controller)
|
142
|
+
footnotes_perform!
|
143
|
+
assert @controller.response.body.split('<split>').first.include?('<!-- Footnotes Style -->')
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_insert_footnotes_inside_body
|
147
|
+
@controller.response.body = "<head></head><split><body></body>"
|
148
|
+
@footnotes = Footnotes::Filter.new(@controller)
|
149
|
+
footnotes_perform!
|
150
|
+
assert @controller.response.body.split('<split>').last.include?('<!-- End Footnotes -->')
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_insert_footnotes_inside_holder
|
154
|
+
@controller.response.body = "<head></head><split><div id='footnotes_holder'></div>"
|
155
|
+
@footnotes = Footnotes::Filter.new(@controller)
|
156
|
+
footnotes_perform!
|
157
|
+
assert @controller.response.body.split('<split>').last.include?('<!-- End Footnotes -->')
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_insert_text
|
161
|
+
@footnotes.send(:insert_text, :after, /<head>/, "Graffiti")
|
162
|
+
after = " <head>Graffiti\n"
|
163
|
+
assert_equal after, @controller.response.body.to_a[2]
|
164
|
+
|
165
|
+
@footnotes.send(:insert_text, :before, /<\/body>/, "Notes")
|
166
|
+
after = " Notes</body>\n"
|
167
|
+
assert_equal after, @controller.response.body.to_a[12]
|
168
|
+
end
|
169
|
+
|
170
|
+
protected
|
171
|
+
# First we make sure that footnotes will perform (long life to mocha!)
|
172
|
+
# Then we call add_footnotes!
|
173
|
+
#
|
174
|
+
def footnotes_perform!
|
175
|
+
@controller.template.expects(:instance_variable_get).returns(true)
|
176
|
+
@controller.template.expects(:template_format).returns('html')
|
177
|
+
@controller.performed_render = true
|
178
|
+
|
179
|
+
Footnotes::Filter.start!(@controller)
|
180
|
+
@footnotes.add_footnotes!
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
$html = <<HTML
|
185
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
186
|
+
<html>
|
187
|
+
<head>
|
188
|
+
<title>HTML to XHTML Example: HTML page</title>
|
189
|
+
<link rel="Stylesheet" href="htmltohxhtml.css" type="text/css" media="screen">
|
190
|
+
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
191
|
+
</head>
|
192
|
+
<body>
|
193
|
+
<p>This is the HTML page. It works and is encoded just like any HTML page you
|
194
|
+
have previously done. View <a href="htmltoxhtml2.htm">the XHTML version</a> of
|
195
|
+
this page to view the difference between HTML and XHTML.</p>
|
196
|
+
<p>You will be glad to know that no changes need to be made to any of your CSS files.</p>
|
197
|
+
</body>
|
198
|
+
</html>
|
199
|
+
HTML
|