rdoc 6.17.0 → 8.1.0

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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +193 -0
  3. data/LEGAL.rdoc +6 -0
  4. data/LICENSE.rdoc +4 -0
  5. data/README.md +132 -8
  6. data/RI.md +75 -75
  7. data/doc/markup_reference/markdown.md +659 -0
  8. data/doc/markup_reference/rdoc.rdoc +1169 -0
  9. data/exe/rdoc +2 -2
  10. data/lib/rdoc/code_object/alias.rb +70 -74
  11. data/lib/rdoc/code_object/any_method.rb +308 -293
  12. data/lib/rdoc/code_object/attr.rb +150 -142
  13. data/lib/rdoc/code_object/class_module.rb +802 -715
  14. data/lib/rdoc/code_object/constant.rb +181 -144
  15. data/lib/rdoc/code_object/context/section.rb +140 -130
  16. data/lib/rdoc/code_object/context.rb +925 -941
  17. data/lib/rdoc/code_object/extend.rb +7 -5
  18. data/lib/rdoc/code_object/include.rb +7 -5
  19. data/lib/rdoc/code_object/method_attr.rb +328 -315
  20. data/lib/rdoc/code_object/mixin.rb +97 -92
  21. data/lib/rdoc/code_object/normal_class.rb +77 -78
  22. data/lib/rdoc/code_object/normal_module.rb +61 -59
  23. data/lib/rdoc/code_object/require.rb +23 -39
  24. data/lib/rdoc/code_object/single_class.rb +21 -19
  25. data/lib/rdoc/code_object/top_level.rb +215 -202
  26. data/lib/rdoc/code_object.rb +305 -305
  27. data/lib/rdoc/comment.rb +274 -337
  28. data/lib/rdoc/cross_reference.rb +195 -206
  29. data/lib/rdoc/encoding.rb +105 -103
  30. data/lib/rdoc/erb_partial.rb +13 -11
  31. data/lib/rdoc/erbio.rb +29 -27
  32. data/lib/rdoc/generator/aliki.rb +196 -30
  33. data/lib/rdoc/generator/darkfish.rb +647 -629
  34. data/lib/rdoc/generator/json_index.rb +233 -229
  35. data/lib/rdoc/generator/markup.rb +165 -122
  36. data/lib/rdoc/generator/pot/message_extractor.rb +57 -51
  37. data/lib/rdoc/generator/pot/po.rb +52 -51
  38. data/lib/rdoc/generator/pot/po_entry.rb +138 -132
  39. data/lib/rdoc/generator/pot.rb +85 -81
  40. data/lib/rdoc/generator/ri.rb +23 -19
  41. data/lib/rdoc/generator/template/aliki/DESIGN.md +538 -0
  42. data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +1 -1
  43. data/lib/rdoc/generator/template/aliki/_footer.rhtml +2 -2
  44. data/lib/rdoc/generator/template/aliki/_head.rhtml +15 -10
  45. data/lib/rdoc/generator/template/aliki/_header.rhtml +29 -44
  46. data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +8 -6
  47. data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +8 -6
  48. data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +1 -1
  49. data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +3 -3
  50. data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +3 -3
  51. data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +1 -1
  52. data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +1 -1
  53. data/lib/rdoc/generator/template/aliki/class.rhtml +71 -61
  54. data/lib/rdoc/generator/template/aliki/css/rdoc.css +796 -323
  55. data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
  56. data/lib/rdoc/generator/template/aliki/js/aliki.js +119 -113
  57. data/lib/rdoc/generator/template/aliki/js/bash_highlighter.js +167 -0
  58. data/lib/rdoc/generator/template/aliki/js/c_highlighter.js +1 -1
  59. data/lib/rdoc/generator/template/aliki/js/{search.js → search_controller.js} +16 -7
  60. data/lib/rdoc/generator/template/aliki/js/search_navigation.js +105 -0
  61. data/lib/rdoc/generator/template/aliki/js/search_ranker.js +239 -0
  62. data/lib/rdoc/generator/template/aliki/page.rhtml +1 -1
  63. data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
  64. data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +2 -2
  65. data/lib/rdoc/generator/template/darkfish/_footer.rhtml +1 -1
  66. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +8 -6
  67. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +8 -6
  68. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +1 -1
  69. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +2 -2
  70. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +1 -1
  71. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +5 -5
  72. data/lib/rdoc/generator/template/darkfish/class.rhtml +29 -32
  73. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +19 -1
  74. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +3 -3
  75. data/lib/rdoc/generator.rb +48 -46
  76. data/lib/rdoc/i18n/locale.rb +99 -95
  77. data/lib/rdoc/i18n/text.rb +109 -105
  78. data/lib/rdoc/i18n.rb +7 -5
  79. data/lib/rdoc/markdown/byte_runtime.rb +80 -0
  80. data/lib/rdoc/markdown.kpeg +52 -33
  81. data/lib/rdoc/markdown.rb +365 -177
  82. data/lib/rdoc/markup/blank_line.rb +25 -23
  83. data/lib/rdoc/markup/block_quote.rb +12 -8
  84. data/lib/rdoc/markup/document.rb +127 -123
  85. data/lib/rdoc/markup/element.rb +21 -0
  86. data/lib/rdoc/markup/formatter.rb +220 -203
  87. data/lib/rdoc/markup/hard_break.rb +30 -27
  88. data/lib/rdoc/markup/heading.rb +163 -77
  89. data/lib/rdoc/markup/include.rb +33 -29
  90. data/lib/rdoc/markup/indented_paragraph.rb +37 -33
  91. data/lib/rdoc/markup/inline_parser.rb +316 -0
  92. data/lib/rdoc/markup/list.rb +80 -88
  93. data/lib/rdoc/markup/list_item.rb +73 -85
  94. data/lib/rdoc/markup/paragraph.rb +23 -19
  95. data/lib/rdoc/markup/parser.rb +501 -497
  96. data/lib/rdoc/markup/pre_process.rb +284 -305
  97. data/lib/rdoc/markup/raw.rb +52 -55
  98. data/lib/rdoc/markup/rule.rb +16 -12
  99. data/lib/rdoc/markup/table.rb +48 -40
  100. data/lib/rdoc/markup/to_ansi.rb +143 -92
  101. data/lib/rdoc/markup/to_bs.rb +86 -102
  102. data/lib/rdoc/markup/to_html.rb +608 -506
  103. data/lib/rdoc/markup/to_html_crossref.rb +219 -210
  104. data/lib/rdoc/markup/to_html_snippet.rb +210 -205
  105. data/lib/rdoc/markup/to_joined_paragraph.rb +40 -41
  106. data/lib/rdoc/markup/to_label.rb +64 -51
  107. data/lib/rdoc/markup/to_markdown.rb +212 -184
  108. data/lib/rdoc/markup/to_rdoc.rb +341 -277
  109. data/lib/rdoc/markup/to_table_of_contents.rb +66 -62
  110. data/lib/rdoc/markup/to_test.rb +62 -50
  111. data/lib/rdoc/markup/to_tt_only.rb +83 -92
  112. data/lib/rdoc/markup/verbatim.rb +62 -58
  113. data/lib/rdoc/markup.rb +196 -215
  114. data/lib/rdoc/options.rb +1063 -1076
  115. data/lib/rdoc/parser/c.rb +1039 -1036
  116. data/lib/rdoc/parser/changelog.rb +320 -287
  117. data/lib/rdoc/parser/markdown.rb +17 -13
  118. data/lib/rdoc/parser/rbs.rb +279 -0
  119. data/lib/rdoc/parser/rd.rb +17 -13
  120. data/lib/rdoc/parser/ruby.rb +1231 -2222
  121. data/lib/rdoc/parser/ruby_colorizer.rb +303 -0
  122. data/lib/rdoc/parser/simple.rb +31 -27
  123. data/lib/rdoc/parser/text.rb +12 -8
  124. data/lib/rdoc/parser.rb +230 -221
  125. data/lib/rdoc/rbs_helper.rb +186 -0
  126. data/lib/rdoc/rd/inline.rb +57 -53
  127. data/lib/rdoc/rd.rb +90 -88
  128. data/lib/rdoc/rdoc.rb +547 -366
  129. data/lib/rdoc/ri/driver.rb +1141 -1130
  130. data/lib/rdoc/ri/formatter.rb +7 -3
  131. data/lib/rdoc/ri/paths.rb +140 -136
  132. data/lib/rdoc/ri/servlet.rb +456 -0
  133. data/lib/rdoc/ri/store.rb +4 -2
  134. data/lib/rdoc/ri/task.rb +55 -51
  135. data/lib/rdoc/ri.rb +14 -11
  136. data/lib/rdoc/rubygems_hook.rb +194 -192
  137. data/lib/rdoc/server.rb +462 -0
  138. data/lib/rdoc/stats/normal.rb +46 -42
  139. data/lib/rdoc/stats/quiet.rb +39 -35
  140. data/lib/rdoc/stats/verbose.rb +35 -31
  141. data/lib/rdoc/stats.rb +363 -338
  142. data/lib/rdoc/store.rb +919 -725
  143. data/lib/rdoc/task.rb +260 -255
  144. data/lib/rdoc/text.rb +164 -240
  145. data/lib/rdoc/token_stream.rb +88 -106
  146. data/lib/rdoc/tom_doc.rb +203 -201
  147. data/lib/rdoc/version.rb +1 -1
  148. data/lib/rdoc.rb +35 -7
  149. data/lib/rubygems_plugin.rb +2 -11
  150. data/rdoc-logo.svg +43 -0
  151. data/rdoc.gemspec +9 -7
  152. metadata +46 -32
  153. data/CONTRIBUTING.rdoc +0 -219
  154. data/ExampleMarkdown.md +0 -39
  155. data/ExampleRDoc.rdoc +0 -210
  156. data/lib/rdoc/code_object/anon_class.rb +0 -10
  157. data/lib/rdoc/code_object/ghost_method.rb +0 -6
  158. data/lib/rdoc/code_object/meta_method.rb +0 -6
  159. data/lib/rdoc/markdown/literals.kpeg +0 -21
  160. data/lib/rdoc/markdown/literals.rb +0 -454
  161. data/lib/rdoc/markup/attr_changer.rb +0 -22
  162. data/lib/rdoc/markup/attr_span.rb +0 -35
  163. data/lib/rdoc/markup/attribute_manager.rb +0 -405
  164. data/lib/rdoc/markup/attributes.rb +0 -70
  165. data/lib/rdoc/markup/regexp_handling.rb +0 -40
  166. data/lib/rdoc/parser/prism_ruby.rb +0 -1100
  167. data/lib/rdoc/parser/ripper_state_lex.rb +0 -302
  168. data/lib/rdoc/parser/ruby_tools.rb +0 -163
  169. data/lib/rdoc/servlet.rb +0 -452
data/lib/rdoc/text.rb CHANGED
@@ -5,57 +5,30 @@
5
5
 
6
6
  require 'strscan'
7
7
 
8
- ##
9
- # Methods for manipulating comment text
10
-
11
- module RDoc::Text
12
-
8
+ module RDoc
13
9
  ##
14
- # The language for this text. This affects stripping comments
15
- # markers.
10
+ # Methods for manipulating comment text
16
11
 
17
- attr_accessor :language
12
+ module Text
18
13
 
19
- ##
20
- # Maps markup formats to classes that can parse them. If the format is
21
- # unknown, "rdoc" format is used.
14
+ ##
15
+ # The language for this text. This affects stripping comments
16
+ # markers.
22
17
 
23
- MARKUP_FORMAT = {
24
- 'markdown' => RDoc::Markdown,
25
- 'rdoc' => RDoc::Markup,
26
- 'rd' => RDoc::RD,
27
- 'tomdoc' => RDoc::TomDoc,
28
- }
18
+ attr_accessor :language
29
19
 
30
- MARKUP_FORMAT.default = RDoc::Markup
20
+ ##
21
+ # Maps markup formats to classes that can parse them. If the format is
22
+ # unknown, "rdoc" format is used.
31
23
 
32
- ##
33
- # Maps an encoding to a Hash of characters properly transcoded for that
34
- # encoding.
35
- #
36
- # See also encode_fallback.
37
-
38
- TO_HTML_CHARACTERS = Hash.new do |h, encoding|
39
- h[encoding] = {
40
- :close_dquote => encode_fallback('”', encoding, '"'),
41
- :close_squote => encode_fallback('’', encoding, '\''),
42
- :copyright => encode_fallback('©', encoding, '(c)'),
43
- :ellipsis => encode_fallback('…', encoding, '...'),
44
- :em_dash => encode_fallback('—', encoding, '---'),
45
- :en_dash => encode_fallback('–', encoding, '--'),
46
- :open_dquote => encode_fallback('“', encoding, '"'),
47
- :open_squote => encode_fallback('‘', encoding, '\''),
48
- :trademark => encode_fallback('®', encoding, '(r)'),
24
+ MARKUP_FORMAT = {
25
+ 'markdown' => Markdown,
26
+ 'rdoc' => Markup,
27
+ 'rd' => RD,
28
+ 'tomdoc' => TomDoc,
49
29
  }
50
- end
51
-
52
- ##
53
- # Transcodes +character+ to +encoding+ with a +fallback+ character.
54
30
 
55
- def self.encode_fallback(character, encoding, fallback)
56
- character.encode(encoding, :fallback => { character => fallback },
57
- :undef => :replace, :replace => fallback)
58
- end
31
+ MARKUP_FORMAT.default = Markup
59
32
 
60
33
  ##
61
34
  # Expands tab characters in +text+ to eight spaces
@@ -66,7 +39,7 @@ module RDoc::Text
66
39
  text.each_line do |line|
67
40
  nil while line.gsub!(/(?:\G|\r)((?:.{8})*?)([^\t\r\n]{0,7})\t/) do
68
41
  r = "#{$1}#{$2}#{' ' * (8 - $2.size)}"
69
- r = RDoc::Encoding.change_encoding r, text.encoding
42
+ r = Encoding.change_encoding r, text.encoding
70
43
  r
71
44
  end
72
45
 
@@ -76,247 +49,198 @@ module RDoc::Text
76
49
  expanded.join
77
50
  end
78
51
 
79
- ##
80
- # Flush +text+ left based on the shortest line
52
+ ##
53
+ # Flush +text+ left based on the shortest line
81
54
 
82
- def flush_left(text)
83
- indent = 9999
55
+ def flush_left(text)
56
+ indent = 9999
84
57
 
85
- text.each_line do |line|
86
- line_indent = line =~ /\S/ || 9999
87
- indent = line_indent if indent > line_indent
88
- end
58
+ text.each_line do |line|
59
+ line_indent = line =~ /\S/ || 9999
60
+ indent = line_indent if indent > line_indent
61
+ end
89
62
 
90
- empty = ''
91
- empty = RDoc::Encoding.change_encoding empty, text.encoding
63
+ empty = ''
64
+ empty = Encoding.change_encoding empty, text.encoding
92
65
 
93
- text.gsub(/^ {0,#{indent}}/, empty)
94
- end
66
+ text.gsub(/^ {0,#{indent}}/, empty)
67
+ end
95
68
 
96
- ##
97
- # Convert a string in markup format into HTML.
98
- #
99
- # Requires the including class to implement #formatter
69
+ ##
70
+ # Convert a string in markup format into HTML.
71
+ #
72
+ # Requires the including class to implement #formatter
100
73
 
101
- def markup(text)
102
- if @store.options
103
- locale = @store.options.locale
104
- else
105
- locale = nil
106
- end
107
- if locale
108
- i18n_text = RDoc::I18n::Text.new(text)
109
- text = i18n_text.translate(locale)
74
+ def markup(text)
75
+ if @store.options
76
+ locale = @store.options.locale
77
+ else
78
+ locale = nil
79
+ end
80
+ if locale
81
+ i18n_text = I18n::Text.new(text)
82
+ text = i18n_text.translate(locale)
83
+ end
84
+ parse(text).accept formatter
110
85
  end
111
- parse(text).accept formatter
112
- end
113
86
 
114
- ##
115
- # Strips hashes, expands tabs then flushes +text+ to the left
87
+ ##
88
+ # Strips hashes, expands tabs then flushes +text+ to the left
116
89
 
117
- def normalize_comment(text)
118
- return text if text.empty?
90
+ def normalize_comment(text)
91
+ return text if text.empty?
119
92
 
120
- case language
121
- when :ruby
122
- text = strip_hashes text
123
- when :c
124
- text = strip_stars text
93
+ case language
94
+ when :ruby
95
+ text = strip_hashes text
96
+ when :c
97
+ text = strip_stars text
98
+ end
99
+ text = expand_tabs text
100
+ text = flush_left text
101
+ text = strip_newlines text
102
+ text
125
103
  end
126
- text = expand_tabs text
127
- text = flush_left text
128
- text = strip_newlines text
129
- text
130
- end
131
104
 
132
- ##
133
- # Normalizes +text+ then builds a RDoc::Markup::Document from it
105
+ ##
106
+ # Normalizes +text+ then builds a RDoc::Markup::Document from it
134
107
 
135
- def parse(text, format = 'rdoc')
136
- return text if RDoc::Markup::Document === text
137
- return text.parse if RDoc::Comment === text
108
+ def parse(text, format = 'rdoc')
109
+ return text if Markup::Document === text
110
+ return text.parse if Comment === text
138
111
 
139
- text = normalize_comment text # TODO remove, should not be necessary
112
+ text = normalize_comment text # TODO remove, should not be necessary
140
113
 
141
- return RDoc::Markup::Document.new if text =~ /\A\n*\z/
114
+ return Markup::Document.new if text =~ /\A\n*\z/
142
115
 
143
- MARKUP_FORMAT[format].parse text
144
- end
116
+ MARKUP_FORMAT[format].parse text
117
+ end
145
118
 
146
- ##
147
- # The first +limit+ characters of +text+ as HTML
119
+ ##
120
+ # The first +limit+ characters of +text+ as HTML
148
121
 
149
- def snippet(text, limit = 100)
150
- document = parse text
122
+ def snippet(text, limit = 100)
123
+ document = parse text
151
124
 
152
- RDoc::Markup::ToHtmlSnippet.new(options, limit).convert document
153
- end
125
+ Markup::ToHtmlSnippet.new(limit).convert document
126
+ end
154
127
 
155
- ##
156
- # Strips leading # characters from +text+
128
+ ##
129
+ # Strips leading # characters from +text+
157
130
 
158
- def strip_hashes(text)
159
- return text if text =~ /^(?>\s*)[^\#]/
131
+ def strip_hashes(text)
132
+ return text if text =~ /^(?>\s*)[^\#]/
160
133
 
161
- empty = ''
162
- empty = RDoc::Encoding.change_encoding empty, text.encoding
134
+ empty = ''
135
+ empty = Encoding.change_encoding empty, text.encoding
163
136
 
164
- text.gsub(/^\s*(#+)/) { $1.tr '#', ' ' }.gsub(/^\s+$/, empty)
165
- end
137
+ text.gsub(/^\s*(#+)/) { $1.tr '#', ' ' }.gsub(/^\s+$/, empty)
138
+ end
166
139
 
167
- ##
168
- # Strips leading and trailing \n characters from +text+
140
+ ##
141
+ # Strips leading and trailing \n characters from +text+
169
142
 
170
- def strip_newlines(text)
171
- text.gsub(/\A\n*(.*?)\n*\z/m) do $1 end # block preserves String encoding
172
- end
143
+ def strip_newlines(text)
144
+ text.gsub(/\A\n*(.*?)\n*\z/m) do $1 end # block preserves String encoding
145
+ end
173
146
 
174
- ##
175
- # Strips /* */ style comments
147
+ ##
148
+ # Strips /* */ style comments
176
149
 
177
- def strip_stars(text)
178
- return text unless text =~ %r%/\*.*\*/%m
150
+ def strip_stars(text)
151
+ return text unless text =~ %r%/\*.*\*/%m
179
152
 
180
- encoding = text.encoding
153
+ encoding = text.encoding
181
154
 
182
- text = text.gsub %r%Document-method:\s+[\w:.#=!?|^&<>~+\-/*\%@`\[\]]+%, ''
155
+ text = text.gsub %r%Document-method:\s+[\w:.#=!?|^&<>~+\-/*\%@`\[\]]+%, ''
183
156
 
184
- space = ' '
185
- space = RDoc::Encoding.change_encoding space, encoding if encoding
157
+ space = ' '
158
+ space = Encoding.change_encoding space, encoding if encoding
186
159
 
187
- text.sub! %r%/\*+% do space * $&.length end
188
- text.sub! %r%\*+/% do space * $&.length end
189
- text.gsub! %r%^[ \t]*\*%m do space * $&.length end
160
+ text.sub! %r%/\*+% do space * $&.length end
161
+ text.sub! %r%\*+/% do space * $&.length end
162
+ text.gsub! %r%^[ \t]*\*%m do space * $&.length end
190
163
 
191
- empty = ''
192
- empty = RDoc::Encoding.change_encoding empty, encoding if encoding
193
- text.gsub(/^\s+$/, empty)
194
- end
164
+ empty = ''
165
+ empty = Encoding.change_encoding empty, encoding if encoding
166
+ text.gsub(/^\s+$/, empty)
167
+ end
195
168
 
196
- ##
197
- # Converts ampersand, dashes, ellipsis, quotes, copyright and registered
198
- # trademark symbols in +text+ to properly encoded characters.
199
-
200
- def to_html(text)
201
- html = (''.encode text.encoding).dup
202
-
203
- encoded = RDoc::Text::TO_HTML_CHARACTERS[text.encoding]
204
-
205
- s = StringScanner.new text
206
- insquotes = false
207
- indquotes = false
208
- after_word = nil
209
-
210
- until s.eos? do
211
- case
212
- when s.scan(/<(tt|code)>.*?<\/\1>/) then # skip contents of tt
213
- html << s.matched.gsub('\\\\', '\\')
214
- when s.scan(/<(tt|code)>.*?/) then
215
- warn "mismatched <#{s[1]}> tag" # TODO signal file/line
216
- html << s.matched
217
- when s.scan(/<[^>]+\/?s*>/) then # skip HTML tags
218
- html << s.matched
219
- when s.scan(/\\(\S)/) then # unhandled suppressed crossref
220
- html << s[1]
221
- after_word = nil
222
- when s.scan(/\.\.\.(\.?)/) then
223
- html << s[1] << encoded[:ellipsis]
224
- after_word = nil
225
- when s.scan(/\(c\)/i) then
226
- html << encoded[:copyright]
227
- after_word = nil
228
- when s.scan(/\(r\)/i) then
229
- html << encoded[:trademark]
230
- after_word = nil
231
- when s.scan(/---/) then
232
- html << encoded[:em_dash]
233
- after_word = nil
234
- when s.scan(/--/) then
235
- html << encoded[:en_dash]
236
- after_word = nil
237
- when s.scan(/&quot;|"/) then
238
- html << encoded[indquotes ? :close_dquote : :open_dquote]
239
- indquotes = !indquotes
240
- after_word = nil
241
- when s.scan(/``/) then # backtick double quote
242
- html << encoded[:open_dquote]
243
- after_word = nil
244
- when s.scan(/(?:&#39;|'){2}/) then # tick double quote
245
- html << encoded[:close_dquote]
246
- after_word = nil
247
- when s.scan(/`/) then # backtick
248
- if insquotes or after_word
249
- html << '`'
250
- after_word = false
251
- else
252
- html << encoded[:open_squote]
253
- insquotes = true
254
- end
255
- when s.scan(/&#39;|'/) then # single quote
256
- if insquotes
257
- html << encoded[:close_squote]
258
- insquotes = false
259
- elsif after_word
260
- # Mary's dog, my parents' house: do not start paired quotes
261
- html << encoded[:close_squote]
262
- else
263
- html << encoded[:open_squote]
264
- insquotes = true
265
- end
169
+ ##
170
+ # Wraps +txt+ to +line_len+
266
171
 
267
- after_word = nil
268
- else # advance to the next potentially significant character
269
- match = s.scan(/.+?(?=[<\\.("'`&-])/) #"
172
+ def wrap(txt, line_len = 76)
173
+ res = []
174
+ sp = 0
175
+ ep = txt.length
270
176
 
271
- if match then
272
- html << match
273
- after_word = match =~ /\w$/
177
+ while sp < ep
178
+ # scan back for a space
179
+ p = sp + line_len - 1
180
+ if p >= ep
181
+ p = ep
274
182
  else
275
- html << s.rest
276
- break
183
+ while p > sp and txt[p] != ?\s
184
+ p -= 1
185
+ end
186
+ if p <= sp
187
+ p = sp + line_len
188
+ while p < ep and txt[p] != ?\s
189
+ p += 1
190
+ end
191
+ end
277
192
  end
193
+ res << txt[sp...p] << "\n"
194
+ sp = p
195
+ sp += 1 while sp < ep and txt[sp] == ?\s
278
196
  end
197
+
198
+ res.join.strip
279
199
  end
280
200
 
281
- html
282
- end
201
+ ##
202
+ # Character class to be separated by a space when concatenating
203
+ # lines.
204
+
205
+ SPACE_SEPARATED_LETTER_CLASS = /[\p{Nd}\p{Lc}\p{Pc}]|[!-~&&\W]/
283
206
 
284
207
  ##
285
- # Wraps +txt+ to +line_len+
286
-
287
- def wrap(txt, line_len = 76)
288
- res = []
289
- sp = 0
290
- ep = txt.length
291
-
292
- while sp < ep
293
- # scan back for a space
294
- p = sp + line_len - 1
295
- if p >= ep
296
- p = ep
297
- else
298
- while p > sp and txt[p] != ?\s
299
- p -= 1
300
- end
301
- if p <= sp
302
- p = sp + line_len
303
- while p < ep and txt[p] != ?\s
304
- p += 1
305
- end
306
- end
307
- end
308
- res << txt[sp...p] << "\n"
309
- sp = p
310
- sp += 1 while sp < ep and txt[sp] == ?\s
311
- end
208
+ # Converts +text+ to a GitHub-style anchor ID:
209
+ # - Lowercase
210
+ # - Remove characters that aren't alphanumeric, space, or hyphen
211
+ # - Replace spaces with hyphens
212
+ #
213
+ # Examples:
214
+ # "Hello World" -> "hello-world"
215
+ # "Foo::Bar" -> "foobar"
216
+ # "What's New?" -> "whats-new"
312
217
 
313
- res.join.strip
218
+ module_function def to_anchor(text)
219
+ text.downcase.gsub(/[^a-z0-9 \-]/, '').gsub(' ', '-')
314
220
  end
315
221
 
316
222
  ##
317
- # Character class to be separated by a space when concatenating
318
- # lines.
319
-
320
- SPACE_SEPARATED_LETTER_CLASS = /[\p{Nd}\p{Lc}\p{Pc}]|[!-~&&\W]/
223
+ # Decodes a label that may be in legacy RDoc format where CGI.escape was
224
+ # applied and then '%' was replaced with '-'. Converts '+' to space,
225
+ # then reverses -XX hex encoding for non-alphanumeric characters.
226
+ #
227
+ # Labels in new format pass through unchanged because -XX patterns that
228
+ # decode to alphanumeric characters are left as-is (CGI.escape never
229
+ # encodes alphanumerics).
230
+ #
231
+ # Examples:
232
+ # "What-27s+Here" -> "What's Here" (legacy: -27 is apostrophe)
233
+ # "Foo-3A-3ABar" -> "Foo::Bar" (legacy: -3A is colon)
234
+ # "Whats-Here" -> "Whats-Here" (new format, unchanged)
235
+
236
+ module_function def decode_legacy_label(label)
237
+ label = label.tr('+', ' ')
238
+ label.gsub!(/-([0-7][0-9A-F])/) do
239
+ char = [$1.hex].pack('C')
240
+ char.match?(/[a-zA-Z0-9]/) ? $& : char
241
+ end
242
+ label
243
+ end
321
244
 
245
+ end
322
246
  end