lexrupy-rails-footnotes 3.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,16 @@
1
+ require "#{File.dirname(__FILE__)}/files_note"
2
+
3
+ module Footnotes
4
+ module Notes
5
+ class JavascriptsNote < FilesNote
6
+ def title
7
+ "Javascripts (#{@files.length})"
8
+ end
9
+
10
+ protected
11
+ def scan_text(text)
12
+ text.scan(/<script[^>]+src\s*=\s*['"]([^>?'"]+\.js)/im).flatten
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,33 @@
1
+ require "#{File.dirname(__FILE__)}/view_note"
2
+
3
+ module Footnotes
4
+ module Notes
5
+ class LayoutNote < 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(layout_filename, 1, 1))
17
+ end
18
+
19
+ def valid?
20
+ prefix? && @controller.active_layout && layout_template
21
+ end
22
+
23
+ protected
24
+ def layout_template
25
+ @layout_template ||= @template.send(:_pick_template, @controller.active_layout)
26
+ end
27
+
28
+ def layout_filename
29
+ layout_template.filename
30
+ end
31
+ end
32
+ end
33
+ 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
+ escape(@params.inspect)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,156 @@
1
+ require "#{File.dirname(__FILE__)}/abstract_note"
2
+
3
+ module Footnotes
4
+ module Notes
5
+ class QueriesNote < AbstractNote
6
+ @@sql = []
7
+ cattr_accessor :sql
8
+
9
+ def self.start!(controller)
10
+ @@sql = []
11
+ end
12
+
13
+ def self.to_sym
14
+ :queries
15
+ end
16
+
17
+ def title
18
+ "Queries (#{@@sql.length})"
19
+ end
20
+
21
+ def stylesheet
22
+ <<-STYLESHEET
23
+ #queries_debug_info table td, #queries_debug_info table th{border:1px solid #A00; padding:0 3px; text-align:center;}
24
+ #queries_debug_info table thead, #queries_debug_info table tbody {color:#A00;}
25
+ #queries_debug_info p {background-color:#F3F3FF; border:1px solid #CCC; margin:12px; padding:4px 6px;}
26
+ #queries_debug_info a:hover {text-decoration:underline;}
27
+ STYLESHEET
28
+ end
29
+
30
+ def javascript
31
+ <<-JAVASCRIPT
32
+ function queries_toogle(type, id){
33
+ s = document.getElementById('q'+type+'_'+id).style
34
+ s.display = (s.display != 'block') ? 'block' : 'none'
35
+ location.href = '#qtitle_'+id
36
+ }
37
+ JAVASCRIPT
38
+ end
39
+
40
+ def content
41
+ html = ''
42
+
43
+ @@sql.each_with_index do |item, i|
44
+ sql_links = []
45
+ sql_links << "<a href=\"#\" style=\"color:#A00;\" onclick=\"queries_toogle('table',#{i});return false\">explain</a>" if item.explain
46
+ sql_links << "<a href=\"#\" style=\"color:#00A;\" onclick=\"queries_toogle('trace',#{i});return false\">trace</a>" if item.trace
47
+
48
+ html << <<-HTML
49
+ <b id="qtitle_#{i}">#{escape(item.type.to_s.upcase)}</b> (#{sql_links.join(' | ')})<br />
50
+ #{print_name_and_time(item.name, item.time)}<br />
51
+ #{print_query(item.query)}<br />
52
+ #{print_explain(i, item.explain) if item.explain}
53
+ <p id="qtrace_#{i}" style="display:none;">#{parse_trace(item.trace) if item.trace}</p><br />
54
+ HTML
55
+ end
56
+
57
+ return html
58
+ end
59
+
60
+ protected
61
+ def parse_explain(results)
62
+ table = []
63
+ table << results.fetch_fields.map(&:name)
64
+ results.each{|row| table << row}
65
+ table
66
+ end
67
+
68
+ def parse_trace(trace)
69
+ trace.map do |t|
70
+ s = t.split(':')
71
+ %[<a href="#{escape(Footnotes::Filter.prefix("#{RAILS_ROOT}/#{s[0]}", s[1].to_i, 1))}">#{escape(t)}</a><br />]
72
+ end.join
73
+ end
74
+
75
+ def print_name_and_time(name, time)
76
+ "#{escape(name || 'SQL')} (#{sprintf('%f', time)}s)"
77
+ end
78
+
79
+ def print_query(query)
80
+ escape(query.to_s.gsub(/(\s)+/, ' ').gsub('`', ''))
81
+ end
82
+
83
+ def print_explain(i, explain)
84
+ mount_table(parse_explain(explain), :id => "qtable_#{i}", :style => 'margin:10px;display:none;')
85
+ end
86
+ end
87
+ end
88
+
89
+ module Extensions
90
+ class Sql
91
+ attr_accessor :type, :name, :time, :query, :explain, :trace
92
+
93
+ def initialize(type, name, time, query, explain)
94
+ @type = type
95
+ @name = name
96
+ @time = time
97
+ @query = query
98
+ @explain = explain
99
+
100
+ # Strip, select those ones from app and reject first two, because they are from the plugin
101
+ @trace = Kernel.caller.collect(&:strip).select{|i| i.gsub!(/^#{RAILS_ROOT}\//im, '') }[2..-1]
102
+ end
103
+ end
104
+
105
+ module QueryAnalyzer
106
+ def self.included(base)
107
+ base.class_eval do
108
+ alias_method_chain :execute, :analyzer
109
+ end
110
+ end
111
+
112
+ def execute_with_analyzer(query, name = nil)
113
+ query_results = nil
114
+ time = Benchmark.realtime { query_results = execute_without_analyzer(query, name) }
115
+
116
+ if query =~ /^(select|create|update|delete)\b/i
117
+ type = $&.downcase.to_sym
118
+ explain = nil
119
+
120
+ if adapter_name == 'MySQL' && type == :select
121
+ log_silence do
122
+ explain = execute_without_analyzer("EXPLAIN #{query}", name)
123
+ end
124
+ end
125
+ Footnotes::Notes::QueriesNote.sql << Footnotes::Extensions::Sql.new(type, name, time, query, explain)
126
+ end
127
+
128
+ query_results
129
+ end
130
+ end
131
+
132
+ module AbstractAdapter
133
+ def log_silence
134
+ result = nil
135
+ if @logger
136
+ @logger.silence do
137
+ result = yield
138
+ end
139
+ else
140
+ result = yield
141
+ end
142
+ result
143
+ end
144
+ end
145
+
146
+ end
147
+ end
148
+
149
+ if Footnotes::Notes::QueriesNote.included?
150
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.send :include, Footnotes::Extensions::AbstractAdapter
151
+ ActiveRecord::ConnectionAdapters.local_constants.each do |adapter|
152
+ next unless adapter =~ /.*[^Abstract]Adapter$/
153
+ next if adapter =~ /SQLite.Adapter$/
154
+ eval("ActiveRecord::ConnectionAdapters::#{adapter}").send :include, Footnotes::Extensions::QueryAnalyzer
155
+ end
156
+ 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_name).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,15 @@
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.instance_variable_get("@data") || {}).symbolize_keys
8
+ end
9
+
10
+ def content
11
+ escape(@session.inspect)
12
+ end
13
+ end
14
+ end
15
+ 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,33 @@
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
+ def first_render?
25
+ @template.instance_variable_get(:@_first_render)
26
+ end
27
+
28
+ def filename
29
+ @filename ||= @template.instance_variable_get(:@_first_render).filename
30
+ end
31
+ end
32
+ end
33
+ 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_toogle(\'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