123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::DirectiveComment

Relationships & Source Files
Inherits: Object
Defined in: lib/rubocop/directive_comment.rb

Overview

This class wraps the Parser::Source::Comment object that represents a special rubocop:disable and rubocop:enable comment and exposes what cops it contains.

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(comment, cop_registry = Cop::Registry.global) ⇒ DirectiveComment

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 61

def initialize(comment, cop_registry = Cop::Registry.global)
  @comment = comment
  @cop_registry = cop_registry
  match_data = comment.text.match(DIRECTIVE_COMMENT_REGEXP)
  @match_data = match_data&.pre_match&.match?(/\A#\s*\z/) ? nil : match_data
  @mode, @cops = match_captures
end

Class Method Details

.before_comment(line)

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 55

def self.before_comment(line)
  line.split(DIRECTIVE_COMMENT_REGEXP).first
end

Instance Attribute Details

#all_cops?Boolean (readonly)

Checks if all cops specified in this directive

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 207

def all_cops?
  cops == 'all'
end

#comment (readonly)

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 59

attr_reader :comment, :cop_registry, :mode, :cops

#cop_registry (readonly)

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 59

attr_reader :comment, :cop_registry, :mode, :cops

#cops (readonly)

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 59

attr_reader :comment, :cop_registry, :mode, :cops

#disable_next?Boolean (readonly)

Checks if this directive disables cops for the next statement only

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 160

def disable_next?
  %w[disable-next todo-next].include?(mode)
end

#disabled?Boolean (readonly)

Checks if this directive disables cops

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 155

def disabled?
  %w[disable todo].include?(mode) || disable_next?
end

#disabled_all?Boolean (readonly)

Checks if this directive disables all cops

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 202

def disabled_all?
  disabled? && all_cops?
end

#enable_next?Boolean (readonly)

Checks if this directive enables cops for the next statement only

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 170

def enable_next?
  mode == 'enable-next'
end

#enabled?Boolean (readonly)

Checks if this directive enables cops

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 165

def enabled?
  mode == 'enable' || enable_next?
end

#enabled_all?Boolean (readonly)

Checks if this directive enables all cops

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 197

def enabled_all?
  !disabled? && all_cops?
end

#invalid_signed_args?Boolean (readonly)

push and next arguments must be +/- prefixed cop names, and pop takes no arguments at all.

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 92

def invalid_signed_args?
  return cops ? !cops.empty? : false if pop?
  return false unless push? || next?
  return false unless cops

  cops.split.any? { |cop_spec| !cop_spec.start_with?('+', '-') }
end

#malformed?Boolean (readonly)

Checks if the comment is malformed as a # rubocop: directive

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 75

def malformed?
  return true if !start_with_marker? || @match_data.nil?
  return true if missing_cop_name? || invalid_signed_args?

  tail = @match_data.post_match.lstrip
  !(tail.empty? || tail.start_with?(TRAILING_COMMENT_MARKER))
end

#missing_cop_name?Boolean (readonly)

Checks if the directive comment is missing a cop name

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 84

def missing_cop_name?
  return false if push? || pop?

  MALFORMED_DIRECTIVE_WITHOUT_COP_NAME_REGEXP.match?(comment.text)
end

#mode (readonly)

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 59

attr_reader :comment, :cop_registry, :mode, :cops

#next?Boolean (readonly)

Checks if this directive toggles cops for the next statement only

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 185

def next?
  mode == 'next'
end

#pop?Boolean (readonly)

Checks if this directive is a pop

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 180

def pop?
  mode == 'pop'
end

#push?Boolean (readonly)

Checks if this directive is a push

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 175

def push?
  mode == 'push'
end

#single_line?Boolean (readonly)

Checks if this directive relates to single line

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 113

def single_line?
  !comment.text.start_with?(DIRECTIVE_COMMENT_REGEXP)
end

#start_with_marker?Boolean (readonly)

Checks if the comment starts with # rubocop: marker

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 70

def start_with_marker?
  comment.text.start_with?(DIRECTIVE_MARKER_REGEXP)
end

Instance Method Details

#all_cop_names (private)

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 261

def all_cop_names
  exclude_lint_department_cops(cop_registry.names)
end

#cop_names

Returns array of specified in this directive cop names

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 212

def cop_names
  @cop_names ||= all_cops? ? all_cop_names : parsed_cop_names
end

#cop_names_for_department(department) (private)

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 265

def cop_names_for_department(department)
  names = cop_registry.names_for_department(department)
  department == LINT_DEPARTMENT ? exclude_lint_department_cops(names) : names
end

#department?(name) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 257

def department?(name)
  cop_registry.department?(name)
end

#department_names

Returns array of specified in this directive department names when all department disabled

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 223

def department_names
  raw_cop_names.select { |cop| department?(cop) }
end

#directive_count

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 237

def directive_count
  return signed_args.values.sum(&:count) if push? || next?

  raw_cop_names.count
end

#exclude_lint_department_cops(cops) (private)

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 270

def exclude_lint_department_cops(cops)
  cops - [LINT_REDUNDANT_DIRECTIVE_COP, LINT_SYNTAX_COP]
end

#in_directive_department?(cop) ⇒ Boolean

Checks if directive departments include cop

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 228

def in_directive_department?(cop)
  department_names.any? { |department| cop.start_with?(department) }
end

#line_number

Returns line number for directive

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 244

def line_number
  comment.source_range.line
end

#match?(cop_names) ⇒ Boolean

Checks if this directive contains all the given cop names

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 118

def match?(cop_names)
  parsed_cop_names.uniq.sort == cop_names.uniq.sort
end

#match_captures

Returns match captures to directive comment pattern

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 144

def match_captures
  @match_captures ||= @match_data && begin
    captures = @match_data.captures
    mode = captures[0]
    # COPS_PATTERN is at captures[1], PUSH_POP_ARGS_PATTERN is at captures[4]
    cops = captures[1] || captures[4]
    [mode, cops]
  end
end

#overridden_by_department?(cop) ⇒ Boolean

Checks if cop department has already used in directive comment

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 233

def overridden_by_department?(cop)
  in_directive_department?(cop) && raw_cop_names.include?(cop)
end

#parse_signed_args (private)

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 274

def parse_signed_args
  return {} unless (push? || next?) && cops

  args = {}
  cops.split.each do |cop_spec|
    op = cop_spec[0]
    cop_name = cop_spec[1..]
    next unless SIGNED_OPERATIONS.include?(op)

    args[op] ||= []
    args[op] << cop_name
  end
  args
end

#parsed_cop_names (private)

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 250

def parsed_cop_names
  cops = raw_cop_names.map do |name|
    department?(name) ? cop_names_for_department(name) : name
  end.flatten
  cops - [LINT_SYNTAX_COP]
end

#push_args

Alias for #signed_args.

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 194

alias push_args signed_args

#range

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 122

def range
  match = comment.text.match(DIRECTIVE_COMMENT_REGEXP)
  begin_pos = comment.source_range.begin_pos
  Parser::Source::Range.new(
    comment.source_range.source_buffer, begin_pos + match.begin(0), begin_pos + match.end(0)
  )
end

#range_with_reason

#range stops at the cop list, so a -- reason sits outside it. The reason documents the directive and means nothing once the directive is gone, so removal has to cover both. Any other trailing text is an ordinary comment and is left alone.

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 133

def range_with_reason
  directive_range = range
  trailing = Parser::Source::Range.new(
    comment.source_range.source_buffer, directive_range.end_pos, comment.source_range.end_pos
  )
  return directive_range unless trailing.source.lstrip.start_with?(TRAILING_COMMENT_MARKER)

  directive_range.with(end_pos: comment.source_range.end_pos)
end

#raw_cop_names

Returns an array of cops for this directive comment, without resolving departments

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 217

def raw_cop_names
  @raw_cop_names ||= (cops || '').split(/,\s*/)
end

#reason

The text of the directive’s optional -- trailing comment, or nil when there is none.

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 102

def reason
  return unless @match_data

  tail = @match_data.post_match.lstrip
  return unless tail.start_with?(TRAILING_COMMENT_MARKER)

  reason = tail.delete_prefix(TRAILING_COMMENT_MARKER).strip
  reason unless reason.empty?
end

#signed_args Also known as: #push_args

Returns the +/- arguments of a push or next directive as a hash of operations to cop names

[ GitHub ]

  
# File 'lib/rubocop/directive_comment.rb', line 191

def signed_args
  @signed_args ||= parse_signed_args
end