scharfie-rails-footnotes 3.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ *~
@@ -0,0 +1,56 @@
1
+ TODO:
2
+ * Create ProfilerNote
3
+ * Javascript injection for partials
4
+
5
+ == Footnotes v3.4
6
+ Author: José Valim (jose.valim@gmail.com)
7
+ Site: http://josevalim.blogspot.com/
8
+ * Rails 2.3 compatible.
9
+
10
+ == Footnotes v3.3.1
11
+ * Changed prefix to support %s and %d;
12
+ * Created gemspec;
13
+ * Some code refactoring (called eval just once instead of three times).
14
+
15
+ == Footnotes v3.3
16
+ * Rails Edge (aka 2.2) compatibility;
17
+ * Initial Ruby 1.9 compatibility.
18
+
19
+ == Footnotes v3.2.2
20
+ * Added trace to QueriesNote;
21
+ * Fixed incompatibility with Ultrasphinx (thanks to mhartl);
22
+ * Added W3C compatibility (thanks to tapajos);
23
+ * Added support to other log mechanisms in LogNote.
24
+
25
+ == Footnotes v3.2.1
26
+ * Added some tests;
27
+ * Redefined Footnotes CSS and Javascripts to use concise names.
28
+
29
+ == Footnotes v3.2
30
+ * Now you can easily add your own notes;
31
+ * Added numbers to tabs;
32
+ * Added Queries note;
33
+ * Added MySQL Query Analyzer.
34
+
35
+ == Footnotes v3.1
36
+ * Code refactoring (using modules, except backtracer);
37
+ * Ability to cherry pick notes;
38
+ * Working on Rails 2.1.
39
+
40
+ == Footnotes v3.0
41
+ * Some code refactoring;
42
+ * Stylesheets bug fixed: was showing not only css in Stylesheets div;
43
+ * Logtail fix: working with Rails 2.0 logger and in all OS, since it's Regexp based;
44
+ * Rails 1.2 (except backtrace) and 2.0 compatible;
45
+ * RoutingNavigator (based on Rick Olson plugin);
46
+ * FilterChain.
47
+
48
+ == Textmate Footnotes v2.0
49
+ Copyright (c) 2006 InquiryLabs, Inc.
50
+ Author: Duane Johnson (duane.johnson@gmail.com)
51
+ Site: http://inquirylabs.com/
52
+ Description:
53
+ Creates clickable footnotes on each rendered page, as well as clickable
54
+ links in the backtrace should an error occur in your Rails app. Links take
55
+ you to the right place inside TextMate.
56
+ 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,147 @@
1
+ Rails Footnotes
2
+ License: MIT
3
+ Version: 3.4.1
4
+
5
+ You can also read this README in pretty html at the GitHub project Wiki page
6
+
7
+ http://github.com/josevalim/rails-footnotes/wikis/home
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://gems.github.com
28
+ sudo gem install josevalim-rails-footnotes
29
+
30
+ In RAILS_ROOT/config/environments/development.rb (yes, you want it only in development):
31
+
32
+ config.gem "josevalim-rails-footnotes", :lib => "rails-footnotes", :source => "http://gems.github.com"
33
+
34
+ If you want it as plugin, just do:
35
+
36
+ script/plugin install git://github.com/josevalim/rails-footnotes.git
37
+
38
+ If you are running on Rails 2.2 or Rails 2.1 you should do:
39
+
40
+ cd myapp
41
+ git clone git://github.com/josevalim/rails-footnotes.git
42
+ cd vendor/plugins/rails-footnotes
43
+ git checkout VERSION_NUMBER
44
+ rm -rf ./.git
45
+
46
+ Where you should replace VERSION_NUMBER for "v3.3.2" for Rails 2.2 and "v3.2.2"
47
+ for Rails 2.1 (without the quotes).
48
+
49
+ Configuration
50
+ -------------
51
+
52
+ If you are not using Textmate as text editor, in your environment.rb or
53
+ in an initializer do:
54
+
55
+ if defined?(Footnotes)
56
+ Footnotes::Filter.prefix = 'txmt://open?url=file://%s&line=%d&column=%d'
57
+ end
58
+
59
+ Where you are going to choose a prefix compatible with your text editor. The %s is
60
+ replaced by the name of the file, the first %d is replaced by the line number and
61
+ the second %d is replaced by the column. You can also enable this behaviour in other
62
+ editors following the steps in the link below:
63
+
64
+ http://josevalim.blogspot.com/2008/06/textmate-protocol-behavior-on-any.html
65
+
66
+ By default, footnotes are appended at the end of the page with default stylesheet. If you want
67
+ to change their position, you can define a div with id "footnotes_holder" or define your own stylesheet
68
+ by turning footnotes stylesheet off:
69
+
70
+ Footnotes::Filter.no_style = true
71
+
72
+ Another option is to allow multiple notes to be opened at the same time:
73
+
74
+ Footnotes::Filter.multiple_notes = true
75
+
76
+ Finally, you can control which notes you want to show. The default are:
77
+
78
+ Footnotes::Filter.notes = [:session, :cookies, :params, :filters, :routes, :env, :queries, :log, :general]
79
+
80
+
81
+ Creating your own notes
82
+ -----------------------
83
+
84
+ Create your notes to integrate with Footnotes is easy.
85
+
86
+ 1. Create a Footnotes::Notes::YourExampleNote class
87
+
88
+ 2. Implement the necessary methods (check abstract_note.rb file in lib/notes)
89
+
90
+ 3. Append your example note in Footnotes::Filter.notes array (usually at the end of your environment file or in an initializer):
91
+
92
+ For example, to create a note that shows info about the user logged in your application you just have to do:
93
+
94
+ module Footnotes
95
+ module Notes
96
+ class CurrentUserNote < AbstractNote
97
+ # This method always receives a controller
98
+ #
99
+ def initialize(controller)
100
+ @current_user = controller.instance_variable_get("@current_user")
101
+ end
102
+
103
+ # The name that will appear as legend in fieldsets
104
+ #
105
+ def legend
106
+ "Current user: #{@current_user.name}"
107
+ end
108
+
109
+ # This Note is only valid if we actually found an user
110
+ # If it's not valid, it won't be displayed
111
+ #
112
+ def valid?
113
+ @current_user
114
+ end
115
+
116
+ # The fieldset content
117
+ #
118
+ def content
119
+ escape(@current_user.inspect)
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ Then put in your environment:
126
+
127
+ Footnotes::Filter.notes += [:current_user]
128
+
129
+
130
+ Bugs and Feedback
131
+ -----------------
132
+
133
+ If you discover any bugs, please send an e-mail to jose.valim@gmail.com
134
+ If you just want to give some positive feedback or drop a line, that's fine too! =)
135
+
136
+ Copyright (c) 2009 José Valim
137
+ http://www.pagestacker.com/
138
+ http://josevalim.blogspot.com/
139
+
140
+
141
+ Version 2.0
142
+ -----------
143
+
144
+ Until version 2.0, this plugin was created and maintained by:
145
+
146
+ Duane Johnson (duane.johnson@gmail.com)
147
+ http://blog.inquirylabs.com/
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "scharfie-rails-footnotes"
8
+ gem.summary = %Q{Textmate footnotes for rails}
9
+ gem.description = %Q{Textmate footnotes for rails}
10
+ gem.email = "tastyhat@jamesstuart.org"
11
+ gem.homepage = "http://github.com/scharfie/rails-footnotes"
12
+ gem.authors = ["Scharfie"]
13
+ gem.add_development_dependency "thoughtbot-shoulda"
14
+ gem.add_development_dependency "mocha"
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/*_test.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/*_test.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ if File.exist?('VERSION')
48
+ version = File.read('VERSION')
49
+ else
50
+ version = ""
51
+ end
52
+
53
+ rdoc.rdoc_dir = 'rdoc'
54
+ rdoc.title = "scharfie-rails-footnotes #{version}"
55
+ rdoc.rdoc_files.include('README*')
56
+ rdoc.rdoc_files.include('lib/**/*.rb')
57
+ end
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ require File.join(File.dirname(__FILE__), 'lib', 'rails-footnotes')
2
+
@@ -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
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,26 @@
1
+ #footnotes_debug {
2
+ font-family: Myriad Pro, Helvetica, Arial, sans-serif;
3
+ color: #ccc;
4
+ font-size: 12px;
5
+ text-align: left;
6
+ margin: 10px 0 0;
7
+ padding: 5px 10px;
8
+ background: #f5f5f5;
9
+ }
10
+
11
+ #footnotes_debug a {
12
+ color: #24242;
13
+ padding: 4px;
14
+ text-decoration: none; color: #444; line-height: 18px;
15
+ }
16
+
17
+ #footnotes_debug table {text-align: center;}
18
+ #footnotes_debug table td {padding: 0 5px;}
19
+ #footnotes_debug tbody {text-align: left;}
20
+ #footnotes_debug legend {background-color: #FFF;}
21
+ #footnotes_debug fieldset {
22
+ text-align: left;
23
+ border: 1px dashed #aaa;
24
+ padding: 0.5em 1em 1em 1em; margin: 10px; color: #444; background-color: #FFF;
25
+ font-family: Inconsolata, Monaco, monospace;
26
+ }
@@ -0,0 +1,38 @@
1
+ var Footnotes = function() {
2
+ function hideAll() {}
3
+
4
+ function hideAllAndToggle(id) {
5
+ var el = get(id)
6
+ var display = el.style.display
7
+ Footnotes.hideAll();
8
+ toggle(id, display)
9
+ }
10
+
11
+ function get(id) {
12
+ return document.getElementById(id);
13
+ }
14
+
15
+ function toggle(id, display) {
16
+ var el = get(id)
17
+ if (display == null) { display = el.style.display }
18
+ display == 'none' ? show(el) : hide(el)
19
+ location.href = '#footnotes_debug';
20
+ }
21
+
22
+ function show(element) {
23
+ element.style.display = 'block'
24
+ }
25
+
26
+ function hide(element) {
27
+ element.style.display = 'none'
28
+ }
29
+
30
+ return {
31
+ show: show,
32
+ hide: hide,
33
+ get: get,
34
+ toggle: toggle,
35
+ hideAllAndToggle: hideAllAndToggle,
36
+ multipleNotes: false
37
+ }
38
+ }();
@@ -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,297 @@
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&line=%d&column=%d'
9
+
10
+ # Edit notes
11
+ @@notes = [ :controller, :view, :layout, :stylesheets, :javascripts ]
12
+ # Show notes
13
+ @@notes += [ :session, :cookies, :params, :filters, :routes, :env, :queries, :log, :general ]
14
+
15
+ # :no_style => If you don't want the style to be appended to your pages
16
+ # :notes => Class variable that holds the notes to be processed
17
+ # :prefix => Prefix appended to FootnotesLinks
18
+ # :multiple_notes => Set to true if you want to open several notes at the same time
19
+ cattr_accessor :no_style, :notes, :prefix, :multiple_notes
20
+
21
+ class << self
22
+ # Method called to start the notes
23
+ # It's a before filter prepend in the controller
24
+ #
25
+ def before(controller)
26
+ Footnotes::Filter.start!(controller)
27
+ end
28
+
29
+ # Method that calls Footnotes to attach its contents
30
+ #
31
+ def after(controller)
32
+ filter = Footnotes::Filter.new(controller)
33
+ filter.add_footnotes!
34
+ filter.close!(controller)
35
+ end
36
+
37
+ # Calls the class method start! in each note
38
+ # Sometimes notes need to set variables or clean the environment to work properly
39
+ # This method allows this kind of setup
40
+ #
41
+ def start!(controller)
42
+ @@klasses = []
43
+
44
+ each_with_rescue(@@notes.flatten) do |note|
45
+ klass = "Footnotes::Notes::#{note.to_s.camelize}Note".constantize
46
+ klass.start!(controller) if klass.respond_to?(:start!)
47
+ @@klasses << klass
48
+ end
49
+ end
50
+
51
+ # Process notes, discarding only the note if any problem occurs
52
+ #
53
+ def each_with_rescue(notes)
54
+ delete_me = []
55
+
56
+ notes.each do |note|
57
+ begin
58
+ yield note
59
+ rescue Exception => e
60
+ # Discard note if it has a problem
61
+ log_error("Footnotes #{note.to_s.camelize}Note Exception", e)
62
+ delete_me << note
63
+ next
64
+ end
65
+ end
66
+
67
+ delete_me.each{ |note| notes.delete(note) }
68
+ return notes
69
+ end
70
+
71
+ # Logs the error using specified title and format
72
+ #
73
+ def log_error(title, exception)
74
+ RAILS_DEFAULT_LOGGER.error "#{title}: #{exception}\n#{exception.backtrace.join("\n")}"
75
+ end
76
+
77
+ # If none argument is sent, simply return the prefix.
78
+ # Otherwise, replace the args in the prefix.
79
+ #
80
+ def prefix(*args)
81
+ if args.empty?
82
+ @@prefix
83
+ else
84
+ format(@@prefix, *args)
85
+ end
86
+ end
87
+
88
+ end
89
+
90
+ def initialize(controller)
91
+ @controller = controller
92
+ @template = controller.instance_variable_get(:@template)
93
+ @body = controller.response.body
94
+ @notes = []
95
+ end
96
+
97
+ def add_footnotes!
98
+ add_footnotes_without_validation! if valid?
99
+ rescue Exception => e
100
+ # Discard footnotes if there are any problems
101
+ self.class.log_error("Footnotes Exception", e)
102
+ end
103
+
104
+ # Calls the class method close! in each note
105
+ # Sometimes notes need to finish their work even after being read
106
+ # This method allows this kind of work
107
+ #
108
+ def close!(controller)
109
+ each_with_rescue(@@klasses) do |klass|
110
+ klass.close!(controller)
111
+ end
112
+ end
113
+
114
+ protected
115
+ def valid?
116
+ performed_render? && valid_format? && valid_content_type? && @body.is_a?(String) && !component_request? && !xhr?
117
+ end
118
+
119
+ def add_footnotes_without_validation!
120
+ initialize_notes!
121
+ insert_styles unless @@no_style
122
+ insert_footnotes
123
+ end
124
+
125
+ def initialize_notes!
126
+ each_with_rescue(@@klasses) do |klass|
127
+ note = klass.new(@controller)
128
+ @notes << note if note.respond_to?(:valid?) && note.valid?
129
+ end
130
+ end
131
+
132
+ def performed_render?
133
+ @controller.instance_variable_get(:@performed_render)
134
+ end
135
+
136
+ def valid_format?
137
+ [:html,:rhtml,:xhtml,:rxhtml].include?(@template.template_format.to_sym)
138
+ end
139
+
140
+ def valid_content_type?
141
+ c = @controller.response.headers['Content-Type'].to_s
142
+ (c.empty? || c =~ /html/)
143
+ end
144
+
145
+ def component_request?
146
+ @controller.instance_variable_get(:@parent_controller)
147
+ end
148
+
149
+ def xhr?
150
+ @controller.request.xhr?
151
+ end
152
+
153
+ def read_asset(filename)
154
+ File.read(File.join(File.dirname(__FILE__), 'assets', filename))
155
+ end
156
+
157
+ #
158
+ # Insertion methods
159
+ #
160
+
161
+ def insert_styles
162
+ insert_text :before, /<\/head>/i, <<-HTML
163
+ <!-- Footnotes Style -->
164
+ <style type="text/css">
165
+ #{read_asset('footnotes.css')}
166
+ /* Aditional Stylesheets */
167
+ #{@notes.map(&:stylesheet).compact.join("\n")}
168
+ </style>
169
+ <!-- End Footnotes Style -->
170
+ HTML
171
+ end
172
+
173
+ def insert_footnotes
174
+ # Fieldsets method should be called first
175
+ content = fieldsets
176
+ hideAll = @@multiple_notes ? nil : %[Footnotes.hideAll = function() { #{close} }]
177
+
178
+ footnotes_html = <<-HTML
179
+ <!-- Footnotes -->
180
+ <div style="clear:both"></div>
181
+ <div id="footnotes_debug">
182
+ #{links}
183
+ #{content}
184
+ <script type="text/javascript">
185
+ #{read_asset('footnotes.js')}
186
+ #{hideAll}
187
+ /* Additional Javascript */
188
+ #{@notes.map(&:javascript).compact.join("\n")}
189
+ </script>
190
+ </div>
191
+ <!-- End Footnotes -->
192
+ HTML
193
+
194
+ if @body =~ %r{<div[^>]+id=['"]footnotes_holder['"][^>]*>}
195
+ # Insert inside the "footnotes_holder" div if it exists
196
+ insert_text :after, %r{<div[^>]+id=['"]footnotes_holder['"][^>]*>}, footnotes_html
197
+ else
198
+ # Otherwise, try to insert as the last part of the html body
199
+ insert_text :before, /<\/body>/i, footnotes_html
200
+ end
201
+ end
202
+
203
+ # Process notes to gets their links in their equivalent row
204
+ #
205
+ def links
206
+ links = Hash.new([])
207
+ order = []
208
+ each_with_rescue(@notes) do |note|
209
+ order << note.row
210
+ links[note.row] += [link_helper(note)]
211
+ end
212
+
213
+ html = ''
214
+ order.uniq!
215
+ order.each do |row|
216
+ html << "#{row.is_a?(String) ? row : row.to_s.camelize}: #{links[row].join(" | \n")}<br />"
217
+ end
218
+ html
219
+ end
220
+
221
+ # Process notes to get their content
222
+ #
223
+ def fieldsets
224
+ content = ''
225
+ each_with_rescue(@notes) do |note|
226
+ next unless note.has_fieldset?
227
+ content << <<-HTML
228
+ <fieldset id="#{note.to_sym}_debug_info" style="display: none">
229
+ <legend>#{note.legend}</legend>
230
+ <div>#{note.content}</div>
231
+ </fieldset>
232
+ HTML
233
+ end
234
+ content
235
+ end
236
+
237
+ # Process notes to get javascript code to close them.
238
+ # This method is only used when multiple_notes is false.
239
+ #
240
+ def close
241
+ javascript = ''
242
+ each_with_rescue(@notes) do |note|
243
+ next unless note.has_fieldset?
244
+ javascript << close_helper(note)
245
+ end
246
+ javascript
247
+ end
248
+
249
+ #
250
+ # Helpers
251
+ #
252
+
253
+ # Helper that creates the javascript code to close the note
254
+ #
255
+ def close_helper(note)
256
+ "Footnotes.hide(document.getElementById('#{note.to_sym}_debug_info'));\n"
257
+ end
258
+
259
+ # Helper that creates the link and javascript code when note is clicked
260
+ #
261
+ def link_helper(note)
262
+ onclick = note.onclick
263
+ unless href = note.link
264
+ href = '#'
265
+ onclick ||= "Footnotes.hideAllAndToggle('#{note.to_sym}_debug_info');return false;" if note.has_fieldset?
266
+ end
267
+
268
+ "<a href=\"#{href}\" onclick=\"#{onclick}\">#{note.title}</a>"
269
+ end
270
+
271
+ # Inserts text in to the body of the document
272
+ # +pattern+ is a Regular expression which, when matched, will cause +new_text+
273
+ # to be inserted before or after the match. If no match is found, +new_text+ is appended
274
+ # to the body instead. +position+ may be either :before or :after
275
+ #
276
+ def insert_text(position, pattern, new_text)
277
+ index = case pattern
278
+ when Regexp
279
+ if match = @body.match(pattern)
280
+ match.offset(0)[position == :before ? 0 : 1]
281
+ else
282
+ @body.size
283
+ end
284
+ else
285
+ pattern
286
+ end
287
+ @body.insert index, new_text
288
+ end
289
+
290
+ # Instance each_with_rescue method
291
+ #
292
+ def each_with_rescue(*args, &block)
293
+ self.class.each_with_rescue(*args, &block)
294
+ end
295
+
296
+ end
297
+ end