rdoc-babel 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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