lib/reek/source/source_code.rb in reek-2.2.1 vs lib/reek/source/source_code.rb in reek-3.0.0

- old
+ new

@@ -1,26 +1,28 @@ require_relative '../cli/silencer' Reek::CLI::Silencer.silently do - require 'parser/current' + require 'parser/ruby22' end -require_relative '../core/tree_dresser' -require_relative '../core/ast_node' +require_relative '../tree_dresser' +require_relative '../ast/node' module Reek + # @api private module Source # # A +Source+ object represents a chunk of Ruby source code. # + # @api private class SourceCode attr_reader :description # Initializer. # # code - ruby code as String # description - in case of STDIN this is "STDIN" otherwise it's a filepath as String # parser - the parser to use for generating AST's out of the given source - def initialize(code, description, parser = Parser::Ruby21) + def initialize(code, description, parser = Parser::Ruby22) @source = code @description = description @parser = parser end @@ -28,34 +30,63 @@ # This source can come via 3 different ways: # - from files a la `reek lib/reek/` # - from IO (STDIN) a la `echo "class Foo; end" | reek` # - from String via our rspec matchers a la `expect("class Foo; end").to reek` # - # source - One of File|IO|String + # @param source [File|IO|String] - the given source # - # Returns an instance of SourceCode + # @return an instance of SourceCode def self.from(source) case source when File then new(source.read, source.path) when IO then new(source.readlines.join, 'STDIN') when String then new(source, 'string') end end - # Parses the given source into an AST. + # Parses the given source into an AST and associates the source code comments with it. + # This AST is then traversed by a TreeDresser which adorns the nodes in the AST + # with our SexpExtensions. + # Finally this AST is returned where each node is an anonymous subclass of Reek::AST::Node # - # @return [Reek::Core::ASTNode] the AST presentation of the given source + # Important to note is that reek will not fail on unparseable files but rather print out + # a warning and then just continue. + # + # Given this @source: + # + # # comment about C + # class C + # def m + # puts 'nada' + # end + # end + # + # this method would return something that looks like + # + # (class + # (const nil :C) nil + # (def :m + # (args) + # (send nil :puts + # (str "nada")))) + # + # where each node is possibly adorned with our SexpExtensions (see ast/ast_node_class_map + # and ast/sexp_extensions for details). + # + # @return [Anonymous subclass of Reek::AST::Node] the AST presentation + # for the given source def syntax_tree @syntax_tree ||= begin begin ast, comments = @parser.parse_with_comments(@source, @description) rescue Racc::ParseError, Parser::SyntaxError => error $stderr.puts "#{description}: #{error.class.name}: #{error}" end + # See https://whitequark.github.io/parser/Parser/Source/Comment/Associator.html comment_map = Parser::Source::Comment.associate(ast, comments) if ast - Core::TreeDresser.new.dress(ast, comment_map) + TreeDresser.new.dress(ast, comment_map) end end end end end