From b245b46e0375aeadb80ebedce2db377d6eea5bc0 Mon Sep 17 00:00:00 2001 From: Brian Hawley Date: Mon, 31 Jul 2023 08:25:15 -0700 Subject: [PATCH] Update rubocop to 1.56.1 and ruby to 3.2.2 Ruby 2 is EOL, and can have trouble installnig on modern systems. - Updated ruby in .ruby-version and Dockerfile. - No need to install an old version of bundler in Dockerfile. - Removed the standard gem (see #357). - General bundle update. - Updated docs. --- .ruby-version | 2 +- Dockerfile | 5 +- Gemfile | 3 +- Gemfile.lock | 68 ++++++++----------- config/contents/bundler/duplicated_gem.md | 1 + config/contents/bundler/duplicated_group.md | 51 ++++++++++++++ config/contents/bundler/ordered_gems.md | 10 ++- .../contents/gemspec/ordered_dependencies.md | 10 ++- config/contents/layout/class_structure.md | 8 +++ .../layout/closing_heredoc_indentation.md | 1 - .../space_around_method_call_operator.md | 4 +- config/contents/lint/duplicate_hash_key.md | 1 + config/contents/lint/erb_new_arguments.md | 7 +- config/contents/lint/identity_comparison.md | 1 - ...mpatible_io_select_with_fiber_scheduler.md | 4 +- .../lint/lambda_without_literal_block.md | 2 +- config/contents/lint/missing_super.md | 25 +++++++ config/contents/lint/mixed_case_range.md | 23 +++++++ .../lint/numbered_parameter_assignment.md | 4 +- .../contents/lint/ordered_magic_comments.md | 1 - .../lint/redundant_regexp_quantifiers.md | 27 ++++++++ .../contents/lint/send_with_mixin_argument.md | 3 +- .../lint/top_level_return_with_argument.md | 6 +- config/contents/lint/useless_assignment.md | 7 ++ .../naming/memoized_instance_variable_name.md | 3 +- config/contents/naming/variable_name.md | 8 ++- config/contents/style/arguments_forwarding.md | 30 +++++++- config/contents/style/begin_block.md | 3 +- .../style/class_equality_comparison.md | 56 +++++---------- config/contents/style/collection_compact.md | 10 ++- config/contents/style/colon_method_call.md | 4 +- config/contents/style/copyright.md | 6 +- config/contents/style/dir.md | 2 +- config/contents/style/documentation.md | 2 +- config/contents/style/eval_with_location.md | 6 +- config/contents/style/exact_regexp_match.md | 18 +++++ config/contents/style/hash_conversion.md | 10 +++ config/contents/style/hash_transform_keys.md | 4 +- .../contents/style/hash_transform_values.md | 4 +- .../style/invertible_unless_condition.md | 13 ++-- config/contents/style/multiple_comparison.md | 10 ++- config/contents/style/redundant_argument.md | 4 ++ .../style/redundant_array_constructor.md | 18 +++++ .../redundant_current_directory_in_path.md | 9 +++ .../contents/style/redundant_filter_chain.md | 31 +++++++++ .../style/redundant_regexp_argument.md | 29 ++++++++ .../style/redundant_regexp_constructor.md | 13 ++++ config/contents/style/redundant_return.md | 7 +- config/contents/style/regexp_literal.md | 10 ++- config/contents/style/rescue_modifier.md | 4 +- ...turn_nil_in_predicate_method_definition.md | 44 ++++++++++++ config/contents/style/special_global_vars.md | 3 +- .../style/string_literals_in_interpolation.md | 30 ++++++-- config/contents/style/symbol_array.md | 9 +++ config/contents/style/yaml_file_read.md | 20 ++++++ 55 files changed, 552 insertions(+), 142 deletions(-) create mode 100644 config/contents/bundler/duplicated_group.md create mode 100644 config/contents/lint/mixed_case_range.md create mode 100644 config/contents/lint/redundant_regexp_quantifiers.md create mode 100644 config/contents/style/exact_regexp_match.md create mode 100644 config/contents/style/redundant_array_constructor.md create mode 100644 config/contents/style/redundant_current_directory_in_path.md create mode 100644 config/contents/style/redundant_filter_chain.md create mode 100644 config/contents/style/redundant_regexp_argument.md create mode 100644 config/contents/style/redundant_regexp_constructor.md create mode 100644 config/contents/style/return_nil_in_predicate_method_definition.md create mode 100644 config/contents/style/yaml_file_read.md diff --git a/.ruby-version b/.ruby-version index 49cdd668..be94e6f5 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.6 +3.2.2 diff --git a/Dockerfile b/Dockerfile index dbeeca17..31a95678 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ -FROM ruby:2.7-alpine3.11 +FROM ruby:3.2-alpine3.18 -LABEL name="Ruby-2.7" \ +LABEL name="Ruby-3.2" \ version="1.0" WORKDIR /usr/src/app @@ -10,7 +10,6 @@ RUN adduser -u 9000 -D app COPY Gemfile Gemfile.lock /usr/src/app/ RUN apk add --update build-base git && \ - gem install bundler -v 2.0.2 && \ bundle install --quiet -j 4 && \ chown -R app:app /usr/local/bundle && \ rm -fr ~/.gem ~/.bundle ~/.wh..gem && \ diff --git a/Gemfile b/Gemfile index 79f0f97c..28fa8e6a 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,7 @@ source 'https://rubygems.org' gem "activesupport", require: false gem "parser" gem "pry", require: false -gem "rubocop", "1.50.2", require: false +gem "rubocop", "1.56.1", require: false gem "rubocop-i18n", require: false gem "rubocop-graphql", require: false gem "rubocop-minitest", require: false @@ -17,7 +17,6 @@ gem "rubocop-sequel", require: false gem "rubocop-shopify", require: false gem "rubocop-sorbet", require: false gem "rubocop-thread_safety", require: false -gem "standard", ">= 1.0", require: false gem "test-prof", require: false group :test do diff --git a/Gemfile.lock b/Gemfile.lock index ba560207..a1c9b4da 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,33 +1,35 @@ GEM remote: https://rubygems.org/ specs: - activesupport (7.0.4.3) + activesupport (7.0.7.2) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) ast (2.4.2) + base64 (0.1.1) coderay (1.1.3) concurrent-ruby (1.2.2) diff-lcs (1.5.0) - i18n (1.13.0) + i18n (1.14.1) concurrent-ruby (~> 1.0) json (2.6.3) language_server-protocol (3.17.0.3) - lint_roller (1.0.0) method_source (1.0.0) - minitest (5.18.0) + minitest (5.19.0) parallel (1.23.0) - parser (3.2.2.1) + parser (3.2.2.3) ast (~> 2.4.1) + racc pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) - rack (3.0.7) + racc (1.7.1) + rack (3.0.8) rainbow (3.1.1) rake (13.0.6) - regexp_parser (2.8.0) - rexml (3.2.5) + regexp_parser (2.8.1) + rexml (3.2.6) rspec (3.12.0) rspec-core (~> 3.12.0) rspec-expectations (~> 3.12.0) @@ -37,66 +39,57 @@ GEM rspec-expectations (3.12.3) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) - rspec-mocks (3.12.5) + rspec-mocks (3.12.6) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) - rspec-support (3.12.0) - rubocop (1.50.2) + rspec-support (3.12.1) + rubocop (1.56.1) + base64 (~> 0.1.1) json (~> 2.3) + language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.2.0.0) + parser (>= 3.2.2.3) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.28.0, < 2.0) + rubocop-ast (>= 1.28.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.28.1) + rubocop-ast (1.29.0) parser (>= 3.2.1.0) rubocop-capybara (2.18.0) rubocop (~> 1.41) - rubocop-factory_bot (2.22.0) + rubocop-factory_bot (2.23.1) rubocop (~> 1.33) - rubocop-graphql (1.1.1) - rubocop (>= 0.87, < 2) + rubocop-graphql (1.4.0) + rubocop (>= 0.90, < 2) rubocop-i18n (3.0.0) rubocop (~> 1.0) rubocop-minitest (0.31.0) rubocop (>= 1.39, < 2.0) - rubocop-performance (1.16.0) + rubocop-performance (1.19.0) rubocop (>= 1.7.0, < 2.0) rubocop-ast (>= 0.4.0) - rubocop-rails (2.19.1) + rubocop-rails (2.20.2) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) rubocop-rake (0.6.0) rubocop (~> 1.0) - rubocop-rspec (2.22.0) + rubocop-rspec (2.23.2) rubocop (~> 1.33) rubocop-capybara (~> 2.17) rubocop-factory_bot (~> 2.22) rubocop-sequel (0.3.4) rubocop (~> 1.0) - rubocop-shopify (2.13.0) - rubocop (~> 1.50) - rubocop-sorbet (0.7.0) + rubocop-shopify (2.14.0) + rubocop (~> 1.51) + rubocop-sorbet (0.7.3) rubocop (>= 0.90.0) rubocop-thread_safety (0.5.1) rubocop (>= 0.90.0) ruby-progressbar (1.13.0) - standard (1.28.2) - language_server-protocol (~> 3.17.0.2) - lint_roller (~> 1.0) - rubocop (~> 1.50.2) - standard-custom (~> 1.0.0) - standard-performance (~> 1.0.1) - standard-custom (1.0.0) - lint_roller (~> 1.0) - standard-performance (1.0.1) - lint_roller (~> 1.0) - rubocop-performance (~> 1.16.0) - test-prof (1.2.1) + test-prof (1.2.2) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.4.2) @@ -110,7 +103,7 @@ DEPENDENCIES pry rake rspec - rubocop (= 1.50.2) + rubocop (= 1.56.1) rubocop-graphql rubocop-i18n rubocop-minitest @@ -122,8 +115,7 @@ DEPENDENCIES rubocop-shopify rubocop-sorbet rubocop-thread_safety - standard (>= 1.0) test-prof BUNDLED WITH - 2.1.4 + 2.4.10 diff --git a/config/contents/bundler/duplicated_gem.md b/config/contents/bundler/duplicated_gem.md index 029c38e0..6f3f5aaa 100644 --- a/config/contents/bundler/duplicated_gem.md +++ b/config/contents/bundler/duplicated_gem.md @@ -1,4 +1,5 @@ A Gem's requirements should be listed only once in a Gemfile. + ### Example: # bad gem 'rubocop' diff --git a/config/contents/bundler/duplicated_group.md b/config/contents/bundler/duplicated_group.md new file mode 100644 index 00000000..cc403600 --- /dev/null +++ b/config/contents/bundler/duplicated_group.md @@ -0,0 +1,51 @@ +A Gem group, or a set of groups, should be listed only once in a Gemfile. + +For example, if the values of `source`, `git`, `platforms`, or `path` +surrounding `group` are different, no offense will be registered: + +[source,ruby] +----- +platforms :ruby do + group :default do + gem 'openssl' + end +end + +platforms :jruby do + group :default do + gem 'jruby-openssl' + end +end +----- + +### Example: + # bad + group :development do + gem 'rubocop' + end + + group :development do + gem 'rubocop-rails' + end + + # bad (same set of groups declared twice) + group :development, :test do + gem 'rubocop' + end + + group :test, :development do + gem 'rspec' + end + + # good + group :development do + gem 'rubocop' + end + + group :development, :test do + gem 'rspec' + end + + # good + gem 'rubocop', groups: [:development, :test] + gem 'rspec', groups: [:development, :test] diff --git a/config/contents/bundler/ordered_gems.md b/config/contents/bundler/ordered_gems.md index 84d8f9a2..3540c390 100644 --- a/config/contents/bundler/ordered_gems.md +++ b/config/contents/bundler/ordered_gems.md @@ -14,7 +14,15 @@ Gems should be alphabetically sorted within groups. gem 'rspec' - # good only if TreatCommentsAsGroupSeparators is true +### Example: TreatCommentsAsGroupSeparators: true (default) + # good + # For code quality + gem 'rubocop' + # For tests + gem 'rspec' + +### Example: TreatCommentsAsGroupSeparators: false + # bad # For code quality gem 'rubocop' # For tests diff --git a/config/contents/gemspec/ordered_dependencies.md b/config/contents/gemspec/ordered_dependencies.md index 92e0c6f8..b57b76b9 100644 --- a/config/contents/gemspec/ordered_dependencies.md +++ b/config/contents/gemspec/ordered_dependencies.md @@ -40,7 +40,15 @@ Dependencies in the gemspec should be alphabetically sorted. spec.add_runtime_dependency 'rspec' - # good only if TreatCommentsAsGroupSeparators is true +### Example: TreatCommentsAsGroupSeparators: true (default) + # good + # For code quality + spec.add_dependency 'rubocop' + # For tests + spec.add_dependency 'rspec' + +### Example: TreatCommentsAsGroupSeparators: false + # bad # For code quality spec.add_dependency 'rubocop' # For tests diff --git a/config/contents/layout/class_structure.md b/config/contents/layout/class_structure.md index 719d7e6a..a6319e86 100644 --- a/config/contents/layout/class_structure.md +++ b/config/contents/layout/class_structure.md @@ -61,6 +61,14 @@ automatically. - extend ``` +### Safety: + +Autocorrection is unsafe because class methods and module inclusion +can behave differently, based on which methods or constants have +already been defined. + +Constants will only be moved when they are assigned with literals. + ### Example: # bad # Expect extend be before constant diff --git a/config/contents/layout/closing_heredoc_indentation.md b/config/contents/layout/closing_heredoc_indentation.md index 6a78ff4d..1ccd210e 100644 --- a/config/contents/layout/closing_heredoc_indentation.md +++ b/config/contents/layout/closing_heredoc_indentation.md @@ -1,4 +1,3 @@ - Checks the indentation of here document closings. ### Example: diff --git a/config/contents/layout/space_around_method_call_operator.md b/config/contents/layout/space_around_method_call_operator.md index 37ef0ce6..b29cda5d 100644 --- a/config/contents/layout/space_around_method_call_operator.md +++ b/config/contents/layout/space_around_method_call_operator.md @@ -14,7 +14,7 @@ Checks method call operators to not have spaces around them. foo &. bar foo &. bar&. buzz RuboCop:: Cop - RuboCop:: Cop:: Cop + RuboCop:: Cop:: Base :: RuboCop::Cop # good @@ -26,5 +26,5 @@ Checks method call operators to not have spaces around them. foo&.bar foo&.bar&.buzz RuboCop::Cop - RuboCop::Cop::Cop + RuboCop::Cop::Base ::RuboCop::Cop diff --git a/config/contents/lint/duplicate_hash_key.md b/config/contents/lint/duplicate_hash_key.md index af8b7263..520de6d7 100644 --- a/config/contents/lint/duplicate_hash_key.md +++ b/config/contents/lint/duplicate_hash_key.md @@ -1,4 +1,5 @@ Checks for duplicated keys in hash literals. +This cop considers both primitive types and constants for the hash keys. This cop mirrors a warning in Ruby 2.2. diff --git a/config/contents/lint/erb_new_arguments.md b/config/contents/lint/erb_new_arguments.md index 00d5786b..04a979d0 100644 --- a/config/contents/lint/erb_new_arguments.md +++ b/config/contents/lint/erb_new_arguments.md @@ -1,10 +1,9 @@ - -This cop emulates the following Ruby warnings in Ruby 2.6. +Emulates the following Ruby warnings in Ruby 2.6. ```console -% cat example.rb +$ cat example.rb ERB.new('hi', nil, '-', '@output_buffer') -% ruby -rerb example.rb +$ ruby -rerb example.rb example.rb:1: warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments. example.rb:1: warning: Passing trim_mode with the 3rd argument of ERB.new is diff --git a/config/contents/lint/identity_comparison.md b/config/contents/lint/identity_comparison.md index c52449e0..23f51dbb 100644 --- a/config/contents/lint/identity_comparison.md +++ b/config/contents/lint/identity_comparison.md @@ -1,4 +1,3 @@ - Prefer `equal?` over `==` when comparing `object_id`. `Object#equal?` is provided to compare objects for identity, and in contrast diff --git a/config/contents/lint/incompatible_io_select_with_fiber_scheduler.md b/config/contents/lint/incompatible_io_select_with_fiber_scheduler.md index 0ab7459f..fdcc110d 100644 --- a/config/contents/lint/incompatible_io_select_with_fiber_scheduler.md +++ b/config/contents/lint/incompatible_io_select_with_fiber_scheduler.md @@ -1,5 +1,7 @@ +Checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0. -This cop checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0. +When an array of IO objects waiting for an exception (the third argument of `IO.select`) +is used as an argument, there is no alternative API, so offenses are not registered. NOTE: When the method is successful the return value of `IO.select` is `[[IO]]`, and the return value of `io.wait_readable` and `io.wait_writable` are `self`. diff --git a/config/contents/lint/lambda_without_literal_block.md b/config/contents/lint/lambda_without_literal_block.md index e670a213..6a82ea41 100644 --- a/config/contents/lint/lambda_without_literal_block.md +++ b/config/contents/lint/lambda_without_literal_block.md @@ -1,7 +1,7 @@ Checks uses of lambda without a literal block. It emulates the following warning in Ruby 3.0: - % ruby -vwe 'lambda(&proc {})' + $ ruby -vwe 'lambda(&proc {})' ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19] -e:1: warning: lambda without a literal block is deprecated; use the proc without lambda instead diff --git a/config/contents/lint/missing_super.md b/config/contents/lint/missing_super.md index 07c08433..8b9f0a0a 100644 --- a/config/contents/lint/missing_super.md +++ b/config/contents/lint/missing_super.md @@ -6,6 +6,16 @@ because in some cases it makes sense to overtake what is considered a missing method. In other cases, the theoretical ideal handling could be challenging or verbose for no actual gain. +Autocorrection is not supported because the position of `super` cannot be +determined automatically. + +`Object` and `BasicObject` are allowed by this cop because of their +stateless nature. However, sometimes you might want to allow other parent +classes from this cop, for example in the case of an abstract class that is +not meant to be called with `super`. In those cases, you can use the +`AllowedParentClasses` option to specify which classes should be allowed +*in addition to* `Object` and `BasicObject`. + ### Example: # bad class Employee < Person @@ -51,3 +61,18 @@ challenging or verbose for no actual gain. do_something end end + + # good + class ClassWithNoParent + def initialize + do_something + end + end + +### Example: AllowedParentClasses: [MyAbstractClass] + # good + class MyConcreteClass < MyAbstractClass + def initialize + do_something + end + end diff --git a/config/contents/lint/mixed_case_range.md b/config/contents/lint/mixed_case_range.md new file mode 100644 index 00000000..c30d53bf --- /dev/null +++ b/config/contents/lint/mixed_case_range.md @@ -0,0 +1,23 @@ +Checks for mixed-case character ranges since they include likely unintended characters. + +Offenses are registered for regexp character classes like `/[A-z]/` +as well as range objects like `('A'..'z')`. + +NOTE: Range objects cannot be autocorrected. + +### Safety: + +The cop autocorrects regexp character classes +by replacing one character range with two: `A-z` becomes `A-Za-z`. +In most cases this is probably what was originally intended +but it changes the regexp to no longer match symbols it used to include. +For this reason, this cop's autocorrect is unsafe (it will +change the behavior of the code). + +### Example: + + # bad + r = /[A-z]/ + + # good + r = /[A-Za-z]/ \ No newline at end of file diff --git a/config/contents/lint/numbered_parameter_assignment.md b/config/contents/lint/numbered_parameter_assignment.md index f6dd46b4..32395532 100644 --- a/config/contents/lint/numbered_parameter_assignment.md +++ b/config/contents/lint/numbered_parameter_assignment.md @@ -1,13 +1,13 @@ Checks for uses of numbered parameter assignment. It emulates the following warning in Ruby 2.7: - % ruby -ve '_1 = :value' + $ ruby -ve '_1 = :value' ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19] -e:1: warning: `_1' is reserved for numbered parameter; consider another name Assigning to a numbered parameter (from `_1` to `_9`) causes an error in Ruby 3.0. - % ruby -ve '_1 = :value' + $ ruby -ve '_1 = :value' ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19] -e:1: _1 is reserved for numbered parameter diff --git a/config/contents/lint/ordered_magic_comments.md b/config/contents/lint/ordered_magic_comments.md index fc2c19ac..f1502005 100644 --- a/config/contents/lint/ordered_magic_comments.md +++ b/config/contents/lint/ordered_magic_comments.md @@ -1,4 +1,3 @@ - Checks the proper ordering of magic comments and whether a magic comment is not placed before a shebang. diff --git a/config/contents/lint/redundant_regexp_quantifiers.md b/config/contents/lint/redundant_regexp_quantifiers.md new file mode 100644 index 00000000..bdf97594 --- /dev/null +++ b/config/contents/lint/redundant_regexp_quantifiers.md @@ -0,0 +1,27 @@ +Checks for redundant quantifiers inside Regexp literals. + +It is always allowed when interpolation is used in a regexp literal, +because it's unknown what kind of string will be expanded as a result: + +```ruby +/(?:a*#{interpolation})?/x +``` + +### Example: + # bad + /(?:x+)+/ + + # good + /(?:x)+/ + + # good + /(?:x+)/ + + # bad + /(?:x+)?/ + + # good + /(?:x)*/ + + # good + /(?:x*)/ \ No newline at end of file diff --git a/config/contents/lint/send_with_mixin_argument.md b/config/contents/lint/send_with_mixin_argument.md index 47547f7d..c0e59e69 100644 --- a/config/contents/lint/send_with_mixin_argument.md +++ b/config/contents/lint/send_with_mixin_argument.md @@ -1,5 +1,4 @@ - -This cop checks for `send`, `public_send`, and `__send__` methods +Checks for `send`, `public_send`, and `__send__` methods when using mix-in. `include` and `prepend` methods were private methods until Ruby 2.0, diff --git a/config/contents/lint/top_level_return_with_argument.md b/config/contents/lint/top_level_return_with_argument.md index 720acdf4..35f8ce5e 100644 --- a/config/contents/lint/top_level_return_with_argument.md +++ b/config/contents/lint/top_level_return_with_argument.md @@ -3,6 +3,8 @@ top-level return statement with an argument, then the argument is always ignored. This is detected automatically since Ruby 2.7. ### Example: + # bad + return 1 - # Detected since Ruby 2.7 - return 1 # 1 is always ignored. \ No newline at end of file + # good + return \ No newline at end of file diff --git a/config/contents/lint/useless_assignment.md b/config/contents/lint/useless_assignment.md index 97406952..8a6926d3 100644 --- a/config/contents/lint/useless_assignment.md +++ b/config/contents/lint/useless_assignment.md @@ -8,6 +8,13 @@ Currently this cop has advanced logic that detects unreferenced reassignments and properly handles varied cases such as branch, loop, rescue, ensure, etc. +### Safety: + +This cop's autocorrection is unsafe because removing assignment from +operator assignment can cause NameError if this assignment has been used to declare +local variable. For example, replacing `a ||= 1` to `a || 1` may cause +"undefined local variable or method `a' for main:Object (NameError)". + ### Example: # bad diff --git a/config/contents/naming/memoized_instance_variable_name.md b/config/contents/naming/memoized_instance_variable_name.md index b9b19eb2..82b4eb5a 100644 --- a/config/contents/naming/memoized_instance_variable_name.md +++ b/config/contents/naming/memoized_instance_variable_name.md @@ -13,7 +13,8 @@ be set or referenced outside of the memoization method. This cop relies on the pattern `@instance_var ||= ...`, but this is sometimes used for other purposes than memoization -so this cop is considered unsafe. +so this cop is considered unsafe. Also, its autocorrection is unsafe +because it may conflict with instance variable names already in use. ### Example: EnforcedStyleForLeadingUnderscores: disallowed (default) # bad diff --git a/config/contents/naming/variable_name.md b/config/contents/naming/variable_name.md index 6d4378cf..01f16eaf 100644 --- a/config/contents/naming/variable_name.md +++ b/config/contents/naming/variable_name.md @@ -15,6 +15,10 @@ snake_case or camelCase, for their names. # good fooBar = 1 +### Example: AllowedIdentifiers: ['fooBar'] + # good (with EnforcedStyle: snake_case) + fooBar = 1 + ### Example: AllowedPatterns: ['_v\d+\z'] - # good - :release_v1 \ No newline at end of file + # good (with EnforcedStyle: camelCase) + :release_v1 diff --git a/config/contents/style/arguments_forwarding.md b/config/contents/style/arguments_forwarding.md index 4e24717a..1288291a 100644 --- a/config/contents/style/arguments_forwarding.md +++ b/config/contents/style/arguments_forwarding.md @@ -3,6 +3,12 @@ In Ruby 2.7, arguments forwarding has been added. This cop identifies places where `do_something(*args, &block)` can be replaced by `do_something(...)`. +In Ruby 3.2, anonymous args/kwargs forwarding has been added. + +This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be +replaced by `use_args(*)`/`use_kwargs(**)`; if desired, this functionality can be disabled +by setting UseAnonymousForwarding: false. + ### Example: # bad def foo(*args, &block) @@ -19,7 +25,27 @@ can be replaced by `do_something(...)`. bar(...) end -### Example: AllowOnlyRestArgument: true (default) +### Example: UseAnonymousForwarding: true (default, only relevant for Ruby >= 3.2) + # bad + def foo(*args, **kwargs) + args_only(*args) + kwargs_only(**kwargs) + end + + # good + def foo(*, **) + args_only(*) + kwargs_only(**) + end + +### Example: UseAnonymousForwarding: false (only relevant for Ruby >= 3.2) + # good + def foo(*args, **kwargs) + args_only(*args) + kwargs_only(**kwargs) + end + +### Example: AllowOnlyRestArgument: true (default, only relevant for Ruby < 3.2) # good def foo(*args) bar(*args) @@ -29,7 +55,7 @@ can be replaced by `do_something(...)`. bar(**kwargs) end -### Example: AllowOnlyRestArgument: false +### Example: AllowOnlyRestArgument: false (only relevant for Ruby < 3.2) # bad # The following code can replace the arguments with `...`, # but it will change the behavior. Because `...` forwards block also. diff --git a/config/contents/style/begin_block.md b/config/contents/style/begin_block.md index e37a9b77..01b7175e 100644 --- a/config/contents/style/begin_block.md +++ b/config/contents/style/begin_block.md @@ -1,5 +1,4 @@ - -This cop checks for BEGIN blocks. +Checks for BEGIN blocks. ### Example: # bad diff --git a/config/contents/style/class_equality_comparison.md b/config/contents/style/class_equality_comparison.md index c1a9dee5..0e36b969 100644 --- a/config/contents/style/class_equality_comparison.md +++ b/config/contents/style/class_equality_comparison.md @@ -1,6 +1,6 @@ Enforces the use of `Object#instance_of?` instead of class comparison for equality. -`==`, `equal?`, and `eql?` methods are allowed by default. +`==`, `equal?`, and `eql?` custom method definitions are allowed by default. These are customizable with `AllowedMethods` option. ### Example: @@ -13,50 +13,28 @@ These are customizable with `AllowedMethods` option. # good var.instance_of?(Date) -### Example: AllowedMethods: [] (default) +### Example: AllowedMethods: ['==', 'equal?', 'eql?'] (default) # good - var.instance_of?(Date) - - # bad - var.class == Date - var.class.equal?(Date) - var.class.eql?(Date) - var.class.name == 'Date' - var.class.to_s == 'Date' - var.class.inspect == 'Date' + def ==(other) + self.class == other.class && name == other.name + end -### Example: AllowedMethods: [`==`] - # good - var.instance_of?(Date) - var.class == Date - var.class.name == 'Date' - var.class.to_s == 'Date' - var.class.inspect == 'Date' + def equal?(other) + self.class.equal?(other.class) && name.equal?(other.name) + end - # bad - var.class.equal?(Date) - var.class.eql?(Date) + def eql?(other) + self.class.eql?(other.class) && name.eql?(other.name) + end ### Example: AllowedPatterns: [] (default) - # good - var.instance_of?(Date) - # bad - var.class == Date - var.class.equal?(Date) - var.class.eql?(Date) - var.class.name == 'Date' - var.class.to_s == 'Date' - var.class.inspect == 'Date' + def eq(other) + self.class.eq(other.class) && name.eq(other.name) + end ### Example: AllowedPatterns: ['eq'] # good - var.instance_of?(Date) - var.class.equal?(Date) - var.class.eql?(Date) - - # bad - var.class == Date - var.class.name == 'Date' - var.class.to_s == 'Date' - var.class.inspect == 'Date' + def eq(other) + self.class.eq(other.class) && name.eq(other.name) + end diff --git a/config/contents/style/collection_compact.md b/config/contents/style/collection_compact.md index f7bc8ccc..8d494072 100644 --- a/config/contents/style/collection_compact.md +++ b/config/contents/style/collection_compact.md @@ -5,8 +5,8 @@ and hashes can be replaced with `{Array,Hash}#{compact,compact!}`. It is unsafe by default because false positives may occur in the `nil` check of block arguments to the receiver object. Additionally, - we can't know the type of the receiver object for sure, which may - result in false positives as well. +we can't know the type of the receiver object for sure, which may +result in false positives as well. For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }` and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine @@ -15,7 +15,9 @@ when the receiver is a hash object. ### Example: # bad array.reject(&:nil?) + array.delete_if(&:nil?) array.reject { |e| e.nil? } + array.delete_if { |e| e.nil? } array.select { |e| !e.nil? } # good @@ -28,3 +30,7 @@ when the receiver is a hash object. # good hash.compact! + +### Example: AllowedReceivers: ['params'] + # good + params.reject(&:nil?) diff --git a/config/contents/style/colon_method_call.md b/config/contents/style/colon_method_call.md index ee5c26a7..befd8d4c 100644 --- a/config/contents/style/colon_method_call.md +++ b/config/contents/style/colon_method_call.md @@ -1,5 +1,5 @@ -Checks for methods invoked via the :: operator instead -of the . operator (like FileUtils::rmdir instead of FileUtils.rmdir). +Checks for methods invoked via the `::` operator instead +of the `.` operator (like `FileUtils::rmdir` instead of `FileUtils.rmdir`). ### Example: # bad diff --git a/config/contents/style/copyright.md b/config/contents/style/copyright.md index 1e00d3cf..5f114272 100644 --- a/config/contents/style/copyright.md +++ b/config/contents/style/copyright.md @@ -3,8 +3,10 @@ Check that a copyright notice was given in each source file. The default regexp for an acceptable copyright notice can be found in config/default.yml. The default can be changed as follows: - Style/Copyright: - Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc' +```yaml +Style/Copyright: + Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc' +``` This regex string is treated as an unanchored regex. For each file that RuboCop scans, a comment that matches this regex must be found or diff --git a/config/contents/style/dir.md b/config/contents/style/dir.md index 25a6253e..6a210758 100644 --- a/config/contents/style/dir.md +++ b/config/contents/style/dir.md @@ -1,4 +1,4 @@ -Checks for places where the `#__dir__` method can replace more +Checks for places where the `#\_\_dir\_\_` method can replace more complex constructs to retrieve a canonicalized absolute path to the current file. diff --git a/config/contents/style/documentation.md b/config/contents/style/documentation.md index df95c36d..068eff10 100644 --- a/config/contents/style/documentation.md +++ b/config/contents/style/documentation.md @@ -5,7 +5,7 @@ classes, other modules, constant definitions or constant visibility declarations. The documentation requirement is annulled if the class or module has -a "#:nodoc:" comment next to it. Likewise, "#:nodoc: all" does the +a `#:nodoc:` comment next to it. Likewise, `#:nodoc: all` does the same for all its children. ### Example: diff --git a/config/contents/style/eval_with_location.md b/config/contents/style/eval_with_location.md index 9fc21672..f441417b 100644 --- a/config/contents/style/eval_with_location.md +++ b/config/contents/style/eval_with_location.md @@ -1,10 +1,10 @@ Ensures that eval methods (`eval`, `instance_eval`, `class_eval` -and `module_eval`) are given filename and line number values (`__FILE__` -and `__LINE__`). This data is used to ensure that any errors raised +and `module_eval`) are given filename and line number values (`\_\_FILE\_\_` +and `\_\_LINE\_\_`). This data is used to ensure that any errors raised within the evaluated code will be given the correct identification in a backtrace. -The cop also checks that the line number given relative to `__LINE__` is +The cop also checks that the line number given relative to `\_\_LINE\_\_` is correct. This cop will autocorrect incorrect or missing filename and line number diff --git a/config/contents/style/exact_regexp_match.md b/config/contents/style/exact_regexp_match.md new file mode 100644 index 00000000..dda0c37c --- /dev/null +++ b/config/contents/style/exact_regexp_match.md @@ -0,0 +1,18 @@ +Checks for exact regexp match inside Regexp literals. + +### Example: + + # bad + string =~ /\Astring\z/ + string === /\Astring\z/ + string.match(/\Astring\z/) + string.match?(/\Astring\z/) + + # good + string == 'string' + + # bad + string !~ /\Astring\z/ + + # good + string != 'string' diff --git a/config/contents/style/hash_conversion.md b/config/contents/style/hash_conversion.md index 24886bba..90d7aa52 100644 --- a/config/contents/style/hash_conversion.md +++ b/config/contents/style/hash_conversion.md @@ -5,6 +5,16 @@ Correction code from splat argument (`Hash[*ary]`) is not simply determined. For `Hash[*ary]` can be replaced with `ary.each_slice(2).to_h` but it will be complicated. So, `AllowSplatArgument` option is true by default to allow splat argument for simple code. +### Safety: + +This cop's autocorrection is unsafe because `ArgumentError` occurs +if the number of elements is odd: + +```ruby +Hash[[[1, 2], [3]]] #=> {1=>2, 3=>nil} +[[1, 2], [5]].to_h #=> wrong array length at 1 (expected 2, was 1) (ArgumentError) +``` + ### Example: # bad Hash[ary] diff --git a/config/contents/style/hash_transform_keys.md b/config/contents/style/hash_transform_keys.md index 20377080..90120a3f 100644 --- a/config/contents/style/hash_transform_keys.md +++ b/config/contents/style/hash_transform_keys.md @@ -1,5 +1,5 @@ -Looks for uses of `_.each_with_object({}) {...}`, -`_.map {...}.to_h`, and `Hash[_.map {...}]` that are actually just +Looks for uses of `\_.each_with_object({}) {...}`, +`\_.map {...}.to_h`, and `Hash[\_.map {...}]` that are actually just transforming the keys of a hash, and tries to use a simpler & faster call to `transform_keys` instead. It should only be enabled on Ruby version 2.5 or newer. diff --git a/config/contents/style/hash_transform_values.md b/config/contents/style/hash_transform_values.md index cbf3d869..07a5b396 100644 --- a/config/contents/style/hash_transform_values.md +++ b/config/contents/style/hash_transform_values.md @@ -1,5 +1,5 @@ -Looks for uses of `_.each_with_object({}) {...}`, -`_.map {...}.to_h`, and `Hash[_.map {...}]` that are actually just +Looks for uses of `\_.each_with_object({}) {...}`, +`\_.map {...}.to_h`, and `Hash[\_.map {...}]` that are actually just transforming the values of a hash, and tries to use a simpler & faster call to `transform_values` instead. diff --git a/config/contents/style/invertible_unless_condition.md b/config/contents/style/invertible_unless_condition.md index 2b73f7ac..5d108e53 100644 --- a/config/contents/style/invertible_unless_condition.md +++ b/config/contents/style/invertible_unless_condition.md @@ -5,12 +5,15 @@ is disabled by default. Methods that can be inverted should be defined in `InverseMethods`. Note that the relationship of inverse methods needs to be defined in both directions. For example, - InverseMethods: - :!=: :== - :even?: :odd? - :odd?: :even? - will suggest both `even?` and `odd?` to be inverted, but only `!=` (and not `==`). +```yaml +InverseMethods: + :!=: :== + :even?: :odd? + :odd?: :even? +``` + +will suggest both `even?` and `odd?` to be inverted, but only `!=` (and not `==`). ### Safety: diff --git a/config/contents/style/multiple_comparison.md b/config/contents/style/multiple_comparison.md index 4025ced7..50277034 100644 --- a/config/contents/style/multiple_comparison.md +++ b/config/contents/style/multiple_comparison.md @@ -34,4 +34,12 @@ by default. It can be configured by `AllowMethodComparison` option. foo if a == b.lightweight || a == b.heavyweight # good - foo if [b.lightweight, b.heavyweight].include?(a) \ No newline at end of file + foo if [b.lightweight, b.heavyweight].include?(a) + +### Example: ComparisonsThreshold: 2 (default) + # bad + foo if a == 'a' || a == 'b' + +### Example: ComparisonsThreshold: 3 + # good + foo if a == 'a' || a == 'b' diff --git a/config/contents/style/redundant_argument.md b/config/contents/style/redundant_argument.md index f75c7c4e..271c33a3 100644 --- a/config/contents/style/redundant_argument.md +++ b/config/contents/style/redundant_argument.md @@ -30,6 +30,8 @@ This cop is unsafe because of the following limitations: array.join('') [1, 2, 3].join("") array.sum(0) + exit(true) + exit!(false) string.split(" ") "first\nsecond".split(" ") string.chomp("\n") @@ -40,6 +42,8 @@ This cop is unsafe because of the following limitations: array.join [1, 2, 3].join array.sum + exit + exit! string.split "first second".split string.chomp diff --git a/config/contents/style/redundant_array_constructor.md b/config/contents/style/redundant_array_constructor.md new file mode 100644 index 00000000..f9ee1cee --- /dev/null +++ b/config/contents/style/redundant_array_constructor.md @@ -0,0 +1,18 @@ +Checks for the instantiation of array using redundant `Array` constructor. +Autocorrect replaces to array literal which is the simplest and fastest. + +### Example: + + # bad + Array.new([]) + Array[] + Array([]) + Array.new(['foo', 'foo', 'foo']) + Array['foo', 'foo', 'foo'] + Array(['foo', 'foo', 'foo']) + + # good + [] + ['foo', 'foo', 'foo'] + Array.new(3, 'foo') + Array.new(3) { 'foo' } diff --git a/config/contents/style/redundant_current_directory_in_path.md b/config/contents/style/redundant_current_directory_in_path.md new file mode 100644 index 00000000..20f0c635 --- /dev/null +++ b/config/contents/style/redundant_current_directory_in_path.md @@ -0,0 +1,9 @@ +Checks for uses a redundant current directory in path. + +### Example: + + # bad + require_relative './path/to/feature' + + # good + require_relative 'path/to/feature' diff --git a/config/contents/style/redundant_filter_chain.md b/config/contents/style/redundant_filter_chain.md new file mode 100644 index 00000000..cda1fd3f --- /dev/null +++ b/config/contents/style/redundant_filter_chain.md @@ -0,0 +1,31 @@ +Identifies usages of `any?`, `empty?` or `none?` predicate methods +chained to `select`/`filter`/`find_all` and change them to use predicate method instead. + +### Example: + # bad + arr.select { |x| x > 1 }.any? + + # good + arr.any? { |x| x > 1 } + + # bad + arr.select { |x| x > 1 }.empty? + arr.select { |x| x > 1 }.none? + + # good + arr.none? { |x| x > 1 } + + # good + relation.select(:name).any? + arr.select { |x| x > 1 }.any?(&:odd?) + +### Example: AllCops:ActiveSupportExtensionsEnabled: false (default) + # good + arr.select { |x| x > 1 }.many? + +### Example: AllCops:ActiveSupportExtensionsEnabled: true + # bad + arr.select { |x| x > 1 }.many? + + # good + arr.many? { |x| x > 1 } diff --git a/config/contents/style/redundant_regexp_argument.md b/config/contents/style/redundant_regexp_argument.md new file mode 100644 index 00000000..29e4c23e --- /dev/null +++ b/config/contents/style/redundant_regexp_argument.md @@ -0,0 +1,29 @@ +Identifies places where argument can be replaced from +a deterministic regexp to a string. + +### Example: + # bad + 'foo'.byteindex(/f/) + 'foo'.byterindex(/f/) + 'foo'.gsub(/f/, 'x') + 'foo'.gsub!(/f/, 'x') + 'foo'.partition(/f/) + 'foo'.rpartition(/f/) + 'foo'.scan(/f/) + 'foo'.split(/f/) + 'foo'.start_with?(/f/) + 'foo'.sub(/f/, 'x') + 'foo'.sub!(/f/, 'x') + + # good + 'foo'.byteindex('f') + 'foo'.byterindex('f') + 'foo'.gsub('f', 'x') + 'foo'.gsub!('f', 'x') + 'foo'.partition('f') + 'foo'.rpartition('f') + 'foo'.scan('f') + 'foo'.split('f') + 'foo'.start_with?('f') + 'foo'.sub('f', 'x') + 'foo'.sub!('f', 'x') \ No newline at end of file diff --git a/config/contents/style/redundant_regexp_constructor.md b/config/contents/style/redundant_regexp_constructor.md new file mode 100644 index 00000000..07f2516e --- /dev/null +++ b/config/contents/style/redundant_regexp_constructor.md @@ -0,0 +1,13 @@ +Checks for the instantiation of regexp using redundant `Regexp.new` or `Regexp.compile`. +Autocorrect replaces to regexp literal which is the simplest and fastest. + +### Example: + + # bad + Regexp.new(/regexp/) + Regexp.compile(/regexp/) + + # good + /regexp/ + Regexp.new('regexp') + Regexp.compile('regexp') diff --git a/config/contents/style/redundant_return.md b/config/contents/style/redundant_return.md index 803477d1..49199335 100644 --- a/config/contents/style/redundant_return.md +++ b/config/contents/style/redundant_return.md @@ -17,11 +17,16 @@ Checks for redundant `return` expressions. return something end - # good + # bad def test return something if something_else end + # good + def test + something if something_else + end + # good def test if x diff --git a/config/contents/style/regexp_literal.md b/config/contents/style/regexp_literal.md index 6fb43378..630ef303 100644 --- a/config/contents/style/regexp_literal.md +++ b/config/contents/style/regexp_literal.md @@ -1,4 +1,12 @@ -Enforces using // or %r around regular expressions. +Enforces using `//` or `%r` around regular expressions. + +NOTE: The following `%r` cases using a regexp starts with a blank or `=` +as a method argument allowed to prevent syntax errors. + +```ruby +do_something %r{ regexp} # `do_something / regexp/` is an invalid syntax. +do_something %r{=regexp} # `do_something /=regexp/` is an invalid syntax. +``` ### Example: EnforcedStyle: slashes (default) # bad diff --git a/config/contents/style/rescue_modifier.md b/config/contents/style/rescue_modifier.md index 2215d4de..89fff66f 100644 --- a/config/contents/style/rescue_modifier.md +++ b/config/contents/style/rescue_modifier.md @@ -1,6 +1,4 @@ -Checks for uses of rescue in its modifier form. - -The cop to check `rescue` in its modifier form is added for following +Checks for uses of `rescue` in its modifier form is added for following reasons: * The syntax of modifier form `rescue` can be misleading because it diff --git a/config/contents/style/return_nil_in_predicate_method_definition.md b/config/contents/style/return_nil_in_predicate_method_definition.md new file mode 100644 index 00000000..87b2416a --- /dev/null +++ b/config/contents/style/return_nil_in_predicate_method_definition.md @@ -0,0 +1,44 @@ +Checks if `return` or `return nil` is used in predicate method definitions. + +### Safety: + +Autocorrection is marked as unsafe because the change of the return value +from `nil` to `false` could potentially lead to incompatibility issues. + +### Example: + # bad + def foo? + return if condition + + do_something? + end + + # bad + def foo? + return nil if condition + + do_something? + end + + # good + def foo? + return false if condition + + do_something? + end + +### Example: AllowedMethods: ['foo?'] + # good + def foo? + return if condition + + do_something? + end + +### Example: AllowedPatterns: [/foo/] + # good + def foo? + return if condition + + do_something? + end diff --git a/config/contents/style/special_global_vars.md b/config/contents/style/special_global_vars.md index d7e82809..782c88b4 100644 --- a/config/contents/style/special_global_vars.md +++ b/config/contents/style/special_global_vars.md @@ -1,5 +1,4 @@ - -This cop looks for uses of Perl-style global variables. +Looks for uses of Perl-style global variables. Correcting to global variables in the 'English' library will add a require statement to the top of the file if enabled by RequireEnglish config. diff --git a/config/contents/style/string_literals_in_interpolation.md b/config/contents/style/string_literals_in_interpolation.md index 0e7fb586..d2f3b976 100644 --- a/config/contents/style/string_literals_in_interpolation.md +++ b/config/contents/style/string_literals_in_interpolation.md @@ -1,16 +1,36 @@ -Checks that quotes inside the string interpolation +Checks that quotes inside string, symbol, and regexp interpolations match the configured preference. ### Example: EnforcedStyle: single_quotes (default) # bad - result = "Tests #{success ? "PASS" : "FAIL"}" + string = "Tests #{success ? "PASS" : "FAIL"}" + symbol = :"Tests #{success ? "PASS" : "FAIL"}" + heredoc = <<~TEXT + Tests #{success ? "PASS" : "FAIL"} + TEXT + regexp = /Tests #{success ? "PASS" : "FAIL"}/ # good - result = "Tests #{success ? 'PASS' : 'FAIL'}" + string = "Tests #{success ? 'PASS' : 'FAIL'}" + symbol = :"Tests #{success ? 'PASS' : 'FAIL'}" + heredoc = <<~TEXT + Tests #{success ? 'PASS' : 'FAIL'} + TEXT + regexp = /Tests #{success ? 'PASS' : 'FAIL'}/ ### Example: EnforcedStyle: double_quotes # bad - result = "Tests #{success ? 'PASS' : 'FAIL'}" + string = "Tests #{success ? 'PASS' : 'FAIL'}" + symbol = :"Tests #{success ? 'PASS' : 'FAIL'}" + heredoc = <<~TEXT + Tests #{success ? 'PASS' : 'FAIL'} + TEXT + regexp = /Tests #{success ? 'PASS' : 'FAIL'}/ # good - result = "Tests #{success ? "PASS" : "FAIL"}" \ No newline at end of file + string = "Tests #{success ? "PASS" : "FAIL"}" + symbol = :"Tests #{success ? "PASS" : "FAIL"}" + heredoc = <<~TEXT + Tests #{success ? "PASS" : "FAIL"} + TEXT + regexp = /Tests #{success ? "PASS" : "FAIL"}/ \ No newline at end of file diff --git a/config/contents/style/symbol_array.md b/config/contents/style/symbol_array.md index a9ebaeb4..15722365 100644 --- a/config/contents/style/symbol_array.md +++ b/config/contents/style/symbol_array.md @@ -17,6 +17,15 @@ array of 2 or fewer elements. # bad [:foo, :bar, :baz] + # bad (contains spaces) + %i[foo\ bar baz\ quux] + + # bad (contains [] with spaces) + %i[foo \[ \]] + + # bad (contains () with spaces) + %i(foo \( \)) + ### Example: EnforcedStyle: brackets # good [:foo, :bar, :baz] diff --git a/config/contents/style/yaml_file_read.md b/config/contents/style/yaml_file_read.md new file mode 100644 index 00000000..99ce4354 --- /dev/null +++ b/config/contents/style/yaml_file_read.md @@ -0,0 +1,20 @@ +Checks for the use of `YAML.load`, `YAML.safe_load`, and `YAML.parse` with +`File.read` argument. + +NOTE: `YAML.safe_load_file` was introduced in Ruby 3.0. + +### Example: + + # bad + YAML.load(File.read(path)) + YAML.parse(File.read(path)) + + # good + YAML.load_file(path) + YAML.parse_file(path) + + # bad + YAML.safe_load(File.read(path)) # Ruby 3.0 and newer + + # good + YAML.safe_load_file(path) # Ruby 3.0 and newer