rdoc 6.1.2 → 6.3.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rdoc might be problematic. Click here for more details.

Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -0
  3. data/README.rdoc +0 -1
  4. data/Rakefile +28 -18
  5. data/lib/rdoc.rb +21 -0
  6. data/lib/rdoc/any_method.rb +52 -7
  7. data/lib/rdoc/class_module.rb +1 -1
  8. data/lib/rdoc/comment.rb +12 -1
  9. data/lib/rdoc/context.rb +10 -2
  10. data/lib/rdoc/context/section.rb +0 -13
  11. data/lib/rdoc/cross_reference.rb +4 -4
  12. data/lib/rdoc/erb_partial.rb +1 -1
  13. data/lib/rdoc/erbio.rb +2 -2
  14. data/lib/rdoc/generator/darkfish.rb +9 -9
  15. data/lib/rdoc/generator/pot.rb +3 -3
  16. data/lib/rdoc/generator/template/darkfish/_head.rhtml +4 -5
  17. data/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml +2 -2
  18. data/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml +2 -2
  19. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +7 -7
  20. data/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml +2 -2
  21. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +7 -7
  22. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +6 -6
  23. data/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml +5 -5
  24. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +5 -5
  25. data/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml +5 -5
  26. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +4 -4
  27. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +4 -4
  28. data/lib/rdoc/generator/template/darkfish/class.rhtml +44 -44
  29. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +33 -5
  30. data/lib/rdoc/generator/template/darkfish/index.rhtml +3 -4
  31. data/lib/rdoc/generator/template/darkfish/js/darkfish.js +0 -1
  32. data/lib/rdoc/generator/template/darkfish/servlet_root.rhtml +15 -16
  33. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +16 -16
  34. data/lib/rdoc/i18n.rb +1 -1
  35. data/lib/rdoc/markdown.kpeg +20 -2
  36. data/lib/rdoc/markdown.rb +16685 -0
  37. data/lib/rdoc/markdown/literals.rb +417 -0
  38. data/lib/rdoc/markup.rb +1 -2
  39. data/lib/rdoc/markup/attr_span.rb +8 -2
  40. data/lib/rdoc/markup/attribute_manager.rb +93 -28
  41. data/lib/rdoc/markup/formatter.rb +1 -1
  42. data/lib/rdoc/markup/parser.rb +58 -42
  43. data/lib/rdoc/markup/pre_process.rb +1 -1
  44. data/lib/rdoc/markup/to_html.rb +46 -6
  45. data/lib/rdoc/markup/to_html_crossref.rb +18 -6
  46. data/lib/rdoc/markup/to_joined_paragraph.rb +1 -0
  47. data/lib/rdoc/markup/to_rdoc.rb +28 -0
  48. data/lib/rdoc/markup/to_table_of_contents.rb +1 -0
  49. data/lib/rdoc/options.rb +56 -6
  50. data/lib/rdoc/parser.rb +7 -7
  51. data/lib/rdoc/parser/c.rb +139 -183
  52. data/lib/rdoc/parser/changelog.rb +145 -14
  53. data/lib/rdoc/parser/ripper_state_lex.rb +2 -1
  54. data/lib/rdoc/parser/ruby.rb +18 -8
  55. data/lib/rdoc/rd/block_parser.rb +1056 -0
  56. data/lib/rdoc/rd/inline_parser.rb +1208 -0
  57. data/lib/rdoc/rdoc.rb +35 -22
  58. data/lib/rdoc/ri/driver.rb +9 -5
  59. data/lib/rdoc/ri/paths.rb +3 -17
  60. data/lib/rdoc/ri/task.rb +1 -1
  61. data/lib/rdoc/rubygems_hook.rb +2 -2
  62. data/lib/rdoc/servlet.rb +16 -8
  63. data/lib/rdoc/store.rb +6 -14
  64. data/lib/rdoc/task.rb +1 -1
  65. data/lib/rdoc/text.rb +8 -2
  66. data/lib/rdoc/token_stream.rb +8 -3
  67. data/lib/rdoc/tom_doc.rb +6 -7
  68. data/lib/rdoc/version.rb +1 -1
  69. data/man/ri.1 +247 -0
  70. data/rdoc.gemspec +195 -9
  71. metadata +9 -70
  72. data/.document +0 -5
  73. data/.gitignore +0 -14
  74. data/.travis.yml +0 -21
  75. data/appveyor.yml +0 -36
  76. data/lib/rdoc/markup/formatter_test_case.rb +0 -764
  77. data/lib/rdoc/markup/text_formatter_test_case.rb +0 -115
@@ -58,6 +58,10 @@ class RDoc::Markup::AttributeManager
58
58
 
59
59
  attr_reader :regexp_handlings
60
60
 
61
+ ##
62
+ # A bits of exclusive maps
63
+ attr_reader :exclusive_bitmap
64
+
61
65
  ##
62
66
  # Creates a new attribute manager that understands bold, emphasized and
63
67
  # teletype text.
@@ -68,17 +72,18 @@ class RDoc::Markup::AttributeManager
68
72
  @protectable = %w[<]
69
73
  @regexp_handlings = []
70
74
  @word_pair_map = {}
75
+ @exclusive_bitmap = 0
71
76
  @attributes = RDoc::Markup::Attributes.new
72
77
 
73
- add_word_pair "*", "*", :BOLD
74
- add_word_pair "_", "_", :EM
75
- add_word_pair "+", "+", :TT
78
+ add_word_pair "*", "*", :BOLD, true
79
+ add_word_pair "_", "_", :EM, true
80
+ add_word_pair "+", "+", :TT, true
76
81
 
77
- add_html "em", :EM
78
- add_html "i", :EM
79
- add_html "b", :BOLD
80
- add_html "tt", :TT
81
- add_html "code", :TT
82
+ add_html "em", :EM, true
83
+ add_html "i", :EM, true
84
+ add_html "b", :BOLD, true
85
+ add_html "tt", :TT, true
86
+ add_html "code", :TT, true
82
87
  end
83
88
 
84
89
  ##
@@ -122,29 +127,67 @@ class RDoc::Markup::AttributeManager
122
127
  res
123
128
  end
124
129
 
130
+ def exclusive?(attr)
131
+ (attr & @exclusive_bitmap) != 0
132
+ end
133
+
134
+ NON_PRINTING_START = "\1" # :nodoc:
135
+ NON_PRINTING_END = "\2" # :nodoc:
136
+
125
137
  ##
126
138
  # Map attributes like <b>text</b>to the sequence
127
139
  # \001\002<char>\001\003<char>, where <char> is a per-attribute specific
128
140
  # character
129
141
 
130
- def convert_attrs(str, attrs)
142
+ def convert_attrs(str, attrs, exclusive = false)
143
+ convert_attrs_matching_word_pairs(str, attrs, exclusive)
144
+ convert_attrs_word_pair_map(str, attrs, exclusive)
145
+ end
146
+
147
+ def convert_attrs_matching_word_pairs(str, attrs, exclusive)
131
148
  # first do matching ones
132
- tags = @matching_word_pairs.keys.join("")
149
+ tags = @matching_word_pairs.select { |start, bitmap|
150
+ if exclusive && exclusive?(bitmap)
151
+ true
152
+ elsif !exclusive && !exclusive?(bitmap)
153
+ true
154
+ else
155
+ false
156
+ end
157
+ }.keys
158
+ return if tags.empty?
159
+ all_tags = @matching_word_pairs.keys
133
160
 
134
- re = /(^|\W)([#{tags}])([#\\]?[\w:.\/-]+?\S?)\2(\W|$)/
161
+ re = /(^|\W|[#{all_tags.join("")}])([#{tags.join("")}])(\2*[#\\]?[\w:.\/\[\]-]+?\S?)\2(?!\2)([#{all_tags.join("")}]|\W|$)/
135
162
 
136
- 1 while str.gsub!(re) do
163
+ 1 while str.gsub!(re) { |orig|
137
164
  attr = @matching_word_pairs[$2]
138
- attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr)
139
- $1 + NULL * $2.length + $3 + NULL * $2.length + $4
140
- end
165
+ attr_updated = attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr)
166
+ if attr_updated
167
+ $1 + NULL * $2.length + $3 + NULL * $2.length + $4
168
+ else
169
+ $1 + NON_PRINTING_START + $2 + NON_PRINTING_END + $3 + NON_PRINTING_START + $2 + NON_PRINTING_END + $4
170
+ end
171
+ }
172
+ str.delete!(NON_PRINTING_START + NON_PRINTING_END)
173
+ end
141
174
 
175
+ def convert_attrs_word_pair_map(str, attrs, exclusive)
142
176
  # then non-matching
143
177
  unless @word_pair_map.empty? then
144
178
  @word_pair_map.each do |regexp, attr|
145
- str.gsub!(regexp) {
146
- attrs.set_attrs($`.length + $1.length, $2.length, attr)
147
- NULL * $1.length + $2 + NULL * $3.length
179
+ if !exclusive
180
+ next if exclusive?(attr)
181
+ else
182
+ next if !exclusive?(attr)
183
+ end
184
+ 1 while str.gsub!(regexp) { |orig|
185
+ updated = attrs.set_attrs($`.length + $1.length, $2.length, attr)
186
+ if updated
187
+ NULL * $1.length + $2 + NULL * $3.length
188
+ else
189
+ orig
190
+ end
148
191
  }
149
192
  end
150
193
  end
@@ -153,10 +196,18 @@ class RDoc::Markup::AttributeManager
153
196
  ##
154
197
  # Converts HTML tags to RDoc attributes
155
198
 
156
- def convert_html(str, attrs)
157
- tags = @html_tags.keys.join '|'
199
+ def convert_html(str, attrs, exclusive = false)
200
+ tags = @html_tags.select { |start, bitmap|
201
+ if exclusive && exclusive?(bitmap)
202
+ true
203
+ elsif !exclusive && !exclusive?(bitmap)
204
+ true
205
+ else
206
+ false
207
+ end
208
+ }.keys.join '|'
158
209
 
159
- 1 while str.gsub!(/<(#{tags})>(.*?)<\/\1>/i) {
210
+ 1 while str.gsub!(/<(#{tags})>(.*?)<\/\1>/i) { |orig|
160
211
  attr = @html_tags[$1.downcase]
161
212
  html_length = $1.length + 2
162
213
  seq = NULL * html_length
@@ -168,8 +219,13 @@ class RDoc::Markup::AttributeManager
168
219
  ##
169
220
  # Converts regexp handling sequences to RDoc attributes
170
221
 
171
- def convert_regexp_handlings str, attrs
222
+ def convert_regexp_handlings str, attrs, exclusive = false
172
223
  @regexp_handlings.each do |regexp, attribute|
224
+ if exclusive
225
+ next if !exclusive?(attribute)
226
+ else
227
+ next if exclusive?(attribute)
228
+ end
173
229
  str.scan(regexp) do
174
230
  capture = $~.size == 1 ? 0 : 1
175
231
 
@@ -205,7 +261,7 @@ class RDoc::Markup::AttributeManager
205
261
  #
206
262
  # am.add_word_pair '*', '*', :BOLD
207
263
 
208
- def add_word_pair(start, stop, name)
264
+ def add_word_pair(start, stop, name, exclusive = false)
209
265
  raise ArgumentError, "Word flags may not start with '<'" if
210
266
  start[0,1] == '<'
211
267
 
@@ -220,6 +276,8 @@ class RDoc::Markup::AttributeManager
220
276
 
221
277
  @protectable << start[0,1]
222
278
  @protectable.uniq!
279
+
280
+ @exclusive_bitmap |= bitmap if exclusive
223
281
  end
224
282
 
225
283
  ##
@@ -228,8 +286,10 @@ class RDoc::Markup::AttributeManager
228
286
  #
229
287
  # am.add_html 'em', :EM
230
288
 
231
- def add_html(tag, name)
232
- @html_tags[tag.downcase] = @attributes.bitmap_for name
289
+ def add_html(tag, name, exclusive = false)
290
+ bitmap = @attributes.bitmap_for name
291
+ @html_tags[tag.downcase] = bitmap
292
+ @exclusive_bitmap |= bitmap if exclusive
233
293
  end
234
294
 
235
295
  ##
@@ -238,8 +298,10 @@ class RDoc::Markup::AttributeManager
238
298
  #
239
299
  # @am.add_regexp_handling(/((https?:)\S+\w)/, :HYPERLINK)
240
300
 
241
- def add_regexp_handling pattern, name
242
- @regexp_handlings << [pattern, @attributes.bitmap_for(name)]
301
+ def add_regexp_handling pattern, name, exclusive = false
302
+ bitmap = @attributes.bitmap_for(name)
303
+ @regexp_handlings << [pattern, bitmap]
304
+ @exclusive_bitmap |= bitmap if exclusive
243
305
  end
244
306
 
245
307
  ##
@@ -250,8 +312,11 @@ class RDoc::Markup::AttributeManager
250
312
 
251
313
  mask_protected_sequences
252
314
 
253
- @attrs = RDoc::Markup::AttrSpan.new @str.length
315
+ @attrs = RDoc::Markup::AttrSpan.new @str.length, @exclusive_bitmap
254
316
 
317
+ convert_attrs @str, @attrs, true
318
+ convert_html @str, @attrs, true
319
+ convert_regexp_handlings @str, @attrs, true
255
320
  convert_attrs @str, @attrs
256
321
  convert_html @str, @attrs
257
322
  convert_regexp_handlings @str, @attrs
@@ -156,7 +156,7 @@ class RDoc::Markup::Formatter
156
156
  method_name = "handle_regexp_#{name}"
157
157
 
158
158
  if respond_to? method_name then
159
- target.text = send method_name, target
159
+ target.text = public_send method_name, target
160
160
  handled = true
161
161
  end
162
162
  end
@@ -80,10 +80,6 @@ class RDoc::Markup::Parser
80
80
  @binary_input = nil
81
81
  @current_token = nil
82
82
  @debug = false
83
- @input = nil
84
- @input_encoding = nil
85
- @line = 0
86
- @line_pos = 0
87
83
  @s = nil
88
84
  @tokens = []
89
85
  end
@@ -319,13 +315,6 @@ class RDoc::Markup::Parser
319
315
  verbatim
320
316
  end
321
317
 
322
- ##
323
- # The character offset for the input string at the given +byte_offset+
324
-
325
- def char_pos byte_offset
326
- @input.byteslice(0, byte_offset).length
327
- end
328
-
329
318
  ##
330
319
  # Pulls the next token from the stream.
331
320
 
@@ -424,15 +413,53 @@ class RDoc::Markup::Parser
424
413
  token
425
414
  end
426
415
 
416
+ ##
417
+ # A simple wrapper of StringScanner that is aware of the current column and lineno
418
+
419
+ class MyStringScanner
420
+ def initialize(input)
421
+ @line = @column = 0
422
+ @s = StringScanner.new input
423
+ end
424
+
425
+ def scan(re)
426
+ ret = @s.scan(re)
427
+ @column += ret.length if ret
428
+ ret
429
+ end
430
+
431
+ def unscan(s)
432
+ @s.pos -= s.bytesize
433
+ @column -= s.length
434
+ end
435
+
436
+ def pos
437
+ [@column, @line]
438
+ end
439
+
440
+ def newline!
441
+ @column = 0
442
+ @line += 1
443
+ end
444
+
445
+ def eos?
446
+ @s.eos?
447
+ end
448
+
449
+ def matched
450
+ @s.matched
451
+ end
452
+
453
+ def [](i)
454
+ @s[i]
455
+ end
456
+ end
457
+
427
458
  ##
428
459
  # Creates the StringScanner
429
460
 
430
461
  def setup_scanner input
431
- @line = 0
432
- @line_pos = 0
433
- @input = input.dup
434
-
435
- @s = StringScanner.new input
462
+ @s = MyStringScanner.new input
436
463
  end
437
464
 
438
465
  ##
@@ -467,31 +494,30 @@ class RDoc::Markup::Parser
467
494
  @tokens << case
468
495
  # [CR]LF => :NEWLINE
469
496
  when @s.scan(/\r?\n/) then
470
- token = [:NEWLINE, @s.matched, *token_pos(pos)]
471
- @line_pos = char_pos @s.pos
472
- @line += 1
497
+ token = [:NEWLINE, @s.matched, *pos]
498
+ @s.newline!
473
499
  token
474
500
  # === text => :HEADER then :TEXT
475
501
  when @s.scan(/(=+)(\s*)/) then
476
502
  level = @s[1].length
477
- header = [:HEADER, level, *token_pos(pos)]
503
+ header = [:HEADER, level, *pos]
478
504
 
479
505
  if @s[2] =~ /^\r?\n/ then
480
- @s.pos -= @s[2].length
506
+ @s.unscan(@s[2])
481
507
  header
482
508
  else
483
509
  pos = @s.pos
484
510
  @s.scan(/.*/)
485
511
  @tokens << header
486
- [:TEXT, @s.matched.sub(/\r$/, ''), *token_pos(pos)]
512
+ [:TEXT, @s.matched.sub(/\r$/, ''), *pos]
487
513
  end
488
514
  # --- (at least 3) and nothing else on the line => :RULE
489
515
  when @s.scan(/(-{3,}) *\r?$/) then
490
- [:RULE, @s[1].length - 2, *token_pos(pos)]
516
+ [:RULE, @s[1].length - 2, *pos]
491
517
  # * or - followed by white space and text => :BULLET
492
518
  when @s.scan(/([*-]) +(\S)/) then
493
- @s.pos -= @s[2].bytesize # unget \S
494
- [:BULLET, @s[1], *token_pos(pos)]
519
+ @s.unscan(@s[2])
520
+ [:BULLET, @s[1], *pos]
495
521
  # A. text, a. text, 12. text => :UALPHA, :LALPHA, :NUMBER
496
522
  when @s.scan(/([a-z]|\d+)\. +(\S)/i) then
497
523
  # FIXME if tab(s), the column will be wrong
@@ -500,7 +526,7 @@ class RDoc::Markup::Parser
500
526
  # before (and provide a check for that at least in debug
501
527
  # mode)
502
528
  list_label = @s[1]
503
- @s.pos -= @s[2].bytesize # unget \S
529
+ @s.unscan(@s[2])
504
530
  list_type =
505
531
  case list_label
506
532
  when /[a-z]/ then :LALPHA
@@ -509,24 +535,24 @@ class RDoc::Markup::Parser
509
535
  else
510
536
  raise ParseError, "BUG token #{list_label}"
511
537
  end
512
- [list_type, list_label, *token_pos(pos)]
538
+ [list_type, list_label, *pos]
513
539
  # [text] followed by spaces or end of line => :LABEL
514
540
  when @s.scan(/\[(.*?)\]( +|\r?$)/) then
515
- [:LABEL, @s[1], *token_pos(pos)]
541
+ [:LABEL, @s[1], *pos]
516
542
  # text:: followed by spaces or end of line => :NOTE
517
543
  when @s.scan(/(.*?)::( +|\r?$)/) then
518
- [:NOTE, @s[1], *token_pos(pos)]
544
+ [:NOTE, @s[1], *pos]
519
545
  # >>> followed by end of line => :BLOCKQUOTE
520
546
  when @s.scan(/>>> *(\w+)?$/) then
521
- [:BLOCKQUOTE, @s[1], *token_pos(pos)]
547
+ [:BLOCKQUOTE, @s[1], *pos]
522
548
  # anything else: :TEXT
523
549
  else
524
550
  @s.scan(/(.*?)( )?\r?$/)
525
- token = [:TEXT, @s[1], *token_pos(pos)]
551
+ token = [:TEXT, @s[1], *pos]
526
552
 
527
553
  if @s[2] then
528
554
  @tokens << token
529
- [:BREAK, @s[2], *token_pos(pos + @s[1].length)]
555
+ [:BREAK, @s[2], pos[0] + @s[1].length, pos[1]]
530
556
  else
531
557
  token
532
558
  end
@@ -536,16 +562,6 @@ class RDoc::Markup::Parser
536
562
  self
537
563
  end
538
564
 
539
- ##
540
- # Calculates the column (by character) and line of the current token based
541
- # on +byte_offset+.
542
-
543
- def token_pos byte_offset
544
- offset = char_pos byte_offset
545
-
546
- [offset - @line_pos, @line]
547
- end
548
-
549
565
  ##
550
566
  # Returns the current token to the token stream
551
567
 
@@ -178,7 +178,7 @@ class RDoc::Markup::PreProcess
178
178
 
179
179
  blankline
180
180
  when 'include' then
181
- filename = param.split.first
181
+ filename = param.split(' ', 2).first
182
182
  include_file filename, prefix, encoding
183
183
  when 'main' then
184
184
  @options.main_page = param if @options.respond_to? :main_page
@@ -52,12 +52,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
52
52
  @th = nil
53
53
  @hard_break = "<br>\n"
54
54
 
55
- # external links
56
- @markup.add_regexp_handling(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)\S+\w/,
57
- :HYPERLINK)
58
-
59
- add_regexp_handling_RDOCLINK
60
- add_regexp_handling_TIDYLINK
55
+ init_regexp_handlings
61
56
 
62
57
  init_tags
63
58
  end
@@ -66,6 +61,24 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
66
61
  #
67
62
  # These methods are used by regexp handling markup added by RDoc::Markup#add_regexp_handling.
68
63
 
64
+ ##
65
+ # Adds regexp handlings.
66
+
67
+ def init_regexp_handlings
68
+ # external links
69
+ @markup.add_regexp_handling(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)\S+\w/,
70
+ :HYPERLINK)
71
+ init_link_notation_regexp_handlings
72
+ end
73
+
74
+ ##
75
+ # Adds regexp handlings about link notations.
76
+
77
+ def init_link_notation_regexp_handlings
78
+ add_regexp_handling_RDOCLINK
79
+ add_regexp_handling_TIDYLINK
80
+ end
81
+
69
82
  def handle_RDOCLINK url # :nodoc:
70
83
  case url
71
84
  when /^rdoc-ref:/
@@ -301,6 +314,29 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
301
314
  @res << raw.parts.join("\n")
302
315
  end
303
316
 
317
+ ##
318
+ # Adds +table+ to the output
319
+
320
+ def accept_table header, body, aligns
321
+ @res << "\n<table role=\"table\">\n<thead>\n<tr>\n"
322
+ header.zip(aligns) do |text, align|
323
+ @res << '<th'
324
+ @res << ' align="' << align << '"' if align
325
+ @res << '>' << CGI.escapeHTML(text) << "</th>\n"
326
+ end
327
+ @res << "</tr>\n</thead>\n<tbody>\n"
328
+ body.each do |row|
329
+ @res << "<tr>\n"
330
+ row.zip(aligns) do |text, align|
331
+ @res << '<td'
332
+ @res << ' align="' << align << '"' if align
333
+ @res << '>' << CGI.escapeHTML(text) << "</td>\n"
334
+ end
335
+ @res << "</tr>\n"
336
+ end
337
+ @res << "</tbody>\n</table>\n"
338
+ end
339
+
304
340
  # :section: Utilities
305
341
 
306
342
  ##
@@ -321,6 +357,10 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
321
357
  url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
322
358
  "<img src=\"#{url}\" />"
323
359
  else
360
+ if scheme != 'link' and /\.(?:rb|rdoc|md)\z/i =~ url
361
+ url = url.sub(%r%\A([./]*)(.*)\z%) { "#$1#{$2.tr('.', '_')}.html" }
362
+ end
363
+
324
364
  text = text.sub %r%^#{scheme}:/*%i, ''
325
365
  text = text.sub %r%^[*\^](\d+)$%, '\1'
326
366