Merge pull request #16463 from dduugg/no-active-support
Remove ActiveSupport from runtime
This commit is contained in:
		
						commit
						86e1c8aacf
					
				
							
								
								
									
										20
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -53,25 +53,6 @@
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/*/lib
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/addressable-*/data
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/public_suffix-*/data
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/rubocop-performance-*/config
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/rubocop-rails-*/config
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/rubocop-rspec-*/config
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/rubocop-sorbet-*/config
 | 
			
		||||
 | 
			
		||||
# Ignore activesupport, except the ones we need.
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/activesupport-*/lib/**/*
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/core_ext/
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/core_ext/*/
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/core_ext/array/access.rb
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/core_ext/enumerable.rb
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/core_ext/file/atomic.rb
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/core_ext/hash/deep_merge.rb
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/core_ext/hash/deep_transform_values.rb
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/core_ext/hash/keys.rb
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/core_ext/object/deep_dup.rb
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/core_ext/object/duplicable.rb
 | 
			
		||||
!**/vendor/bundle/ruby/*/gems/activesupport-*/lib/active_support/core_ext/string/exclude.rb
 | 
			
		||||
 | 
			
		||||
# Ignore partially included gems where we don't need all files
 | 
			
		||||
**/vendor/gems/mechanize-*/.*
 | 
			
		||||
@ -89,6 +70,7 @@
 | 
			
		||||
**/vendor/gems/mechanize-*/test/
 | 
			
		||||
 | 
			
		||||
# Ignore dependencies we don't wish to vendor
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/activesupport-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/ast-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/bootsnap-*/
 | 
			
		||||
**/vendor/bundle/ruby/*/gems/bundler-*/
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "attrable"
 | 
			
		||||
require "active_support/core_ext/object/deep_dup"
 | 
			
		||||
require "extend/object/deep_dup"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  module Artifact
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ require "timeout"
 | 
			
		||||
require "utils/user"
 | 
			
		||||
require "cask/artifact/abstract_artifact"
 | 
			
		||||
require "cask/pkg"
 | 
			
		||||
require "extend/hash/keys"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  module Artifact
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cask/artifact/abstract_artifact"
 | 
			
		||||
require "extend/hash/keys"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  module Artifact
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ require "plist"
 | 
			
		||||
 | 
			
		||||
require "utils/user"
 | 
			
		||||
require "cask/artifact/abstract_artifact"
 | 
			
		||||
require "extend/hash/keys"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  module Artifact
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cask/artifact/abstract_artifact"
 | 
			
		||||
require "extend/hash/keys"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  module Artifact
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ require "cask/cache"
 | 
			
		||||
require "cask/cask"
 | 
			
		||||
require "uri"
 | 
			
		||||
require "utils/curl"
 | 
			
		||||
require "extend/hash/keys"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  # Loads a cask from various sources.
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ require "json"
 | 
			
		||||
 | 
			
		||||
require "lazy_object"
 | 
			
		||||
require "locale"
 | 
			
		||||
require "extend/hash/keys"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  # Configuration for installing casks.
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "delegate"
 | 
			
		||||
require "extend/hash/keys"
 | 
			
		||||
 | 
			
		||||
module Cask
 | 
			
		||||
  class DSL
 | 
			
		||||
 | 
			
		||||
@ -126,9 +126,9 @@ module Homebrew
 | 
			
		||||
        # Filter out Sorbet runtime type checking method calls.
 | 
			
		||||
        cmd_location = T.must(caller_locations).select do |location|
 | 
			
		||||
          T.must(location.path).exclude?("/gems/sorbet-runtime-")
 | 
			
		||||
        end.second
 | 
			
		||||
        @command_name = cmd_location.label.chomp("_args").tr("_", "-")
 | 
			
		||||
        @is_dev_cmd = cmd_location.absolute_path.start_with?(Commands::HOMEBREW_DEV_CMD_PATH)
 | 
			
		||||
        end.fetch(1)
 | 
			
		||||
        @command_name = T.must(cmd_location.label).chomp("_args").tr("_", "-")
 | 
			
		||||
        @is_dev_cmd = T.must(cmd_location.absolute_path).start_with?(Commands::HOMEBREW_DEV_CMD_PATH)
 | 
			
		||||
 | 
			
		||||
        @constraints = []
 | 
			
		||||
        @conflicts = []
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,7 @@ require "utils/inreplace"
 | 
			
		||||
require "erb"
 | 
			
		||||
require "utils/gzip"
 | 
			
		||||
require "api"
 | 
			
		||||
require "extend/hash/deep_merge"
 | 
			
		||||
 | 
			
		||||
BOTTLE_ERB = <<-EOS.freeze
 | 
			
		||||
  bottle do
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ require "cli/parser"
 | 
			
		||||
require "formula"
 | 
			
		||||
require "github_packages"
 | 
			
		||||
require "github_releases"
 | 
			
		||||
require "extend/hash/deep_merge"
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  module_function
 | 
			
		||||
 | 
			
		||||
@ -360,7 +360,7 @@ class AbstractFileDownloadStrategy < AbstractDownloadStrategy
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      if search_query && (uri_query = uri.query.presence)
 | 
			
		||||
        components[:query] = URI.decode_www_form(uri_query).map(&:second)
 | 
			
		||||
        components[:query] = URI.decode_www_form(uri_query).map { _2 }
 | 
			
		||||
      end
 | 
			
		||||
    else
 | 
			
		||||
      components[:path] = [url]
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,27 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Array
 | 
			
		||||
  # Equal to <tt>self[1]</tt>.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d e ).second # => "b"
 | 
			
		||||
  def second = self[1]
 | 
			
		||||
 | 
			
		||||
  # Equal to <tt>self[2]</tt>.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d e ).third # => "c"
 | 
			
		||||
  def third = self[2]
 | 
			
		||||
 | 
			
		||||
  # Equal to <tt>self[3]</tt>.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d e ).fourth # => "d"
 | 
			
		||||
  def fourth = self[3]
 | 
			
		||||
 | 
			
		||||
  # Equal to <tt>self[4]</tt>.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d e ).fifth # => "e"
 | 
			
		||||
  def fifth = self[4]
 | 
			
		||||
 | 
			
		||||
  # Converts the array to a comma-separated sentence where the last element is
 | 
			
		||||
  # joined by the connector word.
 | 
			
		||||
  #
 | 
			
		||||
@ -48,6 +68,7 @@ class Array
 | 
			
		||||
  # 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.
 | 
			
		||||
  sig { params(words_connector: String, two_words_connector: String, last_word_connector: String).returns(String) }
 | 
			
		||||
  def to_sentence(words_connector: ", ", two_words_connector: " and ", last_word_connector: " and ")
 | 
			
		||||
    case length
 | 
			
		||||
    when 0
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								Library/Homebrew/extend/array.rbi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Library/Homebrew/extend/array.rbi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
 | 
			
		||||
class Array
 | 
			
		||||
  sig { returns(T.nilable(Elem)) }
 | 
			
		||||
  def second; end
 | 
			
		||||
 | 
			
		||||
  sig { returns(T.nilable(Elem)) }
 | 
			
		||||
  def third; end
 | 
			
		||||
 | 
			
		||||
  sig { returns(T.nilable(Elem)) }
 | 
			
		||||
  def fourth; end
 | 
			
		||||
 | 
			
		||||
  sig { returns(T.nilable(Elem)) }
 | 
			
		||||
  def fifth; end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										30
									
								
								Library/Homebrew/extend/enumerable.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Library/Homebrew/extend/enumerable.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Enumerable
 | 
			
		||||
  # The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
 | 
			
		||||
  # collection does not include the object.
 | 
			
		||||
  sig { params(object: T.untyped).returns(T::Boolean) }
 | 
			
		||||
  def exclude?(object) = !include?(object)
 | 
			
		||||
 | 
			
		||||
  # Returns a new +Array+ without the blank items.
 | 
			
		||||
  # Uses Object#blank? for determining if an item is blank.
 | 
			
		||||
  #
 | 
			
		||||
  #   [1, "", nil, 2, " ", [], {}, false, true].compact_blank
 | 
			
		||||
  #   # =>  [1, 2, true]
 | 
			
		||||
  #
 | 
			
		||||
  #   Set.new([nil, "", 1, false]).compact_blank
 | 
			
		||||
  #   # => [1]
 | 
			
		||||
  #
 | 
			
		||||
  # When called on a +Hash+, returns a new +Hash+ without the blank values.
 | 
			
		||||
  #
 | 
			
		||||
  #   { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
 | 
			
		||||
  #   # => { b: 1, f: true }
 | 
			
		||||
  sig { returns(T.self_type) }
 | 
			
		||||
  def compact_blank = T.unsafe(self).reject(&:blank?)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Hash
 | 
			
		||||
  # Hash#reject has its own definition, so this needs one too.
 | 
			
		||||
  def compact_blank = reject { |_k, v| T.unsafe(v).blank? }
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										6
									
								
								Library/Homebrew/extend/enumerable.rbi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Library/Homebrew/extend/enumerable.rbi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
 | 
			
		||||
class Hash
 | 
			
		||||
  sig { returns(T::Hash[Hash::K, Hash::V]) }
 | 
			
		||||
  def compact_blank; end
 | 
			
		||||
end
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "fileutils"
 | 
			
		||||
@ -18,7 +19,14 @@ class File
 | 
			
		||||
  #   File.atomic_write('/data/something.important', '/data/tmp') do |file|
 | 
			
		||||
  #     file.write('hello')
 | 
			
		||||
  #   end
 | 
			
		||||
  def self.atomic_write(file_name, temp_dir = dirname(file_name))
 | 
			
		||||
  sig {
 | 
			
		||||
    type_parameters(:out).params(
 | 
			
		||||
      file_name: T.any(Pathname, String),
 | 
			
		||||
      temp_dir:  String,
 | 
			
		||||
      _block:    T.proc.params(arg0: Tempfile).returns(T.type_parameter(:out)),
 | 
			
		||||
    ).returns(T.type_parameter(:out))
 | 
			
		||||
  }
 | 
			
		||||
  def self.atomic_write(file_name, temp_dir = dirname(file_name), &_block)
 | 
			
		||||
    require "tempfile" unless defined?(Tempfile)
 | 
			
		||||
 | 
			
		||||
    Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file|
 | 
			
		||||
@ -38,32 +46,35 @@ class File
 | 
			
		||||
      if old_stat
 | 
			
		||||
        # Set correct permissions on new file
 | 
			
		||||
        begin
 | 
			
		||||
          chown(old_stat.uid, old_stat.gid, temp_file.path)
 | 
			
		||||
          chown(old_stat.uid, old_stat.gid, T.must(temp_file.path))
 | 
			
		||||
          # This operation will affect filesystem ACL's
 | 
			
		||||
          chmod(old_stat.mode, temp_file.path)
 | 
			
		||||
          chmod(old_stat.mode, T.must(temp_file.path))
 | 
			
		||||
        rescue Errno::EPERM, Errno::EACCES
 | 
			
		||||
          # Changing file ownership failed, moving on.
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Overwrite original file with temp file
 | 
			
		||||
      rename(temp_file.path, file_name)
 | 
			
		||||
      rename(T.must(temp_file.path), file_name)
 | 
			
		||||
      return_val
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Private utility method.
 | 
			
		||||
  def self.probe_stat_in(dir) #:nodoc:
 | 
			
		||||
  sig { params(dir: String).returns(T.nilable(File::Stat)) }
 | 
			
		||||
  private_class_method def self.probe_stat_in(dir) # :nodoc:
 | 
			
		||||
    basename = [
 | 
			
		||||
      ".permissions_check",
 | 
			
		||||
      Thread.current.object_id,
 | 
			
		||||
      Process.pid,
 | 
			
		||||
      rand(1000000)
 | 
			
		||||
      rand(1_000_000),
 | 
			
		||||
    ].join(".")
 | 
			
		||||
 | 
			
		||||
    file_name = join(dir, basename)
 | 
			
		||||
    FileUtils.touch(file_name)
 | 
			
		||||
    stat(file_name)
 | 
			
		||||
  rescue Errno::ENOENT
 | 
			
		||||
    file_name = nil
 | 
			
		||||
  ensure
 | 
			
		||||
    FileUtils.rm_f(file_name) if file_name
 | 
			
		||||
  end
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Hash
 | 
			
		||||
@ -22,10 +23,10 @@ class Hash
 | 
			
		||||
  # Same as +deep_merge+, but modifies +self+.
 | 
			
		||||
  def deep_merge!(other_hash, &block)
 | 
			
		||||
    merge!(other_hash) do |key, this_val, other_val|
 | 
			
		||||
      if this_val.is_a?(Hash) && other_val.is_a?(Hash)
 | 
			
		||||
        this_val.deep_merge(other_val, &block)
 | 
			
		||||
      elsif block_given?
 | 
			
		||||
        block.call(key, this_val, other_val)
 | 
			
		||||
      if T.unsafe(this_val).is_a?(Hash) && other_val.is_a?(Hash)
 | 
			
		||||
        T.unsafe(this_val).deep_merge(other_val, &block)
 | 
			
		||||
      elsif block
 | 
			
		||||
        yield(key, this_val, other_val)
 | 
			
		||||
      else
 | 
			
		||||
        other_val
 | 
			
		||||
      end
 | 
			
		||||
							
								
								
									
										20
									
								
								Library/Homebrew/extend/hash/deep_merge.rbi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Library/Homebrew/extend/hash/deep_merge.rbi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Hash
 | 
			
		||||
  sig do
 | 
			
		||||
    type_parameters(:k2).params(
 | 
			
		||||
      other_hash: T::Hash[T.type_parameter(:k2), T.untyped],
 | 
			
		||||
      block: T.nilable(T.proc.params(k: T.untyped, v1: T.untyped, v2: T.untyped).returns(T.untyped))
 | 
			
		||||
    ).returns(T::Hash[T.any(Hash::K, T.type_parameter(:k2)), T.untyped])
 | 
			
		||||
  end
 | 
			
		||||
  def deep_merge(other_hash, &block); end
 | 
			
		||||
 | 
			
		||||
  sig do
 | 
			
		||||
    type_parameters(:k2).params(
 | 
			
		||||
      other_hash: T::Hash[T.type_parameter(:k2), T.untyped],
 | 
			
		||||
      block: T.nilable(T.proc.params(k: T.untyped, v1: T.untyped, v2: T.untyped).returns(T.untyped))
 | 
			
		||||
    ).returns(T::Hash[T.any(Hash::K, T.type_parameter(:k2)), T.untyped])
 | 
			
		||||
  end
 | 
			
		||||
  def deep_merge!(other_hash, &block); end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										46
									
								
								Library/Homebrew/extend/hash/deep_transform_values.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								Library/Homebrew/extend/hash/deep_transform_values.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Hash
 | 
			
		||||
  # Returns a new hash with all values converted by the block operation.
 | 
			
		||||
  # This includes the values from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  #
 | 
			
		||||
  #  hash = { person: { name: 'Rob', age: '28' } }
 | 
			
		||||
  #
 | 
			
		||||
  #  hash.deep_transform_values{ |value| value.to_s.upcase }
 | 
			
		||||
  #  # => {person: {name: "ROB", age: "28"}}
 | 
			
		||||
  def deep_transform_values(&block) = _deep_transform_values_in_object(self, &block)
 | 
			
		||||
 | 
			
		||||
  # Destructively converts all values by using the block operation.
 | 
			
		||||
  # This includes the values from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  def deep_transform_values!(&block) = _deep_transform_values_in_object!(self, &block)
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  # Support methods for deep transforming nested hashes and arrays.
 | 
			
		||||
  sig { params(object: T.anything, block: T.proc.params(v: T.untyped).returns(T.untyped)).returns(T.untyped) }
 | 
			
		||||
  def _deep_transform_values_in_object(object, &block)
 | 
			
		||||
    case object
 | 
			
		||||
    when Hash
 | 
			
		||||
      object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
 | 
			
		||||
    when Array
 | 
			
		||||
      object.map { |e| _deep_transform_values_in_object(e, &block) }
 | 
			
		||||
    else
 | 
			
		||||
      yield(object)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { params(object: T.anything, block: T.proc.params(v: T.untyped).returns(T.untyped)).returns(T.untyped) }
 | 
			
		||||
  def _deep_transform_values_in_object!(object, &block)
 | 
			
		||||
    case object
 | 
			
		||||
    when Hash
 | 
			
		||||
      object.transform_values! { |value| _deep_transform_values_in_object!(value, &block) }
 | 
			
		||||
    when Array
 | 
			
		||||
      object.map! { |e| _deep_transform_values_in_object!(e, &block) }
 | 
			
		||||
    else
 | 
			
		||||
      yield(object)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										17
									
								
								Library/Homebrew/extend/hash/deep_transform_values.rbi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Library/Homebrew/extend/hash/deep_transform_values.rbi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
 | 
			
		||||
class Hash
 | 
			
		||||
  sig {
 | 
			
		||||
    type_parameters(:out).params(
 | 
			
		||||
      block: T.proc.params(o: Hash::V).returns(T.type_parameter(:out))
 | 
			
		||||
    ).returns(T::Hash[Hash::K, T.type_parameter(:out)])
 | 
			
		||||
  }
 | 
			
		||||
  def deep_transform_values(&block); end
 | 
			
		||||
 | 
			
		||||
  sig {
 | 
			
		||||
    type_parameters(:out).params(
 | 
			
		||||
      block: T.proc.params(o: Hash::V).returns(T.type_parameter(:out))
 | 
			
		||||
    ).returns(T::Hash[Hash::K, T.type_parameter(:out)])
 | 
			
		||||
  }
 | 
			
		||||
  def deep_transform_values!(&block); end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										117
									
								
								Library/Homebrew/extend/hash/keys.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								Library/Homebrew/extend/hash/keys.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,117 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Hash
 | 
			
		||||
  # Validates all keys in a hash match <tt>*valid_keys</tt>, raising
 | 
			
		||||
  # +ArgumentError+ on a mismatch.
 | 
			
		||||
  #
 | 
			
		||||
  # Note that keys are treated differently than HashWithIndifferentAccess,
 | 
			
		||||
  # meaning that string and symbol keys will not match.
 | 
			
		||||
  #
 | 
			
		||||
  #   { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age)
 | 
			
		||||
  #   # => raises "ArgumentError: Unknown key: :years. Valid keys are: :name, :age"
 | 
			
		||||
  #   { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age')
 | 
			
		||||
  #   # => raises "ArgumentError: Unknown key: :name. Valid keys are: 'name', 'age'"
 | 
			
		||||
  #   { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age)   # => passes, raises nothing
 | 
			
		||||
  sig { params(valid_keys: T.untyped).void }
 | 
			
		||||
  def assert_valid_keys(*valid_keys)
 | 
			
		||||
    valid_keys.flatten!
 | 
			
		||||
    each_key do |k|
 | 
			
		||||
      next if valid_keys.include?(k)
 | 
			
		||||
 | 
			
		||||
      raise ArgumentError,
 | 
			
		||||
            "Unknown key: #{T.unsafe(k).inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(", ")}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a new hash with all keys converted by the block operation.
 | 
			
		||||
  # This includes the keys from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  #
 | 
			
		||||
  #  hash = { person: { name: 'Rob', age: '28' } }
 | 
			
		||||
  #
 | 
			
		||||
  #  hash.deep_transform_keys{ |key| key.to_s.upcase }
 | 
			
		||||
  #  # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
 | 
			
		||||
  def deep_transform_keys(&block) = _deep_transform_keys_in_object(self, &block)
 | 
			
		||||
 | 
			
		||||
  # Destructively converts all keys by using the block operation.
 | 
			
		||||
  # This includes the keys from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  def deep_transform_keys!(&block) = _deep_transform_keys_in_object!(self, &block)
 | 
			
		||||
 | 
			
		||||
  # Returns a new hash with all keys converted to strings.
 | 
			
		||||
  # This includes the keys from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  #
 | 
			
		||||
  #   hash = { person: { name: 'Rob', age: '28' } }
 | 
			
		||||
  #
 | 
			
		||||
  #   hash.deep_stringify_keys
 | 
			
		||||
  #   # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
 | 
			
		||||
  def deep_stringify_keys = T.unsafe(self).deep_transform_keys(&:to_s)
 | 
			
		||||
 | 
			
		||||
  # Destructively converts all keys to strings.
 | 
			
		||||
  # This includes the keys from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  def deep_stringify_keys! = T.unsafe(self).deep_transform_keys!(&:to_s)
 | 
			
		||||
 | 
			
		||||
  # Returns a new hash with all keys converted to symbols, as long as
 | 
			
		||||
  # they respond to +to_sym+. This includes the keys from the root hash
 | 
			
		||||
  # and from all nested hashes and arrays.
 | 
			
		||||
  #
 | 
			
		||||
  #   hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
 | 
			
		||||
  #
 | 
			
		||||
  #   hash.deep_symbolize_keys
 | 
			
		||||
  #   # => {:person=>{:name=>"Rob", :age=>"28"}}
 | 
			
		||||
  def deep_symbolize_keys
 | 
			
		||||
    deep_transform_keys do |key|
 | 
			
		||||
      T.unsafe(key).to_sym
 | 
			
		||||
    rescue
 | 
			
		||||
      key
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Destructively converts all keys to symbols, as long as they respond
 | 
			
		||||
  # to +to_sym+. This includes the keys from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  def deep_symbolize_keys!
 | 
			
		||||
    deep_transform_keys! do |key|
 | 
			
		||||
      T.unsafe(key).to_sym
 | 
			
		||||
    rescue
 | 
			
		||||
      key
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  # Support methods for deep transforming nested hashes and arrays.
 | 
			
		||||
  sig { params(object: T.anything, block: T.proc.params(k: T.untyped).returns(T.untyped)).returns(T.untyped) }
 | 
			
		||||
  def _deep_transform_keys_in_object(object, &block)
 | 
			
		||||
    case object
 | 
			
		||||
    when Hash
 | 
			
		||||
      object.each_with_object({}) do |(key, value), result|
 | 
			
		||||
        result[yield(key)] = _deep_transform_keys_in_object(value, &block)
 | 
			
		||||
      end
 | 
			
		||||
    when Array
 | 
			
		||||
      object.map { |e| _deep_transform_keys_in_object(e, &block) }
 | 
			
		||||
    else
 | 
			
		||||
      object
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { params(object: T.anything, block: T.proc.params(k: T.untyped).returns(T.untyped)).returns(T.untyped) }
 | 
			
		||||
  def _deep_transform_keys_in_object!(object, &block)
 | 
			
		||||
    case object
 | 
			
		||||
    when Hash
 | 
			
		||||
      # We can't use `each_key` here because we're updating the hash in-place
 | 
			
		||||
      object.keys.each do |key| # rubocop:disable Style/HashEachMethods
 | 
			
		||||
        value = object.delete(key)
 | 
			
		||||
        object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
 | 
			
		||||
      end
 | 
			
		||||
      object
 | 
			
		||||
    when Array
 | 
			
		||||
      object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
 | 
			
		||||
    else
 | 
			
		||||
      object
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										30
									
								
								Library/Homebrew/extend/hash/keys.rbi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Library/Homebrew/extend/hash/keys.rbi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Hash
 | 
			
		||||
  sig {
 | 
			
		||||
    type_parameters(:out).params(
 | 
			
		||||
      block: T.proc.params(o: K).returns(T.type_parameter(:out))
 | 
			
		||||
    ).returns(T::Hash[T.type_parameter(:out), V])
 | 
			
		||||
  }
 | 
			
		||||
  def deep_transform_keys(&block); end
 | 
			
		||||
 | 
			
		||||
  sig {
 | 
			
		||||
    type_parameters(:out).params(
 | 
			
		||||
      block: T.proc.params(o: K).returns(T.type_parameter(:out))
 | 
			
		||||
    ).returns(T::Hash[T.type_parameter(:out), V])
 | 
			
		||||
  }
 | 
			
		||||
  def deep_transform_keys!(&block); end
 | 
			
		||||
 | 
			
		||||
  sig { returns(T::Hash[String, V]) }
 | 
			
		||||
  def deep_stringify_keys; end
 | 
			
		||||
 | 
			
		||||
  sig { returns(T::Hash[String, V]) }
 | 
			
		||||
  def deep_stringify_keys!; end
 | 
			
		||||
 | 
			
		||||
  sig { returns(T::Hash[Symbol, V]) }
 | 
			
		||||
  def deep_symbolize_keys; end
 | 
			
		||||
 | 
			
		||||
  sig { returns(T::Hash[Symbol, V]) }
 | 
			
		||||
  def deep_symbolize_keys!; end
 | 
			
		||||
end
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "active_support/core_ext/object/duplicable"
 | 
			
		||||
require "extend/object/duplicable"
 | 
			
		||||
 | 
			
		||||
class Object
 | 
			
		||||
  # Returns a deep copy of object if it's duplicable. If it's
 | 
			
		||||
@ -12,6 +13,7 @@ class Object
 | 
			
		||||
  #
 | 
			
		||||
  #   object.instance_variable_defined?(:@a) # => false
 | 
			
		||||
  #   dup.instance_variable_defined?(:@a)    # => true
 | 
			
		||||
  sig { returns(T.self_type) }
 | 
			
		||||
  def deep_dup
 | 
			
		||||
    duplicable? ? dup : self
 | 
			
		||||
  end
 | 
			
		||||
@ -26,8 +28,9 @@ class Array
 | 
			
		||||
  #
 | 
			
		||||
  #   array[1][2] # => nil
 | 
			
		||||
  #   dup[1][2]   # => 4
 | 
			
		||||
  sig { returns(T.self_type) }
 | 
			
		||||
  def deep_dup
 | 
			
		||||
    map(&:deep_dup)
 | 
			
		||||
    T.unsafe(self).map(&:deep_dup)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -40,16 +43,35 @@ class Hash
 | 
			
		||||
  #
 | 
			
		||||
  #   hash[:a][:c] # => nil
 | 
			
		||||
  #   dup[:a][:c]  # => "c"
 | 
			
		||||
  sig { returns(T.self_type) }
 | 
			
		||||
  def deep_dup
 | 
			
		||||
    hash = dup
 | 
			
		||||
    each_pair do |key, value|
 | 
			
		||||
      if (::String === key && key.frozen?) || ::Symbol === key
 | 
			
		||||
        hash[key] = value.deep_dup
 | 
			
		||||
      case key
 | 
			
		||||
      when ::String, ::Symbol
 | 
			
		||||
        hash[key] = T.unsafe(value).deep_dup
 | 
			
		||||
      else
 | 
			
		||||
        hash.delete(key)
 | 
			
		||||
        hash[key.deep_dup] = value.deep_dup
 | 
			
		||||
        hash[T.unsafe(key).deep_dup] = T.unsafe(value).deep_dup
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
    hash
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Module
 | 
			
		||||
  # Returns a copy of module or class if it's anonymous. If it's
 | 
			
		||||
  # named, returns +self+.
 | 
			
		||||
  #
 | 
			
		||||
  #   Object.deep_dup == Object # => true
 | 
			
		||||
  #   klass = Class.new
 | 
			
		||||
  #   klass.deep_dup == klass # => false
 | 
			
		||||
  sig { returns(T.self_type) }
 | 
			
		||||
  def deep_dup
 | 
			
		||||
    if name.nil?
 | 
			
		||||
      super
 | 
			
		||||
    else
 | 
			
		||||
      self
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
#--
 | 
			
		||||
@ -23,27 +24,34 @@ class Object
 | 
			
		||||
  #
 | 
			
		||||
  # False for method objects;
 | 
			
		||||
  # true otherwise.
 | 
			
		||||
  def duplicable?
 | 
			
		||||
    true
 | 
			
		||||
  end
 | 
			
		||||
  sig { returns(T::Boolean) }
 | 
			
		||||
  def duplicable? = true
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Method
 | 
			
		||||
  # Methods are not duplicable:
 | 
			
		||||
  #
 | 
			
		||||
  #  method(:puts).duplicable? # => false
 | 
			
		||||
  #  method(:puts).dup         # => TypeError: allocator undefined for Method
 | 
			
		||||
  def duplicable?
 | 
			
		||||
    false
 | 
			
		||||
  end
 | 
			
		||||
  #   method(:puts).duplicable? # => false
 | 
			
		||||
  #   method(:puts).dup         # => TypeError: allocator undefined for Method
 | 
			
		||||
  sig { returns(FalseClass) }
 | 
			
		||||
  def duplicable? = false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class UnboundMethod
 | 
			
		||||
  # Unbound methods are not duplicable:
 | 
			
		||||
  #
 | 
			
		||||
  #  method(:puts).unbind.duplicable? # => false
 | 
			
		||||
  #  method(:puts).unbind.dup         # => TypeError: allocator undefined for UnboundMethod
 | 
			
		||||
  def duplicable?
 | 
			
		||||
    false
 | 
			
		||||
  end
 | 
			
		||||
  #   method(:puts).unbind.duplicable? # => false
 | 
			
		||||
  #   method(:puts).unbind.dup         # => TypeError: allocator undefined for UnboundMethod
 | 
			
		||||
  sig { returns(FalseClass) }
 | 
			
		||||
  def duplicable? = false
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
require "singleton"
 | 
			
		||||
 | 
			
		||||
module Singleton
 | 
			
		||||
  # Singleton instances are not duplicable:
 | 
			
		||||
  #
 | 
			
		||||
  #   Class.new.include(Singleton).instance.dup # TypeError (can't dup instance of singleton
 | 
			
		||||
  sig { returns(FalseClass) }
 | 
			
		||||
  def duplicable? = false
 | 
			
		||||
end
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
require "context"
 | 
			
		||||
require "resource"
 | 
			
		||||
require "metafiles"
 | 
			
		||||
require "extend/file/atomic"
 | 
			
		||||
 | 
			
		||||
module DiskUsageExtension
 | 
			
		||||
  sig { returns(Integer) }
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class String
 | 
			
		||||
@ -7,7 +8,6 @@ class String
 | 
			
		||||
  #   "hello".exclude? "lo" # => false
 | 
			
		||||
  #   "hello".exclude? "ol" # => true
 | 
			
		||||
  #   "hello".exclude? ?h   # => false
 | 
			
		||||
  def exclude?(string)
 | 
			
		||||
    !include?(string)
 | 
			
		||||
  end
 | 
			
		||||
  sig { params(string: String).returns(T::Boolean) }
 | 
			
		||||
  def exclude?(string) = !include?(string)
 | 
			
		||||
end
 | 
			
		||||
@ -566,7 +566,7 @@ on_request: installed_on_request?, options: options)
 | 
			
		||||
    unsatisfied_reqs = Hash.new { |h, k| h[k] = [] }
 | 
			
		||||
    formulae = [formula]
 | 
			
		||||
    formula_deps_map = formula.recursive_dependencies
 | 
			
		||||
                              .index_by(&:name)
 | 
			
		||||
                              .each_with_object({}) { |dep, h| h[dep.name] = dep }
 | 
			
		||||
 | 
			
		||||
    while (f = formulae.pop)
 | 
			
		||||
      runtime_requirements = runtime_requirements(f)
 | 
			
		||||
@ -1208,7 +1208,7 @@ on_request: installed_on_request?, options: options)
 | 
			
		||||
      formula.fetch_bottle_tab
 | 
			
		||||
      @bottle_tab_runtime_dependencies = formula.bottle_tab_attributes
 | 
			
		||||
                                                .fetch("runtime_dependencies", [])
 | 
			
		||||
                                                .index_by { |dep| dep["full_name"] }
 | 
			
		||||
                                                .each_with_object({}) { |dep, h| h[dep["full_name"]] = dep }
 | 
			
		||||
                                                .freeze
 | 
			
		||||
      true
 | 
			
		||||
    rescue DownloadError, ArgumentError
 | 
			
		||||
 | 
			
		||||
@ -8,8 +8,8 @@ require "utils/bottles"
 | 
			
		||||
require "service"
 | 
			
		||||
require "utils/curl"
 | 
			
		||||
require "deprecate_disable"
 | 
			
		||||
 | 
			
		||||
require "active_support/core_ext/hash/deep_transform_values"
 | 
			
		||||
require "extend/hash/deep_transform_values"
 | 
			
		||||
require "extend/hash/keys"
 | 
			
		||||
 | 
			
		||||
# The {Formulary} is responsible for creating instances of {Formula}.
 | 
			
		||||
# It is not meant to be used directly from formulae.
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
require "utils/curl"
 | 
			
		||||
require "json"
 | 
			
		||||
require "zlib"
 | 
			
		||||
require "extend/hash/keys"
 | 
			
		||||
 | 
			
		||||
# GitHub Packages client.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
@ -10,14 +10,10 @@ require "json/add/exception"
 | 
			
		||||
require "forwardable"
 | 
			
		||||
require "set"
 | 
			
		||||
 | 
			
		||||
# Only require "core_ext" here to ensure we're only requiring the minimum of
 | 
			
		||||
# what we need.
 | 
			
		||||
require "active_support/core_ext/array/access"
 | 
			
		||||
require "active_support/core_ext/enumerable"
 | 
			
		||||
require "active_support/core_ext/file/atomic"
 | 
			
		||||
require "active_support/core_ext/hash/deep_merge"
 | 
			
		||||
require "active_support/core_ext/hash/keys"
 | 
			
		||||
require "active_support/core_ext/string/exclude"
 | 
			
		||||
require "extend/array"
 | 
			
		||||
require "extend/blank"
 | 
			
		||||
require "extend/enumerable"
 | 
			
		||||
require "extend/string"
 | 
			
		||||
 | 
			
		||||
HOMEBREW_API_DEFAULT_DOMAIN = ENV.fetch("HOMEBREW_API_DEFAULT_DOMAIN").freeze
 | 
			
		||||
HOMEBREW_BOTTLE_DEFAULT_DOMAIN = ENV.fetch("HOMEBREW_BOTTLE_DEFAULT_DOMAIN").freeze
 | 
			
		||||
@ -70,8 +66,6 @@ HOMEBREW_PULL_OR_COMMIT_URL_REGEX =
 | 
			
		||||
  %r[https://github\.com/([\w-]+)/([\w-]+)?/(?:pull/(\d+)|commit/[0-9a-fA-F]{4,40})]
 | 
			
		||||
HOMEBREW_BOTTLES_EXTNAME_REGEX = /\.([a-z0-9_]+)\.bottle\.(?:(\d+)\.)?tar\.gz$/
 | 
			
		||||
 | 
			
		||||
require "extend/module"
 | 
			
		||||
require "extend/blank"
 | 
			
		||||
require "env_config"
 | 
			
		||||
require "macos_version"
 | 
			
		||||
require "os"
 | 
			
		||||
@ -130,7 +124,6 @@ module Homebrew
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
require "context"
 | 
			
		||||
require "extend/array"
 | 
			
		||||
require "git_repository"
 | 
			
		||||
require "extend/pathname"
 | 
			
		||||
require "cli/args"
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# typed: strict
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
@ -32,11 +32,11 @@ module Homebrew
 | 
			
		||||
        NICE_NAME = "GNU"
 | 
			
		||||
 | 
			
		||||
        # The `Regexp` used to determine if the strategy applies to the URL.
 | 
			
		||||
        URL_MATCH_REGEX = %r{
 | 
			
		||||
        URL_MATCH_REGEX = T.let(%r{
 | 
			
		||||
          ^https?://
 | 
			
		||||
          (?:(?:[^/]+?\.)*gnu\.org/(?:gnu|software)/(?<project_name>[^/]+)/
 | 
			
		||||
          |(?<project_name>[^/]+)\.gnu\.org/?$)
 | 
			
		||||
        }ix
 | 
			
		||||
        }ix, Regexp)
 | 
			
		||||
 | 
			
		||||
        # Whether the strategy can be applied to the provided URL.
 | 
			
		||||
        #
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,5 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require_relative "standalone"
 | 
			
		||||
require_relative "extend/module"
 | 
			
		||||
 | 
			
		||||
require "rubocops/all"
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
# typed: true
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "active_support/core_ext/array/access"
 | 
			
		||||
require "extend/array"
 | 
			
		||||
require "rubocops/shared/helper_functions"
 | 
			
		||||
require "shellwords"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "sorbet-runtime"
 | 
			
		||||
require "extend/module"
 | 
			
		||||
 | 
			
		||||
# Disable runtime checking unless enabled.
 | 
			
		||||
# In the future we should consider not doing this monkey patch,
 | 
			
		||||
 | 
			
		||||
@ -92,7 +92,7 @@ class Tab
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if attributes["source"]["spec"].nil?
 | 
			
		||||
      version = PkgVersion.parse path.to_s.split("/").second_to_last
 | 
			
		||||
      version = PkgVersion.parse(File.basename(File.dirname(path)))
 | 
			
		||||
      attributes["source"]["spec"] = if version.head?
 | 
			
		||||
        "head"
 | 
			
		||||
      else
 | 
			
		||||
 | 
			
		||||
@ -12,9 +12,9 @@ module Homebrew
 | 
			
		||||
  # After updating this, run `brew vendor-gems --update=--bundler`.
 | 
			
		||||
  HOMEBREW_BUNDLER_VERSION = "2.4.18"
 | 
			
		||||
 | 
			
		||||
  # Bump this whenever a committed vendored gem is later added to gitignore.
 | 
			
		||||
  # Bump this whenever a committed vendored gem is later added to or exclusion removed from gitignore.
 | 
			
		||||
  # This will trigger it to reinstall properly if `brew install-bundler-gems` needs it.
 | 
			
		||||
  VENDOR_VERSION = 4
 | 
			
		||||
  VENDOR_VERSION = 5
 | 
			
		||||
  private_constant :VENDOR_VERSION
 | 
			
		||||
 | 
			
		||||
  RUBY_BUNDLE_VENDOR_DIRECTORY = (HOMEBREW_LIBRARY_PATH/"vendor/bundle/ruby").freeze
 | 
			
		||||
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
Copyright (c) 2005-2022 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.
 | 
			
		||||
@ -1,104 +0,0 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Array
 | 
			
		||||
  # Returns the tail of the array from +position+.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d ).from(0)  # => ["a", "b", "c", "d"]
 | 
			
		||||
  #   %w( a b c d ).from(2)  # => ["c", "d"]
 | 
			
		||||
  #   %w( a b c d ).from(10) # => []
 | 
			
		||||
  #   %w().from(0)           # => []
 | 
			
		||||
  #   %w( a b c d ).from(-2) # => ["c", "d"]
 | 
			
		||||
  #   %w( a b c ).from(-10)  # => []
 | 
			
		||||
  def from(position)
 | 
			
		||||
    self[position, length] || []
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns the beginning of the array up to +position+.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d ).to(0)  # => ["a"]
 | 
			
		||||
  #   %w( a b c d ).to(2)  # => ["a", "b", "c"]
 | 
			
		||||
  #   %w( a b c d ).to(10) # => ["a", "b", "c", "d"]
 | 
			
		||||
  #   %w().to(0)           # => []
 | 
			
		||||
  #   %w( a b c d ).to(-2) # => ["a", "b", "c"]
 | 
			
		||||
  #   %w( a b c ).to(-10)  # => []
 | 
			
		||||
  def to(position)
 | 
			
		||||
    if position >= 0
 | 
			
		||||
      take position + 1
 | 
			
		||||
    else
 | 
			
		||||
      self[0..position]
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a new array that includes the passed elements.
 | 
			
		||||
  #
 | 
			
		||||
  #   [ 1, 2, 3 ].including(4, 5) # => [ 1, 2, 3, 4, 5 ]
 | 
			
		||||
  #   [ [ 0, 1 ] ].including([ [ 1, 0 ] ]) # => [ [ 0, 1 ], [ 1, 0 ] ]
 | 
			
		||||
  def including(*elements)
 | 
			
		||||
    self + elements.flatten(1)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a copy of the Array excluding the specified elements.
 | 
			
		||||
  #
 | 
			
		||||
  #   ["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
 | 
			
		||||
  #   [ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ]) # => [ [ 0, 1 ] ]
 | 
			
		||||
  #
 | 
			
		||||
  # Note: This is an optimization of <tt>Enumerable#excluding</tt> that uses <tt>Array#-</tt>
 | 
			
		||||
  # instead of <tt>Array#reject</tt> for performance reasons.
 | 
			
		||||
  def excluding(*elements)
 | 
			
		||||
    self - elements.flatten(1)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Alias for #excluding.
 | 
			
		||||
  def without(*elements)
 | 
			
		||||
    excluding(*elements)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Equal to <tt>self[1]</tt>.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d e ).second # => "b"
 | 
			
		||||
  def second
 | 
			
		||||
    self[1]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Equal to <tt>self[2]</tt>.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d e ).third # => "c"
 | 
			
		||||
  def third
 | 
			
		||||
    self[2]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Equal to <tt>self[3]</tt>.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d e ).fourth # => "d"
 | 
			
		||||
  def fourth
 | 
			
		||||
    self[3]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Equal to <tt>self[4]</tt>.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d e ).fifth # => "e"
 | 
			
		||||
  def fifth
 | 
			
		||||
    self[4]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Equal to <tt>self[41]</tt>. Also known as accessing "the reddit".
 | 
			
		||||
  #
 | 
			
		||||
  #   (1..42).to_a.forty_two # => 42
 | 
			
		||||
  def forty_two
 | 
			
		||||
    self[41]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Equal to <tt>self[-3]</tt>.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d e ).third_to_last # => "c"
 | 
			
		||||
  def third_to_last
 | 
			
		||||
    self[-3]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Equal to <tt>self[-2]</tt>.
 | 
			
		||||
  #
 | 
			
		||||
  #   %w( a b c d e ).second_to_last # => "d"
 | 
			
		||||
  def second_to_last
 | 
			
		||||
    self[-2]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -1,260 +0,0 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Enumerable
 | 
			
		||||
  INDEX_WITH_DEFAULT = Object.new
 | 
			
		||||
  private_constant :INDEX_WITH_DEFAULT
 | 
			
		||||
 | 
			
		||||
  # Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
 | 
			
		||||
  # when we omit an identity.
 | 
			
		||||
 | 
			
		||||
  # :stopdoc:
 | 
			
		||||
 | 
			
		||||
  # We can't use Refinements here because Refinements with Module which will be prepended
 | 
			
		||||
  # doesn't work well https://bugs.ruby-lang.org/issues/13446
 | 
			
		||||
  alias :_original_sum_with_required_identity :sum
 | 
			
		||||
  private :_original_sum_with_required_identity
 | 
			
		||||
 | 
			
		||||
  # :startdoc:
 | 
			
		||||
 | 
			
		||||
  # Calculates a sum from the elements.
 | 
			
		||||
  #
 | 
			
		||||
  #  payments.sum { |p| p.price * p.tax_rate }
 | 
			
		||||
  #  payments.sum(&:price)
 | 
			
		||||
  #
 | 
			
		||||
  # The latter is a shortcut for:
 | 
			
		||||
  #
 | 
			
		||||
  #  payments.inject(0) { |sum, p| sum + p.price }
 | 
			
		||||
  #
 | 
			
		||||
  # It can also calculate the sum without the use of a block.
 | 
			
		||||
  #
 | 
			
		||||
  #  [5, 15, 10].sum # => 30
 | 
			
		||||
  #  ['foo', 'bar'].sum # => "foobar"
 | 
			
		||||
  #  [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
 | 
			
		||||
  #
 | 
			
		||||
  # The default sum of an empty list is zero. You can override this default:
 | 
			
		||||
  #
 | 
			
		||||
  #  [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
 | 
			
		||||
  def sum(identity = nil, &block)
 | 
			
		||||
    if identity
 | 
			
		||||
      _original_sum_with_required_identity(identity, &block)
 | 
			
		||||
    elsif block_given?
 | 
			
		||||
      map(&block).sum(identity)
 | 
			
		||||
    else
 | 
			
		||||
      inject(:+) || 0
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Convert an enumerable to a hash, using the block result as the key and the
 | 
			
		||||
  # element as the value.
 | 
			
		||||
  #
 | 
			
		||||
  #   people.index_by(&:login)
 | 
			
		||||
  #   # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
 | 
			
		||||
  #
 | 
			
		||||
  #   people.index_by { |person| "#{person.first_name} #{person.last_name}" }
 | 
			
		||||
  #   # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
 | 
			
		||||
  def index_by
 | 
			
		||||
    if block_given?
 | 
			
		||||
      result = {}
 | 
			
		||||
      each { |elem| result[yield(elem)] = elem }
 | 
			
		||||
      result
 | 
			
		||||
    else
 | 
			
		||||
      to_enum(:index_by) { size if respond_to?(:size) }
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Convert an enumerable to a hash, using the element as the key and the block
 | 
			
		||||
  # result as the value.
 | 
			
		||||
  #
 | 
			
		||||
  #   post = Post.new(title: "hey there", body: "what's up?")
 | 
			
		||||
  #
 | 
			
		||||
  #   %i( title body ).index_with { |attr_name| post.public_send(attr_name) }
 | 
			
		||||
  #   # => { title: "hey there", body: "what's up?" }
 | 
			
		||||
  #
 | 
			
		||||
  # If an argument is passed instead of a block, it will be used as the value
 | 
			
		||||
  # for all elements:
 | 
			
		||||
  #
 | 
			
		||||
  #   %i( created_at updated_at ).index_with(Time.now)
 | 
			
		||||
  #   # => { created_at: 2020-03-09 22:31:47, updated_at: 2020-03-09 22:31:47 }
 | 
			
		||||
  def index_with(default = INDEX_WITH_DEFAULT)
 | 
			
		||||
    if block_given?
 | 
			
		||||
      result = {}
 | 
			
		||||
      each { |elem| result[elem] = yield(elem) }
 | 
			
		||||
      result
 | 
			
		||||
    elsif default != INDEX_WITH_DEFAULT
 | 
			
		||||
      result = {}
 | 
			
		||||
      each { |elem| result[elem] = default }
 | 
			
		||||
      result
 | 
			
		||||
    else
 | 
			
		||||
      to_enum(:index_with) { size if respond_to?(:size) }
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns +true+ if the enumerable has more than 1 element. Functionally
 | 
			
		||||
  # equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,
 | 
			
		||||
  # much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+
 | 
			
		||||
  # if more than one person is over 26.
 | 
			
		||||
  def many?
 | 
			
		||||
    cnt = 0
 | 
			
		||||
    if block_given?
 | 
			
		||||
      any? do |element|
 | 
			
		||||
        cnt += 1 if yield element
 | 
			
		||||
        cnt > 1
 | 
			
		||||
      end
 | 
			
		||||
    else
 | 
			
		||||
      any? { (cnt += 1) > 1 }
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a new array that includes the passed elements.
 | 
			
		||||
  #
 | 
			
		||||
  #   [ 1, 2, 3 ].including(4, 5)
 | 
			
		||||
  #   # => [ 1, 2, 3, 4, 5 ]
 | 
			
		||||
  #
 | 
			
		||||
  #   ["David", "Rafael"].including %w[ Aaron Todd ]
 | 
			
		||||
  #   # => ["David", "Rafael", "Aaron", "Todd"]
 | 
			
		||||
  def including(*elements)
 | 
			
		||||
    to_a.including(*elements)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
 | 
			
		||||
  # collection does not include the object.
 | 
			
		||||
  def exclude?(object)
 | 
			
		||||
    !include?(object)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a copy of the enumerable excluding the specified elements.
 | 
			
		||||
  #
 | 
			
		||||
  #   ["David", "Rafael", "Aaron", "Todd"].excluding "Aaron", "Todd"
 | 
			
		||||
  #   # => ["David", "Rafael"]
 | 
			
		||||
  #
 | 
			
		||||
  #   ["David", "Rafael", "Aaron", "Todd"].excluding %w[ Aaron Todd ]
 | 
			
		||||
  #   # => ["David", "Rafael"]
 | 
			
		||||
  #
 | 
			
		||||
  #   {foo: 1, bar: 2, baz: 3}.excluding :bar
 | 
			
		||||
  #   # => {foo: 1, baz: 3}
 | 
			
		||||
  def excluding(*elements)
 | 
			
		||||
    elements.flatten!(1)
 | 
			
		||||
    reject { |element| elements.include?(element) }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Alias for #excluding.
 | 
			
		||||
  def without(*elements)
 | 
			
		||||
    excluding(*elements)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Extract the given key from each element in the enumerable.
 | 
			
		||||
  #
 | 
			
		||||
  #   [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
 | 
			
		||||
  #   # => ["David", "Rafael", "Aaron"]
 | 
			
		||||
  #
 | 
			
		||||
  #   [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
 | 
			
		||||
  #   # => [[1, "David"], [2, "Rafael"]]
 | 
			
		||||
  def pluck(*keys)
 | 
			
		||||
    if keys.many?
 | 
			
		||||
      map { |element| keys.map { |key| element[key] } }
 | 
			
		||||
    else
 | 
			
		||||
      key = keys.first
 | 
			
		||||
      map { |element| element[key] }
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Extract the given key from the first element in the enumerable.
 | 
			
		||||
  #
 | 
			
		||||
  #   [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pick(:name)
 | 
			
		||||
  #   # => "David"
 | 
			
		||||
  #
 | 
			
		||||
  #   [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pick(:id, :name)
 | 
			
		||||
  #   # => [1, "David"]
 | 
			
		||||
  def pick(*keys)
 | 
			
		||||
    return if none?
 | 
			
		||||
 | 
			
		||||
    if keys.many?
 | 
			
		||||
      keys.map { |key| first[key] }
 | 
			
		||||
    else
 | 
			
		||||
      first[keys.first]
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a new +Array+ without the blank items.
 | 
			
		||||
  # Uses Object#blank? for determining if an item is blank.
 | 
			
		||||
  #
 | 
			
		||||
  #    [1, "", nil, 2, " ", [], {}, false, true].compact_blank
 | 
			
		||||
  #    # =>  [1, 2, true]
 | 
			
		||||
  #
 | 
			
		||||
  #    Set.new([nil, "", 1, 2])
 | 
			
		||||
  #    # => [2, 1] (or [1, 2])
 | 
			
		||||
  #
 | 
			
		||||
  # When called on a +Hash+, returns a new +Hash+ without the blank values.
 | 
			
		||||
  #
 | 
			
		||||
  #    { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
 | 
			
		||||
  #    #=> { b: 1, f: true }
 | 
			
		||||
  def compact_blank
 | 
			
		||||
    reject(&:blank?)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Hash
 | 
			
		||||
  # Hash#reject has its own definition, so this needs one too.
 | 
			
		||||
  def compact_blank #:nodoc:
 | 
			
		||||
    reject { |_k, v| v.blank? }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Removes all blank values from the +Hash+ in place and returns self.
 | 
			
		||||
  # Uses Object#blank? for determining if a value is blank.
 | 
			
		||||
  #
 | 
			
		||||
  #    h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
 | 
			
		||||
  #    h.compact_blank!
 | 
			
		||||
  #    # => { b: 1, f: true }
 | 
			
		||||
  def compact_blank!
 | 
			
		||||
    # use delete_if rather than reject! because it always returns self even if nothing changed
 | 
			
		||||
    delete_if { |_k, v| v.blank? }
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Range #:nodoc:
 | 
			
		||||
  # Optimize range sum to use arithmetic progression if a block is not given and
 | 
			
		||||
  # we have a range of numeric values.
 | 
			
		||||
  def sum(identity = nil)
 | 
			
		||||
    if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
 | 
			
		||||
      super
 | 
			
		||||
    else
 | 
			
		||||
      actual_last = exclude_end? ? (last - 1) : last
 | 
			
		||||
      if actual_last >= first
 | 
			
		||||
        sum = identity || 0
 | 
			
		||||
        sum + (actual_last - first + 1) * (actual_last + first) / 2
 | 
			
		||||
      else
 | 
			
		||||
        identity || 0
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
# Using Refinements here in order not to expose our internal method
 | 
			
		||||
using Module.new {
 | 
			
		||||
  refine Array do
 | 
			
		||||
    alias :orig_sum :sum
 | 
			
		||||
  end
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Array #:nodoc:
 | 
			
		||||
  # Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
 | 
			
		||||
  def sum(init = nil, &block)
 | 
			
		||||
    if init.is_a?(Numeric) || first.is_a?(Numeric)
 | 
			
		||||
      init ||= 0
 | 
			
		||||
      orig_sum(init, &block)
 | 
			
		||||
    else
 | 
			
		||||
      super
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Removes all blank elements from the +Array+ in place and returns self.
 | 
			
		||||
  # Uses Object#blank? for determining if an item is blank.
 | 
			
		||||
  #
 | 
			
		||||
  #    a = [1, "", nil, 2, " ", [], {}, false, true]
 | 
			
		||||
  #    a.compact_blank!
 | 
			
		||||
  #    # =>  [1, 2, true]
 | 
			
		||||
  def compact_blank!
 | 
			
		||||
    # use delete_if rather than reject! because it always returns self even if nothing changed
 | 
			
		||||
    delete_if(&:blank?)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -1,46 +0,0 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Hash
 | 
			
		||||
  # Returns a new hash with all values converted by the block operation.
 | 
			
		||||
  # This includes the values from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  #
 | 
			
		||||
  #  hash = { person: { name: 'Rob', age: '28' } }
 | 
			
		||||
  #
 | 
			
		||||
  #  hash.deep_transform_values{ |value| value.to_s.upcase }
 | 
			
		||||
  #  # => {person: {name: "ROB", age: "28"}}
 | 
			
		||||
  def deep_transform_values(&block)
 | 
			
		||||
    _deep_transform_values_in_object(self, &block)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Destructively converts all values by using the block operation.
 | 
			
		||||
  # This includes the values from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  def deep_transform_values!(&block)
 | 
			
		||||
    _deep_transform_values_in_object!(self, &block)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
    # Support methods for deep transforming nested hashes and arrays.
 | 
			
		||||
    def _deep_transform_values_in_object(object, &block)
 | 
			
		||||
      case object
 | 
			
		||||
      when Hash
 | 
			
		||||
        object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
 | 
			
		||||
      when Array
 | 
			
		||||
        object.map { |e| _deep_transform_values_in_object(e, &block) }
 | 
			
		||||
      else
 | 
			
		||||
        yield(object)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def _deep_transform_values_in_object!(object, &block)
 | 
			
		||||
      case object
 | 
			
		||||
      when Hash
 | 
			
		||||
        object.transform_values! { |value| _deep_transform_values_in_object!(value, &block) }
 | 
			
		||||
      when Array
 | 
			
		||||
        object.map! { |e| _deep_transform_values_in_object!(e, &block) }
 | 
			
		||||
      else
 | 
			
		||||
        yield(object)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
@ -1,143 +0,0 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Hash
 | 
			
		||||
  # Returns a new hash with all keys converted to strings.
 | 
			
		||||
  #
 | 
			
		||||
  #   hash = { name: 'Rob', age: '28' }
 | 
			
		||||
  #
 | 
			
		||||
  #   hash.stringify_keys
 | 
			
		||||
  #   # => {"name"=>"Rob", "age"=>"28"}
 | 
			
		||||
  def stringify_keys
 | 
			
		||||
    transform_keys(&:to_s)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Destructively converts all keys to strings. Same as
 | 
			
		||||
  # +stringify_keys+, but modifies +self+.
 | 
			
		||||
  def stringify_keys!
 | 
			
		||||
    transform_keys!(&:to_s)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a new hash with all keys converted to symbols, as long as
 | 
			
		||||
  # they respond to +to_sym+.
 | 
			
		||||
  #
 | 
			
		||||
  #   hash = { 'name' => 'Rob', 'age' => '28' }
 | 
			
		||||
  #
 | 
			
		||||
  #   hash.symbolize_keys
 | 
			
		||||
  #   # => {:name=>"Rob", :age=>"28"}
 | 
			
		||||
  def symbolize_keys
 | 
			
		||||
    transform_keys { |key| key.to_sym rescue key }
 | 
			
		||||
  end
 | 
			
		||||
  alias_method :to_options,  :symbolize_keys
 | 
			
		||||
 | 
			
		||||
  # Destructively converts all keys to symbols, as long as they respond
 | 
			
		||||
  # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
 | 
			
		||||
  def symbolize_keys!
 | 
			
		||||
    transform_keys! { |key| key.to_sym rescue key }
 | 
			
		||||
  end
 | 
			
		||||
  alias_method :to_options!, :symbolize_keys!
 | 
			
		||||
 | 
			
		||||
  # Validates all keys in a hash match <tt>*valid_keys</tt>, raising
 | 
			
		||||
  # +ArgumentError+ on a mismatch.
 | 
			
		||||
  #
 | 
			
		||||
  # Note that keys are treated differently than HashWithIndifferentAccess,
 | 
			
		||||
  # meaning that string and symbol keys will not match.
 | 
			
		||||
  #
 | 
			
		||||
  #   { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: :years. Valid keys are: :name, :age"
 | 
			
		||||
  #   { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: :name. Valid keys are: 'name', 'age'"
 | 
			
		||||
  #   { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age)   # => passes, raises nothing
 | 
			
		||||
  def assert_valid_keys(*valid_keys)
 | 
			
		||||
    valid_keys.flatten!
 | 
			
		||||
    each_key do |k|
 | 
			
		||||
      unless valid_keys.include?(k)
 | 
			
		||||
        raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}")
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a new hash with all keys converted by the block operation.
 | 
			
		||||
  # This includes the keys from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  #
 | 
			
		||||
  #  hash = { person: { name: 'Rob', age: '28' } }
 | 
			
		||||
  #
 | 
			
		||||
  #  hash.deep_transform_keys{ |key| key.to_s.upcase }
 | 
			
		||||
  #  # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
 | 
			
		||||
  def deep_transform_keys(&block)
 | 
			
		||||
    _deep_transform_keys_in_object(self, &block)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Destructively converts all keys by using the block operation.
 | 
			
		||||
  # This includes the keys from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  def deep_transform_keys!(&block)
 | 
			
		||||
    _deep_transform_keys_in_object!(self, &block)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a new hash with all keys converted to strings.
 | 
			
		||||
  # This includes the keys from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  #
 | 
			
		||||
  #   hash = { person: { name: 'Rob', age: '28' } }
 | 
			
		||||
  #
 | 
			
		||||
  #   hash.deep_stringify_keys
 | 
			
		||||
  #   # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
 | 
			
		||||
  def deep_stringify_keys
 | 
			
		||||
    deep_transform_keys(&:to_s)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Destructively converts all keys to strings.
 | 
			
		||||
  # This includes the keys from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  def deep_stringify_keys!
 | 
			
		||||
    deep_transform_keys!(&:to_s)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a new hash with all keys converted to symbols, as long as
 | 
			
		||||
  # they respond to +to_sym+. This includes the keys from the root hash
 | 
			
		||||
  # and from all nested hashes and arrays.
 | 
			
		||||
  #
 | 
			
		||||
  #   hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
 | 
			
		||||
  #
 | 
			
		||||
  #   hash.deep_symbolize_keys
 | 
			
		||||
  #   # => {:person=>{:name=>"Rob", :age=>"28"}}
 | 
			
		||||
  def deep_symbolize_keys
 | 
			
		||||
    deep_transform_keys { |key| key.to_sym rescue key }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Destructively converts all keys to symbols, as long as they respond
 | 
			
		||||
  # to +to_sym+. This includes the keys from the root hash and from all
 | 
			
		||||
  # nested hashes and arrays.
 | 
			
		||||
  def deep_symbolize_keys!
 | 
			
		||||
    deep_transform_keys! { |key| key.to_sym rescue key }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
    # Support methods for deep transforming nested hashes and arrays.
 | 
			
		||||
    def _deep_transform_keys_in_object(object, &block)
 | 
			
		||||
      case object
 | 
			
		||||
      when Hash
 | 
			
		||||
        object.each_with_object({}) do |(key, value), result|
 | 
			
		||||
          result[yield(key)] = _deep_transform_keys_in_object(value, &block)
 | 
			
		||||
        end
 | 
			
		||||
      when Array
 | 
			
		||||
        object.map { |e| _deep_transform_keys_in_object(e, &block) }
 | 
			
		||||
      else
 | 
			
		||||
        object
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def _deep_transform_keys_in_object!(object, &block)
 | 
			
		||||
      case object
 | 
			
		||||
      when Hash
 | 
			
		||||
        object.keys.each do |key|
 | 
			
		||||
          value = object.delete(key)
 | 
			
		||||
          object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
 | 
			
		||||
        end
 | 
			
		||||
        object
 | 
			
		||||
      when Array
 | 
			
		||||
        object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
 | 
			
		||||
      else
 | 
			
		||||
        object
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user