Class: RuboCop::Cop::Style::MapIntoArray
Overview
Checks for usages of ‘each` with `<<`, `push`, or `append` which can be replaced by `map`.
If ‘PreferredMethods` is configured for `map` in `Style/CollectionMethods`, this cop uses the specified method for replacement.
NOTE: The return value of ‘Enumerable#each` is `self`, whereas the return value of `Enumerable#map` is an `Array`. They are not autocorrected when a return value could be used because these types differ.
NOTE: It only detects when the mapping destination is either:
-
a local variable initialized as an empty array and referred to only by the
pushing operation;
-
or, if it is the single block argument to a ‘[].tap` block.
This is because, if not, it’s challenging to statically guarantee that the mapping destination variable remains an empty array:
- source,ruby
ret = [] src.each { |e| ret << e * 2 } # ‘<<` method may mutate `ret`
dest = [] src.each { |e| dest << transform(e, dest) } # ‘transform` method may mutate `dest`
Constant Summary collapse
- MSG =
'Use `%<new_method_name>s` instead of `each` to map elements into an array.'
Constants inherited from Base
Instance Attribute Summary
Attributes inherited from Base
Class Method Summary collapse
Instance Method Summary collapse
- #after_leaving_scope(scope, _variable_table) ⇒ Object
- #each_block_with_push?(node) ⇒ Object
- #empty_array_asgn?(node) ⇒ Object
- #empty_array_tap(node) ⇒ Object
- #lvar_ref?(node, name) ⇒ Object
- #on_block(node) ⇒ Object (also: #on_numblock)
- #suitable_argument_node?(node) ⇒ Object
Methods included from AutoCorrector
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, lint?, match?, #message, #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_rails_version, #target_ruby_version
Methods included from ExcludeLimit
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
Constructor Details
This class inherits a constructor from RuboCop::Cop::Base
Class Method Details
.joining_forces ⇒ Object
105 106 107 |
# File 'lib/rubocop/cop/style/map_into_array.rb', line 105 def self.joining_forces VariableForce end |
Instance Method Details
#after_leaving_scope(scope, _variable_table) ⇒ Object
109 110 111 |
# File 'lib/rubocop/cop/style/map_into_array.rb', line 109 def after_leaving_scope(scope, _variable_table) (@scopes ||= []) << scope end |
#each_block_with_push?(node) ⇒ Object
72 73 74 75 76 77 78 |
# File 'lib/rubocop/cop/style/map_into_array.rb', line 72 def_node_matcher :each_block_with_push?, <<-PATTERN [ ^({begin kwbegin block} ...) ({block numblock} (send !{nil? self} :each) _ (send (lvar _) {:<< :push :append} #suitable_argument_node?)) ] PATTERN |
#empty_array_asgn?(node) ⇒ Object
81 82 83 84 85 86 87 88 89 90 |
# File 'lib/rubocop/cop/style/map_into_array.rb', line 81 def_node_matcher :empty_array_asgn?, <<~PATTERN ( lvasgn _ { (array) (send (const {nil? cbase} :Array) :[]) (send (const {nil? cbase} :Array) :new (array)?) (send nil? :Array (array)) } ) PATTERN |
#empty_array_tap(node) ⇒ Object
93 94 95 96 97 98 99 100 |
# File 'lib/rubocop/cop/style/map_into_array.rb', line 93 def_node_matcher :empty_array_tap, <<~PATTERN ^^$( block (send (array) :tap) (args (arg _)) ... ) PATTERN |
#lvar_ref?(node, name) ⇒ Object
103 |
# File 'lib/rubocop/cop/style/map_into_array.rb', line 103 def_node_matcher :lvar_ref?, '(lvar %1)' |
#on_block(node) ⇒ Object Also known as: on_numblock
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/rubocop/cop/style/map_into_array.rb', line 113 def on_block(node) return unless each_block_with_push?(node) dest_var = find_dest_var(node) if offending_empty_array_tap?(node, dest_var) asgn = dest_var.declaration_node else return unless (asgn = find_closest_assignment(node, dest_var)) return unless empty_array_asgn?(asgn) return unless dest_used_only_for_mapping?(node, dest_var, asgn) end register_offense(node, dest_var, asgn) end |
#suitable_argument_node?(node) ⇒ Object
67 68 69 |
# File 'lib/rubocop/cop/style/map_into_array.rb', line 67 def_node_matcher :suitable_argument_node?, <<-PATTERN !{splat forwarded-restarg forwarded-args (hash (forwarded-kwrestarg)) (block-pass nil?)} PATTERN |