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.
Files changed (182) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +78 -0
  4. data/config/default.yml +590 -0
  5. data/docs/cops.md +111 -0
  6. data/lib/rubocop/callbacksystems/autocorrection/batch.rb +135 -0
  7. data/lib/rubocop/callbacksystems/autocorrection/comment_rescue.rb +112 -0
  8. data/lib/rubocop/callbacksystems/autocorrection/rehearsal.rb +65 -0
  9. data/lib/rubocop/callbacksystems/autocorrection/rewrite_permit.rb +14 -0
  10. data/lib/rubocop/callbacksystems/class_structure/builder_assignment.rb +48 -0
  11. data/lib/rubocop/callbacksystems/class_structure/class_body.rb +50 -0
  12. data/lib/rubocop/callbacksystems/class_structure/divergence.rb +31 -0
  13. data/lib/rubocop/callbacksystems/class_structure/node_visibility.rb +82 -0
  14. data/lib/rubocop/callbacksystems/class_structure/reference_order.rb +36 -0
  15. data/lib/rubocop/callbacksystems/class_structure/statement_rank.rb +84 -0
  16. data/lib/rubocop/callbacksystems/class_structure/statement_run.rb +42 -0
  17. data/lib/rubocop/callbacksystems/class_structure/visibility.rb +84 -0
  18. data/lib/rubocop/callbacksystems/cops_document.rb +78 -0
  19. data/lib/rubocop/callbacksystems/execution/deferred_local_variables.rb +138 -0
  20. data/lib/rubocop/callbacksystems/execution/discarded_expression.rb +45 -0
  21. data/lib/rubocop/callbacksystems/execution/eager_evaluation_path.rb +73 -0
  22. data/lib/rubocop/callbacksystems/execution/immediate.rb +71 -0
  23. data/lib/rubocop/callbacksystems/execution/local_variable_occurrences.rb +112 -0
  24. data/lib/rubocop/callbacksystems/hashes/key_transform_detection.rb +108 -0
  25. data/lib/rubocop/callbacksystems/hashes/keyword_options.rb +37 -0
  26. data/lib/rubocop/callbacksystems/helpers/bodies.rb +150 -0
  27. data/lib/rubocop/callbacksystems/helpers/builders.rb +103 -0
  28. data/lib/rubocop/callbacksystems/helpers/comments.rb +56 -0
  29. data/lib/rubocop/callbacksystems/helpers/corrections.rb +15 -0
  30. data/lib/rubocop/callbacksystems/helpers/methods.rb +46 -0
  31. data/lib/rubocop/callbacksystems/helpers/names.rb +65 -0
  32. data/lib/rubocop/callbacksystems/helpers/node_types.rb +154 -0
  33. data/lib/rubocop/callbacksystems/helpers/rails.rb +52 -0
  34. data/lib/rubocop/callbacksystems/helpers/ranges.rb +107 -0
  35. data/lib/rubocop/callbacksystems/helpers/recursion.rb +29 -0
  36. data/lib/rubocop/callbacksystems/helpers/variables.rb +44 -0
  37. data/lib/rubocop/callbacksystems/helpers/visibility.rb +121 -0
  38. data/lib/rubocop/callbacksystems/helpers.rb +43 -0
  39. data/lib/rubocop/callbacksystems/methods/calls.rb +38 -0
  40. data/lib/rubocop/callbacksystems/methods/definitions.rb +218 -0
  41. data/lib/rubocop/callbacksystems/methods/delegate_macro.rb +144 -0
  42. data/lib/rubocop/callbacksystems/methods/delegation_target.rb +55 -0
  43. data/lib/rubocop/callbacksystems/methods/domain.rb +77 -0
  44. data/lib/rubocop/callbacksystems/methods/implicit_invocations.rb +17 -0
  45. data/lib/rubocop/callbacksystems/methods/macro_references.rb +238 -0
  46. data/lib/rubocop/callbacksystems/methods/reference_evidence.rb +74 -0
  47. data/lib/rubocop/callbacksystems/methods/siblings.rb +24 -0
  48. data/lib/rubocop/callbacksystems/methods/statement_definitions.rb +68 -0
  49. data/lib/rubocop/callbacksystems/offense.rb +13 -0
  50. data/lib/rubocop/callbacksystems/plugin.rb +27 -0
  51. data/lib/rubocop/callbacksystems/project_index/cache.rb +16 -0
  52. data/lib/rubocop/callbacksystems/project_index/confinement_cache.rb +40 -0
  53. data/lib/rubocop/callbacksystems/project_index/constant_references.rb +74 -0
  54. data/lib/rubocop/callbacksystems/project_index/corrections.rb +35 -0
  55. data/lib/rubocop/callbacksystems/project_index/coverage.rb +56 -0
  56. data/lib/rubocop/callbacksystems/project_index/diagnostics.rb +60 -0
  57. data/lib/rubocop/callbacksystems/project_index/freshness.rb +104 -0
  58. data/lib/rubocop/callbacksystems/project_index/loader.rb +9 -0
  59. data/lib/rubocop/callbacksystems/project_index/location.rb +29 -0
  60. data/lib/rubocop/callbacksystems/project_index/nested_class_confinement.rb +297 -0
  61. data/lib/rubocop/callbacksystems/project_index/nested_class_method_dispatch.rb +50 -0
  62. data/lib/rubocop/callbacksystems/project_index/reading.rb +129 -0
  63. data/lib/rubocop/callbacksystems/project_index/source_file.rb +59 -0
  64. data/lib/rubocop/callbacksystems/project_index/source_file_match.rb +57 -0
  65. data/lib/rubocop/callbacksystems/project_index/support.rb +46 -0
  66. data/lib/rubocop/callbacksystems/source/comment_blocks.rb +43 -0
  67. data/lib/rubocop/callbacksystems/source/comments.rb +141 -0
  68. data/lib/rubocop/callbacksystems/source/file_ast.rb +15 -0
  69. data/lib/rubocop/callbacksystems/source/files_checksum.rb +43 -0
  70. data/lib/rubocop/callbacksystems/source/single_line_call.rb +181 -0
  71. data/lib/rubocop/callbacksystems/source/statement_with_comments.rb +131 -0
  72. data/lib/rubocop/callbacksystems/testing/cop_helpers.rb +42 -0
  73. data/lib/rubocop/callbacksystems/testing/fixture_call.rb +30 -0
  74. data/lib/rubocop/callbacksystems/testing/fixture_names.rb +62 -0
  75. data/lib/rubocop/callbacksystems/testing/path_mapping.rb +104 -0
  76. data/lib/rubocop/cop/callbacksystems/application_controller_method_definition.rb +44 -0
  77. data/lib/rubocop/cop/callbacksystems/assert_with_expected_argument.rb +60 -0
  78. data/lib/rubocop/cop/callbacksystems/base.rb +134 -0
  79. data/lib/rubocop/cop/callbacksystems/body_order.rb +478 -0
  80. data/lib/rubocop/cop/callbacksystems/builder_method_parentheses.rb +74 -0
  81. data/lib/rubocop/cop/callbacksystems/collapse_multiline_expression.rb +140 -0
  82. data/lib/rubocop/cop/callbacksystems/comment_block_length.rb +137 -0
  83. data/lib/rubocop/cop/callbacksystems/complex_conditional.rb +75 -0
  84. data/lib/rubocop/cop/callbacksystems/controller_test_response_assertion.rb +105 -0
  85. data/lib/rubocop/cop/callbacksystems/controller_test_response_first_assertion.rb +123 -0
  86. data/lib/rubocop/cop/callbacksystems/data_clump.rb +339 -0
  87. data/lib/rubocop/cop/callbacksystems/declarative_method_naming.rb +350 -0
  88. data/lib/rubocop/cop/callbacksystems/delegate_requires_private_option.rb +81 -0
  89. data/lib/rubocop/cop/callbacksystems/eager_loading_scope_naming.rb +386 -0
  90. data/lib/rubocop/cop/callbacksystems/early_return.rb +215 -0
  91. data/lib/rubocop/cop/callbacksystems/empty_line_before_method.rb +168 -0
  92. data/lib/rubocop/cop/callbacksystems/empty_line_between_sections.rb +169 -0
  93. data/lib/rubocop/cop/callbacksystems/empty_private_section.rb +107 -0
  94. data/lib/rubocop/cop/callbacksystems/expanded_empty_class_or_module.rb +71 -0
  95. data/lib/rubocop/cop/callbacksystems/inline_memoized_computation.rb +110 -0
  96. data/lib/rubocop/cop/callbacksystems/job_enqueue_methods.rb +93 -0
  97. data/lib/rubocop/cop/callbacksystems/max_safe_navigation_depth.rb +118 -0
  98. data/lib/rubocop/cop/callbacksystems/method_invocation_order.rb +261 -0
  99. data/lib/rubocop/cop/callbacksystems/nested_class_order.rb +255 -0
  100. data/lib/rubocop/cop/callbacksystems/no_abbreviations.rb +197 -0
  101. data/lib/rubocop/cop/callbacksystems/no_anemic_delegation.rb +101 -0
  102. data/lib/rubocop/cop/callbacksystems/no_anemic_record.rb +309 -0
  103. data/lib/rubocop/cop/callbacksystems/no_assert_select.rb +31 -0
  104. data/lib/rubocop/cop/callbacksystems/no_bang_method_without_counterpart.rb +451 -0
  105. data/lib/rubocop/cop/callbacksystems/no_call_method.rb +73 -0
  106. data/lib/rubocop/cop/callbacksystems/no_comments_in_test_class_body.rb +159 -0
  107. data/lib/rubocop/cop/callbacksystems/no_consecutive_appends.rb +261 -0
  108. data/lib/rubocop/cop/callbacksystems/no_custom_route_actions.rb +124 -0
  109. data/lib/rubocop/cop/callbacksystems/no_direct_eager_loading.rb +90 -0
  110. data/lib/rubocop/cop/callbacksystems/no_each_with_early_return.rb +58 -0
  111. data/lib/rubocop/cop/callbacksystems/no_explicit_public_modifier.rb +81 -0
  112. data/lib/rubocop/cop/callbacksystems/no_hash_with_default_block.rb +68 -0
  113. data/lib/rubocop/cop/callbacksystems/no_local_variable_return.rb +173 -0
  114. data/lib/rubocop/cop/callbacksystems/no_manual_accumulation.rb +188 -0
  115. data/lib/rubocop/cop/callbacksystems/no_mixed_memoization.rb +145 -0
  116. data/lib/rubocop/cop/callbacksystems/no_nested_modules_in_classes.rb +78 -0
  117. data/lib/rubocop/cop/callbacksystems/no_nil_at_end_of_method.rb +74 -0
  118. data/lib/rubocop/cop/callbacksystems/no_redundant_validation_name.rb +37 -0
  119. data/lib/rubocop/cop/callbacksystems/no_redundant_wrapper_method.rb +161 -0
  120. data/lib/rubocop/cop/callbacksystems/no_section_divider_comments.rb +105 -0
  121. data/lib/rubocop/cop/callbacksystems/no_send_in_tests.rb +75 -0
  122. data/lib/rubocop/cop/callbacksystems/no_service_objects.rb +64 -0
  123. data/lib/rubocop/cop/callbacksystems/no_single_letter_names.rb +47 -0
  124. data/lib/rubocop/cop/callbacksystems/no_singleton_class_in_modules.rb +43 -0
  125. data/lib/rubocop/cop/callbacksystems/no_tap_collection_building.rb +173 -0
  126. data/lib/rubocop/cop/callbacksystems/no_turbo_stream_in_controllers.rb +52 -0
  127. data/lib/rubocop/cop/callbacksystems/no_typographic_clutter.rb +159 -0
  128. data/lib/rubocop/cop/callbacksystems/no_writes_in_get_actions.rb +149 -0
  129. data/lib/rubocop/cop/callbacksystems/ordered_mixin_arguments.rb +78 -0
  130. data/lib/rubocop/cop/callbacksystems/plural_controller_names.rb +103 -0
  131. data/lib/rubocop/cop/callbacksystems/prefer_attr_reader_over_instance_variable.rb +86 -0
  132. data/lib/rubocop/cop/callbacksystems/prefer_backslash_continuation.rb +478 -0
  133. data/lib/rubocop/cop/callbacksystems/prefer_class_for_state.rb +532 -0
  134. data/lib/rubocop/cop/callbacksystems/prefer_class_new_for_empty_nested_class.rb +247 -0
  135. data/lib/rubocop/cop/callbacksystems/prefer_class_over_builder_block.rb +124 -0
  136. data/lib/rubocop/cop/callbacksystems/prefer_default_argument.rb +225 -0
  137. data/lib/rubocop/cop/callbacksystems/prefer_delegate.rb +242 -0
  138. data/lib/rubocop/cop/callbacksystems/prefer_delegate_over_instance_variable_assignment.rb +175 -0
  139. data/lib/rubocop/cop/callbacksystems/prefer_excluding.rb +204 -0
  140. data/lib/rubocop/cop/callbacksystems/prefer_extract_associated.rb +54 -0
  141. data/lib/rubocop/cop/callbacksystems/prefer_it_block_parameter.rb +156 -0
  142. data/lib/rubocop/cop/callbacksystems/prefer_many.rb +57 -0
  143. data/lib/rubocop/cop/callbacksystems/prefer_method_over_lambda.rb +211 -0
  144. data/lib/rubocop/cop/callbacksystems/prefer_method_over_variable.rb +172 -0
  145. data/lib/rubocop/cop/callbacksystems/prefer_module_for_static_class.rb +286 -0
  146. data/lib/rubocop/cop/callbacksystems/prefer_ordinal_array_access.rb +136 -0
  147. data/lib/rubocop/cop/callbacksystems/prefer_positive_wrap.rb +265 -0
  148. data/lib/rubocop/cop/callbacksystems/prefer_squish.rb +47 -0
  149. data/lib/rubocop/cop/callbacksystems/prefer_stringify_keys.rb +24 -0
  150. data/lib/rubocop/cop/callbacksystems/prefer_symbolize_keys.rb +24 -0
  151. data/lib/rubocop/cop/callbacksystems/prefer_turbo_page_refresh_broadcasts.rb +40 -0
  152. data/lib/rubocop/cop/callbacksystems/private_constants_in_private_section.rb +160 -0
  153. data/lib/rubocop/cop/callbacksystems/private_delegate_placement.rb +342 -0
  154. data/lib/rubocop/cop/callbacksystems/private_methods_in_private_section.rb +70 -0
  155. data/lib/rubocop/cop/callbacksystems/private_nested_class_method_visibility.rb +269 -0
  156. data/lib/rubocop/cop/callbacksystems/private_nested_classes.rb +94 -0
  157. data/lib/rubocop/cop/callbacksystems/public_methods_must_have_tests.rb +190 -0
  158. data/lib/rubocop/cop/callbacksystems/redundant_concern_extend.rb +157 -0
  159. data/lib/rubocop/cop/callbacksystems/redundant_constant_freeze.rb +57 -0
  160. data/lib/rubocop/cop/callbacksystems/redundant_constant_namespace.rb +134 -0
  161. data/lib/rubocop/cop/callbacksystems/reflow_comments.rb +133 -0
  162. data/lib/rubocop/cop/callbacksystems/repeated_fixture_in_tests.rb +106 -0
  163. data/lib/rubocop/cop/callbacksystems/restricted_controller_actions.rb +85 -0
  164. data/lib/rubocop/cop/callbacksystems/routes_module_scope.rb +336 -0
  165. data/lib/rubocop/cop/callbacksystems/single_line_setup_block.rb +107 -0
  166. data/lib/rubocop/cop/callbacksystems/single_singleton_class.rb +49 -0
  167. data/lib/rubocop/cop/callbacksystems/single_top_level_class_or_module.rb +160 -0
  168. data/lib/rubocop/cop/callbacksystems/single_use_fixture_variable.rb +211 -0
  169. data/lib/rubocop/cop/callbacksystems/single_use_setup_variable.rb +684 -0
  170. data/lib/rubocop/cop/callbacksystems/singular_scope_names.rb +47 -0
  171. data/lib/rubocop/cop/callbacksystems/space_inside_percent_literal.rb +73 -0
  172. data/lib/rubocop/cop/callbacksystems/system_test_browser_driver.rb +30 -0
  173. data/lib/rubocop/cop/callbacksystems/test_method_definition.rb +86 -0
  174. data/lib/rubocop/cop/callbacksystems/test_method_order.rb +319 -0
  175. data/lib/rubocop/cop/callbacksystems/too_many_instance_variables.rb +78 -0
  176. data/lib/rubocop/cop/callbacksystems/too_many_local_variables.rb +77 -0
  177. data/lib/rubocop/cop/callbacksystems/too_many_validation_guards.rb +84 -0
  178. data/lib/rubocop/cop/callbacksystems/unnecessary_local_variable.rb +176 -0
  179. data/lib/rubocop/cop/callbacksystems/unused_private_method_in_nested_class.rb +203 -0
  180. data/lib/rubocop-callbacksystems.rb +21 -0
  181. data/rubocop.yml +685 -0
  182. metadata +337 -0
@@ -0,0 +1,218 @@
1
+ class RuboCop::Callbacksystems::Methods::Definitions
2
+ include Enumerable
3
+ include RuboCop::Callbacksystems::Helpers
4
+
5
+ delegate :each, to: :definitions
6
+
7
+ def initialize(ast)
8
+ @ast = ast
9
+ end
10
+
11
+ private
12
+ Definition = Data.define(:node, :name)
13
+
14
+ attr_reader :ast
15
+
16
+ def definitions
17
+ bodies = top_level_definitions_in(ast).map { Body.new(it.body, depth: 0, context: :owner) }
18
+
19
+ Traversal.new(bodies).to_a
20
+ end
21
+
22
+ # Definition-bearing body and statement entries walked depth first without recursive object calls.
23
+ class Traversal
24
+ include Enumerable
25
+
26
+ def initialize(entries)
27
+ @entries = entries
28
+ end
29
+
30
+ def each
31
+ if block_given?
32
+ pending = entries.reverse
33
+ until pending.empty?
34
+ entry = pending.pop
35
+ entry.definitions.each { yield it }
36
+ pending.concat(entry.children.reverse)
37
+ end
38
+ else
39
+ to_enum(__method__)
40
+ end
41
+ end
42
+
43
+ private
44
+ attr_reader :entries
45
+ end
46
+
47
+ class Body
48
+ include RuboCop::Callbacksystems::Helpers
49
+
50
+ def initialize(node, depth:, context:, singleton_owner_body: nil)
51
+ @node = node
52
+ @depth = depth
53
+ @context = context
54
+ @singleton_owner_body = singleton_owner_body
55
+ end
56
+
57
+ def definitions
58
+ []
59
+ end
60
+
61
+ def children
62
+ statements_in(node).map { Statement.new(it, body: self) }
63
+ end
64
+
65
+ def public_definition?(definition)
66
+ DefinitionVisibility.new(definition, node, singleton_owner_body:).public?
67
+ end
68
+
69
+ def target_definition?(definition)
70
+ depth_of(definition) <= 1
71
+ end
72
+
73
+ def target_scope?
74
+ depth.zero?
75
+ end
76
+
77
+ def body_within_singleton_section(child)
78
+ if depth.zero?
79
+ self.class.new(child, depth: 1, context: :singleton, singleton_owner_body: node)
80
+ end
81
+ end
82
+
83
+ def body_within_definition_block(child, kind:)
84
+ unless context == :singleton
85
+ self.class.new(child, depth: kind == :class_methods ? 1 : 0, context: :definition_block)
86
+ end
87
+ end
88
+
89
+ private
90
+ attr_reader :node, :depth, :context, :singleton_owner_body
91
+
92
+ def depth_of(definition)
93
+ depth + (definition.defs_type? ? 1 : 0)
94
+ end
95
+
96
+ class DefinitionVisibility
97
+ include RuboCop::Callbacksystems::Helpers
98
+
99
+ def initialize(definition, body, singleton_owner_body:)
100
+ @definition = definition
101
+ @body = body
102
+ @singleton_owner_body = singleton_owner_body
103
+ end
104
+
105
+ def public?
106
+ level == :public
107
+ end
108
+
109
+ private
110
+ attr_reader :definition, :body, :singleton_owner_body
111
+
112
+ def level
113
+ if definition.location
114
+ assigned_level || visibility_applied_to(definition.parent, definition) || default_level
115
+ else
116
+ :public
117
+ end
118
+ end
119
+
120
+ def assigned_level
121
+ assignments.max_by(&:position)&.level
122
+ end
123
+
124
+ def assignments
125
+ [
126
+ visibility.assignment_after(definition, singleton: definition.defs_type?),
127
+ singleton_owner_visibility&.assignment_after(definition, singleton: true)
128
+ ].compact
129
+ end
130
+
131
+ def visibility
132
+ @visibility ||= RuboCop::Callbacksystems::ClassStructure::Visibility.for(body)
133
+ end
134
+
135
+ def singleton_owner_visibility
136
+ if singleton_owner_body
137
+ RuboCop::Callbacksystems::ClassStructure::Visibility.for(singleton_owner_body)
138
+ end
139
+ end
140
+
141
+ def default_level
142
+ definition.defs_type? ? :public : visibility.level_at(definition)
143
+ end
144
+ end
145
+ end
146
+
147
+ class Statement
148
+ include RuboCop::Callbacksystems::Helpers
149
+
150
+ DEFINITION_BLOCKS = %i[ class_methods included prepended ].to_set
151
+
152
+ def initialize(node, body:)
153
+ @node = node
154
+ @body = body
155
+ end
156
+
157
+ def definitions
158
+ explicit_definitions + scope_entry
159
+ end
160
+
161
+ def children
162
+ if singleton_section?(node)
163
+ singleton_body.then { [ it ].compact }
164
+ elsif known_definition_block?
165
+ definition_block_body.then { [ it ].compact }
166
+ else
167
+ []
168
+ end
169
+ end
170
+
171
+ private
172
+ attr_reader :node, :body
173
+
174
+ def explicit_definitions
175
+ method_definitions.filter_map do |definition|
176
+ if owned_definition?(definition) && body.public_definition?(definition)
177
+ Definition.new(definition, definition.method_name)
178
+ end
179
+ end
180
+ end
181
+
182
+ def method_definitions
183
+ if node.any_def_type?
184
+ [ node ]
185
+ elsif node.call_type?
186
+ node.arguments.select(&:any_def_type?)
187
+ else
188
+ []
189
+ end
190
+ end
191
+
192
+ def owned_definition?(definition)
193
+ body.target_definition?(definition) && (!definition.defs_type? || definition.receiver.self_type?)
194
+ end
195
+
196
+ def scope_entry
197
+ call = call_of(node)
198
+
199
+ if body.target_scope? && scope_definition?(call)
200
+ [ Definition.new(call, call.first_argument.value) ]
201
+ else
202
+ []
203
+ end
204
+ end
205
+
206
+ def singleton_body
207
+ body.body_within_singleton_section(node.body)
208
+ end
209
+
210
+ def known_definition_block?
211
+ any_block_type?(node) && call_on_self?(call_of(node)) && DEFINITION_BLOCKS.include?(node.method_name)
212
+ end
213
+
214
+ def definition_block_body
215
+ body.body_within_definition_block(node.body, kind: node.method_name)
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,144 @@
1
+ class RuboCop::Callbacksystems::Methods::DelegateMacro
2
+ include RuboCop::Callbacksystems::Helpers
3
+
4
+ MISSING_DELEGATE_METHODS = %i[ method_missing respond_to_missing? ]
5
+
6
+ def initialize(node)
7
+ @node = node
8
+ end
9
+
10
+ def macro?
11
+ delegate_macro?(node) && !options.nil?
12
+ end
13
+
14
+ def target
15
+ value_of(:to)&.then { name_of(it) }
16
+ end
17
+
18
+ # The methods read on the delegation target, before a prefix changes the methods this macro defines.
19
+ def target_method_names
20
+ literal_method_names if node.method?(:delegate)
21
+ end
22
+
23
+ # Nothing is returned when a dynamic argument or option leaves the names unknowable without executing the file.
24
+ def defined_method_names
25
+ if node.method?(:delegate_missing_to)
26
+ MISSING_DELEGATE_METHODS
27
+ elsif node.method?(:delegate)
28
+ prefixed_method_names
29
+ end
30
+ end
31
+
32
+ def private?
33
+ visibility == :private
34
+ end
35
+
36
+ def plain?(private:)
37
+ visibility == (private ? :private : :public) && inactive_option?(:prefix) && inactive_option?(:allow_nil)
38
+ end
39
+
40
+ def private_option_known?
41
+ options && option_known?(:private)
42
+ end
43
+
44
+ def private_option
45
+ option_for(:private)
46
+ end
47
+
48
+ def first_option
49
+ keyword_options.elements.first || options
50
+ end
51
+
52
+ def last_option
53
+ keyword_options.elements.last || options
54
+ end
55
+
56
+ private
57
+ attr_reader :node
58
+
59
+ def options
60
+ node.last_argument if node.last_argument&.hash_type?
61
+ end
62
+
63
+ def value_of(key)
64
+ option_for(key)&.value
65
+ end
66
+
67
+ def option_for(key)
68
+ keyword_options.option_for(key) if options
69
+ end
70
+
71
+ def keyword_options
72
+ @keyword_options ||= RuboCop::Callbacksystems::Hashes::KeywordOptions.new(options)
73
+ end
74
+
75
+ def name_of(value)
76
+ literal_name_of(value) if value.type?(:sym, :str, :const)
77
+ end
78
+
79
+ def literal_method_names
80
+ method_arguments.filter_map { literal_method_name_of(it) }.then do |names|
81
+ names if names.size == method_arguments.size
82
+ end
83
+ end
84
+
85
+ def method_arguments
86
+ @method_arguments ||= node.arguments.reject { it.equal?(options) }
87
+ end
88
+
89
+ def literal_method_name_of(argument)
90
+ argument.value.to_sym if argument.type?(:sym, :str)
91
+ end
92
+
93
+ def prefixed_method_names
94
+ if target_method_names && option_known?(:prefix)
95
+ prefix = prefix_name
96
+
97
+ if prefix || !prefix_active?
98
+ target_method_names.map { prefix ? :"#{prefix}_#{it}" : it }
99
+ end
100
+ end
101
+ end
102
+
103
+ def option_known?(key)
104
+ options.nil? || keyword_options.known?(key)
105
+ end
106
+
107
+ def prefix_name
108
+ value = value_of(:prefix)
109
+
110
+ if value&.true_type?
111
+ target if target&.match?(/\A[a-z_]/)
112
+ elsif value&.type?(:sym, :str)
113
+ value.value.to_s
114
+ end
115
+ end
116
+
117
+ def prefix_active?
118
+ value = value_of(:prefix)
119
+
120
+ value && !value.falsey_literal?
121
+ end
122
+
123
+ def visibility
124
+ if private_option
125
+ literal_visibility
126
+ elsif options && keyword_options.known?(:private)
127
+ :public
128
+ end
129
+ end
130
+
131
+ def literal_visibility
132
+ if private_option.value.true_type?
133
+ :private
134
+ elsif private_option.value.falsey_literal?
135
+ :public
136
+ end
137
+ end
138
+
139
+ def inactive_option?(key)
140
+ option = option_for(key)
141
+
142
+ option ? option.value.falsey_literal? : options && keyword_options.known?(key)
143
+ end
144
+ end
@@ -0,0 +1,55 @@
1
+ # The receiver of a hand-written delegation, read as the target a `delegate` macro would name. A constant stands for
2
+ # itself (`to: Currency`), a call on self becomes a symbol (`to: :registry`), and a chain of them becomes a dotted
3
+ # string (`to: "config.postgres"`). Anything else in the chain gives up the whole reading.
4
+ class RuboCop::Callbacksystems::Methods::DelegationTarget
5
+ def initialize(receiver)
6
+ @receiver = receiver
7
+ end
8
+
9
+ def delegable?
10
+ constant? || chain_names.any?
11
+ end
12
+
13
+ def source
14
+ constant? ? name : quoted_name
15
+ end
16
+
17
+ def name
18
+ constant? ? receiver.source : chain_names.join(".")
19
+ end
20
+
21
+ def nested?
22
+ chain_names.many?
23
+ end
24
+
25
+ private
26
+ attr_reader :receiver
27
+
28
+ def constant?
29
+ receiver&.const_type? || false
30
+ end
31
+
32
+ def chain_names
33
+ @chain_names ||= names_in(receiver) || []
34
+ end
35
+
36
+ def names_in(node)
37
+ names = []
38
+ current = node
39
+
40
+ while chained_call?(current)
41
+ names << current.method_name
42
+ current = current.receiver
43
+ end
44
+
45
+ names.reverse if current.nil? || current.self_type?
46
+ end
47
+
48
+ def chained_call?(node)
49
+ node&.send_type? && node.arguments.empty?
50
+ end
51
+
52
+ def quoted_name
53
+ nested? ? "\"#{name}\"" : ":#{name}"
54
+ end
55
+ end
@@ -0,0 +1,77 @@
1
+ # The class or module and instance/singleton side where a method definition or receiverless call resolves.
2
+ class RuboCop::Callbacksystems::Methods::Domain
3
+ include RuboCop::Callbacksystems::Helpers
4
+
5
+ def initialize(node)
6
+ @node = node
7
+ end
8
+
9
+ def container
10
+ @container ||= domain_node.each_ancestor.find { method_owner_boundary?(it) }
11
+ end
12
+
13
+ def scope
14
+ singleton? ? :singleton : :instance
15
+ end
16
+
17
+ def singleton?
18
+ singleton_depth.positive?
19
+ end
20
+
21
+ def singleton_depth
22
+ identity.size
23
+ end
24
+
25
+ def identity
26
+ @identity ||= singleton_path.freeze
27
+ end
28
+
29
+ private
30
+ attr_reader :node
31
+
32
+ def domain_node
33
+ method_node || node
34
+ end
35
+
36
+ def method_node
37
+ node.any_def_type? ? node : enclosing_method_of(node)
38
+ end
39
+
40
+ # A block around a definition may establish its receiver only when it runs (`Class.new`, `included`, `class_eval`,
41
+ # and user macros). Treat it as an opaque owner rather than attributing the definition to the named outer class.
42
+ def method_owner_boundary?(candidate)
43
+ candidate.type?(:class, :module) || any_block_type?(candidate)
44
+ end
45
+
46
+ def singleton_path
47
+ lexical_singleton_classes.reverse_each.map { singleton_class_identity(it) }.tap do |path|
48
+ path << explicit_singleton_identity if explicit_singleton?
49
+ end
50
+ end
51
+
52
+ def lexical_singleton_classes
53
+ domain_node.each_ancestor(:sclass, :class, :module).take_while { !it.type?(:class, :module) }.to_a
54
+ end
55
+
56
+ def singleton_class_identity(singleton_class)
57
+ singleton_class.children.first.self_type? ? :self : [ :expression, singleton_class.source_range.begin_pos ]
58
+ end
59
+
60
+ def explicit_singleton?
61
+ if method_node
62
+ method_node.defs_type?
63
+ else
64
+ !container.nil?
65
+ end
66
+ end
67
+
68
+ # A definition on some other object does not belong to the container's class side. Its own body still shares this
69
+ # identity with the receiverless calls it holds, while definitions on unrelated expressions remain separate.
70
+ def explicit_singleton_identity
71
+ if method_node&.defs_type? && !method_node.receiver.self_type?
72
+ [ :expression, method_node.receiver.source_range.begin_pos ]
73
+ else
74
+ :self
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,17 @@
1
+ module RuboCop::Callbacksystems::Methods::ImplicitInvocations
2
+ # These hooks supplement the smaller runtime set shipped by RuboCop 1.89.
3
+ RUNTIME_METHODS = %i[
4
+ coerce instance_variables_to_inspect
5
+ inherited included extended prepended
6
+ append_features extend_object prepend_features
7
+ const_missing const_added
8
+ method_added method_removed method_undefined
9
+ singleton_method_added singleton_method_removed singleton_method_undefined
10
+ ].to_set | RuboCop::Cop::Lint::UnusedPrivateMethod::IMPLICITLY_INVOKED_METHODS
11
+ PROTOCOL_METHODS = %i[
12
+ initialize to_hash to_h to_str to_s to_ary to_a to_proc to_int to_i to_path
13
+ == eql? hash <=> === each call inspect as_json to_json
14
+ deconstruct deconstruct_keys encode_with init_with yaml_initialize
15
+ ].to_set
16
+ METHOD_NAMES = RUNTIME_METHODS | PROTOCOL_METHODS
17
+ end