Module: RuboCop::Cop::HashSubset
Relationships & Source Files | |
Extension / Inclusion / Inheritance Descendants | |
Included In:
| |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
Macros
|
|
Instance Chain:
self,
RangeHelp
|
|
Defined in: | lib/rubocop/cop/mixin/hash_subset.rb |
Overview
Common functionality for Style/HashExcept and Style/HashSlice cops. It registers an offense on methods with blocks that are equivalent to Hash#except or Hash#slice.
Constant Summary
-
ACTIVE_SUPPORT_SUBSET_METHODS =
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 15(SUBSET_METHODS + %i[in? exclude?]).freeze
-
MSG =
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 17'Use `%<prefer>s` instead.'
-
RESTRICT_ON_SEND =
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 12%i[reject select filter].freeze
-
SUBSET_METHODS =
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 14%i[== != eql? include?].freeze
RangeHelp
- Included
Instance Method Summary
- #block_with_first_arg_check?(node)
-
#on_csend(node)
Alias for #on_send.
- #on_send(node) (also: #on_csend)
- #decorate_source(value) private
- #except_key(node) private
- #except_key_source(key) private
- #extract_body_if_negated(body) private
- #extract_offense(node) private
- #extracts_hash_subset?(block) ⇒ Boolean private
- #included?(body, negated) ⇒ Boolean private
- #not_included?(body, negated) ⇒ Boolean private
- #offense_range(node) private
- #preferred_method_name private
- #safe_to_register_offense?(block, except_key) ⇒ Boolean private
- #semantically_except_method?(node) ⇒ Boolean private
- #semantically_slice_method?(node) ⇒ Boolean private
- #semantically_subset_method?(node) ⇒ Boolean private
- #supported_subset_method?(method) ⇒ Boolean private
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 |
Instance Method Details
#block_with_first_arg_check?(node)
[ GitHub ]# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 20
def_node_matcher :block_with_first_arg_check?, <<~PATTERN (block (call _ _) (args $(arg _key) (arg _)) { $(send {(lvar _key) $_ _ | _ $_ (lvar _key)}) (send $(send {(lvar _key) $_ _ | _ $_ (lvar _key)}) :!) }) PATTERN
#decorate_source(value) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 149
def decorate_source(value) return ":\"#{value.source}\"" if value.dsym_type? return "\"#{value.source}\"" if value.dstr_type? return ":#{value.source}" if value.sym_type? "'#{value.source}'" end
#except_key(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 157
def except_key(node) key_arg = node.argument_list.first.source body, = extract_body_if_negated(node.body) lhs, _method_name, rhs = *body lhs.source == key_arg ? rhs : lhs end
#except_key_source(key) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 136
def except_key_source(key) if key.array_type? key = if key.percent_literal? key.each_value.map { |v| decorate_source(v) } else key.each_value.map(&:source) end return key.join(', ') end key.literal? ? key.source : "*#{key.source}" end
#extract_body_if_negated(body) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 128
def extract_body_if_negated(body) if body.method?('!') [body.receiver, true] else [body, false] end end
#extract_offense(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 58
def extract_offense(node) block = node.parent return unless extracts_hash_subset?(block) except_key = except_key(block) return if except_key.nil? || !safe_to_register_offense?(block, except_key) [offense_range(node), except_key_source(except_key)] end
#extracts_hash_subset?(block) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 68
def extracts_hash_subset?(block) block_with_first_arg_check?(block) do |key_arg, send_node, method| return false unless supported_subset_method?(method) case method when :include?, :exclude? send_node.first_argument.source == key_arg.source when :in? send_node.receiver.source == key_arg.source else true end end end
#included?(body, negated) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 106
def included?(body, negated) if negated body.method?('exclude?') else body.method?('include?') || body.method?('in?') end end
#not_included?(body, negated) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 114
def not_included?(body, negated) included?(body, !negated) end
#offense_range(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 165
def offense_range(node) range_between(node.loc.selector.begin_pos, node.parent.loc.end.end_pos) end
#on_csend(node)
Alias for #on_send.
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 46
alias on_csend on_send
#on_send(node) Also known as: #on_csend
[ GitHub ]# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 35
def on_send(node) offense_range, key_source = extract_offense(node) return unless offense_range return unless semantically_subset_method?(node) preferred_method = "#{preferred_method_name}(#{key_source})" add_offense(offense_range, message: format(MSG, prefer: preferred_method)) do |corrector| corrector.replace(offense_range, preferred_method) end end
#preferred_method_name (private)
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 54
def preferred_method_name raise NotImplementedError end
#safe_to_register_offense?(block, except_key) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 118
def safe_to_register_offense?(block, except_key) body = block.body if body.method?('==') || body.method?('!=') except_key.sym_type? || except_key.str_type? else true end end
#semantically_except_method?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 91
def semantically_except_method?(node) block = node.parent body, negated = extract_body_if_negated(block.body) if node.method?('reject') body.method?('==') || body.method?('eql?') || included?(body, negated) else body.method?('!=') || not_included?(body, negated) end end
#semantically_slice_method?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 102
def semantically_slice_method?(node) !semantically_except_method?(node) end
#semantically_subset_method?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 50
def semantically_subset_method?(node) raise NotImplementedError end
#supported_subset_method?(method) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/mixin/hash_subset.rb', line 83
def supported_subset_method?(method) if active_support_extensions_enabled? ACTIVE_SUPPORT_SUBSET_METHODS.include?(method) else SUBSET_METHODS.include?(method) end end