class RuboCop::Cop::Style::MagicCommentFormat

Ensures magic comments are written consistently throughout your code base. Looks for discrepancies in separators (`-` vs `_`) and capitalization for both magic comment directives and values.

Required capitalization can be set with the `DirectiveCapitalization` and `ValueCapitalization` configuration keys.

NOTE: If one of these configuration is set to nil, any capitalization is allowed.

@example EnforcedStyle: snake_case (default)

# The `snake_case` style will enforce that the frozen string literal
# comment is written in snake case. (Words separated by underscores)
# bad
# frozen-string-literal: true

module Bar
  # ...
end

# good
# frozen_string_literal: false

module Bar
  # ...
end

@example EnforcedStyle: kebab_case

# The `kebab_case` style will enforce that the frozen string literal
# comment is written in kebab case. (Words separated by hyphens)
# bad
# frozen_string_literal: true

module Baz
  # ...
end

# good
# frozen-string-literal: true

module Baz
  # ...
end

@example DirectiveCapitalization: lowercase (default)

# bad
# FROZEN-STRING-LITERAL: true

# good
# frozen-string-literal: true

@example DirectiveCapitalization: uppercase

# bad
# frozen-string-literal: true

# good
# FROZEN-STRING-LITERAL: true

@example DirectiveCapitalization: nil

# any capitalization is accepted

# good
# frozen-string-literal: true

# good
# FROZEN-STRING-LITERAL: true

@example ValueCapitalization: nil (default)

# any capitalization is accepted

# good
# frozen-string-literal: true

# good
# frozen-string-literal: TRUE

@example ValueCapitalization: lowercase

# when a value is not given, any capitalization is accepted

# bad
# frozen-string-literal: TRUE

# good
# frozen-string-literal: TRUE

@example ValueCapitalization: uppercase

# bad
# frozen-string-literal: true

# good
# frozen-string-literal: TRUE

Constants

KEBAB_SEPARATOR
MSG
MSG_VALUE
SNAKE_SEPARATOR

Public Instance Methods

on_new_investigation() click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 156
def on_new_investigation
  return unless processed_source.ast

  magic_comments.each do |comment|
    issues = find_issues(comment)
    register_offenses(issues) if issues.any?
  end
end

Private Instance Methods

correct_separator() click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 241
def correct_separator
  style == :snake_case ? SNAKE_SEPARATOR : KEBAB_SEPARATOR
end
directive_capitalization() click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 279
def directive_capitalization
  cop_config['DirectiveCapitalization']&.to_sym.tap do |style|
    unless valid_capitalization?(style)
      raise "Unknown `DirectiveCapitalization` #{style} selected!"
    end
  end
end
directive_offends?(directive) click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 197
def directive_offends?(directive)
  incorrect_separator?(directive.source) ||
    wrong_capitalization?(directive.source, directive_capitalization)
end
expected_style() click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 233
def expected_style
  [directive_capitalization, style].compact.join(' ').gsub(/_?case\b/, '')
end
find_issues(comment) click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 183
def find_issues(comment)
  issues = { directives: [], values: [] }

  comment.directives.each do |directive|
    issues[:directives] << directive if directive_offends?(directive)
  end

  comment.values.each do |value| # rubocop:disable Style/HashEachMethods
    issues[:values] << value if wrong_capitalization?(value.source, value_capitalization)
  end

  issues
end
fix_directives(issues) click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 207
def fix_directives(issues)
  return if issues.empty?

  msg = format(MSG, style: expected_style)

  issues.each do |directive|
    add_offense(directive, message: msg) do |corrector|
      replacement = replace_separator(replace_capitalization(directive.source,
                                                             directive_capitalization))
      corrector.replace(directive, replacement)
    end
  end
end
fix_values(issues) click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 221
def fix_values(issues)
  return if issues.empty?

  msg = format(MSG_VALUE, case: value_capitalization)

  issues.each do |value|
    add_offense(value, message: msg) do |corrector|
      corrector.replace(value, replace_capitalization(value.source, value_capitalization))
    end
  end
end
incorrect_separator?(text) click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 245
def incorrect_separator?(text)
  text[wrong_separator]
end
leading_comment_lines() click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 173
def leading_comment_lines
  first_non_comment_token = processed_source.tokens.find { |token| !token.comment? }

  if first_non_comment_token
    0...first_non_comment_token.line
  else
    (0..)
  end
end
line_range(line) click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 275
def line_range(line)
  processed_source.buffer.line_range(line)
end
magic_comments() click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 167
def magic_comments
  processed_source.each_comment_in_lines(leading_comment_lines)
                  .select { |comment| MagicComment.parse(comment.text).valid? }
                  .map { |comment| CommentRange.new(comment) }
end
register_offenses(issues) click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 202
def register_offenses(issues)
  fix_directives(issues[:directives])
  fix_values(issues[:values])
end
replace_capitalization(text, style) click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 264
def replace_capitalization(text, style)
  return text unless style

  case style
  when :lowercase
    text.downcase
  when :uppercase
    text.upcase
  end
end
replace_separator(text) click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 260
def replace_separator(text)
  text.tr(wrong_separator, correct_separator)
end
supported_capitalizations() click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 301
def supported_capitalizations
  cop_config['SupportedCapitalizations'].map(&:to_sym)
end
valid_capitalization?(style) click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 295
def valid_capitalization?(style)
  return true unless style

  supported_capitalizations.include?(style)
end
value_capitalization() click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 287
def value_capitalization
  cop_config['ValueCapitalization']&.to_sym.tap do |style|
    unless valid_capitalization?(style)
      raise "Unknown `ValueCapitalization` #{style} selected!"
    end
  end
end
wrong_capitalization?(text, expected_case) click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 249
def wrong_capitalization?(text, expected_case)
  return false unless expected_case

  case expected_case
  when :lowercase
    text != text.downcase
  when :uppercase
    text != text.upcase
  end
end
wrong_separator() click to toggle source
# File lib/rubocop/cop/style/magic_comment_format.rb, line 237
def wrong_separator
  style == :snake_case ? KEBAB_SEPARATOR : SNAKE_SEPARATOR
end