Class: RuboCop::Cop::Style::FormatStringToken

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Includes:
AllowedMethods, AllowedPattern, ConfigurableEnforcedStyle
Defined in:
lib/rubocop/cop/style/format_string_token.rb

Overview

Use a consistent style for tokens within a format string.

By default, all strings are evaluated. In some cases, this may be undesirable, as they could be used as arguments to a method that does not consider them to be tokens, but rather other identifiers or just part of the string.

AllowedMethods or AllowedPatterns can be configured with in order to mark specific methods as always allowed, thereby avoiding an offense from the cop. By default, there are no allowed methods.

Additionally, the cop can be made conservative by configuring it with ‘Mode: conservative` (default aggressive). In this mode, tokens (regardless of EnforcedStyle) are only considered if used in the format string argument to the methods printf, sprintf, format and `%`.

NOTE: In aggressive mode, offenses are registered for all strings containing tokens, but autocorrection is only applied when the string appears in a known formatting context (format, sprintf, printf, or ‘%`). This is done in order to prevent false autocorrections for strings that are not actually format strings.

NOTE: Tokens in the unannotated style (eg. ‘%s`) are always treated as if configured with `Conservative: true`. This is done in order to prevent false positives, because this format is very similar to encoded URLs or Date/Time formatting strings.

It is allowed to contain unannotated token if the number of them is less than or equals to MaxUnannotatedPlaceholdersAllowed.

Examples:

EnforcedStyle: annotated (default)


# bad
format('%{greeting}', greeting: 'Hello')
format('%s', 'Hello')

# good
format('%<greeting>s', greeting: 'Hello')

EnforcedStyle: template


# bad
format('%<greeting>s', greeting: 'Hello')
format('%s', 'Hello')

# good
format('%{greeting}', greeting: 'Hello')

EnforcedStyle: unannotated


# bad
format('%<greeting>s', greeting: 'Hello')
format('%{greeting}', greeting: 'Hello')

# good
format('%s', 'Hello')

MaxUnannotatedPlaceholdersAllowed: 0


# bad
format('%06d', 10)
format('%s %s.', 'Hello', 'world')

# good
format('%<number>06d', number: 10)

MaxUnannotatedPlaceholdersAllowed: 1 (default)


# bad
format('%s %s.', 'Hello', 'world')

# good
format('%06d', 10)

AllowedMethods: [] (default)


# bad
redirect('foo/%{bar_id}')

AllowedMethods: [redirect]


# good
redirect('foo/%{bar_id}')

AllowedPatterns: [] (default)


# bad
redirect('foo/%{bar_id}')

AllowedPatterns: [‘redirect’]


# good
redirect('foo/%{bar_id}')

Mode: aggressive (default), EnforcedStyle: annotated


# bad
"%{greeting}"
foo("%{greeting}")

# bad
format("%{greeting}", greeting: 'Hello')
printf("%{greeting}", greeting: 'Hello')
sprintf("%{greeting}", greeting: 'Hello')
"%{greeting}" % { greeting: 'Hello' }

# good
format("%<greeting>s", greeting: 'Hello')
printf("%<greeting>s", greeting: 'Hello')
sprintf("%<greeting>s", greeting: 'Hello')
"%<greeting>s" % { greeting: 'Hello' }

Mode: conservative, EnforcedStyle: annotated


# good
"%{greeting}"
foo("%{greeting}")

# bad
format("%{greeting}", greeting: 'Hello')
printf("%{greeting}", greeting: 'Hello')
sprintf("%{greeting}", greeting: 'Hello')
"%{greeting}" % { greeting: 'Hello' }

# good
format("%<greeting>s", greeting: 'Hello')
printf("%<greeting>s", greeting: 'Hello')
sprintf("%<greeting>s", greeting: 'Hello')
"%<greeting>s" % { greeting: 'Hello' }

Constant Summary

Constants inherited from Base

Base::RESTRICT_ON_SEND

Instance Attribute Summary

Attributes inherited from Base

#config, #processed_source

Instance Method Summary collapse

Methods included from AutoCorrector

support_autocorrect?

Methods included from ConfigurableEnforcedStyle

#alternative_style, #alternative_styles, #ambiguous_style_detected, #correct_style_detected, #detected_style, #detected_style=, #no_acceptable_style!, #no_acceptable_style?, #opposite_style_detected, #style, #style_configured?, #style_detected, #style_parameter_name, #supported_styles, #unexpected_style_detected

Methods inherited from Base

#active_support_extensions_enabled?, #add_global_offense, #add_offense, #always_autocorrect?, autocorrect_incompatible_with, badge, #begin_investigation, #callbacks_needed, callbacks_needed, #config_to_allow_offenses, #config_to_allow_offenses=, #contextual_autocorrect?, #cop_config, cop_name, #cop_name, department, documentation_url, exclude_from_registry, #excluded_file?, #external_dependency_checksum, inherited, #initialize, #inspect, joining_forces, lint?, match?, #offenses, #on_investigation_end, #on_new_investigation, #on_other_file, #parse, #parser_engine, #ready, #relevant_file?, requires_gem, #string_literals_frozen_by_default?, support_autocorrect?, support_multiple_source?, #target_gem_version, #target_rails_version, #target_ruby_version

Methods included from ExcludeLimit

#exclude_limit

Methods included from AutocorrectLogic

#autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #autocorrect_with_disable_uncorrectable?, #correctable?, #disable_uncorrectable?, #safe_autocorrect?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods included from Util

silence_warnings

Constructor Details

This class inherits a constructor from RuboCop::Cop::Base

Instance Method Details

#on_str(node) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
# File 'lib/rubocop/cop/style/format_string_token.rb', line 140

def on_str(node)
  return if format_string_token?(node) || use_allowed_method?(node)

  detections = collect_detections(node)
  return if detections.empty?
  return if allowed_unannotated?(detections)

  detections.each do |detected_sequence, token_range|
    check_sequence(node, detected_sequence, token_range)
  end
end