rubocop-callbacksystems 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +78 -0
- data/config/default.yml +590 -0
- data/docs/cops.md +111 -0
- data/lib/rubocop/callbacksystems/autocorrection/batch.rb +135 -0
- data/lib/rubocop/callbacksystems/autocorrection/comment_rescue.rb +112 -0
- data/lib/rubocop/callbacksystems/autocorrection/rehearsal.rb +65 -0
- data/lib/rubocop/callbacksystems/autocorrection/rewrite_permit.rb +14 -0
- data/lib/rubocop/callbacksystems/class_structure/builder_assignment.rb +48 -0
- data/lib/rubocop/callbacksystems/class_structure/class_body.rb +50 -0
- data/lib/rubocop/callbacksystems/class_structure/divergence.rb +31 -0
- data/lib/rubocop/callbacksystems/class_structure/node_visibility.rb +82 -0
- data/lib/rubocop/callbacksystems/class_structure/reference_order.rb +36 -0
- data/lib/rubocop/callbacksystems/class_structure/statement_rank.rb +84 -0
- data/lib/rubocop/callbacksystems/class_structure/statement_run.rb +42 -0
- data/lib/rubocop/callbacksystems/class_structure/visibility.rb +84 -0
- data/lib/rubocop/callbacksystems/cops_document.rb +78 -0
- data/lib/rubocop/callbacksystems/execution/deferred_local_variables.rb +138 -0
- data/lib/rubocop/callbacksystems/execution/discarded_expression.rb +45 -0
- data/lib/rubocop/callbacksystems/execution/eager_evaluation_path.rb +73 -0
- data/lib/rubocop/callbacksystems/execution/immediate.rb +71 -0
- data/lib/rubocop/callbacksystems/execution/local_variable_occurrences.rb +112 -0
- data/lib/rubocop/callbacksystems/hashes/key_transform_detection.rb +108 -0
- data/lib/rubocop/callbacksystems/hashes/keyword_options.rb +37 -0
- data/lib/rubocop/callbacksystems/helpers/bodies.rb +150 -0
- data/lib/rubocop/callbacksystems/helpers/builders.rb +103 -0
- data/lib/rubocop/callbacksystems/helpers/comments.rb +56 -0
- data/lib/rubocop/callbacksystems/helpers/corrections.rb +15 -0
- data/lib/rubocop/callbacksystems/helpers/methods.rb +46 -0
- data/lib/rubocop/callbacksystems/helpers/names.rb +65 -0
- data/lib/rubocop/callbacksystems/helpers/node_types.rb +154 -0
- data/lib/rubocop/callbacksystems/helpers/rails.rb +52 -0
- data/lib/rubocop/callbacksystems/helpers/ranges.rb +107 -0
- data/lib/rubocop/callbacksystems/helpers/recursion.rb +29 -0
- data/lib/rubocop/callbacksystems/helpers/variables.rb +44 -0
- data/lib/rubocop/callbacksystems/helpers/visibility.rb +121 -0
- data/lib/rubocop/callbacksystems/helpers.rb +43 -0
- data/lib/rubocop/callbacksystems/methods/calls.rb +38 -0
- data/lib/rubocop/callbacksystems/methods/definitions.rb +218 -0
- data/lib/rubocop/callbacksystems/methods/delegate_macro.rb +144 -0
- data/lib/rubocop/callbacksystems/methods/delegation_target.rb +55 -0
- data/lib/rubocop/callbacksystems/methods/domain.rb +77 -0
- data/lib/rubocop/callbacksystems/methods/implicit_invocations.rb +17 -0
- data/lib/rubocop/callbacksystems/methods/macro_references.rb +238 -0
- data/lib/rubocop/callbacksystems/methods/reference_evidence.rb +74 -0
- data/lib/rubocop/callbacksystems/methods/siblings.rb +24 -0
- data/lib/rubocop/callbacksystems/methods/statement_definitions.rb +68 -0
- data/lib/rubocop/callbacksystems/offense.rb +13 -0
- data/lib/rubocop/callbacksystems/plugin.rb +27 -0
- data/lib/rubocop/callbacksystems/project_index/cache.rb +16 -0
- data/lib/rubocop/callbacksystems/project_index/confinement_cache.rb +40 -0
- data/lib/rubocop/callbacksystems/project_index/constant_references.rb +74 -0
- data/lib/rubocop/callbacksystems/project_index/corrections.rb +35 -0
- data/lib/rubocop/callbacksystems/project_index/coverage.rb +56 -0
- data/lib/rubocop/callbacksystems/project_index/diagnostics.rb +60 -0
- data/lib/rubocop/callbacksystems/project_index/freshness.rb +104 -0
- data/lib/rubocop/callbacksystems/project_index/loader.rb +9 -0
- data/lib/rubocop/callbacksystems/project_index/location.rb +29 -0
- data/lib/rubocop/callbacksystems/project_index/nested_class_confinement.rb +297 -0
- data/lib/rubocop/callbacksystems/project_index/nested_class_method_dispatch.rb +50 -0
- data/lib/rubocop/callbacksystems/project_index/reading.rb +129 -0
- data/lib/rubocop/callbacksystems/project_index/source_file.rb +59 -0
- data/lib/rubocop/callbacksystems/project_index/source_file_match.rb +57 -0
- data/lib/rubocop/callbacksystems/project_index/support.rb +46 -0
- data/lib/rubocop/callbacksystems/source/comment_blocks.rb +43 -0
- data/lib/rubocop/callbacksystems/source/comments.rb +141 -0
- data/lib/rubocop/callbacksystems/source/file_ast.rb +15 -0
- data/lib/rubocop/callbacksystems/source/files_checksum.rb +43 -0
- data/lib/rubocop/callbacksystems/source/single_line_call.rb +181 -0
- data/lib/rubocop/callbacksystems/source/statement_with_comments.rb +131 -0
- data/lib/rubocop/callbacksystems/testing/cop_helpers.rb +42 -0
- data/lib/rubocop/callbacksystems/testing/fixture_call.rb +30 -0
- data/lib/rubocop/callbacksystems/testing/fixture_names.rb +62 -0
- data/lib/rubocop/callbacksystems/testing/path_mapping.rb +104 -0
- data/lib/rubocop/cop/callbacksystems/application_controller_method_definition.rb +44 -0
- data/lib/rubocop/cop/callbacksystems/assert_with_expected_argument.rb +60 -0
- data/lib/rubocop/cop/callbacksystems/base.rb +134 -0
- data/lib/rubocop/cop/callbacksystems/body_order.rb +478 -0
- data/lib/rubocop/cop/callbacksystems/builder_method_parentheses.rb +74 -0
- data/lib/rubocop/cop/callbacksystems/collapse_multiline_expression.rb +140 -0
- data/lib/rubocop/cop/callbacksystems/comment_block_length.rb +137 -0
- data/lib/rubocop/cop/callbacksystems/complex_conditional.rb +75 -0
- data/lib/rubocop/cop/callbacksystems/controller_test_response_assertion.rb +105 -0
- data/lib/rubocop/cop/callbacksystems/controller_test_response_first_assertion.rb +123 -0
- data/lib/rubocop/cop/callbacksystems/data_clump.rb +339 -0
- data/lib/rubocop/cop/callbacksystems/declarative_method_naming.rb +350 -0
- data/lib/rubocop/cop/callbacksystems/delegate_requires_private_option.rb +81 -0
- data/lib/rubocop/cop/callbacksystems/eager_loading_scope_naming.rb +386 -0
- data/lib/rubocop/cop/callbacksystems/early_return.rb +215 -0
- data/lib/rubocop/cop/callbacksystems/empty_line_before_method.rb +168 -0
- data/lib/rubocop/cop/callbacksystems/empty_line_between_sections.rb +169 -0
- data/lib/rubocop/cop/callbacksystems/empty_private_section.rb +107 -0
- data/lib/rubocop/cop/callbacksystems/expanded_empty_class_or_module.rb +71 -0
- data/lib/rubocop/cop/callbacksystems/inline_memoized_computation.rb +110 -0
- data/lib/rubocop/cop/callbacksystems/job_enqueue_methods.rb +93 -0
- data/lib/rubocop/cop/callbacksystems/max_safe_navigation_depth.rb +118 -0
- data/lib/rubocop/cop/callbacksystems/method_invocation_order.rb +261 -0
- data/lib/rubocop/cop/callbacksystems/nested_class_order.rb +255 -0
- data/lib/rubocop/cop/callbacksystems/no_abbreviations.rb +197 -0
- data/lib/rubocop/cop/callbacksystems/no_anemic_delegation.rb +101 -0
- data/lib/rubocop/cop/callbacksystems/no_anemic_record.rb +309 -0
- data/lib/rubocop/cop/callbacksystems/no_assert_select.rb +31 -0
- data/lib/rubocop/cop/callbacksystems/no_bang_method_without_counterpart.rb +451 -0
- data/lib/rubocop/cop/callbacksystems/no_call_method.rb +73 -0
- data/lib/rubocop/cop/callbacksystems/no_comments_in_test_class_body.rb +159 -0
- data/lib/rubocop/cop/callbacksystems/no_consecutive_appends.rb +261 -0
- data/lib/rubocop/cop/callbacksystems/no_custom_route_actions.rb +124 -0
- data/lib/rubocop/cop/callbacksystems/no_direct_eager_loading.rb +90 -0
- data/lib/rubocop/cop/callbacksystems/no_each_with_early_return.rb +58 -0
- data/lib/rubocop/cop/callbacksystems/no_explicit_public_modifier.rb +81 -0
- data/lib/rubocop/cop/callbacksystems/no_hash_with_default_block.rb +68 -0
- data/lib/rubocop/cop/callbacksystems/no_local_variable_return.rb +173 -0
- data/lib/rubocop/cop/callbacksystems/no_manual_accumulation.rb +188 -0
- data/lib/rubocop/cop/callbacksystems/no_mixed_memoization.rb +145 -0
- data/lib/rubocop/cop/callbacksystems/no_nested_modules_in_classes.rb +78 -0
- data/lib/rubocop/cop/callbacksystems/no_nil_at_end_of_method.rb +74 -0
- data/lib/rubocop/cop/callbacksystems/no_redundant_validation_name.rb +37 -0
- data/lib/rubocop/cop/callbacksystems/no_redundant_wrapper_method.rb +161 -0
- data/lib/rubocop/cop/callbacksystems/no_section_divider_comments.rb +105 -0
- data/lib/rubocop/cop/callbacksystems/no_send_in_tests.rb +75 -0
- data/lib/rubocop/cop/callbacksystems/no_service_objects.rb +64 -0
- data/lib/rubocop/cop/callbacksystems/no_single_letter_names.rb +47 -0
- data/lib/rubocop/cop/callbacksystems/no_singleton_class_in_modules.rb +43 -0
- data/lib/rubocop/cop/callbacksystems/no_tap_collection_building.rb +173 -0
- data/lib/rubocop/cop/callbacksystems/no_turbo_stream_in_controllers.rb +52 -0
- data/lib/rubocop/cop/callbacksystems/no_typographic_clutter.rb +159 -0
- data/lib/rubocop/cop/callbacksystems/no_writes_in_get_actions.rb +149 -0
- data/lib/rubocop/cop/callbacksystems/ordered_mixin_arguments.rb +78 -0
- data/lib/rubocop/cop/callbacksystems/plural_controller_names.rb +103 -0
- data/lib/rubocop/cop/callbacksystems/prefer_attr_reader_over_instance_variable.rb +86 -0
- data/lib/rubocop/cop/callbacksystems/prefer_backslash_continuation.rb +478 -0
- data/lib/rubocop/cop/callbacksystems/prefer_class_for_state.rb +532 -0
- data/lib/rubocop/cop/callbacksystems/prefer_class_new_for_empty_nested_class.rb +247 -0
- data/lib/rubocop/cop/callbacksystems/prefer_class_over_builder_block.rb +124 -0
- data/lib/rubocop/cop/callbacksystems/prefer_default_argument.rb +225 -0
- data/lib/rubocop/cop/callbacksystems/prefer_delegate.rb +242 -0
- data/lib/rubocop/cop/callbacksystems/prefer_delegate_over_instance_variable_assignment.rb +175 -0
- data/lib/rubocop/cop/callbacksystems/prefer_excluding.rb +204 -0
- data/lib/rubocop/cop/callbacksystems/prefer_extract_associated.rb +54 -0
- data/lib/rubocop/cop/callbacksystems/prefer_it_block_parameter.rb +156 -0
- data/lib/rubocop/cop/callbacksystems/prefer_many.rb +57 -0
- data/lib/rubocop/cop/callbacksystems/prefer_method_over_lambda.rb +211 -0
- data/lib/rubocop/cop/callbacksystems/prefer_method_over_variable.rb +172 -0
- data/lib/rubocop/cop/callbacksystems/prefer_module_for_static_class.rb +286 -0
- data/lib/rubocop/cop/callbacksystems/prefer_ordinal_array_access.rb +136 -0
- data/lib/rubocop/cop/callbacksystems/prefer_positive_wrap.rb +265 -0
- data/lib/rubocop/cop/callbacksystems/prefer_squish.rb +47 -0
- data/lib/rubocop/cop/callbacksystems/prefer_stringify_keys.rb +24 -0
- data/lib/rubocop/cop/callbacksystems/prefer_symbolize_keys.rb +24 -0
- data/lib/rubocop/cop/callbacksystems/prefer_turbo_page_refresh_broadcasts.rb +40 -0
- data/lib/rubocop/cop/callbacksystems/private_constants_in_private_section.rb +160 -0
- data/lib/rubocop/cop/callbacksystems/private_delegate_placement.rb +342 -0
- data/lib/rubocop/cop/callbacksystems/private_methods_in_private_section.rb +70 -0
- data/lib/rubocop/cop/callbacksystems/private_nested_class_method_visibility.rb +269 -0
- data/lib/rubocop/cop/callbacksystems/private_nested_classes.rb +94 -0
- data/lib/rubocop/cop/callbacksystems/public_methods_must_have_tests.rb +190 -0
- data/lib/rubocop/cop/callbacksystems/redundant_concern_extend.rb +157 -0
- data/lib/rubocop/cop/callbacksystems/redundant_constant_freeze.rb +57 -0
- data/lib/rubocop/cop/callbacksystems/redundant_constant_namespace.rb +134 -0
- data/lib/rubocop/cop/callbacksystems/reflow_comments.rb +133 -0
- data/lib/rubocop/cop/callbacksystems/repeated_fixture_in_tests.rb +106 -0
- data/lib/rubocop/cop/callbacksystems/restricted_controller_actions.rb +85 -0
- data/lib/rubocop/cop/callbacksystems/routes_module_scope.rb +336 -0
- data/lib/rubocop/cop/callbacksystems/single_line_setup_block.rb +107 -0
- data/lib/rubocop/cop/callbacksystems/single_singleton_class.rb +49 -0
- data/lib/rubocop/cop/callbacksystems/single_top_level_class_or_module.rb +160 -0
- data/lib/rubocop/cop/callbacksystems/single_use_fixture_variable.rb +211 -0
- data/lib/rubocop/cop/callbacksystems/single_use_setup_variable.rb +684 -0
- data/lib/rubocop/cop/callbacksystems/singular_scope_names.rb +47 -0
- data/lib/rubocop/cop/callbacksystems/space_inside_percent_literal.rb +73 -0
- data/lib/rubocop/cop/callbacksystems/system_test_browser_driver.rb +30 -0
- data/lib/rubocop/cop/callbacksystems/test_method_definition.rb +86 -0
- data/lib/rubocop/cop/callbacksystems/test_method_order.rb +319 -0
- data/lib/rubocop/cop/callbacksystems/too_many_instance_variables.rb +78 -0
- data/lib/rubocop/cop/callbacksystems/too_many_local_variables.rb +77 -0
- data/lib/rubocop/cop/callbacksystems/too_many_validation_guards.rb +84 -0
- data/lib/rubocop/cop/callbacksystems/unnecessary_local_variable.rb +176 -0
- data/lib/rubocop/cop/callbacksystems/unused_private_method_in_nested_class.rb +203 -0
- data/lib/rubocop-callbacksystems.rb +21 -0
- data/rubocop.yml +685 -0
- metadata +337 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
module RuboCop::Callbacksystems::Helpers::NodeTypes
|
|
2
|
+
BLOCK_NODE_TYPES = %i[ block numblock itblock ]
|
|
3
|
+
|
|
4
|
+
def declaration_macro?(node)
|
|
5
|
+
attribute_macro?(node) || delegate_macro?(node)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def attribute_macro?(node)
|
|
9
|
+
bare_send?(node) && ATTRIBUTE_MACROS.include?(node.method_name)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def bare_send?(node)
|
|
13
|
+
node&.send_type? && node.receiver.nil?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def delegate_macro?(node)
|
|
17
|
+
bare_send?(node) && DELEGATE_MACROS.include?(node.method_name)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def mixin_macro?(node)
|
|
21
|
+
bare_send?(node) && MIXIN_MACROS.include?(node.method_name)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def association_macro?(node)
|
|
25
|
+
bare_send?(node) && ASSOCIATION_MACROS.include?(node.method_name)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def call_on_self?(node)
|
|
29
|
+
node&.call_type? && (node.receiver.nil? || node.receiver.self_type?)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def singleton_section?(node)
|
|
33
|
+
node&.sclass_type? && node.identifier.self_type?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def structural_self?(node)
|
|
37
|
+
(node.parent&.sclass_type? && node.parent.identifier.equal?(node)) ||
|
|
38
|
+
(node.parent&.defs_type? && node.parent.receiver.equal?(node))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def definition_identifier?(node)
|
|
42
|
+
node.parent&.type?(:class, :module) && node.parent.identifier.equal?(node)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def reads_of(variable_name, within:)
|
|
46
|
+
nodes_in(within, :lvar, :ivar).select { reads_variable?(it, variable_name) }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def nodes_in(tree, *types)
|
|
50
|
+
tree ? tree.each_node(*types).to_a : []
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def reads_variable?(node, variable_name)
|
|
54
|
+
node&.type?(:lvar, :ivar) && node.name == variable_name
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def definition_nodes_in(tree)
|
|
58
|
+
nodes_in(tree, :class, :module, :sclass)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def reads_as_string?(node)
|
|
62
|
+
node && reads_as?(node, literals: STRING_LITERAL_TYPES, methods: STRING_RESULT_METHODS)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def reads_as?(node, literals:, methods:)
|
|
66
|
+
literals.include?(node.type) || (node.call_type? && methods.include?(node.method_name))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def reads_as_array?(node)
|
|
70
|
+
node&.array_type? || array_construction?(node)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def call_of(node)
|
|
74
|
+
any_block_type?(node) ? node.send_node : node
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def any_block_type?(node)
|
|
78
|
+
node && BLOCK_NODE_TYPES.include?(node.type)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def core_constant?(node)
|
|
82
|
+
node&.const_type? && (node.namespace.nil? || node.namespace.cbase_type?)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def empty_collection_literal?(node)
|
|
86
|
+
node&.type?(:array, :hash) && node.children.empty?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def loop_block?(node)
|
|
90
|
+
node.method?(:loop)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def returned_expression_of(node)
|
|
94
|
+
node.return_type? ? node.children.first : node
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def hash_pairs_of(send_node)
|
|
98
|
+
send_node.arguments.select(&:hash_type?).flat_map(&:pairs)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def top_level_definitions_in(node)
|
|
102
|
+
TopLevelDefinitions.new(node).to_a
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
ARRAY_CONSTRUCTION_METHODS = %i[ new [] ]
|
|
107
|
+
STRING_LITERAL_TYPES = %i[ dstr str xstr ]
|
|
108
|
+
STRING_RESULT_METHODS = %i[
|
|
109
|
+
to_s to_str to_json to_param to_query inspect join strip lstrip rstrip squish chomp chop
|
|
110
|
+
gsub sub tr delete_prefix delete_suffix upcase downcase capitalize swapcase titleize humanize
|
|
111
|
+
parameterize dasherize underscore camelize classify tableize demodulize truncate name
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
ATTRIBUTE_MACROS =
|
|
115
|
+
%i[ attr_reader attr_writer attr_accessor attribute class_attribute has_secure_password has_secure_token ]
|
|
116
|
+
DELEGATE_MACROS = %i[ delegate delegate_missing_to ]
|
|
117
|
+
MIXIN_MACROS = %i[ include extend prepend ]
|
|
118
|
+
ASSOCIATION_MACROS = %i[
|
|
119
|
+
belongs_to has_many has_one has_and_belongs_to_many delegated_type
|
|
120
|
+
has_one_attached has_many_attached has_rich_text accepts_nested_attributes_for
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
def array_construction?(node)
|
|
124
|
+
node&.send_type? && core_constant?(node.receiver) && node.receiver.short_name == :Array &&
|
|
125
|
+
ARRAY_CONSTRUCTION_METHODS.include?(node.method_name)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Class and module definitions opened by a file, with only top-level begin nodes transparent.
|
|
129
|
+
class TopLevelDefinitions
|
|
130
|
+
include Enumerable
|
|
131
|
+
|
|
132
|
+
def initialize(node)
|
|
133
|
+
@node = node
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def each
|
|
137
|
+
if block_given?
|
|
138
|
+
pending = [ node ].compact
|
|
139
|
+
until pending.empty?
|
|
140
|
+
current = pending.pop
|
|
141
|
+
case current.type
|
|
142
|
+
when :class, :module then yield current
|
|
143
|
+
when :begin then pending.concat(current.each_child_node.to_a.reverse)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
else
|
|
147
|
+
to_enum(__method__)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
private
|
|
152
|
+
attr_reader :node
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module RuboCop::Callbacksystems::Helpers::Rails
|
|
2
|
+
EAGER_LOADING_METHODS = %i[ preload eager_load includes ]
|
|
3
|
+
CONTROLLER_SUPERCLASSES = %w[ ApplicationController ActionController::Base ActionController::API ]
|
|
4
|
+
STANDARD_CONTROLLER_ACTIONS = %i[ index show new create edit update destroy ]
|
|
5
|
+
RAILS_TEST_BASE_CLASSES = %w[
|
|
6
|
+
ActiveSupport::TestCase
|
|
7
|
+
ActionDispatch::IntegrationTest
|
|
8
|
+
ActionController::TestCase
|
|
9
|
+
ActionMailer::TestCase
|
|
10
|
+
ActionView::TestCase
|
|
11
|
+
ActiveJob::TestCase
|
|
12
|
+
ActionCable::TestCase
|
|
13
|
+
ActionCable::Channel::TestCase
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
def controller_class?(node)
|
|
17
|
+
node&.class_type? && controller_superclass?(node.parent_class)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def controller_superclass?(superclass_node)
|
|
21
|
+
name = constant_name_of(superclass_node)&.delete_prefix("::")
|
|
22
|
+
name && (CONTROLLER_SUPERCLASSES.include?(name) || name.end_with?("Controller"))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def application_controller_class?(node)
|
|
26
|
+
node&.class_type? && node.identifier.short_name == :ApplicationController
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def scope_definition?(node)
|
|
30
|
+
bare_send?(node) && node.method?(:scope) && node.first_argument&.sym_type?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def rails_test_base_class?(superclass_node)
|
|
34
|
+
RAILS_TEST_BASE_CLASSES.include?(constant_name_of(superclass_node)&.delete_prefix("::"))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def routes_file?(path)
|
|
38
|
+
path.present? && (path.include?("config/routes") || path.end_with?("routes.rb"))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def controller_file?(path)
|
|
42
|
+
path.present? && (path.split("/").include?("controllers") || path.end_with?("_controller.rb"))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def model_file?(path)
|
|
46
|
+
path.present? && path.tr("\\", "/").match?(%r{(?:\A|/)app/models/})
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_file?(path)
|
|
50
|
+
path.present? && path.end_with?("_test.rb")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
module RuboCop::Callbacksystems::Helpers::Ranges
|
|
2
|
+
include RuboCop::Cop::RangeHelp, RuboCop::Cop::Util
|
|
3
|
+
|
|
4
|
+
def statement_removal_range_for(node)
|
|
5
|
+
inline_statement_removal_range_for(node) || statement_removal_range_of(node.source_range)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# The buffer given explicitly is what frees this from a cop's processed source, so plain objects can use it too.
|
|
9
|
+
def statement_removal_range_of(source_range)
|
|
10
|
+
range = range_by_whole_lines(source_range, include_final_newline: true, buffer: source_range.source_buffer)
|
|
11
|
+
blank_line_above(range) || blank_line_below(range) || range
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Statements with only blank lines between them share one range, so their removal takes one blank line, not one each.
|
|
15
|
+
def statement_removal_ranges_of(source_ranges)
|
|
16
|
+
source_ranges
|
|
17
|
+
.slice_when { |left, right| code_between?(left, right) }
|
|
18
|
+
.map { statement_removal_range_of(span_of(it)) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def span_of(ranges)
|
|
22
|
+
ranges.first.join(ranges.last)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def line_removal_range_for(node)
|
|
26
|
+
line_removal_range_of(node.source_range)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def line_removal_range_of(source_range)
|
|
30
|
+
range_by_whole_lines(source_range, include_final_newline: true, buffer: source_range.source_buffer)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def indentation_of(node)
|
|
34
|
+
" " * node.source_range.column
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def call_prefix_of(node)
|
|
38
|
+
node.source_range.with(end_pos: node.loc.selector.begin_pos).source
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def carries_heredoc?(node)
|
|
42
|
+
node.each_node(:str, :dstr, :xstr).any? { it.loc?(:heredoc_body) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def range_through_heredocs(node)
|
|
46
|
+
node.source_range.with(end_pos: [ node.source_range.end_pos, *heredoc_ends_in(node) ].max)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def range_spanning(nodes)
|
|
50
|
+
span_of(nodes.map(&:source_range))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def fits_on_line?(node, source, max_line_length)
|
|
54
|
+
node.source_range.column + source.length + trailing_length_of(node) <= max_line_length
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def trailing_length_of(node)
|
|
58
|
+
ending = node.source_range.end
|
|
59
|
+
ending.source_line.length - ending.column
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def line_start_position_of(node)
|
|
63
|
+
range = node.source_range
|
|
64
|
+
range.begin_pos - range.column
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
def inline_statement_removal_range_for(node)
|
|
69
|
+
if same_line_siblings?([ node, node.right_sibling ])
|
|
70
|
+
node.source_range.with(end_pos: node.right_sibling.source_range.begin_pos)
|
|
71
|
+
elsif same_line_siblings?([ node.left_sibling, node ])
|
|
72
|
+
node.source_range.with(begin_pos: node.left_sibling.source_range.end_pos)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def same_line_siblings?(nodes)
|
|
77
|
+
left, right = nodes
|
|
78
|
+
|
|
79
|
+
left && right && left.parent.type?(:begin, :kwbegin) && left.parent.equal?(right.parent) &&
|
|
80
|
+
left.last_line == right.first_line
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def blank_line_above(range)
|
|
84
|
+
buffer = range.source_buffer
|
|
85
|
+
line = buffer.line_for_position(range.begin_pos) - 1
|
|
86
|
+
range.with(begin_pos: buffer.line_range(line).begin_pos) if blank_line?(buffer, line)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def blank_line?(buffer, line)
|
|
90
|
+
line.between?(1, buffer.last_line) && buffer.source_line(line).match?(/\A[ \t]*\z/)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def blank_line_below(range)
|
|
94
|
+
buffer = range.source_buffer
|
|
95
|
+
line = buffer.line_for_position(range.end_pos)
|
|
96
|
+
end_of_blank = [ buffer.line_range(line).end_pos + 1, buffer.source.length ].min
|
|
97
|
+
range.with(end_pos: end_of_blank) if blank_line?(buffer, line)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def code_between?(left, right)
|
|
101
|
+
left.end.join(right.begin).source.strip.present?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def heredoc_ends_in(node)
|
|
105
|
+
node.each_node(:str, :dstr, :xstr).filter_map { it.loc.heredoc_end.end_pos if it.loc?(:heredoc_end) }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module RuboCop::Callbacksystems::Helpers::Recursion
|
|
2
|
+
# A recursion subject is a name passed both bare and as the receiver of a derived value: `walk(node.child, node)`.
|
|
3
|
+
def recursion_subject_names_in(node)
|
|
4
|
+
if node
|
|
5
|
+
calls = node.each_node(:send, :csend)
|
|
6
|
+
calls = [ node ].chain(calls) if node.call_type?
|
|
7
|
+
calls.flat_map { recursion_subjects_in(it) }.to_set
|
|
8
|
+
else
|
|
9
|
+
Set.new
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def recursion_subjects_in(call)
|
|
14
|
+
receiver_names = derived_receiver_names_in(call)
|
|
15
|
+
direct_argument_names_in(call).select { receiver_names.include?(it) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def derived_receiver_names_in(call)
|
|
19
|
+
call.arguments.filter_map { local_variable_name_of(it.receiver) if it.call_type? }.to_set
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def local_variable_name_of(argument)
|
|
23
|
+
argument.children.first.to_s if argument&.lvar_type?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def direct_argument_names_in(call)
|
|
27
|
+
call.arguments.filter_map { local_variable_name_of(it) }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module RuboCop::Callbacksystems::Helpers::Variables
|
|
2
|
+
def deferred_callable_block?(node)
|
|
3
|
+
if any_block_type?(node)
|
|
4
|
+
call = call_of(node)
|
|
5
|
+
|
|
6
|
+
kernel_callable?(call) || proc_constructor?(call)
|
|
7
|
+
else
|
|
8
|
+
false
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def method_definition_block?(node)
|
|
13
|
+
any_block_type?(node) && METHOD_DEFINITION_CALLS.include?(call_of(node).method_name)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def variable_name_of(node)
|
|
17
|
+
node.match_var_type? ? node.children.first : node.name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def conditional_return_of_block_argument?(return_node, block:)
|
|
21
|
+
value = return_node.children.first
|
|
22
|
+
|
|
23
|
+
return_node.parent.if_type? && value&.lvar_type? && block.argument_list.any? { it.name == value.name } &&
|
|
24
|
+
!name_rebound_between?(value.name, node: return_node, boundary: block)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def name_rebound_between?(name, node:, boundary:)
|
|
28
|
+
node.each_ancestor(:any_block).take_while { !it.equal?(boundary) }.any? do |block|
|
|
29
|
+
block.argument_list.any? { it.respond_to?(:name) && it.name.to_s == name.to_s }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
METHOD_DEFINITION_CALLS = %i[ define_method define_singleton_method ]
|
|
35
|
+
|
|
36
|
+
def kernel_callable?(call)
|
|
37
|
+
%i[ lambda proc ].include?(call.method_name) &&
|
|
38
|
+
(call.receiver.nil? || (core_constant?(call.receiver) && call.receiver.short_name == :Kernel))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def proc_constructor?(call)
|
|
42
|
+
call.method?(:new) && core_constant?(call.receiver) && call.receiver.short_name == :Proc
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
module RuboCop::Callbacksystems::Helpers::Visibility
|
|
2
|
+
LEVELS = %i[ public protected private ]
|
|
3
|
+
|
|
4
|
+
def public_method?(node)
|
|
5
|
+
visibility_for(node).public?
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def visibility_of(node)
|
|
9
|
+
visibility_for(node).level
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def visibility_at(node, body)
|
|
13
|
+
visibility_for(node).level_in(body)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def enclosing_body_for(node)
|
|
17
|
+
visibility_for(node).enclosing_body
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def enclosing_definition_of(node)
|
|
21
|
+
visibility_for(node).enclosing_definition
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def private_modifier_in(body)
|
|
25
|
+
sections_in(body).private_modifier
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def in_private_section?(node, body)
|
|
29
|
+
sections_in(body).in_private_section?(node)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def visibility_applied_to(node, definition)
|
|
33
|
+
if bare_send?(node) && node.arguments.include?(definition)
|
|
34
|
+
wrapped_visibility(node.method_name, definition)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def private_method?(node)
|
|
39
|
+
visibility_for(node).private?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def protected_method?(node)
|
|
43
|
+
visibility_for(node).protected?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def private_non_predicate?(node)
|
|
47
|
+
visibility_for(node).private_non_predicate?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def private_nested_class?(class_node)
|
|
51
|
+
enclosing = enclosing_class_or_module_of(class_node)
|
|
52
|
+
enclosing && private_nested_classes_in(enclosing).include?(class_node)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def enclosing_class_or_module_of(node)
|
|
56
|
+
node.each_ancestor(:class, :module).first
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def private_nested_classes_in(class_node)
|
|
60
|
+
sections_in(class_node.body).private_nested_classes
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def public_methods_in(class_node)
|
|
64
|
+
sections_in(class_node.body).public_method_nodes
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def private_methods_in(class_node)
|
|
68
|
+
sections_in(class_node.body).private_method_nodes
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def enclosing_method_of(node)
|
|
72
|
+
node.each_ancestor(:any_def).first
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def enclosing_scope_of(node)
|
|
76
|
+
node.each_ancestor(:any_def, :any_block).first
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def sibling_method_nodes_of(node)
|
|
80
|
+
direct_method_nodes_in(enclosing_class_or_module_of(node)&.body)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def leaves_public_section?(node)
|
|
84
|
+
%i[ private protected ].include?(visibility_modifier_of(node))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def visibility_modifier_of(node)
|
|
88
|
+
if bare_send?(node) && node.arguments.empty?
|
|
89
|
+
node.method_name if LEVELS.include?(node.method_name)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def private_constant_names_of(node)
|
|
94
|
+
names_marked_by(node, macro: :private_constant).map { it.value.to_sym }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def names_marked_by(node, macro:)
|
|
98
|
+
bare_send?(node) && node.method?(macro) ? name_arguments_of(node) : []
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
def visibility_for(node)
|
|
103
|
+
RuboCop::Callbacksystems::ClassStructure::NodeVisibility.new(node)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def sections_in(body)
|
|
107
|
+
RuboCop::Callbacksystems::ClassStructure::ClassBody.new(body)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def wrapped_visibility(modifier, definition)
|
|
111
|
+
case modifier
|
|
112
|
+
when *LEVELS then modifier if definition.def_type?
|
|
113
|
+
when :private_class_method then :private if self_singleton_definition?(definition)
|
|
114
|
+
when :public_class_method then :public if self_singleton_definition?(definition)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def self_singleton_definition?(definition)
|
|
119
|
+
definition.defs_type? && definition.receiver.self_type?
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module RuboCop::Callbacksystems::Helpers
|
|
2
|
+
extend self
|
|
3
|
+
|
|
4
|
+
def const_added(name)
|
|
5
|
+
super
|
|
6
|
+
helper = const_get(name)
|
|
7
|
+
Wiring.new(self, helper).connect unless helper.is_a?(Class)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
class Wiring
|
|
12
|
+
def initialize(helpers, submodule)
|
|
13
|
+
@helpers = helpers
|
|
14
|
+
@submodule = submodule
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def connect
|
|
18
|
+
if helper_module?(submodule)
|
|
19
|
+
siblings.each { extend_mutually(it) }
|
|
20
|
+
helpers.include(submodule)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
attr_reader :helpers, :submodule
|
|
26
|
+
|
|
27
|
+
def helper_module?(const)
|
|
28
|
+
const.is_a?(Module) && !const.is_a?(Class)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def siblings
|
|
32
|
+
helpers.constants.filter_map do |name|
|
|
33
|
+
candidate = helpers.const_get(name)
|
|
34
|
+
candidate if helper_module?(candidate) && candidate != submodule
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def extend_mutually(other)
|
|
39
|
+
submodule.extend(other) unless submodule.singleton_class < other
|
|
40
|
+
other.extend(submodule) unless other.singleton_class < submodule
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Calls on self indexed by their enclosing class and method domain, so several definitions can ask who calls them
|
|
2
|
+
# without each walking the whole class again.
|
|
3
|
+
class RuboCop::Callbacksystems::Methods::Calls
|
|
4
|
+
include RuboCop::Callbacksystems::Helpers
|
|
5
|
+
|
|
6
|
+
def initialize(ast)
|
|
7
|
+
@ast = ast
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def named(name, from:)
|
|
11
|
+
domain = RuboCop::Callbacksystems::Methods::Domain.new(from)
|
|
12
|
+
calls_in(domain.container, identity: domain.identity).fetch(name) { [] }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
attr_reader :ast
|
|
17
|
+
|
|
18
|
+
def calls_in(container, identity:)
|
|
19
|
+
calls_by_container[container]&.fetch(identity, {}) || {}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def calls_by_container
|
|
23
|
+
@calls_by_container ||= {}.compare_by_identity.tap do |index|
|
|
24
|
+
nodes_in(ast, :send, :csend).each { add(it, to: index) if call_on_self?(it) }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def add(call, to:)
|
|
29
|
+
domain = domain_of_call(call)
|
|
30
|
+
scopes = to[domain.container] ||= {}
|
|
31
|
+
calls = scopes[domain.identity] ||= {}
|
|
32
|
+
(calls[call.method_name] ||= []) << call
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def domain_of_call(call)
|
|
36
|
+
RuboCop::Callbacksystems::Methods::Domain.new(call)
|
|
37
|
+
end
|
|
38
|
+
end
|