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
@@ -0,0 +1,316 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+ require 'strscan'
5
+
6
+ module RDoc
7
+ class Markup
8
+ # Parses inline markup in RDoc text.
9
+ # This parser handles em, bold, strike, tt, hard break, and tidylink.
10
+ # Block-level constructs are handled in RDoc::Markup::Parser.
11
+
12
+ class InlineParser
13
+
14
+ # TT, BOLD_WORD, EM_WORD: regexp-handling(example: crossref) is disabled
15
+ WORD_PAIRS = {
16
+ '*' => :BOLD_WORD,
17
+ '**' => :BOLD_WORD,
18
+ '_' => :EM_WORD,
19
+ '__' => :EM_WORD,
20
+ '+' => :TT,
21
+ '++' => :TT,
22
+ '`' => :TT,
23
+ '``' => :TT
24
+ } # :nodoc:
25
+
26
+ # Other types: regexp-handling(example: crossref) is enabled
27
+ TAGS = {
28
+ 'em' => :EM,
29
+ 'i' => :EM,
30
+ 'b' => :BOLD,
31
+ 's' => :STRIKE,
32
+ 'del' => :STRIKE,
33
+ } # :nodoc:
34
+
35
+ STANDALONE_TAGS = { 'br' => :HARD_BREAK } # :nodoc:
36
+
37
+ CODEBLOCK_TAGS = %w[tt code] # :nodoc:
38
+
39
+ TOKENS = {
40
+ **WORD_PAIRS.transform_values { [:word_pair, nil] },
41
+ **TAGS.keys.to_h {|tag| ["<#{tag}>", [:open_tag, tag]] },
42
+ **TAGS.keys.to_h {|tag| ["</#{tag}>", [:close_tag, tag]] },
43
+ **CODEBLOCK_TAGS.to_h {|tag| ["<#{tag}>", [:code_start, tag]] },
44
+ **STANDALONE_TAGS.keys.to_h {|tag| ["<#{tag}>", [:standalone_tag, tag]] },
45
+ '{' => [:tidylink_start, nil],
46
+ '}' => [:tidylink_mid, nil],
47
+ '\\' => [:escape, nil],
48
+ '[' => nil # To make `label[url]` scan as separate tokens
49
+ } # :nodoc:
50
+
51
+ multi_char_tokens_regexp = Regexp.union(TOKENS.keys.select {|s| s.size > 1 }).source
52
+ token_starts_regexp = TOKENS.keys.map {|s| s[0] }.uniq.map {|s| Regexp.escape(s) }.join
53
+
54
+ SCANNER_REGEXP =
55
+ /(?:
56
+ #{multi_char_tokens_regexp}
57
+ |[^#{token_starts_regexp}\sa-zA-Z0-9\.]+ # chunk of normal text
58
+ |\s+|[a-zA-Z0-9\.]+|.
59
+ )/x # :nodoc:
60
+
61
+ # Characters that can be escaped with backslash.
62
+ ESCAPING_CHARS = '\\*_+`{}[]<>' # :nodoc:
63
+
64
+ # Pattern to match code block content until <code></tt></code> or <tt></code></tt>.
65
+ CODEBLOCK_REGEXPS = CODEBLOCK_TAGS.to_h {|name| [name, /((?:\\.|[^\\])*?)<\/#{name}>/] } # :nodoc:
66
+
67
+ # Word contains alphanumeric and <tt>_./:[]-</tt> characters.
68
+ # Word may start with <tt>#</tt> and may end with any non-space character. (e.g. <tt>#eql?</tt>).
69
+ # Underscore delimiter have special rules.
70
+ WORD_REGEXPS = {
71
+ # Words including _, longest match.
72
+ # Example: `_::A_` `_-42_` `_A::B::C.foo_bar[baz]_` `_kwarg:_`
73
+ # Content must not include _ followed by non-alphanumeric character
74
+ # Example: `_host_:_port_` will be `_host_` + `:` + `_port_`
75
+ '_' => /#?([a-zA-Z0-9.\/:\[\]-]|_+[a-zA-Z0-9])+[^\s]?_(?=[^a-zA-Z0-9_]|\z)/,
76
+ # Words allowing _ but not allowing __
77
+ '__' => /#?[a-zA-Z0-9.\/:\[\]-]*(_[a-zA-Z0-9.\/:\[\]-]+)*[^\s]?__(?=[^a-zA-Z0-9]|\z)/,
78
+ **%w[* ** + ++ ` ``].to_h do |s|
79
+ # normal words that can be used within +word+ or *word*
80
+ [s, /#?[a-zA-Z0-9_.\/:\[\]-]+[^\s]?#{Regexp.escape(s)}(?=[^a-zA-Z0-9]|\z)/]
81
+ end
82
+ } # :nodoc:
83
+
84
+ def initialize(string)
85
+ @scanner = StringScanner.new(string)
86
+ @last_match = nil
87
+ @scanner_negative_cache = Set.new
88
+ @stack = []
89
+ @delimiters = {}
90
+ end
91
+
92
+ # Return the current parsing node on <tt>@stack</tt>.
93
+
94
+ def current
95
+ @stack.last
96
+ end
97
+
98
+ # Parse and return an array of nodes.
99
+ # Node format:
100
+ # {
101
+ # type: :EM | :BOLD | :BOLD_WORD | :EM_WORD | :TT | :STRIKE | :HARD_BREAK | :TIDYLINK,
102
+ # url: string # only for :TIDYLINK
103
+ # children: [string_or_node, ...]
104
+ # }
105
+
106
+ def parse
107
+ stack_push(:root, nil)
108
+ while true
109
+ type, token, value = scan_token
110
+ close = nil
111
+ tidylink_url = nil
112
+ case type
113
+ when :node
114
+ current[:children] << value
115
+ invalidate_open_tidylinks if value[:type] == :TIDYLINK
116
+ when :eof
117
+ close = :root
118
+ when :tidylink_open
119
+ stack_push(:tidylink, token)
120
+ when :tidylink_close
121
+ close = :tidylink
122
+ if value
123
+ tidylink_url = value
124
+ else
125
+ # Tidylink closing brace without URL part. Treat opening and closing braces as normal text
126
+ # `{labelnodes}...` case.
127
+ current[:children] << token
128
+ end
129
+ when :invalidated_tidylink_close
130
+ # `{...{label}[url]...}` case. Nested tidylink invalidates outer one. The last `}` closes the invalidated tidylink.
131
+ current[:children] << token
132
+ close = :invalidated_tidylink
133
+ when :text
134
+ current[:children] << token
135
+ when :open
136
+ stack_push(value, token)
137
+ when :close
138
+ if @delimiters[value]
139
+ close = value
140
+ else
141
+ # closing tag without matching opening tag. Treat as normal text.
142
+ current[:children] << token
143
+ end
144
+ end
145
+
146
+ next unless close
147
+
148
+ while current[:delimiter] != close
149
+ children = current[:children]
150
+ open_token = current[:token]
151
+ stack_pop
152
+ current[:children] << open_token if open_token
153
+ current[:children].concat(children)
154
+ end
155
+
156
+ token = current[:token]
157
+ children = compact_string(current[:children])
158
+ stack_pop
159
+
160
+ return children if close == :root
161
+
162
+ if close == :tidylink || close == :invalidated_tidylink
163
+ if tidylink_url
164
+ current[:children] << { type: :TIDYLINK, children: children, url: tidylink_url }
165
+ invalidate_open_tidylinks
166
+ else
167
+ current[:children] << token
168
+ current[:children].concat(children)
169
+ end
170
+ else
171
+ current[:children] << { type: TAGS[close], children: children }
172
+ end
173
+ end
174
+ end
175
+
176
+ private
177
+
178
+ # When a valid tidylink node is encountered, invalidate all nested tidylinks.
179
+
180
+ def invalidate_open_tidylinks
181
+ return unless @delimiters[:tidylink]
182
+
183
+ @delimiters[:invalidated_tidylink] ||= []
184
+ @delimiters[:tidylink].each do |idx|
185
+ @delimiters[:invalidated_tidylink] << idx
186
+ @stack[idx][:delimiter] = :invalidated_tidylink
187
+ end
188
+ @delimiters.delete(:tidylink)
189
+ end
190
+
191
+ # Pop the top node off the stack when node is closed by a closing delimiter or an error.
192
+
193
+ def stack_pop
194
+ delimiter = current[:delimiter]
195
+ @delimiters[delimiter].pop
196
+ @delimiters.delete(delimiter) if @delimiters[delimiter].empty?
197
+ @stack.pop
198
+ end
199
+
200
+ # Push a new node onto the stack when encountering an opening delimiter.
201
+
202
+ def stack_push(delimiter, token)
203
+ node = { delimiter: delimiter, token: token, children: [] }
204
+ (@delimiters[delimiter] ||= []) << @stack.size
205
+ @stack << node
206
+ end
207
+
208
+ # Compacts adjacent strings in +nodes+ into a single string.
209
+
210
+ def compact_string(nodes)
211
+ nodes.chunk {|e| String === e }.flat_map do |is_str, elems|
212
+ is_str ? elems.join : elems
213
+ end
214
+ end
215
+
216
+ # Scan from StringScanner with +pattern+
217
+ # If +negative_cache+ is true, caches scan failure result. <tt>scan(pattern, negative_cache: true)</tt> return nil when it is called again after a failure.
218
+ # Be careful to use +negative_cache+ with a pattern and position that does not match after previous failure.
219
+
220
+ def strscan(pattern, negative_cache: false)
221
+ return if negative_cache && @scanner_negative_cache.include?(pattern)
222
+
223
+ string = @scanner.scan(pattern)
224
+ @last_match = string if string
225
+ @scanner_negative_cache << pattern if !string && negative_cache
226
+ string
227
+ end
228
+
229
+ # Scan and return the next token for parsing.
230
+ # Returns <tt>[token_type, token_string_or_nil, extra_info]</tt>
231
+
232
+ def scan_token
233
+ last_match = @last_match
234
+ token = strscan(SCANNER_REGEXP)
235
+ type, name = TOKENS[token]
236
+
237
+ case type
238
+ when :word_pair
239
+ # If the character before word pair delimiter is alphanumeric, do not treat as word pair.
240
+ word_pair = strscan(WORD_REGEXPS[token]) unless /[a-zA-Z0-9]\z/.match?(last_match)
241
+
242
+ if word_pair.nil?
243
+ [:text, token, nil]
244
+ elsif token == '__' && word_pair.match?(/\A[a-zA-Z]+__\z/)
245
+ # Special exception: __FILE__, __LINE__, __send__ should be treated as normal text.
246
+ [:text, "#{token}#{word_pair}", nil]
247
+ else
248
+ [:node, nil, { type: WORD_PAIRS[token], children: [word_pair.delete_suffix(token)] }]
249
+ end
250
+ when :open_tag
251
+ [:open, token, name]
252
+ when :close_tag
253
+ [:close, token, name]
254
+ when :code_start
255
+ if (codeblock = strscan(CODEBLOCK_REGEXPS[name], negative_cache: true))
256
+ # Need to unescape `\\` and `\<`.
257
+ # RDoc also unescapes backslash + word separators, but this is not really necessary.
258
+ content = codeblock.delete_suffix("</#{name}>").gsub(/\\(.)/) { '\\<*+_`'.include?($1) ? $1 : $& }
259
+ [:node, nil, { type: :TT, children: content.empty? ? [] : [content] }]
260
+ else
261
+ [:text, token, nil]
262
+ end
263
+ when :standalone_tag
264
+ [:node, nil, { type: STANDALONE_TAGS[name], children: [] }]
265
+ when :tidylink_start
266
+ [:tidylink_open, token, nil]
267
+ when :tidylink_mid
268
+ if @delimiters[:tidylink]
269
+ if (url = read_tidylink_url)
270
+ [:tidylink_close, nil, url]
271
+ else
272
+ [:tidylink_close, token, nil]
273
+ end
274
+ elsif @delimiters[:invalidated_tidylink]
275
+ [:invalidated_tidylink_close, token, nil]
276
+ else
277
+ [:text, token, nil]
278
+ end
279
+ when :escape
280
+ next_char = strscan(/./)
281
+ if next_char.nil?
282
+ # backslash at end of string
283
+ [:text, '\\', nil]
284
+ elsif next_char && ESCAPING_CHARS.include?(next_char)
285
+ # escaped character
286
+ [:text, next_char, nil]
287
+ else
288
+ # If next_char not an escaping character, it is treated as text token with backslash + next_char
289
+ # For example, backslash of `\Ruby` (suppressed crossref) remains.
290
+ [:text, "\\#{next_char}", nil]
291
+ end
292
+ else
293
+ if token.nil?
294
+ [:eof, nil, nil]
295
+ elsif token.match?(/\A[A-Za-z0-9]*\z/) && (url = read_tidylink_url)
296
+ # Simplified tidylink: label[url]
297
+ [:node, nil, { type: :TIDYLINK, children: [token], url: url }]
298
+ else
299
+ [:text, token, nil]
300
+ end
301
+ end
302
+ end
303
+
304
+ # Read the URL part of a tidylink from the current position.
305
+ # Returns nil if no valid URL part is found.
306
+ # URL part is enclosed in square brackets and may contain escaped brackets.
307
+ # Example: <tt>[http://example.com/?q=\[\]]</tt> represents <tt>http://example.com/?q=[]</tt>.
308
+ # If we're accepting rdoc-style links in markdown, url may include <tt>*+<_</tt> with backslash escape.
309
+
310
+ def read_tidylink_url
311
+ bracketed_url = strscan(/\[([^\s\[\]\\]|\\[\[\]\\*+<_])+\]/)
312
+ bracketed_url[1...-1].gsub(/\\(.)/, '\1') if bracketed_url
313
+ end
314
+ end
315
+ end
316
+ end
@@ -1,101 +1,93 @@
1
1
  # frozen_string_literal: true
2
- ##
3
- # A List is a homogeneous set of ListItems.
4
- #
5
- # The supported list types include:
6
- #
7
- # :BULLET::
8
- # An unordered list
9
- # :LABEL::
10
- # An unordered definition list, but using an alternate RDoc::Markup syntax
11
- # :LALPHA::
12
- # An ordered list using increasing lowercase English letters
13
- # :NOTE::
14
- # An unordered definition list
15
- # :NUMBER::
16
- # An ordered list using increasing Arabic numerals
17
- # :UALPHA::
18
- # An ordered list using increasing uppercase English letters
19
- #
20
- # Definition lists behave like HTML definition lists. Each list item can
21
- # describe multiple terms. See RDoc::Markup::ListItem for how labels and
22
- # definition are stored as list items.
23
2
 
24
- class RDoc::Markup::List
25
-
26
- ##
27
- # The list's type
28
-
29
- attr_accessor :type
30
-
31
- ##
32
- # Items in the list
33
-
34
- attr_reader :items
35
-
36
- ##
37
- # Creates a new list of +type+ with +items+. Valid list types are:
38
- # +:BULLET+, +:LABEL+, +:LALPHA+, +:NOTE+, +:NUMBER+, +:UALPHA+
39
-
40
- def initialize type = nil, *items
41
- @type = type
42
- @items = []
43
- @items.concat items
44
- end
45
-
46
- ##
47
- # Appends +item+ to the list
48
-
49
- def <<(item)
50
- @items << item
51
- end
52
-
53
- def ==(other) # :nodoc:
54
- self.class == other.class and
55
- @type == other.type and
56
- @items == other.items
57
- end
58
-
59
- ##
60
- # Runs this list and all its #items through +visitor+
61
-
62
- def accept(visitor)
63
- visitor.accept_list_start self
3
+ module RDoc
4
+ class Markup
5
+ # A List is a homogeneous set of ListItems.
6
+ #
7
+ # The supported list types include:
8
+ #
9
+ # :BULLET::
10
+ # An unordered list
11
+ # :LABEL::
12
+ # An unordered definition list, but using an alternate RDoc::Markup syntax
13
+ # :LALPHA::
14
+ # An ordered list using increasing lowercase English letters
15
+ # :NOTE::
16
+ # An unordered definition list
17
+ # :NUMBER::
18
+ # An ordered list using increasing Arabic numerals
19
+ # :UALPHA::
20
+ # An ordered list using increasing uppercase English letters
21
+ #
22
+ # Definition lists behave like HTML definition lists. Each list item can
23
+ # describe multiple terms. See RDoc::Markup::ListItem for how labels and
24
+ # definitions are stored as list items.
25
+ class List < Element
26
+ # The list's type
27
+ #: Symbol?
28
+ attr_accessor :type
29
+
30
+ # Items in the list
31
+ #: Array[ListItem]
32
+ attr_reader :items
33
+
34
+ # Creates a new list of +type+ with +items+. Valid list types are:
35
+ # +:BULLET+, +:LABEL+, +:LALPHA+, +:NOTE+, +:NUMBER+, +:UALPHA+
36
+ #: (Symbol?, *ListItem) -> void
37
+ def initialize(type = nil, *items)
38
+ @type = type
39
+ @items = items
40
+ end
64
41
 
65
- @items.each do |item|
66
- item.accept visitor
67
- end
42
+ # Appends +item+ to the list
43
+ #: (ListItem) -> void
44
+ def <<(item)
45
+ @items << item
46
+ end
68
47
 
69
- visitor.accept_list_end self
70
- end
48
+ #: (top) -> bool
49
+ def ==(other) # :nodoc:
50
+ self.class == other.class &&
51
+ @type == other.type &&
52
+ @items == other.items
53
+ end
71
54
 
72
- ##
73
- # Is the list empty?
55
+ # Runs this list and all its #items through +visitor+
56
+ # @override
57
+ #: (untyped) -> void
58
+ def accept(visitor)
59
+ visitor.accept_list_start(self)
60
+ @items.each { |item| item.accept(visitor) }
61
+ visitor.accept_list_end(self)
62
+ end
74
63
 
75
- def empty?
76
- @items.empty?
77
- end
64
+ # Is the list empty?
65
+ #: () -> bool
66
+ def empty?
67
+ @items.empty?
68
+ end
78
69
 
79
- ##
80
- # Returns the last item in the list
70
+ # Returns the last item in the list
71
+ #: () -> ListItem?
72
+ def last
73
+ @items.last
74
+ end
81
75
 
82
- def last
83
- @items.last
84
- end
76
+ # @override
77
+ #: (PP) -> void
78
+ def pretty_print(q) # :nodoc:
79
+ q.group(2, "[list: #{@type} ", ']') do
80
+ q.seplist(@items) do |item|
81
+ q.pp(item)
82
+ end
83
+ end
84
+ end
85
85
 
86
- def pretty_print(q) # :nodoc:
87
- q.group 2, "[list: #{@type} ", ']' do
88
- q.seplist @items do |item|
89
- q.pp item
86
+ # Appends +items+ to the list
87
+ #: (*ListItem) -> void
88
+ def push(*items)
89
+ @items.concat(items)
90
90
  end
91
91
  end
92
92
  end
93
-
94
- ##
95
- # Appends +items+ to the list
96
-
97
- def push *items
98
- @items.concat items
99
- end
100
-
101
93
  end
@@ -1,99 +1,87 @@
1
1
  # frozen_string_literal: true
2
- ##
3
- # An item within a List that contains paragraphs, headings, etc.
4
- #
5
- # For BULLET, NUMBER, LALPHA and UALPHA lists, the label will always be nil.
6
- # For NOTE and LABEL lists, the list label may contain:
7
- #
8
- # * a single String for a single label
9
- # * an Array of Strings for a list item with multiple terms
10
- # * nil for an extra description attached to a previously labeled list item
11
2
 
12
- class RDoc::Markup::ListItem
13
-
14
- ##
15
- # The label for the ListItem
16
-
17
- attr_accessor :label
18
-
19
- ##
20
- # Parts of the ListItem
21
-
22
- attr_reader :parts
23
-
24
- ##
25
- # Creates a new ListItem with an optional +label+ containing +parts+
26
-
27
- def initialize label = nil, *parts
28
- @label = label
29
- @parts = []
30
- @parts.concat parts
31
- end
32
-
33
- ##
34
- # Appends +part+ to the ListItem
35
-
36
- def <<(part)
37
- @parts << part
38
- end
39
-
40
- def ==(other) # :nodoc:
41
- self.class == other.class and
42
- @label == other.label and
43
- @parts == other.parts
44
- end
45
-
46
- ##
47
- # Runs this list item and all its #parts through +visitor+
48
-
49
- def accept(visitor)
50
- visitor.accept_list_item_start self
51
-
52
- @parts.each do |part|
53
- part.accept visitor
54
- end
3
+ module RDoc
4
+ class Markup
5
+ # An item within a List that contains paragraphs, headings, etc.
6
+ #
7
+ # For BULLET, NUMBER, LALPHA and UALPHA lists, the label will always be nil.
8
+ # For NOTE and LABEL lists, the list label may contain:
9
+ #
10
+ # * a single String for a single label
11
+ # * an Array of Strings for a list item with multiple terms
12
+ # * nil for an extra description attached to a previously labeled list item
13
+ class ListItem < Element
14
+ # The label for the ListItem
15
+ #: (Array[String] | String)?
16
+ attr_accessor :label
17
+
18
+ # Parts of the ListItem
19
+ #: Array[untyped]
20
+ attr_reader :parts
21
+
22
+ # Creates a new ListItem with an optional +label+ containing +parts+
23
+ #: ((Array[String] | String)?, *untyped) -> void
24
+ def initialize(label = nil, *parts)
25
+ @label = label
26
+ @parts = parts
27
+ end
55
28
 
56
- visitor.accept_list_item_end self
57
- end
29
+ # Appends +part+ to the ListItem
30
+ #: (untyped) -> void
31
+ def <<(part)
32
+ @parts << part
33
+ end
58
34
 
59
- ##
60
- # Is the ListItem empty?
35
+ #: (top) -> bool
36
+ def ==(other) # :nodoc:
37
+ self.class == other.class &&
38
+ @label == other.label &&
39
+ @parts == other.parts
40
+ end
61
41
 
62
- def empty?
63
- @parts.empty?
64
- end
42
+ # Runs this list item and all its #parts through +visitor+
43
+ # @override
44
+ #: (untyped) -> void
45
+ def accept(visitor)
46
+ visitor.accept_list_item_start(self)
47
+ @parts.each { |part| part.accept(visitor) }
48
+ visitor.accept_list_item_end(self)
49
+ end
65
50
 
66
- ##
67
- # Length of parts in the ListItem
51
+ # Is the ListItem empty?
52
+ #: () -> bool
53
+ def empty?
54
+ @parts.empty?
55
+ end
68
56
 
69
- def length
70
- @parts.length
71
- end
57
+ # Length of parts in the ListItem
58
+ #: () -> Integer
59
+ def length
60
+ @parts.length
61
+ end
72
62
 
73
- def pretty_print(q) # :nodoc:
74
- q.group 2, '[item: ', ']' do
75
- case @label
76
- when Array then
77
- q.pp @label
78
- q.text ';'
79
- q.breakable
80
- when String then
81
- q.pp @label
82
- q.text ';'
83
- q.breakable
63
+ # @override
64
+ #: (PP) -> void
65
+ def pretty_print(q) # :nodoc:
66
+ q.group(2, '[item: ', ']') do
67
+ case @label
68
+ when Array, String
69
+ q.pp(@label)
70
+ q.text(';')
71
+ q.breakable
72
+ end
73
+
74
+ q.seplist(@parts) do |part|
75
+ q.pp(part)
76
+ end
77
+ end
84
78
  end
85
79
 
86
- q.seplist @parts do |part|
87
- q.pp part
80
+ # Adds +parts+ to the ListItem
81
+ #: (*untyped) -> void
82
+ def push(*parts)
83
+ @parts.concat(parts)
88
84
  end
89
85
  end
90
86
  end
91
-
92
- ##
93
- # Adds +parts+ to the ListItem
94
-
95
- def push *parts
96
- @parts.concat parts
97
- end
98
-
99
87
  end