diff --git a/Library/Homebrew/cask/cmd/install.rb b/Library/Homebrew/cask/cmd/install.rb index 71d39f491ff65..efd84d93651f8 100644 --- a/Library/Homebrew/cask/cmd/install.rb +++ b/Library/Homebrew/cask/cmd/install.rb @@ -85,7 +85,7 @@ def self.install_casks( if dry_run if (casks_to_install = casks.reject(&:installed?).presence) - plural = "cask".pluralize(casks_to_install.count) + plural = ::Utils.pluralize("cask", casks_to_install.count) ohai "Would install #{casks_to_install.count} #{plural}:" puts casks_to_install.map(&:full_name).join(" ") end @@ -97,7 +97,7 @@ def self.install_casks( .map(&:name) next if dep_names.blank? - plural = "dependency".pluralize(dep_names.count) + plural = ::Utils.pluralize("dependenc", dep_names.count, plural: "ies", singular: "y") ohai "Would install #{dep_names.count} #{plural} for #{cask.full_name}:" puts dep_names.join(" ") end diff --git a/Library/Homebrew/cask/cmd/uninstall.rb b/Library/Homebrew/cask/cmd/uninstall.rb index 1ab2c8ce2d2aa..1700482a65148 100644 --- a/Library/Homebrew/cask/cmd/uninstall.rb +++ b/Library/Homebrew/cask/cmd/uninstall.rb @@ -46,7 +46,7 @@ def self.uninstall_casks(*casks, binaries: nil, force: false, verbose: false) next if (versions = cask.versions).empty? puts <<~EOS - #{cask} #{versions.to_sentence} #{"is".pluralize(versions.count)} still installed. + #{cask} #{versions.to_sentence} #{(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/cmd/upgrade.rb b/Library/Homebrew/cask/cmd/upgrade.rb index b3c87a60d87ca..d4caa561e94ea 100644 --- a/Library/Homebrew/cask/cmd/upgrade.rb +++ b/Library/Homebrew/cask/cmd/upgrade.rb @@ -121,7 +121,7 @@ def self.upgrade_casks( if manual_installer_casks.present? count = manual_installer_casks.count - ofail "Not upgrading #{count} `installer manual` #{"cask".pluralize(count)}." + ofail "Not upgrading #{count} `installer manual` #{::Utils.pluralize("cask", versions.count)}." puts manual_installer_casks.map(&:to_s) outdated_casks -= manual_installer_casks end @@ -142,7 +142,7 @@ def self.upgrade_casks( end verb = dry_run ? "Would upgrade" : "Upgrading" - oh1 "#{verb} #{outdated_casks.count} outdated #{"package".pluralize(outdated_casks.count)}:" + oh1 "#{verb} #{outdated_casks.count} outdated #{::Utils.pluralize("package", outdated_casks.count)}:" caught_exceptions = [] diff --git a/Library/Homebrew/cask/installer.rb b/Library/Homebrew/cask/installer.rb index ceb2c528e5e7a..91f6fc1401214 100644 --- a/Library/Homebrew/cask/installer.rb +++ b/Library/Homebrew/cask/installer.rb @@ -231,7 +231,7 @@ def install_artifacts already_installed_artifacts = [] odebug "Installing artifacts" - odebug "#{artifacts.length} #{"artifact".pluralize(artifacts.length)} defined", artifacts + odebug "#{artifacts.length} #{::Utils.pluralize("artifact", artifacts.length)} defined", artifacts artifacts.each do |artifact| next unless artifact.respond_to?(:install_phase) @@ -460,7 +460,7 @@ def uninstall_artifacts(clear: false) artifacts = @cask.artifacts odebug "Uninstalling artifacts" - odebug "#{artifacts.length} #{"artifact".pluralize(artifacts.length)} defined", artifacts + odebug "#{artifacts.length} #{::Utils.pluralize("artifact", artifacts.length)} defined", artifacts artifacts.each do |artifact| if artifact.respond_to?(:uninstall_phase) diff --git a/Library/Homebrew/cleanup.rb b/Library/Homebrew/cleanup.rb index 39b1484f38f4b..548dbf095a8a2 100644 --- a/Library/Homebrew/cleanup.rb +++ b/Library/Homebrew/cleanup.rb @@ -584,7 +584,7 @@ def self.autoremove(dry_run: false) formulae_names = removable_formulae.map(&:full_name).sort verb = dry_run ? "Would autoremove" : "Autoremoving" - oh1 "#{verb} #{formulae_names.count} unneeded #{"formula".pluralize(formulae_names.count)}:" + oh1 "#{verb} #{formulae_names.count} unneeded #{Utils.pluralize("formula", formulae_names.count, plural: "e")}:" puts formulae_names.join("\n") return if dry_run diff --git a/Library/Homebrew/cli/parser.rb b/Library/Homebrew/cli/parser.rb index 81ca29b28c610..cd3c98f735626 100644 --- a/Library/Homebrew/cli/parser.rb +++ b/Library/Homebrew/cli/parser.rb @@ -684,7 +684,7 @@ def initialize(maximum, types: []) arg_types = types.map { |type| type.to_s.tr("_", " ") } .to_sentence two_words_connector: " or ", last_word_connector: " or " - "This command does not take more than #{maximum} #{arg_types} #{"argument".pluralize(maximum)}." + "This command does not take more than #{maximum} #{arg_types} #{Utils.pluralize("argument", maximum)}." end end end @@ -698,7 +698,7 @@ def initialize(minimum, types: []) arg_types = types.map { |type| type.to_s.tr("_", " ") } .to_sentence two_words_connector: " or ", last_word_connector: " or " - super "This command requires at least #{minimum} #{arg_types} #{"argument".pluralize(minimum)}." + super "This command requires at least #{minimum} #{arg_types} #{Utils.pluralize("argument", minimum)}." end end @@ -711,7 +711,7 @@ def initialize(minimum, types: []) arg_types = types.map { |type| type.to_s.tr("_", " ") } .to_sentence two_words_connector: " or ", last_word_connector: " or " - super "This command requires exactly #{minimum} #{arg_types} #{"argument".pluralize(minimum)}." + super "This command requires exactly #{minimum} #{arg_types} #{Utils.pluralize("argument", minimum)}." end end end diff --git a/Library/Homebrew/cmd/developer.rb b/Library/Homebrew/cmd/developer.rb index e967844b7a201..131f18cef56d8 100755 --- a/Library/Homebrew/cmd/developer.rb +++ b/Library/Homebrew/cmd/developer.rb @@ -40,7 +40,7 @@ def developer case args.named.first when nil, "state" if env_vars.any? - puts "Developer mode is enabled because #{env_vars.to_sentence} #{"is".pluralize(env_vars.count)} set." + puts "Developer mode is enabled because #{env_vars.to_sentence} #{(env_vars.count == 1) ? "is" : "are"} set." elsif Homebrew::Settings.read("devcmdrun") == "true" puts "Developer mode is enabled." else diff --git a/Library/Homebrew/cmd/fetch.rb b/Library/Homebrew/cmd/fetch.rb index 5bbe534ee7b2c..d348b69bf2135 100644 --- a/Library/Homebrew/cmd/fetch.rb +++ b/Library/Homebrew/cmd/fetch.rb @@ -166,7 +166,7 @@ def retry_fetch?(f, args:) if args.retry? && (@fetch_tries[f] < FETCH_MAX_TRIES) wait = 2 ** @fetch_tries[f] remaining = FETCH_MAX_TRIES - @fetch_tries[f] - what = "try".pluralize(remaining) + what = Utils.pluralize("tr", remaining, plural: "ies", singular: "y") ohai "Retrying download in #{wait}s... (#{remaining} #{what} left)" sleep wait diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index 22326122d3ca3..52cc4267175bf 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -124,7 +124,7 @@ def print_statistics return unless HOMEBREW_CELLAR.exist? count = Formula.racks.length - puts "#{count} #{"keg".pluralize(count)}, #{HOMEBREW_CELLAR.dup.abv}" + puts "#{count} #{Utils.pluralize("keg", count)}, #{HOMEBREW_CELLAR.dup.abv}" end sig { params(args: CLI::Args).void } diff --git a/Library/Homebrew/cmd/tap-info.rb b/Library/Homebrew/cmd/tap-info.rb index f72c611abd8de..4a471a8e0193d 100644 --- a/Library/Homebrew/cmd/tap-info.rb +++ b/Library/Homebrew/cmd/tap-info.rb @@ -57,10 +57,10 @@ def print_tap_info(taps) command_count += tap.command_files.size private_count += 1 if tap.private? end - info = "#{tap_count} #{"tap".pluralize(tap_count)}" + info = "#{tap_count} #{Utils.pluralize("tap", tap_count)}" info += ", #{private_count} private" - info += ", #{formula_count} #{"formula".pluralize(formula_count)}" - info += ", #{command_count} #{"command".pluralize(command_count)}" + info += ", #{formula_count} #{Utils.pluralize("formula", formula_count, plural: "e")}" + info += ", #{command_count} #{Utils.pluralize("command", command_count)}" info += ", #{Tap::TAP_DIRECTORY.dup.abv}" if Tap::TAP_DIRECTORY.directory? puts info else diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb index 69b2efeb5db5a..4d548e3d5e1f9 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -199,7 +199,8 @@ def output_update_report unless updated_taps.empty? auto_update_header args: args - puts "Updated #{updated_taps.count} #{"tap".pluralize(updated_taps.count)} (#{updated_taps.to_sentence})." + noun = Utils.pluralize("tap", updated_taps.count) + puts "Updated #{updated_taps.count} #{noun} (#{updated_taps.to_sentence})." updated = true end @@ -584,11 +585,12 @@ def dump(updated_formula_report: true) output_dump_formula_or_cask_report "Outdated Casks", outdated_casks elsif report_all if (changed_formulae = select_formula_or_cask(:M).count) && changed_formulae.positive? - ohai "Modified Formulae", "Modified #{changed_formulae} #{"formula".pluralize(changed_formulae)}." + noun = Utils.pluralize("formula", changed_formulae, plural: "e") + ohai "Modified Formulae", "Modified #{changed_formulae} #{noun}." end if (changed_casks = select_formula_or_cask(:MC).count) && changed_casks.positive? - ohai "Modified Casks", "Modified #{changed_casks} #{"cask".pluralize(changed_casks)}." + ohai "Modified Casks", "Modified #{changed_casks} #{Utils.pluralize("cask", changed_casks)}." end else outdated_formulae = Formula.installed.select(&:outdated?).map(&:name) @@ -609,12 +611,13 @@ def dump(updated_formula_report: true) msg = "" if outdated_formulae.positive? - msg += "#{Tty.bold}#{outdated_formulae}#{Tty.reset} outdated #{"formula".pluralize(outdated_formulae)}" + noun = Utils.pluralize("formula", outdated_formulae, plural: "e") + msg += "#{Tty.bold}#{outdated_formulae}#{Tty.reset} outdated #{noun}" end if outdated_casks.positive? msg += " and " if msg.present? - msg += "#{Tty.bold}#{outdated_casks}#{Tty.reset} outdated #{"cask".pluralize(outdated_casks)}" + msg += "#{Tty.bold}#{outdated_casks}#{Tty.reset} outdated #{Utils.pluralize("cask", outdated_casks)}" end return if msg.blank? diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb index f7012e316543f..94323b369fdca 100644 --- a/Library/Homebrew/cmd/upgrade.rb +++ b/Library/Homebrew/cmd/upgrade.rb @@ -172,7 +172,7 @@ def upgrade_outdated_formulae(formulae, args:) end if !pinned.empty? && !args.ignore_pinned? - ofail "Not upgrading #{pinned.count} pinned #{"package".pluralize(pinned.count)}:" + ofail "Not upgrading #{pinned.count} pinned #{Utils.pluralize("package", pinned.count)}:" puts pinned.map { |f| "#{f.full_specified_name} #{f.pkg_version}" } * ", " end @@ -180,7 +180,7 @@ def upgrade_outdated_formulae(formulae, args:) oh1 "No packages to upgrade" else verb = args.dry_run? ? "Would upgrade" : "Upgrading" - oh1 "#{verb} #{formulae_to_install.count} outdated #{"package".pluralize(formulae_to_install.count)}:" + oh1 "#{verb} #{formulae_to_install.count} outdated #{Utils.pluralize("package", formulae_to_install.count)}:" formulae_upgrades = formulae_to_install.map do |f| if f.optlinked? "#{f.full_specified_name} #{Keg.new(f.opt_prefix).version} -> #{f.pkg_version}" diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index ff0ebb3de8903..c5dac1cb53857 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -277,19 +277,22 @@ def audit if total_problems_count.positive? puts new_formula_problem_lines.map { |s| " #{s}" } - errors_summary = "#{total_problems_count} #{"problem".pluralize(total_problems_count)}" + errors_summary = "#{total_problems_count} #{Utils.pluralize("problem", total_problems_count)}" error_sources = [] - error_sources << "#{formula_count} #{"formula".pluralize(formula_count)}" if formula_count.positive? - error_sources << "#{cask_count} #{"cask".pluralize(cask_count)}" if cask_count.positive? - error_sources << "#{tap_count} #{"tap".pluralize(tap_count)}" if tap_count.positive? + if formula_count.positive? + error_sources << "#{formula_count} #{Utils.pluralize("formula", formula_count, plural: "e")}" + end + 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 += " detected" if corrected_problem_count.positive? - errors_summary += ", #{corrected_problem_count} #{"problem".pluralize(corrected_problem_count)} corrected" + noun = Utils.pluralize("problem", corrected_problem_count) + errors_summary += ", #{corrected_problem_count} #{noun} corrected" end ofail errors_summary diff --git a/Library/Homebrew/dev-cmd/pr-automerge.rb b/Library/Homebrew/dev-cmd/pr-automerge.rb index 4014b9a656dd2..e2e302b6c965e 100644 --- a/Library/Homebrew/dev-cmd/pr-automerge.rb +++ b/Library/Homebrew/dev-cmd/pr-automerge.rb @@ -61,7 +61,7 @@ def pr_automerge return end - ohai "#{prs.count} matching pull #{"request".pluralize(prs.count)}:" + ohai "#{prs.count} matching pull #{Utils.pluralize("request", prs.count)}:" pr_urls = [] prs.each do |pr| puts "#{tap.full_name unless tap.core_tap?}##{pr["number"]}: #{pr["title"]}" diff --git a/Library/Homebrew/diagnostic.rb b/Library/Homebrew/diagnostic.rb index 6b57247b20acb..3d1c512a22592 100644 --- a/Library/Homebrew/diagnostic.rb +++ b/Library/Homebrew/diagnostic.rb @@ -906,11 +906,11 @@ def check_cask_taps 0 end - "#{tap.path} (#{cask_count} #{"cask".pluralize(cask_count)})" + "#{tap.path} (#{cask_count} #{Utils.pluralize("cask", cask_count)})" end end) - taps = "tap".pluralize error_tap_paths.count + taps = Utils.pluralize("tap", error_tap_paths.count) "Unable to read from cask #{taps}: #{error_tap_paths.to_sentence}" if error_tap_paths.present? end diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index cda88f88c92ad..c0b525e1cb607 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -568,7 +568,7 @@ def dump(verbose: false) class UnbottledError < RuntimeError def initialize(formulae) msg = +<<~EOS - The following #{"formula".pluralize(formulae.count)} cannot be installed from #{"bottle".pluralize(formulae.count)} and must be + 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} EOS diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 6d1b16708e892..aa179fbcfa80b 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -52,10 +52,10 @@ def self.clear_cache next if type == :formulary_factory cached_objects.each_value do |klass| - namespace = klass.name.deconstantize - next if namespace.deconstantize != name + namespace = Utils.deconstantize(klass.name) + next if Utils.deconstantize(namespace) != name - remove_const(namespace.demodulize) + remove_const(Utils.demodulize(namespace)) end end diff --git a/Library/Homebrew/install.rb b/Library/Homebrew/install.rb index 86e0f7c5b627d..aedd5723933dd 100644 --- a/Library/Homebrew/install.rb +++ b/Library/Homebrew/install.rb @@ -324,7 +324,7 @@ def install_formulae( if dry_run if (formulae_name_to_install = formulae_to_install.map(&:name)) - plural = "formula".pluralize(formulae_name_to_install.count) + plural = Utils.pluralize("formula", formulae_name_to_install.count, plural: "e") ohai "Would install #{formulae_name_to_install.count} #{plural}:" puts formulae_name_to_install.join(" ") @@ -354,7 +354,7 @@ def install_formula(formula_installer) def print_dry_run_dependencies(formula, dependencies, &block) return if dependencies.empty? - plural = "dependency".pluralize(dependencies.count) + plural = Utils.pluralize("dependenc", dependencies.count, plural: "ies", singular: "y") ohai "Would install #{dependencies.count} #{plural} for #{formula.name}:" formula_names = dependencies.map(&:first).map(&:to_formula).map(&block) puts formula_names.join(" ") diff --git a/Library/Homebrew/livecheck/livecheck.rb b/Library/Homebrew/livecheck/livecheck.rb index 9e2920a77c23e..07c436f3a5f7f 100644 --- a/Library/Homebrew/livecheck/livecheck.rb +++ b/Library/Homebrew/livecheck/livecheck.rb @@ -61,7 +61,7 @@ def livecheck_strategy_names constant = Strategy.const_get(const_symbol) next unless constant.is_a?(Class) - @livecheck_strategy_names[constant] = T.must(constant.name).demodulize + @livecheck_strategy_names[constant] = Utils.demodulize(T.must(constant.name)) end @livecheck_strategy_names.freeze end diff --git a/Library/Homebrew/livecheck/strategy/electron_builder.rb b/Library/Homebrew/livecheck/strategy/electron_builder.rb index 8bb862e1d4259..4be6c35f3e898 100644 --- a/Library/Homebrew/livecheck/strategy/electron_builder.rb +++ b/Library/Homebrew/livecheck/strategy/electron_builder.rb @@ -73,7 +73,8 @@ def self.versions_from_content(content, regex = nil, &block) } def self.find_versions(url:, regex: nil, **_unused, &block) if regex.present? && block.blank? - raise ArgumentError, "#{T.must(name).demodulize} only supports a regex when using a `strategy` block" + raise ArgumentError, + "#{Utils.demodulize(T.must(name))} only supports a regex when using a `strategy` block" end match_data = { matches: {}, regex: regex, url: url } diff --git a/Library/Homebrew/livecheck/strategy/extract_plist.rb b/Library/Homebrew/livecheck/strategy/extract_plist.rb index 2486a545bc82a..842e966571561 100644 --- a/Library/Homebrew/livecheck/strategy/extract_plist.rb +++ b/Library/Homebrew/livecheck/strategy/extract_plist.rb @@ -97,9 +97,12 @@ def self.versions_from_items(items, regex = nil, &block) } def self.find_versions(cask:, url: nil, regex: nil, **_unused, &block) if regex.present? && block.blank? - raise ArgumentError, "#{T.must(name).demodulize} only supports a regex when using a `strategy` block" + raise ArgumentError, + "#{Utils.demodulize(T.must(name))} only supports a regex when using a `strategy` block" + end + unless T.unsafe(cask) + raise ArgumentError, "The #{Utils.demodulize(T.must(name))} strategy only supports casks." end - raise ArgumentError, "The #{T.must(name).demodulize} strategy only supports casks." unless T.unsafe(cask) match_data = { matches: {}, regex: regex, url: url } diff --git a/Library/Homebrew/livecheck/strategy/git.rb b/Library/Homebrew/livecheck/strategy/git.rb index 8b0d6c2d5ab14..1843b3ab9fa8d 100644 --- a/Library/Homebrew/livecheck/strategy/git.rb +++ b/Library/Homebrew/livecheck/strategy/git.rb @@ -103,7 +103,8 @@ def self.versions_from_tags(tags, regex = nil, &block) tags.map do |tag| if regex # Use the first capture group (the version) - tag.scan(regex).first&.first + # This code is not typesafe unless the regex includes a capture group + T.unsafe(tag.scan(regex).first)&.first else # Remove non-digits from the start of the tag and use that as the # version text diff --git a/Library/Homebrew/livecheck/strategy/json.rb b/Library/Homebrew/livecheck/strategy/json.rb index a6353ddd58084..91a7fbe30fd7b 100644 --- a/Library/Homebrew/livecheck/strategy/json.rb +++ b/Library/Homebrew/livecheck/strategy/json.rb @@ -100,7 +100,7 @@ def self.versions_from_content(content, regex = nil, &block) ).returns(T::Hash[Symbol, T.untyped]) } def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **_unused, &block) - raise ArgumentError, "#{T.must(name).demodulize} requires a `strategy` block" if block.blank? + raise ArgumentError, "#{Utils.demodulize(T.must(name))} requires a `strategy` block" if block.blank? match_data = { matches: {}, regex: regex, url: url } return match_data if url.blank? || block.blank? diff --git a/Library/Homebrew/livecheck/strategy/page_match.rb b/Library/Homebrew/livecheck/strategy/page_match.rb index 9b16c8b8c081d..a024bdb55200d 100644 --- a/Library/Homebrew/livecheck/strategy/page_match.rb +++ b/Library/Homebrew/livecheck/strategy/page_match.rb @@ -93,7 +93,7 @@ def self.versions_from_content(content, regex, &block) } def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **_unused, &block) if regex.blank? && block.blank? - raise ArgumentError, "#{T.must(name).demodulize} requires a regex or `strategy` block" + raise ArgumentError, "#{Utils.demodulize(T.must(name))} requires a regex or `strategy` block" end match_data = { matches: {}, regex: regex, url: url } diff --git a/Library/Homebrew/livecheck/strategy/sparkle.rb b/Library/Homebrew/livecheck/strategy/sparkle.rb index 7cf8cd9acf456..5fbb74842b2f4 100644 --- a/Library/Homebrew/livecheck/strategy/sparkle.rb +++ b/Library/Homebrew/livecheck/strategy/sparkle.rb @@ -203,7 +203,8 @@ def self.versions_from_content(content, regex = nil, &block) } def self.find_versions(url:, regex: nil, **_unused, &block) if regex.present? && block.blank? - raise ArgumentError, "#{T.must(name).demodulize} only supports a regex when using a `strategy` block" + raise ArgumentError, + "#{Utils.demodulize(T.must(name))} only supports a regex when using a `strategy` block" end match_data = { matches: {}, regex: regex, url: url } diff --git a/Library/Homebrew/sorbet/rbi/gems/activesupport@6.1.7.2.rbi b/Library/Homebrew/sorbet/rbi/gems/activesupport@6.1.7.2.rbi index 3515dbbea3785..8840430c242d5 100644 --- a/Library/Homebrew/sorbet/rbi/gems/activesupport@6.1.7.2.rbi +++ b/Library/Homebrew/sorbet/rbi/gems/activesupport@6.1.7.2.rbi @@ -3415,56 +3415,6 @@ class Regexp::Token < ::Struct end end -class String - include ::Comparable - include ::JSON::Ext::Generator::GeneratorMethods::String - include ::MessagePack::CoreExt - extend ::JSON::Ext::Generator::GeneratorMethods::String::Extend - - def acts_like_string?; end - def as_json(options = T.unsafe(nil)); end - def at(position); end - def blank?; end - def camelcase(first_letter = T.unsafe(nil)); end - def camelize(first_letter = T.unsafe(nil)); end - def classify; end - def constantize; end - def dasherize; end - def deconstantize; end - def demodulize; end - def first(limit = T.unsafe(nil)); end - def foreign_key(separate_class_name_and_id_with_underscore = T.unsafe(nil)); end - def from(position); end - def html_safe; end - def humanize(capitalize: T.unsafe(nil), keep_id_suffix: T.unsafe(nil)); end - def is_utf8?; end - def last(limit = T.unsafe(nil)); end - def mb_chars; end - def parameterize(separator: T.unsafe(nil), preserve_case: T.unsafe(nil), locale: T.unsafe(nil)); end - def pluralize(count = T.unsafe(nil), locale = T.unsafe(nil)); end - def remove(*patterns); end - def remove!(*patterns); end - def safe_constantize; end - def singularize(locale = T.unsafe(nil)); end - def squish; end - def squish!; end - def tableize; end - def titlecase(keep_id_suffix: T.unsafe(nil)); end - def titleize(keep_id_suffix: T.unsafe(nil)); end - def to(position); end - def to_date; end - def to_datetime; end - def to_time(form = T.unsafe(nil)); end - def truncate(truncate_at, options = T.unsafe(nil)); end - def truncate_bytes(truncate_at, omission: T.unsafe(nil)); end - def truncate_words(words_count, options = T.unsafe(nil)); end - def underscore; end - def upcase_first; end -end - -String::BLANK_RE = T.let(T.unsafe(nil), Regexp) -String::ENCODED_BLANKS = T.let(T.unsafe(nil), Concurrent::Map) - class Struct include ::Enumerable diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index f165ffcc4aed0..457fe6772613f 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -475,15 +475,15 @@ def contents contents = [] if (command_count = command_files.count).positive? - contents << "#{command_count} #{"command".pluralize(command_count)}" + contents << "#{command_count} #{Utils.pluralize("command", command_count)}" end if (cask_count = cask_files.count).positive? - contents << "#{cask_count} #{"cask".pluralize(cask_count)}" + contents << "#{cask_count} #{Utils.pluralize("cask", cask_count)}" end if (formula_count = formula_files.count).positive? - contents << "#{formula_count} #{"formula".pluralize(formula_count)}" + contents << "#{formula_count} #{Utils.pluralize("formula", formula_count, plural: "e")}" end contents diff --git a/Library/Homebrew/test/utils_spec.rb b/Library/Homebrew/test/utils_spec.rb new file mode 100644 index 0000000000000..c75d21bed85e3 --- /dev/null +++ b/Library/Homebrew/test/utils_spec.rb @@ -0,0 +1,61 @@ +# typed: false +# frozen_string_literal: true + +require "utils" + +describe Utils do + describe ".deconstantize" do + it "removes the rightmost segment from the constant expression in the string" do + expect(described_class.deconstantize("Net::HTTP")).to eq("Net") + expect(described_class.deconstantize("::Net::HTTP")).to eq("::Net") + expect(described_class.deconstantize("String")).to eq("") + expect(described_class.deconstantize("::String")).to eq("") + end + + it "returns an empty string if the namespace is empty" do + expect(described_class.deconstantize("")).to eq("") + expect(described_class.deconstantize("::")).to eq("") + end + end + + describe ".demodulize" do + it "removes the module part from the expression in the string" do + expect(described_class.demodulize("Foo::Bar")).to eq("Bar") + end + + it "returns the string if it does not contain a module expression" do + expect(described_class.demodulize("FooBar")).to eq("FooBar") + end + + it "returns an empty string if the namespace is empty" do + expect(described_class.demodulize("")).to eq("") + expect(described_class.demodulize("::")).to eq("") + end + end + + describe ".pluralize" do + it "combines the stem with the default suffix based on the count" do + expect(described_class.pluralize("foo", 0)).to eq("foos") + expect(described_class.pluralize("foo", 1)).to eq("foo") + expect(described_class.pluralize("foo", 2)).to eq("foos") + end + + it "combines the stem with the singular suffix based on the count" do + expect(described_class.pluralize("foo", 0, singular: "o")).to eq("foos") + expect(described_class.pluralize("foo", 1, singular: "o")).to eq("fooo") + expect(described_class.pluralize("foo", 2, singular: "o")).to eq("foos") + end + + it "combines the stem with the plural suffix based on the count" do + expect(described_class.pluralize("foo", 0, plural: "es")).to eq("fooes") + expect(described_class.pluralize("foo", 1, plural: "es")).to eq("foo") + expect(described_class.pluralize("foo", 2, plural: "es")).to eq("fooes") + end + + it "combines the stem with the singular and plural suffix based on the count" do + expect(described_class.pluralize("foo", 0, singular: "o", plural: "es")).to eq("fooes") + expect(described_class.pluralize("foo", 1, singular: "o", plural: "es")).to eq("fooo") + expect(described_class.pluralize("foo", 2, singular: "o", plural: "es")).to eq("fooes") + end + end +end diff --git a/Library/Homebrew/uninstall.rb b/Library/Homebrew/uninstall.rb index 1d9a1585e4d17..a6f366f448797 100644 --- a/Library/Homebrew/uninstall.rb +++ b/Library/Homebrew/uninstall.rb @@ -52,7 +52,7 @@ def uninstall_kegs(kegs_by_rack, casks: [], force: false, ignore_dependencies: f if rack.directory? versions = rack.subdirs.map(&:basename) puts <<~EOS - #{keg.name} #{versions.to_sentence} #{"is".pluralize(versions.count)} still installed. + #{keg.name} #{versions.to_sentence} #{(versions.count == 1) ? "is" : "are"} still installed. To remove all versions, run: brew uninstall --force #{keg.name} EOS @@ -136,8 +136,8 @@ def sample_command end def are_required_by_deps - "#{"is".pluralize(reqs.count)} required by #{deps.to_sentence}, " \ - "which #{"is".pluralize(deps.count)} currently installed" + "#{(reqs.count == 1) ? "is" : "are"} required by #{deps.to_sentence}, " \ + "which #{(deps.count == 1) ? "is" : "are"} currently installed" end end @@ -157,7 +157,7 @@ class NondeveloperDependentsMessage < DependentsMessage def output ofail <<~EOS Refusing to uninstall #{reqs.to_sentence} - because #{"it".pluralize(reqs.count)} #{are_required_by_deps}. + because #{(reqs.count == 1) ? "it" : "they"} #{are_required_by_deps}. You can override this and force removal with: #{sample_command} EOS diff --git a/Library/Homebrew/upgrade.rb b/Library/Homebrew/upgrade.rb index 6acb840881a19..98757792752a6 100644 --- a/Library/Homebrew/upgrade.rb +++ b/Library/Homebrew/upgrade.rb @@ -299,7 +299,7 @@ def check_installed_dependents( .sort { |a, b| depends_on(a, b) } if pinned_dependents.present? - plural = "dependent".pluralize(pinned_dependents.count) + plural = Utils.pluralize("dependent", pinned_dependents.count) ohai "Not upgrading #{pinned_dependents.count} pinned #{plural}:" puts(pinned_dependents.map do |f| "#{f.full_specified_name} #{f.pkg_version}" @@ -310,8 +310,8 @@ def check_installed_dependents( if upgradeable_dependents.blank? ohai "No outdated dependents to upgrade!" unless dry_run else - dependent_plural = "dependent".pluralize(upgradeable_dependents.count) - formula_plural = "formula".pluralize(installed_formulae.count) + dependent_plural = Utils.pluralize("dependent", upgradeable_dependents.count) + formula_plural = Utils.pluralize("formula", installed_formulae.count, plural: "e") upgrade_verb = dry_run ? "Would upgrade" : "Upgrading" ohai "#{upgrade_verb} #{upgradeable_dependents.count} #{dependent_plural} of upgraded #{formula_plural}:" Upgrade.puts_no_installed_dependents_check_disable_message_if_not_already! @@ -375,7 +375,7 @@ def check_installed_dependents( # Print the pinned dependents. if outdated_pinned_broken_dependents.present? count = outdated_pinned_broken_dependents.count - plural = "dependent".pluralize(outdated_pinned_broken_dependents.count) + plural = Utils.pluralize("dependent", outdated_pinned_broken_dependents.count) onoe "Not reinstalling #{count} broken and outdated, but pinned #{plural}:" $stderr.puts(outdated_pinned_broken_dependents.map do |f| "#{f.full_specified_name} #{f.pkg_version}" @@ -387,7 +387,7 @@ def check_installed_dependents( ohai "No broken dependents to reinstall!" else count = reinstallable_broken_dependents.count - plural = "dependent".pluralize(reinstallable_broken_dependents.count) + plural = Utils.pluralize("dependent", reinstallable_broken_dependents.count) ohai "Reinstalling #{count} #{plural} with broken linkage from source:" Upgrade.puts_no_installed_dependents_check_disable_message_if_not_already! puts reinstallable_broken_dependents.map(&:full_specified_name) diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index d3edd13e4bf2a..df758bafeb346 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -85,3 +85,50 @@ def inject_dump_stats!(the_module, pattern) end # rubocop:enable Style/GlobalVars end + +module Utils + extend T::Sig + + # Removes the rightmost segment from the constant expression in the string. + # + # deconstantize('Net::HTTP') # => "Net" + # deconstantize('::Net::HTTP') # => "::Net" + # deconstantize('String') # => "" + # deconstantize('::String') # => "" + # deconstantize('') # => "" + # + # See also #demodulize. + # @see https://github.com/rails/rails/blob/b0dd7c7/activesupport/lib/active_support/inflector/methods.rb#L247-L258 + # `ActiveSupport::Inflector.deconstantize` + sig { params(path: String).returns(String) } + def self.deconstantize(path) + T.must(path[0, path.rindex("::") || 0]) # implementation based on the one in facets' Module#spacename + end + + # Removes the module part from the expression in the string. + # + # demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections" + # demodulize('Inflections') # => "Inflections" + # demodulize('::Inflections') # => "Inflections" + # demodulize('') # => "" + # + # See also #deconstantize. + # @see https://github.com/rails/rails/blob/b0dd7c7/activesupport/lib/active_support/inflector/methods.rb#L230-L245 + # `ActiveSupport::Inflector.demodulize` + sig { params(path: String).returns(String) } + def self.demodulize(path) + if (i = path.rindex("::")) + T.must(path[(i + 2)..]) + else + path + end + end + + # A lightweight alternative to `ActiveSupport::Inflector.pluralize`: + # Combines `stem` with the `singular` or `plural` suffix based on `count`. + sig { params(stem: String, count: Integer, plural: String, singular: String).returns(String) } + def self.pluralize(stem, count, plural: "s", singular: "") + suffix = (count == 1) ? singular : plural + "#{stem}#{suffix}" + end +end diff --git a/Library/Homebrew/utils/repology.rb b/Library/Homebrew/utils/repology.rb index 0782cd1d49ad3..14396de368cbe 100644 --- a/Library/Homebrew/utils/repology.rb +++ b/Library/Homebrew/utils/repology.rb @@ -53,14 +53,14 @@ def single_package_query(name, repository:) def parse_api_response(limit = nil, last_package = "", repository:) package_term = case repository when HOMEBREW_CORE - "formula" + "formulae" when HOMEBREW_CASK - "cask" + "casks" else - "package" + "packages" end - ohai "Querying outdated #{package_term.pluralize} from Repology" + ohai "Querying outdated #{package_term} from Repology" page_no = 1 outdated_packages = {} @@ -76,7 +76,8 @@ def parse_api_response(limit = nil, last_package = "", repository:) break if (limit && outdated_packages.size >= limit) || response.size <= 1 end - puts "#{outdated_packages.size} outdated #{package_term.pluralize(outdated_packages.size)} found" + package_term = package_term.chop if outdated_packages.size == 1 + puts "#{outdated_packages.size} outdated #{package_term} found" puts outdated_packages.sort.to_h diff --git a/Library/Homebrew/utils/spdx.rb b/Library/Homebrew/utils/spdx.rb index 873cc8310e86d..8d793e6b01ff6 100644 --- a/Library/Homebrew/utils/spdx.rb +++ b/Library/Homebrew/utils/spdx.rb @@ -95,7 +95,7 @@ def license_expression_to_string(license_expression, bracket: false, hash_type: when String license_expression when Symbol - license_expression.to_s.tr("_", " ").titleize + license_expression.to_s.tr("_", " ").gsub(/\b(?