class RuboCop::Cop::Style::MagicCommentFormat
# frozen-string-literal: TRUE
# good
# frozen-string-literal: true
# bad
@example ValueCapitalization: uppercase
# frozen-string-literal: TRUE
# good
# frozen-string-literal: TRUE
# bad
# when a value is not given, any capitalization is accepted
@example ValueCapitalization: lowercase
# frozen-string-literal: TRUE
# good
# frozen-string-literal: true
# good
# any capitalization is accepted
@example ValueCapitalization: nil (default)
# FROZEN-STRING-LITERAL: true
# good
# frozen-string-literal: true
# good
# any capitalization is accepted
@example DirectiveCapitalization: nil
# FROZEN-STRING-LITERAL: true
# good
# frozen-string-literal: true
# bad
@example DirectiveCapitalization: uppercase
# frozen-string-literal: true
# good
# FROZEN-STRING-LITERAL: true
# bad
@example DirectiveCapitalization: lowercase (default)
end
# …
module Baz
# frozen-string-literal: true
# good
end
# …
module Baz
# frozen_string_literal: true
# bad
# comment is written in kebab case. (Words separated by hyphens)
# The ‘kebab_case` style will enforce that the frozen string literal
@example EnforcedStyle: kebab_case
end
# …
module Bar
# frozen_string_literal: false
# good
end
# …
module Bar
# frozen-string-literal: true
# bad
# comment is written in snake case. (Words separated by underscores)
# The `snake_case` style will enforce that the frozen string literal
@example EnforcedStyle: snake_case (default)
NOTE: If one of these configuration is set to nil, any capitalization is allowed.
`ValueCapitalization` configuration keys.
Required capitalization can be set with the `DirectiveCapitalization` and
both magic comment directives and values.
Looks for discrepancies in separators (`-` vs `_`) and capitalization for
Ensures magic comments are written consistently throughout your code base.
def correct_separator
def correct_separator style == :snake_case ? SNAKE_SEPARATOR : KEBAB_SEPARATOR end
def directive_capitalization
def directive_capitalization cop_config['DirectiveCapitalization']&.to_sym.tap do |style| unless valid_capitalization?(style) raise "Unknown `DirectiveCapitalization` #{style} selected!" end end end
def directive_offends?(directive)
def directive_offends?(directive) incorrect_separator?(directive.source) || wrong_capitalization?(directive.source, directive_capitalization) end
def expected_style
def expected_style [directive_capitalization, style].compact.join(' ').gsub(/_?case\b/, '') end
def find_issues(comment)
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
def fix_directives(issues)
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
def fix_values(issues)
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
def incorrect_separator?(text)
def incorrect_separator?(text) text[wrong_separator] end
def leading_comment_lines
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
def line_range(line)
def line_range(line) processed_source.buffer.line_range(line) end
def magic_comments
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
def on_new_investigation
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
def register_offenses(issues)
def register_offenses(issues) fix_directives(issues[:directives]) fix_values(issues[:values]) end
def replace_capitalization(text, style)
def replace_capitalization(text, style) return text unless style case style when :lowercase text.downcase when :uppercase text.upcase end end
def replace_separator(text)
def replace_separator(text) text.tr(wrong_separator, correct_separator) end
def supported_capitalizations
def supported_capitalizations cop_config['SupportedCapitalizations'].map(&:to_sym) end
def valid_capitalization?(style)
def valid_capitalization?(style) return true unless style supported_capitalizations.include?(style) end
def value_capitalization
def value_capitalization cop_config['ValueCapitalization']&.to_sym.tap do |style| unless valid_capitalization?(style) raise "Unknown `ValueCapitalization` #{style} selected!" end end end
def wrong_capitalization?(text, expected_case)
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
def wrong_separator
def wrong_separator style == :snake_case ? KEBAB_SEPARATOR : SNAKE_SEPARATOR end