diff --git a/Library/Homebrew/extend/array.rb b/Library/Homebrew/extend/array.rb new file mode 100644 index 0000000000..2c2d1dfa71 --- /dev/null +++ b/Library/Homebrew/extend/array.rb @@ -0,0 +1,64 @@ +# typed: true +# frozen_string_literal: true + +class Array + # Converts the array to a comma-separated sentence where the last element is + # joined by the connector word. + # + # You can pass the following kwargs to change the default behavior: + # + # * :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" + # @see https://github.com/rails/rails/blob/v7.0.4.2/activesupport/lib/active_support/core_ext/array/conversions.rb#L8-L84 + # ActiveSupport Array#to_sentence monkey-patch + # + # Copyright (c) David Heinemeier Hansson + # + # Permission is hereby granted, free of charge, to any person obtaining + # a copy of this software and associated documentation files (the + # "Software"), to deal in the Software without restriction, including + # without limitation the rights to use, copy, modify, merge, publish, + # distribute, sublicense, and/or sell copies of the Software, and to + # permit persons to whom the Software is furnished to do so, subject to + # the following conditions: + # + # The above copyright notice and this permission notice shall be + # included in all copies or substantial portions of the Software. + # + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + def to_sentence(words_connector: ", ", two_words_connector: " and ", last_word_connector: ", and ") + case length + when 0 + +"" + when 1 + # This is not typesafe, if the array contains a BasicObject + +T.unsafe(self[0]).to_s + when 2 + +"#{self[0]}#{two_words_connector}#{self[1]}" + else + +"#{T.must(self[0...-1]).join(words_connector)}#{last_word_connector}#{self[-1]}" + end + end +end diff --git a/Library/Homebrew/global.rb b/Library/Homebrew/global.rb index c773b8bb0f..9666251ced 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" @@ -132,6 +133,7 @@ module Homebrew end require "context" +require "extend/array" require "extend/git_repository" require "extend/pathname" require "extend/predicable" diff --git a/Library/Homebrew/rubocops/all.rb b/Library/Homebrew/rubocops/all.rb index ba9442d61c..ec0fe92957 100644 --- a/Library/Homebrew/rubocops/all.rb +++ b/Library/Homebrew/rubocops/all.rb @@ -1,9 +1,7 @@ # 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 "../extend/array" require_relative "io_read" require_relative "move_to_extend_os" require_relative "shell_commands" diff --git a/Library/Homebrew/test/extend/array_spec.rb b/Library/Homebrew/test/extend/array_spec.rb new file mode 100644 index 0000000000..6654b23a69 --- /dev/null +++ b/Library/Homebrew/test/extend/array_spec.rb @@ -0,0 +1,51 @@ +# typed: false +# frozen_string_literal: true + +require "extend/array" + +describe Array do + describe ".to_sentence" do + it "converts a plain array to a sentence" do + expect([].to_sentence).to eq("") + expect(["one"].to_sentence).to eq("one") + expect(["one", "two"].to_sentence).to eq("one and two") + expect(["one", "two", "three"].to_sentence).to eq("one, two, and three") + end + + it "converts an array to a sentence with a custom connector" do + expect(["one", "two", "three"].to_sentence(words_connector: " ")).to eq("one two, and three") + expect(["one", "two", "three"].to_sentence(words_connector: " & ")).to eq("one & two, and three") + end + + it "converts an array to a sentence with a custom last word connector" do + expect(["one", "two", "three"].to_sentence(last_word_connector: ", and also ")) + .to eq("one, two, and also three") + expect(["one", "two", "three"].to_sentence(last_word_connector: " ")).to eq("one, two three") + expect(["one", "two", "three"].to_sentence(last_word_connector: " and ")).to eq("one, two and three") + end + + it "converts an array to a sentence with a custom two word connector" do + expect(["one", "two"].to_sentence(two_words_connector: " ")).to eq("one two") + end + + it "creates a new string" do + elements = ["one"] + expect(elements.to_sentence.object_id).not_to eq(elements[0].object_id) + end + + it "converts a non-String to a sentence" do + expect([1].to_sentence).to eq("1") + end + + it "converts an array with blank elements to a sentence" do + expect([nil, "one", "", "two", "three"].to_sentence).to eq(", one, , two, and three") + end + + it "does not return a frozen string" do + expect([""].to_sentence).not_to be_frozen + expect(["one"].to_sentence).not_to be_frozen + expect(["one", "two"].to_sentence).not_to be_frozen + expect(["one", "two", "three"].to_sentence).not_to be_frozen + end + end +end diff --git a/Library/Homebrew/test/rubocops/components_order_spec.rb b/Library/Homebrew/test/rubocops/components_order_spec.rb index afead946d0..cc1dd2f3a1 100644 --- a/Library/Homebrew/test/rubocops/components_order_spec.rb +++ b/Library/Homebrew/test/rubocops/components_order_spec.rb @@ -1014,7 +1014,7 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do resource do on_macos do - ^^^^^^^^^^^ `on_macos` blocks within `resource` blocks must contain at least `url` and `sha256` and at most `url`, `mirror`, `version` and `sha256` (in order). + ^^^^^^^^^^^ `on_macos` blocks within `resource` blocks must contain at least `url` and `sha256` and at most `url`, `mirror`, `version`, and `sha256` (in order). sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" url "https://brew.sh/resource2.tar.gz" end @@ -1081,7 +1081,7 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do resource do on_macos do - ^^^^^^^^^^^ `on_macos` blocks within `resource` blocks must contain at least `url` and `sha256` and at most `url`, `mirror`, `version` and `sha256` (in order). + ^^^^^^^^^^^ `on_macos` blocks within `resource` blocks must contain at least `url` and `sha256` and at most `url`, `mirror`, `version`, and `sha256` (in order). if foo == :bar url "https://brew.sh/resource2.tar.gz" sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" @@ -1112,7 +1112,7 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do end on_arm do - ^^^^^^^^^ `on_arm` blocks within `resource` blocks must contain at least `url` and `sha256` and at most `url`, `mirror`, `version` and `sha256` (in order). + ^^^^^^^^^ `on_arm` blocks within `resource` blocks must contain at least `url` and `sha256` and at most `url`, `mirror`, `version`, and `sha256` (in order). sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" url "https://brew.sh/resource2.tar.gz" end @@ -1158,7 +1158,7 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do end on_arm do - ^^^^^^^^^ `on_arm` blocks within `resource` blocks must contain at least `url` and `sha256` and at most `url`, `mirror`, `version` and `sha256` (in order). + ^^^^^^^^^ `on_arm` blocks within `resource` blocks must contain at least `url` and `sha256` and at most `url`, `mirror`, `version`, and `sha256` (in order). if foo == :bar url "https://brew.sh/resource2.tar.gz" sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35"