class RuboCop::Cop::Flexport::InclusiveCode
This cop encourages use of inclusive language to help programmers avoid using terminology that is derogatory, hurtful, or perpetuates discrimination, either directly or indirectly, in their code.
@example
# bad BLACKLIST_COUNTRIES = "blacklist_countries".freeze
@example
# good BLOCKLIST_COUNTRIES = "blocklist_countries".freeze
Constants
- ALLOWED_TERM_MASK_CHAR
- FLAG_ONLY_MSG
- FULL_FLAG_MSG
- SEVERITY
Public Class Methods
new(config = nil, options = nil, source_file = nil)
click to toggle source
Calls superclass method
# File lib/rubocop/cop/inclusive_code.rb, line 35 def initialize(config = nil, options = nil, source_file = nil) super(config, options) source_file ||= YAML.load_file(cop_config['GlobalConfigPath']) @non_inclusive_words_alternatives_hash = source_file['flagged_terms'] @all_non_inclusive_words = @non_inclusive_words_alternatives_hash.keys @non_inclusive_words_regex = concatenated_regex(@all_non_inclusive_words) @allowed_terms = {} @allowed_files = {} @all_non_inclusive_words.each do |word| @allowed_terms[word] = get_allowed_string(word) @allowed_files[word] = source_file['flagged_terms'][word]['allowed_files'] || [] end @allowed_regex = @allowed_terms.values.reject(&:blank?).join('|') @allowed_regex = if @allowed_regex.blank? Regexp.new(/^$/) else Regexp.new(@allowed_regex, Regexp::IGNORECASE) end end
Public Instance Methods
autocorrect(arg_pair)
click to toggle source
# File lib/rubocop/cop/inclusive_code.rb, line 114 def autocorrect(arg_pair) return if cop_config['DisableAutoCorrect'] word_to_correct = arg_pair.source correction = correction_for_word(word_to_correct) return if correction['suggestions'].blank? corrected = correction['suggestions'][0] # Only respects case if it is capitalized or uniform (all upper or all lower) to_upcase = word_to_correct == word_to_correct.upcase if to_upcase corrected = corrected.upcase elsif word_to_correct == word_to_correct.capitalize corrected = corrected.capitalize end lambda do |corrector| corrector.insert_before(arg_pair, corrected) corrector.remove(arg_pair) end end
investigate(processed_source)
click to toggle source
# File lib/rubocop/cop/inclusive_code.rb, line 58 def investigate(processed_source) non_inclusive_words_for_current_file = @all_non_inclusive_words.reject do |non_inclusive_word| Dir.glob("{#{@allowed_files[non_inclusive_word].join(',')}}").include?(processed_source.path) end processed_source.lines.each_with_index do |line, line_number| next unless line.match(@non_inclusive_words_regex) non_inclusive_words_for_current_file.each do |non_inclusive_word| allowed = @allowed_terms[non_inclusive_word] scan_regex = /(?=#{non_inclusive_word})/i if allowed.present? line = line.gsub(/(#{allowed})/i){ |match| ALLOWED_TERM_MASK_CHAR * match.size } end locations = line.enum_for( :scan, scan_regex ).map { Regexp.last_match&.offset(0)&.first } non_inclusive_words = line.scan(/#{non_inclusive_word}/i) locations = locations.zip(non_inclusive_words).to_h next if locations.blank? locations.each do |location, word| range = source_range( processed_source.buffer, line_number + 1, location, word.length ) add_offense( range, location: range, message: create_message(word), severity: SEVERITY ) end end end # Also error for non-inclusive language in file names path = processed_source.path return if path.nil? non_inclusive_words_match = path.match(concatenated_regex(non_inclusive_words_for_current_file)) return unless non_inclusive_words_match && !path.match(@allowed_regex) range = source_range(processed_source.buffer, 1, 0) add_offense( range, location: range, message: create_message(non_inclusive_words_match[0]), severity: SEVERITY ) end
Private Instance Methods
concatenated_regex(non_inclusive_words)
click to toggle source
# File lib/rubocop/cop/inclusive_code.rb, line 139 def concatenated_regex(non_inclusive_words) Regexp.new( non_inclusive_words.join('|'), Regexp::IGNORECASE ) end
correction_for_word(word_to_correct)
click to toggle source
# File lib/rubocop/cop/inclusive_code.rb, line 153 def correction_for_word(word_to_correct) _, correction = @non_inclusive_words_alternatives_hash.detect do |correction_key, _| Regexp.new(correction_key, Regexp::IGNORECASE).match?(word_to_correct.downcase) end correction || {} end
create_message(non_inclusive_word)
click to toggle source
# File lib/rubocop/cop/inclusive_code.rb, line 161 def create_message(non_inclusive_word) correction = correction_for_word(non_inclusive_word) suggestions = correction.fetch('suggestions') { [] }.join(', ') format( suggestions.present? ? FULL_FLAG_MSG : FLAG_ONLY_MSG, non_inclusive_word: non_inclusive_word, suggestions: suggestions ) end
get_allowed_string(non_inclusive_word)
click to toggle source
# File lib/rubocop/cop/inclusive_code.rb, line 146 def get_allowed_string(non_inclusive_word) allowed = @non_inclusive_words_alternatives_hash[non_inclusive_word].fetch('allowed') { [] } snake_case = allowed.map { |e| e.tr(' ', '_').underscore } pascal_case = snake_case.map(&:camelize) (allowed + snake_case + pascal_case).join('|') end