Class: RDoc::Parser::Rails
- Inherits:
-
Ruby
- Object
- Ruby
- RDoc::Parser::Rails
- Includes:
- RubyToken
- Defined in:
- lib/rdoc_rails/rdoc/parser/rails.rb
Constant Summary collapse
- RAILS_IDENTIFIERS =
The identifiers that should be processed as rails meta-calls
[ 'belongs_to', 'has_one', 'has_many', 'has_and_belongs_to_many', 'delegate', 'validates_uniqueness_of' ]
Instance Method Summary collapse
- #parse_ar_association(container, single, tk, comment, args, opts) ⇒ Object (also: #parse_belongs_to, #parse_has_one, #parse_has_many, #parse_has_and_belongs_to_many)
-
#parse_delegate(container, single, tk, comment, args, opts) ⇒ Object
Take the args, opts, and tokens collected by parse_rails_meta and generate method documentation for delegated methods.
-
#parse_final_hash ⇒ Object
Parse tokens assumed to represent a final hash argument, thus will parse either a {} enclosed hash or a naked final hash.
- #parse_rails_debug(container, single, tk, comment, args, opts) ⇒ Object
- #parse_rails_meta(container, single, tk, comment) ⇒ Object
- #parse_rails_pending(container, single, tk, comment, args, opts) ⇒ Object (also: #parse_validates_uniqueness_of)
-
#parse_statements(container, single = NORMAL, current_method = nil, comment = '') ⇒ Object
Copied from super, with a minor tweak to the TkIDENTIFIER parsing portion.
-
#parse_symbol_arg(no = nil) ⇒ Object
Largely copied from super, but rewinds if it hits a =>, indicating the last symbol/string read should have been part of the final hash arg.
-
#position_comment(tk) ⇒ Object
Comment line required to help generator put line numbers on included source code.
-
#restore_init_token(tk) ⇒ Object
Clear @token_stream and then put back the indentation and initial token; basically assumes tk is the first non-whitespace token on the line.
- #skip_to_eol ⇒ Object
Instance Method Details
#parse_ar_association(container, single, tk, comment, args, opts) ⇒ Object Also known as: parse_belongs_to, parse_has_one, parse_has_many, parse_has_and_belongs_to_many
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/rdoc_rails/rdoc/parser/rails.rb', line 29 def parse_ar_association(container, single, tk, comment, args, opts) ara = RDoc::ArAssociation.new( :atype => tk.name, :name => args[0], :opts => opts, :comment => comment ) ara.start_collecting_tokens ara.add_tokens [position_comment(tk), NEWLINE_TOKEN] ara.add_tokens token_stream ara.parent = container container.ar_associations << ara end |
#parse_delegate(container, single, tk, comment, args, opts) ⇒ Object
Take the args, opts, and tokens collected by parse_rails_meta and generate method documentation for delegated methods.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/rdoc_rails/rdoc/parser/rails.rb', line 51 def parse_delegate(container, single, tk, comment, args, opts) add_token_listener self skip_to_eol remove_token_listener self args.each do |arg| d_meth = RDoc::AnyMethod.new('', arg) @stats.add_method d_meth container.add_method d_meth d_meth.start_collecting_tokens d_meth.add_tokens [position_comment(tk), NEWLINE_TOKEN] d_meth.add_tokens token_stream d_meth.params = "(?) - delegated to #{opts[:to].inspect}" if opts[:to] d_meth.params ||= '(?) - delegated method...' d_meth.comment = comment end end |
#parse_final_hash ⇒ Object
Parse tokens assumed to represent a final hash argument, thus will parse either a {} enclosed hash or a naked final hash.
The purpose of this is mainly to be able to generate documentation for Rails meta calls, which generally have symbols/strings for keys and values, so that is what I’ve prioritized being able to parse. Shouldn’t be difficult to add parsing of numeric keys/values. Parsing array/hash keys/values would be more difficult and isn’t in the scope of what I currently plan to do. If this hits something it doesn’t know how to parse, it rewinds all its tokens and quits.
The best way to set up a call to parse_final_hash is as is done in parse_rails_meta, where we first call parse_symbol_arg. This is good setup because parse_symbol_arg will rewind to the comma before the final hash if it detects a hash in parsing other args.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/rdoc_rails/rdoc/parser/rails.rb', line 91 def parse_final_hash buffer = TokenStream.new add_token_listener(buffer) skip_tkspace(true) case tk = get_tk when TkLBRACE then bracketed = true when TkSYMBOL, TkSTRING then bracketed = false else unget_tk(tk) until buffer.token_stream.empty? remove_token_listener(buffer) return end last_tk = tk while tk = get_tk do case tk when TkSEMICOLON then break when TkNL unget_tk(tk) and break unless last_tk and TkCOMMA === last_tk when TkSPACE, TkCOMMENT when TkSYMBOL, TkSTRING, TkCOMMA, TkASSIGN, TkGT, TkASSOC then last_tk = tk # Will probably want to expand this to include numerics, possibly others; let's cross that bridge when we come to it. else break if bracketed and tk.is_a?(TkRBRACE) unget_tk(tk) and break if !bracketed and tk.is_a?(TkDO) unget_tk(tk) until buffer.token_stream.empty? remove_token_listener(buffer) return end end remove_token_listener(buffer) read = buffer.token_stream.collect{|tk|tk.text}.join read = "{#{read}\n}" if !bracketed # We need the \n in case #{read} ends with a comment eval(read) rescue nil end |
#parse_rails_debug(container, single, tk, comment, args, opts) ⇒ Object
19 20 21 22 23 24 |
# File 'lib/rdoc_rails/rdoc/parser/rails.rb', line 19 def parse_rails_debug(container, single, tk, comment, args, opts) puts tk.name puts args.inspect puts opts.inspect if opts puts "" end |
#parse_rails_meta(container, single, tk, comment) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 |
# File 'lib/rdoc_rails/rdoc/parser/rails.rb', line 6 def (container, single, tk, comment) return unless container.document_children restore_init_token(tk) # Start listening to get_tk and saving read tokens into @token_stream, parse # symbol args add_token_listener self args = parse_symbol_arg # This gets any symbol or string args opts = (parse_final_hash if token_stream[-1].is_a?(TkCOMMA)) || {} remove_token_listener self send("parse_#{tk.name}", container, single, tk, comment, args, opts) end |
#parse_rails_pending(container, single, tk, comment, args, opts) ⇒ Object Also known as: parse_validates_uniqueness_of
26 |
# File 'lib/rdoc_rails/rdoc/parser/rails.rb', line 26 def parse_rails_pending(container, single, tk, comment, args, opts); end |
#parse_statements(container, single = NORMAL, current_method = nil, comment = '') ⇒ Object
Copied from super, with a minor tweak to the TkIDENTIFIER parsing portion.
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'lib/rdoc_rails/rdoc/parser/rails.rb', line 234 def parse_statements(container, single = NORMAL, current_method = nil, comment = '') nest = 1 save_visibility = container.visibility non_comment_seen = true while tk = get_tk do keep_comment = false non_comment_seen = true unless TkCOMMENT === tk case tk when TkNL then skip_tkspace true # Skip blanks and newlines tk = get_tk if TkCOMMENT === tk then if non_comment_seen then # Look for RDoc in a comment about to be thrown away parse_comment container, tk, comment unless comment.empty? comment = '' non_comment_seen = false end while TkCOMMENT === tk do comment << tk.text << "\n" tk = get_tk # this is the newline skip_tkspace(false) # leading spaces tk = get_tk end unless comment.empty? then look_for_directives_in container, comment if container.done_documenting then container.ongoing_visibility = save_visibility end end keep_comment = true else non_comment_seen = true end unget_tk tk keep_comment = true when TkCLASS then if container.document_children then parse_class container, single, tk, comment else nest += 1 end when TkMODULE then if container.document_children then parse_module container, single, tk, comment else nest += 1 end when TkDEF then if container.document_self then parse_method container, single, tk, comment else nest += 1 end when TkCONSTANT then if container.document_self then # parse_constant container, single, tk, comment # change for rdoc > 2.4.3 parse_constant container, tk, comment end when TkALIAS then if container.document_self then parse_alias container, single, tk, comment end when TkYIELD then if current_method.nil? then warn "Warning: yield outside of method" if container.document_self else parse_yield container, single, tk, current_method end # Until and While can have a 'do', which shouldn't increase the nesting. # We can't solve the general case, but we can handle most occurrences by # ignoring a do at the end of a line. when TkUNTIL, TkWHILE then nest += 1 skip_optional_do_after_expression # 'for' is trickier when TkFOR then nest += 1 skip_for_variable skip_optional_do_after_expression when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN then nest += 1 when TkIDENTIFIER then if nest == 1 and current_method.nil? then case tk.name when 'private', 'protected', 'public', 'private_class_method', 'public_class_method', 'module_function' then parse_visibility container, single, tk keep_comment = true when 'attr' then parse_attr container, single, tk, comment when /^attr_(reader|writer|accessor)$/ then parse_attr_accessor container, single, tk, comment when 'alias_method' then if container.document_self then parse_alias container, single, tk, comment end when *RAILS_IDENTIFIERS then container, single, tk, comment else if container.document_self and comment =~ /\A#\#$/ then container, single, tk, comment end end end case tk.name when "require" then parse_require container, comment when "include" then parse_include container, comment end when TkEND then nest -= 1 if nest == 0 then read_documentation_modifiers container, RDoc::CLASS_MODIFIERS container.ongoing_visibility = save_visibility return end end comment = '' unless keep_comment begin get_tkread skip_tkspace(false) end while peek_tk == TkNL end end |
#parse_symbol_arg(no = nil) ⇒ Object
Largely copied from super, but rewinds if it hits a =>, indicating the last symbol/string read should have been part of the final hash arg. Rewinds to the comma before the final hash, which provides a good check after we return of whether there are still more arguments to parse.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/rdoc_rails/rdoc/parser/rails.rb', line 133 def parse_symbol_arg(no=nil) buffer = TokenStream.new add_token_listener(buffer) args = [] skip_tkspace_comment case tk = get_tk when TkLPAREN loop do skip_tkspace_comment if tk = parse_symbol_in_arg args.push tk break if no and args.size >= no end skip_tkspace_comment case tk2 = get_tk when TkRPAREN break when TkCOMMA when TkASSOC, TkASSIGN, TkGT # Oops, we started slurping the final Hash! # So rewind back past the symbol or string that came before the => unget_tk(buffer.token_stream[-1]) until buffer.token_stream[-1].is_a?(TkCOMMA) or buffer.token_stream.empty? args.pop break when TkLBRACE # We hit the beginning of a hash or block, so rewind to the comma unget_tk(buffer.token_stream[-1]) until buffer.token_stream[-1].is_a?(TkCOMMA) or buffer.token_stream.empty? break else warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC break end end else unget_tk tk if tk = parse_symbol_in_arg args.push tk return args if no and args.size >= no end loop do skip_tkspace(false) tk1 = get_tk if TkCOMMA === tk1 elsif TkASSOC === tk1 or TkASSIGN === tk1 or TkGT === tk1 # Oops, we started slurping the final Hash! # So rewind back past the symbol or string that came before the => unget_tk(buffer.token_stream[-1]) until buffer.token_stream[-1].is_a?(TkCOMMA) or buffer.token_stream.empty? args.pop break elsif TkLBRACE === tk1 # We hit the beginning of a hash or block, so rewind to the comma unget_tk(buffer.token_stream[-1]) until buffer.token_stream[-1].is_a?(TkCOMMA) or buffer.token_stream.empty? break else unget_tk tk1 break end skip_tkspace_comment if tk = parse_symbol_in_arg args.push tk break if no and args.size >= no end end end remove_token_listener buffer args end |
#position_comment(tk) ⇒ Object
Comment line required to help generator put line numbers on included source code.
208 209 210 |
# File 'lib/rdoc_rails/rdoc/parser/rails.rb', line 208 def position_comment(tk) TkCOMMENT.new(tk.line_no, 1, "# File #{@top_level.absolute_name}, line #{tk.line_no}") end |
#restore_init_token(tk) ⇒ Object
Clear @token_stream and then put back the indentation and initial token; basically assumes tk is the first non-whitespace token on the line.
214 215 216 217 218 219 220 221 |
# File 'lib/rdoc_rails/rdoc/parser/rails.rb', line 214 def restore_init_token(tk) start_collecting_tokens # indent = TkSPACE.new(1, 1) # change for rdoc > 2.4.3 indent = TkSPACE.new(nil,1, 1) indent.set_text(' ' * tk.char_no) add_tokens([indent, tk]) end |
#skip_to_eol ⇒ Object
72 73 74 |
# File 'lib/rdoc_rails/rdoc/parser/rails.rb', line 72 def skip_to_eol tk = get_tk until tk.is_a?(TkNL) end |