Class: RuboCop::Cop::Lint::PercentStringArray
| Relationships & Source Files | |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
::RuboCop::Cop::AutoCorrector,
::RuboCop::Cop::Base,
::RuboCop::ExcludeLimit,
NodePattern::Macros,
RuboCop::AST::Sexp
|
|
|
Instance Chain:
|
|
| Inherits: |
RuboCop::Cop::Base
|
| Defined in: | lib/rubocop/cop/lint/percent_string_array.rb |
Overview
Checks for quotes and commas in %w, e.g. %w('foo', "bar")
It is more likely that the additional characters are unintended (for example, mistranslating an array of literals to percent string notation) rather than meant to be part of the resulting strings.
When a quoted string contains whitespace, %w splits it into separate values,
so removing the quotes would not restore the intended string.
Such an array is corrected to an array literal instead, as long as its content
reads as one with only string elements.
Constant Summary
-
LEADING_QUOTE =
# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 45/^['"]/.freeze
-
MSG =
# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 48"Within `%w`/`%W`, quotes and ',' are unnecessary and may be " \ 'unwanted in the resulting strings.'
-
MSG_SPLIT_STRING =
# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 50'Within `%w`/`%W`, quoted strings are split at whitespace; ' \ 'use an array literal instead.'
-
QUOTES_AND_COMMAS =
# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 44[/,$/, /^'.*'$/, /^".*"$/].freeze
-
TRAILING_QUOTE =
# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 46/['"]?,?$/.freeze
::RuboCop::Cop::Base - Inherited
DEPARTMENT_SEVERITIES, EMPTY_OFFENSES, RESTRICT_ON_SEND
::RuboCop::Cop::RangeHelp - Included
Class Attribute Summary
::RuboCop::Cop::AutoCorrector - Extended
::RuboCop::Cop::Base - Inherited
| .gem_requirements, .lint?, | |
| .support_autocorrect? | Returns if class supports autocorrect. |
| .support_multiple_source? | Override if your cop should be called repeatedly for multiple investigations Between calls to |
Class Method Summary
::RuboCop::Cop::Base - Inherited
| .autocorrect_incompatible_with | List of cops that should not try to autocorrect at the same time as this cop. |
| .badge | Naming. |
| .callbacks_needed, .cop_name, .department, | |
| .documentation_url | Returns a url to view this cops documentation online. |
| .exclude_from_registry | Call for abstract Cop classes. |
| .inherited, | |
| .joining_forces | Override and return the Force class(es) you need to join. |
| .match? | Returns true if the cop name or the cop namespace matches any of the given names. |
| .new, | |
| .requires_gem | Register a version requirement for the given gem name. |
| .restrict_on_send | Reserved for Commissioner. |
::RuboCop::ExcludeLimit - Extended
| exclude_limit | Sets up a configuration option to have an exclude limit tracked. |
| transform | |
Instance Attribute Summary
::RuboCop::Cop::Base - Inherited
| #active_support_extensions_enabled?, #always_autocorrect?, #config, #config_to_allow_offenses, #config_to_allow_offenses=, #contextual_autocorrect?, #disabled_autocorrect?, | |
| #preview? | Whether the user opted in to unstable behavior, with |
| #processed_source, #project_index, #string_literals_frozen_by_default?, #target_satisfies_all_gem_version_requirements? | |
::RuboCop::Cop::AutocorrectLogic - Included
| #autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #autocorrect_with_disable_uncorrectable?, #correctable?, #disable_uncorrectable?, #safe_autocorrect?, | |
| #skipped_unsafe_correction_with_disable_uncorrectable? | Whether a correction exists but is skipped because it is unsafe in a safe autocorrect run, while |
| #contextual_autocorrect_held_back? | When LSP is enabled or the |
Instance Method Summary
- #on_array(node)
- #on_percent_literal(node)
- #array_literal_source(node) private
- #closing_quote?(source, quote) ⇒ Boolean private
- #contains_quotes_or_commas?(node) ⇒ Boolean private
- #quoted_string?(node) ⇒ Boolean private
- #register_quotes_or_commas(node) private
- #register_split_quoted_string(node) private
- #split_quoted_string?(node) ⇒ Boolean private
- #string_array?(processed_source) ⇒ Boolean private
- #unclosed_quote(source) private
::RuboCop::Cop::PercentLiteral - Included
::RuboCop::Cop::RangeHelp - Included
| #add_range, | |
| #arguments_range | A range containing the first to the last argument of a method call or method definition. |
| #column_offset_between, | |
| #contents_range | A range containing only the contents of a literal with delimiters (e.g. |
| #directions, | |
| #effective_column | Returns the column attribute of the range, except if the range is on the first line and there’s a byte order mark at the beginning of that line, in which case 1 is subtracted from the column value. |
| #final_pos | rubocop:disable-next Metrics/ParameterLists. |
| #move_pos, #move_pos_str, #range_between, #range_by_whole_lines, #range_with_comments, #range_with_comments_and_lines, #range_with_surrounding_comma, #range_with_surrounding_space, #source_range | |
::RuboCop::Cop::Base - Inherited
| #add_global_offense | Adds an offense that has no particular location. |
| #add_offense | Adds an offense on the specified range (or node with an expression) Unless that offense is disabled for this range, a corrector will be yielded to provide the cop the opportunity to autocorrect the offense. |
| #begin_investigation | Called before any investigation. |
| #callbacks_needed | — grouped under the Commissioner heading above. |
| #cop_config | Configuration Helpers. |
| #cop_name, #excluded_file?, | |
| #external_dependency_checksum | This method should be overridden when a cop’s behavior depends on state that lives outside of these locations: |
| #inspect, | |
| #message | Gets called if no message is specified when calling |
| #name | Alias for Base#cop_name. |
| #offenses, | |
| #on_investigation_end | Called after all on_… |
| #on_new_investigation | Called before all on_… |
| #on_other_file | Called instead of all on_… |
| #parse | There should be very limited reasons for a Cop to do it’s own parsing. |
| #parser_engine, | |
| #ready | Called between investigations. |
| #relevant_file?, | |
| #target_gem_version | Returns the version of a gem in the target, by default its locked version (i.e. from Gemfile.lock or gems.locked). |
| #target_rails_version, #target_ruby_version, #annotate, #apply_correction, #attempt_correction, | |
| #callback_argument | Reserved for Cop::Cop. |
| #complete_investigation | Called to complete an investigation. |
| #correct, #covering_disabled_range, #current_corrector, | |
| #current_offense_locations | Reserved for Commissioner: |
| #current_offenses, #currently_disabled_lines, #custom_severity, #default_severity, #disable_uncorrectable, #enabled_line?, | |
| #enabled_lines? | A multi-line offense is suppressed by a directive on any line of its range, not only its first line, matching the intuition that the directive is attached to the offending code. |
| #file_name_matches_any?, #find_message, #find_severity, #matches_absolute_include_pattern?, #new_offense, #range_for_original, #range_from_node_or_range, | |
| #reset_investigation | Actually private methods. |
| #suppression_reason | The |
| #use_corrector | |
::RuboCop::Cop::AutocorrectLogic - Included
::RuboCop::Cop::IgnoredNode - Included
Constructor Details
This class inherits a constructor from RuboCop::Cop::Base
Instance Method Details
#array_literal_source(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 96
def array_literal_source(node) content = range_between(node.loc.begin.end_pos, node.loc.end.begin_pos).source array_literal = "[#{content}]" array_literal if string_array?(parse(array_literal)) end
#closing_quote?(source, quote) ⇒ Boolean (private)
#contains_quotes_or_commas?(node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 114
def contains_quotes_or_commas?(node) node.values.any? do |value| literal = value.children.first.to_s.scrub # To avoid likely false positives (e.g. a single ' or ") next if literal.gsub(/[^[[:alnum:]]]/, '').empty? QUOTES_AND_COMMAS.any? { |pat| literal.match?(pat) } end end
#on_array(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 53
def on_array(node) process(node, '%w', '%W') end
#on_percent_literal(node)
[ GitHub ]# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 57
def on_percent_literal(node) if split_quoted_string?(node) register_split_quoted_string(node) elsif contains_quotes_or_commas?(node) register_quotes_or_commas(node) end end
#quoted_string?(node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 110
def quoted_string?(node) node.type?(:str, :dstr) && node.loc?(:begin) end
#register_quotes_or_commas(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 125
def register_quotes_or_commas(node) add_offense(node) do |corrector| node.each_value do |value| range = value.source_range match = range.source.match(TRAILING_QUOTE) corrector.remove_trailing(range, match[0].length) if match corrector.remove_leading(range, 1) if LEADING_QUOTE.match?(range.source) end end end
#register_split_quoted_string(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 88
def register_split_quoted_string(node) add_offense(node, message: MSG_SPLIT_STRING) do |corrector| next unless (array_literal = array_literal_source(node)) corrector.replace(node, array_literal) end end
#split_quoted_string?(node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 67
def split_quoted_string?(node) sources = node.values.map { |value| value.source.delete_suffix(',') } sources.each_with_index.any? do |source, index| next false unless (quote = unclosed_quote(source)) sources.drop(index + 1).any? { |rest| closing_quote?(rest, quote) } end end
#string_array?(processed_source) ⇒ Boolean (private)
# File 'lib/rubocop/cop/lint/percent_string_array.rb', line 103
def string_array?(processed_source) return false unless processed_source.valid_syntax? && processed_source.comments.empty? return false unless (array = processed_source.ast).array_type? array.children.all? { |child| quoted_string?(child) } end