rdoc 3.1 → 6.3.3

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

Potentially problematic release.


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

Files changed (247) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.rdoc +220 -0
  3. data/CVE-2013-0256.rdoc +49 -0
  4. data/ExampleMarkdown.md +37 -0
  5. data/ExampleRDoc.rdoc +208 -0
  6. data/Gemfile +12 -0
  7. data/History.rdoc +1666 -0
  8. data/LEGAL.rdoc +50 -0
  9. data/LICENSE.rdoc +57 -0
  10. data/README.rdoc +129 -0
  11. data/RI.rdoc +57 -0
  12. data/Rakefile +84 -81
  13. data/TODO.rdoc +59 -0
  14. data/bin/console +7 -0
  15. data/bin/setup +6 -0
  16. data/{bin → exe}/rdoc +11 -2
  17. data/exe/ri +12 -0
  18. data/lib/rdoc/alias.rb +1 -2
  19. data/lib/rdoc/anon_class.rb +3 -2
  20. data/lib/rdoc/any_method.rb +234 -40
  21. data/lib/rdoc/attr.rb +79 -11
  22. data/lib/rdoc/class_module.rb +443 -71
  23. data/lib/rdoc/code_object.rb +216 -20
  24. data/lib/rdoc/code_objects.rb +4 -21
  25. data/lib/rdoc/comment.rb +250 -0
  26. data/lib/rdoc/constant.rb +110 -9
  27. data/lib/rdoc/context/section.rb +232 -0
  28. data/lib/rdoc/context.rb +392 -172
  29. data/lib/rdoc/cross_reference.rb +202 -0
  30. data/lib/rdoc/encoding.rb +83 -28
  31. data/lib/rdoc/erb_partial.rb +19 -0
  32. data/lib/rdoc/erbio.rb +8 -3
  33. data/lib/rdoc/extend.rb +10 -0
  34. data/lib/rdoc/generator/darkfish.rb +507 -84
  35. data/lib/rdoc/generator/json_index.rb +300 -0
  36. data/lib/rdoc/generator/markup.rb +27 -74
  37. data/lib/rdoc/generator/pot/message_extractor.rb +68 -0
  38. data/lib/rdoc/generator/pot/po.rb +84 -0
  39. data/lib/rdoc/generator/pot/po_entry.rb +141 -0
  40. data/lib/rdoc/generator/pot.rb +98 -0
  41. data/lib/rdoc/generator/ri.rb +8 -62
  42. data/lib/rdoc/generator/template/darkfish/_footer.rhtml +5 -0
  43. data/lib/rdoc/generator/template/darkfish/_head.rhtml +22 -0
  44. data/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml +19 -0
  45. data/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml +9 -0
  46. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +15 -0
  47. data/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml +9 -0
  48. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +15 -0
  49. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +15 -0
  50. data/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml +12 -0
  51. data/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml +11 -0
  52. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +12 -0
  53. data/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml +11 -0
  54. data/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml +14 -0
  55. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +11 -0
  56. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +18 -0
  57. data/lib/rdoc/generator/template/darkfish/class.rhtml +172 -0
  58. data/lib/rdoc/generator/template/darkfish/css/fonts.css +167 -0
  59. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +639 -0
  60. data/lib/rdoc/generator/template/darkfish/fonts/Lato-Light.ttf +0 -0
  61. data/lib/rdoc/generator/template/darkfish/fonts/Lato-LightItalic.ttf +0 -0
  62. data/lib/rdoc/generator/template/darkfish/fonts/Lato-Regular.ttf +0 -0
  63. data/lib/rdoc/generator/template/darkfish/fonts/Lato-RegularItalic.ttf +0 -0
  64. data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf +0 -0
  65. data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf +0 -0
  66. data/lib/rdoc/generator/template/darkfish/images/add.png +0 -0
  67. data/lib/rdoc/generator/template/darkfish/images/arrow_up.png +0 -0
  68. data/lib/rdoc/generator/template/darkfish/images/delete.png +0 -0
  69. data/lib/rdoc/generator/template/darkfish/images/tag_blue.png +0 -0
  70. data/lib/rdoc/generator/template/darkfish/images/transparent.png +0 -0
  71. data/lib/rdoc/generator/template/darkfish/index.rhtml +18 -60
  72. data/lib/rdoc/generator/template/darkfish/js/darkfish.js +51 -83
  73. data/lib/rdoc/generator/template/darkfish/js/search.js +110 -0
  74. data/lib/rdoc/generator/template/darkfish/page.rhtml +18 -0
  75. data/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml +18 -0
  76. data/lib/rdoc/generator/template/darkfish/servlet_root.rhtml +62 -0
  77. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +58 -0
  78. data/lib/rdoc/generator/template/json_index/.document +1 -0
  79. data/lib/rdoc/generator/template/json_index/js/navigation.js +105 -0
  80. data/lib/rdoc/generator/template/json_index/js/searcher.js +229 -0
  81. data/lib/rdoc/generator.rb +24 -13
  82. data/lib/rdoc/ghost_method.rb +1 -2
  83. data/lib/rdoc/i18n/locale.rb +102 -0
  84. data/lib/rdoc/i18n/text.rb +126 -0
  85. data/lib/rdoc/i18n.rb +10 -0
  86. data/lib/rdoc/include.rb +5 -95
  87. data/lib/rdoc/known_classes.rb +5 -2
  88. data/lib/rdoc/markdown/entities.rb +2132 -0
  89. data/lib/rdoc/markdown/literals.kpeg +23 -0
  90. data/lib/rdoc/markdown/literals.rb +416 -0
  91. data/lib/rdoc/markdown.kpeg +1237 -0
  92. data/lib/rdoc/markdown.rb +16684 -0
  93. data/lib/rdoc/markup/attr_changer.rb +23 -0
  94. data/lib/rdoc/markup/attr_span.rb +36 -0
  95. data/lib/rdoc/markup/attribute_manager.rb +135 -62
  96. data/lib/rdoc/markup/attributes.rb +71 -0
  97. data/lib/rdoc/markup/blank_line.rb +1 -0
  98. data/lib/rdoc/markup/block_quote.rb +15 -0
  99. data/lib/rdoc/markup/document.rb +96 -9
  100. data/lib/rdoc/markup/formatter.rb +138 -25
  101. data/lib/rdoc/markup/hard_break.rb +32 -0
  102. data/lib/rdoc/markup/heading.rb +61 -2
  103. data/lib/rdoc/markup/include.rb +43 -0
  104. data/lib/rdoc/markup/indented_paragraph.rb +48 -0
  105. data/lib/rdoc/markup/list.rb +25 -4
  106. data/lib/rdoc/markup/list_item.rb +18 -4
  107. data/lib/rdoc/markup/paragraph.rb +15 -0
  108. data/lib/rdoc/markup/parser.rb +180 -88
  109. data/lib/rdoc/markup/pre_process.rb +183 -38
  110. data/lib/rdoc/markup/raw.rb +6 -5
  111. data/lib/rdoc/markup/regexp_handling.rb +41 -0
  112. data/lib/rdoc/markup/rule.rb +1 -0
  113. data/lib/rdoc/markup/table.rb +47 -0
  114. data/lib/rdoc/markup/to_ansi.rb +17 -7
  115. data/lib/rdoc/markup/to_bs.rb +5 -8
  116. data/lib/rdoc/markup/to_html.rb +238 -137
  117. data/lib/rdoc/markup/to_html_crossref.rb +125 -152
  118. data/lib/rdoc/markup/to_html_snippet.rb +285 -0
  119. data/lib/rdoc/markup/to_joined_paragraph.rb +47 -0
  120. data/lib/rdoc/markup/to_label.rb +75 -0
  121. data/lib/rdoc/markup/to_markdown.rb +192 -0
  122. data/lib/rdoc/markup/to_rdoc.rb +85 -15
  123. data/lib/rdoc/markup/to_table_of_contents.rb +89 -0
  124. data/lib/rdoc/markup/to_test.rb +2 -4
  125. data/lib/rdoc/markup/to_tt_only.rb +121 -0
  126. data/lib/rdoc/markup/verbatim.rb +39 -0
  127. data/lib/rdoc/markup.rb +388 -110
  128. data/lib/rdoc/meta_method.rb +1 -2
  129. data/lib/rdoc/method_attr.rb +87 -21
  130. data/lib/rdoc/mixin.rb +121 -0
  131. data/lib/rdoc/normal_class.rb +39 -10
  132. data/lib/rdoc/normal_module.rb +22 -7
  133. data/lib/rdoc/options.rb +613 -73
  134. data/lib/rdoc/parser/c.rb +621 -287
  135. data/lib/rdoc/parser/changelog.rb +335 -0
  136. data/lib/rdoc/parser/markdown.rb +24 -0
  137. data/lib/rdoc/parser/rd.rb +23 -0
  138. data/lib/rdoc/parser/ripper_state_lex.rb +590 -0
  139. data/lib/rdoc/parser/ruby.rb +1368 -762
  140. data/lib/rdoc/parser/ruby_tools.rb +42 -35
  141. data/lib/rdoc/parser/simple.rb +23 -11
  142. data/lib/rdoc/parser/text.rb +12 -0
  143. data/lib/rdoc/parser.rb +162 -89
  144. data/lib/rdoc/rd/block_parser.rb +1056 -0
  145. data/lib/rdoc/rd/block_parser.ry +639 -0
  146. data/lib/rdoc/rd/inline.rb +72 -0
  147. data/lib/rdoc/rd/inline_parser.rb +1208 -0
  148. data/lib/rdoc/rd/inline_parser.ry +593 -0
  149. data/lib/rdoc/rd.rb +100 -0
  150. data/lib/rdoc/rdoc.rb +208 -115
  151. data/lib/rdoc/require.rb +1 -2
  152. data/lib/rdoc/ri/driver.rb +734 -239
  153. data/lib/rdoc/ri/formatter.rb +1 -0
  154. data/lib/rdoc/ri/paths.rb +91 -48
  155. data/lib/rdoc/ri/store.rb +3 -261
  156. data/lib/rdoc/ri/task.rb +71 -0
  157. data/lib/rdoc/ri.rb +5 -2
  158. data/lib/rdoc/rubygems_hook.rb +246 -0
  159. data/lib/rdoc/servlet.rb +451 -0
  160. data/lib/rdoc/single_class.rb +14 -2
  161. data/lib/rdoc/stats/normal.rb +19 -12
  162. data/lib/rdoc/stats/quiet.rb +1 -0
  163. data/lib/rdoc/stats/verbose.rb +1 -0
  164. data/lib/rdoc/stats.rb +262 -104
  165. data/lib/rdoc/store.rb +979 -0
  166. data/lib/rdoc/task.rb +84 -44
  167. data/lib/rdoc/text.rb +117 -72
  168. data/lib/rdoc/token_stream.rb +73 -4
  169. data/lib/rdoc/tom_doc.rb +263 -0
  170. data/lib/rdoc/top_level.rb +111 -261
  171. data/lib/rdoc/version.rb +8 -0
  172. data/lib/rdoc.rb +127 -64
  173. data/man/ri.1 +247 -0
  174. data/rdoc.gemspec +249 -0
  175. metadata +171 -291
  176. data/.autotest +0 -16
  177. data/.document +0 -5
  178. data/History.txt +0 -594
  179. data/LICENSE.txt +0 -57
  180. data/Manifest.txt +0 -158
  181. data/README.txt +0 -45
  182. data/RI.txt +0 -58
  183. data/bin/ri +0 -5
  184. data/lib/rdoc/gauntlet.rb +0 -52
  185. data/lib/rdoc/generator/template/darkfish/classpage.rhtml +0 -296
  186. data/lib/rdoc/generator/template/darkfish/filepage.rhtml +0 -124
  187. data/lib/rdoc/generator/template/darkfish/js/jquery.js +0 -32
  188. data/lib/rdoc/generator/template/darkfish/js/quicksearch.js +0 -114
  189. data/lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js +0 -10
  190. data/lib/rdoc/generator/template/darkfish/rdoc.css +0 -706
  191. data/lib/rdoc/markup/formatter_test_case.rb +0 -689
  192. data/lib/rdoc/markup/inline.rb +0 -137
  193. data/lib/rdoc/markup/text_formatter_test_case.rb +0 -116
  194. data/lib/rdoc/ruby_lex.rb +0 -1291
  195. data/lib/rdoc/ruby_token.rb +0 -416
  196. data/test/README +0 -1
  197. data/test/binary.dat +0 -0
  198. data/test/hidden.zip.txt +0 -1
  199. data/test/test.ja.rdoc +0 -10
  200. data/test/test.ja.txt +0 -8
  201. data/test/test.txt +0 -1
  202. data/test/test_attribute_manager.rb +0 -120
  203. data/test/test_rdoc_alias.rb +0 -13
  204. data/test/test_rdoc_any_method.rb +0 -126
  205. data/test/test_rdoc_attr.rb +0 -61
  206. data/test/test_rdoc_class_module.rb +0 -233
  207. data/test/test_rdoc_code_object.rb +0 -165
  208. data/test/test_rdoc_constant.rb +0 -15
  209. data/test/test_rdoc_context.rb +0 -370
  210. data/test/test_rdoc_encoding.rb +0 -166
  211. data/test/test_rdoc_generator_darkfish.rb +0 -119
  212. data/test/test_rdoc_generator_ri.rb +0 -76
  213. data/test/test_rdoc_include.rb +0 -96
  214. data/test/test_rdoc_markup.rb +0 -37
  215. data/test/test_rdoc_markup_attribute_manager.rb +0 -240
  216. data/test/test_rdoc_markup_document.rb +0 -51
  217. data/test/test_rdoc_markup_paragraph.rb +0 -9
  218. data/test/test_rdoc_markup_parser.rb +0 -1395
  219. data/test/test_rdoc_markup_pre_process.rb +0 -185
  220. data/test/test_rdoc_markup_raw.rb +0 -27
  221. data/test/test_rdoc_markup_to_ansi.rb +0 -328
  222. data/test/test_rdoc_markup_to_bs.rb +0 -341
  223. data/test/test_rdoc_markup_to_html.rb +0 -335
  224. data/test/test_rdoc_markup_to_html_crossref.rb +0 -169
  225. data/test/test_rdoc_markup_to_rdoc.rb +0 -327
  226. data/test/test_rdoc_method_attr.rb +0 -122
  227. data/test/test_rdoc_normal_class.rb +0 -17
  228. data/test/test_rdoc_normal_module.rb +0 -31
  229. data/test/test_rdoc_options.rb +0 -342
  230. data/test/test_rdoc_parser.rb +0 -83
  231. data/test/test_rdoc_parser_c.rb +0 -912
  232. data/test/test_rdoc_parser_ruby.rb +0 -1754
  233. data/test/test_rdoc_parser_simple.rb +0 -99
  234. data/test/test_rdoc_rdoc.rb +0 -164
  235. data/test/test_rdoc_require.rb +0 -25
  236. data/test/test_rdoc_ri_driver.rb +0 -846
  237. data/test/test_rdoc_ri_paths.rb +0 -43
  238. data/test/test_rdoc_ri_store.rb +0 -352
  239. data/test/test_rdoc_ruby_lex.rb +0 -23
  240. data/test/test_rdoc_stats.rb +0 -38
  241. data/test/test_rdoc_task.rb +0 -92
  242. data/test/test_rdoc_text.rb +0 -251
  243. data/test/test_rdoc_top_level.rb +0 -120
  244. data/test/xref_data.rb +0 -62
  245. data/test/xref_test_case.rb +0 -61
  246. data.tar.gz.sig +0 -3
  247. metadata.gz.sig +0 -0
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  ##
2
3
  # This file contains stuff stolen outright from:
3
4
  #
@@ -7,17 +8,6 @@
7
8
  # by Keiju ISHITSUKA (Nippon Rational Inc.)
8
9
  #
9
10
 
10
- require 'rdoc/ruby_token'
11
- require 'rdoc/ruby_lex'
12
-
13
- require 'rdoc/code_objects'
14
- require 'rdoc/token_stream'
15
- require 'rdoc/markup/pre_process'
16
- require 'rdoc/parser'
17
- require 'rdoc/parser/ruby_tools'
18
-
19
- $TOKEN_DEBUG ||= nil
20
-
21
11
  ##
22
12
  # Extracts code elements from a source file returning a TopLevel object
23
13
  # containing the constituent file elements.
@@ -32,6 +22,7 @@ $TOKEN_DEBUG ||= nil
32
22
  # * aliases
33
23
  # * private, public, protected
34
24
  # * private_class_function, public_class_function
25
+ # * private_constant, public_constant
35
26
  # * module_function
36
27
  # * attr, attr_reader, attr_writer, attr_accessor
37
28
  # * extra accessors given on the command line
@@ -103,7 +94,7 @@ $TOKEN_DEBUG ||= nil
103
94
  # You can force the name of a method using the :method: directive:
104
95
  #
105
96
  # ##
106
- # # :method: woo_hoo!
97
+ # # :method: some_method!
107
98
  #
108
99
  # By default, meta-methods are instance methods. To indicate that a method is
109
100
  # a singleton method instead use the :singleton-method: directive:
@@ -114,7 +105,10 @@ $TOKEN_DEBUG ||= nil
114
105
  # You can also use the :singleton-method: directive with a name:
115
106
  #
116
107
  # ##
117
- # # :singleton-method: woo_hoo!
108
+ # # :singleton-method: some_method!
109
+ #
110
+ # You can define arguments for metaprogrammed methods via either the
111
+ # :call-seq:, :arg: or :args: directives.
118
112
  #
119
113
  # Additionally you can mark a method as an attribute by
120
114
  # using :attr:, :attr_reader:, :attr_writer: or :attr_accessor:. Just like
@@ -144,11 +138,13 @@ $TOKEN_DEBUG ||= nil
144
138
  # Note that by default, the :method: directive will be ignored if there is a
145
139
  # standard rdocable item following it.
146
140
 
141
+ require 'ripper'
142
+ require_relative 'ripper_state_lex'
143
+
147
144
  class RDoc::Parser::Ruby < RDoc::Parser
148
145
 
149
146
  parse_files_matching(/\.rbw?$/)
150
147
 
151
- include RDoc::RubyToken
152
148
  include RDoc::TokenStream
153
149
  include RDoc::Parser::RubyTools
154
150
 
@@ -168,40 +164,110 @@ class RDoc::Parser::Ruby < RDoc::Parser
168
164
  def initialize(top_level, file_name, content, options, stats)
169
165
  super
170
166
 
167
+ if /\t/ =~ content then
168
+ tab_width = @options.tab_width
169
+ content = content.split(/\n/).map do |line|
170
+ 1 while line.gsub!(/\t+/) {
171
+ ' ' * (tab_width*$&.length - $`.length % tab_width)
172
+ } && $~
173
+ line
174
+ end.join("\n")
175
+ end
176
+
171
177
  @size = 0
172
178
  @token_listeners = nil
173
- @scanner = RDoc::RubyLex.new content, @options
174
- @scanner.exception_on_syntax_error = false
179
+ content = RDoc::Encoding.remove_magic_comment content
180
+ @scanner = RDoc::Parser::RipperStateLex.parse(content)
181
+ @content = content
182
+ @scanner_point = 0
175
183
  @prev_seek = nil
184
+ @markup = @options.markup
185
+ @track_visibility = :nodoc != @options.visibility
186
+ @encoding = @options.encoding
176
187
 
177
188
  reset
178
189
  end
179
190
 
191
+ def tk_nl?(tk)
192
+ :on_nl == tk[:kind] or :on_ignored_nl == tk[:kind]
193
+ end
194
+
195
+ ##
196
+ # Retrieves the read token stream and replaces +pattern+ with +replacement+
197
+ # using gsub. If the result is only a ";" returns an empty string.
198
+
199
+ def get_tkread_clean pattern, replacement # :nodoc:
200
+ read = get_tkread.gsub(pattern, replacement).strip
201
+ return '' if read == ';'
202
+ read
203
+ end
204
+
205
+ ##
206
+ # Extracts the visibility information for the visibility token +tk+
207
+ # and +single+ class type identifier.
208
+ #
209
+ # Returns the visibility type (a string), the visibility (a symbol) and
210
+ # +singleton+ if the methods following should be converted to singleton
211
+ # methods.
212
+
213
+ def get_visibility_information tk, single # :nodoc:
214
+ vis_type = tk[:text]
215
+ singleton = single == SINGLE
216
+
217
+ vis =
218
+ case vis_type
219
+ when 'private' then :private
220
+ when 'protected' then :protected
221
+ when 'public' then :public
222
+ when 'private_class_method' then
223
+ singleton = true
224
+ :private
225
+ when 'public_class_method' then
226
+ singleton = true
227
+ :public
228
+ when 'module_function' then
229
+ singleton = true
230
+ :public
231
+ else
232
+ raise RDoc::Error, "Invalid visibility: #{tk.name}"
233
+ end
234
+
235
+ return vis_type, vis, singleton
236
+ end
237
+
180
238
  ##
181
239
  # Look for the first comment in a file that isn't a shebang line.
182
240
 
183
241
  def collect_first_comment
184
242
  skip_tkspace
185
- comment = ''
243
+ comment = ''.dup
244
+ comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding
186
245
  first_line = true
246
+ first_comment_tk_kind = nil
247
+ line_no = nil
187
248
 
188
249
  tk = get_tk
189
250
 
190
- while TkCOMMENT === tk
191
- if first_line and tk.text =~ /\A#!/ then
251
+ while tk && (:on_comment == tk[:kind] or :on_embdoc == tk[:kind])
252
+ comment_body = retrieve_comment_body(tk)
253
+ if first_line and comment_body =~ /\A#!/ then
192
254
  skip_tkspace
193
255
  tk = get_tk
194
- elsif first_line and tk.text =~ /\A#\s*-\*-/ then
256
+ elsif first_line and comment_body =~ /\A#\s*-\*-/ then
195
257
  first_line = false
196
258
  skip_tkspace
197
259
  tk = get_tk
198
260
  else
261
+ break if first_comment_tk_kind and not first_comment_tk_kind === tk[:kind]
262
+ first_comment_tk_kind = tk[:kind]
263
+
264
+ line_no = tk[:line_no] if first_line
199
265
  first_line = false
200
- comment << tk.text << "\n"
266
+ comment << comment_body
201
267
  tk = get_tk
202
268
 
203
- if TkNL === tk then
204
- skip_tkspace false
269
+ if :on_nl === tk then
270
+ skip_tkspace_without_nl
205
271
  tk = get_tk
206
272
  end
207
273
  end
@@ -209,45 +275,61 @@ class RDoc::Parser::Ruby < RDoc::Parser
209
275
 
210
276
  unget_tk tk
211
277
 
212
- comment
278
+ new_comment comment, line_no
213
279
  end
214
280
 
215
281
  ##
216
- # Aborts with +msg+
282
+ # Consumes trailing whitespace from the token stream
217
283
 
218
- def error(msg)
219
- msg = make_message msg
284
+ def consume_trailing_spaces # :nodoc:
285
+ skip_tkspace_without_nl
286
+ end
220
287
 
221
- abort msg
288
+ ##
289
+ # Creates a new attribute in +container+ with +name+.
290
+
291
+ def create_attr container, single, name, rw, comment # :nodoc:
292
+ att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE
293
+ record_location att
294
+
295
+ container.add_attribute att
296
+ @stats.add_attribute att
297
+
298
+ att
222
299
  end
223
300
 
224
301
  ##
225
- # Look for a 'call-seq' in the comment, and override the normal parameter
226
- # stuff
227
- #--
228
- # TODO handle undent
302
+ # Creates a module alias in +container+ at +rhs_name+ (or at the top-level
303
+ # for "::") with the name from +constant+.
229
304
 
230
- def extract_call_seq(comment, meth)
231
- if comment.sub!(/:?call-seq:(.*?)(^\s*#?\s*$|\z)/m, '') then
232
- seq = $1
233
- seq.gsub!(/^\s*\#\s*/, '')
234
- meth.call_seq = seq
235
- end
305
+ def create_module_alias container, constant, rhs_name # :nodoc:
306
+ mod = if rhs_name =~ /^::/ then
307
+ @store.find_class_or_module rhs_name
308
+ else
309
+ container.find_module_named rhs_name
310
+ end
236
311
 
237
- meth
312
+ container.add_module_alias mod, rhs_name, constant, @top_level
313
+ end
314
+
315
+ ##
316
+ # Aborts with +msg+
317
+
318
+ def error(msg)
319
+ msg = make_message msg
320
+
321
+ abort msg
238
322
  end
239
323
 
240
324
  ##
241
- # Looks for a true or false token. Returns false if TkFALSE or TkNIL are
242
- # found.
325
+ # Looks for a true or false token.
243
326
 
244
327
  def get_bool
245
328
  skip_tkspace
246
329
  tk = get_tk
247
- case tk
248
- when TkTRUE
330
+ if :on_kw == tk[:kind] && 'true' == tk[:text]
249
331
  true
250
- when TkFALSE, TkNIL
332
+ elsif :on_kw == tk[:kind] && ('false' == tk[:text] || 'nil' == tk[:text])
251
333
  false
252
334
  else
253
335
  unget_tk tk
@@ -260,58 +342,87 @@ class RDoc::Parser::Ruby < RDoc::Parser
260
342
  # with :: separated named) and return the ultimate name, the associated
261
343
  # container, and the given name (with the ::).
262
344
 
263
- def get_class_or_module(container)
345
+ def get_class_or_module container, ignore_constants = false
264
346
  skip_tkspace
265
347
  name_t = get_tk
266
- given_name = ''
348
+ given_name = ''.dup
267
349
 
268
350
  # class ::A -> A is in the top level
269
- case name_t
270
- when TkCOLON2, TkCOLON3 then # bug
351
+ if :on_op == name_t[:kind] and '::' == name_t[:text] then # bug
271
352
  name_t = get_tk
272
353
  container = @top_level
273
354
  given_name << '::'
274
355
  end
275
356
 
276
- skip_tkspace false
277
- given_name << name_t.name
357
+ skip_tkspace_without_nl
358
+ given_name << name_t[:text]
278
359
 
279
- while TkCOLON2 === peek_tk do
360
+ is_self = name_t[:kind] == :on_op && name_t[:text] == '<<'
361
+ new_modules = []
362
+ while !is_self && (tk = peek_tk) and :on_op == tk[:kind] and '::' == tk[:text] do
280
363
  prev_container = container
281
- container = container.find_module_named name_t.name
282
- unless container then
283
- container = prev_container.add_module RDoc::NormalModule, name_t.name
284
- end
364
+ container = container.find_module_named name_t[:text]
365
+ container ||=
366
+ if ignore_constants then
367
+ c = RDoc::NormalModule.new name_t[:text]
368
+ c.store = @store
369
+ new_modules << [prev_container, c]
370
+ c
371
+ else
372
+ c = prev_container.add_module RDoc::NormalModule, name_t[:text]
373
+ c.ignore unless prev_container.document_children
374
+ @top_level.add_to_classes_or_modules c
375
+ c
376
+ end
377
+
378
+ record_location container
379
+
285
380
  get_tk
381
+ skip_tkspace
382
+ if :on_lparen == peek_tk[:kind] # ProcObjectInConstant::()
383
+ parse_method_or_yield_parameters
384
+ break
385
+ end
286
386
  name_t = get_tk
287
- given_name << '::' << name_t.name
387
+ unless :on_const == name_t[:kind] || :on_ident == name_t[:kind]
388
+ raise RDoc::Error, "Invalid class or module definition: #{given_name}"
389
+ end
390
+ if prev_container == container and !ignore_constants
391
+ given_name = name_t[:text]
392
+ else
393
+ given_name << '::' + name_t[:text]
394
+ end
288
395
  end
289
- skip_tkspace false
290
- return [container, name_t, given_name]
396
+
397
+ skip_tkspace_without_nl
398
+
399
+ return [container, name_t, given_name, new_modules]
291
400
  end
292
401
 
293
402
  ##
294
403
  # Return a superclass, which can be either a constant of an expression
295
404
 
296
405
  def get_class_specification
297
- tk = get_tk
298
- return "self" if TkSELF === tk
299
-
300
- res = ""
301
- while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do
302
- res += tk.name
303
- tk = get_tk
406
+ tk = peek_tk
407
+ if tk.nil?
408
+ return ''
409
+ elsif :on_kw == tk[:kind] && 'self' == tk[:text]
410
+ return 'self'
411
+ elsif :on_gvar == tk[:kind]
412
+ return ''
304
413
  end
305
414
 
306
- unget_tk(tk)
307
- skip_tkspace false
415
+ res = get_constant
416
+
417
+ skip_tkspace_without_nl
308
418
 
309
419
  get_tkread # empty out read buffer
310
420
 
311
421
  tk = get_tk
422
+ return res unless tk
312
423
 
313
- case tk
314
- when TkNL, TkCOMMENT, TkSEMICOLON then
424
+ case tk[:kind]
425
+ when :on_nl, :on_comment, :on_embdoc, :on_semicolon then
315
426
  unget_tk(tk)
316
427
  return res
317
428
  end
@@ -326,42 +437,164 @@ class RDoc::Parser::Ruby < RDoc::Parser
326
437
 
327
438
  def get_constant
328
439
  res = ""
329
- skip_tkspace false
440
+ skip_tkspace_without_nl
330
441
  tk = get_tk
331
442
 
332
- while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do
333
- res += tk.name
443
+ while tk && ((:on_op == tk[:kind] && '::' == tk[:text]) || :on_const == tk[:kind]) do
444
+ res += tk[:text]
334
445
  tk = get_tk
335
446
  end
336
447
 
337
- # if res.empty?
338
- # warn("Unexpected token #{tk} in constant")
339
- # end
340
448
  unget_tk(tk)
341
449
  res
342
450
  end
343
451
 
344
452
  ##
345
- # Get a constant that may be surrounded by parens
453
+ # Get an included module that may be surrounded by parens
454
+
455
+ def get_included_module_with_optional_parens
456
+ skip_tkspace_without_nl
457
+ get_tkread
458
+ tk = get_tk
459
+ end_token = get_end_token tk
460
+ return '' unless end_token
346
461
 
347
- def get_constant_with_optional_parens
348
- skip_tkspace false
349
462
  nest = 0
350
- while TkLPAREN === (tk = peek_tk) or TkfLPAREN === tk do
351
- get_tk
352
- skip_tkspace
353
- nest += 1
463
+ continue = false
464
+ only_constant = true
465
+
466
+ while tk != nil do
467
+ is_element_of_constant = false
468
+ case tk[:kind]
469
+ when :on_semicolon then
470
+ break if nest == 0
471
+ when :on_lbracket then
472
+ nest += 1
473
+ when :on_rbracket then
474
+ nest -= 1
475
+ when :on_lbrace then
476
+ nest += 1
477
+ when :on_rbrace then
478
+ nest -= 1
479
+ if nest <= 0
480
+ # we might have a.each { |i| yield i }
481
+ unget_tk(tk) if nest < 0
482
+ break
483
+ end
484
+ when :on_lparen then
485
+ nest += 1
486
+ when end_token[:kind] then
487
+ if end_token[:kind] == :on_rparen
488
+ nest -= 1
489
+ break if nest <= 0
490
+ else
491
+ break if nest <= 0
492
+ end
493
+ when :on_rparen then
494
+ nest -= 1
495
+ when :on_comment, :on_embdoc then
496
+ @read.pop
497
+ if :on_nl == end_token[:kind] and "\n" == tk[:text][-1] and
498
+ (!continue or (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0) then
499
+ break if !continue and nest <= 0
500
+ end
501
+ when :on_comma then
502
+ continue = true
503
+ when :on_ident then
504
+ continue = false if continue
505
+ when :on_kw then
506
+ case tk[:text]
507
+ when 'def', 'do', 'case', 'for', 'begin', 'class', 'module'
508
+ nest += 1
509
+ when 'if', 'unless', 'while', 'until', 'rescue'
510
+ # postfix if/unless/while/until/rescue must be EXPR_LABEL
511
+ nest += 1 unless (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0
512
+ when 'end'
513
+ nest -= 1
514
+ break if nest == 0
515
+ end
516
+ when :on_const then
517
+ is_element_of_constant = true
518
+ when :on_op then
519
+ is_element_of_constant = true if '::' == tk[:text]
520
+ end
521
+ only_constant = false unless is_element_of_constant
522
+ tk = get_tk
354
523
  end
355
524
 
356
- name = get_constant
525
+ if only_constant
526
+ get_tkread_clean(/\s+/, ' ')
527
+ else
528
+ ''
529
+ end
530
+ end
357
531
 
358
- while nest > 0
359
- skip_tkspace
360
- tk = get_tk
361
- nest -= 1 if TkRPAREN === tk
532
+ ##
533
+ # Little hack going on here. In the statement:
534
+ #
535
+ # f = 2*(1+yield)
536
+ #
537
+ # We see the RPAREN as the next token, so we need to exit early. This still
538
+ # won't catch all cases (such as "a = yield + 1"
539
+
540
+ def get_end_token tk # :nodoc:
541
+ case tk[:kind]
542
+ when :on_lparen
543
+ token = RDoc::Parser::RipperStateLex::Token.new
544
+ token[:kind] = :on_rparen
545
+ token[:text] = ')'
546
+ token
547
+ when :on_rparen
548
+ nil
549
+ else
550
+ token = RDoc::Parser::RipperStateLex::Token.new
551
+ token[:kind] = :on_nl
552
+ token[:text] = "\n"
553
+ token
554
+ end
555
+ end
556
+
557
+ ##
558
+ # Retrieves the method container for a singleton method.
559
+
560
+ def get_method_container container, name_t # :nodoc:
561
+ prev_container = container
562
+ container = container.find_module_named(name_t[:text])
563
+
564
+ unless container then
565
+ constant = prev_container.constants.find do |const|
566
+ const.name == name_t[:text]
567
+ end
568
+
569
+ if constant then
570
+ parse_method_dummy prev_container
571
+ return
572
+ end
573
+ end
574
+
575
+ unless container then
576
+ # TODO seems broken, should starting at Object in @store
577
+ obj = name_t[:text].split("::").inject(Object) do |state, item|
578
+ state.const_get(item)
579
+ end rescue nil
580
+
581
+ type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule
582
+
583
+ unless [Class, Module].include?(obj.class) then
584
+ warn("Couldn't find #{name_t[:text]}. Assuming it's a module")
585
+ end
586
+
587
+ if type == RDoc::NormalClass then
588
+ sclass = obj.superclass ? obj.superclass.name : nil
589
+ container = prev_container.add_class type, name_t[:text], sclass
590
+ else
591
+ container = prev_container.add_module type, name_t[:text]
592
+ end
593
+
594
+ record_location container
362
595
  end
363
596
 
364
- name
597
+ container
365
598
  end
366
599
 
367
600
  ##
@@ -369,28 +602,36 @@ class RDoc::Parser::Ruby < RDoc::Parser
369
602
 
370
603
  def get_symbol_or_name
371
604
  tk = get_tk
372
- case tk
373
- when TkSYMBOL then
374
- text = tk.text.sub(/^:/, '')
605
+ case tk[:kind]
606
+ when :on_symbol then
607
+ text = tk[:text].sub(/^:/, '')
375
608
 
376
- if TkASSIGN === peek_tk then
609
+ next_tk = peek_tk
610
+ if next_tk && :on_op == next_tk[:kind] && '=' == next_tk[:text] then
377
611
  get_tk
378
612
  text << '='
379
613
  end
380
614
 
381
615
  text
382
- when TkId, TkOp then
383
- tk.name
384
- when TkAMPER,
385
- TkDSTRING,
386
- TkSTAR,
387
- TkSTRING then
388
- tk.text
616
+ when :on_ident, :on_const, :on_gvar, :on_cvar, :on_ivar, :on_op, :on_kw then
617
+ tk[:text]
618
+ when :on_tstring, :on_dstring then
619
+ tk[:text][1..-2]
389
620
  else
390
621
  raise RDoc::Error, "Name or symbol expected (got #{tk})"
391
622
  end
392
623
  end
393
624
 
625
+ ##
626
+ # Marks containers between +container+ and +ancestor+ as ignored
627
+
628
+ def suppress_parents container, ancestor # :nodoc:
629
+ while container and container != ancestor do
630
+ container.suppress unless container.documented?
631
+ container = container.parent
632
+ end
633
+ end
634
+
394
635
  ##
395
636
  # Look for directives in a normal comment block:
396
637
  #
@@ -399,77 +640,69 @@ class RDoc::Parser::Ruby < RDoc::Parser
399
640
  #
400
641
  # This routine modifies its +comment+ parameter.
401
642
 
402
- def look_for_directives_in(context, comment)
403
- preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
404
-
405
- preprocess.handle comment, context do |directive, param|
643
+ def look_for_directives_in container, comment
644
+ @preprocess.handle comment, container do |directive, param|
406
645
  case directive
407
- when 'enddoc' then
408
- context.done_documenting = true
409
- ''
410
- when 'main' then
411
- @options.main_page = param if @options.respond_to? :main_page
412
- ''
413
646
  when 'method', 'singleton-method',
414
647
  'attr', 'attr_accessor', 'attr_reader', 'attr_writer' then
415
648
  false # handled elsewhere
416
649
  when 'section' then
417
- context.set_current_section param, comment
418
- comment.replace ''
650
+ break unless container.kind_of?(RDoc::Context)
651
+ container.set_current_section param, comment.dup
652
+ comment.text = ''
419
653
  break
420
- when 'startdoc' then
421
- context.start_doc
422
- context.force_documentation = true
423
- ''
424
- when 'stopdoc' then
425
- context.stop_doc
426
- ''
427
- when 'title' then
428
- @options.default_title = param if @options.respond_to? :default_title=
429
- ''
430
654
  end
431
655
  end
432
656
 
433
- remove_private_comments comment
657
+ comment.remove_private
434
658
  end
435
659
 
436
660
  ##
437
661
  # Adds useful info about the parser to +message+
438
662
 
439
663
  def make_message message
440
- prefix = "#{@file_name}:"
664
+ prefix = "#{@file_name}:".dup
441
665
 
442
- prefix << "#{@scanner.line_no}:#{@scanner.char_no}:" if @scanner
666
+ tk = peek_tk
667
+ prefix << "#{tk[:line_no]}:#{tk[:char_no]}:" if tk
443
668
 
444
669
  "#{prefix} #{message}"
445
670
  end
446
671
 
672
+ ##
673
+ # Creates a comment with the correct format
674
+
675
+ def new_comment comment, line_no = nil
676
+ c = RDoc::Comment.new comment, @top_level, :ruby
677
+ c.line = line_no
678
+ c.format = @markup
679
+ c
680
+ end
681
+
447
682
  ##
448
683
  # Creates an RDoc::Attr for the name following +tk+, setting the comment to
449
684
  # +comment+.
450
685
 
451
686
  def parse_attr(context, single, tk, comment)
687
+ line_no = tk[:line_no]
688
+
452
689
  args = parse_symbol_arg 1
453
690
  if args.size > 0 then
454
691
  name = args[0]
455
692
  rw = "R"
456
- skip_tkspace false
693
+ skip_tkspace_without_nl
457
694
  tk = get_tk
458
695
 
459
- if TkCOMMA === tk then
696
+ if :on_comma == tk[:kind] then
460
697
  rw = "RW" if get_bool
461
698
  else
462
699
  unget_tk tk
463
700
  end
464
701
 
465
- att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE
466
- att.record_location @top_level
702
+ att = create_attr context, single, name, rw, comment
703
+ att.line = line_no
467
704
 
468
705
  read_documentation_modifiers att, RDoc::ATTR_MODIFIERS
469
-
470
- context.add_attribute att if att.document_self
471
-
472
- @stats.add_attribute att
473
706
  else
474
707
  warn "'attr' ignored - looks like a variable"
475
708
  end
@@ -480,14 +713,18 @@ class RDoc::Parser::Ruby < RDoc::Parser
480
713
  # comment for each to +comment+.
481
714
 
482
715
  def parse_attr_accessor(context, single, tk, comment)
716
+ line_no = tk[:line_no]
717
+
483
718
  args = parse_symbol_arg
484
719
  rw = "?"
485
720
 
486
721
  tmp = RDoc::CodeObject.new
487
722
  read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS
488
- return unless tmp.document_self
723
+ # TODO In most other places we let the context keep track of document_self
724
+ # and add found items appropriately but here we do not. I'm not sure why.
725
+ return if @track_visibility and not tmp.document_self
489
726
 
490
- case tk.name
727
+ case tk[:text]
491
728
  when "attr_reader" then rw = "R"
492
729
  when "attr_writer" then rw = "W"
493
730
  when "attr_accessor" then rw = "RW"
@@ -496,11 +733,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
496
733
  end
497
734
 
498
735
  for name in args
499
- att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE
500
- att.record_location @top_level
501
-
502
- context.add_attribute att
503
- @stats.add_attribute att
736
+ att = create_attr context, single, name, rw, comment
737
+ att.line = line_no
504
738
  end
505
739
  end
506
740
 
@@ -508,19 +742,19 @@ class RDoc::Parser::Ruby < RDoc::Parser
508
742
  # Parses an +alias+ in +context+ with +comment+
509
743
 
510
744
  def parse_alias(context, single, tk, comment)
745
+ line_no = tk[:line_no]
746
+
511
747
  skip_tkspace
512
748
 
513
- if TkLPAREN === peek_tk then
749
+ if :on_lparen === peek_tk[:kind] then
514
750
  get_tk
515
751
  skip_tkspace
516
752
  end
517
753
 
518
754
  new_name = get_symbol_or_name
519
755
 
520
- @scanner.instance_eval { @lex_state = EXPR_FNAME }
521
-
522
756
  skip_tkspace
523
- if TkCOMMA === peek_tk then
757
+ if :on_comma === peek_tk[:kind] then
524
758
  get_tk
525
759
  skip_tkspace
526
760
  end
@@ -533,10 +767,11 @@ class RDoc::Parser::Ruby < RDoc::Parser
533
767
 
534
768
  al = RDoc::Alias.new(get_tkread, old_name, new_name, comment,
535
769
  single == SINGLE)
536
- al.record_location @top_level
770
+ record_location al
771
+ al.line = line_no
537
772
 
538
773
  read_documentation_modifiers al, RDoc::ATTR_MODIFIERS
539
- context.add_alias al if al.document_self
774
+ context.add_alias al
540
775
  @stats.add_alias al
541
776
 
542
777
  al
@@ -546,260 +781,458 @@ class RDoc::Parser::Ruby < RDoc::Parser
546
781
  # Extracts call parameters from the token stream.
547
782
 
548
783
  def parse_call_parameters(tk)
549
- end_token = case tk
550
- when TkLPAREN, TkfLPAREN
551
- TkRPAREN
552
- when TkRPAREN
784
+ end_token = case tk[:kind]
785
+ when :on_lparen
786
+ :on_rparen
787
+ when :on_rparen
553
788
  return ""
554
789
  else
555
- TkNL
790
+ :on_nl
556
791
  end
557
792
  nest = 0
558
793
 
559
794
  loop do
560
- case tk
561
- when TkSEMICOLON
795
+ break if tk.nil?
796
+ case tk[:kind]
797
+ when :on_semicolon
562
798
  break
563
- when TkLPAREN, TkfLPAREN
799
+ when :on_lparen
564
800
  nest += 1
565
801
  when end_token
566
- if end_token == TkRPAREN
802
+ if end_token == :on_rparen
567
803
  nest -= 1
568
- break if @scanner.lex_state == EXPR_END and nest <= 0
804
+ break if RDoc::Parser::RipperStateLex.end?(tk) and nest <= 0
569
805
  else
570
- break unless @scanner.continue
806
+ break if RDoc::Parser::RipperStateLex.end?(tk)
571
807
  end
572
- when TkCOMMENT, TkASSIGN, TkOPASGN
808
+ when :on_comment, :on_embdoc
573
809
  unget_tk(tk)
574
810
  break
575
- when nil then
576
- break
811
+ when :on_op
812
+ if tk[:text] =~ /^(.{1,2})?=$/
813
+ unget_tk(tk)
814
+ break
815
+ end
577
816
  end
578
817
  tk = get_tk
579
818
  end
580
- res = get_tkread.tr("\n", " ").strip
581
- res = "" if res == ";"
582
- res
819
+
820
+ get_tkread_clean "\n", " "
583
821
  end
584
822
 
585
823
  ##
586
824
  # Parses a class in +context+ with +comment+
587
825
 
588
- def parse_class(container, single, tk, comment)
589
- declaration_context = container
590
- container, name_t, given_name = get_class_or_module container
826
+ def parse_class container, single, tk, comment
827
+ line_no = tk[:line_no]
591
828
 
592
- case name_t
593
- when TkCONSTANT
594
- name = name_t.name
595
- superclass = '::Object'
829
+ declaration_context = container
830
+ container, name_t, given_name, = get_class_or_module container
596
831
 
597
- if TkLT === peek_tk then
598
- get_tk
599
- skip_tkspace
600
- superclass = get_class_specification
601
- superclass = '(unknown)' if superclass.empty?
832
+ if name_t[:kind] == :on_const
833
+ cls = parse_class_regular container, declaration_context, single,
834
+ name_t, given_name, comment
835
+ elsif name_t[:kind] == :on_op && name_t[:text] == '<<'
836
+ case name = get_class_specification
837
+ when 'self', container.name
838
+ read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
839
+ parse_statements container, SINGLE
840
+ return # don't update line
841
+ else
842
+ cls = parse_class_singleton container, name, comment
602
843
  end
844
+ else
845
+ warn "Expected class name or '<<'. Got #{name_t[:kind]}: #{name_t[:text].inspect}"
846
+ return
847
+ end
603
848
 
604
- cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass
605
- cls = declaration_context.add_class cls_type, given_name, superclass
849
+ cls.line = line_no
606
850
 
607
- read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
608
- cls.record_location @top_level
609
- cls.comment = comment if cls.document_self
851
+ # after end modifiers
852
+ read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
610
853
 
611
- @top_level.add_to_classes_or_modules cls
612
- @stats.add_class cls
854
+ cls
855
+ end
613
856
 
614
- parse_statements cls
615
- when TkLSHFT
616
- case name = get_class_specification
617
- when "self", container.name
618
- parse_statements container, SINGLE
619
- else
620
- other = RDoc::TopLevel.find_class_named name
857
+ ##
858
+ # Parses and creates a regular class
621
859
 
622
- unless other then
623
- other = container.add_module RDoc::NormalModule, name
624
- other.record_location @top_level
625
- other.comment = comment
626
- end
860
+ def parse_class_regular container, declaration_context, single, # :nodoc:
861
+ name_t, given_name, comment
862
+ superclass = '::Object'
627
863
 
628
- # notify :nodoc: all if not a constant-named class/module
629
- # (and remove any comment)
630
- unless name =~ /\A(::)?[A-Z]/
631
- other.document_self = nil
632
- other.document_children = false
633
- other.clear_comment
634
- end
864
+ if given_name =~ /^::/ then
865
+ declaration_context = @top_level
866
+ given_name = $'
867
+ end
868
+
869
+ tk = peek_tk
870
+ if tk[:kind] == :on_op && tk[:text] == '<' then
871
+ get_tk
872
+ skip_tkspace
873
+ superclass = get_class_specification
874
+ superclass = '(unknown)' if superclass.empty?
875
+ end
876
+
877
+ cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass
878
+ cls = declaration_context.add_class cls_type, given_name, superclass
879
+ cls.ignore unless container.document_children
880
+
881
+ read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
882
+ record_location cls
883
+
884
+ cls.add_comment comment, @top_level
885
+
886
+ @top_level.add_to_classes_or_modules cls
887
+ @stats.add_class cls
888
+
889
+ suppress_parents container, declaration_context unless cls.document_self
890
+
891
+ parse_statements cls
892
+
893
+ cls
894
+ end
635
895
 
636
- @top_level.add_to_classes_or_modules other
637
- @stats.add_class other
896
+ ##
897
+ # Parses a singleton class in +container+ with the given +name+ and
898
+ # +comment+.
638
899
 
639
- read_documentation_modifiers other, RDoc::CLASS_MODIFIERS
640
- parse_statements(other, SINGLE)
900
+ def parse_class_singleton container, name, comment # :nodoc:
901
+ other = @store.find_class_named name
902
+
903
+ unless other then
904
+ if name =~ /^::/ then
905
+ name = $'
906
+ container = @top_level
641
907
  end
642
908
 
643
- else
644
- warn("Expected class name or '<<'. Got #{name_t.class}: #{name_t.text.inspect}")
909
+ other = container.add_module RDoc::NormalModule, name
910
+ record_location other
911
+
912
+ # class << $gvar
913
+ other.ignore if name.empty?
914
+
915
+ other.add_comment comment, @top_level
916
+ end
917
+
918
+ # notify :nodoc: all if not a constant-named class/module
919
+ # (and remove any comment)
920
+ unless name =~ /\A(::)?[A-Z]/ then
921
+ other.document_self = nil
922
+ other.document_children = false
923
+ other.clear_comment
645
924
  end
925
+
926
+ @top_level.add_to_classes_or_modules other
927
+ @stats.add_class other
928
+
929
+ read_documentation_modifiers other, RDoc::CLASS_MODIFIERS
930
+ parse_statements(other, SINGLE)
931
+
932
+ other
646
933
  end
647
934
 
648
935
  ##
649
- # Parses a constant in +context+ with +comment+
936
+ # Parses a constant in +context+ with +comment+. If +ignore_constants+ is
937
+ # true, no found constants will be added to RDoc.
938
+
939
+ def parse_constant container, tk, comment, ignore_constants = false
940
+ line_no = tk[:line_no]
650
941
 
651
- def parse_constant(container, tk, comment)
652
- name = tk.name
653
- skip_tkspace false
942
+ name = tk[:text]
943
+ skip_tkspace_without_nl
654
944
 
655
945
  return unless name =~ /^\w+$/
656
946
 
657
- eq_tk = get_tk
947
+ new_modules = []
948
+ if :on_op == peek_tk[:kind] && '::' == peek_tk[:text] then
949
+ unget_tk tk
658
950
 
659
- unless TkASSIGN === eq_tk then
660
- unget_tk eq_tk
661
- return
951
+ container, name_t, _, new_modules = get_class_or_module container, true
952
+
953
+ name = name_t[:text]
662
954
  end
663
955
 
664
- nest = 0
665
- get_tkread
956
+ is_array_or_hash = false
957
+ if peek_tk && :on_lbracket == peek_tk[:kind]
958
+ get_tk
959
+ nest = 1
960
+ while bracket_tk = get_tk
961
+ case bracket_tk[:kind]
962
+ when :on_lbracket
963
+ nest += 1
964
+ when :on_rbracket
965
+ nest -= 1
966
+ break if nest == 0
967
+ end
968
+ end
969
+ skip_tkspace_without_nl
970
+ is_array_or_hash = true
971
+ end
666
972
 
667
- tk = get_tk
973
+ unless peek_tk && :on_op == peek_tk[:kind] && '=' == peek_tk[:text] then
974
+ return false
975
+ end
976
+ get_tk
668
977
 
669
- if TkGT === tk then
670
- unget_tk tk
671
- unget_tk eq_tk
672
- return
978
+ unless ignore_constants
979
+ new_modules.each do |prev_c, new_module|
980
+ prev_c.add_module_by_normal_module new_module
981
+ new_module.ignore unless prev_c.document_children
982
+ @top_level.add_to_classes_or_modules new_module
983
+ end
673
984
  end
674
985
 
675
- rhs_name = ''
986
+ value = ''
987
+ con = RDoc::Constant.new name, value, comment
988
+
989
+ body = parse_constant_body container, con, is_array_or_hash
990
+
991
+ return unless body
992
+
993
+ con.value = body
994
+ record_location con
995
+ con.line = line_no
996
+ read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
997
+
998
+ return if is_array_or_hash
999
+
1000
+ @stats.add_constant con
1001
+ container.add_constant con
1002
+
1003
+ true
1004
+ end
1005
+
1006
+ def parse_constant_body container, constant, is_array_or_hash # :nodoc:
1007
+ nest = 0
1008
+ rhs_name = ''.dup
1009
+
1010
+ get_tkread
1011
+
1012
+ tk = get_tk
676
1013
 
1014
+ body = nil
677
1015
  loop do
678
- case tk
679
- when TkSEMICOLON then
1016
+ break if tk.nil?
1017
+ if :on_semicolon == tk[:kind] then
680
1018
  break if nest <= 0
681
- when TkLPAREN, TkfLPAREN, TkLBRACE, TkfLBRACE, TkLBRACK, TkfLBRACK,
682
- TkDO, TkIF, TkUNLESS, TkCASE, TkDEF, TkBEGIN then
1019
+ elsif [:on_tlambeg, :on_lparen, :on_lbrace, :on_lbracket].include?(tk[:kind]) then
1020
+ nest += 1
1021
+ elsif (:on_kw == tk[:kind] && 'def' == tk[:text]) then
683
1022
  nest += 1
684
- when TkRPAREN, TkRBRACE, TkRBRACK, TkEND then
1023
+ elsif (:on_kw == tk[:kind] && %w{do if unless case begin}.include?(tk[:text])) then
1024
+ if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0
1025
+ nest += 1
1026
+ end
1027
+ elsif [:on_rparen, :on_rbrace, :on_rbracket].include?(tk[:kind]) ||
1028
+ (:on_kw == tk[:kind] && 'end' == tk[:text]) then
685
1029
  nest -= 1
686
- when TkCOMMENT then
687
- if nest <= 0 && @scanner.lex_state == EXPR_END
688
- unget_tk tk
1030
+ elsif (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) then
1031
+ unget_tk tk
1032
+ if nest <= 0 and RDoc::Parser::RipperStateLex.end?(tk) then
1033
+ body = get_tkread_clean(/^[ \t]+/, '')
1034
+ read_documentation_modifiers constant, RDoc::CONSTANT_MODIFIERS
689
1035
  break
1036
+ else
1037
+ read_documentation_modifiers constant, RDoc::CONSTANT_MODIFIERS
690
1038
  end
691
- when TkCONSTANT then
692
- rhs_name << tk.name
693
-
694
- if nest <= 0 and TkNL === peek_tk then
695
- mod = if rhs_name =~ /^::/ then
696
- RDoc::TopLevel.find_class_or_module rhs_name
697
- else
698
- container.find_module_named rhs_name
699
- end
1039
+ elsif :on_const == tk[:kind] then
1040
+ rhs_name << tk[:text]
700
1041
 
701
- container.add_module_alias mod, name if mod
702
- get_tk # TkNL
1042
+ next_tk = peek_tk
1043
+ if nest <= 0 and (next_tk.nil? || :on_nl == next_tk[:kind]) then
1044
+ create_module_alias container, constant, rhs_name unless is_array_or_hash
703
1045
  break
704
1046
  end
705
- when TkNL then
706
- if nest <= 0 &&
707
- (@scanner.lex_state == EXPR_END || !@scanner.continue) then
1047
+ elsif :on_nl == tk[:kind] then
1048
+ if nest <= 0 and RDoc::Parser::RipperStateLex.end?(tk) then
708
1049
  unget_tk tk
709
1050
  break
710
1051
  end
711
- when TkCOLON2, TkCOLON3 then
1052
+ elsif :on_op == tk[:kind] && '::' == tk[:text]
712
1053
  rhs_name << '::'
713
- when nil then
714
- break
715
1054
  end
716
1055
  tk = get_tk
717
1056
  end
718
1057
 
719
- res = get_tkread.gsub(/^[ \t]+/, '').strip
720
- res = "" if res == ";"
721
-
722
- con = RDoc::Constant.new name, res, comment
723
- con.record_location @top_level
724
- read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
725
-
726
- @stats.add_constant con
727
- container.add_constant con if con.document_self
1058
+ body ? body : get_tkread_clean(/^[ \t]+/, '')
728
1059
  end
729
1060
 
730
1061
  ##
731
1062
  # Generates an RDoc::Method or RDoc::Attr from +comment+ by looking for
732
1063
  # :method: or :attr: directives in +comment+.
733
1064
 
734
- def parse_comment(container, tk, comment)
735
- line_no = tk.line_no
736
- column = tk.char_no
1065
+ def parse_comment container, tk, comment
1066
+ return parse_comment_tomdoc container, tk, comment if @markup == 'tomdoc'
1067
+ column = tk[:char_no]
1068
+ line_no = comment.line.nil? ? tk[:line_no] : comment.line
1069
+
1070
+ comment.text = comment.text.sub(/(^# +:?)(singleton-)(method:)/, '\1\3')
1071
+ singleton = !!$~
737
1072
 
738
- singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
1073
+ co =
1074
+ if (comment.text = comment.text.sub(/^# +:?method: *(\S*).*?\n/i, '')) && !!$~ then
1075
+ line_no += $`.count("\n")
1076
+ parse_comment_ghost container, comment.text, $1, column, line_no, comment
1077
+ elsif (comment.text = comment.text.sub(/# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i, '')) && !!$~ then
1078
+ parse_comment_attr container, $1, $3, comment
1079
+ end
739
1080
 
740
- # REFACTOR
741
- if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
742
- name = $1 unless $1.empty?
1081
+ if co then
1082
+ co.singleton = singleton
1083
+ co.line = line_no
1084
+ end
743
1085
 
744
- meth = RDoc::GhostMethod.new get_tkread, name
745
- meth.record_location @top_level
746
- meth.singleton = singleton
1086
+ true
1087
+ end
747
1088
 
748
- meth.start_collecting_tokens
749
- indent = TkSPACE.new nil, 1, 1
750
- indent.set_text " " * column
1089
+ ##
1090
+ # Parse a comment that is describing an attribute in +container+ with the
1091
+ # given +name+ and +comment+.
751
1092
 
752
- position_comment = TkCOMMENT.new nil, line_no, 1
753
- position_comment.set_text "# File #{@top_level.absolute_name}, line #{line_no}"
754
- meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
1093
+ def parse_comment_attr container, type, name, comment # :nodoc:
1094
+ return if name.empty?
755
1095
 
756
- meth.params = ''
1096
+ rw = case type
1097
+ when 'attr_reader' then 'R'
1098
+ when 'attr_writer' then 'W'
1099
+ else 'RW'
1100
+ end
757
1101
 
758
- extract_call_seq comment, meth
1102
+ create_attr container, NORMAL, name, rw, comment
1103
+ end
759
1104
 
760
- return unless meth.name
1105
+ def parse_comment_ghost container, text, name, column, line_no, # :nodoc:
1106
+ comment
1107
+ name = nil if name.empty?
761
1108
 
762
- container.add_method meth if meth.document_self
1109
+ meth = RDoc::GhostMethod.new get_tkread, name
1110
+ record_location meth
763
1111
 
764
- meth.comment = comment
1112
+ meth.start_collecting_tokens
1113
+ indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column)
1114
+ position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment)
1115
+ position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}"
1116
+ newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n")
1117
+ meth.add_tokens [position_comment, newline, indent]
1118
+
1119
+ meth.params =
1120
+ if text.sub!(/^#\s+:?args?:\s*(.*?)\s*$/i, '') then
1121
+ $1
1122
+ else
1123
+ ''
1124
+ end
765
1125
 
766
- @stats.add_method meth
767
- elsif comment.sub!(/# +:?(attr(_reader|_writer|_accessor)?:) *(\S*).*?\n/i, '') then
768
- rw = case $1
769
- when 'attr_reader' then 'R'
770
- when 'attr_writer' then 'W'
771
- else 'RW'
772
- end
1126
+ comment.normalize
1127
+ comment.extract_call_seq meth
773
1128
 
774
- name = $3 unless $3.empty?
1129
+ return unless meth.name
775
1130
 
776
- # TODO authorize 'singleton-attr...'?
777
- att = RDoc::Attr.new get_tkread, name, rw, comment
778
- att.record_location @top_level
1131
+ container.add_method meth
779
1132
 
780
- container.add_attribute att
1133
+ meth.comment = comment
781
1134
 
782
- @stats.add_attribute att
783
- end
1135
+ @stats.add_method meth
784
1136
 
785
- true
1137
+ meth
786
1138
  end
787
1139
 
788
1140
  ##
789
- # Parses an +include+ in +context+ with +comment+
1141
+ # Creates an RDoc::Method on +container+ from +comment+ if there is a
1142
+ # Signature section in the comment
790
1143
 
791
- def parse_include(context, comment)
1144
+ def parse_comment_tomdoc container, tk, comment
1145
+ return unless signature = RDoc::TomDoc.signature(comment)
1146
+ column = tk[:char_no]
1147
+ line_no = tk[:line_no]
1148
+
1149
+ name, = signature.split %r%[ \(]%, 2
1150
+
1151
+ meth = RDoc::GhostMethod.new get_tkread, name
1152
+ record_location meth
1153
+ meth.line = line_no
1154
+
1155
+ meth.start_collecting_tokens
1156
+ indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column)
1157
+ position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment)
1158
+ position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}"
1159
+ newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n")
1160
+ meth.add_tokens [position_comment, newline, indent]
1161
+
1162
+ meth.call_seq = signature
1163
+
1164
+ comment.normalize
1165
+
1166
+ return unless meth.name
1167
+
1168
+ container.add_method meth
1169
+
1170
+ meth.comment = comment
1171
+
1172
+ @stats.add_method meth
1173
+ end
1174
+
1175
+ ##
1176
+ # Parses an +include+ or +extend+, indicated by the +klass+ and adds it to
1177
+ # +container+ # with +comment+
1178
+
1179
+ def parse_extend_or_include klass, container, comment # :nodoc:
792
1180
  loop do
793
1181
  skip_tkspace_comment
794
1182
 
795
- name = get_constant_with_optional_parens
796
- context.add_include RDoc::Include.new(name, comment) unless name.empty?
1183
+ name = get_included_module_with_optional_parens
1184
+
1185
+ unless name.empty? then
1186
+ obj = container.add klass, name, comment
1187
+ record_location obj
1188
+ end
1189
+
1190
+ return if peek_tk.nil? || :on_comma != peek_tk[:kind]
797
1191
 
798
- return unless TkCOMMA === peek_tk
799
1192
  get_tk
800
1193
  end
801
1194
  end
802
1195
 
1196
+ ##
1197
+ # Parses identifiers that can create new methods or change visibility.
1198
+ #
1199
+ # Returns true if the comment was not consumed.
1200
+
1201
+ def parse_identifier container, single, tk, comment # :nodoc:
1202
+ case tk[:text]
1203
+ when 'private', 'protected', 'public', 'private_class_method',
1204
+ 'public_class_method', 'module_function' then
1205
+ parse_visibility container, single, tk
1206
+ return true
1207
+ when 'private_constant', 'public_constant'
1208
+ parse_constant_visibility container, single, tk
1209
+ return true
1210
+ when 'attr' then
1211
+ parse_attr container, single, tk, comment
1212
+ when /^attr_(reader|writer|accessor)$/ then
1213
+ parse_attr_accessor container, single, tk, comment
1214
+ when 'alias_method' then
1215
+ parse_alias container, single, tk, comment
1216
+ when 'require', 'include' then
1217
+ # ignore
1218
+ else
1219
+ if comment.text =~ /\A#\#$/ then
1220
+ case comment.text
1221
+ when /^# +:?attr(_reader|_writer|_accessor)?:/ then
1222
+ parse_meta_attr container, single, tk, comment
1223
+ else
1224
+ method = parse_meta_method container, single, tk, comment
1225
+ method.params = container.params if
1226
+ container.params
1227
+ method.block_params = container.block_params if
1228
+ container.block_params
1229
+ end
1230
+ end
1231
+ end
1232
+
1233
+ false
1234
+ end
1235
+
803
1236
  ##
804
1237
  # Parses a meta-programmed attribute and creates an RDoc::Attr.
805
1238
  #
@@ -837,9 +1270,10 @@ class RDoc::Parser::Ruby < RDoc::Parser
837
1270
 
838
1271
  tmp = RDoc::CodeObject.new
839
1272
  read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS
840
- return unless tmp.document_self
841
1273
 
842
- if comment.sub!(/^# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i, '') then
1274
+ regexp = /^# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i
1275
+ if regexp =~ comment.text then
1276
+ comment.text = comment.text.sub(regexp, '')
843
1277
  rw = case $1
844
1278
  when 'attr_reader' then 'R'
845
1279
  when 'attr_writer' then 'W'
@@ -849,216 +1283,175 @@ class RDoc::Parser::Ruby < RDoc::Parser
849
1283
  end
850
1284
 
851
1285
  if name then
852
- att = RDoc::Attr.new get_tkread, name, rw, comment, single == SINGLE
853
- att.record_location @top_level
854
-
855
- context.add_attribute att
856
- @stats.add_attribute att
1286
+ att = create_attr context, single, name, rw, comment
857
1287
  else
858
1288
  args.each do |attr_name|
859
- att = RDoc::Attr.new(get_tkread, attr_name, rw, comment,
860
- single == SINGLE)
861
- att.record_location @top_level
862
-
863
- context.add_attribute att
864
- @stats.add_attribute att
1289
+ att = create_attr context, single, attr_name, rw, comment
865
1290
  end
866
1291
  end
1292
+
1293
+ att
867
1294
  end
868
1295
 
869
1296
  ##
870
1297
  # Parses a meta-programmed method
871
1298
 
872
1299
  def parse_meta_method(container, single, tk, comment)
873
- line_no = tk.line_no
874
- column = tk.char_no
1300
+ column = tk[:char_no]
1301
+ line_no = tk[:line_no]
875
1302
 
876
1303
  start_collecting_tokens
877
1304
  add_token tk
878
1305
  add_token_listener self
879
1306
 
880
- skip_tkspace false
1307
+ skip_tkspace_without_nl
881
1308
 
882
- singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
1309
+ comment.text = comment.text.sub(/(^# +:?)(singleton-)(method:)/, '\1\3')
1310
+ singleton = !!$~
883
1311
 
884
- if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
885
- name = $1 unless $1.empty?
886
- end
1312
+ name = parse_meta_method_name comment, tk
887
1313
 
888
- if name.nil? then
889
- name_t = get_tk
890
- case name_t
891
- when TkSYMBOL then
892
- name = name_t.text[1..-1]
893
- when TkSTRING then
894
- name = name_t.value[1..-2]
895
- when TkASSIGN then # ignore
896
- remove_token_listener self
897
- return
898
- else
899
- warn "unknown name token #{name_t.inspect} for meta-method '#{tk.name}'"
900
- name = 'unknown'
901
- end
902
- end
1314
+ return unless name
903
1315
 
904
1316
  meth = RDoc::MetaMethod.new get_tkread, name
905
- meth.record_location @top_level
1317
+ record_location meth
1318
+ meth.line = line_no
906
1319
  meth.singleton = singleton
907
1320
 
908
1321
  remove_token_listener self
909
1322
 
910
1323
  meth.start_collecting_tokens
911
- indent = TkSPACE.new nil, 1, 1
912
- indent.set_text " " * column
913
-
914
- position_comment = TkCOMMENT.new nil, line_no, 1
915
- position_comment.value = "# File #{@top_level.absolute_name}, line #{line_no}"
916
- meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
1324
+ indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column)
1325
+ position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment)
1326
+ position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}"
1327
+ newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n")
1328
+ meth.add_tokens [position_comment, newline, indent]
917
1329
  meth.add_tokens @token_stream
918
1330
 
1331
+ parse_meta_method_params container, single, meth, tk, comment
1332
+
1333
+ meth.comment = comment
1334
+
1335
+ @stats.add_method meth
1336
+
1337
+ meth
1338
+ end
1339
+
1340
+ ##
1341
+ # Parses the name of a metaprogrammed method. +comment+ is used to
1342
+ # determine the name while +tk+ is used in an error message if the name
1343
+ # cannot be determined.
1344
+
1345
+ def parse_meta_method_name comment, tk # :nodoc:
1346
+ if comment.text.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
1347
+ return $1 unless $1.empty?
1348
+ end
1349
+
1350
+ name_t = get_tk
1351
+
1352
+ if :on_symbol == name_t[:kind] then
1353
+ name_t[:text][1..-1]
1354
+ elsif :on_tstring == name_t[:kind] then
1355
+ name_t[:text][1..-2]
1356
+ elsif :on_op == name_t[:kind] && '=' == name_t[:text] then # ignore
1357
+ remove_token_listener self
1358
+
1359
+ nil
1360
+ else
1361
+ warn "unknown name token #{name_t.inspect} for meta-method '#{tk[:text]}'"
1362
+ 'unknown'
1363
+ end
1364
+ end
1365
+
1366
+ ##
1367
+ # Parses the parameters and block for a meta-programmed method.
1368
+
1369
+ def parse_meta_method_params container, single, meth, tk, comment # :nodoc:
919
1370
  token_listener meth do
920
1371
  meth.params = ''
921
1372
 
922
- extract_call_seq comment, meth
1373
+ look_for_directives_in meth, comment
1374
+ comment.normalize
1375
+ comment.extract_call_seq meth
923
1376
 
924
- container.add_method meth if meth.document_self
1377
+ container.add_method meth
925
1378
 
926
1379
  last_tk = tk
927
1380
 
928
1381
  while tk = get_tk do
929
- case tk
930
- when TkSEMICOLON then
1382
+ if :on_semicolon == tk[:kind] then
931
1383
  break
932
- when TkNL then
933
- break unless last_tk and TkCOMMA === last_tk
934
- when TkSPACE then
1384
+ elsif :on_nl == tk[:kind] then
1385
+ break unless last_tk and :on_comma == last_tk[:kind]
1386
+ elsif :on_sp == tk[:kind] then
935
1387
  # expression continues
1388
+ elsif :on_kw == tk[:kind] && 'do' == tk[:text] then
1389
+ parse_statements container, single, meth
1390
+ break
936
1391
  else
937
1392
  last_tk = tk
938
1393
  end
939
1394
  end
940
1395
  end
941
-
942
- meth.comment = comment
943
-
944
- @stats.add_method meth
945
1396
  end
946
1397
 
947
1398
  ##
948
1399
  # Parses a normal method defined by +def+
949
1400
 
950
1401
  def parse_method(container, single, tk, comment)
951
- added_container = nil
952
- meth = nil
1402
+ singleton = nil
1403
+ added_container = false
953
1404
  name = nil
954
- line_no = tk.line_no
955
- column = tk.char_no
1405
+ column = tk[:char_no]
1406
+ line_no = tk[:line_no]
956
1407
 
957
1408
  start_collecting_tokens
958
1409
  add_token tk
959
1410
 
960
1411
  token_listener self do
961
- @scanner.instance_eval do @lex_state = EXPR_FNAME end
1412
+ prev_container = container
1413
+ name, container, singleton = parse_method_name container
1414
+ added_container = container != prev_container
1415
+ end
962
1416
 
963
- skip_tkspace
964
- name_t = get_tk
965
- back_tk = skip_tkspace
966
- meth = nil
967
- added_container = false
1417
+ return unless name
968
1418
 
969
- dot = get_tk
970
- if TkDOT === dot or TkCOLON2 === dot then
971
- @scanner.instance_eval do @lex_state = EXPR_FNAME end
972
- skip_tkspace
973
- name_t2 = get_tk
974
-
975
- case name_t
976
- when TkSELF, TkMOD then
977
- name = name_t2.name
978
- when TkCONSTANT then
979
- name = name_t2.name
980
- prev_container = container
981
- container = container.find_module_named(name_t.name)
982
- unless container then
983
- added_container = true
984
- obj = name_t.name.split("::").inject(Object) do |state, item|
985
- state.const_get(item)
986
- end rescue nil
987
-
988
- type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule
989
-
990
- unless [Class, Module].include?(obj.class) then
991
- warn("Couldn't find #{name_t.name}. Assuming it's a module")
992
- end
1419
+ meth = RDoc::AnyMethod.new get_tkread, name
1420
+ look_for_directives_in meth, comment
1421
+ meth.singleton = single == SINGLE ? true : singleton
993
1422
 
994
- if type == RDoc::NormalClass then
995
- sclass = obj.superclass ? obj.superclass.name : nil
996
- container = prev_container.add_class type, name_t.name, sclass
997
- else
998
- container = prev_container.add_module type, name_t.name
999
- end
1423
+ record_location meth
1424
+ meth.line = line_no
1000
1425
 
1001
- container.record_location @top_level
1002
- end
1003
- when TkIDENTIFIER, TkIVAR, TkGVAR then
1004
- dummy = RDoc::Context.new
1005
- dummy.parent = container
1006
- skip_method dummy
1007
- return
1008
- when TkTRUE, TkFALSE, TkNIL then
1009
- klass_name = "#{name_t.name.capitalize}Class"
1010
- container = RDoc::TopLevel.find_class_named klass_name
1011
- container ||= @top_level.add_class RDoc::NormalClass, klass_name
1426
+ meth.start_collecting_tokens
1427
+ indent = RDoc::Parser::RipperStateLex::Token.new(1, 1, :on_sp, ' ' * column)
1428
+ token = RDoc::Parser::RipperStateLex::Token.new(line_no, 1, :on_comment)
1429
+ token[:text] = "# File #{@top_level.relative_name}, line #{line_no}"
1430
+ newline = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n")
1431
+ meth.add_tokens [token, newline, indent]
1432
+ meth.add_tokens @token_stream
1012
1433
 
1013
- name = name_t2.name
1014
- else
1015
- warn "unexpected method name token #{name_t.inspect}"
1016
- # break
1017
- skip_method container
1018
- return
1019
- end
1434
+ parse_method_params_and_body container, single, meth, added_container
1020
1435
 
1021
- meth = RDoc::AnyMethod.new(get_tkread, name)
1022
- meth.singleton = true
1023
- else
1024
- unget_tk dot
1025
- back_tk.reverse_each do |token|
1026
- unget_tk token
1027
- end
1436
+ comment.normalize
1437
+ comment.extract_call_seq meth
1028
1438
 
1029
- name = case name_t
1030
- when TkSTAR, TkAMPER then
1031
- name_t.text
1032
- else
1033
- unless name_t.respond_to? :name then
1034
- warn "expected method name token, . or ::, got #{name_t.inspect}"
1035
- skip_method container
1036
- return
1037
- end
1038
- name_t.name
1039
- end
1040
-
1041
- meth = RDoc::AnyMethod.new get_tkread, name
1042
- meth.singleton = (single == SINGLE)
1043
- end
1044
- end
1439
+ meth.comment = comment
1045
1440
 
1046
- meth.record_location @top_level
1441
+ # after end modifiers
1442
+ read_documentation_modifiers meth, RDoc::METHOD_MODIFIERS
1047
1443
 
1048
- meth.start_collecting_tokens
1049
- indent = TkSPACE.new nil, 1, 1
1050
- indent.set_text " " * column
1444
+ @stats.add_method meth
1445
+ end
1051
1446
 
1052
- token = TkCOMMENT.new nil, line_no, 1
1053
- token.set_text "# File #{@top_level.absolute_name}, line #{line_no}"
1054
- meth.add_tokens [token, NEWLINE_TOKEN, indent]
1055
- meth.add_tokens @token_stream
1447
+ ##
1448
+ # Parses the parameters and body of +meth+
1056
1449
 
1450
+ def parse_method_params_and_body container, single, meth, added_container
1057
1451
  token_listener meth do
1058
- @scanner.instance_eval do @continue = false end
1059
1452
  parse_method_parameters meth
1060
1453
 
1061
- if meth.document_self then
1454
+ if meth.document_self or not @track_visibility then
1062
1455
  container.add_method meth
1063
1456
  elsif added_container then
1064
1457
  container.document_self = false
@@ -1067,7 +1460,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
1067
1460
  # Having now read the method parameters and documentation modifiers, we
1068
1461
  # now know whether we have to rename #initialize to ::new
1069
1462
 
1070
- if name == "initialize" && !meth.singleton then
1463
+ if meth.name == "initialize" && !meth.singleton then
1071
1464
  if meth.dont_rename_initialize then
1072
1465
  meth.visibility = :protected
1073
1466
  else
@@ -1079,12 +1472,108 @@ class RDoc::Parser::Ruby < RDoc::Parser
1079
1472
 
1080
1473
  parse_statements container, single, meth
1081
1474
  end
1475
+ end
1082
1476
 
1083
- extract_call_seq comment, meth
1477
+ ##
1478
+ # Parses a method that needs to be ignored.
1084
1479
 
1085
- meth.comment = comment
1480
+ def parse_method_dummy container
1481
+ dummy = RDoc::Context.new
1482
+ dummy.parent = container
1483
+ dummy.store = container.store
1484
+ skip_method dummy
1485
+ end
1086
1486
 
1087
- @stats.add_method meth
1487
+ ##
1488
+ # Parses the name of a method in +container+.
1489
+ #
1490
+ # Returns the method name, the container it is in (for def Foo.name) and if
1491
+ # it is a singleton or regular method.
1492
+
1493
+ def parse_method_name container # :nodoc:
1494
+ skip_tkspace
1495
+ name_t = get_tk
1496
+ back_tk = skip_tkspace_without_nl
1497
+ singleton = false
1498
+
1499
+ dot = get_tk
1500
+ if dot[:kind] == :on_period || (dot[:kind] == :on_op && dot[:text] == '::') then
1501
+ singleton = true
1502
+
1503
+ name, container = parse_method_name_singleton container, name_t
1504
+ else
1505
+ unget_tk dot
1506
+ back_tk.reverse_each do |token|
1507
+ unget_tk token
1508
+ end
1509
+
1510
+ name = parse_method_name_regular container, name_t
1511
+ end
1512
+
1513
+ return name, container, singleton
1514
+ end
1515
+
1516
+ ##
1517
+ # For the given +container+ and initial name token +name_t+ the method name
1518
+ # is parsed from the token stream for a regular method.
1519
+
1520
+ def parse_method_name_regular container, name_t # :nodoc:
1521
+ if :on_op == name_t[:kind] && (%w{* & [] []= <<}.include?(name_t[:text])) then
1522
+ name_t[:text]
1523
+ else
1524
+ unless [:on_kw, :on_const, :on_ident].include?(name_t[:kind]) then
1525
+ warn "expected method name token, . or ::, got #{name_t.inspect}"
1526
+ skip_method container
1527
+ return
1528
+ end
1529
+ name_t[:text]
1530
+ end
1531
+ end
1532
+
1533
+ ##
1534
+ # For the given +container+ and initial name token +name_t+ the method name
1535
+ # and the new +container+ (if necessary) are parsed from the token stream
1536
+ # for a singleton method.
1537
+
1538
+ def parse_method_name_singleton container, name_t # :nodoc:
1539
+ skip_tkspace
1540
+ name_t2 = get_tk
1541
+
1542
+ if (:on_kw == name_t[:kind] && 'self' == name_t[:text]) || (:on_op == name_t[:kind] && '%' == name_t[:text]) then
1543
+ # NOTE: work around '[' being consumed early
1544
+ if :on_lbracket == name_t2[:kind]
1545
+ get_tk
1546
+ name = '[]'
1547
+ else
1548
+ name = name_t2[:text]
1549
+ end
1550
+ elsif :on_const == name_t[:kind] then
1551
+ name = name_t2[:text]
1552
+
1553
+ container = get_method_container container, name_t
1554
+
1555
+ return unless container
1556
+
1557
+ name
1558
+ elsif :on_ident == name_t[:kind] || :on_ivar == name_t[:kind] || :on_gvar == name_t[:kind] then
1559
+ parse_method_dummy container
1560
+
1561
+ name = nil
1562
+ elsif (:on_kw == name_t[:kind]) && ('true' == name_t[:text] || 'false' == name_t[:text] || 'nil' == name_t[:text]) then
1563
+ klass_name = "#{name_t[:text].capitalize}Class"
1564
+ container = @store.find_class_named klass_name
1565
+ container ||= @top_level.add_class RDoc::NormalClass, klass_name
1566
+
1567
+ name = name_t2[:text]
1568
+ else
1569
+ warn "unexpected method name token #{name_t.inspect}"
1570
+ # break
1571
+ skip_method container
1572
+
1573
+ name = nil
1574
+ end
1575
+
1576
+ return name, container
1088
1577
  end
1089
1578
 
1090
1579
  ##
@@ -1092,63 +1581,61 @@ class RDoc::Parser::Ruby < RDoc::Parser
1092
1581
 
1093
1582
  def parse_method_or_yield_parameters(method = nil,
1094
1583
  modifiers = RDoc::METHOD_MODIFIERS)
1095
- skip_tkspace false
1584
+ skip_tkspace_without_nl
1096
1585
  tk = get_tk
1586
+ end_token = get_end_token tk
1587
+ return '' unless end_token
1097
1588
 
1098
- # Little hack going on here. In the statement
1099
- # f = 2*(1+yield)
1100
- # We see the RPAREN as the next token, so we need
1101
- # to exit early. This still won't catch all cases
1102
- # (such as "a = yield + 1"
1103
- end_token = case tk
1104
- when TkLPAREN, TkfLPAREN
1105
- TkRPAREN
1106
- when TkRPAREN
1107
- return ""
1108
- else
1109
- TkNL
1110
- end
1111
1589
  nest = 0
1590
+ continue = false
1112
1591
 
1113
- loop do
1114
- case tk
1115
- when TkSEMICOLON then
1592
+ while tk != nil do
1593
+ case tk[:kind]
1594
+ when :on_semicolon then
1116
1595
  break if nest == 0
1117
- when TkLBRACE, TkfLBRACE then
1596
+ when :on_lbracket then
1597
+ nest += 1
1598
+ when :on_rbracket then
1599
+ nest -= 1
1600
+ when :on_lbrace then
1118
1601
  nest += 1
1119
- when TkRBRACE then
1602
+ when :on_rbrace then
1120
1603
  nest -= 1
1121
1604
  if nest <= 0
1122
1605
  # we might have a.each { |i| yield i }
1123
1606
  unget_tk(tk) if nest < 0
1124
1607
  break
1125
1608
  end
1126
- when TkLPAREN, TkfLPAREN then
1609
+ when :on_lparen then
1127
1610
  nest += 1
1128
- when end_token then
1129
- if end_token == TkRPAREN
1611
+ when end_token[:kind] then
1612
+ if end_token[:kind] == :on_rparen
1130
1613
  nest -= 1
1131
- break if @scanner.lex_state == EXPR_END and nest <= 0
1614
+ break if nest <= 0
1132
1615
  else
1133
- break unless @scanner.continue
1616
+ break
1134
1617
  end
1135
- when TkRPAREN then
1618
+ when :on_rparen then
1136
1619
  nest -= 1
1137
- when method && method.block_params.nil? && TkCOMMENT then
1138
- unget_tk tk
1139
- read_documentation_modifiers method, modifiers
1620
+ when :on_comment, :on_embdoc then
1140
1621
  @read.pop
1141
- when TkCOMMENT then
1142
- @read.pop
1143
- when nil then
1144
- break
1622
+ if :on_nl == end_token[:kind] and "\n" == tk[:text][-1] and
1623
+ (!continue or (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0) then
1624
+ if method && method.block_params.nil? then
1625
+ unget_tk tk
1626
+ read_documentation_modifiers method, modifiers
1627
+ end
1628
+ break if !continue and nest <= 0
1629
+ end
1630
+ when :on_comma then
1631
+ continue = true
1632
+ when :on_ident then
1633
+ continue = false if continue
1145
1634
  end
1146
1635
  tk = get_tk
1147
1636
  end
1148
1637
 
1149
- res = get_tkread.gsub(/\s+/, ' ').strip
1150
- res = '' if res == ';'
1151
- res
1638
+ get_tkread_clean(/\s+/, ' ')
1152
1639
  end
1153
1640
 
1154
1641
  ##
@@ -1159,34 +1646,37 @@ class RDoc::Parser::Ruby < RDoc::Parser
1159
1646
  #
1160
1647
  # and add this as the block_params for the method
1161
1648
 
1162
- def parse_method_parameters(method)
1649
+ def parse_method_parameters method
1163
1650
  res = parse_method_or_yield_parameters method
1164
1651
 
1165
1652
  res = "(#{res})" unless res =~ /\A\(/
1166
1653
  method.params = res unless method.params
1167
1654
 
1168
- if method.block_params.nil? then
1169
- skip_tkspace false
1170
- read_documentation_modifiers method, RDoc::METHOD_MODIFIERS
1171
- end
1655
+ return if method.block_params
1656
+
1657
+ skip_tkspace_without_nl
1658
+ read_documentation_modifiers method, RDoc::METHOD_MODIFIERS
1172
1659
  end
1173
1660
 
1174
1661
  ##
1175
1662
  # Parses an RDoc::NormalModule in +container+ with +comment+
1176
1663
 
1177
- def parse_module(container, single, tk, comment)
1664
+ def parse_module container, single, tk, comment
1178
1665
  container, name_t, = get_class_or_module container
1179
1666
 
1180
- name = name_t.name
1667
+ name = name_t[:text]
1181
1668
 
1182
1669
  mod = container.add_module RDoc::NormalModule, name
1183
- mod.record_location @top_level
1670
+ mod.ignore unless container.document_children
1671
+ record_location mod
1184
1672
 
1185
1673
  read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
1186
- mod.comment = comment if mod.document_self
1187
- parse_statements(mod)
1674
+ mod.add_comment comment, @top_level
1675
+ parse_statements mod
1676
+
1677
+ # after end modifiers
1678
+ read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
1188
1679
 
1189
- @top_level.add_to_classes_or_modules mod
1190
1680
  @stats.add_module mod
1191
1681
  end
1192
1682
 
@@ -1197,12 +1687,12 @@ class RDoc::Parser::Ruby < RDoc::Parser
1197
1687
  skip_tkspace_comment
1198
1688
  tk = get_tk
1199
1689
 
1200
- if TkLPAREN === tk then
1690
+ if :on_lparen == tk[:kind] then
1201
1691
  skip_tkspace_comment
1202
1692
  tk = get_tk
1203
1693
  end
1204
1694
 
1205
- name = tk.text if TkSTRING === tk
1695
+ name = tk[:text][1..-2] if :on_tstring == tk[:kind]
1206
1696
 
1207
1697
  if name then
1208
1698
  @top_level.add_require RDoc::Require.new(name, comment)
@@ -1212,10 +1702,44 @@ class RDoc::Parser::Ruby < RDoc::Parser
1212
1702
  end
1213
1703
 
1214
1704
  ##
1215
- # The core of the ruby parser.
1705
+ # Parses a rescue
1706
+
1707
+ def parse_rescue
1708
+ skip_tkspace_without_nl
1709
+
1710
+ while tk = get_tk
1711
+ case tk[:kind]
1712
+ when :on_nl, :on_semicolon, :on_comment then
1713
+ break
1714
+ when :on_comma then
1715
+ skip_tkspace_without_nl
1716
+
1717
+ get_tk if :on_nl == peek_tk[:kind]
1718
+ end
1719
+
1720
+ skip_tkspace_without_nl
1721
+ end
1722
+ end
1723
+
1724
+ ##
1725
+ # Retrieve comment body without =begin/=end
1726
+
1727
+ def retrieve_comment_body(tk)
1728
+ if :on_embdoc == tk[:kind]
1729
+ tk[:text].gsub(/\A=begin.*\n/, '').gsub(/=end\n?\z/, '')
1730
+ else
1731
+ tk[:text]
1732
+ end
1733
+ end
1734
+
1735
+ ##
1736
+ # The core of the Ruby parser.
1216
1737
 
1217
1738
  def parse_statements(container, single = NORMAL, current_method = nil,
1218
- comment = '')
1739
+ comment = new_comment(''))
1740
+ raise 'no' unless RDoc::Comment === comment
1741
+ comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding
1742
+
1219
1743
  nest = 1
1220
1744
  save_visibility = container.visibility
1221
1745
 
@@ -1223,35 +1747,63 @@ class RDoc::Parser::Ruby < RDoc::Parser
1223
1747
 
1224
1748
  while tk = get_tk do
1225
1749
  keep_comment = false
1750
+ try_parse_comment = false
1226
1751
 
1227
- non_comment_seen = true unless TkCOMMENT === tk
1752
+ non_comment_seen = true unless (:on_comment == tk[:kind] or :on_embdoc == tk[:kind])
1228
1753
 
1229
- case tk
1230
- when TkNL then
1231
- skip_tkspace
1232
- tk = get_tk
1754
+ case tk[:kind]
1755
+ when :on_nl, :on_ignored_nl, :on_comment, :on_embdoc then
1756
+ if :on_nl == tk[:kind] or :on_ignored_nl == tk[:kind]
1757
+ skip_tkspace
1758
+ tk = get_tk
1759
+ else
1760
+ past_tokens = @read.size > 1 ? @read[0..-2] : []
1761
+ nl_position = 0
1762
+ past_tokens.reverse.each_with_index do |read_tk, i|
1763
+ if read_tk =~ /^\n$/ then
1764
+ nl_position = (past_tokens.size - 1) - i
1765
+ break
1766
+ elsif read_tk =~ /^#.*\n$/ then
1767
+ nl_position = ((past_tokens.size - 1) - i) + 1
1768
+ break
1769
+ end
1770
+ end
1771
+ comment_only_line = past_tokens[nl_position..-1].all?{ |c| c =~ /^\s+$/ }
1772
+ unless comment_only_line then
1773
+ tk = get_tk
1774
+ end
1775
+ end
1233
1776
 
1234
- if TkCOMMENT === tk then
1777
+ if tk and (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) then
1235
1778
  if non_comment_seen then
1236
1779
  # Look for RDoc in a comment about to be thrown away
1237
1780
  non_comment_seen = parse_comment container, tk, comment unless
1238
1781
  comment.empty?
1239
1782
 
1240
1783
  comment = ''
1784
+ comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding
1241
1785
  end
1242
1786
 
1243
- while TkCOMMENT === tk do
1244
- comment << tk.text << "\n"
1787
+ line_no = nil
1788
+ while tk and (:on_comment == tk[:kind] or :on_embdoc == tk[:kind]) do
1789
+ comment_body = retrieve_comment_body(tk)
1790
+ line_no = tk[:line_no] if comment.empty?
1791
+ comment += comment_body
1792
+ comment << "\n" unless comment_body =~ /\n\z/
1245
1793
 
1246
- tk = get_tk # this is the newline
1247
- skip_tkspace false # leading spaces
1794
+ if comment_body.size > 1 && comment_body =~ /\n\z/ then
1795
+ skip_tkspace_without_nl # leading spaces
1796
+ end
1248
1797
  tk = get_tk
1249
1798
  end
1250
1799
 
1800
+ comment = new_comment comment, line_no
1801
+
1251
1802
  unless comment.empty? then
1252
1803
  look_for_directives_in container, comment
1253
1804
 
1254
1805
  if container.done_documenting then
1806
+ throw :eof if RDoc::TopLevel === container
1255
1807
  container.ongoing_visibility = save_visibility
1256
1808
  end
1257
1809
  end
@@ -1263,171 +1815,179 @@ class RDoc::Parser::Ruby < RDoc::Parser
1263
1815
 
1264
1816
  unget_tk tk
1265
1817
  keep_comment = true
1818
+ container.current_line_visibility = nil
1266
1819
 
1267
- when TkCLASS then
1268
- if container.document_children then
1820
+ when :on_kw then
1821
+ case tk[:text]
1822
+ when 'class' then
1269
1823
  parse_class container, single, tk, comment
1270
- else
1271
- nest += 1
1272
- end
1273
1824
 
1274
- when TkMODULE then
1275
- if container.document_children then
1825
+ when 'module' then
1276
1826
  parse_module container, single, tk, comment
1277
- else
1278
- nest += 1
1279
- end
1280
1827
 
1281
- when TkDEF then
1282
- if container.document_self then
1828
+ when 'def' then
1283
1829
  parse_method container, single, tk, comment
1284
- else
1830
+
1831
+ when 'alias' then
1832
+ parse_alias container, single, tk, comment unless current_method
1833
+
1834
+ when 'yield' then
1835
+ if current_method.nil? then
1836
+ warn "Warning: yield outside of method" if container.document_self
1837
+ else
1838
+ parse_yield container, single, tk, current_method
1839
+ end
1840
+
1841
+ when 'until', 'while' then
1842
+ if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0
1843
+ nest += 1
1844
+ skip_optional_do_after_expression
1845
+ end
1846
+
1847
+ # Until and While can have a 'do', which shouldn't increase the nesting.
1848
+ # We can't solve the general case, but we can handle most occurrences by
1849
+ # ignoring a do at the end of a line.
1850
+
1851
+ # 'for' is trickier
1852
+ when 'for' then
1285
1853
  nest += 1
1286
- end
1854
+ skip_for_variable
1855
+ skip_optional_do_after_expression
1287
1856
 
1288
- when TkCONSTANT then
1289
- if container.document_self then
1290
- parse_constant container, tk, comment
1291
- end
1857
+ when 'case', 'do', 'if', 'unless', 'begin' then
1858
+ if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0
1859
+ nest += 1
1860
+ end
1292
1861
 
1293
- when TkALIAS then
1294
- if container.document_self and not current_method then
1295
- parse_alias container, single, tk, comment
1296
- end
1862
+ when 'super' then
1863
+ current_method.calls_super = true if current_method
1297
1864
 
1298
- when TkYIELD then
1299
- if current_method.nil? then
1300
- warn "Warning: yield outside of method" if container.document_self
1301
- else
1302
- parse_yield container, single, tk, current_method
1303
- end
1865
+ when 'rescue' then
1866
+ parse_rescue
1304
1867
 
1305
- # Until and While can have a 'do', which shouldn't increase the nesting.
1306
- # We can't solve the general case, but we can handle most occurrences by
1307
- # ignoring a do at the end of a line.
1868
+ when 'end' then
1869
+ nest -= 1
1870
+ if nest == 0 then
1871
+ container.ongoing_visibility = save_visibility
1308
1872
 
1309
- when TkUNTIL, TkWHILE then
1310
- nest += 1
1311
- skip_optional_do_after_expression
1873
+ parse_comment container, tk, comment unless comment.empty?
1312
1874
 
1313
- # 'for' is trickier
1314
- when TkFOR then
1315
- nest += 1
1316
- skip_for_variable
1317
- skip_optional_do_after_expression
1875
+ return
1876
+ end
1877
+ end
1318
1878
 
1319
- when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN then
1320
- nest += 1
1879
+ when :on_const then
1880
+ unless parse_constant container, tk, comment, current_method then
1881
+ try_parse_comment = true
1882
+ end
1321
1883
 
1322
- when TkIDENTIFIER then
1884
+ when :on_ident then
1323
1885
  if nest == 1 and current_method.nil? then
1324
- case tk.name
1325
- when 'private', 'protected', 'public', 'private_class_method',
1326
- 'public_class_method', 'module_function' then
1327
- parse_visibility container, single, tk
1328
- keep_comment = true
1329
- when 'attr' then
1330
- parse_attr container, single, tk, comment
1331
- when /^attr_(reader|writer|accessor)$/ then
1332
- parse_attr_accessor container, single, tk, comment
1333
- when 'alias_method' then
1334
- parse_alias container, single, tk, comment if
1335
- container.document_self
1336
- when 'require', 'include' then
1337
- # ignore
1338
- else
1339
- if container.document_self and comment =~ /\A#\#$/ then
1340
- case comment
1341
- when /^# +:?attr(_reader|_writer|_accessor)?:/ then
1342
- parse_meta_attr container, single, tk, comment
1343
- else
1344
- parse_meta_method container, single, tk, comment
1345
- end
1346
- end
1347
- end
1886
+ keep_comment = parse_identifier container, single, tk, comment
1348
1887
  end
1349
1888
 
1350
- case tk.name
1889
+ case tk[:text]
1351
1890
  when "require" then
1352
1891
  parse_require container, comment
1353
1892
  when "include" then
1354
- parse_include container, comment
1893
+ parse_extend_or_include RDoc::Include, container, comment
1894
+ when "extend" then
1895
+ parse_extend_or_include RDoc::Extend, container, comment
1355
1896
  end
1356
1897
 
1357
- when TkEND then
1358
- nest -= 1
1359
- if nest == 0 then
1360
- read_documentation_modifiers container, RDoc::CLASS_MODIFIERS
1361
- container.ongoing_visibility = save_visibility
1362
-
1363
- parse_comment container, tk, comment unless comment.empty?
1364
-
1365
- return
1366
- end
1367
1898
  else
1899
+ try_parse_comment = nest == 1
1900
+ end
1901
+
1902
+ if try_parse_comment then
1368
1903
  non_comment_seen = parse_comment container, tk, comment unless
1369
1904
  comment.empty?
1370
1905
 
1371
- comment = ''
1906
+ keep_comment = false
1372
1907
  end
1373
1908
 
1374
- comment = '' unless keep_comment
1909
+ unless keep_comment then
1910
+ comment = new_comment ''
1911
+ comment = RDoc::Encoding.change_encoding comment, @encoding if @encoding
1912
+ container.params = nil
1913
+ container.block_params = nil
1914
+ end
1375
1915
 
1376
- begin
1377
- get_tkread
1378
- skip_tkspace false
1379
- end while peek_tk == TkNL
1916
+ consume_trailing_spaces
1380
1917
  end
1918
+
1919
+ container.params = nil
1920
+ container.block_params = nil
1381
1921
  end
1382
1922
 
1383
1923
  ##
1384
1924
  # Parse up to +no+ symbol arguments
1385
1925
 
1386
1926
  def parse_symbol_arg(no = nil)
1387
- args = []
1388
-
1389
1927
  skip_tkspace_comment
1390
1928
 
1391
- case tk = get_tk
1392
- when TkLPAREN
1393
- loop do
1394
- skip_tkspace_comment
1395
- if tk1 = parse_symbol_in_arg
1396
- args.push tk1
1397
- break if no and args.size >= no
1398
- end
1929
+ tk = get_tk
1930
+ if tk[:kind] == :on_lparen
1931
+ parse_symbol_arg_paren no
1932
+ else
1933
+ parse_symbol_arg_space no, tk
1934
+ end
1935
+ end
1399
1936
 
1400
- skip_tkspace_comment
1401
- case tk2 = get_tk
1402
- when TkRPAREN
1403
- break
1404
- when TkCOMMA
1405
- else
1406
- warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC
1407
- break
1408
- end
1937
+ ##
1938
+ # Parses up to +no+ symbol arguments surrounded by () and places them in
1939
+ # +args+.
1940
+
1941
+ def parse_symbol_arg_paren no # :nodoc:
1942
+ args = []
1943
+
1944
+ loop do
1945
+ skip_tkspace_comment
1946
+ if tk1 = parse_symbol_in_arg
1947
+ args.push tk1
1948
+ break if no and args.size >= no
1409
1949
  end
1410
- else
1411
- unget_tk tk
1412
- if tk = parse_symbol_in_arg
1413
- args.push tk
1414
- return args if no and args.size >= no
1950
+
1951
+ skip_tkspace_comment
1952
+ case (tk2 = get_tk)[:kind]
1953
+ when :on_rparen
1954
+ break
1955
+ when :on_comma
1956
+ else
1957
+ warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC
1958
+ break
1415
1959
  end
1960
+ end
1416
1961
 
1417
- loop do
1418
- skip_tkspace false
1962
+ args
1963
+ end
1419
1964
 
1420
- tk1 = get_tk
1421
- unless TkCOMMA === tk1 then
1422
- unget_tk tk1
1423
- break
1424
- end
1965
+ ##
1966
+ # Parses up to +no+ symbol arguments separated by spaces and places them in
1967
+ # +args+.
1425
1968
 
1426
- skip_tkspace_comment
1427
- if tk = parse_symbol_in_arg
1428
- args.push tk
1429
- break if no and args.size >= no
1430
- end
1969
+ def parse_symbol_arg_space no, tk # :nodoc:
1970
+ args = []
1971
+
1972
+ unget_tk tk
1973
+ if tk = parse_symbol_in_arg
1974
+ args.push tk
1975
+ return args if no and args.size >= no
1976
+ end
1977
+
1978
+ loop do
1979
+ skip_tkspace_without_nl
1980
+
1981
+ tk1 = get_tk
1982
+ if tk1.nil? || :on_comma != tk1[:kind] then
1983
+ unget_tk tk1
1984
+ break
1985
+ end
1986
+
1987
+ skip_tkspace_comment
1988
+ if tk = parse_symbol_in_arg
1989
+ args.push tk
1990
+ break if no and args.size >= no
1431
1991
  end
1432
1992
  end
1433
1993
 
@@ -1438,12 +1998,12 @@ class RDoc::Parser::Ruby < RDoc::Parser
1438
1998
  # Returns symbol text from the next token
1439
1999
 
1440
2000
  def parse_symbol_in_arg
1441
- case tk = get_tk
1442
- when TkSYMBOL
1443
- tk.text.sub(/^:/, '')
1444
- when TkSTRING
1445
- eval @read[-1]
1446
- when TkDSTRING, TkIDENTIFIER then
2001
+ tk = get_tk
2002
+ if :on_symbol == tk[:kind] then
2003
+ tk[:text].sub(/^:/, '')
2004
+ elsif :on_tstring == tk[:kind] then
2005
+ tk[:text][1..-2]
2006
+ elsif :on_dstring == tk[:kind] or :on_ident == tk[:kind] then
1447
2007
  nil # ignore
1448
2008
  else
1449
2009
  warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC
@@ -1452,12 +2012,20 @@ class RDoc::Parser::Ruby < RDoc::Parser
1452
2012
  end
1453
2013
 
1454
2014
  ##
1455
- # Parses statements at the toplevel in +container+
2015
+ # Parses statements in the top-level +container+
1456
2016
 
1457
- def parse_top_level_statements(container)
2017
+ def parse_top_level_statements container
1458
2018
  comment = collect_first_comment
1459
- look_for_directives_in(container, comment)
2019
+
2020
+ look_for_directives_in container, comment
2021
+
2022
+ throw :eof if container.done_documenting
2023
+
2024
+ @markup = comment.format
2025
+
2026
+ # HACK move if to RDoc::Context#comment=
1460
2027
  container.comment = comment if container.document_self unless comment.empty?
2028
+
1461
2029
  parse_statements container, NORMAL, nil, comment
1462
2030
  end
1463
2031
 
@@ -1465,65 +2033,39 @@ class RDoc::Parser::Ruby < RDoc::Parser
1465
2033
  # Determines the visibility in +container+ from +tk+
1466
2034
 
1467
2035
  def parse_visibility(container, single, tk)
1468
- singleton = (single == SINGLE)
1469
-
1470
- vis_type = tk.name
1471
-
1472
- vis = case vis_type
1473
- when 'private' then :private
1474
- when 'protected' then :protected
1475
- when 'public' then :public
1476
- when 'private_class_method' then
1477
- singleton = true
1478
- :private
1479
- when 'public_class_method' then
1480
- singleton = true
1481
- :public
1482
- when 'module_function' then
1483
- singleton = true
1484
- :public
1485
- else
1486
- raise RDoc::Error, "Invalid visibility: #{tk.name}"
1487
- end
2036
+ vis_type, vis, singleton = get_visibility_information tk, single
1488
2037
 
1489
2038
  skip_tkspace_comment false
1490
2039
 
1491
- case peek_tk
1492
- # Ryan Davis suggested the extension to ignore modifiers, because he
1493
- # often writes
1494
- #
1495
- # protected unless $TESTING
1496
- #
1497
- when TkNL, TkUNLESS_MOD, TkIF_MOD, TkSEMICOLON then
2040
+ ptk = peek_tk
2041
+ # Ryan Davis suggested the extension to ignore modifiers, because he
2042
+ # often writes
2043
+ #
2044
+ # protected unless $TESTING
2045
+ #
2046
+ if [:on_nl, :on_semicolon].include?(ptk[:kind]) || (:on_kw == ptk[:kind] && (['if', 'unless'].include?(ptk[:text]))) then
1498
2047
  container.ongoing_visibility = vis
2048
+ elsif :on_kw == ptk[:kind] && 'def' == ptk[:text]
2049
+ container.current_line_visibility = vis
1499
2050
  else
1500
- if vis_type == 'module_function' then
1501
- args = parse_symbol_arg
1502
- container.set_visibility_for args, :private, false
1503
-
1504
- module_functions = []
1505
-
1506
- container.methods_matching args do |m|
1507
- s_m = m.dup
1508
- s_m.record_location @top_level
1509
- s_m.singleton = true
1510
- s_m.visibility = :public
1511
- module_functions << s_m
1512
- end
2051
+ update_visibility container, vis_type, vis, singleton
2052
+ end
2053
+ end
1513
2054
 
1514
- module_functions.each do |s_m|
1515
- case s_m
1516
- when RDoc::AnyMethod then
1517
- container.add_method s_m
1518
- when RDoc::Attr then
1519
- container.add_attribute s_m
1520
- end
1521
- end
1522
- else
1523
- args = parse_symbol_arg
1524
- container.set_visibility_for args, vis, singleton
1525
- end
2055
+ ##
2056
+ # Parses a Module#private_constant or Module#public_constant call from +tk+.
2057
+
2058
+ def parse_constant_visibility(container, single, tk)
2059
+ args = parse_symbol_arg
2060
+ case tk[:text]
2061
+ when 'private_constant'
2062
+ vis = :private
2063
+ when 'public_constant'
2064
+ vis = :public
2065
+ else
2066
+ raise RDoc::Error, 'Unreachable'
1526
2067
  end
2068
+ container.set_constant_visibility_for args, vis
1527
2069
  end
1528
2070
 
1529
2071
  ##
@@ -1533,7 +2075,6 @@ class RDoc::Parser::Ruby < RDoc::Parser
1533
2075
  return if method.block_params
1534
2076
 
1535
2077
  get_tkread
1536
- @scanner.instance_eval { @continue = false }
1537
2078
  method.block_params = parse_method_or_yield_parameters
1538
2079
  end
1539
2080
 
@@ -1547,49 +2088,72 @@ class RDoc::Parser::Ruby < RDoc::Parser
1547
2088
  #
1548
2089
  # class MyClass # :nodoc:
1549
2090
  #
1550
- # We return the directive name and any parameters as a two element array
2091
+ # We return the directive name and any parameters as a two element array if
2092
+ # the name is in +allowed+. A directive can be found anywhere up to the end
2093
+ # of the current line.
1551
2094
 
1552
2095
  def read_directive allowed
1553
- tk = get_tk
2096
+ tokens = []
2097
+
2098
+ while tk = get_tk do
2099
+ tokens << tk
1554
2100
 
1555
- if TkCOMMENT === tk then
1556
- return unless tk.text =~ /\s*:?(\w+):\s*(.*)/
2101
+ if :on_nl == tk[:kind] or (:on_kw == tk[:kind] && 'def' == tk[:text]) then
2102
+ return
2103
+ elsif :on_comment == tk[:kind] or :on_embdoc == tk[:kind] then
2104
+ return unless tk[:text] =~ /\s*:?([\w-]+):\s*(.*)/
1557
2105
 
1558
- directive = $1.downcase
2106
+ directive = $1.downcase
1559
2107
 
1560
- return [directive, $2] if allowed.include? directive
1561
- else
1562
- unget_tk tk
2108
+ return [directive, $2] if allowed.include? directive
2109
+
2110
+ return
2111
+ end
2112
+ end
2113
+ ensure
2114
+ unless tokens.length == 1 and (:on_comment == tokens.first[:kind] or :on_embdoc == tokens.first[:kind]) then
2115
+ tokens.reverse_each do |token|
2116
+ unget_tk token
2117
+ end
1563
2118
  end
1564
2119
  end
1565
2120
 
1566
2121
  ##
1567
- # Handles the directive for +context+ if the directive is listed in +allow+.
1568
- # This method is called for directives following a definition.
2122
+ # Handles directives following the definition for +context+ (any
2123
+ # RDoc::CodeObject) if the directives are +allowed+ at this point.
2124
+ #
2125
+ # See also RDoc::Markup::PreProcess#handle_directive
1569
2126
 
1570
- def read_documentation_modifiers(context, allow)
1571
- directive, value = read_directive allow
2127
+ def read_documentation_modifiers context, allowed
2128
+ skip_tkspace_without_nl
2129
+ directive, value = read_directive allowed
1572
2130
 
1573
2131
  return unless directive
1574
2132
 
1575
- case directive
1576
- when 'notnew', 'not_new', 'not-new' then
1577
- context.dont_rename_initialize = true
1578
- else
1579
- RDoc::Parser.process_directive context, directive, value
2133
+ @preprocess.handle_directive '', directive, value, context do |dir, param|
2134
+ if %w[notnew not_new not-new].include? dir then
2135
+ context.dont_rename_initialize = true
2136
+
2137
+ true
2138
+ end
1580
2139
  end
1581
2140
  end
1582
2141
 
1583
2142
  ##
1584
- # Removes private comments from +comment+
2143
+ # Records the location of this +container+ in the file for this parser and
2144
+ # adds it to the list of classes and modules in the file.
1585
2145
 
1586
- def remove_private_comments(comment)
1587
- comment.gsub!(/^#--\n.*?^#\+\+\n?/m, '')
1588
- comment.sub!(/^#--\n.*\n?/m, '')
2146
+ def record_location container # :nodoc:
2147
+ case container
2148
+ when RDoc::ClassModule then
2149
+ @top_level.add_to_classes_or_modules container
2150
+ end
2151
+
2152
+ container.record_location @top_level
1589
2153
  end
1590
2154
 
1591
2155
  ##
1592
- # Scans this ruby file for ruby constructs
2156
+ # Scans this Ruby file for Ruby constructs
1593
2157
 
1594
2158
  def scan
1595
2159
  reset
@@ -1597,30 +2161,35 @@ class RDoc::Parser::Ruby < RDoc::Parser
1597
2161
  catch :eof do
1598
2162
  begin
1599
2163
  parse_top_level_statements @top_level
2164
+
1600
2165
  rescue StandardError => e
1601
- bytes = ''
1602
-
1603
- 20.times do @scanner.ungetc end
1604
- count = 0
1605
- 60.times do |i|
1606
- count = i
1607
- byte = @scanner.getc
1608
- break unless byte
1609
- bytes << byte
2166
+ if @content.include?('<%') and @content.include?('%>') then
2167
+ # Maybe, this is ERB.
2168
+ $stderr.puts "\033[2KRDoc detects ERB file. Skips it for compatibility:"
2169
+ $stderr.puts @file_name
2170
+ return
1610
2171
  end
1611
- count -= 20
1612
- count.times do @scanner.ungetc end
2172
+
2173
+ if @scanner_point >= @scanner.size
2174
+ now_line_no = @scanner[@scanner.size - 1][:line_no]
2175
+ else
2176
+ now_line_no = peek_tk[:line_no]
2177
+ end
2178
+ first_tk_index = @scanner.find_index { |tk| tk[:line_no] == now_line_no }
2179
+ last_tk_index = @scanner.find_index { |tk| tk[:line_no] == now_line_no + 1 }
2180
+ last_tk_index = last_tk_index ? last_tk_index - 1 : @scanner.size - 1
2181
+ code = @scanner[first_tk_index..last_tk_index].map{ |t| t[:text] }.join
1613
2182
 
1614
2183
  $stderr.puts <<-EOF
1615
2184
 
1616
- #{self.class} failure around line #{@scanner.line_no} of
2185
+ #{self.class} failure around line #{now_line_no} of
1617
2186
  #{@file_name}
1618
2187
 
1619
2188
  EOF
1620
2189
 
1621
- unless bytes.empty? then
2190
+ unless code.empty? then
2191
+ $stderr.puts code
1622
2192
  $stderr.puts
1623
- $stderr.puts bytes.inspect
1624
2193
  end
1625
2194
 
1626
2195
  raise e
@@ -1634,58 +2203,52 @@ class RDoc::Parser::Ruby < RDoc::Parser
1634
2203
  # while, until, and for have an optional do
1635
2204
 
1636
2205
  def skip_optional_do_after_expression
1637
- skip_tkspace false
2206
+ skip_tkspace_without_nl
1638
2207
  tk = get_tk
1639
- case tk
1640
- when TkLPAREN, TkfLPAREN then
1641
- end_token = TkRPAREN
1642
- else
1643
- end_token = TkNL
1644
- end
1645
2208
 
1646
2209
  b_nest = 0
1647
2210
  nest = 0
1648
- @scanner.instance_eval { @continue = false }
1649
2211
 
1650
2212
  loop do
1651
- case tk
1652
- when TkSEMICOLON then
2213
+ break unless tk
2214
+ case tk[:kind]
2215
+ when :on_semicolon, :on_nl, :on_ignored_nl then
1653
2216
  break if b_nest.zero?
1654
- when TkLPAREN, TkfLPAREN then
2217
+ when :on_lparen then
1655
2218
  nest += 1
1656
- when TkBEGIN then
1657
- b_nest += 1
1658
- when TkEND then
1659
- b_nest -= 1
1660
- when TkDO
1661
- break if nest.zero?
1662
- when end_token then
1663
- if end_token == TkRPAREN
1664
- nest -= 1
1665
- break if @scanner.lex_state == EXPR_END and nest.zero?
1666
- else
1667
- break unless @scanner.continue
2219
+ when :on_rparen then
2220
+ nest -= 1
2221
+ when :on_kw then
2222
+ case tk[:text]
2223
+ when 'begin'
2224
+ b_nest += 1
2225
+ when 'end'
2226
+ b_nest -= 1
2227
+ when 'do'
2228
+ break if nest.zero?
2229
+ end
2230
+ when :on_comment, :on_embdoc then
2231
+ if b_nest.zero? and "\n" == tk[:text][-1] then
2232
+ break
1668
2233
  end
1669
- when nil then
1670
- break
1671
2234
  end
1672
2235
  tk = get_tk
1673
2236
  end
1674
2237
 
1675
- skip_tkspace false
2238
+ skip_tkspace_without_nl
1676
2239
 
1677
- get_tk if TkDO === peek_tk
2240
+ get_tk if peek_tk && :on_kw == peek_tk[:kind] && 'do' == peek_tk[:text]
1678
2241
  end
1679
2242
 
1680
2243
  ##
1681
2244
  # skip the var [in] part of a 'for' statement
1682
2245
 
1683
2246
  def skip_for_variable
1684
- skip_tkspace false
1685
- tk = get_tk
1686
- skip_tkspace false
2247
+ skip_tkspace_without_nl
2248
+ get_tk
2249
+ skip_tkspace_without_nl
1687
2250
  tk = get_tk
1688
- unget_tk(tk) unless TkIN === tk
2251
+ unget_tk(tk) unless :on_kw == tk[:kind] and 'in' == tk[:text]
1689
2252
  end
1690
2253
 
1691
2254
  ##
@@ -1702,20 +2265,63 @@ class RDoc::Parser::Ruby < RDoc::Parser
1702
2265
 
1703
2266
  def skip_tkspace_comment(skip_nl = true)
1704
2267
  loop do
1705
- skip_tkspace skip_nl
1706
- return unless TkCOMMENT === peek_tk
2268
+ skip_nl ? skip_tkspace : skip_tkspace_without_nl
2269
+ next_tk = peek_tk
2270
+ return if next_tk.nil? || (:on_comment != next_tk[:kind] and :on_embdoc != next_tk[:kind])
1707
2271
  get_tk
1708
2272
  end
1709
2273
  end
1710
2274
 
1711
2275
  ##
1712
- # Prints +msg+ to +$stderr+ unless we're being quiet
2276
+ # Updates visibility in +container+ from +vis_type+ and +vis+.
1713
2277
 
1714
- def warn(msg)
1715
- return if @options.quiet
1716
- msg = make_message msg
1717
- $stderr.puts msg
2278
+ def update_visibility container, vis_type, vis, singleton # :nodoc:
2279
+ new_methods = []
2280
+
2281
+ case vis_type
2282
+ when 'module_function' then
2283
+ args = parse_symbol_arg
2284
+ container.set_visibility_for args, :private, false
2285
+
2286
+ container.methods_matching args do |m|
2287
+ s_m = m.dup
2288
+ record_location s_m
2289
+ s_m.singleton = true
2290
+ new_methods << s_m
2291
+ end
2292
+ when 'public_class_method', 'private_class_method' then
2293
+ args = parse_symbol_arg
2294
+
2295
+ container.methods_matching args, true do |m|
2296
+ if m.parent != container then
2297
+ m = m.dup
2298
+ record_location m
2299
+ new_methods << m
2300
+ end
2301
+
2302
+ m.visibility = vis
2303
+ end
2304
+ else
2305
+ args = parse_symbol_arg
2306
+ container.set_visibility_for args, vis, singleton
2307
+ end
2308
+
2309
+ new_methods.each do |method|
2310
+ case method
2311
+ when RDoc::AnyMethod then
2312
+ container.add_method method
2313
+ when RDoc::Attr then
2314
+ container.add_attribute method
2315
+ end
2316
+ method.visibility = vis
2317
+ end
1718
2318
  end
1719
2319
 
1720
- end
2320
+ ##
2321
+ # Prints +message+ to +$stderr+ unless we're being quiet
1721
2322
 
2323
+ def warn message
2324
+ @options.warn make_message message
2325
+ end
2326
+
2327
+ end