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
49
# File 'lib/rubocop/ast/processed_source.rb', line 29

def initialize(source, ruby_version, path = nil, parser_engine: :parser_whitequark)
  parser_engine = parser_engine.to_sym
  unless PARSER_ENGINES.include?(parser_engine)
    raise ArgumentError, 'The keyword argument `parser_engine` accepts `parser_whitequark` ' \
                         "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



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

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

#ast_with_commentsObject



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

def ast_with_comments
  return if !ast || !comments

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

#blank?Boolean

Returns:

  • (Boolean)


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

def blank?
  ast.nil?
end

#checksumObject

Raw source checksum for tracking infinite loops.



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

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.



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

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.



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

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.



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

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

#current_line(token) ⇒ Object



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

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

#each_comment(&block) ⇒ Object

Deprecated.

Use ‘comments.each`



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

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`



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

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`



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

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

#file_pathObject



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

def file_path
  buffer.name
end

#find_comment(&block) ⇒ Object

Deprecated.

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



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

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

#find_token(&block) ⇒ Object

Deprecated.

Use ‘tokens.find`



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

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

#first_token_of(range_or_node) ⇒ Object



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

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

#following_line(token) ⇒ Object



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

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

#last_token_of(range_or_node) ⇒ Object



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

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

#line_indentation(line_number) ⇒ Object



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

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.



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

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.



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

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



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

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.



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

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)


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

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

  self[0].start_with?(string)
end

#tokens_within(range_or_node) ⇒ Object



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

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)


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

def valid_syntax?
  return false if @parser_error

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