yard 0.5.5 → 0.5.6

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

Potentially problematic release.


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

Files changed (46) hide show
  1. data/ChangeLog +131 -0
  2. data/README.md +16 -12
  3. data/Rakefile +2 -1
  4. data/docs/GettingStarted.md +1 -107
  5. data/docs/Tags.md +250 -53
  6. data/docs/WhatsNew.md +13 -0
  7. data/lib/rubygems_plugin.rb +18 -17
  8. data/lib/yard.rb +1 -1
  9. data/lib/yard/autoload.rb +4 -0
  10. data/lib/yard/cli/yardoc.rb +5 -4
  11. data/lib/yard/cli/yri.rb +18 -3
  12. data/lib/yard/code_objects/base.rb +5 -4
  13. data/lib/yard/code_objects/class_object.rb +1 -1
  14. data/lib/yard/code_objects/constant_object.rb +1 -1
  15. data/lib/yard/code_objects/method_object.rb +3 -2
  16. data/lib/yard/code_objects/namespace_object.rb +3 -3
  17. data/lib/yard/code_objects/proxy.rb +4 -0
  18. data/lib/yard/docstring.rb +3 -2
  19. data/lib/yard/handlers/base.rb +1 -1
  20. data/lib/yard/handlers/ruby/class_condition_handler.rb +5 -1
  21. data/lib/yard/handlers/ruby/class_handler.rb +41 -1
  22. data/lib/yard/handlers/ruby/legacy/class_condition_handler.rb +5 -1
  23. data/lib/yard/handlers/ruby/legacy/class_handler.rb +44 -0
  24. data/lib/yard/handlers/ruby/struct_handler_methods.rb +128 -0
  25. data/lib/yard/parser/base.rb +55 -0
  26. data/lib/yard/parser/c_parser.rb +5 -1
  27. data/lib/yard/parser/ruby/ast_node.rb +4 -4
  28. data/lib/yard/parser/ruby/legacy/ruby_parser.rb +26 -0
  29. data/lib/yard/parser/ruby/legacy/statement_list.rb +0 -4
  30. data/lib/yard/parser/ruby/ruby_parser.rb +45 -2
  31. data/lib/yard/parser/source_parser.rb +69 -45
  32. data/lib/yard/serializers/file_system_serializer.rb +1 -1
  33. data/lib/yard/tags/default_factory.rb +1 -13
  34. data/lib/yard/tags/library.rb +3 -1
  35. data/lib/yard/templates/erb_cache.rb +5 -2
  36. data/lib/yard/templates/helpers/html_helper.rb +1 -0
  37. data/lib/yard/templates/template.rb +2 -1
  38. data/spec/cli/yardoc_spec.rb +6 -6
  39. data/spec/handlers/class_condition_handler_spec.rb +11 -0
  40. data/spec/handlers/class_handler_spec.rb +121 -0
  41. data/spec/handlers/examples/class_handler_001.rb.txt +19 -0
  42. data/spec/parser/base_spec.rb +25 -0
  43. data/spec/parser/source_parser_spec.rb +63 -0
  44. data/templates/default/layout/html/setup.rb +1 -1
  45. data/templates/default/tags/html/option.erb +1 -1
  46. metadata +21 -5
@@ -0,0 +1,128 @@
1
+ module YARD::Handlers::Ruby::StructHandlerMethods
2
+ include YARD::CodeObjects
3
+
4
+ # Extracts the user's defined @member tag for a given class and its member. Returns
5
+ # nil if the user did not define a @member tag for this struct entry.
6
+ #
7
+ # @param [ClassObject] klass the class whose tags we're searching
8
+ # @param [String] member the name of the struct member we need
9
+ # @param [Symbol] type reader method, or writer method?
10
+ # @return [Tags::Tag, nil] the tag matching the request, or nil if not found
11
+ def member_tag_for_member(klass, member, type = :read)
12
+ specific_tag = type == :read ? :attr_reader : :attr_writer
13
+ (klass.tags(specific_tag) + klass.tags(:attr)).find {|tag| tag.name == member}
14
+ end
15
+
16
+ # Determines whether to create an attribute method based on the class's
17
+ # tags.
18
+ #
19
+ # @param [ClassObject] klass the class whose tags we're searching
20
+ # @param [String] member the name of the struct member we need
21
+ # @param [Symbol] type (:read) reader method, or writer method?
22
+ # @return [Boolean] should the attribute be created?
23
+ def create_member_method?(klass, member, type = :read)
24
+ return true if (klass.tags(:attr) + klass.tags(:attr_reader) + klass.tags(:attr_writer)).empty?
25
+ return true if member_tag_for_member(klass, member, type)
26
+ return !member_tag_for_member(klass, member, :write) if type == :read
27
+ return !member_tag_for_member(klass, member, :read)
28
+ end
29
+
30
+ # Gets the return type for the member in a nicely formatted string. Used
31
+ # to be injected into auto-generated docstrings.
32
+ #
33
+ # @param [ClassObject] klass the class whose tags we're searching
34
+ # @param [String] member the name of the struct member whose return type we need
35
+ # @return [String] the user-declared type of the struct member, or [Object] if
36
+ # the user did not define a type for this member.
37
+ def return_type_from_tag(member_tag)
38
+ (member_tag && member_tag.types) ? member_tag.types : "Object"
39
+ end
40
+
41
+ # Creates the auto-generated docstring for the getter method of a struct's
42
+ # member. This is used so the generated documentation will look just like that
43
+ # of an attribute defined using attr_accessor.
44
+ #
45
+ # @param [ClassObject] klass the class whose members we're working with
46
+ # @param [String] member the name of the member we're generating documentation for
47
+ # @return [String] a docstring to be attached to the getter method for this member
48
+ def add_reader_tags(klass, new_method, member)
49
+ member_tag = member_tag_for_member(klass, member, :read)
50
+ return_type = return_type_from_tag(member_tag)
51
+ getter_doc_text = member_tag ? member_tag.text : "Returns the value of attribute #{member}"
52
+ new_method.docstring.replace(getter_doc_text)
53
+ new_method.docstring.add_tag YARD::Tags::Tag.new(:return, "the current value of #{member}", return_type)
54
+ end
55
+
56
+ # Creates the auto-generated docstring for the setter method of a struct's
57
+ # member. This is used so the generated documentation will look just like that
58
+ # of an attribute defined using attr_accessor.
59
+ #
60
+ # @param [ClassObject] klass the class whose members we're working with
61
+ # @param [String] member the name of the member we're generating documentation for
62
+ # @return [String] a docstring to be attached to the setter method for this member
63
+ def add_writer_tags(klass, new_method, member)
64
+ member_tag = member_tag_for_member(klass, member, :write)
65
+ return_type = return_type_from_tag(member_tag)
66
+ setter_doc_text = member_tag ? member_tag.text : "Sets the attribute #{member}"
67
+ new_method.docstring.replace(setter_doc_text)
68
+ new_method.docstring.add_tag YARD::Tags::Tag.new(:param, "the value to set the attribute #{member} to.", return_type, "value")
69
+ new_method.docstring.add_tag YARD::Tags::Tag.new(:return, "the newly set value", return_type)
70
+ end
71
+
72
+ # Creates and registers a class object with the given name and superclass name.
73
+ # Returns it for further use.
74
+ #
75
+ # @param [String] classname the name of the class
76
+ # @param [String] superclass the name of the superclass
77
+ # @return [ClassObject] the class object for further processing/method attaching
78
+ def create_class(classname, superclass)
79
+ register ClassObject.new(namespace, classname) do |o|
80
+ o.superclass = superclass if superclass
81
+ o.superclass.type = :class if o.superclass.is_a?(Proxy)
82
+ end
83
+ end
84
+
85
+ # Creates the setter (writer) method and attaches it to the class as an attribute.
86
+ # Also sets up the docstring to prettify the documentation output.
87
+ #
88
+ # @param [ClassObject] klass the class to attach the method to
89
+ # @param [String] member the name of the member we're generating a method for
90
+ def create_writer(klass, member)
91
+ # We want to convert these members into attributes just like
92
+ # as if they were declared using attr_accessor.
93
+ new_meth = register MethodObject.new(klass, "#{member}=", :instance) do |o|
94
+ o.parameters = [['value', nil]]
95
+ o.signature ||= "def #{member}=(value)"
96
+ o.source ||= "#{o.signature}\n @#{member} = value\nend"
97
+ end
98
+ add_writer_tags(klass, new_meth, member)
99
+ klass.attributes[:instance][member][:write] = new_meth
100
+ end
101
+
102
+ # Creates the getter (reader) method and attaches it to the class as an attribute.
103
+ # Also sets up the docstring to prettify the documentation output.
104
+ #
105
+ # @param [ClassObject] klass the class to attach the method to
106
+ # @param [String] member the name of the member we're generating a method for
107
+ def create_reader(klass, member)
108
+ new_meth = register MethodObject.new(klass, member, :instance) do |o|
109
+ o.signature ||= "def #{member}"
110
+ o.source ||= "#{o.signature}\n @#{member}\nend"
111
+ end
112
+ add_reader_tags(klass, new_meth, member)
113
+ klass.attributes[:instance][member][:read] = new_meth
114
+ end
115
+
116
+ # Creates the given member methods and attaches them to the given ClassObject.
117
+ #
118
+ # @param [ClassObject] klass the class to generate attributes for
119
+ # @param [Array<String>] members a list of member names
120
+ def create_attributes(klass, members)
121
+ # For each parameter, add reader and writers
122
+ members.each do |member|
123
+ klass.attributes[:instance][member] = SymbolHash[:read => nil, :write => nil]
124
+ create_writer klass, member if create_member_method?(klass, member, :write)
125
+ create_reader klass, member if create_member_method?(klass, member, :read)
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,55 @@
1
+ module YARD
2
+ module Parser
3
+ # Represents the abstract base parser class that parses source code in
4
+ # a specific way. A parser should implement {#parse}, {#tokenize} and
5
+ # {#enumerator}.
6
+ #
7
+ # == Registering a Custom Parser
8
+ # To register a parser, see {SourceParser.register_parser_type}
9
+ #
10
+ # @abstract
11
+ # @see #parse
12
+ # @see #tokenize
13
+ # @see #enumerator
14
+ class Base
15
+ # Convenience method to create a new parser and {#parse}
16
+ def self.parse(source, filename = nil)
17
+ new(source, filename).parse
18
+ end
19
+
20
+ # This default constructor does nothing. The subclass is responsible for
21
+ # storing the source contents and filename if they are required.
22
+ # @param [String] source the source contents
23
+ # @param [String] filename the name of the file if from disk
24
+ def initialize(source, filename)
25
+ raise NotImplementedError, "invalid parser implementation"
26
+ end
27
+
28
+ # This method should be implemented to parse the source and return itself.
29
+ # @abstract
30
+ # @return [Base] this method should return itself
31
+ def parse
32
+ raise NotImplementedError, "#{self.class} must implement #parse"
33
+ end
34
+
35
+ # This method should be implemented to tokenize given source
36
+ # @abstract
37
+ # @return [Array] a list/tree of lexical tokens
38
+ def tokenize
39
+ raise NotImplementedError, "#{self.class} does not support tokenization"
40
+ end
41
+
42
+ # This method should be implemented to return a list of semantic tokens
43
+ # representing the source code to be post-processed. Otherwise the method
44
+ # should return nil.
45
+ #
46
+ # @abstract
47
+ # @return [Array] a list of semantic tokens representing the source code
48
+ # to be post-processed
49
+ # @return [nil] if no post-processing should be done
50
+ def enumerator
51
+ nil
52
+ end
53
+ end
54
+ end
55
+ end
@@ -4,7 +4,7 @@
4
4
 
5
5
  module YARD
6
6
  module Parser
7
- class CParser
7
+ class CParser < Base
8
8
  def initialize(source, file = '(stdin)')
9
9
  @file = file
10
10
  @namespaces = {}
@@ -18,6 +18,10 @@ module YARD
18
18
  parse_includes
19
19
  end
20
20
 
21
+ def tokenize
22
+ raise NotImplementedError, "no tokenization support for C/C++ files"
23
+ end
24
+
21
25
  private
22
26
 
23
27
  def remove_var_prefix(var)
@@ -38,8 +38,8 @@ module YARD
38
38
  # list, like Strings or Symbols representing names. To return only
39
39
  # the AstNode children of the node, use {#children}.
40
40
  class AstNode < Array
41
- attr_accessor :type, :parent, :docstring, :file, :full_source, :source
42
- attr_accessor :source_range, :line_range, :docstring_range
41
+ attr_accessor :type, :parent, :docstring, :docstring_range, :source
42
+ attr_writer :source_range, :line_range, :file, :full_source
43
43
  alias comments docstring
44
44
  alias comments_range docstring_range
45
45
  alias to_s source
@@ -235,12 +235,12 @@ module YARD
235
235
  q.group(3, 's(', ')') do
236
236
  q.seplist(objs, nil, :each) do |v|
237
237
  if v == :__last__
238
- q.seplist(options, nil, :each) do |k, v|
238
+ q.seplist(options, nil, :each) do |k, v2|
239
239
  q.group(3) do
240
240
  q.text k
241
241
  q.group(3) do
242
242
  q.text ': '
243
- q.pp v
243
+ q.pp v2
244
244
  end
245
245
  end
246
246
  end
@@ -0,0 +1,26 @@
1
+ module YARD
2
+ module Parser
3
+ module Ruby
4
+ module Legacy
5
+ # Legacy Ruby parser
6
+ class RubyParser < Parser::Base
7
+ def initialize(source, filename)
8
+ @source = source
9
+ end
10
+
11
+ def parse
12
+ @parse ||= StatementList.new(@source)
13
+ end
14
+
15
+ def tokenize
16
+ @tokenize ||= TokenList.new(@source)
17
+ end
18
+
19
+ def enumerator
20
+ @parse
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -24,10 +24,6 @@ module YARD
24
24
  parse_statements
25
25
  end
26
26
 
27
- def enumerator
28
- self
29
- end
30
-
31
27
  private
32
28
 
33
29
  def parse_statements
@@ -3,12 +3,25 @@ require 'ripper'
3
3
  module YARD
4
4
  module Parser
5
5
  module Ruby
6
- class RubyParser < Ripper
6
+ # Ruby 1.9 parser
7
+ class RubyParser < Parser::Base
8
+ def initialize(source, filename)
9
+ @parser = RipperParser.new(source, filename)
10
+ end
11
+
12
+ def parse; @parser.parse end
13
+ def tokenize; @parser.tokens end
14
+ def enumerator; @parser.enumerator end
15
+ end
16
+
17
+ # Internal parser class
18
+ class RipperParser < Ripper
7
19
  attr_reader :ast, :charno, :comments, :file, :tokens
8
20
  alias root ast
9
21
 
10
22
  def initialize(source, filename, *args)
11
23
  super
24
+ @last_ns_token = nil
12
25
  @file = filename
13
26
  @source = source
14
27
  @tokens = []
@@ -107,6 +120,7 @@ module YARD
107
120
  eof
108
121
  elsif /_add(_.+)?\z/ =~ event
109
122
  module_eval(<<-eof, __FILE__, __LINE__ + 1)
123
+ undef on_#{event} if instance_method(:on_#{event})
110
124
  def on_#{event}(list, item)
111
125
  list.push(item)
112
126
  list
@@ -114,12 +128,14 @@ module YARD
114
128
  eof
115
129
  elsif MAPPINGS.has_key?(event)
116
130
  module_eval(<<-eof, __FILE__, __LINE__ + 1)
131
+ undef on_#{event} if instance_method(:on_#{event})
117
132
  def on_#{event}(*args)
118
133
  visit_event #{node_class}.new(:#{event}, args)
119
134
  end
120
135
  eof
121
136
  else
122
137
  module_eval(<<-eof, __FILE__, __LINE__ + 1)
138
+ undef on_#{event} if instance_method(:on_#{event})
123
139
  def on_#{event}(*args)
124
140
  #{node_class}.new(:#{event}, args, listline: lineno..lineno, listchar: charno...charno)
125
141
  end
@@ -130,6 +146,7 @@ module YARD
130
146
  SCANNER_EVENTS.each do |event|
131
147
  ast_token = AST_TOKENS.include?(event)
132
148
  module_eval(<<-eof, __FILE__, __LINE__ + 1)
149
+ undef on_#{event} if instance_method(:on_#{event})
133
150
  def on_#{event}(tok)
134
151
  visit_ns_token(:#{event}, tok, #{ast_token.inspect})
135
152
  end
@@ -139,6 +156,7 @@ module YARD
139
156
  REV_MAPPINGS.select {|k| k.is_a?(Symbol) }.each do |event, value|
140
157
  ast_token = AST_TOKENS.include?(event)
141
158
  module_eval(<<-eof, __FILE__, __LINE__ + 1)
159
+ undef on_#{event} if instance_method(:on_#{event})
142
160
  def on_#{event}(tok)
143
161
  (@map[:#{event}] ||= []) << [lineno, charno]
144
162
  visit_ns_token(:#{event}, tok, #{ast_token.inspect})
@@ -148,6 +166,7 @@ module YARD
148
166
 
149
167
  [:kw, :op].each do |event|
150
168
  module_eval(<<-eof, __FILE__, __LINE__ + 1)
169
+ undef on_#{event} if instance_method(:on_#{event})
151
170
  def on_#{event}(tok)
152
171
  unless @last_ns_token == [:kw, "def"] ||
153
172
  (@tokens.last && @tokens.last[0] == :symbeg)
@@ -160,6 +179,7 @@ module YARD
160
179
 
161
180
  [:sp, :nl, :ignored_nl].each do |event|
162
181
  module_eval(<<-eof, __FILE__, __LINE__ + 1)
182
+ undef on_#{event} if instance_method(:on_#{event})
163
183
  def on_#{event}(tok)
164
184
  add_token(:#{event}, tok)
165
185
  @charno += tok.length
@@ -201,6 +221,28 @@ module YARD
201
221
  end
202
222
  end
203
223
 
224
+ undef on_program
225
+ undef on_bodystmt
226
+ undef on_assoc_new
227
+ undef on_hash
228
+ undef on_bare_assoc_hash
229
+ undef on_assoclist_from_args
230
+ undef on_aref
231
+ undef on_rbracket
232
+ undef on_qwords_new
233
+ undef on_string_literal
234
+ undef on_lambda
235
+ undef on_string_content
236
+ undef on_rescue
237
+ undef on_void_stmt
238
+ undef on_params
239
+ undef on_label
240
+ undef on_comment
241
+ undef on_embdoc_beg
242
+ undef on_embdoc
243
+ undef on_embdoc_end
244
+ undef on_parse_error
245
+
204
246
  def on_program(*args)
205
247
  args.first
206
248
  end
@@ -241,6 +283,7 @@ module YARD
241
283
  [:if_mod, :unless_mod, :while_mod].each do |kw|
242
284
  node_class = AstNode.node_class_for(kw)
243
285
  module_eval(<<-eof, __FILE__, __LINE__ + 1)
286
+ undef on_#{kw} if instance_method(:on_#{kw})
244
287
  def on_#{kw}(*args)
245
288
  sr = args.last.source_range.first..args.first.source_range.last
246
289
  lr = args.last.line_range.first..args.first.line_range.last
@@ -340,7 +383,7 @@ module YARD
340
383
  def insert_comments
341
384
  root.traverse do |node|
342
385
  next if node.type == :list || node.parent.type != :list
343
- node.line.downto(node.line - 2) do |line|
386
+ (node.line - 2).upto(node.line) do |line|
344
387
  comment = @comments[line]
345
388
  if comment && !comment.empty?
346
389
  node.docstring = comment
@@ -22,22 +22,19 @@ module YARD
22
22
  # also invokes handlers to process the parsed statements and generate
23
23
  # any code objects that may be recognized.
24
24
  #
25
+ # == Custom Parsers
26
+ # SourceParser allows custom parsers to be registered and called when
27
+ # a certain filetype is recognized. To register a parser and hook it
28
+ # up to a set of file extensions, call {register_parser_type}
29
+ #
30
+ # @see register_parser_type
25
31
  # @see Handlers::Base
26
32
  # @see CodeObjects::Base
27
33
  class SourceParser
28
34
  class << self
29
- # The default parser type to use for blocks of code. Change this
30
- # attribute to apply a new parser type for all newly parsed
31
- # blocks of code.
32
- #
33
- # @return [Symbol] the parser type
34
- attr_accessor :parser_type
35
- undef parser_type=
35
+ # @return [Symbol] the default parser type (defaults to :ruby)
36
+ attr_reader :parser_type
36
37
 
37
- # Sets the parser and makes sure it's a valid type
38
- #
39
- # @param [Symbol] value the new parser type
40
- # @return [void]
41
38
  def parser_type=(value)
42
39
  @parser_type = validated_parser_type(value)
43
40
  end
@@ -86,6 +83,49 @@ module YARD
86
83
  new(ptype).tokenize(content)
87
84
  end
88
85
 
86
+ # Registers a new parser type.
87
+ #
88
+ # @example Registering a parser for "java" files
89
+ # SourceParser.register_parser_type :java, JavaParser, 'java'
90
+ # @param [Symbol] type a symbolic name for the parser type
91
+ # @param [Base] parser_klass a class that implements parsing and tokenization
92
+ # @param [Array<String>, String, Regexp] extensions a list of extensions or a
93
+ # regex to match against the file extension
94
+ # @return [void]
95
+ # @see Parser::Base
96
+ def register_parser_type(type, parser_klass, extensions = nil)
97
+ unless Base > parser_klass
98
+ raise ArgumentError, "expecting parser_klass to be a subclass of YARD::Parser::Base"
99
+ end
100
+ parser_type_extensions[type.to_sym] = extensions if extensions
101
+ parser_types[type.to_sym] = parser_klass
102
+ end
103
+
104
+ # @return [Hash{Symbol=>Object}] a list of registered parser types
105
+ def parser_types; @@parser_types ||= {} end
106
+ def parser_types=(value) @@parser_types = value end
107
+
108
+ # @return [Hash] a list of registered parser type extensions
109
+ def parser_type_extensions; @@parser_type_extensions ||= {} end
110
+ def parser_type_extensions=(value) @@parser_type_extensions = value end
111
+
112
+ # Finds a parser type that is registered for the extension. If no
113
+ # type is found, the default Ruby type is returned.
114
+ #
115
+ # @return [Symbol] the parser type to be used for the extension
116
+ def parser_type_for_extension(extension)
117
+ type = parser_type_extensions.find do |t, exts|
118
+ if exts.is_a?(Array)
119
+ exts.include?(extension)
120
+ elsif exts.is_a?(String)
121
+ exts == extension
122
+ elsif exts.is_a?(Regexp)
123
+ extension =~ exts
124
+ end
125
+ end
126
+ validated_parser_type(type ? type.first : :ruby)
127
+ end
128
+
89
129
  # Returns the validated parser type. Basically, enforces that :ruby
90
130
  # type is never set from Ruby 1.8
91
131
  #
@@ -94,7 +134,7 @@ module YARD
94
134
  def validated_parser_type(type)
95
135
  RUBY18 && type == :ruby ? :ruby18 : type
96
136
  end
97
-
137
+
98
138
  private
99
139
 
100
140
  # Parses a list of files in a queue. If a {LoadOrderError} is caught,
@@ -124,6 +164,10 @@ module YARD
124
164
 
125
165
  self.parser_type = :ruby
126
166
 
167
+ register_parser_type :ruby, Ruby::RubyParser if RUBY19
168
+ register_parser_type :ruby18, Ruby::Legacy::RubyParser
169
+ register_parser_type :c, CParser, ['c', 'cc', 'cxx', 'cpp']
170
+
127
171
  # The filename being parsed by the parser.
128
172
  attr_reader :file
129
173
 
@@ -163,7 +207,8 @@ module YARD
163
207
  content = content.read if content.respond_to? :read
164
208
  end
165
209
 
166
- @parser = parse_statements(content)
210
+ @parser = parser_class.new(content, file)
211
+ @parser.parse
167
212
  post_process
168
213
  @parser
169
214
  rescue ArgumentError, NotImplementedError => e
@@ -177,16 +222,8 @@ module YARD
177
222
  # @param [String] content the block of code to tokenize
178
223
  # @return [Array] a list of tokens
179
224
  def tokenize(content)
180
- case parser_type
181
- when :c
182
- raise NotImplementedError, "no support for C/C++ files"
183
- when :ruby18
184
- Ruby::Legacy::TokenList.new(content)
185
- when :ruby
186
- Ruby::RubyParser.parse(content).tokens
187
- else
188
- raise ArgumentError, "invalid parser type or unrecognized file"
189
- end
225
+ @parser = parser_class.new(content, file)
226
+ @parser.tokenize
190
227
  end
191
228
 
192
229
  private
@@ -205,8 +242,9 @@ module YARD
205
242
  # @return [void]
206
243
  def post_process
207
244
  return unless @parser.respond_to? :enumerator
245
+ return unless enumerator = @parser.enumerator
208
246
  post = Handlers::Processor.new(@file, @load_order_errors, @parser_type)
209
- post.process(@parser.enumerator)
247
+ post.process(enumerator)
210
248
  end
211
249
 
212
250
  def parser_type=(value)
@@ -218,29 +256,15 @@ module YARD
218
256
  # @param [String] filename the filename to use to guess the parser type
219
257
  # @return [Symbol] a parser type that matches the filename
220
258
  def parser_type_for_filename(filename)
221
- case (File.extname(filename)[1..-1] || "").downcase
222
- when "c", "cpp", "cxx"
223
- :c
224
- else # when "rb", "rbx", "erb"
225
- parser_type == :ruby18 ? :ruby18 : :ruby
226
- end
259
+ ext = (File.extname(filename)[1..-1] || "").downcase
260
+ type = self.class.parser_type_for_extension(ext)
261
+ parser_type == :ruby18 && type == :ruby ? :ruby18 : type
227
262
  end
228
263
 
229
- # Selects a parser to use to parse +content+.
230
- #
231
- # @param [String] content the block of code to parse
232
- # @return the resulting parser object
233
- def parse_statements(content)
234
- case parser_type
235
- when :c
236
- CParser.new(content, file).parse
237
- when :ruby18
238
- Ruby::Legacy::StatementList.new(content)
239
- when :ruby
240
- Ruby::RubyParser.parse(content, file)
241
- else
242
- raise ArgumentError, "invalid parser type or unrecognized file"
243
- end
264
+ def parser_class
265
+ klass = self.class.parser_types[parser_type]
266
+ raise ArgumentError, "invalid parser type '#{parser_type}' or unrecognized file", caller[1..-1] if !klass
267
+ klass
244
268
  end
245
269
  end
246
270
  end