From e6976ae3d1c79ce7cd5afa3f6739658eb2ae5992 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sat, 13 Jul 2024 15:35:06 -0400 Subject: [PATCH 01/10] rubocop: Discourage the use of `FileUtils.rm_rf` - This cop checks for the use of `FileUtils.rm_rf` and suggests using `FileUtils.rm_r` because we should know if we couldn't delete a thing for some reason, not just force it. --- Library/Homebrew/rubocops/all.rb | 1 + .../Homebrew/rubocops/no_fileutils_rmrf.rb | 27 +++++++++++++++++ .../test/rubocops/no_fileutils_rmrf_spec.rb | 30 +++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 Library/Homebrew/rubocops/no_fileutils_rmrf.rb create mode 100644 Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb diff --git a/Library/Homebrew/rubocops/all.rb b/Library/Homebrew/rubocops/all.rb index 284d135bd5970..bfcf79a8b9630 100644 --- a/Library/Homebrew/rubocops/all.rb +++ b/Library/Homebrew/rubocops/all.rb @@ -8,6 +8,7 @@ require_relative "io_read" require_relative "move_to_extend_os" require_relative "negate_include" +require_relative "no_fileutils_rmrf" require_relative "presence" require_relative "present" require_relative "safe_navigation_with_blank" diff --git a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb new file mode 100644 index 0000000000000..c6de46f8b3403 --- /dev/null +++ b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb @@ -0,0 +1,27 @@ +# typed: true +# frozen_string_literal: true + +module RuboCop + module Cop + module Homebrew + # This cop checks for the use of `FileUtils.rm_rf` and recommends `FileUtils.rm_r`. + class NoFileutilsRmrf < Base + extend AutoCorrector + + MSG = "Use `FileUtils.rm_r` instead of `FileUtils.rm_rf`." + + def_node_matcher :fileutils_rm_rf?, <<~PATTERN + (send (const {nil? cbase} :FileUtils) :rm_rf ...) + PATTERN + + def on_send(node) + return unless fileutils_rm_rf?(node) + + add_offense(node) do |corrector| + corrector.replace(node.loc.expression, "FileUtils.rm_r(#{node.arguments.first.source})") + end + end + end + end + end +end diff --git a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb new file mode 100644 index 0000000000000..1b590fa12b08e --- /dev/null +++ b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require "rubocops/no_fileutils_rmrf" + +RSpec.describe RuboCop::Cop::Homebrew::NoFileutilsRmrf do + subject(:cop) { described_class.new } + + it "registers an offense when using FileUtils.rm_rf" do + expect_offense(<<~RUBY) + FileUtils.rm_rf("path/to/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: Use `FileUtils.rm_r` instead of `FileUtils.rm_rf`. + RUBY + end + + it "autocorrects" do + corrected = autocorrect_source(<<~RUBY) + FileUtils.rm_rf("path/to/directory") + RUBY + + expect(corrected).to eq(<<~RUBY) + FileUtils.rm_r("path/to/directory") + RUBY + end + + it "does not register an offense when using FileUtils.rm_r" do + expect_no_offenses(<<~RUBY) + FileUtils.rm_r("path/to/directory") + RUBY + end +end From f4e4808553cf45c460373e08d1f0e967c5c745cb Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sat, 13 Jul 2024 16:01:25 -0400 Subject: [PATCH 02/10] rubocop/no_fileutils_rmrf: Extend to cover `FileUtils#rm_f` too --- Library/Homebrew/rubocops/no_fileutils_rmrf.rb | 13 +++++++------ .../test/rubocops/no_fileutils_rmrf_spec.rb | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb index c6de46f8b3403..5dd4a57f1027e 100644 --- a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb +++ b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb @@ -4,21 +4,22 @@ module RuboCop module Cop module Homebrew - # This cop checks for the use of `FileUtils.rm_rf` and recommends `FileUtils.rm_r`. + # This cop checks for the use of `FileUtils.rm_f` or `FileUtils.rm_rf` and recommends the non-`f` versions. class NoFileutilsRmrf < Base extend AutoCorrector - MSG = "Use `FileUtils.rm_r` instead of `FileUtils.rm_rf`." + MSG = "Use `FileUtils.rm` or `FileUtils.rm_f` instead of `FileUtils.rm_rf` or `FileUtils.rm_f`." - def_node_matcher :fileutils_rm_rf?, <<~PATTERN - (send (const {nil? cbase} :FileUtils) :rm_rf ...) + def_node_matcher :fileutils_rm_r_f?, <<~PATTERN + (send (const {nil? cbase} :FileUtils) {:rm_rf :rm_f} ...) PATTERN def on_send(node) - return unless fileutils_rm_rf?(node) + return unless fileutils_rm_r_f?(node) add_offense(node) do |corrector| - corrector.replace(node.loc.expression, "FileUtils.rm_r(#{node.arguments.first.source})") + new_method = node.method?(:rm_rf) ? "rm_r" : "rm" + corrector.replace(node.loc.expression, "FileUtils.#{new_method}(#{node.arguments.first.source})") end end end diff --git a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb index 1b590fa12b08e..df0c6249b9110 100644 --- a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb +++ b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb @@ -8,7 +8,14 @@ it "registers an offense when using FileUtils.rm_rf" do expect_offense(<<~RUBY) FileUtils.rm_rf("path/to/directory") - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: Use `FileUtils.rm_r` instead of `FileUtils.rm_rf`. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + RUBY + end + + it "registers an offense when using FileUtils.rm_f" do + expect_offense(<<~RUBY) + FileUtils.rm_f("path/to/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} RUBY end @@ -27,4 +34,10 @@ FileUtils.rm_r("path/to/directory") RUBY end + + it "does not register an offense when using FileUtils.rm" do + expect_no_offenses(<<~RUBY) + FileUtils.rm("path/to/directory") + RUBY + end end From ebd9d183dc8357cf2d282579dcc6130b4ffe5992 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sat, 13 Jul 2024 16:12:30 -0400 Subject: [PATCH 03/10] rubocop/no_fileutils_rmrf: Extend to cover `FileUtils#rmtree` too --- Library/Homebrew/rubocops/no_fileutils_rmrf.rb | 13 +++++++++---- .../test/rubocops/no_fileutils_rmrf_spec.rb | 7 +++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb index 5dd4a57f1027e..914d2a79d89f0 100644 --- a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb +++ b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb @@ -4,21 +4,26 @@ module RuboCop module Cop module Homebrew - # This cop checks for the use of `FileUtils.rm_f` or `FileUtils.rm_rf` and recommends the non-`f` versions. + # This cop checks for the use of `FileUtils.rm_f`, `FileUtils.rm_rf`, or `FileUtils.rmtree` + # and recommends the non-`f` versions. class NoFileutilsRmrf < Base extend AutoCorrector - MSG = "Use `FileUtils.rm` or `FileUtils.rm_f` instead of `FileUtils.rm_rf` or `FileUtils.rm_f`." + MSG = "Use `FileUtils.rm`, `FileUtils.rm_r` instead of `FileUtils.rm_rf`, `FileUtils.rm_f`, or `FileUtils.rmtree`." def_node_matcher :fileutils_rm_r_f?, <<~PATTERN - (send (const {nil? cbase} :FileUtils) {:rm_rf :rm_f} ...) + (send (const {nil? cbase} :FileUtils) {:rm_rf :rm_f :rmtree} ...) PATTERN def on_send(node) return unless fileutils_rm_r_f?(node) add_offense(node) do |corrector| - new_method = node.method?(:rm_rf) ? "rm_r" : "rm" + new_method = if node.method?(:rm_rf) || node.method?(:rmtree) + "rm_r" + else + "rm" + end corrector.replace(node.loc.expression, "FileUtils.#{new_method}(#{node.arguments.first.source})") end end diff --git a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb index df0c6249b9110..90cf8718e53f7 100644 --- a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb +++ b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb @@ -19,6 +19,13 @@ RUBY end + it "registers an offense when using FileUtils.rmtree" do + expect_offense(<<~RUBY) + FileUtils.rmtree("path/to/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + RUBY + end + it "autocorrects" do corrected = autocorrect_source(<<~RUBY) FileUtils.rm_rf("path/to/directory") From cc7784605d5dfbbca330d2934e7616cf38c46c5d Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sat, 13 Jul 2024 16:24:22 -0400 Subject: [PATCH 04/10] rubocop/no_fileutils_rmrf: Reorganize tests --- .../test/rubocops/no_fileutils_rmrf_spec.rb | 80 +++++++++++-------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb index 90cf8718e53f7..9ea3634ae2d2b 100644 --- a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb +++ b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb @@ -5,46 +5,60 @@ RSpec.describe RuboCop::Cop::Homebrew::NoFileutilsRmrf do subject(:cop) { described_class.new } - it "registers an offense when using FileUtils.rm_rf" do - expect_offense(<<~RUBY) - FileUtils.rm_rf("path/to/directory") - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} - RUBY - end + describe "FileUtils.rm_rf" do + it "registers an offense" do + expect_offense(<<~RUBY) + FileUtils.rm_rf("path/to/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + RUBY + end - it "registers an offense when using FileUtils.rm_f" do - expect_offense(<<~RUBY) - FileUtils.rm_f("path/to/directory") - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} - RUBY - end + it "autocorrects" do + corrected = autocorrect_source(<<~RUBY) + FileUtils.rm_rf("path/to/directory") + RUBY - it "registers an offense when using FileUtils.rmtree" do - expect_offense(<<~RUBY) - FileUtils.rmtree("path/to/directory") - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} - RUBY + expect(corrected).to eq(<<~RUBY) + FileUtils.rm_r("path/to/directory") + RUBY + end end - it "autocorrects" do - corrected = autocorrect_source(<<~RUBY) - FileUtils.rm_rf("path/to/directory") - RUBY + describe "FileUtils.rm_f" do + it "registers an offense" do + expect_offense(<<~RUBY) + FileUtils.rm_f("path/to/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + RUBY + end - expect(corrected).to eq(<<~RUBY) - FileUtils.rm_r("path/to/directory") - RUBY - end + it "autocorrects" do + corrected = autocorrect_source(<<~RUBY) + FileUtils.rm_f("path/to/directory") + RUBY - it "does not register an offense when using FileUtils.rm_r" do - expect_no_offenses(<<~RUBY) - FileUtils.rm_r("path/to/directory") - RUBY + expect(corrected).to eq(<<~RUBY) + FileUtils.rm("path/to/directory") + RUBY + end end - it "does not register an offense when using FileUtils.rm" do - expect_no_offenses(<<~RUBY) - FileUtils.rm("path/to/directory") - RUBY + describe "FileUtils.rmtree" do + it "registers an offense" do + expect_offense(<<~RUBY) + FileUtils.rmtree("path/to/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + RUBY + end + + it "autocorrects" do + corrected = autocorrect_source(<<~RUBY) + FileUtils.rmtree("path/to/directory") + RUBY + + expect(corrected).to eq(<<~RUBY) + FileUtils.rm_r("path/to/directory") + RUBY + end end end From 14dd3592dc3d81d5e299210c402b438e053c751c Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sat, 13 Jul 2024 22:13:03 -0400 Subject: [PATCH 05/10] rubocop/no_fileutils_rmrf: Discourage `Pathname#rmtree` too - This [seems to be](https://ruby-doc.org/3.3.4/exts/pathname/Pathname.html#method-i-rmtree) equivalent to `FileUtils#rm_r`, so replace it with that. --- .../Homebrew/rubocops/no_fileutils_rmrf.rb | 18 ++++++++++++++---- .../test/rubocops/no_fileutils_rmrf_spec.rb | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb index 914d2a79d89f0..a99c9c5452e29 100644 --- a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb +++ b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb @@ -4,19 +4,24 @@ module RuboCop module Cop module Homebrew - # This cop checks for the use of `FileUtils.rm_f`, `FileUtils.rm_rf`, or `FileUtils.rmtree` - # and recommends the non-`f` versions. + # This cop checks for the use of `FileUtils.rm_f`, `FileUtils.rm_rf`, or `{FileUtils,Pathname}.rmtree` + # and recommends the safer versions. class NoFileutilsRmrf < Base extend AutoCorrector - MSG = "Use `FileUtils.rm`, `FileUtils.rm_r` instead of `FileUtils.rm_rf`, `FileUtils.rm_f`, or `FileUtils.rmtree`." + MSG = "Use `FileUtils.rm` or `FileUtils.rm_r` instead of `FileUtils.rm_rf`, `FileUtils.rm_f`, " \ + "or `{FileUtils,Pathname}.rmtree`." def_node_matcher :fileutils_rm_r_f?, <<~PATTERN (send (const {nil? cbase} :FileUtils) {:rm_rf :rm_f :rmtree} ...) PATTERN + def_node_matcher :pathname_rmtree?, <<~PATTERN + (send (const {nil? cbase} :Pathname) :rmtree ...) + PATTERN + def on_send(node) - return unless fileutils_rm_r_f?(node) + return if neither_rm_rf_nor_rmtree?(node) add_offense(node) do |corrector| new_method = if node.method?(:rm_rf) || node.method?(:rmtree) @@ -24,9 +29,14 @@ def on_send(node) else "rm" end + corrector.replace(node.loc.expression, "FileUtils.#{new_method}(#{node.arguments.first.source})") end end + + def neither_rm_rf_nor_rmtree?(node) + !fileutils_rm_r_f?(node) && !pathname_rmtree?(node) + end end end end diff --git a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb index 9ea3634ae2d2b..4581fb2dbba70 100644 --- a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb +++ b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb @@ -61,4 +61,23 @@ RUBY end end + + describe "Pathname.rmtree" do + it "registers an offense" do + expect_offense(<<~RUBY) + Pathname.rmtree("path/to/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + RUBY + end + + it "autocorrects" do + corrected = autocorrect_source(<<~RUBY) + Pathname.rmtree("path/to/directory") + RUBY + + expect(corrected).to eq(<<~RUBY) + FileUtils.rm_r("path/to/directory") + RUBY + end + end end From 99c5cc99b5115d47728f50e611b5c368a28b26fa Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 14 Jul 2024 12:09:59 -0400 Subject: [PATCH 06/10] rubocop/no_fileutils_rmrf: Scope to just formulae and casks --- Library/.rubocop.yml | 5 ++ .../Homebrew/rubocops/no_fileutils_rmrf.rb | 15 +++--- .../cop/homebrew/no_fileutils_rmrf.rbi | 14 ++++++ .../test/rubocops/no_fileutils_rmrf_spec.rb | 49 ++++++------------- 4 files changed, 41 insertions(+), 42 deletions(-) create mode 100644 Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi diff --git a/Library/.rubocop.yml b/Library/.rubocop.yml index aaddb602a6ddc..829dd2dcdc50b 100644 --- a/Library/.rubocop.yml +++ b/Library/.rubocop.yml @@ -60,6 +60,11 @@ Homebrew/CompactBlank: # `blank?` is not necessarily available here: - "Homebrew/extend/enumerable.rb" +Homebrew/NoFileutilsRmrf: + Include: + - "/**/{Formula,Casks}/**/*.rb" + - "**/{Formula,Casks}/**/*.rb" + # only used internally Homebrew/MoveToExtendOS: Enabled: false diff --git a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb index a99c9c5452e29..ed234c96992b9 100644 --- a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb +++ b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb @@ -9,15 +9,14 @@ module Homebrew class NoFileutilsRmrf < Base extend AutoCorrector - MSG = "Use `FileUtils.rm` or `FileUtils.rm_r` instead of `FileUtils.rm_rf`, `FileUtils.rm_f`, " \ - "or `{FileUtils,Pathname}.rmtree`." + MSG = "Use `rm` or `rm_r` instead of `rm_rf`, `rm_f`, or `rmtree`." - def_node_matcher :fileutils_rm_r_f?, <<~PATTERN - (send (const {nil? cbase} :FileUtils) {:rm_rf :rm_f :rmtree} ...) + def_node_matcher :self_rm_r_f_tree?, <<~PATTERN + (send (self) {:rm_rf :rm_f :rmtree} ...) PATTERN - def_node_matcher :pathname_rmtree?, <<~PATTERN - (send (const {nil? cbase} :Pathname) :rmtree ...) + def_node_matcher :plain_rm_r_f_tree?, <<~PATTERN + (send nil? {:rm_rf :rm_f :rmtree} ...) PATTERN def on_send(node) @@ -30,12 +29,12 @@ def on_send(node) "rm" end - corrector.replace(node.loc.expression, "FileUtils.#{new_method}(#{node.arguments.first.source})") + corrector.replace(node.loc.expression, "#{new_method}(#{node.arguments.first.source})") end end def neither_rm_rf_nor_rmtree?(node) - !fileutils_rm_r_f?(node) && !pathname_rmtree?(node) + !self_rm_r_f_tree?(node) && !plain_rm_r_f_tree?(node) end end end diff --git a/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi b/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi new file mode 100644 index 0000000000000..c6bc07663b851 --- /dev/null +++ b/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi @@ -0,0 +1,14 @@ +# typed: true + +# DO NOT EDIT MANUALLY +# This is an autogenerated file for dynamic methods in `RuboCop::Cop::Homebrew::NoFileutilsRmrf`. +# Please instead update this file by running `bin/tapioca dsl RuboCop::Cop::Homebrew::NoFileutilsRmrf`. + + +class RuboCop::Cop::Homebrew::NoFileutilsRmrf + sig { params(node: RuboCop::AST::Node, kwargs: T.untyped, block: T.untyped).returns(T.untyped) } + def plain_rm_r_f_tree?(node, **kwargs, &block); end + + sig { params(node: RuboCop::AST::Node, kwargs: T.untyped, block: T.untyped).returns(T.untyped) } + def self_rm_r_f_tree?(node, **kwargs, &block); end +end diff --git a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb index 4581fb2dbba70..749808ccbd8ab 100644 --- a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb +++ b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb @@ -5,78 +5,59 @@ RSpec.describe RuboCop::Cop::Homebrew::NoFileutilsRmrf do subject(:cop) { described_class.new } - describe "FileUtils.rm_rf" do + describe "rm_rf" do it "registers an offense" do expect_offense(<<~RUBY) - FileUtils.rm_rf("path/to/directory") - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + rm_rf("path/to/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} RUBY end it "autocorrects" do corrected = autocorrect_source(<<~RUBY) - FileUtils.rm_rf("path/to/directory") + rm_rf("path/to/directory") RUBY expect(corrected).to eq(<<~RUBY) - FileUtils.rm_r("path/to/directory") + rm_r("path/to/directory") RUBY end end - describe "FileUtils.rm_f" do + describe "rm_f" do it "registers an offense" do expect_offense(<<~RUBY) - FileUtils.rm_f("path/to/directory") - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + rm_f("path/to/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} RUBY end it "autocorrects" do corrected = autocorrect_source(<<~RUBY) - FileUtils.rm_f("path/to/directory") + rm_f("path/to/directory") RUBY expect(corrected).to eq(<<~RUBY) - FileUtils.rm("path/to/directory") + rm("path/to/directory") RUBY end end - describe "FileUtils.rmtree" do + describe "rmtree" do it "registers an offense" do expect_offense(<<~RUBY) - FileUtils.rmtree("path/to/directory") - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + rmtree("path/to/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} RUBY end it "autocorrects" do corrected = autocorrect_source(<<~RUBY) - FileUtils.rmtree("path/to/directory") + rmtree("path/to/directory") RUBY expect(corrected).to eq(<<~RUBY) - FileUtils.rm_r("path/to/directory") - RUBY - end - end - - describe "Pathname.rmtree" do - it "registers an offense" do - expect_offense(<<~RUBY) - Pathname.rmtree("path/to/directory") - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} - RUBY - end - - it "autocorrects" do - corrected = autocorrect_source(<<~RUBY) - Pathname.rmtree("path/to/directory") - RUBY - - expect(corrected).to eq(<<~RUBY) - FileUtils.rm_r("path/to/directory") + rm_r("path/to/directory") RUBY end end From 0889df837a7a1eb1d5af0bf68e5cd3de18a037c1 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 14 Jul 2024 14:13:37 -0400 Subject: [PATCH 07/10] Casks use `FileUtils.rm_rf` & `Pathname.rmtree` still --- Library/Homebrew/rubocops/no_fileutils_rmrf.rb | 14 ++++++++++++-- .../rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi | 6 ++++++ .../test/rubocops/no_fileutils_rmrf_spec.rb | 12 ++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb index ed234c96992b9..cafeda7accd6f 100644 --- a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb +++ b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb @@ -11,6 +11,14 @@ class NoFileutilsRmrf < Base MSG = "Use `rm` or `rm_r` instead of `rm_rf`, `rm_f`, or `rmtree`." + def_node_matcher :fileutils_rm_r_f_tree?, <<~PATTERN + (send (const {nil? cbase} :FileUtils) {:rm_rf :rm_f :rmtree} ...) + PATTERN + + def_node_matcher :pathname_rm_r_f_tree?, <<~PATTERN + (send (const {nil? cbase} :Pathname) :rmtree ...) + PATTERN + def_node_matcher :self_rm_r_f_tree?, <<~PATTERN (send (self) {:rm_rf :rm_f :rmtree} ...) PATTERN @@ -23,18 +31,20 @@ def on_send(node) return if neither_rm_rf_nor_rmtree?(node) add_offense(node) do |corrector| + class_name = "FileUtils." if fileutils_rm_r_f_tree?(node) || pathname_rm_r_f_tree?(node) new_method = if node.method?(:rm_rf) || node.method?(:rmtree) "rm_r" else "rm" end - corrector.replace(node.loc.expression, "#{new_method}(#{node.arguments.first.source})") + corrector.replace(node.loc.expression, "#{class_name}#{new_method}(#{node.arguments.first.source})") end end def neither_rm_rf_nor_rmtree?(node) - !self_rm_r_f_tree?(node) && !plain_rm_r_f_tree?(node) + !self_rm_r_f_tree?(node) && !plain_rm_r_f_tree?(node) && + !fileutils_rm_r_f_tree?(node) && !pathname_rm_r_f_tree?(node) end end end diff --git a/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi b/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi index c6bc07663b851..6c6f3c1db7eae 100644 --- a/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi +++ b/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi @@ -6,6 +6,12 @@ class RuboCop::Cop::Homebrew::NoFileutilsRmrf + sig { params(node: RuboCop::AST::Node, kwargs: T.untyped, block: T.untyped).returns(T.untyped) } + def fileutils_rm_r_f_tree?(node, **kwargs, &block); end + + sig { params(node: RuboCop::AST::Node, kwargs: T.untyped, block: T.untyped).returns(T.untyped) } + def pathname_rm_r_f_tree?(node, **kwargs, &block); end + sig { params(node: RuboCop::AST::Node, kwargs: T.untyped, block: T.untyped).returns(T.untyped) } def plain_rm_r_f_tree?(node, **kwargs, &block); end diff --git a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb index 749808ccbd8ab..93d2f2be78d4f 100644 --- a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb +++ b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb @@ -10,16 +10,20 @@ expect_offense(<<~RUBY) rm_rf("path/to/directory") ^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + FileUtils.rm_rf("path/to/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} RUBY end it "autocorrects" do corrected = autocorrect_source(<<~RUBY) rm_rf("path/to/directory") + FileUtils.rm_rf("path/to/other/directory") RUBY expect(corrected).to eq(<<~RUBY) rm_r("path/to/directory") + FileUtils.rm_r("path/to/other/directory") RUBY end end @@ -29,16 +33,20 @@ expect_offense(<<~RUBY) rm_f("path/to/directory") ^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + FileUtils.rm_f("path/to/other/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} RUBY end it "autocorrects" do corrected = autocorrect_source(<<~RUBY) rm_f("path/to/directory") + FileUtils.rm_f("path/to/other/directory") RUBY expect(corrected).to eq(<<~RUBY) rm("path/to/directory") + FileUtils.rm("path/to/other/directory") RUBY end end @@ -48,16 +56,20 @@ expect_offense(<<~RUBY) rmtree("path/to/directory") ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + Pathname.rmtree("path/to/other/directory") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} RUBY end it "autocorrects" do corrected = autocorrect_source(<<~RUBY) rmtree("path/to/directory") + Pathname.rmtree("path/to/other/directory") RUBY expect(corrected).to eq(<<~RUBY) rm_r("path/to/directory") + FileUtils.rm_r("path/to/other/directory") RUBY end end From 83e21fba1196518b5fae4ee2f05415f479d6ef47 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Sun, 14 Jul 2024 22:34:34 -0400 Subject: [PATCH 08/10] rubocop/no_fileutils_rmrf: Handle `rmtree` as an instance method --- Library/Homebrew/rubocops/no_fileutils_rmrf.rb | 18 ++++++++++++------ .../cop/homebrew/no_fileutils_rmrf.rbi | 2 +- .../test/rubocops/no_fileutils_rmrf_spec.rb | 11 +++++++---- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb index cafeda7accd6f..981f5e916e28c 100644 --- a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb +++ b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb @@ -4,7 +4,7 @@ module RuboCop module Cop module Homebrew - # This cop checks for the use of `FileUtils.rm_f`, `FileUtils.rm_rf`, or `{FileUtils,Pathname}.rmtree` + # This cop checks for the use of `FileUtils.rm_f`, `FileUtils.rm_rf`, or `{FileUtils,instance}.rmtree` # and recommends the safer versions. class NoFileutilsRmrf < Base extend AutoCorrector @@ -15,8 +15,8 @@ class NoFileutilsRmrf < Base (send (const {nil? cbase} :FileUtils) {:rm_rf :rm_f :rmtree} ...) PATTERN - def_node_matcher :pathname_rm_r_f_tree?, <<~PATTERN - (send (const {nil? cbase} :Pathname) :rmtree ...) + def_node_matcher :instance_rmtree?, <<~PATTERN + (send (lvar ...) :rmtree ...) PATTERN def_node_matcher :self_rm_r_f_tree?, <<~PATTERN @@ -31,20 +31,26 @@ def on_send(node) return if neither_rm_rf_nor_rmtree?(node) add_offense(node) do |corrector| - class_name = "FileUtils." if fileutils_rm_r_f_tree?(node) || pathname_rm_r_f_tree?(node) + class_name = "FileUtils." if fileutils_rm_r_f_tree?(node) || instance_rmtree?(node) new_method = if node.method?(:rm_rf) || node.method?(:rmtree) "rm_r" else "rm" end - corrector.replace(node.loc.expression, "#{class_name}#{new_method}(#{node.arguments.first.source})") + args = if instance_rmtree?(node) + node.receiver.source + else + node.arguments.first.source + end + + corrector.replace(node.loc.expression, "#{class_name}#{new_method}(#{args})") end end def neither_rm_rf_nor_rmtree?(node) !self_rm_r_f_tree?(node) && !plain_rm_r_f_tree?(node) && - !fileutils_rm_r_f_tree?(node) && !pathname_rm_r_f_tree?(node) + !fileutils_rm_r_f_tree?(node) && !instance_rmtree?(node) end end end diff --git a/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi b/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi index 6c6f3c1db7eae..a95a8dc7932c2 100644 --- a/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi +++ b/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi @@ -10,7 +10,7 @@ class RuboCop::Cop::Homebrew::NoFileutilsRmrf def fileutils_rm_r_f_tree?(node, **kwargs, &block); end sig { params(node: RuboCop::AST::Node, kwargs: T.untyped, block: T.untyped).returns(T.untyped) } - def pathname_rm_r_f_tree?(node, **kwargs, &block); end + def instance_rmtree?(node, **kwargs, &block); end sig { params(node: RuboCop::AST::Node, kwargs: T.untyped, block: T.untyped).returns(T.untyped) } def plain_rm_r_f_tree?(node, **kwargs, &block); end diff --git a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb index 93d2f2be78d4f..2774696b9e743 100644 --- a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb +++ b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb @@ -56,20 +56,23 @@ expect_offense(<<~RUBY) rmtree("path/to/directory") ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} - Pathname.rmtree("path/to/other/directory") - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + other_dir = Pathname("path/to/other/directory") + other_dir.rmtree + ^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} RUBY end it "autocorrects" do corrected = autocorrect_source(<<~RUBY) rmtree("path/to/directory") - Pathname.rmtree("path/to/other/directory") + other_dir = Pathname("path/to/other/directory") + other_dir.rmtree RUBY expect(corrected).to eq(<<~RUBY) rm_r("path/to/directory") - FileUtils.rm_r("path/to/other/directory") + other_dir = Pathname("path/to/other/directory") + FileUtils.rm_r(other_dir) RUBY end end From 7404735654cecb5f4139ecc7f78ce86bd355b326 Mon Sep 17 00:00:00 2001 From: Issy Long Date: Mon, 15 Jul 2024 14:05:36 -0400 Subject: [PATCH 09/10] rubocops/no_fileutils_rmrf: Fix `rmtree` on a method returning Pathname - Tidy up the node matchers. Either `FileUtils.rm_rf` or `rm_rf` on a `Pathname` instance or `self`. --- .../Homebrew/rubocops/no_fileutils_rmrf.rb | 29 ++++++++++--------- .../cop/homebrew/no_fileutils_rmrf.rbi | 8 ++--- .../test/rubocops/no_fileutils_rmrf_spec.rb | 13 +++++++++ 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb index 981f5e916e28c..9828d12c306a4 100644 --- a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb +++ b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb @@ -11,35 +11,38 @@ class NoFileutilsRmrf < Base MSG = "Use `rm` or `rm_r` instead of `rm_rf`, `rm_f`, or `rmtree`." - def_node_matcher :fileutils_rm_r_f_tree?, <<~PATTERN - (send (const {nil? cbase} :FileUtils) {:rm_rf :rm_f :rmtree} ...) + def_node_matcher :any_receiver_rm_r_f?, <<~PATTERN + (send + {(const {nil? cbase} :FileUtils) (self)} + {:rm_rf :rm_f} + ...) PATTERN - def_node_matcher :instance_rmtree?, <<~PATTERN - (send (lvar ...) :rmtree ...) + def_node_matcher :no_receiver_rm_r_f?, <<~PATTERN + (send nil? {:rm_rf :rm_f} ...) PATTERN - def_node_matcher :self_rm_r_f_tree?, <<~PATTERN - (send (self) {:rm_rf :rm_f :rmtree} ...) + def_node_matcher :no_receiver_rmtree?, <<~PATTERN + (send nil? :rmtree ...) PATTERN - def_node_matcher :plain_rm_r_f_tree?, <<~PATTERN - (send nil? {:rm_rf :rm_f :rmtree} ...) + def_node_matcher :any_receiver_rmtree?, <<~PATTERN + (send !nil? :rmtree ...) PATTERN def on_send(node) return if neither_rm_rf_nor_rmtree?(node) add_offense(node) do |corrector| - class_name = "FileUtils." if fileutils_rm_r_f_tree?(node) || instance_rmtree?(node) + class_name = "FileUtils." if any_receiver_rm_r_f?(node) || any_receiver_rmtree?(node) new_method = if node.method?(:rm_rf) || node.method?(:rmtree) "rm_r" else "rm" end - args = if instance_rmtree?(node) - node.receiver.source + args = if any_receiver_rmtree?(node) + node.receiver&.source || node.arguments.first&.source else node.arguments.first.source end @@ -49,8 +52,8 @@ def on_send(node) end def neither_rm_rf_nor_rmtree?(node) - !self_rm_r_f_tree?(node) && !plain_rm_r_f_tree?(node) && - !fileutils_rm_r_f_tree?(node) && !instance_rmtree?(node) + !any_receiver_rm_r_f?(node) && !no_receiver_rm_r_f?(node) && + !any_receiver_rmtree?(node) && !no_receiver_rmtree?(node) end end end diff --git a/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi b/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi index a95a8dc7932c2..b6d9c6a094994 100644 --- a/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi +++ b/Library/Homebrew/sorbet/rbi/dsl/rubo_cop/cop/homebrew/no_fileutils_rmrf.rbi @@ -7,14 +7,14 @@ class RuboCop::Cop::Homebrew::NoFileutilsRmrf sig { params(node: RuboCop::AST::Node, kwargs: T.untyped, block: T.untyped).returns(T.untyped) } - def fileutils_rm_r_f_tree?(node, **kwargs, &block); end + def any_receiver_rm_r_f?(node, **kwargs, &block); end sig { params(node: RuboCop::AST::Node, kwargs: T.untyped, block: T.untyped).returns(T.untyped) } - def instance_rmtree?(node, **kwargs, &block); end + def any_receiver_rmtree?(node, **kwargs, &block); end sig { params(node: RuboCop::AST::Node, kwargs: T.untyped, block: T.untyped).returns(T.untyped) } - def plain_rm_r_f_tree?(node, **kwargs, &block); end + def no_receiver_rm_r_f?(node, **kwargs, &block); end sig { params(node: RuboCop::AST::Node, kwargs: T.untyped, block: T.untyped).returns(T.untyped) } - def self_rm_r_f_tree?(node, **kwargs, &block); end + def no_receiver_rmtree?(node, **kwargs, &block); end end diff --git a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb index 2774696b9e743..128d3bd3e5b75 100644 --- a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb +++ b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb @@ -59,6 +59,11 @@ other_dir = Pathname("path/to/other/directory") other_dir.rmtree ^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + def buildpath + Pathname("path/to/yet/another/directory") + end + buildpath.rmtree + ^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} RUBY end @@ -67,12 +72,20 @@ rmtree("path/to/directory") other_dir = Pathname("path/to/other/directory") other_dir.rmtree + def buildpath + Pathname("path/to/yet/another/directory") + end + buildpath.rmtree RUBY expect(corrected).to eq(<<~RUBY) rm_r("path/to/directory") other_dir = Pathname("path/to/other/directory") FileUtils.rm_r(other_dir) + def buildpath + Pathname("path/to/yet/another/directory") + end + FileUtils.rm_r(buildpath) RUBY end end From 0872966c27096f55586fb482e6c8ac5ad5e3f50d Mon Sep 17 00:00:00 2001 From: Issy Long Date: Mon, 15 Jul 2024 15:09:55 -0400 Subject: [PATCH 10/10] Avoid double parentheses for eg. `(path/here/).rmtree` corrections --- Library/Homebrew/rubocops/no_fileutils_rmrf.rb | 4 ++-- Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb index 9828d12c306a4..b1e22cf30f9f9 100644 --- a/Library/Homebrew/rubocops/no_fileutils_rmrf.rb +++ b/Library/Homebrew/rubocops/no_fileutils_rmrf.rb @@ -46,8 +46,8 @@ def on_send(node) else node.arguments.first.source end - - corrector.replace(node.loc.expression, "#{class_name}#{new_method}(#{args})") + args = "(#{args})" unless args.start_with?("(") + corrector.replace(node.loc.expression, "#{class_name}#{new_method}#{args}") end end diff --git a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb index 128d3bd3e5b75..bc8b4aa99f6fa 100644 --- a/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb +++ b/Library/Homebrew/test/rubocops/no_fileutils_rmrf_spec.rb @@ -64,6 +64,8 @@ def buildpath end buildpath.rmtree ^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} + (path/"here").rmtree + ^^^^^^^^^^^^^^^^^^^^ Homebrew/NoFileutilsRmrf: #{RuboCop::Cop::Homebrew::NoFileutilsRmrf::MSG} RUBY end @@ -76,6 +78,7 @@ def buildpath Pathname("path/to/yet/another/directory") end buildpath.rmtree + (path/"here").rmtree RUBY expect(corrected).to eq(<<~RUBY) @@ -86,6 +89,7 @@ def buildpath Pathname("path/to/yet/another/directory") end FileUtils.rm_r(buildpath) + FileUtils.rm_r(path/"here") RUBY end end