Class: Reek::Source::SourceCode

Inherits:
Object
  • Object
show all
Defined in:
lib/reek/source/source_code.rb

Overview

A SourceCode object represents a chunk of Ruby source code.

Constant Summary collapse

IO_IDENTIFIER =
'STDIN'
STRING_IDENTIFIER =
'string'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source:, origin: nil, parser: self.class.default_parser) ⇒ SourceCode

Initializer.

Parameters:

  • source (File|Pathname|IO|String)

    Ruby source code

  • origin (String) (defaults to: nil)

    Origin of the source code. Will be determined automatically if left blank.

  • parser (defaults to: self.class.default_parser)

    the parser to use for generating AST's out of the given code


28
29
30
31
32
# File 'lib/reek/source/source_code.rb', line 28

def initialize(source:, origin: nil, parser: self.class.default_parser)
  @origin = origin
  @parser = parser
  @source = source
end

Instance Attribute Details

#parserObject (readonly, private)

Returns the value of attribute parser


85
86
87
# File 'lib/reek/source/source_code.rb', line 85

def parser
  @parser
end

#sourceObject (readonly, private)

Returns the value of attribute source


85
86
87
# File 'lib/reek/source/source_code.rb', line 85

def source
  @source
end

Class Method Details

.default_parserObject


56
57
58
59
60
61
62
# File 'lib/reek/source/source_code.rb', line 56

def self.default_parser
  Parser::CurrentRuby.new(AST::Builder.new).tap do |parser|
    diagnostics = parser.diagnostics
    diagnostics.all_errors_are_fatal = true
    diagnostics.ignore_warnings      = true
  end
end

.from(source, origin: nil) ⇒ Object

Initializes an instance of SourceCode given a source. This source can come via several different ways:

  • from Files or Pathnames 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`

  • from an existing SourceCode object. This is passed through unchanged

Parameters:

  • source (SourceCode|File|Pathname|IO|String)

    the given source

  • origin (String|nil) (defaults to: nil)

Returns:

  • an instance of SourceCode


45
46
47
48
49
50
# File 'lib/reek/source/source_code.rb', line 45

def self.from(source, origin: nil)
  case source
  when self then source
  else new(source: source, origin: origin)
  end
end

Instance Method Details

#codeObject (private)


76
77
78
79
80
81
82
83
# File 'lib/reek/source/source_code.rb', line 76

def code
  @code ||=
    case source
    when File, Pathname then source.read
    when IO             then source.readlines.join
    when String         then source
    end.force_encoding(Encoding::UTF_8)
end

#originObject


64
65
66
67
68
69
70
71
72
# File 'lib/reek/source/source_code.rb', line 64

def origin
  @origin ||=
    case source
    when File     then source.path
    when IO       then IO_IDENTIFIER
    when Pathname then source.to_s
    when String   then STRING_IDENTIFIER
    end
end

#parseObject (private)

Parses the given code 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

Given this @code:

# 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).

Returns:

  • Reek::AST::Node the AST presentation for the given code


114
115
116
117
118
119
120
121
122
# File 'lib/reek/source/source_code.rb', line 114

def parse
  buffer = Parser::Source::Buffer.new(origin, 1)
  buffer.source = code
  ast, comments = parser.parse_with_comments(buffer)

  # See https://whitequark.github.io/parser/Parser/Source/Comment/Associator.html
  comment_map = Parser::Source::Comment.associate(ast, comments)
  TreeDresser.new.dress(ast, comment_map) || AST::Node.new(:empty)
end

#syntax_treeObject


52
53
54
# File 'lib/reek/source/source_code.rb', line 52

def syntax_tree
  @syntax_tree ||= parse
end