forked from rubocop/rubocop
/
iterating_block.rb
61 lines (53 loc) · 2.19 KB
/
iterating_block.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# frozen_string_literal: true
module RuboCop
module Cop
module Metrics
module Utils
# Used to identify iterating blocks like `.map{}` and `.map(&:...)`
module IteratingBlock
enumerable = %i[
all? any? chain chunk chunk_while collect collect_concat count cycle
detect drop drop_while each each_cons each_entry each_slice
each_with_index each_with_object entries filter filter_map find
find_all find_index flat_map grep grep_v group_by inject lazy map
max max_by min min_by minmax minmax_by none? one? partition reduce
reject reverse_each select slice_after slice_before slice_when sort
sort_by sum take take_while tally to_h uniq zip
]
enumerator = %i[with_index with_object]
array = %i[
bsearch bsearch_index collect! combination d_permutation delete_if
each_index keep_if map! permutation product reject! repeat
repeated_combination select! sort sort! sort_by sort_by
]
hash = %i[
each_key each_pair each_value fetch fetch_values has_key? merge
merge! transform_keys transform_keys! transform_values
transform_values!
]
KNOWN_ITERATING_METHODS = (Set.new(enumerable) + enumerator + array + hash).freeze
# Returns the name of the method called with a block
# if node is a block node, or a block-pass node.
def block_method_name(node)
case node.type
when :block
node.method_name
when :block_pass
node.parent.method_name
end
end
# Returns true iff name is a known iterating type (e.g. :each, :transform_values)
def iterating_method?(name)
KNOWN_ITERATING_METHODS.include? name
end
# Returns nil if node is neither a block node or a block-pass node.
# Otherwise returns true/false if method call is a known iterating call
def iterating_block?(node)
name = block_method_name(node)
name && iterating_method?(name)
end
end
end
end
end
end