lexrupy-rails-footnotes 3.3.2

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.
@@ -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