Class: RuboCop::AST::ProcessedSource

Inherits:
Object
  • Object
show all
Defined in:
lib/rubocop/ast/processed_source.rb

Overview

ProcessedSource contains objects which are generated by Parser and other information such as disabled lines for cops. It also provides a convenient way to access source lines.

Constant Summary collapse

STRING_SOURCE_NAME =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

'(string)'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, ruby_version, path = nil, parser_engine: :parser_whitequark) ⇒ ProcessedSource

Returns a new instance of ProcessedSource.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/rubocop/ast/processed_source.rb', line 29

def initialize(source, ruby_version, path = nil, parser_engine: :parser_whitequark)
  unless PARSER_ENGINES.include?(parser_engine)
    raise ArgumentError, 'The keyword argument `parser_engine` accepts ' \
                         "`parser` or `parser_prism`, but `#{parser_engine}` was passed."
  end

  # Defaults source encoding to UTF-8, regardless of the encoding it has
  # been read with, which could be non-utf8 depending on the default
  # external encoding.
  (+source).force_encoding(Encoding::UTF_8) unless source.encoding == Encoding::UTF_8

  @raw_source = source
  @path = path
  @diagnostics = []
  @ruby_version = ruby_version
  @parser_engine = parser_engine
  @parser_error = nil

  parse(source, ruby_version, parser_engine)
end

Instance Attribute Details

#astObject (readonly)

Returns the value of attribute ast.



21
22
23
# File 'lib/rubocop/ast/processed_source.rb', line 21

def ast
  @ast
end

#bufferObject (readonly)

Returns the value of attribute buffer.



21
22
23
# File 'lib/rubocop/ast/processed_source.rb', line 21

def buffer
  @buffer
end

#commentsObject (readonly)

Returns the value of attribute comments.



21
22
23
# File 'lib/rubocop/ast/processed_source.rb', line 21

def comments
  @comments
end

#diagnosticsObject (readonly)

Returns the value of attribute diagnostics.



21
22
23
# File 'lib/rubocop/ast/processed_source.rb', line 21

def diagnostics
  @diagnostics
end

#parser_engineObject (readonly)

Returns the value of attribute parser_engine.



21
22
23
# File 'lib/rubocop/ast/processed_source.rb', line 21

def parser_engine
  @parser_engine
end

#parser_errorObject (readonly)

Returns the value of attribute parser_error.



21
22
23
# File 'lib/rubocop/ast/processed_source.rb', line 21

def parser_error
  @parser_error
end

#pathObject (readonly)

Returns the value of attribute path.



21
22
23
# File 'lib/rubocop/ast/processed_source.rb', line 21

def path
  @path
end

#raw_sourceObject (readonly)

Returns the value of attribute raw_source.



21
22
23
# File 'lib/rubocop/ast/processed_source.rb', line 21

def raw_source
  @raw_source
end

#ruby_versionObject (readonly)

Returns the value of attribute ruby_version.



21
22
23
# File 'lib/rubocop/ast/processed_source.rb', line 21

def ruby_version
  @ruby_version
end

#tokensObject (readonly)

Returns the value of attribute tokens.



21
22
23
# File 'lib/rubocop/ast/processed_source.rb', line 21

def tokens
  @tokens
end

Class Method Details

.from_file(path, ruby_version, parser_engine: :parser_whitequark) ⇒ Object



24
25
26
27
# File 'lib/rubocop/ast/processed_source.rb', line 24

def self.from_file(path, ruby_version, parser_engine: :parser_whitequark)
  file = File.read(path, mode: 'rb')
  new(file, ruby_version, path, parser_engine: parser_engine)
end

Instance Method Details

#[](*args) ⇒ Object



72
73
74
# File 'lib/rubocop/ast/processed_source.rb', line 72

def [](*args)
  lines[*args]
end

#ast_with_commentsObject



50
51
52
53
54
# File 'lib/rubocop/ast/processed_source.rb', line 50

def ast_with_comments
  return if !ast || !comments

  @ast_with_comments ||= Parser::Source::Comment.associate_by_identity(ast, comments)
end

#blank?Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/rubocop/ast/processed_source.rb', line 111

def blank?
  ast.nil?
end

#checksumObject

Raw source checksum for tracking infinite loops.



83
84
85
# File 'lib/rubocop/ast/processed_source.rb', line 83

def checksum
  Digest::SHA1.hexdigest(@raw_source)
end

#comment_at_line(line) ⇒ Comment?

Returns the comment at that line, if any.

Returns:

  • (Comment, nil)

    the comment at that line, if any.



116
117
118
# File 'lib/rubocop/ast/processed_source.rb', line 116

def comment_at_line(line)
  comment_index[line]
end

#comments_before_line(line) ⇒ Object

Deprecated.

Use ‘each_comment_in_lines`

Should have been called ‘comments_before_or_at_line`. Doubtful it has of any valid use.



146
147
148
# File 'lib/rubocop/ast/processed_source.rb', line 146

def comments_before_line(line)
  each_comment_in_lines(0..line).to_a
end

#contains_comment?(source_range) ⇒ Boolean Also known as: commented?

Consider using ‘each_comment_in_lines` instead

Returns:

  • (Boolean)

    if any of the lines in the given ‘source_range` has a comment.



138
139
140
# File 'lib/rubocop/ast/processed_source.rb', line 138

def contains_comment?(source_range)
  each_comment_in_lines(source_range.line..source_range.last_line).any?
end

#current_line(token) ⇒ Object



160
161
162
# File 'lib/rubocop/ast/processed_source.rb', line 160

def current_line(token)
  lines[token.line - 1]
end

#each_comment(&block) ⇒ Object

Deprecated.

Use ‘comments.each`



88
89
90
# File 'lib/rubocop/ast/processed_source.rb', line 88

def each_comment(&block)
  comments.each(&block)
end

#each_comment_in_lines(line_range) ⇒ Object

Enumerates on the comments contained with the given ‘line_range`



126
127
128
129
130
131
132
133
134
# File 'lib/rubocop/ast/processed_source.rb', line 126

def each_comment_in_lines(line_range)
  return to_enum(:each_comment_in_lines, line_range) unless block_given?

  line_range.each do |line|
    if (comment = comment_index[line])
      yield comment
    end
  end
end

#each_token(&block) ⇒ Object

Deprecated.

Use ‘tokens.each`



98
99
100
# File 'lib/rubocop/ast/processed_source.rb', line 98

def each_token(&block)
  tokens.each(&block)
end

#file_pathObject



107
108
109
# File 'lib/rubocop/ast/processed_source.rb', line 107

def file_path
  buffer.name
end

#find_comment(&block) ⇒ Object

Deprecated.

Use ‘comment_at_line`, `each_comment_in_lines`, or `comments.find`



93
94
95
# File 'lib/rubocop/ast/processed_source.rb', line 93

def find_comment(&block)
  comments.find(&block)
end

#find_token(&block) ⇒ Object

Deprecated.

Use ‘tokens.find`



103
104
105
# File 'lib/rubocop/ast/processed_source.rb', line 103

def find_token(&block)
  tokens.find(&block)
end

#first_token_of(range_or_node) ⇒ Object



181
182
183
# File 'lib/rubocop/ast/processed_source.rb', line 181

def first_token_of(range_or_node)
  sorted_tokens[first_token_index(range_or_node)]
end

#following_line(token) ⇒ Object



164
165
166
# File 'lib/rubocop/ast/processed_source.rb', line 164

def following_line(token)
  lines[token.line]
end

#last_token_of(range_or_node) ⇒ Object



185
186
187
# File 'lib/rubocop/ast/processed_source.rb', line 185

def last_token_of(range_or_node)
  sorted_tokens[last_token_index(range_or_node)]
end

#line_indentation(line_number) ⇒ Object



168
169
170
171
172
173
# File 'lib/rubocop/ast/processed_source.rb', line 168

def line_indentation(line_number)
  lines[line_number - 1]
    .match(/^(\s*)/)[1]
    .to_s
    .length
end

#line_with_comment?(line) ⇒ Boolean

Returns if the given line number has a comment.

Returns:

  • (Boolean)

    if the given line number has a comment.



121
122
123
# File 'lib/rubocop/ast/processed_source.rb', line 121

def line_with_comment?(line)
  comment_index.include?(line)
end

#linesObject

Returns the source lines, line break characters removed, excluding a possible __END__ and everything that comes after.



58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/rubocop/ast/processed_source.rb', line 58

def lines
  @lines ||= begin
    all_lines = @buffer.source_lines
    last_token_line = tokens.any? ? tokens.last.line : all_lines.size
    result = []
    all_lines.each_with_index do |line, ix|
      break if ix >= last_token_line && line == '__END__'

      result << line
    end
    result
  end
end

#preceding_line(token) ⇒ Object



156
157
158
# File 'lib/rubocop/ast/processed_source.rb', line 156

def preceding_line(token)
  lines[token.line - 2]
end

#sorted_tokensObject

The tokens list is always sorted by token position, except for cases when heredoc is passed as a method argument. In this case tokens are interleaved by heredoc contents’ tokens.



192
193
194
195
# File 'lib/rubocop/ast/processed_source.rb', line 192

def sorted_tokens
  # Use stable sort.
  @sorted_tokens ||= tokens.sort_by.with_index { |token, i| [token.begin_pos, i] }
end

#start_with?(string) ⇒ Boolean

Returns:

  • (Boolean)


150
151
152
153
154
# File 'lib/rubocop/ast/processed_source.rb', line 150

def start_with?(string)
  return false if self[0].nil?

  self[0].start_with?(string)
end

#tokens_within(range_or_node) ⇒ Object



175
176
177
178
179
# File 'lib/rubocop/ast/processed_source.rb', line 175

def tokens_within(range_or_node)
  begin_index = first_token_index(range_or_node)
  end_index = last_token_index(range_or_node)
  sorted_tokens[begin_index..end_index]
end

#valid_syntax?Boolean

Returns:

  • (Boolean)


76
77
78
79
80
# File 'lib/rubocop/ast/processed_source.rb', line 76

def valid_syntax?
  return false if @parser_error

  @diagnostics.none? { |d| INVALID_LEVELS.include?(d.level) }
end