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
@@ -1,585 +1,589 @@
1
1
  # frozen_string_literal: true
2
2
  require 'strscan'
3
3
 
4
- ##
5
- # A recursive-descent parser for RDoc markup.
6
- #
7
- # The parser tokenizes an input string then parses the tokens into a Document.
8
- # Documents can be converted into output formats by writing a visitor like
9
- # RDoc::Markup::ToHTML.
10
- #
11
- # The parser only handles the block-level constructs Paragraph, List,
12
- # ListItem, Heading, Verbatim, BlankLine, Rule and BlockQuote.
13
- # Inline markup such as <tt>\+blah\+</tt> is handled separately by
14
- # RDoc::Markup::InlineParser.
15
- #
16
- # To see what markup the Parser implements read RDoc. To see how to use
17
- # RDoc markup to format text in your program read RDoc::Markup.
18
-
19
- class RDoc::Markup::Parser
20
-
21
- include RDoc::Text
22
-
23
- ##
24
- # List token types
25
-
26
- LIST_TOKENS = [
27
- :BULLET,
28
- :LABEL,
29
- :LALPHA,
30
- :NOTE,
31
- :NUMBER,
32
- :UALPHA,
33
- ]
34
-
35
- ##
36
- # Parser error subclass
37
-
38
- class Error < RuntimeError; end
39
-
40
- ##
41
- # Raised when the parser is unable to handle the given markup
42
-
43
- class ParseError < Error; end
44
-
45
- ##
46
- # Enables display of debugging information
47
-
48
- attr_accessor :debug
49
-
50
- ##
51
- # Token accessor
52
-
53
- attr_reader :tokens
54
-
55
- ##
56
- # Parses +str+ into a Document.
57
- #
58
- # Use RDoc::Markup#parse instead of this method.
59
-
60
- def self.parse(str)
61
- parser = new
62
- parser.tokenize str
63
- doc = RDoc::Markup::Document.new
64
- parser.parse doc
65
- end
66
-
67
- ##
68
- # Returns a token stream for +str+, for testing
69
-
70
- def self.tokenize(str)
71
- parser = new
72
- parser.tokenize str
73
- parser.tokens
74
- end
75
-
76
- ##
77
- # Creates a new Parser. See also ::parse
4
+ module RDoc
5
+ class Markup
6
+ ##
7
+ # A recursive-descent parser for RDoc markup.
8
+ #
9
+ # The parser tokenizes an input string then parses the tokens into a Document.
10
+ # Documents can be converted into output formats by writing a visitor like
11
+ # RDoc::Markup::ToHTML.
12
+ #
13
+ # The parser only handles the block-level constructs Paragraph, List,
14
+ # ListItem, Heading, Verbatim, BlankLine, Rule and BlockQuote.
15
+ # Inline markup such as <tt>\+blah\+</tt> is handled separately by
16
+ # RDoc::Markup::InlineParser.
17
+ #
18
+ # To see what markup the Parser implements read RDoc. To see how to use
19
+ # RDoc markup to format text in your program read RDoc::Markup.
20
+
21
+ class Parser
22
+
23
+ include Text
24
+
25
+ ##
26
+ # List token types
27
+
28
+ LIST_TOKENS = [
29
+ :BULLET,
30
+ :LABEL,
31
+ :LALPHA,
32
+ :NOTE,
33
+ :NUMBER,
34
+ :UALPHA,
35
+ ]
36
+
37
+ ##
38
+ # Parser error subclass
39
+
40
+ class Error < RuntimeError; end
41
+
42
+ ##
43
+ # Raised when the parser is unable to handle the given markup
44
+
45
+ class ParseError < Error; end
46
+
47
+ ##
48
+ # Enables display of debugging information
49
+
50
+ attr_accessor :debug
51
+
52
+ ##
53
+ # Token accessor
54
+
55
+ attr_reader :tokens
56
+
57
+ ##
58
+ # Parses +str+ into a Document.
59
+ #
60
+ # Use RDoc::Markup#parse instead of this method.
61
+
62
+ def self.parse(str)
63
+ parser = new
64
+ parser.tokenize str
65
+ doc = Markup::Document.new
66
+ parser.parse doc
67
+ end
78
68
 
79
- def initialize
80
- @binary_input = nil
81
- @current_token = nil
82
- @debug = false
83
- @s = nil
84
- @tokens = []
85
- end
69
+ ##
70
+ # Returns a token stream for +str+, for testing
86
71
 
87
- ##
88
- # Builds a Heading of +level+
72
+ def self.tokenize(str)
73
+ parser = new
74
+ parser.tokenize str
75
+ parser.tokens
76
+ end
89
77
 
90
- def build_heading(level)
91
- type, text, = get
78
+ ##
79
+ # Creates a new Parser. See also ::parse
92
80
 
93
- text = case type
94
- when :TEXT then
95
- skip :NEWLINE
96
- text
97
- else
98
- unget
99
- ''
100
- end
81
+ def initialize
82
+ @binary_input = nil
83
+ @current_token = nil
84
+ @debug = false
85
+ @s = nil
86
+ @tokens = []
87
+ end
101
88
 
102
- RDoc::Markup::Heading.new level, text
103
- end
89
+ ##
90
+ # Builds a Heading of +level+
104
91
 
105
- ##
106
- # Builds a List flush to +margin+
92
+ def build_heading(level)
93
+ type, text, = get
107
94
 
108
- def build_list(margin)
109
- p :list_start => margin if @debug
95
+ text = case type
96
+ when :TEXT
97
+ skip :NEWLINE
98
+ text
99
+ else
100
+ unget
101
+ ''
102
+ end
110
103
 
111
- list = RDoc::Markup::List.new
112
- label = nil
104
+ Markup::Heading.new level, text
105
+ end
113
106
 
114
- until @tokens.empty? do
115
- type, data, column, = get
107
+ ##
108
+ # Builds a List flush to +margin+
116
109
 
117
- case type
118
- when *LIST_TOKENS then
119
- if column < margin || (list.type && list.type != type) then
120
- unget
121
- break
122
- end
110
+ def build_list(margin)
111
+ p :list_start => margin if @debug
123
112
 
124
- list.type = type
125
- peek_type, _, column, = peek_token
113
+ list = Markup::List.new
114
+ label = nil
126
115
 
127
- case type
128
- when :NOTE, :LABEL then
129
- label = [] unless label
116
+ until @tokens.empty? do
117
+ type, data, column, = get
130
118
 
131
- if peek_type == :NEWLINE then
132
- # description not on the same line as LABEL/NOTE
133
- # skip the trailing newline & any blank lines below
134
- while peek_type == :NEWLINE
135
- get
136
- peek_type, _, column, = peek_token
119
+ case type
120
+ when *LIST_TOKENS
121
+ if column < margin || (list.type && list.type != type)
122
+ unget
123
+ break
137
124
  end
138
125
 
139
- # we may be:
140
- # - at end of stream
141
- # - at a column < margin:
142
- # [text]
143
- # blah blah blah
144
- # - at the same column, but with a different type of list item
145
- # [text]
146
- # * blah blah
147
- # - at the same column, with the same type of list item
148
- # [one]
149
- # [two]
150
- # In all cases, we have an empty description.
151
- # In the last case only, we continue.
152
- if peek_type.nil? || column < margin then
153
- empty = true
154
- elsif column == margin then
155
- case peek_type
156
- when type
157
- empty = :continue
158
- when *LIST_TOKENS
159
- empty = true
160
- else
161
- empty = false
126
+ list.type = type
127
+ peek_type, _, column, = peek_token
128
+
129
+ case type
130
+ when :NOTE, :LABEL
131
+ label = [] unless label
132
+
133
+ if peek_type == :NEWLINE
134
+ # description not on the same line as LABEL/NOTE
135
+ # skip the trailing newline & any blank lines below
136
+ while peek_type == :NEWLINE
137
+ get
138
+ peek_type, _, column, = peek_token
139
+ end
140
+
141
+ # we may be:
142
+ # - at end of stream
143
+ # - at a column < margin:
144
+ # [text]
145
+ # blah blah blah
146
+ # - at the same column, but with a different type of list item
147
+ # [text]
148
+ # * blah blah
149
+ # - at the same column, with the same type of list item
150
+ # [one]
151
+ # [two]
152
+ # In all cases, we have an empty description.
153
+ # In the last case only, we continue.
154
+ if peek_type.nil? || column < margin
155
+ empty = true
156
+ elsif column == margin
157
+ case peek_type
158
+ when type
159
+ empty = :continue
160
+ when *LIST_TOKENS
161
+ empty = true
162
+ else
163
+ empty = false
164
+ end
165
+ else
166
+ empty = false
167
+ end
168
+
169
+ if empty
170
+ label << data
171
+ next if empty == :continue
172
+ break
173
+ end
162
174
  end
163
175
  else
164
- empty = false
176
+ data = nil
165
177
  end
166
178
 
167
- if empty then
168
- label << data
169
- next if empty == :continue
170
- break
179
+ if label
180
+ data = label << data
181
+ label = nil
171
182
  end
183
+
184
+ list_item = Markup::ListItem.new data
185
+ parse list_item, column
186
+ list << list_item
187
+
188
+ else
189
+ unget
190
+ break
172
191
  end
173
- else
174
- data = nil
175
192
  end
176
193
 
177
- if label then
178
- data = label << data
179
- label = nil
180
- end
194
+ p :list_end => margin if @debug
181
195
 
182
- list_item = RDoc::Markup::ListItem.new data
183
- parse list_item, column
184
- list << list_item
196
+ if list.empty?
197
+ return nil unless label
198
+ return nil unless [:LABEL, :NOTE].include? list.type
185
199
 
186
- else
187
- unget
188
- break
189
- end
190
- end
200
+ list_item = Markup::ListItem.new label, Markup::BlankLine.new
201
+ list << list_item
202
+ end
191
203
 
192
- p :list_end => margin if @debug
204
+ list
205
+ end
193
206
 
194
- if list.empty? then
195
- return nil unless label
196
- return nil unless [:LABEL, :NOTE].include? list.type
207
+ ##
208
+ # Builds a Paragraph that is flush to +margin+
197
209
 
198
- list_item = RDoc::Markup::ListItem.new label, RDoc::Markup::BlankLine.new
199
- list << list_item
200
- end
210
+ def build_paragraph(margin)
211
+ p :paragraph_start => margin if @debug
201
212
 
202
- list
203
- end
213
+ paragraph = Markup::Paragraph.new
204
214
 
205
- ##
206
- # Builds a Paragraph that is flush to +margin+
215
+ until @tokens.empty? do
216
+ type, data, column, = get
207
217
 
208
- def build_paragraph(margin)
209
- p :paragraph_start => margin if @debug
218
+ if type == :TEXT and column == margin
219
+ paragraph << data
210
220
 
211
- paragraph = RDoc::Markup::Paragraph.new
221
+ break if peek_token.first == :BREAK
212
222
 
213
- until @tokens.empty? do
214
- type, data, column, = get
223
+ data << ' ' if skip :NEWLINE and /#{SPACE_SEPARATED_LETTER_CLASS}\z/o.match?(data)
224
+ else
225
+ unget
226
+ break
227
+ end
228
+ end
215
229
 
216
- if type == :TEXT and column == margin then
217
- paragraph << data
230
+ paragraph.parts.last.sub!(/ \z/, '') # cleanup
218
231
 
219
- break if peek_token.first == :BREAK
232
+ p :paragraph_end => margin if @debug
220
233
 
221
- data << ' ' if skip :NEWLINE and /#{SPACE_SEPARATED_LETTER_CLASS}\z/o.match?(data)
222
- else
223
- unget
224
- break
234
+ paragraph
225
235
  end
226
- end
227
236
 
228
- paragraph.parts.last.sub!(/ \z/, '') # cleanup
237
+ ##
238
+ # Builds a Verbatim that is indented from +margin+.
239
+ #
240
+ # The verbatim block is shifted left (the least indented lines start in
241
+ # column 0). Each part of the verbatim is one line of text, always
242
+ # terminated by a newline. Blank lines always consist of a single newline
243
+ # character, and there is never a single newline at the end of the verbatim.
229
244
 
230
- p :paragraph_end => margin if @debug
231
-
232
- paragraph
233
- end
245
+ def build_verbatim(margin)
246
+ p :verbatim_begin => margin if @debug
247
+ verbatim = Markup::Verbatim.new
234
248
 
235
- ##
236
- # Builds a Verbatim that is indented from +margin+.
237
- #
238
- # The verbatim block is shifted left (the least indented lines start in
239
- # column 0). Each part of the verbatim is one line of text, always
240
- # terminated by a newline. Blank lines always consist of a single newline
241
- # character, and there is never a single newline at the end of the verbatim.
242
-
243
- def build_verbatim(margin)
244
- p :verbatim_begin => margin if @debug
245
- verbatim = RDoc::Markup::Verbatim.new
249
+ min_indent = nil
250
+ generate_leading_spaces = true
251
+ line = ''.dup
246
252
 
247
- min_indent = nil
248
- generate_leading_spaces = true
249
- line = ''.dup
253
+ until @tokens.empty? do
254
+ type, data, column, = get
250
255
 
251
- until @tokens.empty? do
252
- type, data, column, = get
256
+ if type == :NEWLINE
257
+ line << data
258
+ verbatim << line
259
+ line = ''.dup
260
+ generate_leading_spaces = true
261
+ next
262
+ end
253
263
 
254
- if type == :NEWLINE then
255
- line << data
256
- verbatim << line
257
- line = ''.dup
258
- generate_leading_spaces = true
259
- next
260
- end
264
+ if column <= margin
265
+ unget
266
+ break
267
+ end
261
268
 
262
- if column <= margin
263
- unget
264
- break
265
- end
269
+ if generate_leading_spaces
270
+ indent = column - margin
271
+ line << ' ' * indent
272
+ min_indent = indent if min_indent.nil? || indent < min_indent
273
+ generate_leading_spaces = false
274
+ end
266
275
 
267
- if generate_leading_spaces then
268
- indent = column - margin
269
- line << ' ' * indent
270
- min_indent = indent if min_indent.nil? || indent < min_indent
271
- generate_leading_spaces = false
272
- end
276
+ case type
277
+ when :HEADER
278
+ line << '=' * data
279
+ _, _, peek_column, = peek_token
280
+ peek_column ||= column + data
281
+ indent = peek_column - column - data
282
+ line << ' ' * indent
283
+ when :RULE
284
+ width = 2 + data
285
+ line << '-' * width
286
+ _, _, peek_column, = peek_token
287
+ peek_column ||= column + width
288
+ indent = peek_column - column - width
289
+ line << ' ' * indent
290
+ when :BREAK, :TEXT
291
+ line << data
292
+ when :BLOCKQUOTE
293
+ line << '>>>'
294
+ peek_type, _, peek_column = peek_token
295
+ if peek_type != :NEWLINE and peek_column
296
+ line << ' ' * (peek_column - column - 3)
297
+ end
298
+ else # *LIST_TOKENS
299
+ list_marker = case type
300
+ when :BULLET then data
301
+ when :LABEL then "[#{data}]"
302
+ when :NOTE then "#{data}::"
303
+ else # :LALPHA, :NUMBER, :UALPHA
304
+ "#{data}."
305
+ end
306
+ line << list_marker
307
+ peek_type, _, peek_column = peek_token
308
+ unless peek_type == :NEWLINE
309
+ peek_column ||= column + list_marker.length
310
+ indent = peek_column - column - list_marker.length
311
+ line << ' ' * indent
312
+ end
313
+ end
273
314
 
274
- case type
275
- when :HEADER then
276
- line << '=' * data
277
- _, _, peek_column, = peek_token
278
- peek_column ||= column + data
279
- indent = peek_column - column - data
280
- line << ' ' * indent
281
- when :RULE then
282
- width = 2 + data
283
- line << '-' * width
284
- _, _, peek_column, = peek_token
285
- peek_column ||= column + width
286
- indent = peek_column - column - width
287
- line << ' ' * indent
288
- when :BREAK, :TEXT then
289
- line << data
290
- when :BLOCKQUOTE then
291
- line << '>>>'
292
- peek_type, _, peek_column = peek_token
293
- if peek_type != :NEWLINE and peek_column
294
- line << ' ' * (peek_column - column - 3)
295
315
  end
296
- else # *LIST_TOKENS
297
- list_marker = case type
298
- when :BULLET then data
299
- when :LABEL then "[#{data}]"
300
- when :NOTE then "#{data}::"
301
- else # :LALPHA, :NUMBER, :UALPHA
302
- "#{data}."
303
- end
304
- line << list_marker
305
- peek_type, _, peek_column = peek_token
306
- unless peek_type == :NEWLINE then
307
- peek_column ||= column + list_marker.length
308
- indent = peek_column - column - list_marker.length
309
- line << ' ' * indent
310
- end
311
- end
312
316
 
313
- end
317
+ verbatim << line << "\n" unless line.empty?
318
+ verbatim.parts.each { |p| p.slice!(0, min_indent) unless p == "\n" } if min_indent > 0
319
+ verbatim.normalize
314
320
 
315
- verbatim << line << "\n" unless line.empty?
316
- verbatim.parts.each { |p| p.slice!(0, min_indent) unless p == "\n" } if min_indent > 0
317
- verbatim.normalize
321
+ p :verbatim_end => margin if @debug
318
322
 
319
- p :verbatim_end => margin if @debug
323
+ verbatim
324
+ end
320
325
 
321
- verbatim
322
- end
326
+ ##
327
+ # Pulls the next token from the stream.
323
328
 
324
- ##
325
- # Pulls the next token from the stream.
329
+ def get
330
+ @current_token = @tokens.shift
331
+ p :get => @current_token if @debug
332
+ @current_token
333
+ end
326
334
 
327
- def get
328
- @current_token = @tokens.shift
329
- p :get => @current_token if @debug
330
- @current_token
331
- end
335
+ ##
336
+ # Parses the tokens into an array of RDoc::Markup::XXX objects,
337
+ # and appends them to the passed +parent+ RDoc::Markup::YYY object.
338
+ #
339
+ # Exits at the end of the token stream, or when it encounters a token
340
+ # in a column less than +indent+ (unless it is a NEWLINE).
341
+ #
342
+ # Returns +parent+.
343
+
344
+ def parse(parent, indent = 0)
345
+ p :parse_start => indent if @debug
346
+
347
+ until @tokens.empty? do
348
+ type, data, column, = get
349
+
350
+ case type
351
+ when :BREAK
352
+ parent << Markup::BlankLine.new
353
+ skip :NEWLINE, false
354
+ next
355
+ when :NEWLINE
356
+ # trailing newlines are skipped below, so this is a blank line
357
+ parent << Markup::BlankLine.new
358
+ skip :NEWLINE, false
359
+ next
360
+ end
332
361
 
333
- ##
334
- # Parses the tokens into an array of RDoc::Markup::XXX objects,
335
- # and appends them to the passed +parent+ RDoc::Markup::YYY object.
336
- #
337
- # Exits at the end of the token stream, or when it encounters a token
338
- # in a column less than +indent+ (unless it is a NEWLINE).
339
- #
340
- # Returns +parent+.
341
-
342
- def parse(parent, indent = 0)
343
- p :parse_start => indent if @debug
344
-
345
- until @tokens.empty? do
346
- type, data, column, = get
347
-
348
- case type
349
- when :BREAK then
350
- parent << RDoc::Markup::BlankLine.new
351
- skip :NEWLINE, false
352
- next
353
- when :NEWLINE then
354
- # trailing newlines are skipped below, so this is a blank line
355
- parent << RDoc::Markup::BlankLine.new
356
- skip :NEWLINE, false
357
- next
358
- end
362
+ # indentation change: break or verbatim
363
+ if column < indent
364
+ unget
365
+ break
366
+ elsif column > indent
367
+ unget
368
+ parent << build_verbatim(indent)
369
+ next
370
+ end
359
371
 
360
- # indentation change: break or verbatim
361
- if column < indent then
362
- unget
363
- break
364
- elsif column > indent then
365
- unget
366
- parent << build_verbatim(indent)
367
- next
368
- end
372
+ # indentation is the same
373
+ case type
374
+ when :HEADER
375
+ parent << build_heading(data)
376
+ when :RULE
377
+ parent << Markup::Rule.new(data)
378
+ skip :NEWLINE
379
+ when :TEXT
380
+ unget
381
+ parse_text parent, indent
382
+ when :BLOCKQUOTE
383
+ nil while (type, = get; type) and type != :NEWLINE
384
+ _, _, column, = peek_token
385
+ bq = Markup::BlockQuote.new
386
+ p :blockquote_start => [data, column] if @debug
387
+ parse bq, column
388
+ p :blockquote_end => indent if @debug
389
+ parent << bq
390
+ when *LIST_TOKENS
391
+ unget
392
+ parent << build_list(indent)
393
+ else
394
+ type, data, column, line = @current_token
395
+ raise ParseError, "Unhandled token #{type} (#{data.inspect}) at #{line}:#{column}"
396
+ end
397
+ end
369
398
 
370
- # indentation is the same
371
- case type
372
- when :HEADER then
373
- parent << build_heading(data)
374
- when :RULE then
375
- parent << RDoc::Markup::Rule.new(data)
376
- skip :NEWLINE
377
- when :TEXT then
378
- unget
379
- parse_text parent, indent
380
- when :BLOCKQUOTE then
381
- nil while (type, = get; type) and type != :NEWLINE
382
- _, _, column, = peek_token
383
- bq = RDoc::Markup::BlockQuote.new
384
- p :blockquote_start => [data, column] if @debug
385
- parse bq, column
386
- p :blockquote_end => indent if @debug
387
- parent << bq
388
- when *LIST_TOKENS then
389
- unget
390
- parent << build_list(indent)
391
- else
392
- type, data, column, line = @current_token
393
- raise ParseError, "Unhandled token #{type} (#{data.inspect}) at #{line}:#{column}"
394
- end
395
- end
399
+ p :parse_end => indent if @debug
396
400
 
397
- p :parse_end => indent if @debug
401
+ parent
398
402
 
399
- parent
403
+ end
400
404
 
401
- end
405
+ ##
406
+ # Small hook that is overridden by RDoc::TomDoc
402
407
 
403
- ##
404
- # Small hook that is overridden by RDoc::TomDoc
408
+ def parse_text(parent, indent) # :nodoc:
409
+ parent << build_paragraph(indent)
410
+ end
405
411
 
406
- def parse_text(parent, indent) # :nodoc:
407
- parent << build_paragraph(indent)
408
- end
412
+ ##
413
+ # Returns the next token on the stream without modifying the stream
409
414
 
410
- ##
411
- # Returns the next token on the stream without modifying the stream
415
+ def peek_token
416
+ token = @tokens.first || []
417
+ p :peek => token if @debug
418
+ token
419
+ end
412
420
 
413
- def peek_token
414
- token = @tokens.first || []
415
- p :peek => token if @debug
416
- token
417
- end
421
+ ##
422
+ # A simple wrapper of StringScanner that is aware of the current column and lineno
418
423
 
419
- ##
420
- # A simple wrapper of StringScanner that is aware of the current column and lineno
424
+ class MyStringScanner
425
+ # :stopdoc:
421
426
 
422
- class MyStringScanner
423
- # :stopdoc:
427
+ def initialize(input)
428
+ @line = @column = 0
429
+ @s = StringScanner.new input
430
+ end
424
431
 
425
- def initialize(input)
426
- @line = @column = 0
427
- @s = StringScanner.new input
428
- end
432
+ def scan(re)
433
+ ret = @s.scan(re)
434
+ @column += ret.length if ret
435
+ ret
436
+ end
429
437
 
430
- def scan(re)
431
- ret = @s.scan(re)
432
- @column += ret.length if ret
433
- ret
434
- end
438
+ def unscan(s)
439
+ @s.pos -= s.bytesize
440
+ @column -= s.length
441
+ end
435
442
 
436
- def unscan(s)
437
- @s.pos -= s.bytesize
438
- @column -= s.length
439
- end
443
+ def pos
444
+ [@column, @line]
445
+ end
440
446
 
441
- def pos
442
- [@column, @line]
443
- end
447
+ def newline!
448
+ @column = 0
449
+ @line += 1
450
+ end
444
451
 
445
- def newline!
446
- @column = 0
447
- @line += 1
448
- end
452
+ def eos?
453
+ @s.eos?
454
+ end
449
455
 
450
- def eos?
451
- @s.eos?
452
- end
456
+ def matched
457
+ @s.matched
458
+ end
453
459
 
454
- def matched
455
- @s.matched
456
- end
460
+ def [](i)
461
+ @s[i]
462
+ end
457
463
 
458
- def [](i)
459
- @s[i]
460
- end
464
+ #:startdoc:
465
+ end
461
466
 
462
- #:startdoc:
463
- end
467
+ ##
468
+ # Creates the StringScanner
464
469
 
465
- ##
466
- # Creates the StringScanner
470
+ def setup_scanner(input)
471
+ @s = MyStringScanner.new input
472
+ end
467
473
 
468
- def setup_scanner(input)
469
- @s = MyStringScanner.new input
470
- end
474
+ ##
475
+ # Skips the next token if its type is +token_type+.
476
+ #
477
+ # Optionally raises an error if the next token is not of the expected type.
471
478
 
472
- ##
473
- # Skips the next token if its type is +token_type+.
474
- #
475
- # Optionally raises an error if the next token is not of the expected type.
476
-
477
- def skip(token_type, error = true)
478
- type, = get
479
- return unless type # end of stream
480
- return @current_token if token_type == type
481
- unget
482
- raise ParseError, "expected #{token_type} got #{@current_token.inspect}" if error
483
- end
479
+ def skip(token_type, error = true)
480
+ type, = get
481
+ return unless type # end of stream
482
+ return @current_token if token_type == type
483
+ unget
484
+ raise ParseError, "expected #{token_type} got #{@current_token.inspect}" if error
485
+ end
484
486
 
485
- ##
486
- # Turns text +input+ into a stream of tokens
487
-
488
- def tokenize(input)
489
- setup_scanner input
490
-
491
- until @s.eos? do
492
- pos = @s.pos
493
-
494
- # leading spaces will be reflected by the column of the next token
495
- # the only thing we loose are trailing spaces at the end of the file
496
- next if @s.scan(/ +/)
497
-
498
- # note: after BULLET, LABEL, etc.,
499
- # indent will be the column of the next non-newline token
500
-
501
- @tokens << case
502
- # [CR]LF => :NEWLINE
503
- when @s.scan(/\r?\n/) then
504
- token = [:NEWLINE, @s.matched, *pos]
505
- @s.newline!
506
- token
507
- # === text => :HEADER then :TEXT
508
- when @s.scan(/(=+)(\s*)/) then
509
- level = @s[1].length
510
- header = [:HEADER, level, *pos]
511
-
512
- if @s[2] =~ /^\r?\n/ then
513
- @s.unscan(@s[2])
514
- header
515
- else
516
- pos = @s.pos
517
- @s.scan(/.*/)
518
- @tokens << header
519
- [:TEXT, @s.matched.sub(/\r$/, ''), *pos]
520
- end
521
- # --- (at least 3) and nothing else on the line => :RULE
522
- when @s.scan(/(-{3,}) *\r?$/) then
523
- [:RULE, @s[1].length - 2, *pos]
524
- # * or - followed by white space and text => :BULLET
525
- when @s.scan(/([*-]) +(\S)/) then
526
- @s.unscan(@s[2])
527
- [:BULLET, @s[1], *pos]
528
- # A. text, a. text, 12. text => :UALPHA, :LALPHA, :NUMBER
529
- when @s.scan(/([a-z]|\d+)\. +(\S)/i) then
530
- # FIXME if tab(s), the column will be wrong
531
- # either support tabs everywhere by first expanding them to
532
- # spaces, or assume that they will have been replaced
533
- # before (and provide a check for that at least in debug
534
- # mode)
535
- list_label = @s[1]
536
- @s.unscan(@s[2])
537
- list_type =
538
- case list_label
539
- when /[a-z]/ then :LALPHA
540
- when /[A-Z]/ then :UALPHA
541
- when /\d/ then :NUMBER
487
+ ##
488
+ # Turns text +input+ into a stream of tokens
489
+
490
+ def tokenize(input)
491
+ setup_scanner input
492
+
493
+ until @s.eos? do
494
+ pos = @s.pos
495
+
496
+ # leading spaces will be reflected by the column of the next token
497
+ # the only thing we loose are trailing spaces at the end of the file
498
+ next if @s.scan(/ +/)
499
+
500
+ # note: after BULLET, LABEL, etc.,
501
+ # indent will be the column of the next non-newline token
502
+
503
+ @tokens << case
504
+ # [CR]LF => :NEWLINE
505
+ when @s.scan(/\r?\n/)
506
+ token = [:NEWLINE, @s.matched, *pos]
507
+ @s.newline!
508
+ token
509
+ # === text => :HEADER then :TEXT
510
+ when @s.scan(/(=+)(\s*)/)
511
+ level = @s[1].length
512
+ header = [:HEADER, level, *pos]
513
+
514
+ if @s[2] =~ /^\r?\n/
515
+ @s.unscan(@s[2])
516
+ header
517
+ else
518
+ pos = @s.pos
519
+ @s.scan(/.*/)
520
+ @tokens << header
521
+ [:TEXT, @s.matched.sub(/\r$/, ''), *pos]
522
+ end
523
+ # --- (at least 3) and nothing else on the line => :RULE
524
+ when @s.scan(/(-{3,}) *\r?$/)
525
+ [:RULE, @s[1].length - 2, *pos]
526
+ # * or - followed by white space and text => :BULLET
527
+ when @s.scan(/([*-]) +(\S)/)
528
+ @s.unscan(@s[2])
529
+ [:BULLET, @s[1], *pos]
530
+ # A. text, a. text, 12. text => :UALPHA, :LALPHA, :NUMBER
531
+ when @s.scan(/([a-z]|\d+)\. +(\S)/i)
532
+ # FIXME if tab(s), the column will be wrong
533
+ # either support tabs everywhere by first expanding them to
534
+ # spaces, or assume that they will have been replaced
535
+ # before (and provide a check for that at least in debug
536
+ # mode)
537
+ list_label = @s[1]
538
+ @s.unscan(@s[2])
539
+ list_type =
540
+ case list_label
541
+ when /[a-z]/ then :LALPHA
542
+ when /[A-Z]/ then :UALPHA
543
+ when /\d/ then :NUMBER
544
+ else
545
+ raise ParseError, "BUG token #{list_label}"
546
+ end
547
+ [list_type, list_label, *pos]
548
+ # [text] followed by spaces or end of line => :LABEL
549
+ when @s.scan(/\[(.*?)\]( +|\r?$)/)
550
+ [:LABEL, @s[1], *pos]
551
+ # text:: followed by spaces or end of line => :NOTE
552
+ when @s.scan(/(.*?)::( +|\r?$)/)
553
+ [:NOTE, @s[1], *pos]
554
+ # >>> followed by end of line => :BLOCKQUOTE
555
+ when @s.scan(/>>> *(\w+)?$/)
556
+ if word = @s[1]
557
+ @s.unscan(word)
558
+ end
559
+ [:BLOCKQUOTE, word, *pos]
560
+ # anything else: :TEXT
542
561
  else
543
- raise ParseError, "BUG token #{list_label}"
562
+ @s.scan(/(.*?)( )?\r?$/)
563
+ token = [:TEXT, @s[1], *pos]
564
+
565
+ if @s[2]
566
+ @tokens << token
567
+ [:BREAK, @s[2], pos[0] + @s[1].length, pos[1]]
568
+ else
569
+ token
570
+ end
544
571
  end
545
- [list_type, list_label, *pos]
546
- # [text] followed by spaces or end of line => :LABEL
547
- when @s.scan(/\[(.*?)\]( +|\r?$)/) then
548
- [:LABEL, @s[1], *pos]
549
- # text:: followed by spaces or end of line => :NOTE
550
- when @s.scan(/(.*?)::( +|\r?$)/) then
551
- [:NOTE, @s[1], *pos]
552
- # >>> followed by end of line => :BLOCKQUOTE
553
- when @s.scan(/>>> *(\w+)?$/) then
554
- if word = @s[1]
555
- @s.unscan(word)
556
- end
557
- [:BLOCKQUOTE, word, *pos]
558
- # anything else: :TEXT
559
- else
560
- @s.scan(/(.*?)( )?\r?$/)
561
- token = [:TEXT, @s[1], *pos]
562
-
563
- if @s[2] then
564
- @tokens << token
565
- [:BREAK, @s[2], pos[0] + @s[1].length, pos[1]]
566
- else
567
- token
568
- end
569
- end
570
- end
572
+ end
571
573
 
572
- self
573
- end
574
+ self
575
+ end
574
576
 
575
- ##
576
- # Returns the current token to the token stream
577
+ ##
578
+ # Returns the current token to the token stream
577
579
 
578
- def unget
579
- token = @current_token
580
- p :unget => token if @debug
581
- raise Error, 'too many #ungets' if token == @tokens.first
582
- @tokens.unshift token if token
583
- end
580
+ def unget
581
+ token = @current_token
582
+ p :unget => token if @debug
583
+ raise Error, 'too many #ungets' if token == @tokens.first
584
+ @tokens.unshift token if token
585
+ end
584
586
 
587
+ end
588
+ end
585
589
  end