From 91ad24b8761d22c6c2cad933eae7c17198a2cfdd Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Tue, 28 Feb 2023 16:37:13 -0800 Subject: [PATCH] Remove Array#to_sentence monkey-patch --- Library/Homebrew/cask/artifact/pkg.rb | 2 +- Library/Homebrew/cask/auditor.rb | 5 ++- Library/Homebrew/cask/cmd/uninstall.rb | 2 +- Library/Homebrew/cask/installer.rb | 2 +- Library/Homebrew/cli/parser.rb | 12 ++--- Library/Homebrew/cmd/developer.rb | 5 ++- Library/Homebrew/cmd/update-report.rb | 2 +- Library/Homebrew/dev-cmd/audit.rb | 2 +- Library/Homebrew/dev-cmd/contributions.rb | 3 +- .../Homebrew/dev-cmd/update-maintainers.rb | 2 +- Library/Homebrew/dev-cmd/update-sponsors.rb | 2 +- Library/Homebrew/diagnostic.rb | 2 +- Library/Homebrew/exceptions.rb | 8 ++-- Library/Homebrew/formula_installer.rb | 4 +- Library/Homebrew/global.rb | 3 +- Library/Homebrew/rubocops/all.rb | 3 -- Library/Homebrew/rubocops/components_order.rb | 3 ++ Library/Homebrew/tap.rb | 4 +- Library/Homebrew/uninstall.rb | 8 ++-- Library/Homebrew/utils.rb | 45 +++++++++++++++++++ 20 files changed, 85 insertions(+), 34 deletions(-) diff --git a/Library/Homebrew/cask/artifact/pkg.rb b/Library/Homebrew/cask/artifact/pkg.rb index 924f731ae4..8d903922ca 100644 --- a/Library/Homebrew/cask/artifact/pkg.rb +++ b/Library/Homebrew/cask/artifact/pkg.rb @@ -46,7 +46,7 @@ module Cask pkgs = Pathname.glob(cask.staged_path/"**"/"*.pkg").map { |path| path.relative_path_from(cask.staged_path) } message = "Could not find PKG source file '#{pkg}'" - message += ", found #{pkgs.map { |path| "'#{path}'" }.to_sentence} instead" if pkgs.any? + message += ", found #{::Utils.to_sentence(pkgs.map { |path| "'#{path}'" })} instead" if pkgs.any? message += "." raise CaskError, message diff --git a/Library/Homebrew/cask/auditor.rb b/Library/Homebrew/cask/auditor.rb index 0969a7dc30..80bdb5f839 100644 --- a/Library/Homebrew/cask/auditor.rb +++ b/Library/Homebrew/cask/auditor.rb @@ -57,7 +57,8 @@ module Cask if !language && language_blocks sample_languages = if language_blocks.length > LANGUAGE_BLOCK_LIMIT && !@audit_new_cask sample_keys = language_blocks.keys.sample(LANGUAGE_BLOCK_LIMIT) - ohai "Auditing a sample of available languages: #{sample_keys.map { |lang| lang[0].to_s }.to_sentence}" + sample_keys_sentence = ::Utils.to_sentence(sample_keys.map { |lang| lang[0].to_s }) + ohai "Auditing a sample of available languages: #{sameple_keys_sentence}" language_blocks.select { |k| sample_keys.include?(k) } else language_blocks @@ -67,7 +68,7 @@ module Cask audit = audit_languages(l) summary = audit.summary(include_passed: output_passed?, include_warnings: output_warnings?) if summary.present? && output_summary?(audit) - ohai "Auditing language: #{l.map { |lang| "'#{lang}'" }.to_sentence}" if output_summary? + ohai "Auditing language: #{::Utils.to_sentence(l.map { |lang| "'#{lang}'" })}" if output_summary? puts summary end warnings += audit.warnings diff --git a/Library/Homebrew/cask/cmd/uninstall.rb b/Library/Homebrew/cask/cmd/uninstall.rb index 1700482a65..e6874f2666 100644 --- a/Library/Homebrew/cask/cmd/uninstall.rb +++ b/Library/Homebrew/cask/cmd/uninstall.rb @@ -46,7 +46,7 @@ module Cask next if (versions = cask.versions).empty? puts <<~EOS - #{cask} #{versions.to_sentence} #{(versions.count == 1) ? "is" : "are"} still installed. + #{cask} #{::Utils.to_sentence(versions)} #{(versions.count == 1) ? "is" : "are"} still installed. Remove #{(versions.count == 1) ? "it" : "them all"} with `brew uninstall --cask --force #{cask}`. EOS end diff --git a/Library/Homebrew/cask/installer.rb b/Library/Homebrew/cask/installer.rb index 03e49a9744..465cf18982 100644 --- a/Library/Homebrew/cask/installer.rb +++ b/Library/Homebrew/cask/installer.rb @@ -306,7 +306,7 @@ module Cask rescue TSort::Cyclic strongly_connected_components = graph.strongly_connected_components.sort_by(&:count) cyclic_dependencies = strongly_connected_components.last - [@cask] - raise CaskCyclicDependencyError.new(@cask.token, cyclic_dependencies.to_sentence) + raise CaskCyclicDependencyError.new(@cask.token, ::Utils.to_sentence(cyclic_dependencies)) end end diff --git a/Library/Homebrew/cli/parser.rb b/Library/Homebrew/cli/parser.rb index 568ab62d06..64d19f8ef2 100644 --- a/Library/Homebrew/cli/parser.rb +++ b/Library/Homebrew/cli/parser.rb @@ -683,8 +683,8 @@ module Homebrew "This command does not take named arguments." else types << :named if types.empty? - arg_types = types.map { |type| type.to_s.tr("_", " ") } - .to_sentence two_words_connector: " or ", last_word_connector: " or " + arg_types = Utils.to_sentence(types.map { |type| type.to_s.tr("_", " ") }, + two_words_connector: " or ", last_word_connector: " or ") "This command does not take more than #{maximum} #{arg_types} #{Utils.pluralize("argument", maximum)}." end @@ -697,8 +697,8 @@ module Homebrew sig { params(minimum: Integer, types: T::Array[Symbol]).void } def initialize(minimum, types: []) types << :named if types.empty? - arg_types = types.map { |type| type.to_s.tr("_", " ") } - .to_sentence two_words_connector: " or ", last_word_connector: " or " + arg_types = Utils.to_sentence(types.map { |type| type.to_s.tr("_", " ") }, + two_words_connector: " or ", last_word_connector: " or ") super "This command requires at least #{minimum} #{arg_types} #{Utils.pluralize("argument", minimum)}." end @@ -710,8 +710,8 @@ module Homebrew sig { params(minimum: Integer, types: T::Array[Symbol]).void } def initialize(minimum, types: []) types << :named if types.empty? - arg_types = types.map { |type| type.to_s.tr("_", " ") } - .to_sentence two_words_connector: " or ", last_word_connector: " or " + arg_types = Utils.to_sentence(types.map { |type| type.to_s.tr("_", " ") }, + two_words_connector: " or ", last_word_connector: " or ") super "This command requires exactly #{minimum} #{arg_types} #{Utils.pluralize("argument", minimum)}." end diff --git a/Library/Homebrew/cmd/developer.rb b/Library/Homebrew/cmd/developer.rb index 131f18cef5..028010707c 100755 --- a/Library/Homebrew/cmd/developer.rb +++ b/Library/Homebrew/cmd/developer.rb @@ -40,7 +40,8 @@ module Homebrew case args.named.first when nil, "state" if env_vars.any? - puts "Developer mode is enabled because #{env_vars.to_sentence} #{(env_vars.count == 1) ? "is" : "are"} set." + env_vars_str = Utils.to_sentence(env_vars) + puts "Developer mode is enabled because #{env_vars_str} #{(env_vars.count == 1) ? "is" : "are"} set." elsif Homebrew::Settings.read("devcmdrun") == "true" puts "Developer mode is enabled." else @@ -50,7 +51,7 @@ module Homebrew Homebrew::Settings.write "devcmdrun", true when "off" Homebrew::Settings.delete "devcmdrun" - puts "To fully disable developer mode, you must unset #{env_vars.to_sentence}." if env_vars.any? + puts "To fully disable developer mode, you must unset #{Utils.to_sentence(env_vars)}." if env_vars.any? else raise UsageError, "unknown subcommand: #{args.named.first}" end diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb index 22306001bf..e75ede46ec 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -234,7 +234,7 @@ module Homebrew unless updated_taps.empty? auto_update_header args: args noun = Utils.pluralize("tap", updated_taps.count) - puts "Updated #{updated_taps.count} #{noun} (#{updated_taps.to_sentence})." + puts "Updated #{updated_taps.count} #{noun} (#{Utils.to_sentence(updated_taps)})." updated = true end diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index c5dac1cb53..40da9791ec 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -286,7 +286,7 @@ module Homebrew error_sources << "#{cask_count} #{Utils.pluralize("cask", cask_count)}" if cask_count.positive? error_sources << "#{tap_count} #{Utils.pluralize("tap", tap_count)}" if tap_count.positive? - errors_summary += " in #{error_sources.to_sentence}" if error_sources.any? + errors_summary += " in #{Utils.to_sentence(error_sources)}" if error_sources.any? errors_summary += " detected" diff --git a/Library/Homebrew/dev-cmd/contributions.rb b/Library/Homebrew/dev-cmd/contributions.rb index 9fe19f8b59..4129f41e43 100755 --- a/Library/Homebrew/dev-cmd/contributions.rb +++ b/Library/Homebrew/dev-cmd/contributions.rb @@ -18,6 +18,7 @@ module Homebrew sig { returns(CLI::Parser) } def contributions_args + supported_repos_sentence = Utils.to_sentence(SUPPORTED_REPOS.map { |t| "`#{t}`" }) Homebrew::CLI::Parser.new do usage_banner "`contributions` [--user=] [<--repositories>`=`] [<--csv>]" description <<~EOS @@ -26,7 +27,7 @@ module Homebrew comma_array "--repositories", description: "Specify a comma-separated (no spaces) list of repositories to search. " \ - "Supported repositories: #{SUPPORTED_REPOS.map { |t| "`#{t}`" }.to_sentence}. " \ + "Supported repositories: #{supported_repos_sentence}. " \ "Omitting this flag, or specifying `--repositories=all`, searches all repositories. " \ "Use `--repositories=primary` to search only the main repositories: brew,core,cask." flag "--from=", diff --git a/Library/Homebrew/dev-cmd/update-maintainers.rb b/Library/Homebrew/dev-cmd/update-maintainers.rb index 2b76426e55..6185a072c4 100644 --- a/Library/Homebrew/dev-cmd/update-maintainers.rb +++ b/Library/Homebrew/dev-cmd/update-maintainers.rb @@ -37,7 +37,7 @@ module Homebrew members.each do |group, hash| hash.slice!(*public_members) hash.each { |login, name| hash[login] = "[#{name}](https://github.com/#{login})" } - sentences[group] = hash.values.sort.to_sentence + sentences[group] = Utils.to_sentence(hash.values.sort) end readme = HOMEBREW_REPOSITORY/"README.md" diff --git a/Library/Homebrew/dev-cmd/update-sponsors.rb b/Library/Homebrew/dev-cmd/update-sponsors.rb index dc5b62b277..93879ce3ac 100644 --- a/Library/Homebrew/dev-cmd/update-sponsors.rb +++ b/Library/Homebrew/dev-cmd/update-sponsors.rb @@ -57,7 +57,7 @@ module Homebrew readme = HOMEBREW_REPOSITORY/"README.md" content = readme.read - content.gsub!(/(Homebrew is generously supported by) .*\Z/m, "\\1 #{named_sponsors.to_sentence}.\n") + content.gsub!(/(Homebrew is generously supported by) .*\Z/m, "\\1 #{Utils.to_sentence(named_sponsors)}.\n") content << "\n#{logo_sponsors.join}\n" if logo_sponsors.presence File.write(readme, content) diff --git a/Library/Homebrew/diagnostic.rb b/Library/Homebrew/diagnostic.rb index 3d1c512a22..4e12603528 100644 --- a/Library/Homebrew/diagnostic.rb +++ b/Library/Homebrew/diagnostic.rb @@ -911,7 +911,7 @@ module Homebrew end) taps = Utils.pluralize("tap", error_tap_paths.count) - "Unable to read from cask #{taps}: #{error_tap_paths.to_sentence}" if error_tap_paths.present? + "Unable to read from cask #{taps}: #{Utils.to_sentence(error_tap_paths)}" if error_tap_paths.present? end def check_cask_load_path diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index 7f8b4f9d6b..56cb1da56b 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -100,7 +100,8 @@ class FormulaOrCaskUnavailableError < RuntimeError similar_formula_names = Formula.fuzzy_search(name) return "" if similar_formula_names.blank? - "Did you mean #{similar_formula_names.to_sentence two_words_connector: " or ", last_word_connector: " or "}?" + "Did you mean #{Utils.to_sentence(similar_formula_names, two_words_connector: " or ", + last_word_connector: " or ")}?" end sig { returns(String) } @@ -570,7 +571,7 @@ class UnbottledError < RuntimeError msg = +<<~EOS The following #{Utils.pluralize("formula", formulae.count, plural: "e")} cannot be installed from #{Utils.pluralize("bottle", formulae.count)} and must be built from source. - #{formulae.to_sentence} + #{Utils.to_sentence(formulae)} EOS msg += "#{DevelopmentTools.installation_instructions}\n" unless DevelopmentTools.installed? msg.freeze @@ -804,7 +805,8 @@ class CyclicDependencyError < RuntimeError def initialize(strongly_connected_components) super <<~EOS The following packages contain cyclic dependencies: - #{strongly_connected_components.select { |packages| packages.count > 1 }.map(&:to_sentence).join("\n ")} + #{strongly_connected_components.select { |packages| packages.count > 1 } + .map { |p| Utils.to_sentence(p) }.join("\n ")} EOS end end diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 12eb8ec499..1af0800d3b 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -652,7 +652,7 @@ class FormulaInstaller puts "All dependencies for #{formula.full_name} are satisfied." elsif !deps.empty? oh1 "Installing dependencies for #{formula.full_name}: " \ - "#{deps.map(&:first).map(&Formatter.method(:identifier)).to_sentence}", + "#{Utils.to_sentence(deps.map(&:first).map(&Formatter.method(:identifier)))}", truncate: false deps.each { |dep, options| install_dependency(dep, options) } end @@ -1163,7 +1163,7 @@ class FormulaInstaller return if deps.empty? oh1 "Fetching dependencies for #{formula.full_name}: " \ - "#{deps.map(&:first).map(&Formatter.method(:identifier)).to_sentence}", + "#{Utils.to_sentence(deps.map(&:first).map(&Formatter.method(:identifier)))}", truncate: false deps.each { |dep, _options| fetch_dependency(dep) } diff --git a/Library/Homebrew/global.rb b/Library/Homebrew/global.rb index c773b8bb0f..fb3d785efa 100644 --- a/Library/Homebrew/global.rb +++ b/Library/Homebrew/global.rb @@ -17,7 +17,8 @@ require "active_support/core_ext/string/filters" require "active_support/core_ext/object/try" require "active_support/core_ext/array/access" require "active_support/core_ext/string/inflections" -require "active_support/core_ext/array/conversions" +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/hash/keys" require "active_support/core_ext/hash/deep_merge" require "active_support/core_ext/file/atomic" require "active_support/core_ext/enumerable" diff --git a/Library/Homebrew/rubocops/all.rb b/Library/Homebrew/rubocops/all.rb index ba9442d61c..96a9f5176c 100644 --- a/Library/Homebrew/rubocops/all.rb +++ b/Library/Homebrew/rubocops/all.rb @@ -1,9 +1,6 @@ # typed: strict # frozen_string_literal: true -# TODO: remove this (and avoid further active support in rubocops) -require "active_support/core_ext/array/conversions" - require_relative "io_read" require_relative "move_to_extend_os" require_relative "shell_commands" diff --git a/Library/Homebrew/rubocops/components_order.rb b/Library/Homebrew/rubocops/components_order.rb index 4661aed6fa..e07af84e11 100644 --- a/Library/Homebrew/rubocops/components_order.rb +++ b/Library/Homebrew/rubocops/components_order.rb @@ -4,6 +4,9 @@ require "ast_constants" require "rubocops/extend/formula_cop" +# TODO: remove this (and avoid further active support in rubocops) +require "active_support/core_ext/array/conversions" + module RuboCop module Cop module FormulaAudit diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index 457fe67726..21bad4bf22 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -326,7 +326,7 @@ class Tap Commands.rebuild_commands_completion_list link_completions_and_manpages - formatted_contents = contents.presence&.to_sentence&.dup&.prepend(" ") + formatted_contents = contents.presence&.then { |c| Utils.to_sentence(c) }&.dup&.prepend(" ") $stderr.puts "Tapped#{formatted_contents} (#{path.abv})." unless quiet CacheStoreDatabase.use(:descriptions) do |db| DescriptionCacheStore.new(db) @@ -414,7 +414,7 @@ class Tap $stderr.puts "Untapping #{name}..." abv = path.abv - formatted_contents = contents.presence&.to_sentence&.dup&.prepend(" ") + formatted_contents = contents.presence&.then { |c| Utils.to_sentence(c) }&.dup&.prepend(" ") CacheStoreDatabase.use(:descriptions) do |db| DescriptionCacheStore.new(db) diff --git a/Library/Homebrew/uninstall.rb b/Library/Homebrew/uninstall.rb index a6f366f448..4e7c9eff8f 100644 --- a/Library/Homebrew/uninstall.rb +++ b/Library/Homebrew/uninstall.rb @@ -52,7 +52,7 @@ module Homebrew if rack.directory? versions = rack.subdirs.map(&:basename) puts <<~EOS - #{keg.name} #{versions.to_sentence} #{(versions.count == 1) ? "is" : "are"} still installed. + #{keg.name} #{Utils.to_sentence(versions)} #{(versions.count == 1) ? "is" : "are"} still installed. To remove all versions, run: brew uninstall --force #{keg.name} EOS @@ -136,7 +136,7 @@ module Homebrew end def are_required_by_deps - "#{(reqs.count == 1) ? "is" : "are"} required by #{deps.to_sentence}, " \ + "#{(reqs.count == 1) ? "is" : "are"} required by #{Utils.to_sentence(deps)}, " \ "which #{(deps.count == 1) ? "is" : "are"} currently installed" end end @@ -145,7 +145,7 @@ module Homebrew class DeveloperDependentsMessage < DependentsMessage def output opoo <<~EOS - #{reqs.to_sentence} #{are_required_by_deps}. + #{Utils.to_sentence(reqs)} #{are_required_by_deps}. You can silence this warning with: #{sample_command} EOS @@ -156,7 +156,7 @@ module Homebrew class NondeveloperDependentsMessage < DependentsMessage def output ofail <<~EOS - Refusing to uninstall #{reqs.to_sentence} + Refusing to uninstall #{Utils.to_sentence(reqs)} because #{(reqs.count == 1) ? "it" : "they"} #{are_required_by_deps}. You can override this and force removal with: #{sample_command} diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index 3ca0e63535..a6435344f0 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -133,4 +133,49 @@ module Utils suffix = (count == 1) ? singular : plural "#{stem}#{suffix}" end + + # Converts the array to a comma-separated sentence where the last element is + # joined by the connector word. + # + # You can pass the following options to change the default behavior. If you + # pass an option key that doesn't exist in the list below, it will raise an + # ArgumentError. + # + # ==== Options + # + # * :words_connector - The sign or word used to join all but the last + # element in arrays with three or more elements (default: ", "). + # * :last_word_connector - The sign or word used to join the last element + # in arrays with three or more elements (default: ", and "). + # * :two_words_connector - The sign or word used to join the elements + # in arrays with two elements (default: " and "). + # + # ==== Examples + # + # [].to_sentence # => "" + # ['one'].to_sentence # => "one" + # ['one', 'two'].to_sentence # => "one and two" + # ['one', 'two', 'three'].to_sentence # => "one, two, and three" + # + # ['one', 'two'].to_sentence(two_words_connector: '-') + # # => "one-two" + # + # ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ') + # # => "one or two or at least three" + sig { + params(array: T::Array[String], words_connector: String, two_words_connector: String, last_word_connector: String) + .returns(String) + } + def self.to_sentence(array, words_connector: ", ", two_words_connector: " and ", last_word_connector: ", and ") + case array.length + when 0 + +"" + when 1 + +(array[0]).to_s + when 2 + +"#{array[0]}#{two_words_connector}#{array[1]}" + else + +"#{array[0...-1].join(words_connector)}#{last_word_connector}#{array[-1]}" + end + end end