Class: YARD::Parser::SourceParser
- Inherits:
-
Object
- Object
- YARD::Parser::SourceParser
- Defined in:
- lib/yard/parser/source_parser.rb
Overview
Responsible for parsing a source file into the namespace. Parsing also invokes handlers to process the parsed statements and generate any code objects that may be recognized.
Custom Parsers
SourceParser allows custom parsers to be registered and called when a certain filetype is recognized. To register a parser and hook it up to a set of file extensions, call SourceParser.register_parser_type
Constant Summary collapse
- SHEBANG_LINE =
/\A\s*#!\S+/
- ENCODING_LINE =
%r{\A(?:\s*#*!.*\r?\n)?\s*(?:#+|/\*+|//+).*coding\s*[:=]{1,2}\s*([a-z\d_\-]+)}i
- FROZEN_STRING_LINE =
/frozen(-|_)string(-|_)literal:\s+(true|false)/i
- DEFAULT_PATH_GLOB =
The default glob of files to be parsed.
["{lib,app}/**/*.rb", "ext/**/*.{c,cc,cxx,cpp,rb}"]
- ENCODING_BYTE_ORDER_MARKS =
Byte order marks for various encodings
{ 'utf-8' => String.new("\xEF\xBB\xBF"), # Not yet supported # 'utf-16be' => "\xFE\xFF", # 'utf-16le' => "\xFF\xFE", # 'utf-32be' => "\x00\x00\xFF\xFE", # 'utf-32le' => "\xFF\xFE", }
Parser Callbacks collapse
-
#contents ⇒ String
readonly
The contents of the file to be parsed.
-
#file ⇒ String
The filename being parsed by the parser.
-
#globals ⇒ OpenStruct
readonly
An open struct containing arbitrary global state shared between files and handlers.
-
#parser_type ⇒ Symbol
readonly
The parser type associated with the parser instance.
Class Attribute Summary collapse
-
.parser_type ⇒ Symbol
The default parser type (defaults to :ruby).
Parser Callbacks collapse
-
.after_parse_file {|parser| ... } ⇒ Proc
Registers a callback to be called after an individual file is parsed.
-
.after_parse_file_callbacks ⇒ Array<Proc>
The list of callbacks to be called after parsing a file.
-
.after_parse_list {|files, globals| ... } ⇒ Proc
Registers a callback to be called after a list of files is parsed via SourceParser.parse.
-
.after_parse_list_callbacks ⇒ Array<Proc>
The list of callbacks to be called after parsing a list of files.
-
.before_parse_file {|parser| ... } ⇒ Proc
Registers a callback to be called before an individual file is parsed.
-
.before_parse_file_callbacks ⇒ Array<Proc>
The list of callbacks to be called before parsing a file.
-
.before_parse_list {|files, globals| ... } ⇒ Proc
Registers a callback to be called before a list of files is parsed via SourceParser.parse.
-
.before_parse_list_callbacks ⇒ Array<Proc>
The list of callbacks to be called before parsing a list of files.
-
#initialize(parser_type = SourceParser.parser_type, globals = nil) ⇒ SourceParser
constructor
Creates a new parser object for code parsing with a specific parser type.
-
#parse(content = __FILE__) ⇒ Object?
The main parser method.
-
#tokenize(content) ⇒ Array
Tokenizes but does not parse the block of code using the current #parser_type.
Class Method Summary collapse
-
.parse(paths = DEFAULT_PATH_GLOB, excluded = [], level = log.level) ⇒ void
Parses a path or set of paths.
-
.parse_string(content, ptype = parser_type) ⇒ Object
Parses a string
content
. -
.parser_type_extensions ⇒ Hash
A list of registered parser type extensions.
- .parser_type_extensions=(value) ⇒ Object
-
.parser_type_for_extension(extension) ⇒ Symbol
Finds a parser type that is registered for the extension.
-
.parser_types ⇒ Hash{Symbol=>Object}
A list of registered parser types.
- .parser_types=(value) ⇒ Object
-
.register_parser_type(type, parser_klass, extensions = nil) ⇒ void
Registers a new parser type.
-
.tokenize(content, ptype = parser_type) ⇒ Array
Tokenizes but does not parse the block of code.
-
.validated_parser_type(type) ⇒ Symbol
Returns the validated parser type.
Constructor Details
#initialize(parser_type = SourceParser.parser_type, globals = nil) ⇒ SourceParser
Returns a new instance of SourceParser.
406 407 408 409 410 411 |
# File 'lib/yard/parser/source_parser.rb', line 406 def initialize(parser_type = SourceParser.parser_type, globals1 = nil, globals2 = nil) globals = [true, false].include?(globals1) ? globals2 : globals1 @file = '(stdin)' @globals = globals || OpenStruct.new self.parser_type = parser_type end |
Class Attribute Details
.parser_type ⇒ Symbol
Returns the default parser type (defaults to :ruby).
86 87 88 |
# File 'lib/yard/parser/source_parser.rb', line 86 def parser_type @parser_type end |
Instance Attribute Details
#contents ⇒ String (readonly)
Returns the contents of the file to be parsed.
399 400 401 |
# File 'lib/yard/parser/source_parser.rb', line 399 def contents @contents end |
#file ⇒ String
Returns the filename being parsed by the parser.
386 387 388 |
# File 'lib/yard/parser/source_parser.rb', line 386 def file @file end |
#globals ⇒ OpenStruct (readonly)
Returns an open struct containing arbitrary global state shared between files and handlers.
395 396 397 |
# File 'lib/yard/parser/source_parser.rb', line 395 def globals @globals end |
#parser_type ⇒ Symbol
Returns the parser type associated with the parser instance. This should be set by the constructor.
390 391 392 |
# File 'lib/yard/parser/source_parser.rb', line 390 def parser_type @parser_type end |
Class Method Details
.after_parse_file {|parser| ... } ⇒ Proc
Registers a callback to be called after an individual file is parsed. The block passed to this method will be called on subsequent parse calls.
To register a callback that is called after the entire list of files is processed, see after_parse_list.
324 325 326 |
# File 'lib/yard/parser/source_parser.rb', line 324 def after_parse_file(&block) after_parse_file_callbacks << block end |
.after_parse_file_callbacks ⇒ Array<Proc>
Returns the list of callbacks to be called after parsing a file. Should only be used for testing.
352 353 354 |
# File 'lib/yard/parser/source_parser.rb', line 352 def after_parse_file_callbacks @after_parse_file_callbacks ||= [] end |
.after_parse_list {|files, globals| ... } ⇒ Proc
Registers a callback to be called after a list of files is parsed via parse. The block passed to this method will be called on subsequent parse calls.
258 259 260 |
# File 'lib/yard/parser/source_parser.rb', line 258 def after_parse_list(&block) after_parse_list_callbacks << block end |
.after_parse_list_callbacks ⇒ Array<Proc>
Returns the list of callbacks to be called after parsing a list of files. Should only be used for testing.
338 339 340 |
# File 'lib/yard/parser/source_parser.rb', line 338 def after_parse_list_callbacks @after_parse_list_callbacks ||= [] end |
.before_parse_file {|parser| ... } ⇒ Proc
Registers a callback to be called before an individual file is parsed. The block passed to this method will be called on subsequent parse calls.
To register a callback that is called before the entire list of files is processed, see before_parse_list.
295 296 297 |
# File 'lib/yard/parser/source_parser.rb', line 295 def before_parse_file(&block) before_parse_file_callbacks << block end |
.before_parse_file_callbacks ⇒ Array<Proc>
Returns the list of callbacks to be called before parsing a file. Should only be used for testing.
345 346 347 |
# File 'lib/yard/parser/source_parser.rb', line 345 def before_parse_file_callbacks @before_parse_file_callbacks ||= [] end |
.before_parse_list {|files, globals| ... } ⇒ Proc
Registers a callback to be called before a list of files is parsed via parse. The block passed to this method will be called on subsequent parse calls.
234 235 236 |
# File 'lib/yard/parser/source_parser.rb', line 234 def before_parse_list(&block) before_parse_list_callbacks << block end |
.before_parse_list_callbacks ⇒ Array<Proc>
Returns the list of callbacks to be called before parsing a list of files. Should only be used for testing.
331 332 333 |
# File 'lib/yard/parser/source_parser.rb', line 331 def before_parse_list_callbacks @before_parse_list_callbacks ||= [] end |
.parse(paths = DEFAULT_PATH_GLOB, excluded = [], level = log.level) ⇒ void
This method returns an undefined value.
Parses a path or set of paths
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/yard/parser/source_parser.rb', line 100 def parse(paths = DEFAULT_PATH_GLOB, excluded = [], level = log.level) log.debug("Parsing #{paths.inspect} with `#{parser_type}` parser") excluded = excluded.map do |path| case path when Regexp; path else Regexp.new(path.to_s, Regexp::IGNORECASE) end end files = [paths].flatten. map {|p| File.directory?(p) ? "#{p}/**/*.{rb,c,cc,cxx,cpp}" : p }. map {|p| p.include?("*") ? Dir[p].sort_by {|d| [d.length, d] } : p }.flatten. reject {|p| !File.file?(p) || excluded.any? {|re| p =~ re } } log.enter_level(level) do parse_in_order(*files.uniq) end end |
.parse_string(content, ptype = parser_type) ⇒ Object
Parses a string content
123 124 125 |
# File 'lib/yard/parser/source_parser.rb', line 123 def parse_string(content, ptype = parser_type) new(ptype).parse(StringIO.new(content)) end |
.parser_type_extensions ⇒ Hash
Returns a list of registered parser type extensions.
163 |
# File 'lib/yard/parser/source_parser.rb', line 163 def parser_type_extensions; @@parser_type_extensions ||= {} end |
.parser_type_extensions=(value) ⇒ Object
164 |
# File 'lib/yard/parser/source_parser.rb', line 164 def parser_type_extensions=(value) @@parser_type_extensions = value end |
.parser_type_for_extension(extension) ⇒ Symbol
Finds a parser type that is registered for the extension. If no type is found, the default Ruby type is returned.
171 172 173 174 175 176 |
# File 'lib/yard/parser/source_parser.rb', line 171 def parser_type_for_extension(extension) type = parser_type_extensions.find do |_t, exts| [exts].flatten.any? {|ext| ext === extension } end validated_parser_type(type ? type.first : :ruby) end |
.parser_types ⇒ Hash{Symbol=>Object}
Returns a list of registered parser types.
157 |
# File 'lib/yard/parser/source_parser.rb', line 157 def parser_types; @@parser_types ||= {} end |
.parser_types=(value) ⇒ Object
158 |
# File 'lib/yard/parser/source_parser.rb', line 158 def parser_types=(value) @@parser_types = value end |
.register_parser_type(type, parser_klass, extensions = nil) ⇒ void
This method returns an undefined value.
Registers a new parser type.
146 147 148 149 150 151 152 |
# File 'lib/yard/parser/source_parser.rb', line 146 def register_parser_type(type, parser_klass, extensions = nil) unless Base > parser_klass raise ArgumentError, "expecting parser_klass to be a subclass of YARD::Parser::Base" end parser_type_extensions[type.to_sym] = extensions if extensions parser_types[type.to_sym] = parser_klass end |
.tokenize(content, ptype = parser_type) ⇒ Array
Tokenizes but does not parse the block of code
132 133 134 |
# File 'lib/yard/parser/source_parser.rb', line 132 def tokenize(content, ptype = parser_type) new(ptype).tokenize(content) end |
.validated_parser_type(type) ⇒ Symbol
Returns the validated parser type. Basically, enforces that :ruby type is never set if the Ripper library is not available
184 185 186 |
# File 'lib/yard/parser/source_parser.rb', line 184 def validated_parser_type(type) !defined?(::Ripper) && type == :ruby ? :ruby18 : type end |
Instance Method Details
#parse(content = __FILE__) ⇒ Object?
The main parser method. This should not be called directly. Instead, use the class methods parse and parse_string.
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
# File 'lib/yard/parser/source_parser.rb', line 418 def parse(content = __FILE__) case content when String @file = File.cleanpath(content) content = convert_encoding(String.new(File.read_binary(file))) checksum = Registry.checksum_for(content) return if Registry.checksums[file] == checksum if Registry.checksums.key?(file) log.info "File '#{file}' was modified, re-processing..." end Registry.checksums[@file] = checksum self.parser_type = parser_type_for_filename(file) else content = content.read if content.respond_to? :read end @contents = content @parser = parser_class.new(content, file) self.class.before_parse_file_callbacks.each do |cb| return @parser if cb.call(self) == false end @parser.parse post_process self.class.after_parse_file_callbacks.each do |cb| cb.call(self) end @parser rescue ArgumentError, NotImplementedError => e log.warn("Cannot parse `#{file}': #{e.}") log.backtrace(e, :warn) rescue ParserSyntaxError => e log.warn(e..capitalize) log.backtrace(e, :warn) end |
#tokenize(content) ⇒ Array
Tokenizes but does not parse the block of code using the current #parser_type
462 463 464 465 |
# File 'lib/yard/parser/source_parser.rb', line 462 def tokenize(content) @parser = parser_class.new(content, file) @parser.tokenize end |