Class: RuboCop::Cop::Naming::InclusiveLanguage
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
::RuboCop::Cop::AutoCorrector ,
::RuboCop::Cop::Base ,
::RuboCop::ExcludeLimit ,
NodePattern::Macros,
RuboCop::AST::Sexp
|
|
Instance Chain:
self,
::RuboCop::Cop::RangeHelp ,
::RuboCop::Cop::Base ,
::RuboCop::Cop::AutocorrectLogic ,
::RuboCop::Cop::IgnoredNode ,
::RuboCop::Util ,
RuboCop::AST::Sexp
|
|
Inherits: |
RuboCop::Cop::Base
|
Defined in: | lib/rubocop/cop/naming/inclusive_language.rb |
Overview
Recommends the use of inclusive language instead of problematic terms. The cop can check the following locations for offenses:
-
identifiers
-
constants
-
variables
-
strings
-
symbols
-
comments
-
file paths
Each of these locations can be individually enabled/disabled via configuration, for example CheckIdentifiers = true/false.
Flagged terms are configurable for the cop. For each flagged term an optional
Regex can be specified to identify offenses. Suggestions for replacing a flagged term can
be configured and will be displayed as part of the offense message.
An AllowedRegex can be specified for a flagged term to exempt allowed uses of the term.
WholeWord: true
can be set on a flagged term to indicate the cop should only match when
a term matches the whole word (partial matches will not be offenses).
The cop supports autocorrection when there is only one suggestion. When there are multiple suggestions, the best suggestion cannot be identified and will not be autocorrected.
Constant Summary
-
EMPTY_ARRAY =
# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 78[].freeze
-
MSG =
# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 79"Consider replacing '%<term>s'%<suffix>s."
-
MSG_FOR_FILE_PATH =
# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 80"Consider replacing '%<term>s' in file path%<suffix>s."
::RuboCop::Cop::Base
- Inherited
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 #on_new_investigation and |
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 |
::RuboCop::ExcludeLimit
- Extended
exclude_limit | Sets up a configuration option to have an exclude limit tracked. |
transform |
Instance Attribute Summary
::RuboCop::Cop::Base
- Inherited
::RuboCop::Cop::AutocorrectLogic
- Included
Instance Method Summary
- #on_new_investigation
- #add_offenses_for_token(token, word_locations) private
- #add_to_flagged_term_hash(regex_string, term, term_definition) private
- #array_to_ignorecase_regex(strings) private
- #check_token?(type) ⇒ Boolean private
- #create_message(word, message = MSG) private
- #create_multiple_word_message_for_file(words) private
- #create_single_word_message_for_file(word) private
- #ensure_regex_string(regex) private
- #extract_regexp(term, term_definition) private
- #find_flagged_term(word) private
- #format_suggestions(suggestions) private
- #investigate_filepath private
- #investigate_tokens private
- #mask_input(str) private
- #offense_range(token, word) private
- #preferred_sole_term(suggestions) private
- #preprocess_check_config private
- #preprocess_flagged_terms private
- #preprocess_suggestions(suggestions) private
- #process_allowed_regex(allowed) private
- #scan_for_words(input) private
- #set_regexes(flagged_term_strings, allowed_strings) private
::RuboCop::Cop::RangeHelp
- Included
#add_range, #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, #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, | |
#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_rails_version, #target_ruby_version, #annotate, #apply_correction, #attempt_correction, | |
#callback_argument | Reserved for Cop::Cop. |
#complete_investigation | Called to complete an investigation. |
#correct, #current_corrector, | |
#current_offense_locations | Reserved for Commissioner: |
#current_offenses, #currently_disabled_lines, #custom_severity, #default_severity, #disable_uncorrectable, #enabled_line?, #file_name_matches_any?, #find_message, #find_severity, #range_for_original, #range_from_node_or_range, | |
#reset_investigation | Actually private methods. |
#use_corrector |
::RuboCop::Cop::AutocorrectLogic
- Included
#disable_offense, #disable_offense_at_end_of_line, #disable_offense_before_and_after, #disable_offense_with_eol_or_surround_comment, #heredoc_range, #max_line_length, #multiline_ranges, #multiline_string?, | |
#range_by_lines | Expand the given range to include all of any lines it covers. |
#range_of_first_line, #range_overlaps_offense?, #string_continuation?, #surrounding_heredoc?, #surrounding_percent_array? |
::RuboCop::Cop::IgnoredNode
- Included
Constructor Details
.new(config = nil, options = nil) ⇒ InclusiveLanguage
# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 84
def initialize(config = nil, = nil) super @flagged_term_hash = {} @flagged_terms_regex = nil @allowed_regex = nil @check_token = preprocess_check_config preprocess_flagged_terms end
Instance Method Details
#add_offenses_for_token(token, word_locations) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 111
def add_offenses_for_token(token, word_locations) word_locations.each do |word_location| word = word_location.word range = offense_range(token, word) add_offense(range, message: (word)) do |corrector| suggestions = find_flagged_term(word)['Suggestions'] if (preferred_term = preferred_sole_term(suggestions)) corrector.replace(range, preferred_term) end end end end
#add_to_flagged_term_hash(regex_string, term, term_definition) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 176
def add_to_flagged_term_hash(regex_string, term, term_definition) @flagged_term_hash[Regexp.new(regex_string, Regexp::IGNORECASE)] = term_definition.merge('Term' => term, 'SuggestionString' => preprocess_suggestions(term_definition['Suggestions'])) end
#array_to_ignorecase_regex(strings) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 202
def array_to_ignorecase_regex(strings) Regexp.new(strings.join('|'), Regexp::IGNORECASE) end
#check_token?(type) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 126
def check_token?(type) !!@check_token[type] end
#create_message(word, message = MSG) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 252
def (word, = MSG) flagged_term = find_flagged_term(word) suggestions = flagged_term['SuggestionString'] suggestions = ' with another term' if suggestions.blank? format(, term: word, suffix: suggestions) end
#create_multiple_word_message_for_file(words) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 226
def (words) format(MSG_FOR_FILE_PATH, term: words.join("', '"), suffix: ' with other terms') end
#create_single_word_message_for_file(word) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 222
def (word) (word, MSG_FOR_FILE_PATH) end
#ensure_regex_string(regex) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 198
def ensure_regex_string(regex) regex.is_a?(Regexp) ? regex.source : regex end
#extract_regexp(term, term_definition) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 169
def extract_regexp(term, term_definition) return term_definition['Regex'] if term_definition['Regex'] return /(?:\b|(?<=[\W_]))#{term}(?:\b|(?=[\W_]))/ if term_definition['WholeWord'] term end
#find_flagged_term(word) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 260
def find_flagged_term(word) _regexp, flagged_term = @flagged_term_hash.find do |key, _term| key.match?(word) end flagged_term end
#format_suggestions(suggestions) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 274
def format_suggestions(suggestions) quoted_suggestions = Array(suggestions).map { |word| "'#{word}'" } suggestion_str = case quoted_suggestions.size when 1 quoted_suggestions.first when 2 quoted_suggestions.join(' or ') else last_quoted = quoted_suggestions.pop quoted_suggestions << "or #{last_quoted}" quoted_suggestions.join(', ') end " with #{suggestion_str}" end
#investigate_filepath (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 206
def investigate_filepath word_locations = scan_for_words(processed_source.file_path) case word_locations.length when 0 return when 1 = (word_locations.first.word) else words = word_locations.map(&:word) = (words) end add_global_offense( ) end
#investigate_tokens (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 100
def investigate_tokens processed_source.tokens.each do |token| next unless check_token?(token.type) word_locations = scan_for_words(token.text) next if word_locations.empty? add_offenses_for_token(token, word_locations) end end
#mask_input(str) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 240
def mask_input(str) safe_str = if str.valid_encoding? str else str.encode('UTF-8', invalid: :replace, undef: :replace) end return safe_str if @allowed_regex.nil? safe_str.gsub(@allowed_regex) { |match| '*' * match.size } end
#offense_range(token, word) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 289
def offense_range(token, word) start_position = token.pos.begin_pos + token.pos.source.index(word) range_between(start_position, start_position + word.length) end
#on_new_investigation
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 93
def on_new_investigation investigate_filepath if cop_config['CheckFilepaths'] investigate_tokens end
#preferred_sole_term(suggestions) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 160
def preferred_sole_term(suggestions) case suggestions when Array suggestions.one? && preferred_sole_term(suggestions.first) when String suggestions end end
#preprocess_check_config (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 130
def preprocess_check_config # rubocop:disable Metrics/AbcSize { tIDENTIFIER: cop_config['CheckIdentifiers'], tCONSTANT: cop_config['CheckConstants'], tIVAR: cop_config['CheckVariables'], tCVAR: cop_config['CheckVariables'], tGVAR: cop_config['CheckVariables'], tSYMBOL: cop_config['CheckSymbols'], tSTRING: cop_config['CheckStrings'], tSTRING_CONTENT: cop_config['CheckStrings'], tCOMMENT: cop_config['CheckComments'] }.freeze end
#preprocess_flagged_terms (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 144
def preprocess_flagged_terms allowed_strings = [] flagged_term_strings = [] cop_config['FlaggedTerms'].each do |term, term_definition| next if term_definition.nil? allowed_strings.concat(process_allowed_regex(term_definition['AllowedRegex'])) regex_string = ensure_regex_string(extract_regexp(term, term_definition)) flagged_term_strings << regex_string add_to_flagged_term_hash(regex_string, term, term_definition) end set_regexes(flagged_term_strings, allowed_strings) end
#preprocess_suggestions(suggestions) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 267
def preprocess_suggestions(suggestions) return '' if suggestions.nil? || (suggestions.is_a?(String) && suggestions.strip.empty?) || suggestions.empty? format_suggestions(suggestions) end
#process_allowed_regex(allowed) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 188
def process_allowed_regex(allowed) return EMPTY_ARRAY if allowed.nil? Array(allowed).map do |allowed_term| next if allowed_term.is_a?(String) && allowed_term.strip.empty? ensure_regex_string(allowed_term) end end
#scan_for_words(input) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 230
def scan_for_words(input) masked_input = mask_input(input) return EMPTY_ARRAY unless masked_input.match?(@flagged_terms_regex) masked_input.enum_for(:scan, @flagged_terms_regex).map do match = Regexp.last_match WordLocation.new(match.to_s, match.offset(0).first) end end
#set_regexes(flagged_term_strings, allowed_strings) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/inclusive_language.rb', line 183
def set_regexes(flagged_term_strings, allowed_strings) @flagged_terms_regex = array_to_ignorecase_regex(flagged_term_strings) @allowed_regex = array_to_ignorecase_regex(allowed_strings) unless allowed_strings.empty? end