rdoc 8.0.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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +1 -3
  3. data/RI.md +75 -75
  4. data/exe/rdoc +2 -2
  5. data/lib/rdoc/code_object/alias.rb +71 -69
  6. data/lib/rdoc/code_object/any_method.rb +305 -303
  7. data/lib/rdoc/code_object/attr.rb +150 -148
  8. data/lib/rdoc/code_object/class_module.rb +798 -792
  9. data/lib/rdoc/code_object/constant.rb +175 -173
  10. data/lib/rdoc/code_object/context/section.rb +142 -138
  11. data/lib/rdoc/code_object/context.rb +926 -958
  12. data/lib/rdoc/code_object/extend.rb +7 -5
  13. data/lib/rdoc/code_object/include.rb +7 -5
  14. data/lib/rdoc/code_object/method_attr.rb +326 -319
  15. data/lib/rdoc/code_object/mixin.rb +97 -95
  16. data/lib/rdoc/code_object/normal_class.rb +77 -78
  17. data/lib/rdoc/code_object/normal_module.rb +61 -59
  18. data/lib/rdoc/code_object/require.rb +23 -39
  19. data/lib/rdoc/code_object/single_class.rb +21 -19
  20. data/lib/rdoc/code_object/top_level.rb +212 -219
  21. data/lib/rdoc/code_object.rb +305 -303
  22. data/lib/rdoc/comment.rb +275 -273
  23. data/lib/rdoc/cross_reference.rb +192 -190
  24. data/lib/rdoc/encoding.rb +105 -103
  25. data/lib/rdoc/erb_partial.rb +13 -11
  26. data/lib/rdoc/erbio.rb +29 -27
  27. data/lib/rdoc/generator/aliki.rb +161 -153
  28. data/lib/rdoc/generator/darkfish.rb +645 -635
  29. data/lib/rdoc/generator/json_index.rb +233 -229
  30. data/lib/rdoc/generator/markup.rb +164 -146
  31. data/lib/rdoc/generator/pot/message_extractor.rb +57 -51
  32. data/lib/rdoc/generator/pot/po.rb +52 -51
  33. data/lib/rdoc/generator/pot/po_entry.rb +138 -132
  34. data/lib/rdoc/generator/pot.rb +85 -81
  35. data/lib/rdoc/generator/ri.rb +23 -19
  36. data/lib/rdoc/generator/template/aliki/DESIGN.md +6 -4
  37. data/lib/rdoc/generator/template/aliki/_footer.rhtml +1 -1
  38. data/lib/rdoc/generator/template/aliki/_head.rhtml +10 -10
  39. data/lib/rdoc/generator/template/aliki/_header.rhtml +29 -44
  40. data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +4 -4
  41. data/lib/rdoc/generator/template/aliki/css/rdoc.css +207 -178
  42. data/lib/rdoc/generator/template/aliki/js/aliki.js +60 -84
  43. data/lib/rdoc/generator/template/darkfish/_footer.rhtml +1 -1
  44. data/lib/rdoc/generator.rb +48 -46
  45. data/lib/rdoc/i18n/locale.rb +99 -95
  46. data/lib/rdoc/i18n/text.rb +109 -105
  47. data/lib/rdoc/i18n.rb +7 -5
  48. data/lib/rdoc/markdown/byte_runtime.rb +80 -0
  49. data/lib/rdoc/markdown.kpeg +15 -11
  50. data/lib/rdoc/markdown.rb +40 -47
  51. data/lib/rdoc/markup/block_quote.rb +12 -8
  52. data/lib/rdoc/markup/document.rb +127 -123
  53. data/lib/rdoc/markup/formatter.rb +219 -215
  54. data/lib/rdoc/markup/include.rb +33 -29
  55. data/lib/rdoc/markup/indented_paragraph.rb +37 -33
  56. data/lib/rdoc/markup/inline_parser.rb +281 -277
  57. data/lib/rdoc/markup/list.rb +80 -88
  58. data/lib/rdoc/markup/list_item.rb +73 -85
  59. data/lib/rdoc/markup/paragraph.rb +23 -19
  60. data/lib/rdoc/markup/parser.rb +501 -497
  61. data/lib/rdoc/markup/pre_process.rb +283 -279
  62. data/lib/rdoc/markup/raw.rb +2 -2
  63. data/lib/rdoc/markup/rule.rb +16 -12
  64. data/lib/rdoc/markup/to_ansi.rb +143 -139
  65. data/lib/rdoc/markup/to_bs.rb +72 -68
  66. data/lib/rdoc/markup/to_html.rb +594 -565
  67. data/lib/rdoc/markup/to_html_crossref.rb +234 -230
  68. data/lib/rdoc/markup/to_html_snippet.rb +232 -227
  69. data/lib/rdoc/markup/to_joined_paragraph.rb +36 -32
  70. data/lib/rdoc/markup/to_label.rb +63 -59
  71. data/lib/rdoc/markup/to_markdown.rb +212 -208
  72. data/lib/rdoc/markup/to_rdoc.rb +336 -332
  73. data/lib/rdoc/markup/to_table_of_contents.rb +66 -62
  74. data/lib/rdoc/markup/to_test.rb +60 -56
  75. data/lib/rdoc/markup/to_tt_only.rb +84 -80
  76. data/lib/rdoc/markup/verbatim.rb +62 -58
  77. data/lib/rdoc/markup.rb +198 -196
  78. data/lib/rdoc/options.rb +1063 -1061
  79. data/lib/rdoc/parser/c.rb +1039 -1037
  80. data/lib/rdoc/parser/changelog.rb +319 -315
  81. data/lib/rdoc/parser/markdown.rb +17 -13
  82. data/lib/rdoc/parser/rbs.rb +239 -235
  83. data/lib/rdoc/parser/rd.rb +17 -13
  84. data/lib/rdoc/parser/ruby.rb +1245 -1124
  85. data/lib/rdoc/parser/ruby_colorizer.rb +263 -213
  86. data/lib/rdoc/parser/simple.rb +31 -27
  87. data/lib/rdoc/parser/text.rb +12 -8
  88. data/lib/rdoc/parser.rb +228 -220
  89. data/lib/rdoc/rbs_helper.rb +1 -1
  90. data/lib/rdoc/rd/inline.rb +57 -53
  91. data/lib/rdoc/rd.rb +90 -88
  92. data/lib/rdoc/rdoc.rb +500 -491
  93. data/lib/rdoc/ri/driver.rb +1140 -1135
  94. data/lib/rdoc/ri/formatter.rb +7 -3
  95. data/lib/rdoc/ri/paths.rb +140 -136
  96. data/lib/rdoc/ri/servlet.rb +354 -350
  97. data/lib/rdoc/ri/store.rb +4 -2
  98. data/lib/rdoc/ri/task.rb +55 -51
  99. data/lib/rdoc/ri.rb +14 -12
  100. data/lib/rdoc/rubygems_hook.rb +183 -181
  101. data/lib/rdoc/server.rb +349 -347
  102. data/lib/rdoc/stats/normal.rb +46 -42
  103. data/lib/rdoc/stats/quiet.rb +39 -35
  104. data/lib/rdoc/stats/verbose.rb +35 -31
  105. data/lib/rdoc/stats.rb +365 -363
  106. data/lib/rdoc/store.rb +888 -902
  107. data/lib/rdoc/task.rb +260 -256
  108. data/lib/rdoc/text.rb +135 -133
  109. data/lib/rdoc/token_stream.rb +101 -93
  110. data/lib/rdoc/tom_doc.rb +203 -201
  111. data/lib/rdoc/version.rb +1 -1
  112. metadata +4 -5
  113. data/lib/rdoc/markdown/literals.kpeg +0 -21
  114. data/lib/rdoc/markdown/literals.rb +0 -454
@@ -3,310 +3,314 @@
3
3
  require 'set'
4
4
  require 'strscan'
5
5
 
6
- # Parses inline markup in RDoc text.
7
- # This parser handles em, bold, strike, tt, hard break, and tidylink.
8
- # Block-level constructs are handled in RDoc::Markup::Parser.
9
-
10
- class RDoc::Markup::InlineParser
11
-
12
- # TT, BOLD_WORD, EM_WORD: regexp-handling(example: crossref) is disabled
13
- WORD_PAIRS = {
14
- '*' => :BOLD_WORD,
15
- '**' => :BOLD_WORD,
16
- '_' => :EM_WORD,
17
- '__' => :EM_WORD,
18
- '+' => :TT,
19
- '++' => :TT,
20
- '`' => :TT,
21
- '``' => :TT
22
- } # :nodoc:
23
-
24
- # Other types: regexp-handling(example: crossref) is enabled
25
- TAGS = {
26
- 'em' => :EM,
27
- 'i' => :EM,
28
- 'b' => :BOLD,
29
- 's' => :STRIKE,
30
- 'del' => :STRIKE,
31
- } # :nodoc:
32
-
33
- STANDALONE_TAGS = { 'br' => :HARD_BREAK } # :nodoc:
34
-
35
- CODEBLOCK_TAGS = %w[tt code] # :nodoc:
36
-
37
- TOKENS = {
38
- **WORD_PAIRS.transform_values { [:word_pair, nil] },
39
- **TAGS.keys.to_h {|tag| ["<#{tag}>", [:open_tag, tag]] },
40
- **TAGS.keys.to_h {|tag| ["</#{tag}>", [:close_tag, tag]] },
41
- **CODEBLOCK_TAGS.to_h {|tag| ["<#{tag}>", [:code_start, tag]] },
42
- **STANDALONE_TAGS.keys.to_h {|tag| ["<#{tag}>", [:standalone_tag, tag]] },
43
- '{' => [:tidylink_start, nil],
44
- '}' => [:tidylink_mid, nil],
45
- '\\' => [:escape, nil],
46
- '[' => nil # To make `label[url]` scan as separate tokens
47
- } # :nodoc:
48
-
49
- multi_char_tokens_regexp = Regexp.union(TOKENS.keys.select {|s| s.size > 1 }).source
50
- token_starts_regexp = TOKENS.keys.map {|s| s[0] }.uniq.map {|s| Regexp.escape(s) }.join
51
-
52
- SCANNER_REGEXP =
53
- /(?:
54
- #{multi_char_tokens_regexp}
55
- |[^#{token_starts_regexp}\sa-zA-Z0-9\.]+ # chunk of normal text
56
- |\s+|[a-zA-Z0-9\.]+|.
57
- )/x # :nodoc:
58
-
59
- # Characters that can be escaped with backslash.
60
- ESCAPING_CHARS = '\\*_+`{}[]<>' # :nodoc:
61
-
62
- # Pattern to match code block content until <code></tt></code> or <tt></code></tt>.
63
- CODEBLOCK_REGEXPS = CODEBLOCK_TAGS.to_h {|name| [name, /((?:\\.|[^\\])*?)<\/#{name}>/] } # :nodoc:
64
-
65
- # Word contains alphanumeric and <tt>_./:[]-</tt> characters.
66
- # Word may start with <tt>#</tt> and may end with any non-space character. (e.g. <tt>#eql?</tt>).
67
- # Underscore delimiter have special rules.
68
- WORD_REGEXPS = {
69
- # Words including _, longest match.
70
- # Example: `_::A_` `_-42_` `_A::B::C.foo_bar[baz]_` `_kwarg:_`
71
- # Content must not include _ followed by non-alphanumeric character
72
- # Example: `_host_:_port_` will be `_host_` + `:` + `_port_`
73
- '_' => /#?([a-zA-Z0-9.\/:\[\]-]|_+[a-zA-Z0-9])+[^\s]?_(?=[^a-zA-Z0-9_]|\z)/,
74
- # Words allowing _ but not allowing __
75
- '__' => /#?[a-zA-Z0-9.\/:\[\]-]*(_[a-zA-Z0-9.\/:\[\]-]+)*[^\s]?__(?=[^a-zA-Z0-9]|\z)/,
76
- **%w[* ** + ++ ` ``].to_h do |s|
77
- # normal words that can be used within +word+ or *word*
78
- [s, /#?[a-zA-Z0-9_.\/:\[\]-]+[^\s]?#{Regexp.escape(s)}(?=[^a-zA-Z0-9]|\z)/]
79
- end
80
- } # :nodoc:
81
-
82
- def initialize(string)
83
- @scanner = StringScanner.new(string)
84
- @last_match = nil
85
- @scanner_negative_cache = Set.new
86
- @stack = []
87
- @delimiters = {}
88
- end
89
-
90
- # Return the current parsing node on <tt>@stack</tt>.
91
-
92
- def current
93
- @stack.last
94
- end
95
-
96
- # Parse and return an array of nodes.
97
- # Node format:
98
- # {
99
- # type: :EM | :BOLD | :BOLD_WORD | :EM_WORD | :TT | :STRIKE | :HARD_BREAK | :TIDYLINK,
100
- # url: string # only for :TIDYLINK
101
- # children: [string_or_node, ...]
102
- # }
103
-
104
- def parse
105
- stack_push(:root, nil)
106
- while true
107
- type, token, value = scan_token
108
- close = nil
109
- tidylink_url = nil
110
- case type
111
- when :node
112
- current[:children] << value
113
- invalidate_open_tidylinks if value[:type] == :TIDYLINK
114
- when :eof
115
- close = :root
116
- when :tidylink_open
117
- stack_push(:tidylink, token)
118
- when :tidylink_close
119
- close = :tidylink
120
- if value
121
- tidylink_url = value
122
- else
123
- # Tidylink closing brace without URL part. Treat opening and closing braces as normal text
124
- # `{labelnodes}...` case.
125
- current[:children] << token
126
- end
127
- when :invalidated_tidylink_close
128
- # `{...{label}[url]...}` case. Nested tidylink invalidates outer one. The last `}` closes the invalidated tidylink.
129
- current[:children] << token
130
- close = :invalidated_tidylink
131
- when :text
132
- current[:children] << token
133
- when :open
134
- stack_push(value, token)
135
- when :close
136
- if @delimiters[value]
137
- close = value
138
- else
139
- # closing tag without matching opening tag. Treat as normal text.
140
- current[:children] << token
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)/]
141
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 = {}
142
90
  end
143
91
 
144
- next unless close
92
+ # Return the current parsing node on <tt>@stack</tt>.
145
93
 
146
- while current[:delimiter] != close
147
- children = current[:children]
148
- open_token = current[:token]
149
- stack_pop
150
- current[:children] << open_token if open_token
151
- current[:children].concat(children)
94
+ def current
95
+ @stack.last
152
96
  end
153
97
 
154
- token = current[:token]
155
- children = compact_string(current[:children])
156
- stack_pop
157
-
158
- return children if close == :root
159
-
160
- if close == :tidylink || close == :invalidated_tidylink
161
- if tidylink_url
162
- current[:children] << { type: :TIDYLINK, children: children, url: tidylink_url }
163
- invalidate_open_tidylinks
164
- else
165
- current[:children] << token
166
- current[:children].concat(children)
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
167
173
  end
168
- else
169
- current[:children] << { type: TAGS[close], children: children }
170
174
  end
171
- end
172
- end
173
175
 
174
176
  private
175
177
 
176
- # When a valid tidylink node is encountered, invalidate all nested tidylinks.
178
+ # When a valid tidylink node is encountered, invalidate all nested tidylinks.
177
179
 
178
- def invalidate_open_tidylinks
179
- return unless @delimiters[:tidylink]
180
+ def invalidate_open_tidylinks
181
+ return unless @delimiters[:tidylink]
180
182
 
181
- @delimiters[:invalidated_tidylink] ||= []
182
- @delimiters[:tidylink].each do |idx|
183
- @delimiters[:invalidated_tidylink] << idx
184
- @stack[idx][:delimiter] = :invalidated_tidylink
185
- end
186
- @delimiters.delete(:tidylink)
187
- end
188
-
189
- # Pop the top node off the stack when node is closed by a closing delimiter or an error.
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
190
 
191
- def stack_pop
192
- delimiter = current[:delimiter]
193
- @delimiters[delimiter].pop
194
- @delimiters.delete(delimiter) if @delimiters[delimiter].empty?
195
- @stack.pop
196
- end
191
+ # Pop the top node off the stack when node is closed by a closing delimiter or an error.
197
192
 
198
- # Push a new node onto the stack when encountering an opening delimiter.
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
199
 
200
- def stack_push(delimiter, token)
201
- node = { delimiter: delimiter, token: token, children: [] }
202
- (@delimiters[delimiter] ||= []) << @stack.size
203
- @stack << node
204
- end
200
+ # Push a new node onto the stack when encountering an opening delimiter.
205
201
 
206
- # Compacts adjacent strings in +nodes+ into a single string.
202
+ def stack_push(delimiter, token)
203
+ node = { delimiter: delimiter, token: token, children: [] }
204
+ (@delimiters[delimiter] ||= []) << @stack.size
205
+ @stack << node
206
+ end
207
207
 
208
- def compact_string(nodes)
209
- nodes.chunk {|e| String === e }.flat_map do |is_str, elems|
210
- is_str ? elems.join : elems
211
- end
212
- end
208
+ # Compacts adjacent strings in +nodes+ into a single string.
213
209
 
214
- # Scan from StringScanner with +pattern+
215
- # 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.
216
- # Be careful to use +negative_cache+ with a pattern and position that does not match after previous failure.
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
217
215
 
218
- def strscan(pattern, negative_cache: false)
219
- return if negative_cache && @scanner_negative_cache.include?(pattern)
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.
220
219
 
221
- string = @scanner.scan(pattern)
222
- @last_match = string if string
223
- @scanner_negative_cache << pattern if !string && negative_cache
224
- string
225
- end
220
+ def strscan(pattern, negative_cache: false)
221
+ return if negative_cache && @scanner_negative_cache.include?(pattern)
226
222
 
227
- # Scan and return the next token for parsing.
228
- # Returns <tt>[token_type, token_string_or_nil, extra_info]</tt>
229
-
230
- def scan_token
231
- last_match = @last_match
232
- token = strscan(SCANNER_REGEXP)
233
- type, name = TOKENS[token]
234
-
235
- case type
236
- when :word_pair
237
- # If the character before word pair delimiter is alphanumeric, do not treat as word pair.
238
- word_pair = strscan(WORD_REGEXPS[token]) unless /[a-zA-Z0-9]\z/.match?(last_match)
239
-
240
- if word_pair.nil?
241
- [:text, token, nil]
242
- elsif token == '__' && word_pair.match?(/\A[a-zA-Z]+__\z/)
243
- # Special exception: __FILE__, __LINE__, __send__ should be treated as normal text.
244
- [:text, "#{token}#{word_pair}", nil]
245
- else
246
- [:node, nil, { type: WORD_PAIRS[token], children: [word_pair.delete_suffix(token)] }]
247
- end
248
- when :open_tag
249
- [:open, token, name]
250
- when :close_tag
251
- [:close, token, name]
252
- when :code_start
253
- if (codeblock = strscan(CODEBLOCK_REGEXPS[name], negative_cache: true))
254
- # Need to unescape `\\` and `\<`.
255
- # RDoc also unescapes backslash + word separators, but this is not really necessary.
256
- content = codeblock.delete_suffix("</#{name}>").gsub(/\\(.)/) { '\\<*+_`'.include?($1) ? $1 : $& }
257
- [:node, nil, { type: :TT, children: content.empty? ? [] : [content] }]
258
- else
259
- [:text, token, nil]
223
+ string = @scanner.scan(pattern)
224
+ @last_match = string if string
225
+ @scanner_negative_cache << pattern if !string && negative_cache
226
+ string
260
227
  end
261
- when :standalone_tag
262
- [:node, nil, { type: STANDALONE_TAGS[name], children: [] }]
263
- when :tidylink_start
264
- [:tidylink_open, token, nil]
265
- when :tidylink_mid
266
- if @delimiters[:tidylink]
267
- if (url = read_tidylink_url)
268
- [:tidylink_close, nil, url]
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
269
292
  else
270
- [:tidylink_close, token, nil]
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
271
301
  end
272
- elsif @delimiters[:invalidated_tidylink]
273
- [:invalidated_tidylink_close, token, nil]
274
- else
275
- [:text, token, nil]
276
- end
277
- when :escape
278
- next_char = strscan(/./)
279
- if next_char.nil?
280
- # backslash at end of string
281
- [:text, '\\', nil]
282
- elsif next_char && ESCAPING_CHARS.include?(next_char)
283
- # escaped character
284
- [:text, next_char, nil]
285
- else
286
- # If next_char not an escaping character, it is treated as text token with backslash + next_char
287
- # For example, backslash of `\Ruby` (suppressed crossref) remains.
288
- [:text, "\\#{next_char}", nil]
289
- end
290
- else
291
- if token.nil?
292
- [:eof, nil, nil]
293
- elsif token.match?(/\A[A-Za-z0-9]*\z/) && (url = read_tidylink_url)
294
- # Simplified tidylink: label[url]
295
- [:node, nil, { type: :TIDYLINK, children: [token], url: url }]
296
- else
297
- [:text, token, nil]
298
302
  end
299
- end
300
- end
301
303
 
302
- # Read the URL part of a tidylink from the current position.
303
- # Returns nil if no valid URL part is found.
304
- # URL part is enclosed in square brackets and may contain escaped brackets.
305
- # Example: <tt>[http://example.com/?q=\[\]]</tt> represents <tt>http://example.com/?q=[]</tt>.
306
- # If we're accepting rdoc-style links in markdown, url may include <tt>*+<_</tt> with backslash escape.
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.
307
309
 
308
- def read_tidylink_url
309
- bracketed_url = strscan(/\[([^\s\[\]\\]|\\[\[\]\\*+<_])+\]/)
310
- bracketed_url[1...-1].gsub(/\\(.)/, '\1') if bracketed_url
310
+ def read_tidylink_url
311
+ bracketed_url = strscan(/\[([^\s\[\]\\]|\\[\[\]\\*+<_])+\]/)
312
+ bracketed_url[1...-1].gsub(/\\(.)/, '\1') if bracketed_url
313
+ end
314
+ end
311
315
  end
312
316
  end