rdoc-babel 0.9.1

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.
data/.autotest ADDED
@@ -0,0 +1,12 @@
1
+ require 'autotest/restart'
2
+
3
+ Autotest.add_hook :initialize do |at|
4
+ at.testlib = 'minitest/unit'
5
+ class << at
6
+ alias zen_path_to_classname path_to_classname
7
+ def path_to_classname(s)
8
+ zen_path_to_classname(s).sub('Rdoc', 'RDoc')
9
+ end
10
+ end
11
+ end
12
+
data/.gemtest ADDED
File without changes
data/HISTORY.rdoc ADDED
@@ -0,0 +1,8 @@
1
+
2
+ === 0.9.0 / 2010-10-02
3
+
4
+ Initial version, developed along with {RDoc}[http://github.com/rdoc/rdoc] 3.0.
5
+
6
+ === 0.9.1 / 2011-07-16
7
+
8
+ First public release.
data/Manifest.txt ADDED
@@ -0,0 +1,28 @@
1
+ .autotest
2
+ HISTORY.rdoc
3
+ Manifest.txt
4
+ Rakefile
5
+ README.rdoc
6
+ lib/rdoc/discover.rb
7
+ lib/rdoc/generator/babel.rb
8
+ lib/rdoc/generator/ruby-lang/class-page.html.erb
9
+ lib/rdoc/generator/ruby-lang/file-page.html.erb
10
+ lib/rdoc/generator/ruby-lang/images/zoom.png
11
+ lib/rdoc/generator/ruby-lang/index.html.erb
12
+ lib/rdoc/generator/ruby-lang/indexes.html.erb
13
+ lib/rdoc/generator/ruby-lang/rdoc.css
14
+ lib/rdoc/generator/ruby-lang/scripts/indexFrame.js
15
+ lib/rdoc/generator/ruby-lang/scripts/jquery.js
16
+ lib/rdoc/generator/ruby-lang/scripts/jquery.quicksearch.js
17
+ lib/rdoc/generator/ruby-lang/scripts/mainFrame.js
18
+ lib/rdoc_babel.rb
19
+ test/data/ancestors.rb
20
+ test/data/commented.rb
21
+ test/data/context_alias.rb
22
+ test/data/HISTORY.rdoc
23
+ test/data/main_file.rb
24
+ test/data/not_commented.rb
25
+ test/data/no_class_nor_module.rb
26
+ test/data/no_content.rb
27
+ test/data/README.rdoc
28
+ test/test_rdoc_generator_babel.rb
data/README.rdoc ADDED
@@ -0,0 +1,103 @@
1
+ = Babel
2
+
3
+ * http://github.com/thyresias/rdoc-babel
4
+
5
+ == Description
6
+
7
+ Babel is an RDoc formatter producing HTML documentation.
8
+ The default template is +ruby-lang+.
9
+
10
+ You are welcome to propose changes or enhancements,
11
+ and to contribute alternate templates or style sheets.
12
+
13
+ === Features of the "ruby-lang" template
14
+
15
+ - Look and feel inspired from ruby-lang.org[http://www.ruby-lang.org/].
16
+ - Dual-frame output, with indexes on the left.
17
+ - Search boxes for classes and methods.
18
+ - Links to undocumented classes/methods are grayed.
19
+ - Highlights target methods, attributes and constants.
20
+ - Adds links to ancestor methods/attributes.
21
+ - Borrows some ideas (and one icon) from Darkfish.
22
+ - Tested on Firefox 3.5 & 5, Chrome 9 & 12, Safari 4 & 5.
23
+
24
+ == Synopsis
25
+
26
+ To output documentation formatted by Babel, use the <tt>--format/-f</tt>
27
+ RDoc switch. For instance, to generate the documentation for Ruby core:
28
+
29
+ $ gem install rdoc-babel
30
+ $ cd ~/.rvm/src/ruby-1.8.7-p302
31
+ $ rdoc -f babel -a -t "Ruby 1.8.7 Core" -o ~/docs/ruby_core_187 *.c
32
+
33
+ Using rake:
34
+
35
+ require 'rdoc/task'
36
+
37
+ RDoc::Task.new do |t|
38
+ Dir.chdir '~/.rvm/src/ruby-1.9.2-p0'
39
+ rdoc.options <<
40
+ '--format' << 'babel' <<
41
+ '--all'
42
+ t.title = "Ruby 1.9.2 Core"
43
+ t.rdoc_dir = '~/docs/ruby_core_192'
44
+ t.rdoc_files.concat Dir['*.c']
45
+ end
46
+
47
+ To make Babel the default format when generating RDoc documentation,
48
+ define the RDOCOPT environment variable in the appropriate file
49
+ (e.g., <tt>~/.bashrc</tt>):
50
+
51
+ export RDOCOPT="--format babel"
52
+
53
+ == Specific options
54
+
55
+ Babel supports specific options in addition to the standard RDoc options:
56
+
57
+ [<tt>--style</tt> _url_, +-s+]
58
+
59
+ Specifies the URL of a stylesheet that the template should use.
60
+ The default is "rdoc.css".
61
+
62
+ [<tt>--see-standard-ancestors</tt>]
63
+
64
+ Add links to Kernel/Object ancestor methods.
65
+
66
+ When a method or attribute is defined in a class/module, and is also
67
+ present in an ancestor, Babel adds a link to the ancestor method/attribute
68
+ in the description ("See also ..."). Unless this option is specified,
69
+ this annotation is not generated for Object and Kernel ancestor methods.
70
+
71
+ == Requirements
72
+
73
+ - Ruby >= 1.8.7
74
+ - RDoc >= 3.0
75
+
76
+ == Installation
77
+
78
+ [sudo] gem install rdoc-babel
79
+
80
+ == License
81
+
82
+ (The MIT License)
83
+
84
+ Copyright (c) 2010 Thierry Lambert
85
+
86
+ Permission is hereby granted, free of charge, to any person obtaining
87
+ a copy of this software and associated documentation files (the
88
+ 'Software'), to deal in the Software without restriction, including
89
+ without limitation the rights to use, copy, modify, merge, publish,
90
+ distribute, sublicense, and/or sell copies of the Software, and to
91
+ permit persons to whom the Software is furnished to do so, subject to
92
+ the following conditions:
93
+
94
+ The above copyright notice and this permission notice shall be
95
+ included in all copies or substantial portions of the Software.
96
+
97
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
98
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
99
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
100
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
101
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
102
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
103
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+
4
+ Hoe.spec 'rdoc-babel' do
5
+
6
+ developer('Thierry Lambert', 'thyresias@gmail.com')
7
+
8
+ self.summary = "An RDoc formatter producing HTML documentation."
9
+ self.description = paragraphs_of('README.rdoc', 3, 6).join("\n\n")
10
+
11
+ self.readme_file = 'README.rdoc'
12
+ self.history_file = 'HISTORY.rdoc'
13
+ self.extra_rdoc_files = ['README.rdoc', 'HISTORY.rdoc']
14
+
15
+ self.remote_rdoc_dir = ''
16
+ self.testlib = :minitest
17
+
18
+ self.extra_deps << ['rdoc', '~> 3.0']
19
+
20
+ self.extra_dev_deps << ['minitest', '>= 1.7']
21
+ self.extra_dev_deps << ['nokogiri', '~> 1.4']
22
+
23
+ spec_extras[:homepage] = 'http://github.com/thyresias/babel'
24
+ spec_extras[:rdoc_options] = [
25
+ '--main', 'README.rdoc',
26
+ ]
27
+
28
+ #spec_extras[:post_install_message] = <<-EOS
29
+ # the crash for creating Babel documentation is due to a RubyGem bug
30
+ #EOS
31
+
32
+ end
33
+
34
+ task :file_list do
35
+ puts Dir['*'].reject { |f| File.directory? f }
36
+ puts Dir['lib/**/*'].reject { |f| File.directory? f }
37
+ puts Dir['test/**/*'].reject { |f| File.directory? f }
38
+ end
@@ -0,0 +1 @@
1
+ require 'rdoc/generator/babel'
@@ -0,0 +1,407 @@
1
+ require 'rdoc'
2
+ require 'rdoc/rdoc'
3
+ #require 'rdoc/generator'
4
+ require 'pathname'
5
+ require 'fileutils'
6
+ require 'erb'
7
+
8
+ require 'rdoc/generator/markup'
9
+
10
+ ##
11
+ # Babel RDoc HTML Generator.
12
+ # (Initially a variation of Darkfish.)
13
+
14
+ class RDoc::Generator::Babel
15
+
16
+ RDoc::RDoc.add_generator(self)
17
+
18
+ include ERB::Util
19
+
20
+ # Directory containing babel templates.
21
+ # Each template is in a subdirectory named after the template.
22
+
23
+ TEMPLATE_ROOT = Pathname.new(__FILE__).expand_path.dirname
24
+
25
+ ##
26
+ # Babel-specific options.
27
+
28
+ module Options
29
+
30
+ ##
31
+ # A hash <tt>option => value</tt>.
32
+
33
+ attr_accessor :babel_options
34
+
35
+ end
36
+
37
+ class << self
38
+
39
+ # Standard generator factory method.
40
+
41
+ alias for new
42
+
43
+ # Add Babel options to RDoc standard options.
44
+
45
+ def setup_options(rdoc_options)
46
+
47
+ options = {
48
+ :stylesheet_url => nil,
49
+ #:index_attributes => false,
50
+ #:ancestor_lists => false,
51
+ #:list_standard_ancestors => false,
52
+ :see_standard_ancestors => false,
53
+ }
54
+
55
+ rdoc_options.extend Options
56
+ rdoc_options.babel_options = options
57
+
58
+ opt = rdoc_options.option_parser
59
+
60
+ opt.separator "Babel options:"
61
+ opt.separator nil
62
+
63
+ opt.on('--style=URL', '-s',
64
+ 'Specifies the URL of a stylesheet',
65
+ 'that the template should use.',
66
+ 'The default is "rdoc.css".') do |value|
67
+ options[:stylesheet_url] = value
68
+ end
69
+ opt.separator nil
70
+
71
+ =begin
72
+ opt.on('--index-attributes',
73
+ 'Include attributes in the method index.',
74
+ 'By default, only methods are included.') do |value|
75
+ options[:index_attributes] = true
76
+ end
77
+ opt.separator nil
78
+
79
+ opt.on('--ancestor-lists',
80
+ 'Add lists of ancestor methods, attributes,',
81
+ 'aliases and constants in the documentation',
82
+ 'of a class/module.') do |value|
83
+ options[:ancestor_lists] = true
84
+ end
85
+ opt.separator nil
86
+
87
+ opt.on('--list-standard-ancestors',
88
+ 'Include Kernel/Object methods',
89
+ 'in ancestor methods.') do |value|
90
+ options[:list_standard_ancestors] = true
91
+ end
92
+ opt.separator nil
93
+ =end
94
+
95
+ opt.on('--see-standard-ancestors',
96
+ 'Add links to Kernel/Object',
97
+ 'ancestor methods.') do |value|
98
+ options[:see_standard_ancestors] = true
99
+ end
100
+ opt.separator nil
101
+
102
+ end
103
+
104
+ end
105
+
106
+ # Saves the options, makes sure the template is found.
107
+
108
+ def initialize(options)
109
+ @options = options
110
+ @babel_options = options.babel_options
111
+ @see_standard_ancestors = @babel_options[:see_standard_ancestors]
112
+ RDoc::AnyMethod.add_line_numbers = options.line_numbers
113
+ @options.template = 'ruby-lang' if @options.template == 'babel' # TODO leave template nil
114
+ @template_dir = TEMPLATE_ROOT + @options.template
115
+ @template_dir.directory? or raise RDoc::Error, "template not found: '#@template_dir'"
116
+ @source_dir = Pathname.pwd.expand_path
117
+ end
118
+
119
+ # Directory for generated class/module files.
120
+ # Used by RDoc::ClassModule to build paths.
121
+
122
+ def class_dir
123
+ 'classes'
124
+ end
125
+
126
+ # Directory for generated TopLevel files.
127
+ # Used by RDoc::TopLevel to build paths.
128
+
129
+ def file_dir
130
+ 'files'
131
+ end
132
+
133
+ # Generates the documentation.
134
+
135
+ def generate(top_levels)
136
+
137
+ # set instance variables
138
+
139
+ @output_dir = Pathname.new(@options.op_dir).expand_path(@source_dir)
140
+ @all_classes_and_modules = RDoc::TopLevel.all_classes_and_modules.sort
141
+ @unique_classes_and_modules = RDoc::TopLevel.unique_classes_and_modules.sort
142
+
143
+ @all_methods = @unique_classes_and_modules.
144
+ inject([]) { |a,m| a.concat m.method_list }.
145
+ sort { |a,b| [a, a.parent_name] <=> [b, b.parent_name] }
146
+
147
+ @all_files = top_levels # not sorted: keep command line order
148
+ @files_with_comment = @all_files.reject { |f| f.comment.empty? }
149
+ @simple_files = @files_with_comment.select { |f| f.parser == RDoc::Parser::Simple }
150
+
151
+ @files_to_display =
152
+ if @unique_classes_and_modules.empty?
153
+ @all_files
154
+ else
155
+ @simple_files
156
+ end
157
+
158
+ @main_file = @options.main_page && @all_files.find { |f| f.full_name == @options.main_page }
159
+ if @main_file
160
+ unless @files_to_display.find { |f| f.full_name == @options.main_page }
161
+ @files_to_display.unshift @main_file
162
+ end
163
+ end
164
+
165
+ # write the output
166
+
167
+ write_static_files
168
+ generate_indexes
169
+ generate_class_and_module_files
170
+ generate_file_files
171
+
172
+ rescue StandardError => err
173
+ debug_msg "%s: %s\n %s" % [ err.class.name, err.message, err.backtrace.join("\n ") ]
174
+ raise
175
+ end
176
+
177
+ # Copy static files to the output directory.
178
+ # Static files are all files in the template directory
179
+ # that do not have the <tt>.erb</tt> extension.
180
+
181
+ def write_static_files
182
+ debug_msg "Copying static files"
183
+ options = { :verbose => $DEBUG_RDOC, :noop => @options.dry_run }
184
+ static_files = Pathname.
185
+ glob(@template_dir.to_s + '/**/*').
186
+ reject { |f| f.extname == '.erb' }
187
+ static_files.sort.each do |source_path|
188
+ out_path = @output_dir + source_path.relative_path_from(@template_dir)
189
+ if source_path.directory?
190
+ out_path.mkpath unless @options.dry_run
191
+ else
192
+ FileUtils.cp source_path.to_s, out_path.dirname.to_s, options
193
+ end
194
+ end
195
+ end
196
+
197
+ # Generates +index.html+ and +indexes.html+.
198
+
199
+ def generate_indexes
200
+ @first_page = first_page
201
+ generate_index('index')
202
+ generate_index('indexes')
203
+ end
204
+
205
+ # Generates an index page.
206
+
207
+ def generate_index(basename)
208
+ debug_msg "Generating index #{basename}.html"
209
+ template_file = @template_dir + "#{basename}.html.erb"
210
+ outfile = @output_dir + "#{basename}.html"
211
+ render_template(template_file, binding(), outfile)
212
+ end
213
+
214
+ # Generates a documentation page for each class.
215
+
216
+ def generate_class_and_module_files
217
+ template_file = @template_dir + 'class-page.html.erb'
218
+ debug_msg "Generating class documentation"
219
+ @unique_classes_and_modules.each do |klass|
220
+ debug_msg " %s %s" % [klass.type, klass.full_name]
221
+ outfile = @output_dir + klass.path
222
+ @class = klass
223
+ self.render_template(template_file, binding(), outfile)
224
+ end
225
+ end
226
+
227
+ # Generates a documentation page for each file.
228
+
229
+ def generate_file_files
230
+ template_file = @template_dir + 'file-page.html.erb'
231
+ debug_msg "Generating file documentation"
232
+ @all_files.each do |file|
233
+ debug_msg " file #{file.path}"
234
+ outfile = @output_dir + file.path
235
+ @file = file
236
+ self.render_template(template_file, binding(), outfile)
237
+ end
238
+ end
239
+
240
+ # Returns the first +Context+ object to display in the main frame.
241
+ # This is, in order:
242
+ # - The file designated by the +main_page+ option,
243
+ # if there is a +TopLevel+ with that name.
244
+ # - The first simple file that contains a comment
245
+ # (in the order given on the command line).
246
+ # - The first class or module that contains a comment.
247
+ # - The first file that contains a comment
248
+ # (in the order given on the command line).
249
+ # - The first class or module that has any kind of content.
250
+ # - The first class or module.
251
+ # - The first file.
252
+
253
+ def first_page
254
+ # TODO are there cases where main_page = 'README' for 'lib/README'?
255
+ if @options.main_page && (main_file = @all_files.find { |f| f.full_name == @options.main_page })
256
+ main_file
257
+ elsif (file = @simple_files.first)
258
+ file
259
+ elsif (cm = @unique_classes_and_modules.find { |k| !k.comment.empty? })
260
+ cm
261
+ elsif (file = @files_with_comment.first)
262
+ file
263
+ elsif !@unique_classes_and_modules.empty?
264
+ @unique_classes_and_modules.find { |k| k.any_content } or
265
+ @unique_classes_and_modules.first
266
+ else
267
+ @all_files.first
268
+ end
269
+ end
270
+
271
+ # Returns the HTML for the description of a method,
272
+ # with alias information and link to ancestor method/attribute.
273
+
274
+ def description(method)
275
+ desc = method.documented? ? method.description.strip : ''
276
+ if method.is_alias_for
277
+ text = method.is_alias_for.documented? ? '<p>' : '<p class="nodoc">'
278
+ text << 'Alias for ' << link(method, method.is_alias_for) << '</p>'
279
+ append_with_nl desc, text
280
+ end
281
+ if method.see &&
282
+ (@see_standard_ancestors ||
283
+ method.see.parent.full_name !~ /^(Object|Kernel)$/)
284
+ text = method.see.documented? ? '<p>' : '<p class="nodoc">'
285
+ text << (desc.empty? ? 'See ' : 'See also ')
286
+ text << link(method, method.see) << '</p>'
287
+ append_with_nl desc, text
288
+ end
289
+ desc = '<p class="nodoc">(not documented)</p>' if desc.empty?
290
+ unless method.aliases.empty?
291
+ text = '<p>Also aliased as '
292
+ text << method.aliases.map { |a| link(method, a) }.join(', ') << '</p>'
293
+ append_with_nl desc, text
294
+ end
295
+ desc
296
+ end
297
+
298
+ # Decorates a call-seq to highlight the method name.
299
+ # The output will have the method name inside HTML
300
+ # +span+ tags with CSS class +method_name_class+.
301
+
302
+ def decorated_call_seq(method, method_name_class)
303
+
304
+ # I assume it is safe to use \001 \002 \003 \004 to escape & < > "
305
+ text = method.call_seq.strip.gsub(/->/, "\001rarr;")
306
+ ospan = "\002span class=\004#{method_name_class}\004\003"
307
+ cspan = "\002/span\003"
308
+
309
+ if method.name =~ /^[a-z]/i
310
+ # look for things like 'IO.open' or 'open' at the beginning of lines
311
+ name = Regexp.escape(method.name.sub(/=$/, ''))
312
+ re = Regexp.new('^(\s*)([:\w]+\.)?(' << name << ')', Regexp::MULTILINE)
313
+ text.gsub!(re, "\\1\\2#{ospan}\\3#{cspan}")
314
+ elsif method.name =~ /\[\]=?/
315
+ # [] and []=
316
+ text.gsub!(/\[/m, "#{ospan}[#{cspan}")
317
+ text.gsub!(/\]/m, "#{ospan}]#{cspan}")
318
+ else
319
+ # operators:
320
+ # **
321
+ # -(unary) +(unary) ~
322
+ # * / %
323
+ # + -
324
+ # << >>
325
+ # &
326
+ # | ^
327
+ # > >= < <=
328
+ # <=> == === =~
329
+ name = Regexp.escape(method.name)
330
+ re = Regexp.new(name, Regexp::MULTILINE)
331
+ text.gsub!(re, "#{ospan}\\&#{cspan}")
332
+ end
333
+
334
+ h(text).gsub("\001", '&').gsub("\002",'<').gsub("\003",'>').gsub("\004",'"').gsub("\n", '<br/>')
335
+ end
336
+
337
+ protected
338
+
339
+ # Renders the erb template in +template_file+ within the
340
+ # specified +binding+ context and writes the result to +outfile+.
341
+
342
+ def render_template(template_file, binding, outfile)
343
+
344
+ debug_msg " rendering #{outfile}"
345
+
346
+ @rel_prefix = @output_dir.relative_path_from(outfile.dirname)
347
+ @stylesheet_url = @babel_options[:stylesheet_url] || (@rel_prefix + 'rdoc.css').to_s
348
+
349
+ template_src = template_file.read
350
+ template = ERB.new(template_src, nil, '><')
351
+ template.filename = template_file.to_s
352
+
353
+ output = nil
354
+ begin
355
+ output = template.result(binding)
356
+ rescue => e
357
+ raise RDoc::Error, "Error while evaluating %s: %s (%s at %p)" % [
358
+ template_file.to_s,
359
+ e.message, e.class.name,
360
+ eval("_erbout[-50,50]", binding)
361
+ ], e.backtrace
362
+ end
363
+
364
+ return if @options.dry_run
365
+
366
+ outfile.dirname.mkpath
367
+ outfile.open('w', 0644) do |ofh|
368
+ ofh.print(output)
369
+ end
370
+
371
+ end
372
+
373
+ # Returns the <a> tag code linking to method +to+ from the page
374
+ # describing method +from+.
375
+
376
+ def link(from, to)
377
+ href = from.parent.aref_to(to.path)
378
+ to_parent = to.parent.full_name.dup
379
+ if @options.show_hash
380
+ text = from.parent.full_name == to_parent ? '' : to_parent
381
+ text << (to.singleton ? '::' : '#') << to.name
382
+ elsif from.parent.full_name == to_parent
383
+ text = to.name.dup
384
+ else
385
+ text = to_parent
386
+ text << (to.singleton ? '::' : '#') << to.name
387
+ end
388
+ %Q(<a href="#{href}">#{h(text)}</a>)
389
+ end
390
+
391
+ # Output progress information if debugging is enabled.
392
+
393
+ def debug_msg(msg)
394
+ $stderr.puts(msg) if $DEBUG_RDOC
395
+ end
396
+
397
+ # Appends string +add+ to +base+ with a newline between the two if needed,
398
+ # and a final trailing newline.
399
+
400
+ def append_with_nl(base, add)
401
+ base.strip!
402
+ base.sub!(/\S\z/, "\\&\n")
403
+ base << add
404
+ base << "\n"
405
+ end
406
+
407
+ end