rubocop 1.19.0 → 1.23.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 (236) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +129 -21
  4. data/lib/rubocop/config.rb +5 -0
  5. data/lib/rubocop/config_loader.rb +5 -3
  6. data/lib/rubocop/config_validator.rb +9 -1
  7. data/lib/rubocop/cop/base.rb +3 -3
  8. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  9. data/lib/rubocop/cop/bundler/gem_filename.rb +103 -0
  10. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +45 -21
  11. data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
  12. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
  13. data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
  14. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +11 -10
  15. data/lib/rubocop/cop/documentation.rb +1 -1
  16. data/lib/rubocop/cop/gemspec/date_assignment.rb +2 -10
  17. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +1 -10
  18. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
  19. data/lib/rubocop/cop/gemspec/require_mfa.rb +146 -0
  20. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +31 -24
  21. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -10
  22. data/lib/rubocop/cop/generator.rb +14 -8
  23. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +60 -0
  24. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  25. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  26. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  27. data/lib/rubocop/cop/layout/assignment_indentation.rb +1 -1
  28. data/lib/rubocop/cop/layout/block_alignment.rb +3 -3
  29. data/lib/rubocop/cop/layout/class_structure.rb +2 -1
  30. data/lib/rubocop/cop/layout/dot_position.rb +34 -5
  31. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  32. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +22 -1
  33. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +7 -4
  34. data/lib/rubocop/cop/layout/end_alignment.rb +2 -3
  35. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
  36. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  37. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  38. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
  39. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  40. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  41. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  42. data/lib/rubocop/cop/layout/line_length.rb +9 -7
  43. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  44. data/lib/rubocop/cop/layout/multiline_block_layout.rb +3 -3
  45. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +3 -0
  46. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  47. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
  48. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +6 -5
  49. data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
  50. data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
  51. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
  52. data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
  53. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
  54. data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
  55. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +11 -5
  56. data/lib/rubocop/cop/layout/space_inside_parens.rb +74 -28
  57. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
  58. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +111 -0
  59. data/lib/rubocop/cop/lint/ambiguous_range.rb +11 -11
  60. data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
  61. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
  62. data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
  63. data/lib/rubocop/cop/lint/debugger.rb +2 -4
  64. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  65. data/lib/rubocop/cop/lint/deprecated_constants.rb +3 -2
  66. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
  67. data/lib/rubocop/cop/lint/else_layout.rb +10 -6
  68. data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
  69. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  70. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  71. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +12 -3
  72. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
  73. data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
  74. data/lib/rubocop/cop/lint/loop.rb +4 -3
  75. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
  76. data/lib/rubocop/cop/lint/number_conversion.rb +16 -2
  77. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  78. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
  79. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
  80. data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
  81. data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
  82. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
  83. data/lib/rubocop/cop/lint/require_relative_self_path.rb +50 -0
  84. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
  85. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  86. data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
  87. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
  88. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
  89. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
  90. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +117 -0
  91. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  92. data/lib/rubocop/cop/lint/useless_times.rb +4 -3
  93. data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
  94. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  95. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  96. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  97. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  98. data/lib/rubocop/cop/mixin/annotation_comment.rb +57 -34
  99. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  100. data/lib/rubocop/cop/mixin/documentation_comment.rb +5 -2
  101. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -2
  102. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +23 -1
  103. data/lib/rubocop/cop/mixin/gemspec_help.rb +30 -0
  104. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  105. data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
  106. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  107. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
  108. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  109. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
  110. data/lib/rubocop/cop/mixin/percent_array.rb +11 -3
  111. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
  112. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  113. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  114. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  115. data/lib/rubocop/cop/mixin/trailing_body.rb +1 -1
  116. data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
  117. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  118. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  119. data/lib/rubocop/cop/naming/file_name.rb +37 -4
  120. data/lib/rubocop/cop/naming/inclusive_language.rb +9 -9
  121. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
  122. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
  123. data/lib/rubocop/cop/security/io_methods.rb +49 -0
  124. data/lib/rubocop/cop/security/json_load.rb +8 -7
  125. data/lib/rubocop/cop/security/open.rb +4 -0
  126. data/lib/rubocop/cop/security/yaml_load.rb +4 -0
  127. data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
  128. data/lib/rubocop/cop/style/and_or.rb +5 -0
  129. data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
  130. data/lib/rubocop/cop/style/array_coercion.rb +21 -3
  131. data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
  132. data/lib/rubocop/cop/style/block_delimiters.rb +23 -6
  133. data/lib/rubocop/cop/style/case_equality.rb +6 -9
  134. data/lib/rubocop/cop/style/case_like_if.rb +5 -0
  135. data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
  136. data/lib/rubocop/cop/style/collection_compact.rb +7 -5
  137. data/lib/rubocop/cop/style/collection_methods.rb +8 -6
  138. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  139. data/lib/rubocop/cop/style/comment_annotation.rb +25 -39
  140. data/lib/rubocop/cop/style/commented_keyword.rb +9 -4
  141. data/lib/rubocop/cop/style/date_time.rb +5 -0
  142. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  143. data/lib/rubocop/cop/style/documentation.rb +23 -8
  144. data/lib/rubocop/cop/style/double_negation.rb +27 -6
  145. data/lib/rubocop/cop/style/empty_method.rb +2 -2
  146. data/lib/rubocop/cop/style/encoding.rb +26 -15
  147. data/lib/rubocop/cop/style/explicit_block_argument.rb +21 -11
  148. data/lib/rubocop/cop/style/float_division.rb +10 -2
  149. data/lib/rubocop/cop/style/format_string_token.rb +2 -1
  150. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +7 -2
  151. data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
  152. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +11 -0
  153. data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
  154. data/lib/rubocop/cop/style/hash_except.rb +4 -3
  155. data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -6
  156. data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
  157. data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -16
  158. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +18 -4
  159. data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
  160. data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
  161. data/lib/rubocop/cop/style/lambda_call.rb +1 -1
  162. data/lib/rubocop/cop/style/line_end_concatenation.rb +14 -1
  163. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
  164. data/lib/rubocop/cop/style/module_function.rb +8 -9
  165. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  166. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
  167. data/lib/rubocop/cop/style/mutable_constant.rb +73 -6
  168. data/lib/rubocop/cop/style/negated_if.rb +1 -1
  169. data/lib/rubocop/cop/style/negated_unless.rb +1 -1
  170. data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
  171. data/lib/rubocop/cop/style/not.rb +2 -2
  172. data/lib/rubocop/cop/style/numbered_parameters.rb +46 -0
  173. data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
  174. data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
  175. data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
  176. data/lib/rubocop/cop/style/open_struct_use.rb +69 -0
  177. data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
  178. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
  179. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  180. data/lib/rubocop/cop/style/parentheses_around_condition.rb +12 -2
  181. data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
  182. data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -4
  183. data/lib/rubocop/cop/style/quoted_symbols.rb +21 -7
  184. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  185. data/lib/rubocop/cop/style/redundant_argument.rb +19 -9
  186. data/lib/rubocop/cop/style/redundant_begin.rb +25 -0
  187. data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
  188. data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
  189. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
  190. data/lib/rubocop/cop/style/redundant_freeze.rb +4 -4
  191. data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
  192. data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
  193. data/lib/rubocop/cop/style/redundant_self.rb +10 -0
  194. data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
  195. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +23 -28
  196. data/lib/rubocop/cop/style/redundant_sort.rb +51 -18
  197. data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
  198. data/lib/rubocop/cop/style/return_nil.rb +2 -1
  199. data/lib/rubocop/cop/style/safe_navigation.rb +13 -2
  200. data/lib/rubocop/cop/style/select_by_regexp.rb +139 -0
  201. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
  202. data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
  203. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -0
  204. data/lib/rubocop/cop/style/special_global_vars.rb +4 -0
  205. data/lib/rubocop/cop/style/static_class.rb +5 -5
  206. data/lib/rubocop/cop/style/string_chars.rb +4 -2
  207. data/lib/rubocop/cop/style/string_concatenation.rb +5 -1
  208. data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
  209. data/lib/rubocop/cop/style/struct_inheritance.rb +4 -0
  210. data/lib/rubocop/cop/style/swap_values.rb +4 -2
  211. data/lib/rubocop/cop/style/symbol_array.rb +3 -3
  212. data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
  213. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
  214. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  215. data/lib/rubocop/cop/style/word_array.rb +3 -3
  216. data/lib/rubocop/cop/style/yoda_condition.rb +24 -7
  217. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
  218. data/lib/rubocop/cop/util.rb +15 -4
  219. data/lib/rubocop/cops_documentation_generator.rb +17 -5
  220. data/lib/rubocop/formatter/html_formatter.rb +5 -2
  221. data/lib/rubocop/formatter/json_formatter.rb +4 -1
  222. data/lib/rubocop/magic_comment.rb +44 -15
  223. data/lib/rubocop/options.rb +126 -112
  224. data/lib/rubocop/rake_task.rb +1 -1
  225. data/lib/rubocop/remote_config.rb +1 -1
  226. data/lib/rubocop/result_cache.rb +3 -3
  227. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  228. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  229. data/lib/rubocop/rspec/parallel_formatter.rb +90 -0
  230. data/lib/rubocop/rspec/support.rb +1 -0
  231. data/lib/rubocop/runner.rb +2 -3
  232. data/lib/rubocop/target_finder.rb +1 -1
  233. data/lib/rubocop/version.rb +1 -1
  234. data/lib/rubocop/yaml_duplication_checker.rb +1 -1
  235. data/lib/rubocop.rb +14 -2
  236. metadata +20 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 184ca6701160d34e5fe8f659e159842f397bfe07edbc27df159b7793fd8a0a3c
4
- data.tar.gz: d891042df8d86850afbf19b0d0e81f4255e909f0775b32eb675b3766d0266561
3
+ metadata.gz: cf11fe2d8f8be8879d6afc63d6f3be50b970c7910c83f1d22847d1fc9654d4aa
4
+ data.tar.gz: fd4c7ef3838a286efe3d1729672cc7a0e72f47cfb4c8d815699d53d2a974a372
5
5
  SHA512:
6
- metadata.gz: 6b0ed04638cfa650324684315fcf4c8a99b93fa66c1dce39efa7c76605bbd78a7c4e4b4d6fc6ac608d2ebbb52604f6f9fbccf23e5d097c637b1b6c879601d70b
7
- data.tar.gz: f1310e4f3a7285ecf642edf6e99500decb0d1aa74b676adf38ee6c65c9f1f4cf3124853102a50da51e896a6b9780b3db9156fa4e075f60139f01d239d13ab898
6
+ metadata.gz: 4014183525b58378a0e628ae5136d17c148a41c6c25dd51eddc810ca08fbd89d652f6c715b58eef149005af1145469936416864869b6e63a4c9e521627ab1cb4
7
+ data.tar.gz: 6e0e2a9a9d6fae829b73bd49814965a28d447207aaf7d1dda073f34130343557df965c77cc998d6ddb0d59eca09f1307d6ca56cbd3fcade575ca52950d1a56d3
data/README.md CHANGED
@@ -54,7 +54,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
54
54
  in your `Gemfile`:
55
55
 
56
56
  ```rb
57
- gem 'rubocop', '~> 1.19', require: false
57
+ gem 'rubocop', '~> 1.23', require: false
58
58
  ```
59
59
 
60
60
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
data/config/default.yml CHANGED
@@ -130,7 +130,7 @@ AllCops:
130
130
  # What MRI version of the Ruby interpreter is the inspected code intended to
131
131
  # run on? (If there is more than one, set this to the lowest version.)
132
132
  # If a value is specified for TargetRubyVersion then it is used. Acceptable
133
- # values are specificed as a float (i.e. 3.0); the teeny version of Ruby
133
+ # values are specified as a float (i.e. 3.0); the teeny version of Ruby
134
134
  # should not be included. If the project specifies a Ruby version in the
135
135
  # .tool-versions or .ruby-version files, Gemfile or gems.rb file, RuboCop will
136
136
  # try to determine the desired version of Ruby by inspecting the
@@ -150,6 +150,7 @@ AllCops:
150
150
  rubocop-minitest: [minitest]
151
151
  rubocop-sequel: [sequel]
152
152
  rubocop-rake: [rake]
153
+ rubocop-graphql: [graphql]
153
154
 
154
155
  #################### Bundler ###############################
155
156
 
@@ -174,6 +175,20 @@ Bundler/GemComment:
174
175
  IgnoredGems: []
175
176
  OnlyFor: []
176
177
 
178
+ Bundler/GemFilename:
179
+ Description: 'Enforces the filename for managing gems.'
180
+ Enabled: true
181
+ VersionAdded: '1.20'
182
+ EnforcedStyle: 'Gemfile'
183
+ SupportedStyles:
184
+ - 'Gemfile'
185
+ - 'gems.rb'
186
+ Include:
187
+ - '**/Gemfile'
188
+ - '**/gems.rb'
189
+ - '**/Gemfile.lock'
190
+ - '**/gems.locked'
191
+
177
192
  Bundler/GemVersion:
178
193
  Description: 'Requires or forbids specifying gem versions.'
179
194
  Enabled: false
@@ -195,6 +210,7 @@ Bundler/InsecureProtocolSource:
195
210
  'https://rubygems.org' if possible, or 'http://rubygems.org' if not.
196
211
  Enabled: true
197
212
  VersionAdded: '0.50'
213
+ AllowHttpProtocol: true
198
214
  Include:
199
215
  - '**/*.gemfile'
200
216
  - '**/Gemfile'
@@ -243,11 +259,20 @@ Gemspec/OrderedDependencies:
243
259
  Include:
244
260
  - '**/*.gemspec'
245
261
 
262
+ Gemspec/RequireMFA:
263
+ Description: 'Checks that the gemspec has metadata to require MFA from RubyGems.'
264
+ Enabled: pending
265
+ VersionAdded: '1.23'
266
+ Reference:
267
+ - https://guides.rubygems.org/mfa-requirement-opt-in/
268
+ Include:
269
+ - '**/*.gemspec'
270
+
246
271
  Gemspec/RequiredRubyVersion:
247
272
  Description: 'Checks that `required_ruby_version` of gemspec is specified and equal to `TargetRubyVersion` of .rubocop.yml.'
248
273
  Enabled: true
249
274
  VersionAdded: '0.52'
250
- VersionChanged: '0.89'
275
+ VersionChanged: '1.22'
251
276
  Include:
252
277
  - '**/*.gemspec'
253
278
 
@@ -496,13 +521,13 @@ Layout/EmptyLineBetweenDefs:
496
521
  StyleGuide: '#empty-lines-between-methods'
497
522
  Enabled: true
498
523
  VersionAdded: '0.49'
499
- VersionChanged: '1.7'
524
+ VersionChanged: '1.23'
500
525
  EmptyLineBetweenMethodDefs: true
501
526
  EmptyLineBetweenClassDefs: true
502
527
  EmptyLineBetweenModuleDefs: true
503
- # If `true`, this parameter means that single line method definitions don't
504
- # need an empty line between them.
505
- AllowAdjacentOneLineDefs: false
528
+ # `AllowAdjacentOneLineDefs` means that single line method definitions don't
529
+ # need an empty line between them. `true` by default.
530
+ AllowAdjacentOneLineDefs: true
506
531
  # Can be array to specify minimum and maximum number of empty lines, e.g. [1, 2]
507
532
  NumberOfEmptyLines: 1
508
533
 
@@ -943,7 +968,6 @@ Layout/LineLength:
943
968
  Enabled: true
944
969
  VersionAdded: '0.25'
945
970
  VersionChanged: '1.4'
946
- AutoCorrect: true
947
971
  Max: 120
948
972
  # To make it possible to copy or click on URIs in the code, we allow lines
949
973
  # containing a URI to be longer than Max.
@@ -1347,10 +1371,11 @@ Layout/SpaceInsideParens:
1347
1371
  StyleGuide: '#spaces-braces'
1348
1372
  Enabled: true
1349
1373
  VersionAdded: '0.49'
1350
- VersionChanged: '0.55'
1374
+ VersionChanged: '1.22'
1351
1375
  EnforcedStyle: no_space
1352
1376
  SupportedStyles:
1353
1377
  - space
1378
+ - compact
1354
1379
  - no_space
1355
1380
 
1356
1381
  Layout/SpaceInsidePercentLiteralDelimiters:
@@ -1434,6 +1459,13 @@ Lint/AmbiguousOperator:
1434
1459
  VersionAdded: '0.17'
1435
1460
  VersionChanged: '0.83'
1436
1461
 
1462
+ Lint/AmbiguousOperatorPrecedence:
1463
+ Description: >-
1464
+ Checks for expressions containing multiple binary operations with
1465
+ ambiguous precedence.
1466
+ Enabled: pending
1467
+ VersionAdded: '1.21'
1468
+
1437
1469
  Lint/AmbiguousRange:
1438
1470
  Description: Checks for ranges with ambiguous boundaries.
1439
1471
  Enabled: pending
@@ -1471,9 +1503,9 @@ Lint/BinaryOperatorWithIdenticalOperands:
1471
1503
  Lint/BooleanSymbol:
1472
1504
  Description: 'Check for `:true` and `:false` symbols.'
1473
1505
  Enabled: true
1474
- Safe: false
1506
+ SafeAutoCorrect: false
1475
1507
  VersionAdded: '0.50'
1476
- VersionChanged: '0.83'
1508
+ VersionChanged: '1.22'
1477
1509
 
1478
1510
  Lint/CircularArgumentReference:
1479
1511
  Description: "Default values in optional keyword arguments and optional ordinal arguments should not refer back to the name of the argument."
@@ -1519,6 +1551,11 @@ Lint/Debugger:
1519
1551
  Capybara:
1520
1552
  - save_and_open_page
1521
1553
  - save_and_open_screenshot
1554
+ debug.rb:
1555
+ - binding.b
1556
+ - binding.break
1557
+ - Kernel.binding.b
1558
+ - Kernel.binding.break
1522
1559
  Pry:
1523
1560
  - binding.pry
1524
1561
  - binding.remote_pry
@@ -1527,6 +1564,8 @@ Lint/Debugger:
1527
1564
  Rails:
1528
1565
  - debugger
1529
1566
  - Kernel.debugger
1567
+ RubyJard:
1568
+ - jard
1530
1569
  WebConsole:
1531
1570
  - binding.console
1532
1571
 
@@ -1539,6 +1578,7 @@ Lint/DeprecatedConstants:
1539
1578
  Description: 'Checks for deprecated constants.'
1540
1579
  Enabled: pending
1541
1580
  VersionAdded: '1.8'
1581
+ VersionChanged: '1.22'
1542
1582
  # You can configure deprecated constants.
1543
1583
  # If there is an alternative method, you can set alternative value as `Alternative`.
1544
1584
  # And you can set the deprecated version as `DeprecatedVersion`.
@@ -1559,6 +1599,9 @@ Lint/DeprecatedConstants:
1559
1599
  'FALSE':
1560
1600
  Alternative: 'false'
1561
1601
  DeprecatedVersion: '2.4'
1602
+ 'Net::HTTPServerException':
1603
+ Alternative: 'Net::HTTPClientException'
1604
+ DeprecatedVersion: '2.6'
1562
1605
  'Random::DEFAULT':
1563
1606
  Alternative: 'Random.new'
1564
1607
  DeprecatedVersion: '3.0'
@@ -1750,6 +1793,11 @@ Lint/ImplicitStringConcatenation:
1750
1793
  Enabled: true
1751
1794
  VersionAdded: '0.36'
1752
1795
 
1796
+ Lint/IncompatibleIoSelectWithFiberScheduler:
1797
+ Description: 'Checks for `IO.select` that is incompatible with Fiber Scheduler.'
1798
+ Enabled: pending
1799
+ VersionAdded: '1.21'
1800
+
1753
1801
  Lint/IneffectiveAccessModifier:
1754
1802
  Description: >-
1755
1803
  Checks for attempts to use `private` or `protected` to set
@@ -2013,6 +2061,11 @@ Lint/RequireParentheses:
2013
2061
  Enabled: true
2014
2062
  VersionAdded: '0.18'
2015
2063
 
2064
+ Lint/RequireRelativeSelfPath:
2065
+ Description: 'Checks for uses a file requiring itself with `require_relative`.'
2066
+ Enabled: pending
2067
+ VersionAdded: '1.22'
2068
+
2016
2069
  Lint/RescueException:
2017
2070
  Description: 'Avoid rescuing the Exception class.'
2018
2071
  StyleGuide: '#no-blind-rescues'
@@ -2265,6 +2318,11 @@ Lint/UselessMethodDefinition:
2265
2318
  Safe: false
2266
2319
  AllowComments: true
2267
2320
 
2321
+ Lint/UselessRuby2Keywords:
2322
+ Description: 'Finds unnecessary uses of `ruby2_keywords`.'
2323
+ Enabled: pending
2324
+ VersionAdded: '1.23'
2325
+
2268
2326
  Lint/UselessSetterCall:
2269
2327
  Description: 'Checks for useless setter call to a local variable.'
2270
2328
  Enabled: true
@@ -2458,6 +2516,7 @@ Naming/FileName:
2458
2516
  StyleGuide: '#snake-case-files'
2459
2517
  Enabled: true
2460
2518
  VersionAdded: '0.50'
2519
+ VersionChanged: '1.23'
2461
2520
  # Camel case file names listed in `AllCops:Include` and all file names listed
2462
2521
  # in `AllCops:Exclude` are excluded by default. Add extra excludes here.
2463
2522
  Exclude: []
@@ -2470,6 +2529,13 @@ Naming/FileName:
2470
2529
  # whether each source file's class or module name matches the file name --
2471
2530
  # not whether the nested module hierarchy matches the subdirectory path.
2472
2531
  CheckDefinitionPathHierarchy: true
2532
+ # paths that are considered root directories, for example "lib" in most ruby projects
2533
+ # or "app/models" in rails projects
2534
+ CheckDefinitionPathHierarchyRoots:
2535
+ - lib
2536
+ - spec
2537
+ - test
2538
+ - src
2473
2539
  # If non-`nil`, expect all source file names to match the following regex.
2474
2540
  # Only the file name itself is matched, not the entire file path.
2475
2541
  # Use anchors as necessary if you want to match the entire name rather than
@@ -2542,8 +2608,9 @@ Naming/HeredocDelimiterNaming:
2542
2608
 
2543
2609
  Naming/InclusiveLanguage:
2544
2610
  Description: 'Recommend the use of inclusive language instead of problematic terms.'
2545
- Enabled: pending
2611
+ Enabled: false
2546
2612
  VersionAdded: '1.18'
2613
+ VersionChanged: '1.21'
2547
2614
  CheckIdentifiers: true
2548
2615
  CheckConstants: true
2549
2616
  CheckVariables: true
@@ -2699,6 +2766,14 @@ Security/Eval:
2699
2766
  Enabled: true
2700
2767
  VersionAdded: '0.47'
2701
2768
 
2769
+ Security/IoMethods:
2770
+ Description: >-
2771
+ Checks for the first argument to `IO.read`, `IO.binread`, `IO.write`, `IO.binwrite`,
2772
+ `IO.foreach`, and `IO.readlines`.
2773
+ Enabled: pending
2774
+ Safe: false
2775
+ VersionAdded: '1.22'
2776
+
2702
2777
  Security/JSONLoad:
2703
2778
  Description: >-
2704
2779
  Prefer usage of `JSON.parse` over `JSON.load` due to potential
@@ -2706,10 +2781,9 @@ Security/JSONLoad:
2706
2781
  Reference: 'https://ruby-doc.org/stdlib-2.7.0/libdoc/json/rdoc/JSON.html#method-i-load'
2707
2782
  Enabled: true
2708
2783
  VersionAdded: '0.43'
2709
- VersionChanged: '0.44'
2784
+ VersionChanged: '1.22'
2710
2785
  # Autocorrect here will change to a method that may cause crashes depending
2711
2786
  # on the value of the argument.
2712
- AutoCorrect: false
2713
2787
  SafeAutoCorrect: false
2714
2788
 
2715
2789
  Security/MarshalLoad:
@@ -2775,8 +2849,9 @@ Style/AndOr:
2775
2849
  Description: 'Use &&/|| instead of and/or.'
2776
2850
  StyleGuide: '#no-and-or-or'
2777
2851
  Enabled: true
2852
+ SafeAutoCorrect: false
2778
2853
  VersionAdded: '0.9'
2779
- VersionChanged: '0.25'
2854
+ VersionChanged: '1.21'
2780
2855
  # Whether `and` and `or` are banned only in conditionals (conditionals)
2781
2856
  # or completely (always).
2782
2857
  EnforcedStyle: conditionals
@@ -2810,9 +2885,9 @@ Style/ArrayJoin:
2810
2885
  Style/AsciiComments:
2811
2886
  Description: 'Use only ascii symbols in comments.'
2812
2887
  StyleGuide: '#english-comments'
2813
- Enabled: true
2888
+ Enabled: false
2814
2889
  VersionAdded: '0.9'
2815
- VersionChanged: '0.52'
2890
+ VersionChanged: '1.21'
2816
2891
  AllowedChars:
2817
2892
  - ©
2818
2893
 
@@ -2974,7 +3049,7 @@ Style/CaseEquality:
2974
3049
  Enabled: true
2975
3050
  VersionAdded: '0.9'
2976
3051
  VersionChanged: '0.89'
2977
- # If AllowOnConstant is enabled, the cop will ignore violations when the receiver of
3052
+ # If `AllowOnConstant` option is enabled, the cop will ignore violations when the receiver of
2978
3053
  # the case equality operator is a constant.
2979
3054
  #
2980
3055
  # # bad
@@ -3149,7 +3224,7 @@ Style/CommentAnnotation:
3149
3224
  StyleGuide: '#annotate-keywords'
3150
3225
  Enabled: true
3151
3226
  VersionAdded: '0.10'
3152
- VersionChanged: '1.3'
3227
+ VersionChanged: '1.20'
3153
3228
  Keywords:
3154
3229
  - TODO
3155
3230
  - FIXME
@@ -3669,7 +3744,7 @@ Style/InPatternThen:
3669
3744
  Style/InfiniteLoop:
3670
3745
  Description: >-
3671
3746
  Use Kernel#loop for infinite loops.
3672
- This cop is unsafe in the body may raise a `StopIteration` exception.
3747
+ This cop is unsafe if the body may raise a `StopIteration` exception.
3673
3748
  Safe: false
3674
3749
  StyleGuide: '#infinite-loop'
3675
3750
  Enabled: true
@@ -4095,6 +4170,21 @@ Style/Not:
4095
4170
  VersionAdded: '0.9'
4096
4171
  VersionChanged: '0.20'
4097
4172
 
4173
+ Style/NumberedParameters:
4174
+ Description: 'Restrict the usage of numbered parameters.'
4175
+ Enabled: pending
4176
+ VersionAdded: '1.22'
4177
+ EnforcedStyle: allow_single_line
4178
+ SupportedStyles:
4179
+ - allow_single_line
4180
+ - disallow
4181
+
4182
+ Style/NumberedParametersLimit:
4183
+ Description: 'Avoid excessive numbered params in a single block.'
4184
+ Enabled: pending
4185
+ VersionAdded: '1.22'
4186
+ Max: 1
4187
+
4098
4188
  Style/NumericLiteralPrefix:
4099
4189
  Description: 'Use smallcase prefixes for numeric literals.'
4100
4190
  StyleGuide: '#numeric-literal-prefixes'
@@ -4105,7 +4195,6 @@ Style/NumericLiteralPrefix:
4105
4195
  - zero_with_o
4106
4196
  - zero_only
4107
4197
 
4108
-
4109
4198
  Style/NumericLiterals:
4110
4199
  Description: >-
4111
4200
  Add underscores to large numeric literals to improve their
@@ -4150,6 +4239,16 @@ Style/OneLineConditional:
4150
4239
  VersionAdded: '0.9'
4151
4240
  VersionChanged: '0.90'
4152
4241
 
4242
+ Style/OpenStructUse:
4243
+ Description: >-
4244
+ Avoid using OpenStruct. As of Ruby 3.0, use is officially discouraged due to performance,
4245
+ version compatibility, and potential security issues.
4246
+ Reference:
4247
+ - https://docs.ruby-lang.org/en/3.0.0/OpenStruct.html#class-OpenStruct-label-Caveats
4248
+
4249
+ Enabled: pending
4250
+ VersionAdded: '1.23'
4251
+
4153
4252
  Style/OptionHash:
4154
4253
  Description: "Don't use option hashes when you can use keyword arguments."
4155
4254
  Enabled: false
@@ -4426,6 +4525,8 @@ Style/RedundantSort:
4426
4525
  `max_by` instead of `sort_by...last`, etc.
4427
4526
  Enabled: true
4428
4527
  VersionAdded: '0.76'
4528
+ VersionChanged: '1.22'
4529
+ Safe: false
4429
4530
 
4430
4531
  Style/RedundantSortBy:
4431
4532
  Description: 'Use `sort` instead of `sort_by { |x| x }`.'
@@ -4506,6 +4607,12 @@ Style/Sample:
4506
4607
  Enabled: true
4507
4608
  VersionAdded: '0.30'
4508
4609
 
4610
+ Style/SelectByRegexp:
4611
+ Description: 'Prefer grep/grep_v to select/reject with a regexp match.'
4612
+ Enabled: pending
4613
+ SafeAutoCorrect: false
4614
+ VersionAdded: '1.22'
4615
+
4509
4616
  Style/SelfAssignment:
4510
4617
  Description: >-
4511
4618
  Checks for places where self-assignment shorthand should have
@@ -4692,8 +4799,9 @@ Style/StructInheritance:
4692
4799
  Description: 'Checks for inheritance from Struct.new.'
4693
4800
  StyleGuide: '#no-extend-struct-new'
4694
4801
  Enabled: true
4802
+ SafeAutoCorrect: false
4695
4803
  VersionAdded: '0.29'
4696
- VersionChanged: '0.86'
4804
+ VersionChanged: '1.20'
4697
4805
 
4698
4806
  Style/SwapValues:
4699
4807
  Description: 'This cop enforces the use of shorthand-style swapping of 2 variables.'
@@ -51,6 +51,11 @@ module RuboCop
51
51
  self
52
52
  end
53
53
 
54
+ def validate_after_resolution
55
+ @validator.validate_after_resolution
56
+ self
57
+ end
58
+
54
59
  def_delegators :@hash, :[], :[]=, :delete, :dig, :each, :key?, :keys, :each_key,
55
60
  :fetch, :map, :merge, :replace, :to_h, :to_hash, :transform_values
56
61
  def_delegators :@validator, :validate, :target_ruby_version
@@ -101,6 +101,8 @@ module RuboCop
101
101
  return default_configuration if config_file == DEFAULT_FILE
102
102
 
103
103
  config = load_file(config_file, check: check)
104
+ config.validate_after_resolution if check
105
+
104
106
  if ignore_parent_exclusion?
105
107
  print 'Ignoring AllCops/Exclude from parent folders' if debug?
106
108
  else
@@ -134,7 +136,7 @@ module RuboCop
134
136
  end
135
137
  end
136
138
 
137
- # Returns the path rubocop inferred as the root of the project. No file
139
+ # Returns the path RuboCop inferred as the root of the project. No file
138
140
  # searches will go past this directory.
139
141
  def project_root
140
142
  @project_root ||= find_project_root
@@ -143,7 +145,7 @@ module RuboCop
143
145
  PENDING_BANNER = <<~BANNER
144
146
  The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file.
145
147
 
146
- Please also note that can also opt-in to new cops by default by adding this to your config:
148
+ Please also note that you can opt-in to new cops by default by adding this to your config:
147
149
  AllCops:
148
150
  NewCops: enable
149
151
  BANNER
@@ -161,7 +163,7 @@ module RuboCop
161
163
  def warn_pending_cop(cop)
162
164
  version = cop.metadata['VersionAdded'] || 'N/A'
163
165
 
164
- warn Rainbow("#{cop.name}: # (new in #{version})").yellow
166
+ warn Rainbow("#{cop.name}: # new in #{version}").yellow
165
167
  warn Rainbow(' Enabled: true').yellow
166
168
  end
167
169
 
@@ -44,7 +44,6 @@ module RuboCop
44
44
  check_obsoletions
45
45
 
46
46
  alert_about_unrecognized_cops(invalid_cop_names)
47
- check_target_ruby
48
47
  validate_new_cops_parameter
49
48
  validate_parameter_names(valid_cop_names)
50
49
  validate_enforced_styles(valid_cop_names)
@@ -52,6 +51,15 @@ module RuboCop
52
51
  reject_mutually_exclusive_defaults
53
52
  end
54
53
 
54
+ # Validations that should only be run after all config resolving has
55
+ # taken place:
56
+ # * The target ruby version is only checked once the entire inheritance
57
+ # chain has been loaded so that only the final value is validated, and
58
+ # any obsolete but overridden values are ignored.
59
+ def validate_after_resolution
60
+ check_target_ruby
61
+ end
62
+
55
63
  def target_ruby_version
56
64
  target_ruby.version
57
65
  end
@@ -24,7 +24,7 @@ module RuboCop
24
24
  # `add_global_offense`. Use the `processed_source` method to
25
25
  # get the currently processed source being investigated.
26
26
  #
27
- # In case of invalid syntax / unparseable content,
27
+ # In case of invalid syntax / unparsable content,
28
28
  # the callback `on_other_file` is called instead of all the other
29
29
  # `on_...` callbacks.
30
30
  #
@@ -222,8 +222,8 @@ module RuboCop
222
222
 
223
223
  def relevant_file?(file)
224
224
  file == RuboCop::AST::ProcessedSource::STRING_SOURCE_NAME ||
225
- file_name_matches_any?(file, 'Include', true) &&
226
- !file_name_matches_any?(file, 'Exclude', false)
225
+ (file_name_matches_any?(file, 'Include', true) &&
226
+ !file_name_matches_any?(file, 'Exclude', false))
227
227
  end
228
228
 
229
229
  def excluded_file?(file)
@@ -88,7 +88,7 @@ module RuboCop
88
88
  CHECKED_OPTIONS_CONFIG = 'OnlyFor'
89
89
  VERSION_SPECIFIERS_OPTION = 'version_specifiers'
90
90
  RESTRICTIVE_VERSION_SPECIFIERS_OPTION = 'restrictive_version_specifiers'
91
- RESTRICTIVE_VERSION_PATTERN = /<|~>/.freeze
91
+ RESTRICTIVE_VERSION_PATTERN = /\A\s*(?:<|~>|\d|=)/.freeze
92
92
  RESTRICT_ON_SEND = %i[gem].freeze
93
93
 
94
94
  def on_send(node)
@@ -152,8 +152,8 @@ module RuboCop
152
152
  def restrictive_version_specified_gem?(node)
153
153
  return unless version_specified_gem?(node)
154
154
 
155
- node.arguments
156
- .any? { |arg| arg&.str_type? && RESTRICTIVE_VERSION_PATTERN.match?(arg.to_s) }
155
+ node.arguments[1..-1]
156
+ .any? { |arg| arg&.str_type? && RESTRICTIVE_VERSION_PATTERN.match?(arg.value) }
157
157
  end
158
158
 
159
159
  def contains_checked_options?(node)
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Bundler
6
+ # This cop verifies that a project contains Gemfile or gems.rb file and correct
7
+ # associated lock file based on the configuration.
8
+ #
9
+ # @example EnforcedStyle: Gemfile (default)
10
+ # # bad
11
+ # Project contains gems.rb and gems.locked files
12
+ #
13
+ # # bad
14
+ # Project contains Gemfile and gems.locked file
15
+ #
16
+ # # good
17
+ # Project contains Gemfile and Gemfile.lock
18
+ #
19
+ # @example EnforcedStyle: gems.rb
20
+ # # bad
21
+ # Project contains Gemfile and Gemfile.lock files
22
+ #
23
+ # # bad
24
+ # Project contains gems.rb and Gemfile.lock file
25
+ #
26
+ # # good
27
+ # Project contains gems.rb and gems.locked files
28
+ class GemFilename < Base
29
+ include ConfigurableEnforcedStyle
30
+ include RangeHelp
31
+
32
+ MSG_GEMFILE_REQUIRED = '`gems.rb` file was found but `Gemfile` is required '\
33
+ '(file path: %<file_path>s).'
34
+ MSG_GEMS_RB_REQUIRED = '`Gemfile` was found but `gems.rb` file is required '\
35
+ '(file path: %<file_path>s).'
36
+ MSG_GEMFILE_MISMATCHED = 'Expected a `Gemfile.lock` with `Gemfile` but found '\
37
+ '`gems.locked` file (file path: %<file_path>s).'
38
+ MSG_GEMS_RB_MISMATCHED = 'Expected a `gems.locked` file with `gems.rb` but found '\
39
+ '`Gemfile.lock` (file path: %<file_path>s).'
40
+ GEMFILE_FILES = %w[Gemfile Gemfile.lock].freeze
41
+ GEMS_RB_FILES = %w[gems.rb gems.locked].freeze
42
+
43
+ def on_new_investigation
44
+ file_path = processed_source.file_path
45
+ basename = File.basename(file_path)
46
+ return if expected_gemfile?(basename)
47
+
48
+ register_offense(file_path, basename)
49
+ end
50
+
51
+ private
52
+
53
+ def register_offense(file_path, basename)
54
+ register_gemfile_offense(file_path, basename) if gemfile_offense?(basename)
55
+ register_gems_rb_offense(file_path, basename) if gems_rb_offense?(basename)
56
+ end
57
+
58
+ def register_gemfile_offense(file_path, basename)
59
+ message = case basename
60
+ when 'gems.rb'
61
+ MSG_GEMFILE_REQUIRED
62
+ when 'gems.locked'
63
+ MSG_GEMFILE_MISMATCHED
64
+ end
65
+
66
+ add_global_offense(format(message, file_path: file_path))
67
+ end
68
+
69
+ def register_gems_rb_offense(file_path, basename)
70
+ message = case basename
71
+ when 'Gemfile'
72
+ MSG_GEMS_RB_REQUIRED
73
+ when 'Gemfile.lock'
74
+ MSG_GEMS_RB_MISMATCHED
75
+ end
76
+
77
+ add_global_offense(format(message, file_path: file_path))
78
+ end
79
+
80
+ def gemfile_offense?(basename)
81
+ gemfile_required? && GEMS_RB_FILES.include?(basename)
82
+ end
83
+
84
+ def gems_rb_offense?(basename)
85
+ gems_rb_required? && GEMFILE_FILES.include?(basename)
86
+ end
87
+
88
+ def expected_gemfile?(basename)
89
+ (gemfile_required? && GEMFILE_FILES.include?(basename)) ||
90
+ (gems_rb_required? && GEMS_RB_FILES.include?(basename))
91
+ end
92
+
93
+ def gemfile_required?
94
+ style == :Gemfile
95
+ end
96
+
97
+ def gems_rb_required?
98
+ style == :'gems.rb'
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end