rails-footnotes 3.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ == Footnotes v3.6
2
+ * Cookies, sessions and params notes now use table;
3
+ * Old components note removed;
4
+ * Added assigns notes (thanks to scorpio);
5
+ * Improve query note, count query time and display it with several configurable
6
+ options (:alert_db_time and :alert_sql_number) (thanks to scorpio);
7
+ * Fixed bugs of layout link and route note related (thanks to scorpio).
8
+
9
+ == Footnotes v3.5
10
+ * Added NewRelic RPM footnote (thanks to kbrock);
11
+ * Several bug fixes (thanks to kbrock, ivanoats and kristopher).
12
+
13
+ == Footnotes v3.4
14
+ * Rails 2.3 compatible.
15
+
16
+ == Footnotes v3.3.1
17
+ * Changed prefix to support %s and %d;
18
+ * Created gemspec;
19
+ * Some code refactoring (called eval just once instead of three times).
20
+
21
+ == Footnotes v3.3
22
+ * Rails Edge (aka 2.2) compatibility;
23
+ * Initial Ruby 1.9 compatibility.
24
+
25
+ == Footnotes v3.2.2
26
+ * Added trace to QueriesNote;
27
+ * Fixed incompatibility with Ultrasphinx (thanks to mhartl);
28
+ * Added W3C compatibility (thanks to tapajos);
29
+ * Added support to other log mechanisms in LogNote.
30
+
31
+ == Footnotes v3.2.1
32
+ * Added some tests;
33
+ * Redefined Footnotes CSS and Javascripts to use concise names.
34
+
35
+ == Footnotes v3.2
36
+ * Now you can easily add your own notes;
37
+ * Added numbers to tabs;
38
+ * Added Queries note;
39
+ * Added MySQL Query Analyzer.
40
+
41
+ == Footnotes v3.1
42
+ * Code refactoring (using modules, except backtracer);
43
+ * Ability to cherry pick notes;
44
+ * Working on Rails 2.1.
45
+
46
+ == Footnotes v3.0
47
+ * Some code refactoring;
48
+ * Stylesheets bug fixed: was showing not only css in Stylesheets div;
49
+ * Logtail fix: working with Rails 2.0 logger and in all OS, since it's Regexp based;
50
+ * Rails 1.2 (except backtrace) and 2.0 compatible;
51
+ * RoutingNavigator (based on Rick Olson plugin);
52
+ * FilterChain.
53
+
54
+ == Textmate Footnotes v2.0
55
+ Copyright (c) 2006 InquiryLabs, Inc.
56
+ http://inquirylabs.com/
57
+
58
+ Description:
59
+ Creates clickable footnotes on each rendered page, as well as clickable
60
+ links in the backtrace should an error occur in your Rails app. Links take
61
+ you to the right place inside TextMate.
62
+ Enable only the TextMate on Macs in development mode
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2006 Coda Hale
2
+ Copyright (c) 2008 José Valim (jose.valim at gmail dot com)
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,141 @@
1
+ Rails Footnotes
2
+ License: MIT
3
+ Version: 3.6.3
4
+
5
+ You can also read this README in pretty html at the GitHub project Wiki page
6
+
7
+ http://wiki.github.com/josevalim/rails-footnotes
8
+
9
+
10
+ Description
11
+ -----------
12
+
13
+ If you are developing in Rails you should know the plugin! It displays
14
+ footnotes in your application for easy debugging, such as sessions,
15
+ request parameters, cookies, filter chain, routes, queries, etc.
16
+
17
+ Even more, it contains links to open files directly in your editor including
18
+ your backtrace lines.
19
+
20
+
21
+ Installation
22
+ ------------
23
+
24
+ Install Rails Footnotes is very easy. If you are running on Rails 2.3 just run
25
+ the following:
26
+
27
+ gem sources -a http://gemcutter.org
28
+ sudo gem install rails-footnotes
29
+
30
+ In RAILS_ROOT/config/environments/development.rb (yes, you want it only in development):
31
+
32
+ config.gem "rails-footnotes", :source => "http://gemcutter.org"
33
+
34
+ If you want it as plugin, just do:
35
+
36
+ script/plugin install git://github.com/josevalim/rails-footnotes.git
37
+
38
+ Configuration
39
+ -------------
40
+
41
+ If you are not using Textmate as text editor, in your environment.rb or
42
+ in an initializer do:
43
+
44
+ if defined?(Footnotes)
45
+ Footnotes::Filter.prefix = 'txmt://open?url=file://%s&line=%d&column=%d'
46
+ end
47
+
48
+ Where you are going to choose a prefix compatible with your text editor. The %s is
49
+ replaced by the name of the file, the first %d is replaced by the line number and
50
+ the second %d is replaced by the column.
51
+
52
+ By default, footnotes are appended at the end of the page with default stylesheet. If you want
53
+ to change their position, you can define a div with id "footnotes_holder" or define your own stylesheet
54
+ by turning footnotes stylesheet off:
55
+
56
+ Footnotes::Filter.no_style = true
57
+
58
+ Another option is to allow multiple notes to be opened at the same time:
59
+
60
+ Footnotes::Filter.multiple_notes = true
61
+
62
+ Finally, you can control which notes you want to show. The default are:
63
+
64
+ Footnotes::Filter.notes = [:session, :cookies, :params, :filters, :routes, :env, :queries, :log, :general]
65
+
66
+
67
+ Creating your own notes
68
+ -----------------------
69
+
70
+ Create your notes to integrate with Footnotes is easy.
71
+
72
+ 1. Create a Footnotes::Notes::YourExampleNote class
73
+
74
+ 2. Implement the necessary methods (check abstract_note.rb file in lib/notes)
75
+
76
+ 3. Append your example note in Footnotes::Filter.notes array (usually at the end of your environment file or in an initializer):
77
+
78
+ For example, to create a note that shows info about the user logged in your application you just have to do:
79
+
80
+ module Footnotes
81
+ module Notes
82
+ class CurrentUserNote < AbstractNote
83
+ # This method always receives a controller
84
+ #
85
+ def initialize(controller)
86
+ @current_user = controller.instance_variable_get("@current_user")
87
+ end
88
+
89
+ # The name that will appear as legend in fieldsets
90
+ #
91
+ def legend
92
+ "Current user: #{@current_user.name}"
93
+ end
94
+
95
+ # This Note is only valid if we actually found an user
96
+ # If it's not valid, it won't be displayed
97
+ #
98
+ def valid?
99
+ @current_user
100
+ end
101
+
102
+ # The fieldset content
103
+ #
104
+ def content
105
+ escape(@current_user.inspect)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ Then put in your environment:
112
+
113
+ Footnotes::Filter.notes += [:current_user]
114
+
115
+
116
+ Colaborators
117
+ ------------
118
+
119
+ * Leon Li - http://github.com/scorpio
120
+ * Keenan Brock - http://github.com/kbrock
121
+ * Ivan Storck - http://github.com/ivanoats
122
+ * Kris Chamber - http://github.com/kristopher
123
+
124
+
125
+ Bugs and Feedback
126
+ -----------------
127
+
128
+ If you discover any bugs, please send an e-mail to jose@plataformatec.com.br
129
+ If you just want to give some positive feedback or drop a line, that's fine too!
130
+
131
+ Copyright (c) 2009 José Valim (jose@plataformatec.com.br)
132
+ http://blog.plataformatec.com.br/
133
+
134
+
135
+ Version 2.0
136
+ -----------
137
+
138
+ This plugin was created and maintained until version 2.0 by Duane Johnson:
139
+
140
+ Copyright (c) 2006 InquiryLabs, Inc.
141
+ http://blog.inquirylabs.com/
@@ -0,0 +1,38 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |s|
8
+ s.name = "rails-footnotes"
9
+ s.version = "3.6.3"
10
+ s.rubyforge_project = "rails-footnotes"
11
+ s.summary = "Every Rails page has footnotes that gives information about your application and links back to your editor."
12
+ s.email = "jose@plataformatec.com.br"
13
+ s.homepage = "http://github.com/josevalim/rails-footnotes"
14
+ s.description = "Every Rails page has footnotes that gives information about your application and links back to your editor."
15
+ s.authors = ['José Valim']
16
+ s.files = FileList["[A-Z]*", "{lib}/**/*"]
17
+ end
18
+
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
22
+ end
23
+
24
+ desc 'Run tests for Footnotes.'
25
+ Rake::TestTask.new(:test) do |t|
26
+ t.pattern = 'test/**/*_test.rb'
27
+ t.verbose = true
28
+ end
29
+
30
+ desc 'Generate documentation for Footnotes.'
31
+ Rake::RDocTask.new(:rdoc) do |rdoc|
32
+ rdoc.rdoc_dir = 'rdoc'
33
+ rdoc.title = 'Footnotes'
34
+ rdoc.options << '--line-numbers' << '--inline-source'
35
+ rdoc.rdoc_files.include('README')
36
+ rdoc.rdoc_files.include('MIT-LICENSE')
37
+ rdoc.rdoc_files.include('lib/**/*.rb')
38
+ end
@@ -0,0 +1,20 @@
1
+ if RAILS_ENV == 'development'
2
+ dir = File.dirname(__FILE__)
3
+ require File.join(dir, 'rails-footnotes', 'footnotes')
4
+ require File.join(dir, 'rails-footnotes', 'backtracer')
5
+
6
+ # Load all notes
7
+ #
8
+ Dir[File.join(dir, 'rails-footnotes', 'notes', '*.rb')].each do |note|
9
+ require note unless note =~ /queries/ && !defined?(ActiveRecord)
10
+ end
11
+
12
+ # The footnotes are applied by default to all actions. You can change this
13
+ # behavior commenting the after_filter line below and putting it in Your
14
+ # application. Then you can cherrypick in which actions it will appear.
15
+ #
16
+ class ActionController::Base
17
+ prepend_before_filter Footnotes::Filter
18
+ after_filter Footnotes::Filter
19
+ end
20
+ end
@@ -0,0 +1,34 @@
1
+ module Footnotes
2
+ module Extensions
3
+ module Exception
4
+ def self.included(base)
5
+ base.class_eval do
6
+ alias_method_chain :clean_backtrace, :links
7
+ end
8
+ end
9
+
10
+ def add_links_to_backtrace(lines)
11
+ lines.collect do |line|
12
+ expanded = line.gsub('#{RAILS_ROOT}', RAILS_ROOT)
13
+ if match = expanded.match(/^(.+):(\d+):in/) || match = expanded.match(/^(.+):(\d+)\s*$/)
14
+ file = File.expand_path(match[1])
15
+ line_number = match[2]
16
+ html = %[<a href="#{Footnotes::Filter.prefix(file, line_number, 1)}">#{line}</a>]
17
+ else
18
+ line
19
+ end
20
+ end
21
+ end
22
+
23
+ def clean_backtrace_with_links
24
+ unless ::Footnotes::Filter.prefix.blank?
25
+ add_links_to_backtrace(clean_backtrace_without_links)
26
+ else
27
+ clean_backtrace_without_links
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ Exception.send :include, Footnotes::Extensions::Exception
@@ -0,0 +1,339 @@
1
+ module Footnotes
2
+ class Filter
3
+ @@no_style = false
4
+ @@multiple_notes = false
5
+ @@klasses = []
6
+
7
+ # Default link prefix is textmate
8
+ @@prefix = 'txmt://open?url=file://%s&amp;line=%d&amp;column=%d'
9
+
10
+ # Edit notes
11
+ @@notes = [ :controller, :view, :layout, :stylesheets, :javascripts ]
12
+ # Show notes
13
+ @@notes += [ :assigns, :session, :cookies, :params, :filters, :routes, :env, :queries, :log, :general ]
14
+
15
+ # Change queries for rpm note when available
16
+ # if defined?(NewRelic)
17
+ # @@notes.delete(:queries)
18
+ # @@notes << :rpm
19
+ # end
20
+
21
+ # :no_style => If you don't want the style to be appended to your pages
22
+ # :notes => Class variable that holds the notes to be processed
23
+ # :prefix => Prefix appended to FootnotesLinks
24
+ # :multiple_notes => Set to true if you want to open several notes at the same time
25
+ cattr_accessor :no_style, :notes, :prefix, :multiple_notes
26
+
27
+ class << self
28
+ # Method called to start the notes
29
+ # It's a before filter prepend in the controller
30
+ #
31
+ def before(controller)
32
+ Footnotes::Filter.start!(controller)
33
+ end
34
+
35
+ # Method that calls Footnotes to attach its contents
36
+ #
37
+ def after(controller)
38
+ filter = Footnotes::Filter.new(controller)
39
+ filter.add_footnotes!
40
+ filter.close!(controller)
41
+ end
42
+
43
+ # Calls the class method start! in each note
44
+ # Sometimes notes need to set variables or clean the environment to work properly
45
+ # This method allows this kind of setup
46
+ #
47
+ def start!(controller)
48
+ @@klasses = []
49
+
50
+ each_with_rescue(@@notes.flatten) do |note|
51
+ klass = "Footnotes::Notes::#{note.to_s.camelize}Note".constantize
52
+ klass.start!(controller) if klass.respond_to?(:start!)
53
+ @@klasses << klass
54
+ end
55
+ end
56
+
57
+ # Process notes, discarding only the note if any problem occurs
58
+ #
59
+ def each_with_rescue(notes)
60
+ delete_me = []
61
+
62
+ notes.each do |note|
63
+ begin
64
+ yield note
65
+ rescue Exception => e
66
+ # Discard note if it has a problem
67
+ log_error("Footnotes #{note.to_s.camelize}Note Exception", e)
68
+ delete_me << note
69
+ next
70
+ end
71
+ end
72
+
73
+ delete_me.each{ |note| notes.delete(note) }
74
+ return notes
75
+ end
76
+
77
+ # Logs the error using specified title and format
78
+ #
79
+ def log_error(title, exception)
80
+ RAILS_DEFAULT_LOGGER.error "#{title}: #{exception}\n#{exception.backtrace.join("\n")}"
81
+ end
82
+
83
+ # If none argument is sent, simply return the prefix.
84
+ # Otherwise, replace the args in the prefix.
85
+ #
86
+ def prefix(*args)
87
+ if args.empty?
88
+ @@prefix
89
+ else
90
+ format(@@prefix, *args)
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ def initialize(controller)
97
+ @controller = controller
98
+ @template = controller.instance_variable_get(:@template)
99
+ @body = controller.response.body
100
+ @notes = []
101
+ end
102
+
103
+ def add_footnotes!
104
+ add_footnotes_without_validation! if valid?
105
+ rescue Exception => e
106
+ # Discard footnotes if there are any problems
107
+ self.class.log_error("Footnotes Exception", e)
108
+ end
109
+
110
+ # Calls the class method close! in each note
111
+ # Sometimes notes need to finish their work even after being read
112
+ # This method allows this kind of work
113
+ #
114
+ def close!(controller)
115
+ each_with_rescue(@@klasses) do |klass|
116
+ klass.close!(controller)
117
+ end
118
+ end
119
+
120
+ protected
121
+ def valid?
122
+ performed_render? && valid_format? && valid_content_type? && @body.is_a?(String) && !component_request? && !xhr?
123
+ end
124
+
125
+ def add_footnotes_without_validation!
126
+ initialize_notes!
127
+ insert_styles unless @@no_style
128
+ insert_footnotes
129
+ end
130
+
131
+ def initialize_notes!
132
+ each_with_rescue(@@klasses) do |klass|
133
+ note = klass.new(@controller)
134
+ @notes << note if note.respond_to?(:valid?) && note.valid?
135
+ end
136
+ end
137
+
138
+ def performed_render?
139
+ @controller.instance_variable_get(:@performed_render)
140
+ end
141
+
142
+ def valid_format?
143
+ [:html,:rhtml,:xhtml,:rxhtml].include?(@template.template_format.to_sym)
144
+ end
145
+
146
+ def valid_content_type?
147
+ c = @controller.response.headers['Content-Type'].to_s
148
+ (c.empty? || c =~ /html/)
149
+ end
150
+
151
+ def component_request?
152
+ @controller.instance_variable_get(:@parent_controller)
153
+ end
154
+
155
+ def xhr?
156
+ @controller.request.xhr?
157
+ end
158
+
159
+ #
160
+ # Insertion methods
161
+ #
162
+
163
+ def insert_styles
164
+ insert_text :before, /<\/head>/i, <<-HTML
165
+ <!-- Footnotes Style -->
166
+ <style type="text/css">
167
+ #footnotes_debug {margin: 2em 0 1em 0; text-align: center; color: #444; line-height: 16px;}
168
+ #footnotes_debug a {text-decoration: none; color: #444; line-height: 18px;}
169
+ #footnotes_debug table {text-align: center;}
170
+ #footnotes_debug table td {padding: 0 5px;}
171
+ #footnotes_debug tbody {text-align: left;}
172
+ #footnotes_debug .name_values td {vertical-align: top;}
173
+ #footnotes_debug legend {background-color: #FFF;}
174
+ #footnotes_debug fieldset {text-align: left; border: 1px dashed #aaa; padding: 0.5em 1em 1em 1em; margin: 1em 2em; color: #444; background-color: #FFF;}
175
+ /* Aditional Stylesheets */
176
+ #{@notes.map(&:stylesheet).compact.join("\n")}
177
+ </style>
178
+ <!-- End Footnotes Style -->
179
+ HTML
180
+ end
181
+
182
+ def insert_footnotes
183
+ # Fieldsets method should be called first
184
+ content = fieldsets
185
+
186
+ footnotes_html = <<-HTML
187
+ <!-- Footnotes -->
188
+ <div style="clear:both"></div>
189
+ <div id="footnotes_debug">
190
+ #{links}
191
+ #{content}
192
+ <script type="text/javascript">
193
+ var Footnotes = function() {
194
+
195
+ function hideAll(){
196
+ #{close unless @@multiple_notes}
197
+ }
198
+
199
+ function hideAllAndToggle(id) {
200
+ hideAll();
201
+ toggle(id)
202
+ }
203
+
204
+ function toggle(id){
205
+ var el = document.getElementById(id);
206
+ if (el.style.display == 'none') {
207
+ Footnotes.show(el);
208
+ } else {
209
+ Footnotes.hide(el);
210
+ }
211
+
212
+ location.href = '#footnotes_debug';
213
+ }
214
+
215
+ function show(element) {
216
+ element.style.display = 'block'
217
+ }
218
+
219
+ function hide(element) {
220
+ element.style.display = 'none'
221
+ }
222
+
223
+ return {
224
+ show: show,
225
+ hide: hide,
226
+ toggle: toggle,
227
+ hideAllAndToggle: hideAllAndToggle
228
+ }
229
+ }();
230
+ /* Additional Javascript */
231
+ #{@notes.map(&:javascript).compact.join("\n")}
232
+ </script>
233
+ </div>
234
+ <!-- End Footnotes -->
235
+ HTML
236
+
237
+ placeholder = /<div[^>]+id=['"]footnotes_holder['"][^>]*>/i
238
+ if @body =~ placeholder
239
+ insert_text :after, placeholder, footnotes_html
240
+ else
241
+ insert_text :before, /<\/body>/i, footnotes_html
242
+ end
243
+ end
244
+
245
+ # Process notes to gets their links in their equivalent row
246
+ #
247
+ def links
248
+ links = Hash.new([])
249
+ order = []
250
+ each_with_rescue(@notes) do |note|
251
+ order << note.row
252
+ links[note.row] += [link_helper(note)]
253
+ end
254
+
255
+ html = ''
256
+ order.uniq!
257
+ order.each do |row|
258
+ html << "#{row.is_a?(String) ? row : row.to_s.camelize}: #{links[row].join(" | \n")}<br />"
259
+ end
260
+ html
261
+ end
262
+
263
+ # Process notes to get their content
264
+ #
265
+ def fieldsets
266
+ content = ''
267
+ each_with_rescue(@notes) do |note|
268
+ next unless note.has_fieldset?
269
+ content << <<-HTML
270
+ <fieldset id="#{note.to_sym}_debug_info" style="display: none">
271
+ <legend>#{note.legend}</legend>
272
+ <div>#{note.content}</div>
273
+ </fieldset>
274
+ HTML
275
+ end
276
+ content
277
+ end
278
+
279
+ # Process notes to get javascript code to close them.
280
+ # This method is only used when multiple_notes is false.
281
+ #
282
+ def close
283
+ javascript = ''
284
+ each_with_rescue(@notes) do |note|
285
+ next unless note.has_fieldset?
286
+ javascript << close_helper(note)
287
+ end
288
+ javascript
289
+ end
290
+
291
+ #
292
+ # Helpers
293
+ #
294
+
295
+ # Helper that creates the javascript code to close the note
296
+ #
297
+ def close_helper(note)
298
+ "Footnotes.hide(document.getElementById('#{note.to_sym}_debug_info'));\n"
299
+ end
300
+
301
+ # Helper that creates the link and javascript code when note is clicked
302
+ #
303
+ def link_helper(note)
304
+ onclick = note.onclick
305
+ unless href = note.link
306
+ href = '#'
307
+ onclick ||= "Footnotes.hideAllAndToggle('#{note.to_sym}_debug_info');return false;" if note.has_fieldset?
308
+ end
309
+
310
+ "<a href=\"#{href}\" onclick=\"#{onclick}\">#{note.title}</a>"
311
+ end
312
+
313
+ # Inserts text in to the body of the document
314
+ # +pattern+ is a Regular expression which, when matched, will cause +new_text+
315
+ # to be inserted before or after the match. If no match is found, +new_text+ is appended
316
+ # to the body instead. +position+ may be either :before or :after
317
+ #
318
+ def insert_text(position, pattern, new_text)
319
+ index = case pattern
320
+ when Regexp
321
+ if match = @body.match(pattern)
322
+ match.offset(0)[position == :before ? 0 : 1]
323
+ else
324
+ @body.size
325
+ end
326
+ else
327
+ pattern
328
+ end
329
+ @body.insert index, new_text
330
+ end
331
+
332
+ # Instance each_with_rescue method
333
+ #
334
+ def each_with_rescue(*args, &block)
335
+ self.class.each_with_rescue(*args, &block)
336
+ end
337
+
338
+ end
339
+ end