diff --git a/.github/workflows/triage-issues.yml b/.github/workflows/triage-issues.yml index 7ef4af3ca5..7963be2688 100644 --- a/.github/workflows/triage-issues.yml +++ b/.github/workflows/triage-issues.yml @@ -37,6 +37,7 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-stale: 21 days-before-close: 7 + close-issue-reason: "not_planned" stale-issue-message: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. diff --git a/.gitignore b/.gitignore index 8f52acf25c..10401ee27f 100644 --- a/.gitignore +++ b/.gitignore @@ -150,8 +150,7 @@ **/vendor/bundle/ruby/*/gems/simplecov-*/ **/vendor/bundle/ruby/*/gems/simplecov-html-*/ **/vendor/bundle/ruby/*/gems/sorbet-*/ -**/vendor/bundle/ruby/*/gems/sorbet-runtime-*/ -!**/vendor/bundle/ruby/*/gems/sorbet-runtime-stub-*/ +!**/vendor/bundle/ruby/*/gems/sorbet-runtime-*/ **/vendor/bundle/ruby/*/gems/spoom-*/ **/vendor/bundle/ruby/*/gems/stackprof-*/ **/vendor/bundle/ruby/*/gems/strscan-*/ diff --git a/Library/Homebrew/Gemfile b/Library/Homebrew/Gemfile index 12e3d0926d..fdb2de5c98 100644 --- a/Library/Homebrew/Gemfile +++ b/Library/Homebrew/Gemfile @@ -2,6 +2,8 @@ source "https://rubygems.org" +ruby ">= 2.6.0" + # disallowed gems (should not be used) # * nokogiri - use rexml instead for XML parsing @@ -17,6 +19,7 @@ gem "rspec-github", require: false gem "rspec-its", require: false gem "rspec_junit_formatter", require: false gem "rspec-retry", require: false +gem "rspec-sorbet", require: false gem "rspec-wait", require: false gem "rubocop", require: false gem "rubocop-ast", require: false @@ -26,13 +29,12 @@ gem "warning", require: false group :sorbet, optional: true do gem "parlour", require: false - gem "rspec-sorbet", require: false gem "sorbet-static-and-runtime", require: false gem "tapioca", require: false end # vendored gems -gem "activesupport", "< 7" # 7 requires Ruby 2.7 +gem "activesupport" gem "addressable" gem "concurrent-ruby" gem "did_you_mean" # remove when HOMEBREW_REQUIRED_RUBY_VERSION >= 2.7 @@ -44,4 +46,4 @@ gem "rubocop-rails" gem "rubocop-rspec" gem "rubocop-sorbet" gem "ruby-macho" -gem "sorbet-runtime-stub" +gem "sorbet-runtime" diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index daa1fd174d..518ba1d5ed 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -11,7 +11,7 @@ GEM public_suffix (>= 2.0.2, < 5.0) ast (2.4.2) bindata (2.4.10) - bootsnap (1.12.0) + bootsnap (1.13.0) msgpack (~> 1.2) byebug (11.1.3) coderay (1.1.3) @@ -58,12 +58,12 @@ GEM mime-types-data (3.2022.0105) mini_portile2 (2.8.0) minitest (5.16.2) - msgpack (1.5.3) + msgpack (1.5.4) mustache (1.1.1) net-http-digest_auth (1.4.1) net-http-persistent (4.0.1) connection_pool (~> 2.2) - nokogiri (1.13.7) + nokogiri (1.13.8) mini_portile2 (~> 2.8.0) racc (~> 1.4) parallel (1.22.1) @@ -74,7 +74,7 @@ GEM parser rainbow (~> 3.0) sorbet-runtime (>= 0.5) - parser (3.1.2.0) + parser (3.1.2.1) ast (~> 2.4.1) patchelf (1.3.0) elftools (>= 1.1.3) @@ -124,19 +124,19 @@ GEM rspec (>= 3, < 4) rspec_junit_formatter (0.5.1) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.31.2) + rubocop (1.33.0) json (~> 2.3) parallel (~> 1.10) parser (>= 3.1.0.0) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.18.0, < 2.0) + rubocop-ast (>= 1.19.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.19.1) + rubocop-ast (1.21.0) parser (>= 3.1.1.0) - rubocop-performance (1.14.2) + rubocop-performance (1.14.3) rubocop (>= 1.7.0, < 2.0) rubocop-ast (>= 0.4.0) rubocop-rails (2.15.2) @@ -159,14 +159,13 @@ GEM simplecov (~> 0.19) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) - sorbet (0.5.10158) - sorbet-static (= 0.5.10158) - sorbet-runtime (0.5.10158) - sorbet-runtime-stub (0.2.0) - sorbet-static (0.5.10158-universal-darwin-14) - sorbet-static-and-runtime (0.5.10158) - sorbet (= 0.5.10158) - sorbet-runtime (= 0.5.10158) + sorbet (0.5.10175) + sorbet-static (= 0.5.10175) + sorbet-runtime (0.5.10175) + sorbet-static (0.5.10175-universal-darwin-14) + sorbet-static-and-runtime (0.5.10175) + sorbet (= 0.5.10175) + sorbet-runtime (= 0.5.10175) spoom (1.1.11) sorbet (>= 0.5.9204) sorbet-runtime (>= 0.5.9204) @@ -181,7 +180,7 @@ GEM thor (>= 1.2.0) yard-sorbet thor (1.2.1) - tzinfo (2.0.4) + tzinfo (2.0.5) concurrent-ruby (~> 1.0) unf (0.1.4) unf_ext @@ -205,7 +204,7 @@ PLATFORMS ruby DEPENDENCIES - activesupport (< 7) + activesupport addressable bootsnap byebug @@ -235,10 +234,13 @@ DEPENDENCIES ruby-macho simplecov simplecov-cobertura - sorbet-runtime-stub + sorbet-runtime sorbet-static-and-runtime tapioca warning +RUBY VERSION + ruby 2.6.8p205 + BUNDLED WITH 1.17.3 diff --git a/Library/Homebrew/api/formula.rb b/Library/Homebrew/api/formula.rb index a70fe31b8c..cd65bdbe32 100644 --- a/Library/Homebrew/api/formula.rb +++ b/Library/Homebrew/api/formula.rb @@ -30,10 +30,8 @@ module Homebrew def all_formulae @all_formulae ||= begin curl_args = %w[--compressed --silent https://formulae.brew.sh/api/formula.json] - if cached_formula_json_file.exist? - last_modified = cached_formula_json_file.mtime.utc - last_modified = last_modified.strftime("%a, %d %b %Y %H:%M:%S GMT") - curl_args = ["--header", "If-Modified-Since: #{last_modified}", *curl_args] + if cached_formula_json_file.exist? && !cached_formula_json_file.empty? + curl_args.prepend("--time-cond", cached_formula_json_file) end curl_download(*curl_args, to: HOMEBREW_CACHE_API/"#{formula_api_path}.json", max_time: 5) diff --git a/Library/Homebrew/ast_constants.rb b/Library/Homebrew/ast_constants.rb index 1de605374d..7622f0a2d3 100644 --- a/Library/Homebrew/ast_constants.rb +++ b/Library/Homebrew/ast_constants.rb @@ -29,6 +29,10 @@ FORMULA_COMPONENT_PRECEDENCE_LIST = [ [{ name: :depends_on, type: :method_call }], [{ name: :uses_from_macos, type: :method_call }], [{ name: :on_macos, type: :block_call }], + *MacOSVersions::SYMBOLS.keys.map do |os_name| + [{ name: :"on_#{os_name}", type: :block_call }] + end, + [{ name: :on_system, type: :block_call }], [{ name: :on_linux, type: :block_call }], [{ name: :on_arm, type: :block_call }], [{ name: :on_intel, type: :block_call }], diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index b514d00621..7f52b5a483 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -103,7 +103,15 @@ begin possible_tap = OFFICIAL_CMD_TAPS.find { |_, cmds| cmds.include?(cmd) } possible_tap = Tap.fetch(possible_tap.first) if possible_tap - if !possible_tap || possible_tap.installed? || Tap.untapped_official_taps.include?(possible_tap.name) + if !possible_tap || + possible_tap.installed? || + (blocked_tap = Tap.untapped_official_taps.include?(possible_tap.name)) + if blocked_tap + onoe <<~EOS + `brew #{cmd}` is unavailable because #{possible_tap.name} was manually untapped. + Run `brew tap #{possible_tap.name}` to reenable `brew #{cmd}`. + EOS + end # Check for cask explicitly because it's very common in old guides odie "`brew cask` is no longer a `brew` command. Use `brew --cask` instead." if cmd == "cask" odie "Unknown command: #{cmd}" diff --git a/Library/Homebrew/cask/cask.rb b/Library/Homebrew/cask/cask.rb index c30dfa7c22..d347e27ac3 100644 --- a/Library/Homebrew/cask/cask.rb +++ b/Library/Homebrew/cask/cask.rb @@ -90,13 +90,14 @@ module Cask end def os_versions + # TODO: use #to_hash_with_variations instead once all casks use on_system blocks @os_versions ||= begin version_os_hash = {} actual_version = MacOS.full_version.to_s MacOSVersions::SYMBOLS.each do |os_name, os_version| MacOS.full_version = os_version - cask = CaskLoader.load(token) + cask = CaskLoader.load(full_name) version_os_hash[os_name] = cask.version if cask.version != version end @@ -219,7 +220,7 @@ module Cask end alias == eql? - def to_hash + def to_h { "token" => token, "full_token" => full_name, @@ -243,8 +244,8 @@ module Cask } end - def to_h - hash = to_hash + def to_hash_with_variations + hash = to_h variations = {} hash_keys_to_skip = %w[outdated installed versions] @@ -252,21 +253,20 @@ module Cask if @dsl.on_system_blocks_exist? [:arm, :intel].each do |arch| MacOSVersions::SYMBOLS.each_key do |os_name| - # Big Sur is the first version of macOS that supports arm - next if arch == :arm && MacOS::Version.from_symbol(os_name) < MacOS::Version.from_symbol(:big_sur) + bottle_tag = ::Utils::Bottles::Tag.new(system: os_name, arch: arch) + next unless bottle_tag.valid_combination? Homebrew::SimulateSystem.os = os_name Homebrew::SimulateSystem.arch = arch refresh - bottle_tag = ::Utils::Bottles::Tag.new(system: os_name, arch: arch).to_sym - to_hash.each do |key, value| + to_h.each do |key, value| next if hash_keys_to_skip.include? key next if value.to_s == hash[key].to_s - variations[bottle_tag] ||= {} - variations[bottle_tag][key] = value + variations[bottle_tag.to_sym] ||= {} + variations[bottle_tag.to_sym][key] = value end end end diff --git a/Library/Homebrew/cask/dsl.rb b/Library/Homebrew/cask/dsl.rb index d4d06da622..4499f1bffc 100644 --- a/Library/Homebrew/cask/dsl.rb +++ b/Library/Homebrew/cask/dsl.rb @@ -243,6 +243,17 @@ module Cask end end + # @api public + def arch(arm: nil, intel: nil) + should_return = arm.blank? && intel.blank? + + set_unique_stanza(:arch, should_return) do + @on_system_blocks_exist = true + + on_arch_conditional(arm: arm, intel: intel) + end + end + # `depends_on` uses a load method so that multiple stanzas can be merged. # @api public def depends_on(*args) diff --git a/Library/Homebrew/cask/dsl/preflight.rb b/Library/Homebrew/cask/dsl/preflight.rb index d1f0e57098..79d2a63ba8 100644 --- a/Library/Homebrew/cask/dsl/preflight.rb +++ b/Library/Homebrew/cask/dsl/preflight.rb @@ -1,6 +1,8 @@ # typed: strict # frozen_string_literal: true +require "cask/staged" + module Cask class DSL # Class corresponding to the `preflight` stanza. diff --git a/Library/Homebrew/cask/installer.rb b/Library/Homebrew/cask/installer.rb index ed69a5f5ce..c0417e311d 100644 --- a/Library/Homebrew/cask/installer.rb +++ b/Library/Homebrew/cask/installer.rb @@ -7,7 +7,6 @@ require "utils/topological_hash" require "cask/config" require "cask/download" -require "cask/staged" require "cask/quarantine" require "cgi" @@ -20,12 +19,6 @@ module Cask extend T::Sig extend Predicable - # TODO: it is unwise for Cask::Staged to be a module, when we are - # dealing with both staged and unstaged casks here. This should - # either be a class which is only sometimes instantiated, or there - # should be explicit checks on whether staged state is valid in - # every method. - include Staged def initialize(cask, command: SystemCommand, force: false, skip_cask_deps: false, binaries: true, verbose: false, diff --git a/Library/Homebrew/cleanup.rb b/Library/Homebrew/cleanup.rb index 4eb4689c9b..07e1438c84 100644 --- a/Library/Homebrew/cleanup.rb +++ b/Library/Homebrew/cleanup.rb @@ -156,35 +156,44 @@ module Homebrew def self.install_formula_clean!(f, dry_run: false) return if Homebrew::EnvConfig.no_install_cleanup? + return unless f.latest_version_installed? + return if skip_clean_formula?(f) - cleanup = Cleanup.new(dry_run: dry_run) - if cleanup.periodic_clean_due? - cleanup.periodic_clean! - elsif f.latest_version_installed? && !cleanup.skip_clean_formula?(f) + if dry_run + ohai "Would run `brew cleanup #{f}`" + else ohai "Running `brew cleanup #{f}`..." - puts_no_install_cleanup_disable_message_if_not_already! - cleanup.cleanup_formula(f) end + + puts_no_install_cleanup_disable_message_if_not_already! + return if dry_run + + Cleanup.new.cleanup_formula(f) end - def self.puts_no_install_cleanup_disable_message_if_not_already! + def self.puts_no_install_cleanup_disable_message return if Homebrew::EnvConfig.no_env_hints? return if Homebrew::EnvConfig.no_install_cleanup? - return if @puts_no_install_cleanup_disable_message_if_not_already puts "Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP." puts "Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`)." + end + + def self.puts_no_install_cleanup_disable_message_if_not_already! + return if @puts_no_install_cleanup_disable_message_if_not_already + + puts_no_install_cleanup_disable_message @puts_no_install_cleanup_disable_message_if_not_already = true end - def skip_clean_formula?(f) + def self.skip_clean_formula?(f) return false if Homebrew::EnvConfig.no_cleanup_formulae.blank? skip_clean_formulae = Homebrew::EnvConfig.no_cleanup_formulae.split(",") skip_clean_formulae.include?(f.name) || (skip_clean_formulae & f.aliases).present? end - def periodic_clean_due? + def self.periodic_clean_due? return false if Homebrew::EnvConfig.no_install_cleanup? unless PERIODIC_CLEAN_FILE.exist? @@ -196,29 +205,33 @@ module Homebrew PERIODIC_CLEAN_FILE.mtime < CLEANUP_DEFAULT_DAYS.days.ago end - def periodic_clean! - return false unless periodic_clean_due? + def self.periodic_clean!(dry_run: false) + return if Homebrew::EnvConfig.no_install_cleanup? + return unless periodic_clean_due? - if dry_run? - ohai "Would run `brew cleanup` which has not been run in the last #{CLEANUP_DEFAULT_DAYS} days" + if dry_run + oh1 "Would run `brew cleanup` which has not been run in the last #{CLEANUP_DEFAULT_DAYS} days" else - ohai "`brew cleanup` has not been run in the last #{CLEANUP_DEFAULT_DAYS} days, running now..." + oh1 "`brew cleanup` has not been run in the last #{CLEANUP_DEFAULT_DAYS} days, running now..." end - Cleanup.puts_no_install_cleanup_disable_message_if_not_already! - return if dry_run? + puts_no_install_cleanup_disable_message + return if dry_run - clean!(quiet: true, periodic: true) + Cleanup.new.clean!(quiet: true, periodic: true) end def clean!(quiet: false, periodic: false) if args.empty? Formula.installed .sort_by(&:name) - .reject { |f| skip_clean_formula?(f) } + .reject { |f| Cleanup.skip_clean_formula?(f) } .each do |formula| cleanup_formula(formula, quiet: quiet, ds_store: false, cache_db: false) end + + Cleanup.autoremove(dry_run: dry_run?) if Homebrew::EnvConfig.autoremove? + cleanup_cache cleanup_logs cleanup_lockfiles @@ -253,7 +266,7 @@ module Homebrew nil end - if formula && skip_clean_formula?(formula) + if formula && Cleanup.skip_clean_formula?(formula) onoe "Refusing to clean #{formula} because it is listed in " \ "#{Tty.bold}HOMEBREW_NO_CLEANUP_FORMULAE#{Tty.reset}!" elsif formula @@ -519,5 +532,36 @@ module Homebrew print "and #{d} directories " if d.positive? puts "from #{HOMEBREW_PREFIX}" end + + def self.autoremove(dry_run: false) + require "cask/caskroom" + + # If this runs after install, uninstall, reinstall or upgrade, + # the cache of installed formulae may no longer be valid. + Formula.clear_cache unless dry_run + + # Remove formulae listed in HOMEBREW_NO_CLEANUP_FORMULAE. + formulae = Formula.installed.reject(&method(:skip_clean_formula?)) + casks = Cask::Caskroom.casks + + removable_formulae = Formula.unused_formulae_with_no_dependents(formulae, casks) + + return if removable_formulae.blank? + + 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)}:" + puts formulae_names.join("\n") + return if dry_run + + require "uninstall" + + kegs_by_rack = removable_formulae.map(&:any_installed_keg).group_by(&:rack) + Uninstall.uninstall_kegs(kegs_by_rack) + + # The installed formula cache will be invalid after uninstalling. + Formula.clear_cache + end end end diff --git a/Library/Homebrew/cli/args.rbi b/Library/Homebrew/cli/args.rbi index af6802f6ac..6f7aa4e421 100644 --- a/Library/Homebrew/cli/args.rbi +++ b/Library/Homebrew/cli/args.rbi @@ -303,6 +303,15 @@ module Homebrew sig { returns(T.nilable(String)) } def screen_saverdir; end + sig { returns(T::Array[String])} + def repositories; end + + sig { returns(T.nilable(String)) } + def from; end + + sig { returns(T.nilable(String)) } + def to; end + sig { returns(T.nilable(T::Array[String])) } def groups; end diff --git a/Library/Homebrew/cmd/autoremove.rb b/Library/Homebrew/cmd/autoremove.rb index a80cb4ae49..94dea99605 100644 --- a/Library/Homebrew/cmd/autoremove.rb +++ b/Library/Homebrew/cmd/autoremove.rb @@ -1,9 +1,8 @@ # typed: true # frozen_string_literal: true -require "formula" +require "cleanup" require "cli/parser" -require "uninstall" module Homebrew module_function @@ -20,37 +19,9 @@ module Homebrew end end - def get_removable_formulae(formulae) - removable_formulae = Formula.installed_formulae_with_no_dependents(formulae).reject do |f| - Tab.for_keg(f.any_installed_keg).installed_on_request - end - - removable_formulae += get_removable_formulae(formulae - removable_formulae) if removable_formulae.present? - - removable_formulae - end - def autoremove args = autoremove_args.parse - removable_formulae = get_removable_formulae(Formula.installed) - - if (casks = Cask::Caskroom.casks.presence) - removable_formulae -= casks.flat_map { |cask| cask.depends_on[:formula] } - .compact - .map { |f| Formula[f] } - .flat_map { |f| [f, *f.runtime_formula_dependencies].compact } - end - return if removable_formulae.blank? - - formulae_names = removable_formulae.map(&:full_name).sort - - verb = args.dry_run? ? "Would uninstall" : "Uninstalling" - oh1 "#{verb} #{formulae_names.count} unneeded #{"formula".pluralize(formulae_names.count)}:" - puts formulae_names.join("\n") - return if args.dry_run? - - kegs_by_rack = removable_formulae.map(&:any_installed_keg).group_by(&:rack) - Uninstall.uninstall_kegs(kegs_by_rack) + Cleanup.autoremove(dry_run: args.dry_run?) end end diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index 0fe8851a56..4f6d706567 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -61,6 +61,9 @@ module Homebrew switch "--all", depends_on: "--json", description: "Print JSON of all available formulae." + switch "--variations", + depends_on: "--json", + description: "Include the variations hash in each formula's JSON output." switch "-v", "--verbose", description: "Show more verbose analytics data for ." switch "--formula", "--formulae", @@ -202,6 +205,8 @@ module Homebrew if args.bottle? formulae.map(&:to_recursive_bottle_hash) + elsif args.variations? + formulae.map(&:to_hash_with_variations) else formulae.map(&:to_hash) end @@ -216,6 +221,11 @@ module Homebrew if args.bottle? { "formulae" => formulae.map(&:to_recursive_bottle_hash) } + elsif args.variations? + { + "formulae" => formulae.map(&:to_hash_with_variations), + "casks" => casks.map(&:to_hash_with_variations), + } else { "formulae" => formulae.map(&:to_hash), diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index 6844ef124b..e4d6ab4b47 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -260,6 +260,8 @@ module Homebrew verbose: args.verbose?, ) + Cleanup.periodic_clean! + Homebrew.messages.display_messages(display_times: args.display_times?) rescue FormulaUnreadableError, FormulaClassUnavailableError, TapFormulaUnreadableError, TapFormulaClassUnavailableError => e diff --git a/Library/Homebrew/cmd/leaves.rb b/Library/Homebrew/cmd/leaves.rb index 1c003b4b96..ec134de4a1 100644 --- a/Library/Homebrew/cmd/leaves.rb +++ b/Library/Homebrew/cmd/leaves.rb @@ -37,7 +37,7 @@ module Homebrew def leaves args = leaves_args.parse - leaves_list = Formula.installed_formulae_with_no_dependents + leaves_list = Formula.formulae_with_no_formula_dependents(Formula.installed) leaves_list.select!(&method(:installed_on_request?)) if args.installed_on_request? leaves_list.select!(&method(:installed_as_dependency?)) if args.installed_as_dependency? diff --git a/Library/Homebrew/cmd/reinstall.rb b/Library/Homebrew/cmd/reinstall.rb index 608eee3212..e7d8331dcc 100644 --- a/Library/Homebrew/cmd/reinstall.rb +++ b/Library/Homebrew/cmd/reinstall.rb @@ -158,6 +158,8 @@ module Homebrew ) end + Cleanup.periodic_clean! + Homebrew.messages.display_messages(display_times: args.display_times?) end end diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb index 603735b340..c0a7a20f99 100644 --- a/Library/Homebrew/cmd/search.rb +++ b/Library/Homebrew/cmd/search.rb @@ -82,6 +82,8 @@ module Homebrew search_names(query, string_or_regex, args) end + puts "Use `brew desc` to list packages with a short description." if args.verbose? + print_regex_help(args) end diff --git a/Library/Homebrew/cmd/uninstall.rb b/Library/Homebrew/cmd/uninstall.rb index 8c40d4219d..50a9abd5d1 100644 --- a/Library/Homebrew/cmd/uninstall.rb +++ b/Library/Homebrew/cmd/uninstall.rb @@ -50,6 +50,11 @@ module Homebrew all_kegs: args.force?, ) + # If ignore_unavailable is true and the named args + # are a series of invalid kegs and casks, + # #to_kegs_to_casks will return empty arrays. + return if all_kegs.blank? && casks.blank? + kegs_by_rack = all_kegs.group_by(&:rack) Uninstall.uninstall_kegs( @@ -73,5 +78,7 @@ module Homebrew force: args.force?, ) end + + Cleanup.autoremove if Homebrew::EnvConfig.autoremove? end end diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb index 89b8f50fca..dbc9a7fbfc 100644 --- a/Library/Homebrew/cmd/update-report.rb +++ b/Library/Homebrew/cmd/update-report.rb @@ -148,6 +148,8 @@ module Homebrew Homebrew.failed = true if ENV["HOMEBREW_UPDATE_FAILED"] return if Homebrew::EnvConfig.disable_load_formula? + migrate_gcc_dependents_if_needed + hub = ReporterHub.new updated_taps = [] @@ -289,6 +291,33 @@ module Homebrew #{e} EOS end + + def migrate_gcc_dependents_if_needed + return if OS.mac? + return if Settings.read("gcc-rpaths.fixed") == "true" + + Formula.installed.each do |formula| + next unless formula.tap&.core_tap? + + recursive_runtime_dependencies = Dependency.expand( + formula, + cache_key: "update-report", + ) do |_, dependency| + Dependency.prune if dependency.build? || dependency.test? + end + next unless recursive_runtime_dependencies.map(&:name).include? "gcc" + + keg = formula.installed_kegs.last + tab = Tab.for_keg(keg) + # Force reinstallation upon `brew upgrade` to fix the bottle RPATH. + tab.source["versions"]["version_scheme"] = -1 + tab.write + rescue TapFormulaUnavailableError + nil + end + + Settings.write "gcc-rpaths.fixed", true + end end class Reporter diff --git a/Library/Homebrew/cmd/update.sh b/Library/Homebrew/cmd/update.sh index 0269d73edb..61f7a401b6 100644 --- a/Library/Homebrew/cmd/update.sh +++ b/Library/Homebrew/cmd/update.sh @@ -556,6 +556,9 @@ EOS [[ -d "${DIR}/.git" ]] || continue cd "${DIR}" || continue + # Git's fsmonitor prevents the release of our locks + git config --bool core.fsmonitor false + if ! git config --local --get remote.origin.url &>/dev/null then opoo "No remote 'origin' in ${DIR}, skipping update!" @@ -603,13 +606,13 @@ EOS # Only try to `git fetch` when the upstream tags have changed # (so the API does not return 304: unmodified). GITHUB_API_ETAG="$(sed -n 's/^ETag: "\([a-f0-9]\{32\}\)".*/\1/p' ".git/GITHUB_HEADERS" 2>/dev/null)" - GITHUB_API_ACCEPT="application/vnd.github.v3+json" + GITHUB_API_ACCEPT="application/vnd.github+json" GITHUB_API_ENDPOINT="tags" else # Only try to `git fetch` when the upstream branch is at a different SHA # (so the API does not return 304: unmodified). GITHUB_API_ETAG="$(git rev-parse "refs/remotes/origin/${UPSTREAM_BRANCH_DIR}")" - GITHUB_API_ACCEPT="application/vnd.github.v3.sha" + GITHUB_API_ACCEPT="application/vnd.github.sha" GITHUB_API_ENDPOINT="commits/${UPSTREAM_BRANCH_DIR}" fi diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb index 49d5a783f2..3da6d1232e 100644 --- a/Library/Homebrew/cmd/upgrade.rb +++ b/Library/Homebrew/cmd/upgrade.rb @@ -115,6 +115,8 @@ module Homebrew upgrade_outdated_formulae(formulae, args: args) unless only_upgrade_casks upgrade_outdated_casks(casks, args: args) unless only_upgrade_formulae + Cleanup.periodic_clean!(dry_run: args.dry_run?) + Homebrew.messages.display_messages(display_times: args.display_times?) end diff --git a/Library/Homebrew/default_prefix.rb b/Library/Homebrew/default_prefix.rb index b22f98268d..70e493c233 100644 --- a/Library/Homebrew/default_prefix.rb +++ b/Library/Homebrew/default_prefix.rb @@ -1,10 +1,12 @@ # typed: true # frozen_string_literal: true +require "simulate_system" + module Homebrew DEFAULT_PREFIX, DEFAULT_REPOSITORY = if OS.mac? && Hardware::CPU.arm? [HOMEBREW_MACOS_ARM_DEFAULT_PREFIX, HOMEBREW_MACOS_ARM_DEFAULT_REPOSITORY] - elsif OS.linux? && !EnvConfig.simulate_macos_on_linux? + elsif Homebrew::SimulateSystem.simulating_or_running_on_linux? [HOMEBREW_LINUX_DEFAULT_PREFIX, HOMEBREW_LINUX_DEFAULT_REPOSITORY] else [HOMEBREW_DEFAULT_PREFIX, HOMEBREW_DEFAULT_REPOSITORY] diff --git a/Library/Homebrew/dependency_collector.rb b/Library/Homebrew/dependency_collector.rb index aee6fb15ab..f19b059b12 100644 --- a/Library/Homebrew/dependency_collector.rb +++ b/Library/Homebrew/dependency_collector.rb @@ -161,7 +161,7 @@ class DependencyCollector elsif strategy <= FossilDownloadStrategy Dependency.new("fossil", tags) elsif strategy <= BazaarDownloadStrategy - Dependency.new("bazaar", tags) + Dependency.new("breezy", tags) elsif strategy <= CVSDownloadStrategy cvs_dep_if_needed(tags) elsif strategy < AbstractDownloadStrategy diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 1ad696ceef..fbcc4de792 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -243,8 +243,8 @@ module Homebrew elsif new_tag.present? [ [ - /#{formula_spec.specs[:tag]}(?=")/, - new_tag, + /tag:(\s+")#{formula_spec.specs[:tag]}(?=")/, + "tag:\\1#{new_tag}\\2", ], [ formula_spec.specs[:revision], diff --git a/Library/Homebrew/dev-cmd/contributions.rb b/Library/Homebrew/dev-cmd/contributions.rb new file mode 100755 index 0000000000..946c40b8f1 --- /dev/null +++ b/Library/Homebrew/dev-cmd/contributions.rb @@ -0,0 +1,109 @@ +# typed: true +# frozen_string_literal: true + +require "cli/parser" + +module Homebrew + extend T::Sig + + module_function + + SUPPORTED_REPOS = [ + %w[brew core cask], + OFFICIAL_CMD_TAPS.keys.map { |t| t.delete_prefix("homebrew/") }, + OFFICIAL_CASK_TAPS.reject { |t| t == "cask" }, + ].flatten.freeze + + sig { returns(CLI::Parser) } + def contributions_args + Homebrew::CLI::Parser.new do + usage_banner "`contributions` [<--repositories>`=`]" + description <<~EOS + Contributions to Homebrew repos for a user. + + The first argument is a name (e.g. "BrewTestBot") or an email address (e.g. "brewtestbot@brew.sh"). + EOS + + comma_array "--repositories", + description: "Specify a comma-separated (no spaces) list of repositories to search. " \ + "Supported repositories: #{SUPPORTED_REPOS.map { |t| "`#{t}`" }.to_sentence}." \ + "Omitting this flag, or specifying `--repositories=all`, will search all repositories." + flag "--from=", + description: "Date (ISO-8601 format) to start searching contributions." + + flag "--to=", + description: "Date (ISO-8601 format) to stop searching contributions." + + named_args number: 1 + end + end + + sig { void } + def contributions + args = contributions_args.parse + + commits = 0 + coauthorships = 0 + + all_repos = args.repositories.nil? || args.repositories.include?("all") + repos = all_repos ? SUPPORTED_REPOS : args.repositories + + repos.each do |repo| + if SUPPORTED_REPOS.exclude?(repo) + return ofail "Unsupported repository: #{repo}. Try one of #{SUPPORTED_REPOS.join(", ")}." + end + + repo_path = find_repo_path_for_repo(repo) + unless repo_path.exist? + + opoo "Repository #{repo} not yet tapped! Tapping it now..." + Tap.fetch("homebrew", repo).install + end + + commits += git_log_author_cmd(T.must(repo_path), args) + coauthorships += git_log_coauthor_cmd(T.must(repo_path), args) + end + + sentence = "#{args.named.first} directly authored #{commits} commits " \ + "and co-authored #{coauthorships} commits " \ + "across #{all_repos ? "all Homebrew repos" : repos.to_sentence}" + sentence += if args.from && args.to + " between #{args.from} and #{args.to}" + elsif args.from + " after #{args.from}" + elsif args.to + " before #{args.to}" + else + " in all time" + end + sentence += "." + + puts sentence + end + + sig { params(repo: String).returns(Pathname) } + def find_repo_path_for_repo(repo) + return HOMEBREW_REPOSITORY if repo == "brew" + + Tap.fetch("homebrew", repo).path + end + + sig { params(repo_path: Pathname, args: Homebrew::CLI::Args).returns(Integer) } + def git_log_author_cmd(repo_path, args) + cmd = ["git", "-C", repo_path, "log", "--oneline", "--author=#{args.named.first}"] + cmd << "--before=#{args.to}" if args.to + cmd << "--after=#{args.from}" if args.from + + Utils.safe_popen_read(*cmd).lines.count + end + + sig { params(repo_path: Pathname, args: Homebrew::CLI::Args).returns(Integer) } + def git_log_coauthor_cmd(repo_path, args) + cmd = ["git", "-C", repo_path, "log", "--oneline"] + cmd << "--format='%(trailers:key=Co-authored-by:)'" + cmd << "--before=#{args.to}" if args.to + cmd << "--after=#{args.from}" if args.from + + Utils.safe_popen_read(*cmd).lines.count { |l| l.include?(args.named.first) } + end +end diff --git a/Library/Homebrew/dev-cmd/pr-pull.rb b/Library/Homebrew/dev-cmd/pr-pull.rb index 1c7fd73ba9..9bac23c98c 100644 --- a/Library/Homebrew/dev-cmd/pr-pull.rb +++ b/Library/Homebrew/dev-cmd/pr-pull.rb @@ -368,6 +368,49 @@ module Homebrew end end + def pr_check_conflicts(user, repo, pr) + long_build_pr_files = GitHub.search_issues( + "org:#{user}", repo: repo, state: "open", label: "\"no long build conflict\"" + ).each_with_object({}) do |long_build_pr, hash| + number = long_build_pr["number"] + next if number == pr.to_i + + GitHub.get_pull_request_changed_files("#{user}/#{repo}", number).each do |file| + key = file["filename"] + hash[key] ||= [] + hash[key] << number + end + end + + this_pr_files = GitHub.get_pull_request_changed_files("#{user}/#{repo}", pr) + + conflicts = this_pr_files.each_with_object({}) do |file, hash| + filename = file["filename"] + next unless long_build_pr_files.key?(filename) + + long_build_pr_files[filename].each do |pr_number| + key = "#{user}/#{repo}/pull/#{pr_number}" + hash[key] ||= [] + hash[key] << filename + end + end + + return if conflicts.blank? + + # Raise an error, display the conflicting PR. For example: + # Error: You are trying to merge a pull request that conflicts with a long running build in: + # { + # "homebrew-core/pull/98809": [ + # "Formula/icu4c.rb", + # "Formula/node@10.rb" + # ] + # } + odie <<~EOS + You are trying to merge a pull request that conflicts with a long running build in: + #{JSON.pretty_generate(conflicts)} + EOS + end + def pr_pull args = pr_pull_args.parse @@ -397,6 +440,8 @@ module Homebrew opoo "Current branch is #{tap.path.git_branch}: do you need to pull inside #{tap.path.git_origin_branch}?" end + pr_check_conflicts(user, repo, pr) + ohai "Fetching #{tap} pull request ##{pr}" Dir.mktmpdir pr do |dir| cd dir do diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb index 87a132ec70..a7ea3dc96a 100644 --- a/Library/Homebrew/dev-cmd/tests.rb +++ b/Library/Homebrew/dev-cmd/tests.rb @@ -88,7 +88,7 @@ module Homebrew def tests args = tests_args.parse - Homebrew.install_bundler_gems!(groups: ["sorbet"]) + Homebrew.install_bundler_gems! require "byebug" if args.byebug? diff --git a/Library/Homebrew/dev-cmd/update-test.rb b/Library/Homebrew/dev-cmd/update-test.rb index 4e090cc948..69bfe66f0f 100644 --- a/Library/Homebrew/dev-cmd/update-test.rb +++ b/Library/Homebrew/dev-cmd/update-test.rb @@ -52,7 +52,8 @@ module Homebrew "master" end - start_commit, end_commit = nil + start_commit = nil + end_commit = "HEAD" cd HOMEBREW_REPOSITORY do start_commit = if (commit = args.commit) commit @@ -79,14 +80,13 @@ module Homebrew # ^0 ensures this points to the commit rather than the tag object. "#{previous_tag}^0" else - Utils.popen_read("git", "rev-parse", "origin/master").chomp + Utils.popen_read("git", "merge-base", "origin/master", end_commit).chomp end odie "Could not find start commit!" if start_commit.empty? start_commit = Utils.popen_read("git", "rev-parse", start_commit).chomp odie "Could not find start commit!" if start_commit.empty? - end_commit ||= "HEAD" end_commit = Utils.popen_read("git", "rev-parse", end_commit).chomp odie "Could not find end commit!" if end_commit.empty? diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb index a11c177654..44815e7cd1 100644 --- a/Library/Homebrew/download_strategy.rb +++ b/Library/Homebrew/download_strategy.rb @@ -1034,7 +1034,7 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy output, _, status = curl_output( "--silent", "--head", "--location", - "-H", "Accept: application/vnd.github.v3.sha", + "-H", "Accept: application/vnd.github.sha", "https://api.github.com/repos/#{@user}/#{@repo}/commits/#{@ref}" ) @@ -1051,7 +1051,7 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy output, _, status = curl_output( "--silent", "--head", "--location", - "-H", "Accept: application/vnd.github.v3.sha", + "-H", "Accept: application/vnd.github.sha", "https://api.github.com/repos/#{@user}/#{@repo}/commits/#{commit}" ) @@ -1280,7 +1280,7 @@ class BazaarDownloadStrategy < VCSDownloadStrategy def env { - "PATH" => PATH.new(Formula["bazaar"].opt_bin, ENV.fetch("PATH")), + "PATH" => PATH.new(Formula["breezy"].opt_bin, ENV.fetch("PATH")), "BZR_HOME" => HOMEBREW_TEMP, } end diff --git a/Library/Homebrew/env_config.rb b/Library/Homebrew/env_config.rb index 6397f0abb4..014b24d27d 100644 --- a/Library/Homebrew/env_config.rb +++ b/Library/Homebrew/env_config.rb @@ -36,6 +36,12 @@ module Homebrew "disable auto-update entirely with HOMEBREW_NO_AUTO_UPDATE.", default: 300, }, + HOMEBREW_AUTOREMOVE: { + description: "If set, calls to `brew cleanup` and `brew uninstall` will automatically " \ + "remove unused formula dependents and if HOMEBREW_NO_INSTALL_CLEANUP is not set, " \ + "`brew cleanup` will start running `brew autoremove` periodically.", + boolean: true, + }, HOMEBREW_BAT: { description: "If set, use `bat` for the `brew cat` command.", boolean: true, @@ -263,8 +269,8 @@ module Homebrew boolean: true, }, HOMEBREW_NO_CLEANUP_FORMULAE: { - description: "A comma-separated list of formulae. Homebrew will refuse to clean up a " \ - "formula if it appears on this list.", + description: "A comma-separated list of formulae. Homebrew will refuse to clean up " \ + "or autoremove a formula if it appears on this list.", }, HOMEBREW_NO_COLOR: { description: "If set, do not print text with colour added.", diff --git a/Library/Homebrew/extend/on_system.rb b/Library/Homebrew/extend/on_system.rb index 5ec59cbdfa..035940ba0b 100644 --- a/Library/Homebrew/extend/on_system.rb +++ b/Library/Homebrew/extend/on_system.rb @@ -15,25 +15,12 @@ module OnSystem def arch_condition_met?(arch) raise ArgumentError, "Invalid arch condition: #{arch.inspect}" if ARCH_OPTIONS.exclude?(arch) - current_arch = Homebrew::SimulateSystem.arch || Hardware::CPU.type - arch == current_arch + arch == Homebrew::SimulateSystem.current_arch end sig { params(os_name: Symbol, or_condition: T.nilable(Symbol)).returns(T::Boolean) } def os_condition_met?(os_name, or_condition = nil) - if Homebrew::EnvConfig.simulate_macos_on_linux? - return false if os_name == :linux - return true if [:macos, *MacOSVersions::SYMBOLS.keys].include?(os_name) - end - - if BASE_OS_OPTIONS.include?(os_name) - if Homebrew::SimulateSystem.none? - return OS.linux? if os_name == :linux - return OS.mac? if os_name == :macos - end - - return Homebrew::SimulateSystem.send("#{os_name}?") - end + return Homebrew::SimulateSystem.send("simulating_or_running_on_#{os_name}?") if BASE_OS_OPTIONS.include?(os_name) raise ArgumentError, "Invalid OS condition: #{os_name.inspect}" unless MacOSVersions::SYMBOLS.key?(os_name) @@ -41,10 +28,16 @@ module OnSystem raise ArgumentError, "Invalid OS `or_*` condition: #{or_condition.inspect}" end - return false if Homebrew::SimulateSystem.linux? || (Homebrew::SimulateSystem.none? && OS.linux?) + return false if Homebrew::SimulateSystem.simulating_or_running_on_linux? base_os = MacOS::Version.from_symbol(os_name) - current_os = MacOS::Version.from_symbol(Homebrew::SimulateSystem.os || MacOS.version.to_sym) + current_os = if Homebrew::SimulateSystem.current_os == :macos + # Assume the oldest macOS version when simulating a generic macOS version + # Version::NULL is always treated as less than any other version. + Version::NULL + else + MacOS::Version.from_symbol(Homebrew::SimulateSystem.current_os) + end return current_os >= base_os if or_condition == :or_newer return current_os <= base_os if or_condition == :or_older @@ -72,6 +65,13 @@ module OnSystem result end end + + base.define_method(:on_arch_conditional) do |arm: nil, intel: nil| + @on_system_blocks_exist = true + + return arm if OnSystem.arch_condition_met? :arm + return intel if OnSystem.arch_condition_met? :intel + end end sig { params(base: Class).void } diff --git a/Library/Homebrew/extend/os/linux/extend/ENV/super.rb b/Library/Homebrew/extend/os/linux/extend/ENV/super.rb index 9dbac81d0e..1f737b20c5 100644 --- a/Library/Homebrew/extend/os/linux/extend/ENV/super.rb +++ b/Library/Homebrew/extend/os/linux/extend/ENV/super.rb @@ -36,9 +36,21 @@ module Superenv paths end + def homebrew_extra_isystem_paths + paths = [] + # Add paths for GCC headers when building against glibc@2.13 because we have to use -nostdinc. + if deps.any? { |d| d.name == "glibc@2.13" } + gcc_include_dir = Utils.safe_popen_read(cc, "--print-file-name=include").chomp + gcc_include_fixed_dir = Utils.safe_popen_read(cc, "--print-file-name=include-fixed").chomp + paths << gcc_include_dir << gcc_include_fixed_dir + end + paths + end + def determine_rpath_paths(formula) PATH.new( *formula&.lib, + "#{HOMEBREW_PREFIX}/opt/gcc/lib/gcc/current", PATH.new(run_time_deps.map { |dep| dep.opt_lib.to_s }).existing, "#{HOMEBREW_PREFIX}/lib", ) diff --git a/Library/Homebrew/extend/os/linux/formula.rb b/Library/Homebrew/extend/os/linux/formula.rb index da2d162bdf..f3586103bc 100644 --- a/Library/Homebrew/extend/os/linux/formula.rb +++ b/Library/Homebrew/extend/os/linux/formula.rb @@ -23,17 +23,4 @@ class Formula sig { params(targets: T.nilable(T.any(Pathname, String))).void } def deuniversalize_machos(*targets); end - - class << self - undef ignore_missing_libraries - - def ignore_missing_libraries(*libs) - libraries = libs.flatten - if libraries.any? { |x| !x.is_a?(String) && !x.is_a?(Regexp) } - raise FormulaSpecificationError, "#{__method__} can handle Strings and Regular Expressions only" - end - - allowed_missing_libraries.merge(libraries) - end - end end diff --git a/Library/Homebrew/extend/os/linux/keg_relocate.rb b/Library/Homebrew/extend/os/linux/keg_relocate.rb index ee1537910c..887ff07c80 100644 --- a/Library/Homebrew/extend/os/linux/keg_relocate.rb +++ b/Library/Homebrew/extend/os/linux/keg_relocate.rb @@ -8,9 +8,6 @@ class Keg # Patching the dynamic linker of glibc breaks it. return if name.match? Version.formula_optionally_versioned_regex(:glibc) - # Patching patchelf fails with "Text file busy" or SIGBUS. - return if name == "patchelf" - old_prefix, new_prefix = relocation.replacement_pair_for(:prefix) elf_files.each do |file| @@ -33,6 +30,18 @@ class Keg lib_path = "#{new_prefix}/lib" rpath << lib_path unless rpath.include? lib_path + # Add GCC's lib directory (as of GCC 12+) to RPATH when there is existing linkage. + # This fixes linkage for newly-poured bottles. + if !name.match?(Version.formula_optionally_versioned_regex(:gcc)) && + rpath.any? { |rp| rp.match?(%r{lib/gcc/\d+$}) } + # TODO: Replace with + # rpath.map! { |path| path = path.sub(%r{lib/gcc/\d+$}, "lib/gcc/current") } + # when + # 1. Homebrew/homebrew-core#106755 is merged + # 2. No formula has a runtime dependency on a versioned GCC (see `envoy.rb`) + rpath.prepend HOMEBREW_PREFIX/"opt/gcc/lib/gcc/current" + end + rpath.join(":") end updated[:rpath] = new_rpath if old_rpath != new_rpath @@ -80,16 +89,4 @@ class Keg end elf_files end - - def self.bottle_dependencies - @bottle_dependencies ||= begin - formulae = [] - gcc = Formulary.factory(CompilerSelector.preferred_gcc) - if !Homebrew::EnvConfig.simulate_macos_on_linux? && - DevelopmentTools.non_apple_gcc_version("gcc") < gcc.version.to_i - formulae << gcc - end - formulae - end - end end diff --git a/Library/Homebrew/extend/os/linux/linkage_checker.rb b/Library/Homebrew/extend/os/linux/linkage_checker.rb index 4e2bbf557b..e94995e966 100644 --- a/Library/Homebrew/extend/os/linux/linkage_checker.rb +++ b/Library/Homebrew/extend/os/linux/linkage_checker.rb @@ -72,6 +72,9 @@ class LinkageChecker @unwanted_system_dylibs = @system_dylibs.reject do |s| SYSTEM_LIBRARY_ALLOWLIST.include? File.basename(s) end - @undeclared_deps -= [CompilerSelector.preferred_gcc, "glibc"] + # FIXME: Remove this when these dependencies are injected correctly (e.g. through `DependencyCollector`) + # See discussion at + # https://github.com/Homebrew/brew/pull/13577 + @undeclared_deps -= [CompilerSelector.preferred_gcc, "glibc", "gcc"] end end diff --git a/Library/Homebrew/extend/os/mac/software_spec.rb b/Library/Homebrew/extend/os/mac/software_spec.rb deleted file mode 100644 index 1be80083e2..0000000000 --- a/Library/Homebrew/extend/os/mac/software_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# typed: true -# frozen_string_literal: true - -# The Library/Homebrew/extend/os/software_spec.rb conditional logic will need to be more nuanced -# if this file ever includes more than `uses_from_macos`. -class SoftwareSpec - undef uses_from_macos - - def uses_from_macos(deps, bounds = {}) - if deps.is_a?(Hash) - bounds = deps.dup - deps = [bounds.shift].to_h - end - - @uses_from_macos_elements << deps - - bounds = bounds.transform_values { |v| MacOS::Version.from_symbol(v) } - - # Linux simulating macOS. Assume oldest macOS version. - return if Homebrew::EnvConfig.simulate_macos_on_linux? && !bounds.key?(:since) - - # macOS new enough for dependency to not be required. - return if MacOS.version >= bounds[:since] - - depends_on deps - end -end diff --git a/Library/Homebrew/extend/os/software_spec.rb b/Library/Homebrew/extend/os/software_spec.rb index 32f46468f7..1e6f8f529c 100644 --- a/Library/Homebrew/extend/os/software_spec.rb +++ b/Library/Homebrew/extend/os/software_spec.rb @@ -1,9 +1,4 @@ # typed: strict # frozen_string_literal: true -# This logic will need to be more nuanced if this file includes more than `uses_from_macos`. -if OS.mac? || Homebrew::EnvConfig.simulate_macos_on_linux? - require "extend/os/mac/software_spec" -elsif OS.linux? - require "extend/os/linux/software_spec" -end +require "extend/os/linux/software_spec" if OS.linux? diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index e5b3dc8c15..2e24947fb0 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -69,9 +69,6 @@ class Formula extend Cachable extend Predicable - # @!method inreplace(paths, before = nil, after = nil) - # @see Utils::Inreplace.inreplace - # The name of this {Formula}. # e.g. `this-formula` attr_reader :name @@ -1706,14 +1703,46 @@ class Formula end.uniq(&:name) end - # An array of all installed {Formula} without dependents + # An array of all installed {Formula} with {Cask} dependents. # @private - def self.installed_formulae_with_no_dependents(formulae = installed) + def self.formulae_with_cask_dependents(casks) + casks.flat_map { |cask| cask.depends_on[:formula] } + .compact + .map { |f| Formula[f] } + .flat_map { |f| [f, *f.runtime_formula_dependencies].compact } + end + + # An array of all installed {Formula} without {Formula} dependents + # @private + def self.formulae_with_no_formula_dependents(formulae) return [] if formulae.blank? formulae - formulae.flat_map(&:runtime_formula_dependencies) end + # Recursive function that returns an array of {Formula} without + # {Formula} dependents that weren't installed on request. + # @private + def self.unused_formulae_with_no_formula_dependents(formulae) + unused_formulae = formulae_with_no_formula_dependents(formulae).reject do |f| + Tab.for_keg(f.any_installed_keg).installed_on_request + end + + if unused_formulae.present? + unused_formulae += unused_formulae_with_no_formula_dependents(formulae - unused_formulae) + end + + unused_formulae + end + + # An array of {Formula} without {Formula} or {Cask} + # dependents that weren't installed on request. + # @private + def self.unused_formulae_with_no_dependents(formulae, casks) + unused_formulae = unused_formulae_with_no_formula_dependents(formulae) + unused_formulae - formulae_with_cask_dependents(casks) + end + def self.installed_with_alias_path(alias_path) return [] if alias_path.nil? @@ -2005,6 +2034,45 @@ class Formula hsh end + # @private + def to_hash_with_variations + hash = to_hash + variations = {} + + os_versions = [*MacOSVersions::SYMBOLS.keys, :linux] + + if path.exist? && self.class.on_system_blocks_exist? + formula_contents = path.read + [:arm, :intel].each do |arch| + os_versions.each do |os_name| + bottle_tag = Utils::Bottles::Tag.new(system: os_name, arch: arch) + next unless bottle_tag.valid_combination? + + Homebrew::SimulateSystem.os = os_name + Homebrew::SimulateSystem.arch = arch + + variations_namespace = Formulary.class_s("Variations#{bottle_tag.to_sym.capitalize}") + variations_formula_class = Formulary.load_formula(name, path, formula_contents, variations_namespace, + flags: self.class.build_flags, ignore_errors: true) + variations_formula = variations_formula_class.new(name, path, :stable, + alias_path: alias_path, force_bottle: force_bottle) + + variations_formula.to_hash.each do |key, value| + next if value.to_s == hash[key].to_s + + variations[bottle_tag.to_sym] ||= {} + variations[bottle_tag.to_sym][key] = value + end + end + end + end + + Homebrew::SimulateSystem.clear + + hash["variations"] = variations + hash + end + # @api private # Generate a hash to be used to install a formula from a JSON file def to_recursive_bottle_hash(top_level: true) @@ -2130,6 +2198,30 @@ class Formula # end def install; end + # Sometimes we have to change a bit before we install. Mostly we + # prefer a patch, but if you need the {Formula#prefix prefix} of + # this formula in the patch you have to resort to `inreplace`, + # because in the patch you don't have access to any variables + # defined by the formula, as only `HOMEBREW_PREFIX` is available + # in the {DATAPatch embedded patch}. + # + # `inreplace` supports regular expressions: + #
inreplace "somefile.cfg", /look[for]what?/, "replace by #{bin}/tool"
+ # + # `inreplace` supports blocks: + #
inreplace "Makefile" do |s|
+  #   s.gsub! "/usr/local", HOMEBREW_PREFIX.to_s
+  # end
+  # 
+ # + # @see Utils::Inreplace.inreplace + # @api public + def inreplace(paths, before = nil, after = nil, audit_result = true) # rubocop:disable Style/OptionalBooleanParameter + super(paths, before, after, audit_result) + rescue Utils::Inreplace::Error + raise BuildError.new(self, "inreplace", paths, nil) + end + protected def setup_home(home) @@ -2469,6 +2561,7 @@ class Formula # The methods below define the formula DSL. class << self + extend Predicable include BuildEnvironment::DSL include OnSystem::MacOSAndLinux @@ -2483,6 +2576,11 @@ class Formula end end + # Whether this formula contains OS/arch-specific blocks + # (e.g. `on_macos`, `on_arm`, `on_monterey :or_older`, `on_system :linux, macos: :big_sur_or_newer`). + # @private + attr_predicate :on_system_blocks_exist? + # The reason for why this software is not linked (by default) to # {::HOMEBREW_PREFIX}. # @private @@ -3169,8 +3267,17 @@ class Formula end # Permit links to certain libraries that don't exist. Available on Linux only. - def ignore_missing_libraries(*) - raise FormulaSpecificationError, "#{__method__} is available on Linux only" + def ignore_missing_libraries(*libs) + unless Homebrew::SimulateSystem.simulating_or_running_on_linux? + raise FormulaSpecificationError, "#{__method__} is available on Linux only" + end + + libraries = libs.flatten + if libraries.any? { |x| !x.is_a?(String) && !x.is_a?(Regexp) } + raise FormulaSpecificationError, "#{__method__} can handle Strings and Regular Expressions only" + end + + allowed_missing_libraries.merge(libraries) end # @private diff --git a/Library/Homebrew/formula.rbi b/Library/Homebrew/formula.rbi index f77f4c0c50..fc8d6c255c 100644 --- a/Library/Homebrew/formula.rbi +++ b/Library/Homebrew/formula.rbi @@ -49,6 +49,7 @@ class Formula def env; end def conflicts; end + def self.on_system_blocks_exist?; end # This method is included by `OnSystem` def self.on_macos(&block); end end diff --git a/Library/Homebrew/formula_auditor.rb b/Library/Homebrew/formula_auditor.rb index a06941104d..bb6507fefa 100644 --- a/Library/Homebrew/formula_auditor.rb +++ b/Library/Homebrew/formula_auditor.rb @@ -307,6 +307,13 @@ module Homebrew EOS end + if dep_f.deprecated? && !formula.deprecated? && !formula.disabled? + problem <<~EOS + Dependency '#{dep.name}' is deprecated but has un-deprecated dependents. Either + un-deprecate '#{dep.name}' or deprecate it and all of its dependents. + EOS + end + # we want to allow uses_from_macos for aliases but not bare dependencies if self.class.aliases.include?(dep.name) && spec.uses_from_macos_names.exclude?(dep.name) problem "Dependency '#{dep.name}' is an alias; use the canonical name '#{dep.to_formula.full_name}'." @@ -329,7 +336,7 @@ module Homebrew # The number of conflicts on Linux is absurd. # TODO: remove this and check these there too. - return if OS.linux? && !Homebrew::EnvConfig.simulate_macos_on_linux? + return if Homebrew::SimulateSystem.simulating_or_running_on_linux? recursive_runtime_formulae = formula.runtime_formula_dependencies(undeclared: false) version_hash = {} @@ -410,13 +417,11 @@ module Homebrew end def audit_glibc - return if formula.name != "glibc" return unless @core_tap + return if formula.name != "glibc" + return if [OS::CI_GLIBC_VERSION, "2.27", "2.31", "2.35"].include?(formula.version.to_s) - version = formula.version.to_s - return if version == OS::CI_GLIBC_VERSION - - problem "The glibc version must be #{version}, as this is the version used by our CI on Linux. " \ + problem "The glibc version must be #{OS::CI_GLIBC_VERSION}, as this is the version used by our CI on Linux. " \ "Glibc is for users who have a system Glibc with a lower version, " \ "which allows them to use our Linux bottles, which were compiled against system Glibc on CI." end diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 65858d3e43..658b211c62 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -136,6 +136,18 @@ module Formulary class_s = Formulary.class_s(name) json_formula = Homebrew::API::Formula.all_formulae[name] + if (bottle_tag = Utils::Bottles.tag.to_s.presence) && + (variations = json_formula["variations"].presence) && + (variation = variations[bottle_tag].presence) + json_formula = json_formula.merge(variation) + end + + uses_from_macos_names = json_formula["uses_from_macos"].map do |dep| + next dep unless dep.is_a? Hash + + dep.keys.first + end + klass = Class.new(::Formula) do desc json_formula["desc"] homepage json_formula["homepage"] @@ -176,20 +188,18 @@ module Formulary disable! date: disable_date, because: reason end - json_formula["build_dependencies"].each do |dep| - depends_on dep => :build - end - json_formula["dependencies"].each do |dep| + next if uses_from_macos_names.include? dep + depends_on dep end - json_formula["recommended_dependencies"].each do |dep| - depends_on dep => :recommended - end + [:build, :recommended, :optional].each do |type| + json_formula["#{type}_dependencies"].each do |dep| + next if uses_from_macos_names.include? dep - json_formula["optional_dependencies"].each do |dep| - depends_on dep => :optional + depends_on dep => type + end end json_formula["uses_from_macos"].each do |dep| @@ -264,6 +274,7 @@ module Formulary end def self.convert_to_deprecate_disable_reason_string_or_symbol(string) + require "deprecate_disable" return string unless DeprecateDisable::DEPRECATE_DISABLE_REASONS.keys.map(&:to_s).include?(string) string.to_sym diff --git a/Library/Homebrew/keg_relocate.rb b/Library/Homebrew/keg_relocate.rb index 1df8ee86a4..a396f43205 100644 --- a/Library/Homebrew/keg_relocate.rb +++ b/Library/Homebrew/keg_relocate.rb @@ -368,7 +368,14 @@ class Keg end def self.bottle_dependencies - [] + return [] unless Homebrew::SimulateSystem.simulating_or_running_on_linux? + + @bottle_dependencies ||= begin + formulae = [] + gcc = Formulary.factory(CompilerSelector.preferred_gcc) + formulae << gcc if DevelopmentTools.non_apple_gcc_version("gcc") < gcc.version.to_i + formulae + end end end diff --git a/Library/Homebrew/language/python.rb b/Library/Homebrew/language/python.rb index 958dbc2487..c0297a85cb 100644 --- a/Library/Homebrew/language/python.rb +++ b/Library/Homebrew/language/python.rb @@ -111,7 +111,8 @@ module Language raise ShebangDetectionError.new("Python", "formula has multiple Python dependencies") end - python_shebang_rewrite_info(Formula[python_deps.first].opt_bin/"python3") + python_dep = python_deps.first + python_shebang_rewrite_info(Formula[python_dep].opt_bin/python_dep.sub("@", "")) end end diff --git a/Library/Homebrew/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index b8732b2d34..7887ffe7de 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -198,7 +198,7 @@ class LinkageChecker # In macOS Big Sur and later, system libraries do not exist on-disk and instead exist in a cache. # If dlopen finds the dylib, then the linkage is not broken. @system_dylibs << dylib - else + elsif !system_framework?(dylib) @broken_dylibs << dylib end else @@ -306,11 +306,13 @@ class LinkageChecker def harmless_broken_link?(dylib) # libgcc_s_* is referenced by programs that use the Java Service Wrapper, # and is harmless on x86(_64) machines - return true if [ + [ "/usr/lib/libgcc_s_ppc64.1.dylib", "/opt/local/lib/libgcc/libgcc_s.1.dylib", ].include?(dylib) + end + def system_framework?(dylib) dylib.start_with?("/System/Library/Frameworks/") end diff --git a/Library/Homebrew/livecheck.rb b/Library/Homebrew/livecheck.rb index 66abd5142f..f02eef7e1e 100644 --- a/Library/Homebrew/livecheck.rb +++ b/Library/Homebrew/livecheck.rb @@ -143,7 +143,8 @@ class Livecheck end delegate version: :@package_or_resource - private :version + delegate arch: :@package_or_resource + private :version, :arch # Returns a `Hash` of all instance variable values. # @return [Hash] diff --git a/Library/Homebrew/official_taps.rb b/Library/Homebrew/official_taps.rb index 8e574a3747..75c0f232db 100644 --- a/Library/Homebrew/official_taps.rb +++ b/Library/Homebrew/official_taps.rb @@ -3,7 +3,9 @@ OFFICIAL_CASK_TAPS = %w[ cask - versions + cask-drivers + cask-fonts + cask-versions ].freeze OFFICIAL_CMD_TAPS = { diff --git a/Library/Homebrew/resource_auditor.rb b/Library/Homebrew/resource_auditor.rb index 8155d311c0..624f2b8e07 100644 --- a/Library/Homebrew/resource_auditor.rb +++ b/Library/Homebrew/resource_auditor.rb @@ -105,7 +105,7 @@ module Homebrew # Ideally `ca-certificates` would not be excluded here, but sourcing a HTTP mirror was tricky. # Instead, we have logic elsewhere to pass `--insecure` to curl when downloading the certs. # TODO: try remove the OS/env conditional - if (OS.mac? || Homebrew::EnvConfig.simulate_macos_on_linux?) && spec_name == :stable && + if Homebrew::SimulateSystem.simulating_or_running_on_macos? && spec_name == :stable && owner.name != "ca-certificates" && curl_dep && !urls.find { |u| u.start_with?("http://") } problem "should always include at least one HTTP mirror" end diff --git a/Library/Homebrew/rubocops/components_order.rb b/Library/Homebrew/rubocops/components_order.rb index 094ef0bfce..5d28a172a1 100644 --- a/Library/Homebrew/rubocops/components_order.rb +++ b/Library/Homebrew/rubocops/components_order.rb @@ -14,12 +14,6 @@ module RuboCop class ComponentsOrder < FormulaCop extend AutoCorrector - def on_system_methods - @on_system_methods ||= [:intel, :arm, :macos, :linux, *MacOSVersions::SYMBOLS.keys].map do |m| - :"on_#{m}" - end - end - def audit_formula(_node, _class_node, _parent_class_node, body_node) @present_components, @offensive_nodes = check_order(FORMULA_COMPONENT_PRECEDENCE_LIST, body_node) @@ -116,6 +110,15 @@ module RuboCop end def check_on_system_block_content(component_precedence_list, on_system_block) + if on_system_block.body.block_type? && !on_system_methods.include?(on_system_block.body.method_name) + offending_node(on_system_block) + problem "Nest `#{on_system_block.method_name}` blocks inside `#{on_system_block.body.method_name}` " \ + "blocks when there is only one inner block." do |corrector| + original_source = on_system_block.source.split("\n") + new_source = [original_source.second, original_source.first, *original_source.drop(2)] + corrector.replace(on_system_block.source_range, new_source.join("\n")) + end + end on_system_allowed_methods = %w[ depends_on patch diff --git a/Library/Homebrew/rubocops/dependency_order.rb b/Library/Homebrew/rubocops/dependency_order.rb index fc12fe4119..34775de930 100644 --- a/Library/Homebrew/rubocops/dependency_order.rb +++ b/Library/Homebrew/rubocops/dependency_order.rb @@ -16,7 +16,7 @@ module RuboCop def audit_formula(_node, _class_node, _parent_class_node, body_node) check_dependency_nodes_order(body_node) check_uses_from_macos_nodes_order(body_node) - [:head, :stable].each do |block_name| + ([:head, :stable] + on_system_methods).each do |block_name| block = find_block(body_node, block_name) next unless block diff --git a/Library/Homebrew/rubocops/extend/formula.rb b/Library/Homebrew/rubocops/extend/formula.rb index e6cc658350..d4b09bab73 100644 --- a/Library/Homebrew/rubocops/extend/formula.rb +++ b/Library/Homebrew/rubocops/extend/formula.rb @@ -198,6 +198,12 @@ module RuboCop @file_path !~ Regexp.union(paths_to_exclude) end + + def on_system_methods + @on_system_methods ||= [:intel, :arm, :macos, :linux, :system, *MacOSVersions::SYMBOLS.keys].map do |m| + :"on_#{m}" + end + end end end end diff --git a/Library/Homebrew/rubocops/lines.rb b/Library/Homebrew/rubocops/lines.rb index cbac0882a0..e8c7a631a3 100644 --- a/Library/Homebrew/rubocops/lines.rb +++ b/Library/Homebrew/rubocops/lines.rb @@ -1,6 +1,7 @@ # typed: true # frozen_string_literal: true +require "macos_versions" require "rubocops/extend/formula" module RuboCop @@ -375,61 +376,171 @@ module RuboCop # This cop makes sure that OS conditionals are consistent. # # @api private - class OSConditionals < FormulaCop + class OnSystemConditionals < FormulaCop extend AutoCorrector + NO_ON_SYSTEM_METHOD_NAMES = [:install, :post_install].freeze + NO_ON_SYSTEM_BLOCK_NAMES = [:service, :test].freeze + + ON_ARCH_OPTIONS = [:intel, :arm].freeze + ON_BASE_OS_OPTIONS = [:macos, :linux].freeze + ON_MACOS_VERSION_OPTIONS = MacOSVersions::SYMBOLS.keys.freeze + ALL_SYSTEM_OPTIONS = [*ON_ARCH_OPTIONS, *ON_BASE_OS_OPTIONS, *ON_MACOS_VERSION_OPTIONS, :system].freeze + + MACOS_VERSION_CONDITIONALS = { + "==" => nil, + "<=" => :or_older, + ">=" => :or_newer, + }.freeze + + ON_SYSTEM_CONDITIONALS = [:<, :<=].freeze + + def on_system_method_info(on_system_option) + info = {} + info[:method] = :"on_#{on_system_option}" + info[:if_module], info[:if_method] = if ON_ARCH_OPTIONS.include?(on_system_option) + ["Hardware::CPU", :"#{on_system_option}?"] + elsif ON_BASE_OS_OPTIONS.include?(on_system_option) + ["OS", on_system_option == :macos ? :mac? : :linux?] + else + ["MacOS", :version] + end + info[:on_system_string] = "on_#{on_system_option}" + info[:if_string] = if on_system_option == :system + "if OS.linux? || MacOS.version" + else + "if #{info[:if_module]}.#{info[:if_method]}" + end + + info + end + def audit_formula(_node, _class_node, _parent_class_node, body_node) - no_on_os_method_names = [:install, :post_install].freeze - no_on_os_block_names = [:service, :test].freeze - [[:on_macos, :mac?], [:on_linux, :linux?]].each do |on_method_name, if_method_name| - if_method_and_class = "if OS.#{if_method_name}" - no_on_os_method_names.each do |formula_method_name| - method_node = find_method_def(body_node, formula_method_name) - next unless method_node - next unless method_called_ever?(method_node, on_method_name) + top_level_nodes_to_check = [] + NO_ON_SYSTEM_METHOD_NAMES.each do |formula_method_name| + method_node = find_method_def(body_node, formula_method_name) + top_level_nodes_to_check << [formula_method_name, method_node] if method_node + end + NO_ON_SYSTEM_BLOCK_NAMES.each do |formula_block_name| + block_node = find_block(body_node, formula_block_name) + top_level_nodes_to_check << [formula_block_name, block_node] if block_node + end - problem "Don't use '#{on_method_name}' in 'def #{formula_method_name}', " \ - "use '#{if_method_and_class}' instead." do |corrector| - block_node = offending_node.parent - next if block_node.type != :block + ALL_SYSTEM_OPTIONS.each do |on_system_option| + method_info = on_system_method_info(on_system_option) - # TODO: could fix corrector to handle this but punting for now. - next if block_node.single_line? + top_level_nodes_to_check.each do |top_level_name, top_level_node| + top_level_node_string = if top_level_node.def_type? + "def #{top_level_name}" + else + "#{top_level_name} do" + end - source_range = offending_node.source_range.join(offending_node.parent.loc.begin) - corrector.replace(source_range, if_method_and_class) + find_every_method_call_by_name(top_level_node, method_info[:method]).each do |method| + if ON_MACOS_VERSION_OPTIONS.include?(on_system_option) + on_macos_version_method_call(method, on_method: method_info[:method]) do |on_method_parameters| + if on_method_parameters.empty? + method_info[:if_string] = "if MacOS.version == :#{on_system_option}" + else + method_info[:on_system_string] = "#{method_info[:method]} :#{on_method_parameters.first}" + if_condition_operator = MACOS_VERSION_CONDITIONALS.key(on_method_parameters.first) + method_info[:if_string] = "if MacOS.version #{if_condition_operator} :#{on_system_option}" + end + end + elsif method_info[:method] == :on_system + on_system_method_call(method) do |macos_symbol| + base_os, condition = macos_symbol.to_s.split(/_(?=or_)/).map(&:to_sym) + method_info[:on_system_string] = if condition.present? + "on_system :linux, macos: :#{base_os}_#{condition}" + else + "on_system :linux, macos: :#{base_os}" + end + if_condition_operator = MACOS_VERSION_CONDITIONALS.key(condition) + method_info[:if_string] = "if OS.linux? || MacOS.version #{if_condition_operator} :#{base_os}" + end + end + + offending_node(method) + + problem "Don't use `#{method_info[:on_system_string]}` in `#{top_level_node_string}`, " \ + "use `#{method_info[:if_string]}` instead." do |corrector| + block_node = offending_node.parent + next if block_node.type != :block + + # TODO: could fix corrector to handle this but punting for now. + next if block_node.single_line? + + source_range = offending_node.source_range.join(offending_node.parent.loc.begin) + corrector.replace(source_range, method_info[:if_string]) + end + end + end + end + + # Don't restrict OS.mac? or OS.linux? usage in taps; they don't care + # as much as we do about e.g. formulae.brew.sh generation, often use + # platform-specific URLs and we don't want to add DSLs to support + # that case. + return if formula_tap != "homebrew-core" + + ALL_SYSTEM_OPTIONS.each do |on_system_option| + method_info = on_system_method_info(on_system_option) + + if_nodes_to_check = [] + + if ON_ARCH_OPTIONS.include?(on_system_option) + if_arch_node_search(body_node, arch: method_info[:if_method]) do |if_node, else_node| + else_info = if else_node.present? + { + can_autocorrect: true, + on_system_method: on_system_option == :intel ? "on_arm" : "on_intel", + node: else_node, + } + end + + if_nodes_to_check << [if_node, else_info] + end + elsif ON_BASE_OS_OPTIONS.include?(on_system_option) + if_base_os_node_search(body_node, base_os: method_info[:if_method]) do |if_node, else_node| + else_info = if else_node.present? + { + can_autocorrect: true, + on_system_method: on_system_option == :macos ? "on_linux" : "on_macos", + node: else_node, + } + end + + if_nodes_to_check << [if_node, else_info] + end + else + if_macos_version_node_search(body_node, os_name: on_system_option) do |if_node, operator, else_node| + if operator == :< + method_info[:on_system_string] = "on_system" + elsif operator == :<= + method_info[:on_system_string] = "on_system :linux, macos: :#{on_system_option}_or_older" + elsif operator != :== && MACOS_VERSION_CONDITIONALS.key?(operator.to_s) + method_info[:on_system_string] = "#{method_info[:method]} " \ + ":#{MACOS_VERSION_CONDITIONALS[operator.to_s]}" + end + method_info[:if_string] = "if #{method_info[:if_module]}.#{method_info[:if_method]} #{operator} " \ + ":#{on_system_option}" + if else_node.present? || !MACOS_VERSION_CONDITIONALS.key?(operator.to_s) + else_info = { can_autocorrect: false } + end + + if_nodes_to_check << [if_node, else_info] end end - no_on_os_block_names.each do |formula_block_name| - block_node = find_block(body_node, formula_block_name) - next unless block_node - next unless block_method_called_in_block?(block_node, on_method_name) - - problem "Don't use '#{on_method_name}' in '#{formula_block_name} do', " \ - "use '#{if_method_and_class}' instead." do |corrector| - # TODO: could fix corrector to handle this but punting for now. - next if offending_node.single_line? - - source_range = offending_node.send_node.source_range.join(offending_node.body.source_range.begin) - corrector.replace(source_range, "#{if_method_and_class}\n") - end - end - - # Don't restrict OS.mac? or OS.linux? usage in taps; they don't care - # as much as we do about e.g. formulae.brew.sh generation, often use - # platform-specific URLs and we don't want to add DSLs to support - # that case. - next if formula_tap != "homebrew-core" - - find_instance_method_call(body_node, "OS", if_method_name) do |method| + if_nodes_to_check.each do |if_node, else_info| + # TODO: check to see if it's legal valid = T.let(false, T::Boolean) - method.each_ancestor do |ancestor| + if_node.each_ancestor do |ancestor| valid_method_names = case ancestor.type when :def - no_on_os_method_names + NO_ON_SYSTEM_METHOD_NAMES when :block - no_on_os_block_names + NO_ON_SYSTEM_BLOCK_NAMES else next end @@ -440,19 +551,47 @@ module RuboCop end next if valid - offending_node(method) - problem "Don't use '#{if_method_and_class}', use '#{on_method_name} do' instead." do |corrector| - if_node = method.parent - next if if_node.type != :if + offending_node(if_node) + problem "Don't use `#{method_info[:if_string]}`, " \ + "use `#{method_info[:on_system_string]} do` instead." do |corrector| # TODO: could fix corrector to handle this but punting for now. next if if_node.unless? - corrector.replace(if_node.source_range, "#{on_method_name} do\n#{if_node.body.source}\nend") + if else_info.present? + next unless else_info[:can_autocorrect] + + corrector.replace(if_node.source_range, + "#{method_info[:on_system_string]} do\n#{if_node.body.source}\nend\n" \ + "#{else_info[:on_system_method]} do\n#{else_info[:node].source}\nend") + else + corrector.replace(if_node.source_range, + "#{method_info[:on_system_string]} do\n#{if_node.body.source}\nend") + end end end end end + + def_node_matcher :on_macos_version_method_call, <<~PATTERN + (send nil? %on_method (sym ${:or_newer :or_older})?) + PATTERN + + def_node_matcher :on_system_method_call, <<~PATTERN + (send nil? :on_system (sym :linux) (hash (pair (sym :macos) (sym $_)))) + PATTERN + + def_node_search :if_arch_node_search, <<~PATTERN + $(if (send (const (const nil? :Hardware) :CPU) %arch) _ $_) + PATTERN + + def_node_search :if_base_os_node_search, <<~PATTERN + $(if (send (const nil? :OS) %base_os) _ $_) + PATTERN + + def_node_search :if_macos_version_node_search, <<~PATTERN + $(if (send (send (const nil? :MacOS) :version) ${:== :<= :< :>= :> :!=} (sym %os_name)) _ $_) + PATTERN end # This cop checks for other miscellaneous style violations. diff --git a/Library/Homebrew/rubocops/lines.rbi b/Library/Homebrew/rubocops/lines.rbi new file mode 100644 index 0000000000..4036b6dd7b --- /dev/null +++ b/Library/Homebrew/rubocops/lines.rbi @@ -0,0 +1,24 @@ +# typed: strict + +module RuboCop + module Cop + module FormulaAudit + class OnSystemConditionals < FormulaCop + sig { params(node: T.any, on_method: Symbol, block: T.proc.params(parameters: T::Array[T.any]).void).void } + def on_macos_version_method_call(node, on_method:, &block); end + + sig { params(node: T.any, block: T.proc.params(macos_symbol: Symbol).void).void } + def on_system_method_call(node, &block); end + + sig { params(node: T.any, arch: Symbol, block: T.proc.params(node: T.any, else_node: T.any).void).void } + def if_arch_node_search(node, arch:, &block); end + + sig { params(node: T.any, base_os: Symbol, block: T.proc.params(node: T.any, else_node: T.any).void).void } + def if_base_os_node_search(node, base_os:, &block); end + + sig { params(node: T.any, os_name: Symbol, block: T.proc.params(node: T.any, operator: Symbol, else_node: T.any).void).void } + def if_macos_version_node_search(node, os_name:, &block); end + end + end + end +end diff --git a/Library/Homebrew/rubocops/uses_from_macos.rb b/Library/Homebrew/rubocops/uses_from_macos.rb index d4830ef6ad..d719d42e1d 100644 --- a/Library/Homebrew/rubocops/uses_from_macos.rb +++ b/Library/Homebrew/rubocops/uses_from_macos.rb @@ -82,6 +82,7 @@ module RuboCop git groff gzip + less openssl perl php diff --git a/Library/Homebrew/service.rb b/Library/Homebrew/service.rb index 6ba9919862..f40cff066f 100644 --- a/Library/Homebrew/service.rb +++ b/Library/Homebrew/service.rb @@ -376,6 +376,14 @@ module Homebrew base[:StartCalendarInterval] = @cron.reject { |_, value| value == "*" } end + # Adding all session types has as the primary effect that if you initialise it through e.g. a Background session + # and you later "physically" sign in to the owning account (Aqua session), things shouldn't flip out. + # Also, we're not checking @process_type here because that is used to indicate process priority and not + # necessarily if it should run in a specific session type. Like database services could run with ProcessType + # Interactive so they have no resource limitations enforced upon them, but they aren't really interactive in the + # general sense. + base[:LimitLoadToSessionType] = %w[Aqua Background LoginWindow StandardIO System] + base.to_plist end diff --git a/Library/Homebrew/shims/super/cc b/Library/Homebrew/shims/super/cc index 830f569ea5..be4a3a5c1a 100755 --- a/Library/Homebrew/shims/super/cc +++ b/Library/Homebrew/shims/super/cc @@ -305,7 +305,11 @@ class Cmd end def cppflags - path_flags("-isystem", isystem_paths) + path_flags("-I", include_paths) + args = [] + args += path_flags("-isystem", isystem_paths) + path_flags("-I", include_paths) + # Add -nostdinc when building against glibc@2.13 to avoid mixing system and brewed glibc headers. + args << "-nostdinc" if @deps.include?("glibc@2.13") + args end def ldflags_mac(args) @@ -323,10 +327,17 @@ class Cmd def ldflags_linux(args) unless mode == :ld wl = "-Wl," - args << "-B#{@opt}/glibc/lib" + if @deps.include?("glibc@2.13") + args << "-B#{@opt}/glibc@2.13/lib" + else + args << "-B#{@opt}/glibc/lib" + end end args += rpath_flags("#{wl}-rpath=", rpath_paths) args += ["#{wl}--dynamic-linker=#{dynamic_linker_path}"] if dynamic_linker_path + # Use -rpath-link to make sure linker uses glibc@2.13 rather than the system glibc for indirect + # dependencies because -L will only handle direct dependencies. + args << "#{wl}-rpath-link=#{@opt}/glibc@2.13/lib" if @deps.include?("glibc@2.13") args end diff --git a/Library/Homebrew/simulate_system.rb b/Library/Homebrew/simulate_system.rb index d52a2af752..206e9a460f 100644 --- a/Library/Homebrew/simulate_system.rb +++ b/Library/Homebrew/simulate_system.rb @@ -9,7 +9,14 @@ module Homebrew class << self extend T::Sig - attr_reader :os, :arch + attr_reader :arch + + sig { returns(T.nilable(Symbol)) } + def os + return :macos if @os.blank? && !OS.mac? && Homebrew::EnvConfig.simulate_macos_on_linux? + + @os + end sig { params(new_os: Symbol).void } def os=(new_os) @@ -32,18 +39,30 @@ module Homebrew end sig { returns(T::Boolean) } - def none? - @os.nil? && @arch.nil? + def simulating_or_running_on_macos? + return OS.mac? if os.blank? + + [:macos, *MacOSVersions::SYMBOLS.keys].include?(os) end sig { returns(T::Boolean) } - def macos? - [:macos, *MacOSVersions::SYMBOLS.keys].include?(@os) + def simulating_or_running_on_linux? + return OS.linux? if os.blank? + + os == :linux end - sig { returns(T::Boolean) } - def linux? - @os == :linux + sig { returns(Symbol) } + def current_arch + @arch || Hardware::CPU.type + end + + sig { returns(Symbol) } + def current_os + return T.must(os) if os.present? + return :linux if OS.linux? + + MacOS.version.to_sym end end end diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb index dc7fdfbfa4..0a246d3469 100644 --- a/Library/Homebrew/software_spec.rb +++ b/Library/Homebrew/software_spec.rb @@ -162,12 +162,27 @@ class SoftwareSpec add_dep_option(dep) if dep end - def uses_from_macos(spec, _bounds = {}) - spec = [spec.dup.shift].to_h if spec.is_a?(Hash) + def uses_from_macos(deps, bounds = {}) + if deps.is_a?(Hash) + bounds = deps.dup + deps = [bounds.shift].to_h + end - @uses_from_macos_elements << spec + @uses_from_macos_elements << deps - depends_on(spec) + # Check whether macOS is new enough for dependency to not be required. + if Homebrew::SimulateSystem.simulating_or_running_on_macos? + # Assume the oldest macOS version when simulating a generic macOS version + return if Homebrew::SimulateSystem.current_os == :macos && !bounds.key?(:since) + + if Homebrew::SimulateSystem.current_os != :macos + current_os = MacOS::Version.from_symbol(Homebrew::SimulateSystem.current_os) + since_os = MacOS::Version.from_symbol(bounds[:since]) if bounds.key?(:since) + return if current_os >= since_os + end + end + + depends_on deps end def uses_from_macos_names @@ -205,6 +220,8 @@ class SoftwareSpec def patch(strip = :p1, src = nil, &block) p = Patch.create(strip, src, &block) + return if p.is_a?(ExternalPatch) && p.url.blank? + dependency_collector.add(p.resource) if p.is_a? ExternalPatch patches << p end diff --git a/Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.14.2.rbi b/Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.14.3.rbi similarity index 99% rename from Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.14.2.rbi rename to Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.14.3.rbi index f1de306aba..377295ca1c 100644 --- a/Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.14.2.rbi +++ b/Library/Homebrew/sorbet/rbi/gems/rubocop-performance@1.14.3.rbi @@ -6,6 +6,7 @@ module RuboCop; end module RuboCop::Cop; end +RuboCop::Cop::IgnoredPattern = RuboCop::Cop::AllowedPattern module RuboCop::Cop::Performance; end class RuboCop::Cop::Performance::AncestorsInclude < ::RuboCop::Cop::Base diff --git a/Library/Homebrew/sorbet/rbi/gems/rubocop@1.31.2.rbi b/Library/Homebrew/sorbet/rbi/gems/rubocop@1.32.0.rbi similarity index 99% rename from Library/Homebrew/sorbet/rbi/gems/rubocop@1.31.2.rbi rename to Library/Homebrew/sorbet/rbi/gems/rubocop@1.32.0.rbi index 4a1c47c8fa..fb54326192 100644 --- a/Library/Homebrew/sorbet/rbi/gems/rubocop@1.31.2.rbi +++ b/Library/Homebrew/sorbet/rbi/gems/rubocop@1.32.0.rbi @@ -3157,13 +3157,15 @@ class RuboCop::Cop::Layout::LineContinuationLeadingSpace < ::RuboCop::Cop::Base private def continuation?(line); end - def investigate(first_line, second_line, range_start); end - def offense_range(range_start, matches); end + def enforced_style_leading?; end + def investigate_leading_style(first_line, end_of_first_line); end + def investigate_trailing_style(second_line, end_of_first_line); end + def leading_offense_range(end_of_first_line, matches); end + def message(_range); end def raw_lines(node); end + def trailing_offense_range(end_of_first_line, matches); end end -RuboCop::Cop::Layout::LineContinuationLeadingSpace::MSG = T.let(T.unsafe(nil), String) - class RuboCop::Cop::Layout::LineContinuationSpacing < ::RuboCop::Cop::Base include ::RuboCop::Cop::RangeHelp extend ::RuboCop::Cop::AutoCorrector @@ -3216,6 +3218,7 @@ class RuboCop::Cop::Layout::LineLength < ::RuboCop::Cop::Base def max=(value); end def on_array(node); end def on_block(node); end + def on_def(node); end def on_hash(node); end def on_investigation_end; end def on_new_investigation; end @@ -3417,6 +3420,15 @@ RuboCop::Cop::Layout::MultilineMethodDefinitionBraceLayout::ALWAYS_SAME_LINE_MES RuboCop::Cop::Layout::MultilineMethodDefinitionBraceLayout::NEW_LINE_MESSAGE = T.let(T.unsafe(nil), String) RuboCop::Cop::Layout::MultilineMethodDefinitionBraceLayout::SAME_LINE_MESSAGE = T.let(T.unsafe(nil), String) +class RuboCop::Cop::Layout::MultilineMethodParameterLineBreaks < ::RuboCop::Cop::Base + include ::RuboCop::Cop::MultilineElementLineBreaks + extend ::RuboCop::Cop::AutoCorrector + + def on_def(node); end +end + +RuboCop::Cop::Layout::MultilineMethodParameterLineBreaks::MSG = T.let(T.unsafe(nil), String) + class RuboCop::Cop::Layout::MultilineOperationIndentation < ::RuboCop::Cop::Base include ::RuboCop::Cop::ConfigurableEnforcedStyle include ::RuboCop::Cop::Alignment @@ -5128,14 +5140,21 @@ class RuboCop::Cop::Lint::NonAtomicFileOperation < ::RuboCop::Cop::Base def allowable_use_with_if?(if_node); end def autocorrect(corrector, node, range); end + def autocorrect_replace_method(corrector, node); end + def force_method?(node); end + def force_method_name?(node); end def force_option?(node); end - def message(node); end + def if_node_child?(node); end + def message_remove_file_exist_check(node); end def register_offense(node, exist_node); end def replacement_method(node); end end +RuboCop::Cop::Lint::NonAtomicFileOperation::MAKE_FORCE_METHODS = T.let(T.unsafe(nil), Array) RuboCop::Cop::Lint::NonAtomicFileOperation::MAKE_METHODS = T.let(T.unsafe(nil), Array) -RuboCop::Cop::Lint::NonAtomicFileOperation::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Lint::NonAtomicFileOperation::MSG_CHANGE_FORCE_METHOD = T.let(T.unsafe(nil), String) +RuboCop::Cop::Lint::NonAtomicFileOperation::MSG_REMOVE_FILE_EXIST_CHECK = T.let(T.unsafe(nil), String) +RuboCop::Cop::Lint::NonAtomicFileOperation::REMOVE_FORCE_METHODS = T.let(T.unsafe(nil), Array) RuboCop::Cop::Lint::NonAtomicFileOperation::REMOVE_METHODS = T.let(T.unsafe(nil), Array) RuboCop::Cop::Lint::NonAtomicFileOperation::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) @@ -5554,6 +5573,13 @@ end RuboCop::Cop::Lint::RequireParentheses::MSG = T.let(T.unsafe(nil), String) +class RuboCop::Cop::Lint::RequireRangeParentheses < ::RuboCop::Cop::Base + def on_erange(node); end + def on_irange(node); end +end + +RuboCop::Cop::Lint::RequireRangeParentheses::MSG = T.let(T.unsafe(nil), String) + class RuboCop::Cop::Lint::RequireRelativeSelfPath < ::RuboCop::Cop::Base include ::RuboCop::Cop::RangeHelp extend ::RuboCop::Cop::AutoCorrector @@ -5605,6 +5631,7 @@ RuboCop::Cop::Lint::ReturnInVoidContext::MSG = T.let(T.unsafe(nil), String) class RuboCop::Cop::Lint::SafeNavigationChain < ::RuboCop::Cop::Base include ::RuboCop::Cop::AllowedMethods include ::RuboCop::Cop::NilMethods + extend ::RuboCop::Cop::AutoCorrector extend ::RuboCop::Cop::TargetRubyVersion def bad_method?(param0 = T.unsafe(nil)); end @@ -5612,6 +5639,8 @@ class RuboCop::Cop::Lint::SafeNavigationChain < ::RuboCop::Cop::Base private + def add_safe_navigation_operator(offense_range:, send_node:); end + def autocorrect(corrector, offense_range:, send_node:); end def method_chain(node); end end @@ -7127,11 +7156,16 @@ module RuboCop::Cop::PercentArray private def allowed_bracket_array?(node); end + def build_bracketed_array_with_appropriate_whitespace(elements:, node:); end + def build_message_for_bracketed_array(preferred_array_code); end def check_bracketed_array(node, literal_prefix); end def check_percent_array(node); end def comments_in_array?(node); end def invalid_percent_array_contents?(_node); end def invalid_percent_array_context?(node); end + def whitespace_between(node); end + def whitespace_leading(node); end + def whitespace_trailing(node); end end module RuboCop::Cop::PercentLiteral @@ -8551,6 +8585,16 @@ end RuboCop::Cop::Style::EmptyElse::MSG = T.let(T.unsafe(nil), String) +class RuboCop::Cop::Style::EmptyHeredoc < ::RuboCop::Cop::Base + include ::RuboCop::Cop::Heredoc + include ::RuboCop::Cop::RangeHelp + extend ::RuboCop::Cop::AutoCorrector + + def on_heredoc(node); end +end + +RuboCop::Cop::Style::EmptyHeredoc::MSG = T.let(T.unsafe(nil), String) + class RuboCop::Cop::Style::EmptyLambdaParameter < ::RuboCop::Cop::Base include ::RuboCop::Cop::EmptyParameter include ::RuboCop::Cop::RangeHelp @@ -8791,47 +8835,25 @@ RuboCop::Cop::Style::ExponentialNotation::MESSAGES = T.let(T.unsafe(nil), Hash) class RuboCop::Cop::Style::FetchEnvVar < ::RuboCop::Cop::Base extend ::RuboCop::Cop::AutoCorrector - def block_control?(param0 = T.unsafe(nil)); end def env_with_bracket?(param0 = T.unsafe(nil)); end - def offensive_nodes(param0); end def on_send(node); end - def operand_of_or?(param0 = T.unsafe(nil)); end private def allowable_use?(node); end def allowed_var?(node); end def assigned?(node); end - def configured_indentation; end - def conterpart_rhs_of(node); end - def default_nil(node, name_node); end - def default_rhs(node, name_node); end - def default_rhs_in_outer_or(node, name_node); end - def default_rhs_in_same_or(node, name_node); end - def default_to_rhs?(node); end - def first_line_of(source); end - def left_end_of_or_chains?(node); end def message_chained_with_dot?(node); end - def message_template_for(rhs); end - def new_code_default_nil(name_node); end - def new_code_default_rhs(node, name_node); end - def new_code_default_rhs_multiline(node, name_node); end - def new_code_default_rhs_single_line(node, name_node); end + def new_code(name_node); end def offensive?(node); end - def or_chain_root(node); end + def or_lhs?(node); end def partial_matched?(node, condition); end - def rhs_can_be_default_value?(node); end - def rhs_is_block_control?(node); end - def right_end_of_or_chains?(node); end def used_as_flag?(node); end def used_if_condition_in_body(node); end def used_in_condition?(node, condition); end end -RuboCop::Cop::Style::FetchEnvVar::MSG_DEFAULT_NIL = T.let(T.unsafe(nil), String) -RuboCop::Cop::Style::FetchEnvVar::MSG_DEFAULT_RHS_MULTILINE_BLOCK = T.let(T.unsafe(nil), String) -RuboCop::Cop::Style::FetchEnvVar::MSG_DEFAULT_RHS_SECOND_ARG_OF_FETCH = T.let(T.unsafe(nil), String) -RuboCop::Cop::Style::FetchEnvVar::MSG_DEFAULT_RHS_SINGLE_LINE_BLOCK = T.let(T.unsafe(nil), String) +RuboCop::Cop::Style::FetchEnvVar::MSG = T.let(T.unsafe(nil), String) class RuboCop::Cop::Style::FileRead < ::RuboCop::Cop::Base include ::RuboCop::Cop::RangeHelp @@ -11453,8 +11475,10 @@ class RuboCop::Cop::Style::Semicolon < ::RuboCop::Cop::Base def check_for_line_terminator_or_opener; end def each_semicolon; end def expressions_per_line(exprs); end + def find_range_node(token_before_semicolon); end def find_semicolon_positions(line); end - def register_semicolon(line, column, after_expression); end + def range_nodes; end + def register_semicolon(line, column, after_expression, token_before_semicolon = T.unsafe(nil)); end def tokens_for_lines; end class << self @@ -11971,6 +11995,7 @@ class RuboCop::Cop::Style::TopLevelMethodDefinition < ::RuboCop::Cop::Base end RuboCop::Cop::Style::TopLevelMethodDefinition::MSG = T.let(T.unsafe(nil), String) +RuboCop::Cop::Style::TopLevelMethodDefinition::RESTRICT_ON_SEND = T.let(T.unsafe(nil), Array) class RuboCop::Cop::Style::TrailingBodyOnClass < ::RuboCop::Cop::Base include ::RuboCop::Cop::Alignment diff --git a/Library/Homebrew/sorbet/rbi/gems/tzinfo@2.0.4.rbi b/Library/Homebrew/sorbet/rbi/gems/tzinfo@2.0.5.rbi similarity index 99% rename from Library/Homebrew/sorbet/rbi/gems/tzinfo@2.0.4.rbi rename to Library/Homebrew/sorbet/rbi/gems/tzinfo@2.0.5.rbi index 4928930bce..144492478e 100644 --- a/Library/Homebrew/sorbet/rbi/gems/tzinfo@2.0.4.rbi +++ b/Library/Homebrew/sorbet/rbi/gems/tzinfo@2.0.5.rbi @@ -4,7 +4,11 @@ # This is an autogenerated file for types exported from the `tzinfo` gem. # Please instead update this file by running `bin/tapioca gem tzinfo`. -module TZInfo; end +module TZInfo + class << self + def eager_load!; end + end +end class TZInfo::AbsoluteDayOfYearTransitionRule < ::TZInfo::DayOfYearTransitionRule def initialize(day, transition_at = T.unsafe(nil)); end @@ -94,6 +98,7 @@ class TZInfo::DataSource def country_codes; end def data_timezone_identifiers; end + def eager_load!; end def get_country_info(code); end def get_timezone_info(identifier); end def inspect; end @@ -275,6 +280,7 @@ end TZInfo::DataSources::ZoneinfoDataSource::DEFAULT_ALTERNATE_ISO3166_TAB_SEARCH_PATH = T.let(T.unsafe(nil), Array) TZInfo::DataSources::ZoneinfoDataSource::DEFAULT_SEARCH_PATH = T.let(T.unsafe(nil), Array) +TZInfo::DataSources::ZoneinfoDataSource::EXCLUDED_FILENAMES = T.let(T.unsafe(nil), Array) class TZInfo::DataSources::ZoneinfoDirectoryNotFound < ::StandardError; end class TZInfo::DataSources::ZoneinfoReader diff --git a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi index ba6af6ace7..f22b19bd3a 100644 --- a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi +++ b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi @@ -2442,6 +2442,8 @@ module Homebrew::EnvConfig def self.artifact_domain(); end + def self.autoremove?(); end + def self.auto_update_secs(); end def self.bat?(); end diff --git a/Library/Homebrew/standalone/sorbet.rb b/Library/Homebrew/standalone/sorbet.rb index 8576c7ad0d..8170e0049f 100644 --- a/Library/Homebrew/standalone/sorbet.rb +++ b/Library/Homebrew/standalone/sorbet.rb @@ -1,11 +1,47 @@ # typed: true # frozen_string_literal: true -# Explicitly prevent `sorbet-runtime` from being loaded. -def gem(name, *) - raise Gem::LoadError if name == "sorbet-runtime" +require "sorbet-runtime" - super +# Disable runtime checking unless enabled. +# In the future we should consider not doing this monkey patch, +# if assured that there is no performance hit from removing this. +# There are mechanisms to achieve a middle ground (`default_checked_level`). +unless ENV["HOMEBREW_SORBET_RUNTIME"] + # Redefine T.let etc to make the `checked` parameter default to false rather than true. + # @private + module TNoChecks + def cast(value, type, checked: false) + super(value, type, checked: checked) + end + + def let(value, type, checked: false) + super(value, type, checked: checked) + end + + def bind(value, type, checked: false) + super(value, type, checked: checked) + end + + def assert_type!(value, type, checked: false) + super(value, type, checked: checked) + end + end + + # @private + module T + class << self + prepend TNoChecks + end + + # Redefine T.sig to be noop. + # @private + module Sig + def sig(arg0 = nil, &blk); end + end + end + + # For any cases the above doesn't handle: make sure we don't let TypeError slip through. + T::Configuration.call_validation_error_handler = ->(signature, opts) do end + T::Configuration.inline_type_error_handler = ->(error, opts) do end end - -require "sorbet-runtime-stub" diff --git a/Library/Homebrew/startup.rb b/Library/Homebrew/startup.rb index 5ab9e3d56d..c47ca3749b 100644 --- a/Library/Homebrew/startup.rb +++ b/Library/Homebrew/startup.rb @@ -7,4 +7,4 @@ require_relative "standalone/load_path" require_relative "startup/ruby_path" require "startup/config" require_relative "startup/bootsnap" -require_relative "startup/sorbet" +require_relative "standalone/sorbet" diff --git a/Library/Homebrew/startup/sorbet.rb b/Library/Homebrew/startup/sorbet.rb deleted file mode 100644 index ea21e75807..0000000000 --- a/Library/Homebrew/startup/sorbet.rb +++ /dev/null @@ -1,10 +0,0 @@ -# typed: strict -# frozen_string_literal: true - -if ENV["HOMEBREW_SORBET_RUNTIME"] - # This is only supported under the brew environment. - Homebrew.install_bundler_gems!(groups: ["sorbet"]) - require "sorbet-runtime" -else - require "standalone/sorbet" -end diff --git a/Library/Homebrew/test/cask/cask_spec.rb b/Library/Homebrew/test/cask/cask_spec.rb index be59b6df8e..5b912ae3ca 100644 --- a/Library/Homebrew/test/cask/cask_spec.rb +++ b/Library/Homebrew/test/cask/cask_spec.rb @@ -211,4 +211,64 @@ describe Cask::Cask, :cask do end end end + + describe "#to_hash_with_variations" do + let!(:original_macos_version) { MacOS.full_version.to_s } + let(:expected_variations) { + <<~JSON + { + "arm64_big_sur": { + "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin-arm64/1.2.0/arm.zip", + "version": "1.2.0", + "sha256": "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + }, + "monterey": { + "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin/1.2.3/intel.zip" + }, + "big_sur": { + "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin/1.2.0/intel.zip", + "version": "1.2.0", + "sha256": "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" + }, + "catalina": { + "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin/1.0.0/intel.zip", + "version": "1.0.0", + "sha256": "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216" + }, + "mojave": { + "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin/1.0.0/intel.zip", + "version": "1.0.0", + "sha256": "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216" + } + } + JSON + } + + before do + # Use a more limited symbols list to shorten the variations hash + symbols = { + monterey: "12", + big_sur: "11", + catalina: "10.15", + mojave: "10.14", + } + stub_const("MacOSVersions::SYMBOLS", symbols) + + # For consistency, always run on Monterey and ARM + MacOS.full_version = "12" + allow(Hardware::CPU).to receive(:type).and_return(:arm) + end + + after do + MacOS.full_version = original_macos_version + end + + it "returns the correct variations hash" do + c = Cask::CaskLoader.load("multiple-versions") + h = c.to_hash_with_variations + + expect(h).to be_a(Hash) + expect(JSON.pretty_generate(h["variations"])).to eq expected_variations.strip + end + end end diff --git a/Library/Homebrew/test/cask/cmd/list_spec.rb b/Library/Homebrew/test/cask/cmd/list_spec.rb index b09c8ae9ae..0ce95eb216 100644 --- a/Library/Homebrew/test/cask/cmd/list_spec.rb +++ b/Library/Homebrew/test/cask/cmd/list_spec.rb @@ -120,9 +120,7 @@ describe Cask::Cmd::List, :cask do }, "conflicts_with": null, "container": null, - "auto_updates": null, - "variations": { - } + "auto_updates": null }, { "token": "local-transmission", @@ -151,9 +149,7 @@ describe Cask::Cmd::List, :cask do }, "conflicts_with": null, "container": null, - "auto_updates": null, - "variations": { - } + "auto_updates": null }, { "token": "multiple-versions", @@ -164,7 +160,7 @@ describe Cask::Cmd::List, :cask do ], "desc": null, "homepage": "https://brew.sh/", - "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.2.3/arm.zip", + "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/darwin-arm64/1.2.3/arm.zip", "appcast": null, "version": "1.2.3", "versions": { @@ -185,32 +181,7 @@ describe Cask::Cmd::List, :cask do }, "conflicts_with": null, "container": null, - "auto_updates": null, - "variations": { - "arm_big_sur": { - "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.2.0/arm.zip", - "version": "1.2.0", - "sha256": "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" - }, - "intel_monterey": { - "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.2.3/intel.zip" - }, - "intel_big_sur": { - "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.2.0/intel.zip", - "version": "1.2.0", - "sha256": "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" - }, - "intel_catalina": { - "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.0.0/intel.zip", - "version": "1.0.0", - "sha256": "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216" - }, - "intel_mojave": { - "url": "file://#{TEST_FIXTURE_DIR}/cask/caffeine/1.0.0/intel.zip", - "version": "1.0.0", - "sha256": "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216" - } - } + "auto_updates": null }, { "token": "third-party-cask", @@ -239,9 +210,7 @@ describe Cask::Cmd::List, :cask do }, "conflicts_with": null, "container": null, - "auto_updates": null, - "variations": { - } + "auto_updates": null } ] EOS diff --git a/Library/Homebrew/test/cask/dsl_spec.rb b/Library/Homebrew/test/cask/dsl_spec.rb index f8f3c0ecf7..6572836ace 100644 --- a/Library/Homebrew/test/cask/dsl_spec.rb +++ b/Library/Homebrew/test/cask/dsl_spec.rb @@ -305,6 +305,38 @@ describe Cask::DSL, :cask do end end + describe "arch stanza" do + let(:token) { "invalid/invalid-two-arch" } + + it "prevents defining multiple arches" do + expect { cask }.to raise_error(Cask::CaskInvalidError, /'arch' stanza may only appear once/) + end + + context "when no intel value is specified" do + let(:token) { "arch-arm-only" } + + context "when running on arm" do + before do + allow(Hardware::CPU).to receive(:type).and_return(:arm) + end + + it "returns the value" do + expect(cask.url.to_s).to eq "file://#{TEST_FIXTURE_DIR}/cask/caffeine-arm.zip" + end + end + + context "when running on intel" do + before do + allow(Hardware::CPU).to receive(:type).and_return(:intel) + end + + it "defaults to `nil` for the other when no arrays are passed" do + expect(cask.url.to_s).to eq "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip" + end + end + end + end + describe "appcast stanza" do let(:token) { "with-appcast" } diff --git a/Library/Homebrew/test/cmd/autoremove_spec.rb b/Library/Homebrew/test/cmd/autoremove_spec.rb index 24069e0bb7..1644fbf009 100644 --- a/Library/Homebrew/test/cmd/autoremove_spec.rb +++ b/Library/Homebrew/test/cmd/autoremove_spec.rb @@ -5,4 +5,34 @@ require "cmd/shared_examples/args_parse" describe "brew autoremove" do it_behaves_like "parseable arguments" + + describe "integration test" do + let(:requested_formula) { Formula["testball1"] } + let(:unused_formula) { Formula["testball2"] } + + before do + install_test_formula "testball1" + install_test_formula "testball2" + + # Make testball2 an unused dependency + tab = Tab.for_name("testball2") + tab.installed_on_request = false + tab.installed_as_dependency = true + tab.write + end + + it "only removes unused dependencies", :integration_test do + expect(requested_formula.any_version_installed?).to be true + expect(unused_formula.any_version_installed?).to be true + + # When there are unused dependencies + expect { brew "autoremove" } + .to be_a_success + .and output(/Autoremoving/).to_stdout + .and not_to_output.to_stderr + + expect(requested_formula.any_version_installed?).to be true + expect(unused_formula.any_version_installed?).to be false + end + end end diff --git a/Library/Homebrew/test/dev-cmd/contributions_spec.rb b/Library/Homebrew/test/dev-cmd/contributions_spec.rb new file mode 100644 index 0000000000..bd60333dc0 --- /dev/null +++ b/Library/Homebrew/test/dev-cmd/contributions_spec.rb @@ -0,0 +1,8 @@ +# typed: false +# frozen_string_literal: true + +require "cmd/shared_examples/args_parse" + +describe "brew contributions" do + it_behaves_like "parseable arguments" +end diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index e47a197361..8ad56f402d 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -446,40 +446,143 @@ describe Formula do end end - describe "::installed_formulae_with_no_dependents" do - let(:formula_is_dep) do - formula "foo" do - url "foo-1.1" + shared_context "with formulae for dependency testing" do + let(:formula_with_deps) do + formula "zero" do + url "zero-1.0" end end - let(:formula_with_deps) do - formula "bar" do - url "bar-1.0" + let(:formula_is_dep1) do + formula "one" do + url "one-1.1" + end + end + + let(:formula_is_dep2) do + formula "two" do + url "two-1.1" end end let(:formulae) do [ formula_with_deps, - formula_is_dep, + formula_is_dep1, + formula_is_dep2, ] end before do - allow(formula_with_deps).to receive(:runtime_formula_dependencies).and_return([formula_is_dep]) + allow(formula_with_deps).to receive(:runtime_formula_dependencies).and_return([formula_is_dep1, + formula_is_dep2]) + allow(formula_is_dep1).to receive(:runtime_formula_dependencies).and_return([formula_is_dep2]) end + end - specify "without formulae parameter" do - allow(described_class).to receive(:installed).and_return(formulae) + describe "::formulae_with_no_formula_dependents" do + include_context "with formulae for dependency testing" - expect(described_class.installed_formulae_with_no_dependents) + it "filters out dependencies" do + expect(described_class.formulae_with_no_formula_dependents(formulae)) .to eq([formula_with_deps]) end + end - specify "with formulae parameter" do - expect(described_class.installed_formulae_with_no_dependents(formulae)) - .to eq([formula_with_deps]) + describe "::unused_formulae_with_no_formula_dependents" do + include_context "with formulae for dependency testing" + + let(:tab_from_keg) { double } + + before do + allow(Tab).to receive(:for_keg).and_return(tab_from_keg) + end + + specify "installed on request" do + allow(tab_from_keg).to receive(:installed_on_request).and_return(true) + expect(described_class.unused_formulae_with_no_formula_dependents(formulae)) + .to eq([]) + end + + specify "not installed on request" do + allow(tab_from_keg).to receive(:installed_on_request).and_return(false) + expect(described_class.unused_formulae_with_no_formula_dependents(formulae)) + .to eq(formulae) + end + end + + shared_context "with formulae and casks for dependency testing" do + include_context "with formulae for dependency testing" + + require "cask/cask_loader" + + let(:cask_one_dep) do + Cask::CaskLoader.load(+<<-RUBY) + cask "red" do + depends_on formula: "two" + end + RUBY + end + + let(:cask_multiple_deps) do + Cask::CaskLoader.load(+<<-RUBY) + cask "blue" do + depends_on formula: "zero" + end + RUBY + end + + let(:cask_no_deps1) do + Cask::CaskLoader.load(+<<-RUBY) + cask "green" do + end + RUBY + end + + let(:cask_no_deps2) do + Cask::CaskLoader.load(+<<-RUBY) + cask "purple" do + end + RUBY + end + + let(:casks_no_deps) { [cask_no_deps1, cask_no_deps2] } + let(:casks_one_dep) { [cask_no_deps1, cask_no_deps2, cask_one_dep] } + let(:casks_multiple_deps) { [cask_no_deps1, cask_no_deps2, cask_multiple_deps] } + + before do + allow(described_class).to receive("[]").with("zero").and_return(formula_with_deps) + allow(described_class).to receive("[]").with("one").and_return(formula_is_dep1) + allow(described_class).to receive("[]").with("two").and_return(formula_is_dep2) + end + end + + describe "::formulae_with_cask_dependents" do + include_context "with formulae and casks for dependency testing" + + specify "no dependents" do + expect(described_class.formulae_with_cask_dependents(casks_no_deps)) + .to eq([]) + end + + specify "one dependent" do + expect(described_class.formulae_with_cask_dependents(casks_one_dep)) + .to eq([formula_is_dep2]) + end + + specify "multiple dependents" do + expect(described_class.formulae_with_cask_dependents(casks_multiple_deps)) + .to eq(formulae) + end + end + + describe "::inreplace" do + specify "raises build error on failure" do + f = formula do + url "https://brew.sh/test-1.0.tbz" + end + + expect { f.inreplace([]) }.to raise_error(BuildError) end end @@ -905,6 +1008,99 @@ describe Formula do expect(h["versions"]["bottle"]).to be_truthy end + describe "#to_hash_with_variations", :needs_macos do + let(:formula_path) { CoreTap.new.formula_dir/"foo-variations.rb" } + let(:formula_content) do + <<~RUBY + class FooVariations < Formula + url "file://#{TEST_FIXTURE_DIR}/tarballs/testball-0.1.tbz" + sha256 TESTBALL_SHA256 + + on_intel do + depends_on "intel-formula" + end + + on_big_sur do + depends_on "big-sur-formula" + end + + on_catalina :or_older do + depends_on "catalina-or-older-formula" + end + + on_linux do + depends_on "linux-formula" + end + end + RUBY + end + let(:expected_variations) { + <<~JSON + { + "arm64_big_sur": { + "dependencies": [ + "big-sur-formula" + ] + }, + "monterey": { + "dependencies": [ + "intel-formula" + ] + }, + "big_sur": { + "dependencies": [ + "intel-formula", + "big-sur-formula" + ] + }, + "catalina": { + "dependencies": [ + "intel-formula", + "catalina-or-older-formula" + ] + }, + "mojave": { + "dependencies": [ + "intel-formula", + "catalina-or-older-formula" + ] + }, + "x86_64_linux": { + "dependencies": [ + "intel-formula", + "linux-formula" + ] + } + } + JSON + } + + before do + # Use a more limited symbols list to shorten the variations hash + symbols = { + monterey: "12", + big_sur: "11", + catalina: "10.15", + mojave: "10.14", + } + stub_const("MacOSVersions::SYMBOLS", symbols) + + # For consistency, always run on Monterey and ARM + allow(MacOS).to receive(:version).and_return(MacOS::Version.new("12")) + allow(Hardware::CPU).to receive(:type).and_return(:arm) + + formula_path.dirname.mkpath + formula_path.write formula_content + end + + it "returns the correct variations hash" do + h = Formulary.factory("foo-variations").to_hash_with_variations + + expect(h).to be_a(Hash) + expect(JSON.pretty_generate(h["variations"])).to eq expected_variations.strip + end + end + specify "#to_recursive_bottle_hash" do f1 = formula "foo" do url "foo-1.0" @@ -1752,4 +1948,52 @@ describe Formula do expect(f.test).to eq(2) end end + + describe "#ignore_missing_libraries" do + after do + Homebrew::SimulateSystem.clear + end + + it "adds library to allowed_missing_libraries on Linux", :needs_linux do + Homebrew::SimulateSystem.clear + f = formula do + url "foo-1.0" + + ignore_missing_libraries "bar.so" + end + expect(f.class.allowed_missing_libraries.to_a).to eq(["bar.so"]) + end + + it "adds library to allowed_missing_libraries on macOS when simulating Linux", :needs_macos do + Homebrew::SimulateSystem.os = :linux + f = formula do + url "foo-1.0" + + ignore_missing_libraries "bar.so" + end + expect(f.class.allowed_missing_libraries.to_a).to eq(["bar.so"]) + end + + it "raises an error on macOS", :needs_macos do + Homebrew::SimulateSystem.clear + expect { + formula do + url "foo-1.0" + + ignore_missing_libraries "bar.so" + end + }.to raise_error("ignore_missing_libraries is available on Linux only") + end + + it "raises an error on Linux when simulating macOS", :needs_linux do + Homebrew::SimulateSystem.os = :macos + expect { + formula do + url "foo-1.0" + + ignore_missing_libraries "bar.so" + end + }.to raise_error("ignore_missing_libraries is available on Linux only") + end + end end diff --git a/Library/Homebrew/test/formulary_spec.rb b/Library/Homebrew/test/formulary_spec.rb index 6276ecf876..0fc043fe6b 100644 --- a/Library/Homebrew/test/formulary_spec.rb +++ b/Library/Homebrew/test/formulary_spec.rb @@ -260,6 +260,26 @@ describe Formulary do } end + let(:variations_json) do + { + "variations" => { + Utils::Bottles.tag.to_s => { + "dependencies" => ["dep", "variations_dep"], + }, + }, + } + end + + let(:linux_variations_json) do + { + "variations" => { + "x86_64_linux" => { + "dependencies" => ["dep", "uses_from_macos_dep"], + }, + }, + } + end + before do allow(described_class).to receive(:loader_for).and_return(described_class::FormulaAPILoader.new(formula_name)) end @@ -303,6 +323,25 @@ describe Formulary do formula.install }.to raise_error("Cannot build from source from abstract formula.") end + + it "returns a Formula with variations when given a name", :needs_macos do + allow(Homebrew::API::Formula).to receive(:all_formulae).and_return formula_json_contents(variations_json) + + formula = described_class.factory(formula_name) + expect(formula).to be_kind_of(Formula) + expect(formula.deps.count).to eq 5 + expect(formula.deps.map(&:name).include?("variations_dep")).to be true + end + + it "returns a Formula without duplicated deps and uses_from_macos with variations on Linux", :needs_linux do + allow(Homebrew::API::Formula) + .to receive(:all_formulae).and_return formula_json_contents(linux_variations_json) + + formula = described_class.factory(formula_name) + expect(formula).to be_kind_of(Formula) + expect(formula.deps.count).to eq 5 + expect(formula.deps.map(&:name).include?("uses_from_macos_dep")).to be true + end end end diff --git a/Library/Homebrew/test/language/python/shebang_spec.rb b/Library/Homebrew/test/language/python/shebang_spec.rb index b269129cc0..4fa44b83f3 100644 --- a/Library/Homebrew/test/language/python/shebang_spec.rb +++ b/Library/Homebrew/test/language/python/shebang_spec.rb @@ -7,7 +7,7 @@ require "utils/shebang" describe Language::Python::Shebang do let(:file) { Tempfile.new("python-shebang") } let(:python_f) do - formula "python" do + formula "python@3.11" do url "https://brew.sh/python-1.0.tgz" end end @@ -15,7 +15,7 @@ describe Language::Python::Shebang do formula "foo" do url "https://brew.sh/foo-1.0.tgz" - depends_on "python" + depends_on "python@3.11" end end @@ -37,7 +37,7 @@ describe Language::Python::Shebang do Utils::Shebang.rewrite_shebang described_class.detected_python_shebang(f), file expect(File.read(file)).to eq <<~EOS - #!#{HOMEBREW_PREFIX}/opt/python/bin/python3 + #!#{HOMEBREW_PREFIX}/opt/python@3.11/bin/python3.11 a b c diff --git a/Library/Homebrew/test/os/mac/software_spec_spec.rb b/Library/Homebrew/test/os/mac/software_spec_spec.rb deleted file mode 100644 index c6a72db735..0000000000 --- a/Library/Homebrew/test/os/mac/software_spec_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "software_spec" - -describe SoftwareSpec do - subject(:spec) { described_class.new } - - describe "#uses_from_macos" do - before do - allow(OS).to receive(:mac?).and_return(true) - allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.from_symbol(:sierra)) - end - - it "adds a macOS dependency if the OS version meets requirements" do - spec.uses_from_macos("foo", since: :el_capitan) - - expect(spec.deps).to be_empty - expect(spec.uses_from_macos_elements.first).to eq("foo") - end - - it "doesn't add a macOS dependency if the OS version doesn't meet requirements" do - spec.uses_from_macos("foo", since: :high_sierra) - - expect(spec.deps.first.name).to eq("foo") - expect(spec.uses_from_macos_elements).to eq(["foo"]) - end - - it "works with tags" do - spec.uses_from_macos("foo" => :build, :since => :high_sierra) - - dep = spec.deps.first - - expect(dep.name).to eq("foo") - expect(dep.tags).to include(:build) - end - - it "doesn't add a dependency if no OS version is specified" do - spec.uses_from_macos("foo") - spec.uses_from_macos("bar" => :build) - - expect(spec.deps).to be_empty - end - - it "raises an error if passing invalid OS versions" do - expect { - spec.uses_from_macos("foo", since: :bar) - }.to raise_error(MacOSVersionError, "unknown or unsupported macOS version: :bar") - end - end -end diff --git a/Library/Homebrew/test/rubocops/components_order_spec.rb b/Library/Homebrew/test/rubocops/components_order_spec.rb index 7b8e2a813a..20c6736a55 100644 --- a/Library/Homebrew/test/rubocops/components_order_spec.rb +++ b/Library/Homebrew/test/rubocops/components_order_spec.rb @@ -679,6 +679,130 @@ describe RuboCop::Cop::FormulaAudit::ComponentsOrder do RUBY end + it "reports an offense when a single `patch` block is inside the `on_arm` block" do + expect_offense(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + on_arm do + ^^^^^^^^^ Nest `on_arm` blocks inside `patch` blocks when there is only one inner block. + patch do + url "https://brew.sh/patch1.tar.gz" + sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f" + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + patch do + on_arm do + url "https://brew.sh/patch1.tar.gz" + sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f" + end + end + end + RUBY + end + + it "reports an offense when a single `resource` block is inside the `on_linux` block" do + expect_offense(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + on_linux do + ^^^^^^^^^^^ Nest `on_linux` blocks inside `resource` blocks when there is only one inner block. + resource do + url "https://brew.sh/resource1.tar.gz" + sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + resource do + on_linux do + url "https://brew.sh/resource1.tar.gz" + sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" + end + end + end + RUBY + end + + it "reports an offense when a single `patch` block is inside the `on_monterey :or_newer` block" do + expect_offense(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + on_monterey :or_newer do + ^^^^^^^^^^^^^^^^^^^^^^^^ Nest `on_monterey` blocks inside `patch` blocks when there is only one inner block. + patch do + url "https://brew.sh/patch1.tar.gz" + sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f" + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + patch do + on_monterey :or_newer do + url "https://brew.sh/patch1.tar.gz" + sha256 "2c39089f64d9d4c3e632f120894b36b68dcc8ae8c6f5130c0c2e6f5bb7aebf2f" + end + end + end + RUBY + end + + it "reports an offense when a single `resource` block is inside the `on_system` block" do + expect_offense(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + on_system :linux, macos: :monterey_or_older do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Nest `on_system` blocks inside `resource` blocks when there is only one inner block. + resource do + url "https://brew.sh/resource1.tar.gz" + sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + resource do + on_system :linux, macos: :monterey_or_older do + url "https://brew.sh/resource1.tar.gz" + sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" + end + end + end + RUBY + end + + it "reports no offenses when a single `on_arm` block is inside the `on_macos` block" do + expect_no_offenses(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + on_macos do + on_arm do + resource do + url "https://brew.sh/resource1.tar.gz" + sha256 "586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35" + end + end + end + end + RUBY + end + context "when in a resource block" do it "reports no offenses for a valid `on_macos` and `on_linux` block" do expect_no_offenses(<<~RUBY) diff --git a/Library/Homebrew/test/rubocops/dependency_order_spec.rb b/Library/Homebrew/test/rubocops/dependency_order_spec.rb index b080d55ef7..465477dac0 100644 --- a/Library/Homebrew/test/rubocops/dependency_order_spec.rb +++ b/Library/Homebrew/test/rubocops/dependency_order_spec.rb @@ -114,6 +114,34 @@ describe RuboCop::Cop::FormulaAudit::DependencyOrder do end RUBY end + + it "reports and corrects wrong conditional order within a system block" do + expect_offense(<<~RUBY) + class Foo < Formula + homepage "https://brew.sh" + url "https://brew.sh/foo-1.0.tgz" + on_arm do + uses_from_macos "apple" if build.with? "foo" + uses_from_macos "bar" + ^^^^^^^^^^^^^^^^^^^^^ dependency "bar" (line 6) should be put before dependency "apple" (line 5) + uses_from_macos "foo" => :optional + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dependency "foo" (line 7) should be put before dependency "apple" (line 5) + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + homepage "https://brew.sh" + url "https://brew.sh/foo-1.0.tgz" + on_arm do + uses_from_macos "bar" + uses_from_macos "foo" => :optional + uses_from_macos "apple" if build.with? "foo" + end + end + RUBY + end end context "when auditing `depends_on`" do @@ -224,5 +252,33 @@ describe RuboCop::Cop::FormulaAudit::DependencyOrder do end RUBY end + + it "reports and corrects wrong conditional order within a system block" do + expect_offense(<<~RUBY) + class Foo < Formula + homepage "https://brew.sh" + url "https://brew.sh/foo-1.0.tgz" + on_linux do + depends_on "apple" if build.with? "foo" + depends_on "bar" + ^^^^^^^^^^^^^^^^ dependency "bar" (line 6) should be put before dependency "apple" (line 5) + depends_on "foo" => :optional + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dependency "foo" (line 7) should be put before dependency "apple" (line 5) + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + homepage "https://brew.sh" + url "https://brew.sh/foo-1.0.tgz" + on_linux do + depends_on "bar" + depends_on "foo" => :optional + depends_on "apple" if build.with? "foo" + end + end + RUBY + end end end diff --git a/Library/Homebrew/test/rubocops/text/on_os_conditionals_spec.rb b/Library/Homebrew/test/rubocops/text/on_os_conditionals_spec.rb deleted file mode 100644 index 28f1a41185..0000000000 --- a/Library/Homebrew/test/rubocops/text/on_os_conditionals_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -# typed: false -# frozen_string_literal: true - -require "rubocops/lines" - -describe RuboCop::Cop::FormulaAudit::OSConditionals do - subject(:cop) { described_class.new } - - context "when auditing OS conditionals" do - it "reports an offense when `OS.linux?` is used on Formula class" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - desc "foo" - if OS.linux? - ^^^^^^^^^ Don't use 'if OS.linux?', use 'on_linux do' instead. - url 'https://brew.sh/linux-1.0.tgz' - else - url 'https://brew.sh/linux-1.0.tgz' - end - end - RUBY - end - - it "reports an offense when `OS.mac?` is used on Formula class" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - desc "foo" - if OS.mac? - ^^^^^^^ Don't use 'if OS.mac?', use 'on_macos do' instead. - url 'https://brew.sh/mac-1.0.tgz' - else - url 'https://brew.sh/linux-1.0.tgz' - end - end - RUBY - end - - it "reports an offense when `on_macos` is used in install method" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - desc "foo" - url 'https://brew.sh/foo-1.0.tgz' - - def install - on_macos do - ^^^^^^^^ Don't use 'on_macos' in 'def install', use 'if OS.mac?' instead. - true - end - end - end - RUBY - end - - it "reports an offense when `on_linux` is used in install method" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - desc "foo" - url 'https://brew.sh/foo-1.0.tgz' - - def install - on_linux do - ^^^^^^^^ Don't use 'on_linux' in 'def install', use 'if OS.linux?' instead. - true - end - end - end - RUBY - end - - it "reports an offense when `on_macos` is used in test block" do - expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") - class Foo < Formula - desc "foo" - url 'https://brew.sh/foo-1.0.tgz' - - test do - on_macos do - ^^^^^^^^ Don't use 'on_macos' in 'test do', use 'if OS.mac?' instead. - true - end - end - end - RUBY - end - end -end diff --git a/Library/Homebrew/test/rubocops/text/on_system_conditionals_spec.rb b/Library/Homebrew/test/rubocops/text/on_system_conditionals_spec.rb new file mode 100644 index 0000000000..24ed0a1e86 --- /dev/null +++ b/Library/Homebrew/test/rubocops/text/on_system_conditionals_spec.rb @@ -0,0 +1,546 @@ +# typed: false +# frozen_string_literal: true + +require "rubocops/lines" + +describe RuboCop::Cop::FormulaAudit::OnSystemConditionals do + subject(:cop) { described_class.new } + + context "when auditing OS conditionals" do + it "reports an offense when `OS.linux?` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if OS.linux? + ^^^^^^^^^^^^ Don't use `if OS.linux?`, use `on_linux do` instead. + url 'https://brew.sh/linux-1.0.tgz' + else + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_linux do + url 'https://brew.sh/linux-1.0.tgz' + end + on_macos do + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `OS.mac?` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if OS.mac? + ^^^^^^^^^^ Don't use `if OS.mac?`, use `on_macos do` instead. + url 'https://brew.sh/mac-1.0.tgz' + else + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_macos do + url 'https://brew.sh/mac-1.0.tgz' + end + on_linux do + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `on_macos` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_macos do + ^^^^^^^^ Don't use `on_macos` in `def install`, use `if OS.mac?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if OS.mac? + true + end + end + end + RUBY + end + + it "reports an offense when `on_linux` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_linux do + ^^^^^^^^ Don't use `on_linux` in `def install`, use `if OS.linux?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if OS.linux? + true + end + end + end + RUBY + end + + it "reports an offense when `on_macos` is used in test block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + on_macos do + ^^^^^^^^ Don't use `on_macos` in `test do`, use `if OS.mac?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + if OS.mac? + true + end + end + end + RUBY + end + end + + context "when auditing Hardware::CPU conditionals" do + it "reports an offense when `Hardware::CPU.arm?` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if Hardware::CPU.arm? + ^^^^^^^^^^^^^^^^^^^^^ Don't use `if Hardware::CPU.arm?`, use `on_arm do` instead. + url 'https://brew.sh/linux-1.0.tgz' + else + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_arm do + url 'https://brew.sh/linux-1.0.tgz' + end + on_intel do + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `Hardware::CPU.intel?` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if Hardware::CPU.intel? + ^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if Hardware::CPU.intel?`, use `on_intel do` instead. + url 'https://brew.sh/mac-1.0.tgz' + else + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_intel do + url 'https://brew.sh/mac-1.0.tgz' + end + on_arm do + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `on_intel` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_intel do + ^^^^^^^^ Don't use `on_intel` in `def install`, use `if Hardware::CPU.intel?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if Hardware::CPU.intel? + true + end + end + end + RUBY + end + + it "reports an offense when `on_arm` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_arm do + ^^^^^^ Don't use `on_arm` in `def install`, use `if Hardware::CPU.arm?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if Hardware::CPU.arm? + true + end + end + end + RUBY + end + + it "reports an offense when `on_intel` is used in test block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + on_intel do + ^^^^^^^^ Don't use `on_intel` in `test do`, use `if Hardware::CPU.intel?` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + if Hardware::CPU.intel? + true + end + end + end + RUBY + end + end + + context "when auditing MacOS.version conditionals" do + it "reports an offense when `MacOS.version ==` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if MacOS.version == :monterey + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version == :monterey`, use `on_monterey do` instead. + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_monterey do + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `MacOS.version <=` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if MacOS.version <= :monterey + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version <= :monterey`, use `on_system :linux, macos: :monterey_or_older do` instead. + url 'https://brew.sh/mac-1.0.tgz' + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + on_system :linux, macos: :monterey_or_older do + url 'https://brew.sh/mac-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `MacOS.version <` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if MacOS.version < :monterey + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version < :monterey`, use `on_system do` instead. + url 'https://brew.sh/mac-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `MacOS.version >=` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if MacOS.version >= :monterey + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version >= :monterey`, use `on_monterey :or_newer do` instead. + url 'https://brew.sh/mac-1.0.tgz' + else + url 'https://brew.sh/linux-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `MacOS.version >` is used on Formula class" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + if MacOS.version > :monterey + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `if MacOS.version > :monterey`, use `on_monterey do` instead. + url 'https://brew.sh/mac-1.0.tgz' + end + end + RUBY + end + + it "reports an offense when `on_monterey` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_monterey do + ^^^^^^^^^^^ Don't use `on_monterey` in `def install`, use `if MacOS.version == :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if MacOS.version == :monterey + true + end + end + end + RUBY + end + + it "reports an offense when `on_monterey :or_older` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_monterey :or_older do + ^^^^^^^^^^^^^^^^^^^^^ Don't use `on_monterey :or_older` in `def install`, use `if MacOS.version <= :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if MacOS.version <= :monterey + true + end + end + end + RUBY + end + + it "reports an offense when `on_monterey :or_newer` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_monterey :or_newer do + ^^^^^^^^^^^^^^^^^^^^^ Don't use `on_monterey :or_newer` in `def install`, use `if MacOS.version >= :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if MacOS.version >= :monterey + true + end + end + end + RUBY + end + + it "reports an offense when `on_system :linux, macos: :monterey_or_newer` is used in install method" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + on_system :linux, macos: :monterey_or_newer do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `on_system :linux, macos: :monterey_or_newer` in `def install`, use `if OS.linux? || MacOS.version >= :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + def install + if OS.linux? || MacOS.version >= :monterey + true + end + end + end + RUBY + end + + it "reports an offense when `on_monterey` is used in test block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + on_monterey do + ^^^^^^^^^^^ Don't use `on_monterey` in `test do`, use `if MacOS.version == :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + if MacOS.version == :monterey + true + end + end + end + RUBY + end + + it "reports an offense when `on_system :linux, macos: :monterey` is used in test block" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + on_system :linux, macos: :monterey do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't use `on_system :linux, macos: :monterey` in `test do`, use `if OS.linux? || MacOS.version == :monterey` instead. + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo < Formula + desc "foo" + url 'https://brew.sh/foo-1.0.tgz' + + test do + if OS.linux? || MacOS.version == :monterey + true + end + end + end + RUBY + end + end +end diff --git a/Library/Homebrew/test/service_spec.rb b/Library/Homebrew/test/service_spec.rb index f54d8d8be6..e35f0f4cb9 100644 --- a/Library/Homebrew/test/service_spec.rb +++ b/Library/Homebrew/test/service_spec.rb @@ -180,6 +180,14 @@ describe Homebrew::Service do \t \tLegacyTimers \t + \tLimitLoadToSessionType + \t + \t\tAqua + \t\tBackground + \t\tLoginWindow + \t\tStandardIO + \t\tSystem + \t \tProcessType \tInteractive \tProgramArguments @@ -221,6 +229,14 @@ describe Homebrew::Service do \tLabel \thomebrew.mxcl.formula_name + \tLimitLoadToSessionType + \t + \t\tAqua + \t\tBackground + \t\tLoginWindow + \t\tStandardIO + \t\tSystem + \t \tProgramArguments \t \t\t#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd @@ -262,6 +278,14 @@ describe Homebrew::Service do \tLabel \thomebrew.mxcl.formula_name + \tLimitLoadToSessionType + \t + \t\tAqua + \t\tBackground + \t\tLoginWindow + \t\tStandardIO + \t\tSystem + \t \tProgramArguments \t \t\t#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd @@ -289,6 +313,14 @@ describe Homebrew::Service do \tLabel \thomebrew.mxcl.formula_name + \tLimitLoadToSessionType + \t + \t\tAqua + \t\tBackground + \t\tLoginWindow + \t\tStandardIO + \t\tSystem + \t \tProgramArguments \t \t\t#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd @@ -318,6 +350,14 @@ describe Homebrew::Service do \tLabel \thomebrew.mxcl.formula_name + \tLimitLoadToSessionType + \t + \t\tAqua + \t\tBackground + \t\tLoginWindow + \t\tStandardIO + \t\tSystem + \t \tProgramArguments \t \t\t#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd @@ -356,6 +396,14 @@ describe Homebrew::Service do \t \tLabel \thomebrew.mxcl.formula_name + \tLimitLoadToSessionType + \t + \t\tAqua + \t\tBackground + \t\tLoginWindow + \t\tStandardIO + \t\tSystem + \t \tProgramArguments \t \t\t#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd @@ -387,6 +435,14 @@ describe Homebrew::Service do \t \tLabel \thomebrew.mxcl.formula_name + \tLimitLoadToSessionType + \t + \t\tAqua + \t\tBackground + \t\tLoginWindow + \t\tStandardIO + \t\tSystem + \t \tProgramArguments \t \t\t#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd @@ -418,6 +474,14 @@ describe Homebrew::Service do \t \tLabel \thomebrew.mxcl.formula_name + \tLimitLoadToSessionType + \t + \t\tAqua + \t\tBackground + \t\tLoginWindow + \t\tStandardIO + \t\tSystem + \t \tProgramArguments \t \t\t#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd diff --git a/Library/Homebrew/test/simulate_system_spec.rb b/Library/Homebrew/test/simulate_system_spec.rb new file mode 100644 index 0000000000..3923680064 --- /dev/null +++ b/Library/Homebrew/test/simulate_system_spec.rb @@ -0,0 +1,142 @@ +# typed: false +# frozen_string_literal: true + +require "settings" + +describe Homebrew::SimulateSystem do + after do + described_class.clear + end + + describe "::simulating_or_running_on_macos?" do + it "returns true on macOS", :needs_macos do + described_class.clear + expect(described_class.simulating_or_running_on_macos?).to be true + end + + it "returns false on Linux", :needs_linux do + described_class.clear + expect(described_class.simulating_or_running_on_macos?).to be false + end + + it "returns false on macOS when simulating Linux", :needs_macos do + described_class.clear + described_class.os = :linux + expect(described_class.simulating_or_running_on_macos?).to be false + end + + it "returns true on Linux when simulating a generic macOS version", :needs_linux do + described_class.clear + described_class.os = :macos + expect(described_class.simulating_or_running_on_macos?).to be true + end + + it "returns true on Linux when simulating a specific macOS version", :needs_linux do + described_class.clear + described_class.os = :monterey + expect(described_class.simulating_or_running_on_macos?).to be true + end + + it "returns true on Linux with HOMEBREW_SIMULATE_MACOS_ON_LINUX", :needs_linux do + described_class.clear + ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1" + expect(described_class.simulating_or_running_on_macos?).to be true + end + end + + describe "::simulating_or_running_on_linux?" do + it "returns true on Linux", :needs_linux do + described_class.clear + expect(described_class.simulating_or_running_on_linux?).to be true + end + + it "returns false on macOS", :needs_macos do + described_class.clear + expect(described_class.simulating_or_running_on_linux?).to be false + end + + it "returns true on macOS when simulating Linux", :needs_macos do + described_class.clear + described_class.os = :linux + expect(described_class.simulating_or_running_on_linux?).to be true + end + + it "returns false on Linux when simulating a generic macOS version", :needs_linux do + described_class.clear + described_class.os = :macos + expect(described_class.simulating_or_running_on_linux?).to be false + end + + it "returns false on Linux when simulating a specific macOS version", :needs_linux do + described_class.clear + described_class.os = :monterey + expect(described_class.simulating_or_running_on_linux?).to be false + end + + it "returns false on Linux with HOMEBREW_SIMULATE_MACOS_ON_LINUX", :needs_linux do + described_class.clear + ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1" + expect(described_class.simulating_or_running_on_linux?).to be false + end + end + + describe "::current_arch" do + it "returns the current architecture" do + described_class.clear + expect(described_class.current_arch).to eq Hardware::CPU.type + end + + it "returns the simulated architecture" do + described_class.clear + simulated_arch = if Hardware::CPU.arm? + :intel + else + :arm + end + described_class.arch = simulated_arch + expect(described_class.current_arch).to eq simulated_arch + end + end + + describe "::current_os" do + it "returns the current macOS version on macOS", :needs_macos do + described_class.clear + expect(described_class.current_os).to eq MacOS.version.to_sym + end + + it "returns `:linux` on Linux", :needs_linux do + described_class.clear + expect(described_class.current_os).to eq :linux + end + + it "returns `:linux` when simulating Linux on macOS", :needs_macos do + described_class.clear + described_class.os = :linux + expect(described_class.current_os).to eq :linux + end + + it "returns `:macos` when simulating a generic macOS version on Linux", :needs_linux do + described_class.clear + described_class.os = :macos + expect(described_class.current_os).to eq :macos + end + + it "returns `:macos` when simulating a specific macOS version on Linux", :needs_linux do + described_class.clear + described_class.os = :monterey + expect(described_class.current_os).to eq :monterey + end + + it "returns the current macOS version on macOS with HOMEBREW_SIMULATE_MACOS_ON_LINUX", :needs_macos do + described_class.clear + ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1" + expect(described_class.current_os).to eq MacOS.version.to_sym + end + + it "returns `:macos` on Linux with HOMEBREW_SIMULATE_MACOS_ON_LINUX", :needs_linux do + described_class.clear + ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1" + expect(described_class.current_os).to eq :macos + end + end +end diff --git a/Library/Homebrew/test/software_spec_spec.rb b/Library/Homebrew/test/software_spec_spec.rb index 24b50bb8da..8271b35681 100644 --- a/Library/Homebrew/test/software_spec_spec.rb +++ b/Library/Homebrew/test/software_spec_spec.rb @@ -135,27 +135,86 @@ describe SoftwareSpec do end end - describe "#uses_from_macos" do - it "allows specifying dependencies", :needs_linux do - spec.uses_from_macos("foo") + describe "#uses_from_macos", :needs_linux do + context "when running on Linux", :needs_linux do + it "allows specifying dependencies" do + spec.uses_from_macos("foo") - expect(spec.deps.first.name).to eq("foo") + expect(spec.deps.first.name).to eq("foo") + end + + it "works with tags" do + spec.uses_from_macos("foo" => :build) + + expect(spec.deps.first.name).to eq("foo") + expect(spec.deps.first.tags).to include(:build) + end + + it "ignores dependencies with HOMEBREW_SIMULATE_MACOS_ON_LINUX" do + ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1" + spec.uses_from_macos("foo") + + expect(spec.deps).to be_empty + end + + it "ignores dependencies with tags with HOMEBREW_SIMULATE_MACOS_ON_LINUX" do + ENV["HOMEBREW_SIMULATE_MACOS_ON_LINUX"] = "1" + spec.uses_from_macos("foo" => :build) + + expect(spec.deps).to be_empty + end + + it "ignores OS version specifications" do + spec.uses_from_macos("foo", since: :mojave) + spec.uses_from_macos("bar" => :build, :since => :mojave) + + expect(spec.deps.first.name).to eq("foo") + expect(spec.deps.last.name).to eq("bar") + expect(spec.deps.last.tags).to include(:build) + end end - it "works with tags", :needs_linux do - spec.uses_from_macos("foo" => :build) + context "when running on macOS", :needs_macos do + before do + allow(OS).to receive(:mac?).and_return(true) + allow(OS::Mac).to receive(:version).and_return(OS::Mac::Version.from_symbol(:sierra)) + end - expect(spec.deps.first.name).to eq("foo") - expect(spec.deps.first.tags).to include(:build) - end + it "adds a macOS dependency if the OS version meets requirements" do + spec.uses_from_macos("foo", since: :el_capitan) - it "ignores OS version specifications", :needs_linux do - spec.uses_from_macos("foo", since: :mojave) - spec.uses_from_macos("bar" => :build, :since => :mojave) + expect(spec.deps).to be_empty + expect(spec.uses_from_macos_elements.first).to eq("foo") + end - expect(spec.deps.first.name).to eq("foo") - expect(spec.deps.last.name).to eq("bar") - expect(spec.deps.last.tags).to include(:build) + it "doesn't add a macOS dependency if the OS version doesn't meet requirements" do + spec.uses_from_macos("foo", since: :high_sierra) + + expect(spec.deps.first.name).to eq("foo") + expect(spec.uses_from_macos_elements).to eq(["foo"]) + end + + it "works with tags" do + spec.uses_from_macos("foo" => :build, :since => :high_sierra) + + dep = spec.deps.first + + expect(dep.name).to eq("foo") + expect(dep.tags).to include(:build) + end + + it "doesn't add a dependency if no OS version is specified" do + spec.uses_from_macos("foo") + spec.uses_from_macos("bar" => :build) + + expect(spec.deps).to be_empty + end + + it "raises an error if passing invalid OS versions" do + expect { + spec.uses_from_macos("foo", since: :bar) + }.to raise_error(MacOSVersionError, "unknown or unsupported macOS version: :bar") + end end end @@ -171,5 +230,12 @@ describe SoftwareSpec do expect(spec.patches.count).to eq(1) expect(spec.patches.first.strip).to eq(:p1) end + + it "doesn't add a patch with no url" do + spec.patch do + sha256 "7852a7a365f518b12a1afd763a6a80ece88ac7aeea3c9023aa6c1fe46ac5a1ae" + end + expect(spec.patches.empty?).to be true + end end end diff --git a/Library/Homebrew/test/support/fixtures/cask/Casks/arch-arm-only.rb b/Library/Homebrew/test/support/fixtures/cask/Casks/arch-arm-only.rb new file mode 100644 index 0000000000..d6bc73d35e --- /dev/null +++ b/Library/Homebrew/test/support/fixtures/cask/Casks/arch-arm-only.rb @@ -0,0 +1,11 @@ +cask "arch-arm-only" do + arch arm: "-arm" + + version "1.2.3" + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + + url "file://#{TEST_FIXTURE_DIR}/cask/caffeine#{arch}.zip" + homepage "https://brew.sh/" + + app "Caffeine.app" +end diff --git a/Library/Homebrew/test/support/fixtures/cask/Casks/invalid/invalid-two-arch.rb b/Library/Homebrew/test/support/fixtures/cask/Casks/invalid/invalid-two-arch.rb new file mode 100644 index 0000000000..117e59c3bc --- /dev/null +++ b/Library/Homebrew/test/support/fixtures/cask/Casks/invalid/invalid-two-arch.rb @@ -0,0 +1,12 @@ +cask "invalid-two-arch" do + arch arm: "arm", intel: "intel" + arch arm: "amd64", intel: "x86_64" + + version "1.2.3" + sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" + + url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip" + homepage "https://brew.sh/" + + app "Caffeine.app" +end diff --git a/Library/Homebrew/test/support/fixtures/cask/Casks/multiple-versions.rb b/Library/Homebrew/test/support/fixtures/cask/Casks/multiple-versions.rb index ad05491a2d..05a29fd20f 100644 --- a/Library/Homebrew/test/support/fixtures/cask/Casks/multiple-versions.rb +++ b/Library/Homebrew/test/support/fixtures/cask/Casks/multiple-versions.rb @@ -1,12 +1,10 @@ cask "multiple-versions" do - arch = "arm" + arch arm: "arm", intel: "intel" + platform = on_arch_conditional arm: "darwin-arm64", intel: "darwin" + version "1.2.3" sha256 "67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94" - on_intel do - arch = "intel" - end - on_big_sur do version "1.2.0" sha256 "8c62a2b791cf5f0da6066a0a4b6e85f62949cd60975da062df44adf887f4370b" @@ -17,7 +15,7 @@ cask "multiple-versions" do sha256 "1866dfa833b123bb8fe7fa7185ebf24d28d300d0643d75798bc23730af734216" end - url "file://#{TEST_FIXTURE_DIR}/cask/caffeine/#{version}/#{arch}.zip" + url "file://#{TEST_FIXTURE_DIR}/cask/caffeine/#{platform}/#{version}/#{arch}.zip" homepage "https://brew.sh/" app "Caffeine.app" diff --git a/Library/Homebrew/test/utils/bottles/tag_spec.rb b/Library/Homebrew/test/utils/bottles/tag_spec.rb index 1f2d5d4163..256c592635 100644 --- a/Library/Homebrew/test/utils/bottles/tag_spec.rb +++ b/Library/Homebrew/test/utils/bottles/tag_spec.rb @@ -36,4 +36,37 @@ describe Utils::Bottles::Tag do expect(tag.linux?).to be true expect(tag.to_sym).to eq(symbol) end + + describe "#standardized_arch" do + it "returns :x86_64 for :intel" do + expect(described_class.new(system: :all, arch: :intel).standardized_arch).to eq(:x86_64) + end + + it "returns :arm64 for :arm" do + expect(described_class.new(system: :all, arch: :arm).standardized_arch).to eq(:arm64) + end + end + + describe "#valid_combination?" do + it "returns true for intel archs" do + tag = described_class.new(system: :big_sur, arch: :intel) + expect(tag.valid_combination?).to be true + tag = described_class.new(system: :linux, arch: :x86_64) + expect(tag.valid_combination?).to be true + end + + it "returns false for arm archs and macos versions older than big_sur" do + tag = described_class.new(system: :catalina, arch: :arm64) + expect(tag.valid_combination?).to be false + tag = described_class.new(system: :mojave, arch: :arm) + expect(tag.valid_combination?).to be false + end + + it "returns false for arm archs and linux" do + tag = described_class.new(system: :linux, arch: :arm64) + expect(tag.valid_combination?).to be false + tag = described_class.new(system: :linux, arch: :arm) + expect(tag.valid_combination?).to be false + end + end end diff --git a/Library/Homebrew/test/utils/ruby_check_version_script_spec.rb b/Library/Homebrew/test/utils/ruby_check_version_script_spec.rb new file mode 100644 index 0000000000..cb3bb59b5b --- /dev/null +++ b/Library/Homebrew/test/utils/ruby_check_version_script_spec.rb @@ -0,0 +1,44 @@ +# typed: false +# frozen_string_literal: true + +describe Utils do + describe "ruby_check_version_script" do + subject do + quiet_system "#{HOMEBREW_LIBRARY_PATH}/utils/ruby_check_version_script.rb", required_ruby_version + end + + before do + ENV.delete("HOMEBREW_DEVELOPER") + ENV.delete("HOMEBREW_USE_RUBY_FROM_PATH") + end + + describe "succeeds on Homebrew required Ruby version" do + let(:required_ruby_version) { HOMEBREW_REQUIRED_RUBY_VERSION } + + it { is_expected.to be true } + end + + describe "succeeds on newer mismatched major/minor required Ruby version and configurated environment" do + let(:required_ruby_version) { "2.0.0" } + + before do + ENV["HOMEBREW_DEVELOPER"] = "1" + ENV["HOMEBREW_USE_RUBY_FROM_PATH"] = "1" + end + + it { is_expected.to be true } + end + + describe "fails on on mismatched major/minor required Ruby version" do + let(:required_ruby_version) { "1.2.3" } + + it { is_expected.to be false } + end + + describe "fails on invalid required Ruby version" do + let(:required_ruby_version) { "fish" } + + it { is_expected.to be false } + end + end +end diff --git a/Library/Homebrew/utils/bottles.rb b/Library/Homebrew/utils/bottles.rb index 72767645cd..6ffcb815b9 100644 --- a/Library/Homebrew/utils/bottles.rb +++ b/Library/Homebrew/utils/bottles.rb @@ -169,14 +169,22 @@ module Utils [system, arch].hash end + sig { returns(Symbol) } + def standardized_arch + return :x86_64 if [:x86_64, :intel].include? arch + return :arm64 if [:arm64, :arm].include? arch + + arch + end + sig { returns(Symbol) } def to_sym if system == :all && arch == :all :all - elsif macos? && arch == :x86_64 + elsif macos? && [:x86_64, :intel].include?(arch) system else - "#{arch}_#{system}".to_sym + "#{standardized_arch}_#{system}".to_sym end end @@ -203,6 +211,15 @@ module Utils false end + sig { returns(T::Boolean) } + def valid_combination? + return true unless [:arm64, :arm].include? arch + return false if linux? + + # Big Sur is the first version of macOS that runs on ARM + to_macos_version >= :big_sur + end + sig { returns(String) } def default_prefix if linux? diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb index 072ea202c3..d3d956bd55 100644 --- a/Library/Homebrew/utils/github.rb +++ b/Library/Homebrew/utils/github.rb @@ -479,8 +479,9 @@ module GitHub def check_for_duplicate_pull_requests(name, tap_remote_repo, state:, file:, args:, version: nil) pull_requests = fetch_pull_requests(name, tap_remote_repo, state: state, version: version).select do |pr| - pr_files = API.open_rest(url_to("repos", tap_remote_repo, "pulls", pr["number"], "files")) - pr_files.any? { |f| f["filename"] == file } + get_pull_request_changed_files( + tap_remote_repo, pr["number"] + ).any? { |f| f["filename"] == file } end return if pull_requests.blank? @@ -501,6 +502,10 @@ module GitHub end end + def get_pull_request_changed_files(tap_remote_repo, pr) + API.open_rest(url_to("repos", tap_remote_repo, "pulls", pr, "files")) + end + def forked_repo_info!(tap_remote_repo, org: nil) response = create_fork(tap_remote_repo, org: org) # GitHub API responds immediately but fork takes a few seconds to be ready. diff --git a/Library/Homebrew/utils/github/api.rb b/Library/Homebrew/utils/github/api.rb index 8db64eda0c..005f5baf7b 100644 --- a/Library/Homebrew/utils/github/api.rb +++ b/Library/Homebrew/utils/github/api.rb @@ -184,8 +184,7 @@ module GitHub # This is a no-op if the user is opting out of using the GitHub API. return block_given? ? yield({}) : {} if Homebrew::EnvConfig.no_github_api? - args = ["--header", "Accept: application/vnd.github.v3+json", "--write-out", "\n%\{http_code}"] - args += ["--header", "Accept: application/vnd.github.antiope-preview+json"] + args = ["--header", "Accept: application/vnd.github+json", "--write-out", "\n%\{http_code}"] token = credentials args += ["--header", "Authorization: token #{token}"] unless credentials_type == :none diff --git a/Library/Homebrew/utils/inreplace.rb b/Library/Homebrew/utils/inreplace.rb index 35f7b19ae9..9763760258 100644 --- a/Library/Homebrew/utils/inreplace.rb +++ b/Library/Homebrew/utils/inreplace.rb @@ -10,7 +10,7 @@ module Utils module Inreplace extend T::Sig - # Error during replacement. + # Error during text replacement. class Error < RuntimeError def initialize(errors) formatted_errors = errors.reduce(+"inreplace failed\n") do |s, (path, errs)| @@ -70,7 +70,7 @@ module Utils Pathname(path).atomic_write(s.inreplace_string) end - raise Error, errors unless errors.empty? + raise Utils::Inreplace::Error, errors if errors.present? end # @api private @@ -86,7 +86,7 @@ module Utils contents.gsub!(old, new) end - raise Error, path => contents.errors unless contents.errors.empty? + raise Utils::Inreplace::Error, path => contents.errors if contents.errors.present? Pathname(path).atomic_write(contents.inreplace_string) unless read_only_run contents.inreplace_string diff --git a/Library/Homebrew/utils/ruby.sh b/Library/Homebrew/utils/ruby.sh index 3293949f53..51e1f9eab0 100644 --- a/Library/Homebrew/utils/ruby.sh +++ b/Library/Homebrew/utils/ruby.sh @@ -47,10 +47,10 @@ need_vendored_ruby() { if [[ -n "${HOMEBREW_FORCE_VENDOR_RUBY}" ]] then return 0 - elif [[ -n "${HOMEBREW_MACOS_SYSTEM_RUBY_NEW_ENOUGH}" ]] + elif [[ -n "${HOMEBREW_MACOS_SYSTEM_RUBY_NEW_ENOUGH}" && -z "${HOMEBREW_USE_RUBY_FROM_PATH}" ]] then return 1 - elif [[ -z "${HOMEBREW_MACOS}" ]] && test_ruby "${HOMEBREW_RUBY_PATH}" + elif [[ -z "${HOMEBREW_MACOS}" || -n "${HOMEBREW_USE_RUBY_FROM_PATH}" ]] && test_ruby "${HOMEBREW_RUBY_PATH}" then return 1 else diff --git a/Library/Homebrew/utils/ruby_check_version_script.rb b/Library/Homebrew/utils/ruby_check_version_script.rb index e06ee69c56..2d2ffbd26d 100755 --- a/Library/Homebrew/utils/ruby_check_version_script.rb +++ b/Library/Homebrew/utils/ruby_check_version_script.rb @@ -1,4 +1,4 @@ -#!/usr/bin/env ruby --enable-frozen-string-literal --disable=gems,did_you_mean,rubyopt +#!/usr/bin/env ruby # typed: true # frozen_string_literal: true @@ -17,8 +17,8 @@ ruby_version_major, ruby_version_minor, = ruby_version.canonical_segments homebrew_required_ruby_version_major, homebrew_required_ruby_version_minor, = homebrew_required_ruby_version.canonical_segments -if ENV["HOMEBREW_DEVELOPER"].present? && - ENV["HOMEBREW_USE_RUBY_FROM_PATH"].present? && +if !ENV.fetch("HOMEBREW_DEVELOPER", "").empty? && + !ENV.fetch("HOMEBREW_USE_RUBY_FROM_PATH", "").empty? && ruby_version >= homebrew_required_ruby_version return elsif ruby_version_major != homebrew_required_ruby_version_major || diff --git a/Library/Homebrew/vendor/bundle/bundler/setup.rb b/Library/Homebrew/vendor/bundle/bundler/setup.rb index c5f258c7ea..1f4eea3104 100644 --- a/Library/Homebrew/vendor/bundle/bundler/setup.rb +++ b/Library/Homebrew/vendor/bundle/bundler/setup.rb @@ -6,17 +6,17 @@ path = File.expand_path('..', __FILE__) $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/concurrent-ruby-1.1.10/lib/concurrent-ruby" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/i18n-1.12.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/minitest-5.16.2/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tzinfo-2.0.4/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tzinfo-2.0.5/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/zeitwerk-2.6.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/activesupport-6.1.6.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/public_suffix-4.0.7/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/addressable-2.8.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.10/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/msgpack-1.5.3" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.5.3/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/bootsnap-1.12.0" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.12.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/msgpack-1.5.4" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/msgpack-1.5.4/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/bootsnap-1.13.0" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bootsnap-1.13.0/lib" $:.unshift "#{path}/" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/byebug-11.1.3" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/byebug-11.1.3/lib" @@ -49,7 +49,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/net-http-persistent-4 $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mini_portile2-2.8.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/x86_64-darwin-15/2.6.0-static/racc-1.6.0" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/racc-1.6.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/nokogiri-1.13.7-x86_64-darwin/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/nokogiri-1.13.8-x86_64-darwin/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubyntlm-0.6.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrick-1.7.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrobots-0.1.2/lib" @@ -58,9 +58,9 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/method_source-1.0.0/l $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mustache-1.1.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.22.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.11.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-3.1.2.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-3.1.2.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.1.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.10158/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.10175/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parlour-8.0.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.3.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.6.0/lib" @@ -83,11 +83,11 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-retry-0.6.2/lib $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-sorbet-1.8.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec_junit_formatter-0.5.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.19.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-ast-1.21.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.11.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-2.2.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.31.2/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.14.2/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.33.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.14.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rails-2.15.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.12.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.6.11/lib" @@ -96,10 +96,9 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.12.3 $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov_json_formatter-0.1.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-0.21.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-cobertura-2.1.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.10158-universal-darwin-15/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.10158/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-stub-0.2.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-and-runtime-0.5.10158/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.10175-universal-darwin-15/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.10175/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-and-runtime-0.5.10175/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thor-1.2.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/spoom-1.1.11/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/yard-0.9.28/lib" diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/config/default.yml b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/config/default.yml similarity index 99% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/config/default.yml rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/config/default.yml index 1f67d2d54e..0b5f4c5a5d 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/config/default.yml +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/config/default.yml @@ -160,7 +160,7 @@ Performance/FlatMap: Description: >- Use `Enumerable#flat_map` instead of `Enumerable#map...Array#flatten(1)` - or `Enumberable#collect..Array#flatten(1)`. + or `Enumerable#collect..Array#flatten(1)`. Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code' Enabled: true VersionAdded: '0.30' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/config/obsoletion.yml b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/config/obsoletion.yml similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/config/obsoletion.yml rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/config/obsoletion.yml diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop-performance.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop-performance.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop-performance.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop-performance.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/mixin/regexp_metacharacter.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/mixin/regexp_metacharacter.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/mixin/regexp_metacharacter.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/mixin/regexp_metacharacter.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/mixin/sort_block.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/mixin/sort_block.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/mixin/sort_block.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/mixin/sort_block.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/ancestors_include.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/ancestors_include.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/ancestors_include.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/ancestors_include.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/bind_call.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/bind_call.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/bind_call.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/bind_call.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/block_given_with_explicit_block.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/block_given_with_explicit_block.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/block_given_with_explicit_block.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/block_given_with_explicit_block.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/caller.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/caller.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/caller.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/caller.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/case_when_splat.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/case_when_splat.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/case_when_splat.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/case_when_splat.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/casecmp.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/casecmp.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/casecmp.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/casecmp.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/chain_array_allocation.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/chain_array_allocation.rb similarity index 98% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/chain_array_allocation.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/chain_array_allocation.rb index 84a33f53f7..840ecf5cf3 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/chain_array_allocation.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/chain_array_allocation.rb @@ -47,13 +47,13 @@ module RuboCop RETURNS_NEW_ARRAY = (ALWAYS_RETURNS_NEW_ARRAY + RETURNS_NEW_ARRAY_WHEN_NO_BLOCK).freeze - MSG = 'Use unchained `%s` and `%s!` '\ - '(followed by `return array` if required) instead of chaining '\ + MSG = 'Use unchained `%s` and `%s!` ' \ + '(followed by `return array` if required) instead of chaining ' \ '`%s...%s`.' def_node_matcher :chain_array_allocation?, <<~PATTERN (send { - (send _ $%RETURN_NEW_ARRAY_WHEN_ARGS {int lvar ivar cvar gvar}) + (send _ $%RETURN_NEW_ARRAY_WHEN_ARGS {int lvar ivar cvar gvar send}) (block (send _ $%ALWAYS_RETURNS_NEW_ARRAY) ...) (send _ $%RETURNS_NEW_ARRAY ...) } $%HAS_MUTATION_ALTERNATIVE ...) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/collection_literal_in_loop.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/collection_literal_in_loop.rb similarity index 99% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/collection_literal_in_loop.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/collection_literal_in_loop.rb index 5803594fa7..50b0bbc20f 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/collection_literal_in_loop.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/collection_literal_in_loop.rb @@ -32,7 +32,7 @@ module RuboCop # end # class CollectionLiteralInLoop < Base - MSG = 'Avoid immutable %s literals in loops. '\ + MSG = 'Avoid immutable %s literals in loops. ' \ 'It is better to extract it into a local variable or a constant.' POST_CONDITION_LOOP_TYPES = %i[while_post until_post].freeze diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/compare_with_block.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/compare_with_block.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/compare_with_block.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/compare_with_block.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/concurrent_monotonic_time.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/concurrent_monotonic_time.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/concurrent_monotonic_time.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/concurrent_monotonic_time.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/constant_regexp.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/constant_regexp.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/constant_regexp.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/constant_regexp.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/count.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/count.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/count.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/count.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/delete_prefix.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/delete_prefix.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/delete_prefix.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/delete_prefix.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/delete_suffix.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/delete_suffix.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/delete_suffix.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/delete_suffix.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/detect.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/detect.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/detect.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/detect.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/double_start_end_with.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/double_start_end_with.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/double_start_end_with.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/double_start_end_with.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/end_with.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/end_with.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/end_with.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/end_with.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/fixed_size.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/fixed_size.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/fixed_size.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/fixed_size.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/flat_map.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/flat_map.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/flat_map.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/flat_map.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/inefficient_hash_search.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/inefficient_hash_search.rb similarity index 92% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/inefficient_hash_search.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/inefficient_hash_search.rb index 3c354e3b99..dd38a94b20 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/inefficient_hash_search.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/inefficient_hash_search.rb @@ -58,8 +58,7 @@ module RuboCop # `key?`/`value?` method. corrector.replace( node.loc.expression, - "#{autocorrect_hash_expression(node)}."\ - "#{autocorrect_method(node)}(#{autocorrect_argument(node)})" + "#{autocorrect_hash_expression(node)}.#{autocorrect_method(node)}(#{autocorrect_argument(node)})" ) end end @@ -68,8 +67,7 @@ module RuboCop private def message(node) - "Use `##{autocorrect_method(node)}` instead of "\ - "`##{current_method(node)}.include?`." + "Use `##{autocorrect_method(node)}` instead of `##{current_method(node)}.include?`." end def autocorrect_method(node) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/io_readlines.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/io_readlines.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/io_readlines.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/io_readlines.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/map_compact.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/map_compact.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/map_compact.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/map_compact.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/method_object_as_block.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/method_object_as_block.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/method_object_as_block.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/method_object_as_block.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/open_struct.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/open_struct.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/open_struct.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/open_struct.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/range_include.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/range_include.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/range_include.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/range_include.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_block_call.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_block_call.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_block_call.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_block_call.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_equality_comparison_block.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_equality_comparison_block.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_equality_comparison_block.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_equality_comparison_block.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_match.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_match.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_match.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_match.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_merge.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_merge.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_merge.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_merge.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_sort_block.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_sort_block.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_sort_block.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_sort_block.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_split_regexp_argument.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_split_regexp_argument.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_split_regexp_argument.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_split_regexp_argument.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_string_chars.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_string_chars.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/redundant_string_chars.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/redundant_string_chars.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/regexp_match.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/regexp_match.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/regexp_match.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/regexp_match.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/reverse_each.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/reverse_each.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/reverse_each.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/reverse_each.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/reverse_first.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/reverse_first.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/reverse_first.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/reverse_first.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/select_map.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/select_map.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/select_map.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/select_map.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/size.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/size.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/size.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/size.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/sort_reverse.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/sort_reverse.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/sort_reverse.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/sort_reverse.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/squeeze.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/squeeze.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/squeeze.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/squeeze.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/start_with.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/start_with.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/start_with.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/start_with.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/string_identifier_argument.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/string_identifier_argument.rb similarity index 95% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/string_identifier_argument.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/string_identifier_argument.rb index 63a30ddb2f..00a0bacd9e 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/string_identifier_argument.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/string_identifier_argument.rb @@ -38,7 +38,7 @@ module RuboCop remove_class_variable remove_method undef_method class_variable_get class_variable_set deprecate_constant module_function private private_constant protected public public_constant remove_const ruby2_keywords - define_singleton_method instance_variable_defined instance_variable_get instance_variable_set + define_singleton_method instance_variable_defined? instance_variable_get instance_variable_set method public_method public_send remove_instance_variable respond_to? send singleton_method __send__ ].freeze diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/string_include.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/string_include.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/string_include.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/string_include.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/string_replacement.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/string_replacement.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/string_replacement.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/string_replacement.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/sum.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/sum.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/sum.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/sum.rb index ea590a375d..10303a56b9 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/sum.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/sum.rb @@ -7,7 +7,7 @@ module RuboCop # in some Enumerable object can be replaced by `Enumerable#sum` method. # # @safety - # Auto-corrections are unproblematic wherever an initial value is provided explicitly: + # Autocorrections are unproblematic wherever an initial value is provided explicitly: # # [source,ruby] # ---- @@ -43,7 +43,7 @@ module RuboCop # # @example OnlySumOrWithInitialValue: false (default) # # bad - # [1, 2, 3].inject(:+) # Auto-corrections for cases without initial value are unsafe + # [1, 2, 3].inject(:+) # Autocorrections for cases without initial value are unsafe # [1, 2, 3].inject(&:+) # and will only be performed when using the `-A` option. # [1, 2, 3].reduce { |acc, elem| acc + elem } # They can be prohibited completely using `SafeAutoCorrect: true`. # [1, 2, 3].reduce(10, :+) diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/times_map.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/times_map.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/times_map.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/times_map.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/unfreeze_string.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/unfreeze_string.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/unfreeze_string.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/unfreeze_string.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/uri_default_parser.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/uri_default_parser.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance/uri_default_parser.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance/uri_default_parser.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance_cops.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance_cops.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/cop/performance_cops.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/cop/performance_cops.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/performance.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/performance.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/performance.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/performance.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/performance/inject.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/performance/inject.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/performance/inject.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/performance/inject.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/performance/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/performance/version.rb similarity index 91% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/performance/version.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/performance/version.rb index 9f6d9f2dc7..1d9846349b 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.2/lib/rubocop/performance/version.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-performance-1.14.3/lib/rubocop/performance/version.rb @@ -4,7 +4,7 @@ module RuboCop module Performance # This module holds the RuboCop Performance version information. module Version - STRING = '1.14.2' + STRING = '1.14.3' def self.document_version STRING.match('\d+\.\d+').to_s diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/sorbet-runtime.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/sorbet-runtime.rb new file mode 100644 index 0000000000..c2ad5678d0 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/sorbet-runtime.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true +# typed: true + +# This file is hand-crafted to encode the dependencies. They load the whole type +# system since there is such a high chance of it being used, using an autoloader +# wouldn't buy us any startup time saving. + +# Namespaces without any implementation +module T; end +module T::Helpers; end +module T::Private; end +module T::Private::Abstract; end +module T::Private::Types; end + +# Each section is a group that I believe need a fixed ordering. There is also +# an ordering between groups. + +# These are pre-reqs for almost everything in here. +require_relative 'types/configuration' +require_relative 'types/_types' +require_relative 'types/private/decl_state' +require_relative 'types/private/class_utils' +require_relative 'types/private/runtime_levels' +require_relative 'types/private/methods/_methods' +require_relative 'types/sig' +require_relative 'types/helpers' +require_relative 'types/private/final' +require_relative 'types/private/sealed' + +# The types themselves. First base classes +require_relative 'types/types/base' +require_relative 'types/types/typed_enumerable' +# Everything else +require_relative 'types/types/class_of' +require_relative 'types/types/enum' +require_relative 'types/types/fixed_array' +require_relative 'types/types/fixed_hash' +require_relative 'types/types/intersection' +require_relative 'types/types/noreturn' +require_relative 'types/types/proc' +require_relative 'types/types/attached_class' +require_relative 'types/types/self_type' +require_relative 'types/types/simple' +require_relative 'types/types/t_enum' +require_relative 'types/types/type_parameter' +require_relative 'types/types/typed_array' +require_relative 'types/types/typed_enumerator' +require_relative 'types/types/typed_enumerator_lazy' +require_relative 'types/types/typed_hash' +require_relative 'types/types/typed_range' +require_relative 'types/types/typed_set' +require_relative 'types/types/union' +require_relative 'types/types/untyped' +require_relative 'types/private/types/not_typed' +require_relative 'types/private/types/void' +require_relative 'types/private/types/string_holder' +require_relative 'types/private/types/type_alias' + +require_relative 'types/types/type_variable' +require_relative 'types/types/type_member' +require_relative 'types/types/type_template' + +# Call validation +require_relative 'types/private/methods/modes' +require_relative 'types/private/methods/call_validation' + +# Signature validation +require_relative 'types/private/methods/signature_validation' +require_relative 'types/abstract_utils' +require_relative 'types/private/abstract/validate' + +# Catch all. Sort of built by `cd extn; find types -type f | grep -v test | sort` +require_relative 'types/generic' +require_relative 'types/interface_wrapper' +require_relative 'types/private/abstract/declare' +require_relative 'types/private/abstract/hooks' +require_relative 'types/private/casts' +require_relative 'types/private/methods/decl_builder' +require_relative 'types/private/methods/signature' +require_relative 'types/private/retry' +require_relative 'types/utils' +require_relative 'types/boolean' + +# Props dependencies +require_relative 'types/private/abstract/data' +require_relative 'types/private/mixins/mixins' +require_relative 'types/props/_props' +require_relative 'types/props/custom_type' +require_relative 'types/props/decorator' +require_relative 'types/props/errors' +require_relative 'types/props/plugin' +require_relative 'types/props/utils' +require_relative 'types/enum' +# Props that run sigs statically so have to be after all the others :( +require_relative 'types/props/private/setter_factory' +require_relative 'types/props/private/apply_default' +require_relative 'types/props/has_lazily_specialized_methods' +require_relative 'types/props/optional' +require_relative 'types/props/weak_constructor' +require_relative 'types/props/constructor' +require_relative 'types/props/pretty_printable' +require_relative 'types/props/private/serde_transform' +require_relative 'types/props/private/deserializer_generator' +require_relative 'types/props/private/serializer_generator' +require_relative 'types/props/serializable' +require_relative 'types/props/type_validation' +require_relative 'types/props/private/parser' +require_relative 'types/props/generated_code_validation' + +require_relative 'types/struct' +require_relative 'types/non_forcing_constants' + +require_relative 'types/compatibility_patches' + +# Sorbet Compiler support module +require_relative 'types/private/compiler' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/_types.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/_types.rb new file mode 100644 index 0000000000..20a0e641e0 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/_types.rb @@ -0,0 +1,316 @@ +# frozen_string_literal: true +# typed: true +# This is where we define the shortcuts, so we can't use them here + +# _____ +# |_ _| _ _ __ ___ ___ +# | || | | | '_ \ / _ \/ __| +# | || |_| | |_) | __/\__ \ +# |_| \__, | .__/ \___||___/ +# |___/|_| +# +# Docs at https://sorbet.org/docs/sigs +# +# Types that you can pass to `sig`: +# +# - a Ruby class +# +# - [, , ...] -- to specify a "tuple"; a fixed-size array with known types for each member +# +# - {key: , key2: , ...} -- to speicfy a "shape"; a fixed-size hash +# with known keys and type values +# +# - Any of the `T.foo` methods below + +module T + # T.any(, , ...) -- matches any of the types listed + def self.any(type_a, type_b, *types) + type_a = T::Utils.coerce(type_a) + type_b = T::Utils.coerce(type_b) + types = types.map {|t| T::Utils.coerce(t)} if !types.empty? + T::Types::Union::Private::Pool.union_of_types(type_a, type_b, types) + end + + # Shorthand for T.any(type, NilClass) + def self.nilable(type) + T::Types::Union::Private::Pool.union_of_types(T::Utils.coerce(type), T::Utils::Nilable::NIL_TYPE) + end + + # Matches any object. In the static checker, T.untyped allows any + # method calls or operations. + def self.untyped + T::Types::Untyped::Private::INSTANCE + end + + # Indicates a function never returns (e.g. "Kernel#raise") + def self.noreturn + T::Types::NoReturn::Private::INSTANCE + end + + # T.all(, , ...) -- matches an object that has all of the types listed + def self.all(type_a, type_b, *types) + T::Types::Intersection.new([type_a, type_b] + types) + end + + # Matches any of the listed values + # @deprecated Use T::Enum instead. + def self.deprecated_enum(values) + T::Types::Enum.new(values) + end + + # Creates a proc type + def self.proc + T::Private::Methods.start_proc + end + + # Matches `self`: + def self.self_type + T::Types::SelfType::Private::INSTANCE + end + + # Matches the instance type in a singleton-class context + def self.attached_class + T::Types::AttachedClassType::Private::INSTANCE + end + + # Matches any class that subclasses or includes the provided class + # or module + def self.class_of(klass) + T::Types::ClassOf.new(klass) + end + + ## END OF THE METHODS TO PASS TO `sig`. + + # Constructs a type alias. Used to create a short name for a larger type. In Ruby this returns a + # wrapper that contains a proc that is evaluated to get the underlying type. This syntax however + # is needed for support by the static checker. + # + # @example + # NilableString = T.type_alias {T.nilable(String)} + # + # sig {params(arg: NilableString, default: String).returns(String)} + # def or_else(arg, default) + # arg || default + # end + # + # The name of the type alias is not preserved; Error messages will + # be printed with reference to the underlying type. + # + # TODO Remove `type` parameter. This was left in to make life easier while migrating. + def self.type_alias(type=nil, &blk) + if blk + T::Private::Types::TypeAlias.new(blk) + else + T::Utils.coerce(type) + end + end + + # References a type parameter which was previously defined with + # `type_parameters`. + # + # This is used for generic methods. + # + # @example + # sig + # .type_parameters(:U) + # .params( + # blk: T.proc.params(arg0: Elem).returns(T.type_parameter(:U)), + # ) + # .returns(T::Array[T.type_parameter(:U)]) + # def map(&blk); end + def self.type_parameter(name) + T::Types::TypeParameter.new(name) + end + + # Tells the typechecker that `value` is of type `type`. Use this to get additional checking after + # an expression that the typechecker is unable to analyze. If `checked` is true, raises an + # exception at runtime if the value doesn't match the type. + # + # Compared to `T.let`, `T.cast` is _trusted_ by static system. + def self.cast(value, type, checked: true) + return value unless checked + + Private::Casts.cast(value, type, cast_method: "T.cast") + end + + # Tells the typechecker to declare a variable of type `type`. Use + # like: + # + # seconds = T.let(0.0, Float) + # + # Compared to `T.cast`, `T.let` is _checked_ by static system. + # + # If `checked` is true, raises an exception at runtime if the value + # doesn't match the type. + def self.let(value, type, checked: true) + return value unless checked + + Private::Casts.cast(value, type, cast_method: "T.let") + end + + # Tells the type checker to treat `self` in the current block as `type`. + # Useful for blocks that are captured and executed later with instance_exec. + # Use like: + # + # seconds = lambda do + # T.bind(self, NewBinding) + # ... + # end + # + # `T.bind` behaves like `T.cast` in that it is assumed to be true statically. + # + # If `checked` is true, raises an exception at runtime if the value + # doesn't match the type (this is the default). + def self.bind(value, type, checked: true) + return value unless checked + + Private::Casts.cast(value, type, cast_method: "T.bind") + end + + # Tells the typechecker to ensure that `value` is of type `type` (if not, the typechecker will + # fail). Use this for debugging typechecking errors, or to ensure that type information is + # statically known and being checked appropriately. If `checked` is true, raises an exception at + # runtime if the value doesn't match the type. + def self.assert_type!(value, type, checked: true) + return value unless checked + + Private::Casts.cast(value, type, cast_method: "T.assert_type!") + end + + # For the static type checker, strips all type information from a value + # and returns the same value, but statically-typed as `T.untyped`. + # Can be used to tell the static checker to "trust you" by discarding type information + # you know to be incorrect. Use with care! + # (This has no effect at runtime.) + # + # We can't actually write this sig because we ourselves are inside + # the `T::` module and doing this would create a bootstrapping + # cycle. However, we also don't actually need to do so; An untyped + # identity method works just as well here. + # + # `sig {params(value: T.untyped).returns(T.untyped)}` + def self.unsafe(value) + value + end + + # A convenience method to `raise` when the argument is `nil` and return it + # otherwise. + # + # Intended to be used as: + # + # needs_foo(T.must(maybe_gives_foo)) + # + # Equivalent to: + # + # foo = maybe_gives_foo + # raise "nil" if foo.nil? + # needs_foo(foo) + # + # Intended to be used to promise sorbet that a given nilable value happens + # to contain a non-nil value at this point. + # + # `sig {params(arg: T.nilable(A)).returns(A)}` + def self.must(arg) + return arg if arg + return arg if arg == false + + begin + raise TypeError.new("Passed `nil` into T.must") + rescue TypeError => e # raise into rescue to ensure e.backtrace is populated + T::Configuration.inline_type_error_handler(e, {kind: 'T.must', value: arg, type: nil}) + end + end + + # A way to ask Sorbet to show what type it thinks an expression has. + # This can be useful for debugging and checking assumptions. + # In the runtime, merely returns the value passed in. + def self.reveal_type(value) + value + end + + # A way to ask Sorbet to prove that a certain branch of control flow never + # happens. Commonly used to assert that a case or if statement exhausts all + # possible cases. + def self.absurd(value) + msg = "Control flow reached T.absurd." + + case value + when Kernel + msg += " Got value: #{value}" + end + + begin + raise TypeError.new(msg) + rescue TypeError => e # raise into rescue to ensure e.backtrace is populated + T::Configuration.inline_type_error_handler(e, {kind: 'T.absurd', value: value, type: nil}) + end + end + + ### Generic classes ### + + module Array + def self.[](type) + if type.is_a?(T::Types::Untyped) + T::Types::TypedArray::Untyped.new + else + T::Types::TypedArray.new(type) + end + end + end + + module Hash + def self.[](keys, values) + if keys.is_a?(T::Types::Untyped) && values.is_a?(T::Types::Untyped) + T::Types::TypedHash::Untyped.new + else + T::Types::TypedHash.new(keys: keys, values: values) + end + end + end + + module Enumerable + def self.[](type) + if type.is_a?(T::Types::Untyped) + T::Types::TypedEnumerable::Untyped.new + else + T::Types::TypedEnumerable.new(type) + end + end + end + + module Enumerator + def self.[](type) + if type.is_a?(T::Types::Untyped) + T::Types::TypedEnumerator::Untyped.new + else + T::Types::TypedEnumerator.new(type) + end + end + + module Lazy + def self.[](type) + if type.is_a?(T::Types::Untyped) + T::Types::TypedEnumeratorLazy::Untyped.new + else + T::Types::TypedEnumeratorLazy.new(type) + end + end + end + end + + module Range + def self.[](type) + T::Types::TypedRange.new(type) + end + end + + module Set + def self.[](type) + if type.is_a?(T::Types::Untyped) + T::Types::TypedSet::Untyped.new + else + T::Types::TypedSet.new(type) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/abstract_utils.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/abstract_utils.rb new file mode 100644 index 0000000000..721bd4e0a7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/abstract_utils.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true +# typed: true + +module T::AbstractUtils + Methods = T::Private::Methods + + # Returns whether a module is declared as abstract. After the module is finished being declared, + # this is equivalent to whether it has any abstract methods that haven't been implemented + # (because we validate that and raise an error otherwise). + # + # Note that checking `mod.is_a?(Abstract::Hooks)` is not a safe substitute for this method; when + # a class extends `Abstract::Hooks`, all of its subclasses, including the eventual concrete + # ones, will still have `Abstract::Hooks` as an ancestor. + def self.abstract_module?(mod) + !T::Private::Abstract::Data.get(mod, :abstract_type).nil? + end + + def self.abstract_method?(method) + signature = Methods.signature_for_method(method) + signature&.mode == Methods::Modes.abstract + end + + # Given a module, returns the set of methods declared as abstract (in itself or ancestors) + # that have not been implemented. + def self.abstract_methods_for(mod) + declared_methods = declared_abstract_methods_for(mod) + declared_methods.select do |declared_method| + actual_method = mod.instance_method(declared_method.name) + # Note that in the case where an abstract method is overridden by another abstract method, + # this method will return them both. This is intentional to ensure we validate the final + # implementation against all declarations of an abstract method (they might not all have the + # same signature). + abstract_method?(actual_method) + end + end + + # Given a module, returns the set of methods declared as abstract (in itself or ancestors) + # regardless of whether they have been implemented. + def self.declared_abstract_methods_for(mod) + methods = [] + mod.ancestors.each do |ancestor| + ancestor_methods = ancestor.private_instance_methods(false) + ancestor.instance_methods(false) + ancestor_methods.each do |method_name| + method = ancestor.instance_method(method_name) + methods << method if abstract_method?(method) + end + end + methods + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/boolean.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/boolean.rb new file mode 100644 index 0000000000..8763d8707d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/boolean.rb @@ -0,0 +1,8 @@ +# typed: strict +# frozen_string_literal: true + +module T + # T::Boolean is a type alias helper for the common `T.any(TrueClass, FalseClass)`. + # Defined separately from _types.rb because it has a dependency on T::Types::Union. + Boolean = T.type_alias {T.any(TrueClass, FalseClass)} +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/compatibility_patches.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/compatibility_patches.rb new file mode 100644 index 0000000000..070b182aae --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/compatibility_patches.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true +# typed: ignore + +# Work around an interaction bug with sorbet-runtime and rspec-mocks, +# which occurs when using message expectations (*_any_instance_of, +# expect, allow) and and_call_original. +# +# When a sig is defined, sorbet-runtime will replace the sigged method +# with a wrapper that, upon first invocation, re-wraps the method with a faster +# implementation. +# +# When expect_any_instance_of is used, rspec stores a reference to the first wrapper, +# to be restored later. +# +# The first wrapper is invoked as part of the test and sorbet-runtime replaces +# the method definition with the second wrapper. +# +# But when mocks are cleaned up, rspec restores back to the first wrapper. +# Upon subsequent invocations, the first wrapper is called, and sorbet-runtime +# throws a runtime error, since this is an unexpected state. +# +# We work around this by forcing re-wrapping before rspec stores a reference +# to the method. +if defined? ::RSpec::Mocks + module T + module CompatibilityPatches + module RSpecCompatibility + module RecorderExtensions + def observe!(method_name) + method = @klass.instance_method(method_name.to_sym) + T::Private::Methods.maybe_run_sig_block_for_method(method) + super(method_name) + end + end + ::RSpec::Mocks::AnyInstance::Recorder.prepend(RecorderExtensions) if defined?(::RSpec::Mocks::AnyInstance::Recorder) + + module MethodDoubleExtensions + def initialize(object, method_name, proxy) + if ::Kernel.instance_method(:respond_to?).bind(object).call(method_name, true) + method = ::RSpec::Support.method_handle_for(object, method_name) + T::Private::Methods.maybe_run_sig_block_for_method(method) + end + super(object, method_name, proxy) + end + end + ::RSpec::Mocks::MethodDouble.prepend(MethodDoubleExtensions) if defined?(::RSpec::Mocks::MethodDouble) + end + end + end +end + +# Work around for sorbet-runtime wrapped methods. +# +# When a sig is defined, sorbet-runtime will replace the sigged method +# with a wrapper. Those wrapper methods look like `foo(*args, &blk)` +# so that wrappers can handle and pass on all the arguments supplied. +# +# However, that creates a problem with runtime reflection on the methods, +# since when a sigged method is introspected, it will always return its +# `arity` as `-1`, its `parameters` as `[[:rest, :args], [:block, :blk]]`, +# and its `source_location` as `[, ]`. +# +# This might be a problem for some applications that rely on getting the +# correct information from these methods. +# +# This compatibility module, when prepended to the `Method` class, would fix +# the return values of `arity`, `parameters` and `source_location`. +# +# @example +# require 'sorbet-runtime' +# ::Method.prepend(T::CompatibilityPatches::MethodExtensions) +module T + module CompatibilityPatches + module MethodExtensions + def arity + arity = super + return arity if arity != -1 || self.is_a?(Proc) + sig = T::Private::Methods.signature_for_method(self) + sig ? sig.method.arity : arity + end + + def source_location + sig = T::Private::Methods.signature_for_method(self) + sig ? sig.method.source_location : super + end + + def parameters + sig = T::Private::Methods.signature_for_method(self) + sig ? sig.method.parameters : super + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/configuration.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/configuration.rb new file mode 100644 index 0000000000..c012b6e8b6 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/configuration.rb @@ -0,0 +1,591 @@ +# typed: true +# frozen_string_literal: true + +module T::Configuration + # Cache this comparisonn to avoid two allocations all over the place. + AT_LEAST_RUBY_2_7 = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7') + + # Announces to Sorbet that we are currently in a test environment, so it + # should treat any sigs which are marked `.checked(:tests)` as if they were + # just a normal sig. + # + # If this method is not called, sigs marked `.checked(:tests)` will not be + # checked. In fact, such methods won't even be wrapped--the runtime will put + # back the original method. + # + # Note: Due to the way sigs are evaluated and methods are wrapped, this + # method MUST be called before any code calls `sig`. This method raises if + # it has been called too late. + def self.enable_checking_for_sigs_marked_checked_tests + T::Private::RuntimeLevels.enable_checking_in_tests + end + + # Announce to Sorbet that we would like the final checks to be enabled when + # including and extending modules. Iff this is not called, then the following + # example will not raise an error. + # + # ```ruby + # module M + # extend T::Sig + # sig(:final) {void} + # def foo; end + # end + # class C + # include M + # def foo; end + # end + # ``` + def self.enable_final_checks_on_hooks + T::Private::Methods.set_final_checks_on_hooks(true) + end + + # Undo the effects of a previous call to + # `enable_final_checks_on_hooks`. + def self.reset_final_checks_on_hooks + T::Private::Methods.set_final_checks_on_hooks(false) + end + + @include_value_in_type_errors = true + # Whether to include values in TypeError messages. + # + # Including values is useful for debugging, but can potentially leak + # sensitive information to logs. + # + # @return [T::Boolean] + def self.include_value_in_type_errors? + @include_value_in_type_errors + end + + # Configure if type errors excludes the value of the problematic type. + # + # The default is to include values in type errors: + # TypeError: Expected type Integer, got String with value "foo" + # + # When values are excluded from type errors: + # TypeError: Expected type Integer, got String + def self.exclude_value_in_type_errors + @include_value_in_type_errors = false + end + + # Opposite of exclude_value_in_type_errors. + # (Including values in type errors is the default) + def self.include_value_in_type_errors + @include_value_in_type_errors = true + end + + # Whether VM-defined prop serialization/deserialization routines can be enabled. + # + # @return [T::Boolean] + def self.can_enable_vm_prop_serde? + T::Props::Private::DeserializerGenerator.respond_to?(:generate2) + end + + @use_vm_prop_serde = false + # Whether to use VM-defined prop serialization/deserialization routines. + # + # The default is to use runtime codegen inside sorbet-runtime itself. + # + # @return [T::Boolean] + def self.use_vm_prop_serde? + @use_vm_prop_serde || false + end + + # Enable using VM-defined prop serialization/deserialization routines. + # + # This method is likely to break things outside of Stripe's systems. + def self.enable_vm_prop_serde + if !can_enable_vm_prop_serde? + hard_assert_handler('Ruby VM is not setup to use VM-defined prop serde') + end + @use_vm_prop_serde = true + end + + # Disable using VM-defined prop serialization/deserialization routines. + def self.disable_vm_prop_serde + @use_vm_prop_serde = false + end + + # Configure the default checked level for a sig with no explicit `.checked` + # builder. When unset, the default checked level is `:always`. + # + # Note: setting this option is potentially dangerous! Sorbet can't check all + # code statically. The runtime checks complement the checks that Sorbet does + # statically, so that methods don't have to guard themselves from being + # called incorrectly by untyped code. + # + # @param [:never, :compiled, :tests, :always] default_checked_level + def self.default_checked_level=(default_checked_level) + T::Private::RuntimeLevels.default_checked_level = default_checked_level + end + + @inline_type_error_handler = nil + # Set a handler to handle `TypeError`s raised by any in-line type assertions, + # including `T.must`, `T.let`, `T.cast`, and `T.assert_type!`. + # + # By default, any `TypeError`s detected by this gem will be raised. Setting + # inline_type_error_handler to an object that implements :call (e.g. proc or + # lambda) allows users to customize the behavior when a `TypeError` is + # raised on any inline type assertion. + # + # @param [Lambda, Proc, Object, nil] value Proc that handles the error (pass + # nil to reset to default behavior) + # + # Parameters passed to value.call: + # + # @param [TypeError] error TypeError that was raised + # @param [Hash] opts A hash containing contextual information on the error: + # @option opts [String] :kind One of: + # ['T.cast', 'T.let', 'T.bind', 'T.assert_type!', 'T.must', 'T.absurd'] + # @option opts [Object, nil] :type Expected param/return value type + # @option opts [Object] :value Actual param/return value + # + # @example + # T::Configuration.inline_type_error_handler = lambda do |error, opts| + # puts error.message + # end + def self.inline_type_error_handler=(value) + validate_lambda_given!(value) + @inline_type_error_handler = value + end + + private_class_method def self.inline_type_error_handler_default(error, opts) + raise error + end + + def self.inline_type_error_handler(error, opts={}) + if @inline_type_error_handler + # Backwards compatibility before `inline_type_error_handler` took a second arg + if @inline_type_error_handler.arity == 1 + @inline_type_error_handler.call(error) + else + @inline_type_error_handler.call(error, opts) + end + else + inline_type_error_handler_default(error, opts) + end + nil + end + + @sig_builder_error_handler = nil + # Set a handler to handle errors that occur when the builder methods in the + # body of a sig are executed. The sig builder methods are inside a proc so + # that they can be lazily evaluated the first time the method being sig'd is + # called. + # + # By default, improper use of the builder methods within the body of a sig + # cause an ArgumentError to be raised. Setting sig_builder_error_handler to an + # object that implements :call (e.g. proc or lambda) allows users to + # customize the behavior when a sig can't be built for some reason. + # + # @param [Lambda, Proc, Object, nil] value Proc that handles the error (pass + # nil to reset to default behavior) + # + # Parameters passed to value.call: + # + # @param [StandardError] error The error that was raised + # @param [Thread::Backtrace::Location] location Location of the error + # + # @example + # T::Configuration.sig_builder_error_handler = lambda do |error, location| + # puts error.message + # end + def self.sig_builder_error_handler=(value) + validate_lambda_given!(value) + @sig_builder_error_handler = value + end + + private_class_method def self.sig_builder_error_handler_default(error, location) + raise ArgumentError.new("#{location.path}:#{location.lineno}: Error interpreting `sig`:\n #{error.message}\n\n") + end + + def self.sig_builder_error_handler(error, location) + if @sig_builder_error_handler + @sig_builder_error_handler.call(error, location) + else + sig_builder_error_handler_default(error, location) + end + nil + end + + @sig_validation_error_handler = nil + # Set a handler to handle sig validation errors. + # + # Sig validation errors include things like abstract checks, override checks, + # and type compatibility of arguments. They happen after a sig has been + # successfully built, but the built sig is incompatible with other sigs in + # some way. + # + # By default, sig validation errors cause an exception to be raised. + # Setting sig_validation_error_handler to an object that implements :call + # (e.g. proc or lambda) allows users to customize the behavior when a method + # signature's build fails. + # + # @param [Lambda, Proc, Object, nil] value Proc that handles the error (pass + # nil to reset to default behavior) + # + # Parameters passed to value.call: + # + # @param [StandardError] error The error that was raised + # @param [Hash] opts A hash containing contextual information on the error: + # @option opts [Method, UnboundMethod] :method Method on which the signature build failed + # @option opts [T::Private::Methods::Declaration] :declaration Method + # signature declaration struct + # @option opts [T::Private::Methods::Signature, nil] :signature Signature + # that failed (nil if sig build failed before Signature initialization) + # @option opts [T::Private::Methods::Signature, nil] :super_signature Super + # method's signature (nil if method is not an override or super method + # does not have a method signature) + # + # @example + # T::Configuration.sig_validation_error_handler = lambda do |error, opts| + # puts error.message + # end + def self.sig_validation_error_handler=(value) + validate_lambda_given!(value) + @sig_validation_error_handler = value + end + + private_class_method def self.sig_validation_error_handler_default(error, opts) + raise error + end + + def self.sig_validation_error_handler(error, opts={}) + if @sig_validation_error_handler + @sig_validation_error_handler.call(error, opts) + else + sig_validation_error_handler_default(error, opts) + end + nil + end + + @call_validation_error_handler = nil + # Set a handler for type errors that result from calling a method. + # + # By default, errors from calling a method cause an exception to be raised. + # Setting call_validation_error_handler to an object that implements :call + # (e.g. proc or lambda) allows users to customize the behavior when a method + # is called with invalid parameters, or returns an invalid value. + # + # @param [Lambda, Proc, Object, nil] value Proc that handles the error + # report (pass nil to reset to default behavior) + # + # Parameters passed to value.call: + # + # @param [T::Private::Methods::Signature] signature Signature that failed + # @param [Hash] opts A hash containing contextual information on the error: + # @option opts [String] :message Error message + # @option opts [String] :kind One of: + # ['Parameter', 'Block parameter', 'Return value'] + # @option opts [Symbol] :name Param or block param name (nil for return + # value) + # @option opts [Object] :type Expected param/return value type + # @option opts [Object] :value Actual param/return value + # @option opts [Thread::Backtrace::Location] :location Location of the + # caller + # + # @example + # T::Configuration.call_validation_error_handler = lambda do |signature, opts| + # puts opts[:message] + # end + def self.call_validation_error_handler=(value) + validate_lambda_given!(value) + @call_validation_error_handler = value + end + + private_class_method def self.call_validation_error_handler_default(signature, opts) + raise TypeError.new(opts[:pretty_message]) + end + + def self.call_validation_error_handler(signature, opts={}) + if @call_validation_error_handler + @call_validation_error_handler.call(signature, opts) + else + call_validation_error_handler_default(signature, opts) + end + nil + end + + @log_info_handler = nil + # Set a handler for logging + # + # @param [Lambda, Proc, Object, nil] value Proc that handles the error + # report (pass nil to reset to default behavior) + # + # Parameters passed to value.call: + # + # @param [String] str Message to be logged + # @param [Hash] extra A hash containing additional parameters to be passed along to the logger. + # + # @example + # T::Configuration.log_info_handler = lambda do |str, extra| + # puts "#{str}, context: #{extra}" + # end + def self.log_info_handler=(value) + validate_lambda_given!(value) + @log_info_handler = value + end + + private_class_method def self.log_info_handler_default(str, extra) + puts "#{str}, extra: #{extra}" + end + + def self.log_info_handler(str, extra) + if @log_info_handler + @log_info_handler.call(str, extra) + else + log_info_handler_default(str, extra) + end + end + + @soft_assert_handler = nil + # Set a handler for soft assertions + # + # These generally shouldn't stop execution of the program, but rather inform + # some party of the assertion to action on later. + # + # @param [Lambda, Proc, Object, nil] value Proc that handles the error + # report (pass nil to reset to default behavior) + # + # Parameters passed to value.call: + # + # @param [String] str Assertion message + # @param [Hash] extra A hash containing additional parameters to be passed along to the handler. + # + # @example + # T::Configuration.soft_assert_handler = lambda do |str, extra| + # puts "#{str}, context: #{extra}" + # end + def self.soft_assert_handler=(value) + validate_lambda_given!(value) + @soft_assert_handler = value + end + + private_class_method def self.soft_assert_handler_default(str, extra) + puts "#{str}, extra: #{extra}" + end + + def self.soft_assert_handler(str, extra) + if @soft_assert_handler + @soft_assert_handler.call(str, extra) + else + soft_assert_handler_default(str, extra) + end + end + + @hard_assert_handler = nil + # Set a handler for hard assertions + # + # These generally should stop execution of the program, and optionally inform + # some party of the assertion. + # + # @param [Lambda, Proc, Object, nil] value Proc that handles the error + # report (pass nil to reset to default behavior) + # + # Parameters passed to value.call: + # + # @param [String] str Assertion message + # @param [Hash] extra A hash containing additional parameters to be passed along to the handler. + # + # @example + # T::Configuration.hard_assert_handler = lambda do |str, extra| + # raise "#{str}, context: #{extra}" + # end + def self.hard_assert_handler=(value) + validate_lambda_given!(value) + @hard_assert_handler = value + end + + private_class_method def self.hard_assert_handler_default(str, _) + raise str + end + + def self.hard_assert_handler(str, extra={}) + if @hard_assert_handler + @hard_assert_handler.call(str, extra) + else + hard_assert_handler_default(str, extra) + end + end + + @scalar_types = nil + # Set a list of class strings that are to be considered scalar. + # (pass nil to reset to default behavior) + # + # @param [String] values Class name. + # + # @example + # T::Configuration.scalar_types = ["NilClass", "TrueClass", "FalseClass", ...] + def self.scalar_types=(values) + if values.nil? + @scalar_types = values + else + bad_values = values.reject {|v| v.class == String} + unless bad_values.empty? + raise ArgumentError.new("Provided values must all be class name strings.") + end + + @scalar_types = values.each_with_object({}) {|x, acc| acc[x] = true}.freeze + end + end + + @default_scalar_types = { + "NilClass" => true, + "TrueClass" => true, + "FalseClass" => true, + "Integer" => true, + "Float" => true, + "String" => true, + "Symbol" => true, + "Time" => true, + "T::Enum" => true, + }.freeze + + def self.scalar_types + @scalar_types || @default_scalar_types + end + + # Guard against overrides of `name` or `to_s` + MODULE_NAME = Module.instance_method(:name) + private_constant :MODULE_NAME + + @default_module_name_mangler = if T::Configuration::AT_LEAST_RUBY_2_7 + ->(type) {MODULE_NAME.bind_call(type)} + else + ->(type) {MODULE_NAME.bind(type).call} + end + + @module_name_mangler = nil + + def self.module_name_mangler + @module_name_mangler || @default_module_name_mangler + end + + # Set to override the default behavior for converting types + # to names in generated code. Used by the runtime implementation + # associated with `--stripe-packages` mode. + # + # @param [Lambda, Proc, nil] handler Proc that converts a type (Class/Module) + # to a String (pass nil to reset to default behavior) + def self.module_name_mangler=(handler) + @module_name_mangler = handler + end + + @sensitivity_and_pii_handler = nil + # Set to a PII handler function. This will be called with the `sensitivity:` + # annotations on things that use `T::Props` and can modify them ahead-of-time. + # + # @param [Lambda, Proc, nil] handler Proc that takes a hash mapping symbols to the + # prop values. Pass nil to avoid changing `sensitivity:` annotations. + def self.normalize_sensitivity_and_pii_handler=(handler) + @sensitivity_and_pii_handler = handler + end + + def self.normalize_sensitivity_and_pii_handler + @sensitivity_and_pii_handler + end + + @redaction_handler = nil + # Set to a redaction handling function. This will be called when the + # `_redacted` version of a prop reader is used. By default this is set to + # `nil` and will raise an exception when the redacted version of a prop is + # accessed. + # + # @param [Lambda, Proc, nil] handler Proc that converts a value into its + # redacted version according to the spec passed as the second argument. + def self.redaction_handler=(handler) + @redaction_handler = handler + end + + def self.redaction_handler + @redaction_handler + end + + @class_owner_finder = nil + # Set to a function which can get the 'owner' of a class. This is + # used in reporting deserialization errors + # + # @param [Lambda, Proc, nil] handler Proc that takes a class and + # produces its owner, or `nil` if it does not have one. + def self.class_owner_finder=(handler) + @class_owner_finder = handler + end + + def self.class_owner_finder + @class_owner_finder + end + + # Temporarily disable ruby warnings while executing the given block. This is + # useful when doing something that would normally cause a warning to be + # emitted in Ruby verbose mode ($VERBOSE = true). + # + # @yield + # + def self.without_ruby_warnings + if $VERBOSE + begin + original_verbose = $VERBOSE + $VERBOSE = false + yield + ensure + $VERBOSE = original_verbose + end + else + yield + end + end + + @legacy_t_enum_migration_mode = false + def self.enable_legacy_t_enum_migration_mode + @legacy_t_enum_migration_mode = true + end + def self.disable_legacy_t_enum_migration_mode + @legacy_t_enum_migration_mode = false + end + def self.legacy_t_enum_migration_mode? + @legacy_t_enum_migration_mode || false + end + + @prop_freeze_handler = ->(instance, prop_name) {} + + def self.prop_freeze_handler=(handler) + @prop_freeze_handler = handler + end + + def self.prop_freeze_handler + @prop_freeze_handler + end + + @sealed_violation_whitelist = nil + # @param [Array] sealed_violation_whitelist An array of Regexp to validate + # whether inheriting /including a sealed module outside the defining module + # should be allowed. Useful to whitelist benign violations, like shim files + # generated for an autoloader. + def self.sealed_violation_whitelist=(sealed_violation_whitelist) + if !@sealed_violation_whitelist.nil? + raise ArgumentError.new("Cannot overwrite sealed_violation_whitelist after setting it") + end + + case sealed_violation_whitelist + when Array + sealed_violation_whitelist.each do |x| + case x + when Regexp then nil + else raise TypeError.new("sealed_violation_whitelist accepts an Array of Regexp") + end + end + else + raise TypeError.new("sealed_violation_whitelist= accepts an Array of Regexp") + end + + @sealed_violation_whitelist = sealed_violation_whitelist + end + def self.sealed_violation_whitelist + @sealed_violation_whitelist + end + + private_class_method def self.validate_lambda_given!(value) + if !value.nil? && !value.respond_to?(:call) + raise ArgumentError.new("Provided value must respond to :call") + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/enum.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/enum.rb new file mode 100644 index 0000000000..c2de09abaf --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/enum.rb @@ -0,0 +1,377 @@ +# frozen_string_literal: true +# typed: strict + +# Enumerations allow for type-safe declarations of a fixed set of values. +# +# Every value is a singleton instance of the class (i.e. `Suit::SPADE.is_a?(Suit) == true`). +# +# Each value has a corresponding serialized value. By default this is the constant's name converted +# to lowercase (e.g. `Suit::Club.serialize == 'club'`); however a custom value may be passed to the +# constructor. Enum will `freeze` the serialized value. +# +# @example Declaring an Enum: +# class Suit < T::Enum +# enums do +# CLUB = new +# SPADE = new +# DIAMOND = new +# HEART = new +# end +# end +# +# @example Custom serialization value: +# class Status < T::Enum +# enums do +# READY = new('rdy') +# ... +# end +# end +# +# @example Accessing values: +# Suit::SPADE +# +# @example Converting from serialized value to enum instance: +# Suit.deserialize('club') == Suit::CLUB +# +# @example Using enums in type signatures: +# sig {params(suit: Suit).returns(Boolean)} +# def is_red?(suit); ...; end +# +# WARNING: Enum instances are singletons that are shared among all their users. Their internals +# should be kept immutable to avoid unpredictable action at a distance. +class T::Enum + extend T::Sig + extend T::Props::CustomType + + # TODO(jez) Might want to restrict this, or make subclasses provide this type + SerializedVal = T.type_alias {T.untyped} + private_constant :SerializedVal + + ### Enum class methods ### + sig {returns(T::Array[T.attached_class])} + def self.values + if @values.nil? + raise "Attempting to access values of #{self.class} before it has been initialized." \ + " Enums are not initialized until the 'enums do' block they are defined in has finished running." + end + @values + end + + # This exists for compatibility with the interface of `Hash` & mostly to support + # the HashEachMethods Rubocop. + sig {params(blk: T.nilable(T.proc.params(arg0: T.attached_class).void)).returns(T.any(T::Enumerator[T.attached_class], T::Array[T.attached_class]))} + def self.each_value(&blk) + if blk + values.each(&blk) + else + values.each + end + end + + # Convert from serialized value to enum instance + # + # Note: It would have been nice to make this method final before people started overriding it. + # Note: Failed CriticalMethodsNoRuntimeTypingTest + sig {params(serialized_val: SerializedVal).returns(T.nilable(T.attached_class)).checked(:never)} + def self.try_deserialize(serialized_val) + if @mapping.nil? + raise "Attempting to access serialization map of #{self.class} before it has been initialized." \ + " Enums are not initialized until the 'enums do' block they are defined in has finished running." + end + @mapping[serialized_val] + end + + # Convert from serialized value to enum instance. + # + # Note: It would have been nice to make this method final before people started overriding it. + # Note: Failed CriticalMethodsNoRuntimeTypingTest + # + # @return [self] + # @raise [KeyError] if serialized value does not match any instance. + sig {overridable.params(serialized_val: SerializedVal).returns(T.attached_class).checked(:never)} + def self.from_serialized(serialized_val) + res = try_deserialize(serialized_val) + if res.nil? + raise KeyError.new("Enum #{self} key not found: #{serialized_val.inspect}") + end + res + end + + # Note: It would have been nice to make this method final before people started overriding it. + # @return [Boolean] Does the given serialized value correspond with any of this enum's values. + sig {overridable.params(serialized_val: SerializedVal).returns(T::Boolean).checked(:never)} + def self.has_serialized?(serialized_val) + if @mapping.nil? + raise "Attempting to access serialization map of #{self.class} before it has been initialized." \ + " Enums are not initialized until the 'enums do' block they are defined in has finished running." + end + @mapping.include?(serialized_val) + end + + # Note: Failed CriticalMethodsNoRuntimeTypingTest + sig {override.params(instance: T.nilable(T::Enum)).returns(SerializedVal).checked(:never)} + def self.serialize(instance) + # This is needed otherwise if a Chalk::ODM::Document with a property of the shape + # T::Hash[T.nilable(MyEnum), Integer] and a value that looks like {nil => 0} is + # serialized, we throw the error on L102. + return nil if instance.nil? + + if self == T::Enum + raise "Cannot call T::Enum.serialize directly. You must call on a specific child class." + end + if instance.class != self + raise "Cannot call #serialize on a value that is not an instance of #{self}." + end + instance.serialize + end + + # Note: Failed CriticalMethodsNoRuntimeTypingTest + sig {override.params(mongo_value: SerializedVal).returns(T.attached_class).checked(:never)} + def self.deserialize(mongo_value) + if self == T::Enum + raise "Cannot call T::Enum.deserialize directly. You must call on a specific child class." + end + self.from_serialized(mongo_value) + end + + ### Enum instance methods ### + + sig {returns(T.self_type)} + def dup + self + end + + sig {returns(T.self_type).checked(:tests)} + def clone + self + end + + # Note: Failed CriticalMethodsNoRuntimeTypingTest + sig {returns(SerializedVal).checked(:never)} + def serialize + assert_bound! + @serialized_val + end + + sig {params(args: T.untyped).returns(T.untyped)} + def to_json(*args) + serialize.to_json(*args) + end + + sig {params(args: T.untyped).returns(T.untyped)} + def as_json(*args) + serialized_val = serialize + return serialized_val unless serialized_val.respond_to?(:as_json) + serialized_val.as_json(*args) + end + + sig {returns(String)} + def to_s + inspect + end + + sig {returns(String)} + def inspect + "#<#{self.class.name}::#{@const_name || '__UNINITIALIZED__'}>" + end + + sig {params(other: BasicObject).returns(T.nilable(Integer))} + def <=>(other) + case other + when self.class + self.serialize <=> other.serialize + else + nil + end + end + + # NB: Do not call this method. This exists to allow for a safe migration path in places where enum + # values are compared directly against string values. + # + # Ruby's string has a weird quirk where `'my_string' == obj` calls obj.==('my_string') if obj + # responds to the `to_str` method. It does not actually call `to_str` however. + # + # See https://ruby-doc.org/core-2.4.0/String.html#method-i-3D-3D + sig {returns(String)} + def to_str + msg = 'Implicit conversion of Enum instances to strings is not allowed. Call #serialize instead.' + if T::Configuration.legacy_t_enum_migration_mode? + T::Configuration.soft_assert_handler( + msg, + storytime: {class: self.class.name}, + ) + serialize.to_s + else + raise NoMethodError.new(msg) + end + end + + sig {params(other: BasicObject).returns(T::Boolean).checked(:never)} + def ==(other) + case other + when String + if T::Configuration.legacy_t_enum_migration_mode? + comparison_assertion_failed(:==, other) + self.serialize == other + else + false + end + else + super(other) + end + end + + sig {params(other: BasicObject).returns(T::Boolean).checked(:never)} + def ===(other) + case other + when String + if T::Configuration.legacy_t_enum_migration_mode? + comparison_assertion_failed(:===, other) + self.serialize == other + else + false + end + else + super(other) + end + end + + sig {params(method: Symbol, other: T.untyped).void} + private def comparison_assertion_failed(method, other) + T::Configuration.soft_assert_handler( + 'Enum to string comparison not allowed. Compare to the Enum instance directly instead. See go/enum-migration', + storytime: { + class: self.class.name, + self: self.inspect, + other: other, + other_class: other.class.name, + method: method, + } + ) + end + + ### Private implementation ### + + sig {params(serialized_val: SerializedVal).void} + def initialize(serialized_val=nil) + raise 'T::Enum is abstract' if self.class == T::Enum + if !self.class.started_initializing? + raise "Must instantiate all enum values of #{self.class} inside 'enums do'." + end + if self.class.fully_initialized? + raise "Cannot instantiate a new enum value of #{self.class} after it has been initialized." + end + + serialized_val = serialized_val.frozen? ? serialized_val : serialized_val.dup.freeze + @serialized_val = T.let(serialized_val, T.nilable(SerializedVal)) + @const_name = T.let(nil, T.nilable(Symbol)) + self.class._register_instance(self) + end + + sig {returns(NilClass).checked(:never)} + private def assert_bound! + if @const_name.nil? + raise "Attempting to access Enum value on #{self.class} before it has been initialized." \ + " Enums are not initialized until the 'enums do' block they are defined in has finished running." + end + end + + sig {params(const_name: Symbol).void} + def _bind_name(const_name) + @const_name = const_name + @serialized_val = const_to_serialized_val(const_name) if @serialized_val.nil? + freeze + end + + sig {params(const_name: Symbol).returns(String)} + private def const_to_serialized_val(const_name) + # Historical note: We convert to lowercase names because the majority of existing calls to + # `make_accessible` were arrays of lowercase strings. Doing this conversion allowed for the + # least amount of repetition in migrated declarations. + -const_name.to_s.downcase.freeze + end + + sig {returns(T::Boolean)} + def self.started_initializing? + unless defined?(@started_initializing) + @started_initializing = T.let(false, T.nilable(T::Boolean)) + end + T.must(@started_initializing) + end + + sig {returns(T::Boolean)} + def self.fully_initialized? + unless defined?(@fully_initialized) + @fully_initialized = T.let(false, T.nilable(T::Boolean)) + end + T.must(@fully_initialized) + end + + # Maintains the order in which values are defined + sig {params(instance: T.untyped).void} + def self._register_instance(instance) + @values ||= [] + @values << T.cast(instance, T.attached_class) + end + + # Entrypoint for allowing people to register new enum values. + # All enum values must be defined within this block. + sig {params(blk: T.proc.void).void} + def self.enums(&blk) + raise "enums cannot be defined for T::Enum" if self == T::Enum + raise "Enum #{self} was already initialized" if fully_initialized? + raise "Enum #{self} is still initializing" if started_initializing? + + @started_initializing = true + + @values = T.let(nil, T.nilable(T::Array[T.attached_class])) + + yield + + @mapping = T.let(nil, T.nilable(T::Hash[SerializedVal, T.attached_class])) + @mapping = {} + + # Freeze the Enum class and bind the constant names into each of the instances. + self.constants(false).each do |const_name| + instance = self.const_get(const_name, false) + if !instance.is_a?(self) + raise "Invalid constant #{self}::#{const_name} on enum. " \ + "All constants defined for an enum must be instances itself (e.g. `Foo = new`)." + end + + instance._bind_name(const_name) + serialized = instance.serialize + if @mapping.include?(serialized) + raise "Enum values must have unique serializations. Value '#{serialized}' is repeated on #{self}." + end + @mapping[serialized] = instance + end + @values.freeze + @mapping.freeze + + orphaned_instances = T.must(@values) - @mapping.values + if !orphaned_instances.empty? + raise "Enum values must be assigned to constants: #{orphaned_instances.map {|v| v.instance_variable_get('@serialized_val')}}" + end + + @fully_initialized = true + end + + sig {params(child_class: Module).void} + def self.inherited(child_class) + super + + raise "Inheriting from children of T::Enum is prohibited" if self != T::Enum + end + + # Marshal support + sig {params(_level: Integer).returns(String)} + def _dump(_level) + Marshal.dump(serialize) + end + + sig {params(args: String).returns(T.attached_class)} + def self._load(args) + deserialize(Marshal.load(args)) # rubocop:disable Security/MarshalLoad + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/generic.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/generic.rb new file mode 100644 index 0000000000..58def7aa1a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/generic.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# typed: true + +# Use as a mixin with extend (`extend T::Generic`). +module T::Generic + include T::Helpers + include Kernel + + ### Class/Module Helpers ### + + def [](*types) + self + end + + def type_member(variance=:invariant, &blk) + T::Types::TypeMember.new(variance) + end + + def type_template(variance=:invariant, &blk) + T::Types::TypeTemplate.new(variance) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/helpers.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/helpers.rb new file mode 100644 index 0000000000..7f326e7384 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/helpers.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true +# typed: true + +# Use as a mixin with extend (`extend T::Helpers`). +# Docs at https://sorbet.org/docs/ +module T::Helpers + extend T::Sig + + Private = T::Private + + ### Class/Module Helpers ### + + def abstract! + Private::Abstract::Declare.declare_abstract(self, type: :abstract) + end + + def interface! + Private::Abstract::Declare.declare_abstract(self, type: :interface) + end + + def final! + Private::Final.declare(self) + end + + def sealed! + Private::Sealed.declare(self, Kernel.caller(1..1)&.first&.split(':')&.first) + end + + # Causes a mixin to also mix in class methods from the named module. + # + # Nearly equivalent to + # + # def self.included(other) + # other.extend(mod) + # end + # + # Except that it is statically analyzed by sorbet. + def mixes_in_class_methods(mod, *mods) + Private::Mixins.declare_mixes_in_class_methods(self, [mod].concat(mods)) + end + + # Specify an inclusion or inheritance requirement for `self`. + # + # Example: + # + # module MyHelper + # extend T::Helpers + # + # requires_ancestor { Kernel } + # end + # + # class MyClass < BasicObject # error: `MyClass` must include `Kernel` (required by `MyHelper`) + # include MyHelper + # end + # + # TODO: implement the checks in sorbet-runtime. + def requires_ancestor(&block); end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/interface_wrapper.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/interface_wrapper.rb new file mode 100644 index 0000000000..82998667f7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/interface_wrapper.rb @@ -0,0 +1,158 @@ +# frozen_string_literal: true +# typed: false + +# Wraps an object, exposing only the methods defined on a given class/module. The idea is that, in +# the absence of a static type checker that would prevent you from calling non-Bar methods on a +# variable of type Bar, we can use these wrappers as a way of enforcing it at runtime. +# +# Once we ship static type checking, we should get rid of this entirely. +class T::InterfaceWrapper + extend T::Sig + + module Helpers + def wrap_instance(obj) + T::InterfaceWrapper.wrap_instance(obj, self) + end + + def wrap_instances(arr) + T::InterfaceWrapper.wrap_instances(arr, self) + end + end + + private_class_method :new # use `wrap_instance` + + def self.wrap_instance(obj, interface_mod) + wrapper = wrapped_dynamic_cast(obj, interface_mod) + if wrapper.nil? + raise "#{obj.class} cannot be cast to #{interface_mod}" + end + wrapper + end + + sig do + params( + arr: Array, + interface_mod: T.untyped + ) + .returns(Array) + end + def self.wrap_instances(arr, interface_mod) + arr.map {|instance| self.wrap_instance(instance, interface_mod)} + end + + def initialize(target_obj, interface_mod) + if target_obj.is_a?(T::InterfaceWrapper) + # wrapped_dynamic_cast should guarantee this never happens. + raise "Unexpected: wrapping a wrapper. Please report this bug at https://github.com/sorbet/sorbet/issues" + end + + if !target_obj.is_a?(interface_mod) + # wrapped_dynamic_cast should guarantee this never happens. + raise "Unexpected: `is_a?` failed. Please report this bug at https://github.com/sorbet/sorbet/issues" + end + + if target_obj.class == interface_mod + # wrapped_dynamic_cast should guarantee this never happens. + raise "Unexpected: exact class match. Please report this bug at https://github.com/sorbet/sorbet/issues" + end + + @target_obj = target_obj + @interface_mod = interface_mod + self_methods = self.class.self_methods + + # If perf becomes an issue, we can define these on an anonymous subclass, and keep a cache + # so we only need to do it once per unique `interface_mod` + T::Utils.methods_excluding_object(interface_mod).each do |method_name| + if self_methods.include?(method_name) + raise "interface_mod has a method that conflicts with #{self.class}: #{method_name}" + end + + define_singleton_method(method_name) do |*args, &blk| + target_obj.send(method_name, *args, &blk) + end + + if target_obj.singleton_class.public_method_defined?(method_name) + # no-op, it's already public + elsif target_obj.singleton_class.protected_method_defined?(method_name) + singleton_class.send(:protected, method_name) + elsif target_obj.singleton_class.private_method_defined?(method_name) + singleton_class.send(:private, method_name) + else + raise "This should never happen. Report this bug at https://github.com/sorbet/sorbet/issues" + end + end + end + + def kind_of?(other) + is_a?(other) + end + + def is_a?(other) + if !other.is_a?(Module) + raise TypeError.new("class or module required") + end + + # This makes is_a? return true for T::InterfaceWrapper (and its ancestors), + # as well as for @interface_mod and its ancestors. + self.class <= other || @interface_mod <= other + end + + # Prefixed because we're polluting the namespace of the interface we're wrapping, and we don't + # want anyone else (besides dynamic_cast) calling it. + def __target_obj_DO_NOT_USE # rubocop:disable Naming/MethodName + @target_obj + end + + # Prefixed because we're polluting the namespace of the interface we're wrapping, and we don't + # want anyone else (besides wrapped_dynamic_cast) calling it. + def __interface_mod_DO_NOT_USE # rubocop:disable Naming/MethodName + @interface_mod + end + + # "Cast" an object to another type. If `obj` is an InterfaceWrapper, returns the the wrapped + # object if that matches `type`. Otherwise, returns `obj` if it matches `type`. Otherwise, + # returns nil. + # + # @param obj [Object] object to cast + # @param mod [Module] type to cast `obj` to + # + # @example + # if (impl = T::InterfaceWrapper.dynamic_cast(iface, MyImplementation)) + # impl.do_things + # end + def self.dynamic_cast(obj, mod) + if obj.is_a?(T::InterfaceWrapper) + target_obj = obj.__target_obj_DO_NOT_USE + target_obj.is_a?(mod) ? target_obj : nil + elsif obj.is_a?(mod) + obj + else + nil + end + end + + # Like dynamic_cast, but puts the result in its own wrapper if necessary. + # + # @param obj [Object] object to cast + # @param mod [Module] type to cast `obj` to + def self.wrapped_dynamic_cast(obj, mod) + # Avoid unwrapping and creating an equivalent wrapper. + if obj.is_a?(T::InterfaceWrapper) && obj.__interface_mod_DO_NOT_USE == mod + return obj + end + + cast_obj = dynamic_cast(obj, mod) + if cast_obj.nil? + nil + elsif cast_obj.class == mod + # Nothing to wrap, they want the full class + cast_obj + else + new(cast_obj, mod) + end + end + + def self.self_methods + @self_methods ||= self.instance_methods(false).to_set + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/non_forcing_constants.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/non_forcing_constants.rb new file mode 100644 index 0000000000..96445357cb --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/non_forcing_constants.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true +# typed: strict + +module T::NonForcingConstants + # NOTE: This method is documented on the RBI in Sorbet's payload, so that it + # shows up in the hover/completion documentation via LSP. + T::Sig::WithoutRuntime.sig {params(val: BasicObject, klass: String, package: T.nilable(String)).returns(T::Boolean)} + def self.non_forcing_is_a?(val, klass, package: nil) + method_name = "T::NonForcingConstants.non_forcing_is_a?" + if klass.empty? + raise ArgumentError.new("The string given to `#{method_name}` must not be empty") + end + + # We don't treat packages differently at runtime, but the static + # type-checker still needs to have the package and constant + # separated out. This just re-assembles the string as needed + if !package.nil? + klass = "::#{package}::#{klass}" + end + + current_klass = T.let(nil, T.nilable(Module)) + current_prefix = T.let(nil, T.nilable(String)) + + parts = klass.split('::') + parts.each do |part| + if current_klass.nil? + # First iteration + if part != "" && package.nil? + # if we've supplied a package, we're probably running in + # package mode, which means absolute references are + # meaningless + raise ArgumentError.new("The string given to `#{method_name}` must be an absolute constant reference that starts with `::`") + end + + current_klass = Object + current_prefix = '' + + # if this had a :: prefix, then there's no more loading to + # do---skip to the next one + next if part == "" + end + + if current_klass.autoload?(part) + # There's an autoload registered for that constant, which means it's not + # yet loaded. `value` can't be an instance of something not yet loaded. + return false + end + + # Sorbet guarantees that the string is an absolutely resolved name. + search_inheritance_chain = false + if !current_klass.const_defined?(part, search_inheritance_chain) + return false + end + + current_klass = current_klass.const_get(part) + current_prefix = "#{current_prefix}::#{part}" + + if !Module.===(current_klass) + raise ArgumentError.new("#{current_prefix} is not a class or module") + end + end + + current_klass.===(val) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/data.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/data.rb new file mode 100644 index 0000000000..2692858ddf --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/data.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true +# typed: true + +# We need to associate data with abstract modules. We could add instance methods to them that +# access ivars, but those methods will unnecessarily pollute the module namespace, and they'd +# have access to other private state and methods that they don't actually need. We also need to +# associate data with arbitrary classes/modules that implement abstract mixins, where we don't +# control the interface at all. So, we access data via these `get` and `set` methods. +# +# Using instance_variable_get/set here is gross, but the alternative is to use a hash keyed on +# `mod`, and we can't trust that arbitrary modules can be added to those, because there are lurky +# modules that override the `hash` method with something completely broken. +module T::Private::Abstract::Data + def self.get(mod, key) + mod.instance_variable_get("@opus_abstract__#{key}") if key?(mod, key) + end + + def self.set(mod, key, value) + mod.instance_variable_set("@opus_abstract__#{key}", value) + end + + def self.key?(mod, key) + mod.instance_variable_defined?("@opus_abstract__#{key}") + end + + # Works like `setdefault` in Python. If key has already been set, return its value. If not, + # insert `key` with a value of `default` and return `default`. + def self.set_default(mod, key, default) + if self.key?(mod, key) + self.get(mod, key) + else + self.set(mod, key, default) + default + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/declare.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/declare.rb new file mode 100644 index 0000000000..ce8ddf9531 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/declare.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true +# typed: true + +module T::Private::Abstract::Declare + Abstract = T::Private::Abstract + AbstractUtils = T::AbstractUtils + + def self.declare_abstract(mod, type:) + if AbstractUtils.abstract_module?(mod) + raise "#{mod} is already declared as abstract" + end + if T::Private::Final.final_module?(mod) + raise "#{mod} was already declared as final and cannot be declared as abstract" + end + + Abstract::Data.set(mod, :can_have_abstract_methods, true) + Abstract::Data.set(mod.singleton_class, :can_have_abstract_methods, true) + Abstract::Data.set(mod, :abstract_type, type) + + mod.extend(Abstract::Hooks) + mod.extend(T::InterfaceWrapper::Helpers) + + if mod.is_a?(Class) + if type == :interface + # Since `interface!` is just `abstract!` with some extra validation, we could technically + # allow this, but it's unclear there are good use cases, and it might be confusing. + raise "Classes can't be interfaces. Use `abstract!` instead of `interface!`." + end + + if mod.instance_method(:initialize).owner == mod + raise "You must call `abstract!` *before* defining an initialize method" + end + + # Don't need to silence warnings via without_ruby_warnings when calling + # define_method because of the guard above + + mod.send(:define_method, :initialize) do |*args, &blk| + if self.class == mod + raise "#{mod} is declared as abstract; it cannot be instantiated" + end + super(*args, &blk) + end + + # Ruby doesn not emit "method redefined" warnings for aliased methods + # (more robust than undef_method that would create a small window in which the method doesn't exist) + mod.send(:alias_method, :initialize, :initialize) + + if mod.respond_to?(:ruby2_keywords, true) + mod.send(:ruby2_keywords, :initialize) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/hooks.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/hooks.rb new file mode 100644 index 0000000000..fae9593ae8 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/hooks.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true +# typed: true + +module T::Private::Abstract::Hooks + # This will become the self.extend_object method on a module that extends Abstract::Hooks. + # It gets called when *that* module gets extended in another class/module (similar to the + # `extended` hook, but this gets calls before the ancestors of `other` get modified, which + # is important for our validation). + private def extend_object(other) + T::Private::Abstract::Data.set(self, :last_used_by, other) + super + end + + # This will become the self.append_features method on a module that extends Abstract::Hooks. + # It gets called when *that* module gets included in another class/module (similar to the + # `included` hook, but this gets calls before the ancestors of `other` get modified, which + # is important for our validation). + private def append_features(other) + T::Private::Abstract::Data.set(self, :last_used_by, other) + super + end + + # This will become the self.inherited method on a class that extends Abstract::Hooks. + # It gets called when *that* class gets inherited by another class. + private def inherited(other) + super + # `self` may not actually be abstract -- it could be a concrete class that inherited from an + # abstract class. We only need to check this in `inherited` because, for modules being included + # or extended, the concrete ones won't have these hooks at all. This is just an optimization. + return if !T::AbstractUtils.abstract_module?(self) + + T::Private::Abstract::Data.set(self, :last_used_by, other) + end + + # This will become the self.prepended method on a module that extends Abstract::Hooks. + # It will get called when *that* module gets prepended in another class/module. + private def prepended(other) + # Prepending abstract methods is weird. You'd only be able to override them via other prepended + # modules, or in subclasses. Punt until we have a use case. + Kernel.raise "Prepending abstract mixins is not currently supported." + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/validate.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/validate.rb new file mode 100644 index 0000000000..ba0b57775c --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/abstract/validate.rb @@ -0,0 +1,128 @@ +# frozen_string_literal: true +# typed: true + +module T::Private::Abstract::Validate + Abstract = T::Private::Abstract + AbstractUtils = T::AbstractUtils + Methods = T::Private::Methods + SignatureValidation = T::Private::Methods::SignatureValidation + + def self.validate_abstract_module(mod) + type = Abstract::Data.get(mod, :abstract_type) + validate_interface(mod) if type == :interface + end + + # Validates a class/module with an abstract class/module as an ancestor. This must be called + # after all methods on `mod` have been defined. + def self.validate_subclass(mod) + can_have_abstract_methods = !T::Private::Abstract::Data.get(mod, :can_have_abstract_methods) + unimplemented_methods = [] + + T::AbstractUtils.declared_abstract_methods_for(mod).each do |abstract_method| + implementation_method = mod.instance_method(abstract_method.name) + if AbstractUtils.abstract_method?(implementation_method) + # Note that when we end up here, implementation_method might not be the same as + # abstract_method; the latter could've been overridden by another abstract method. In either + # case, if we have a concrete definition in an ancestor, that will end up as the effective + # implementation (see CallValidation.wrap_method_if_needed), so that's what we'll validate + # against. + implementation_method = T.unsafe(nil) + mod.ancestors.each do |ancestor| + if ancestor.instance_methods.include?(abstract_method.name) + method = ancestor.instance_method(abstract_method.name) + T::Private::Methods.maybe_run_sig_block_for_method(method) + if !T::AbstractUtils.abstract_method?(method) + implementation_method = method + break + end + end + end + if !implementation_method + # There's no implementation + if can_have_abstract_methods + unimplemented_methods << describe_method(abstract_method) + end + next # Nothing to validate + end + end + + implementation_signature = Methods.signature_for_method(implementation_method) + # When a signature exists and the method is defined directly on `mod`, we skip the validation + # here, because it will have already been done when the method was defined (by + # T::Private::Methods._on_method_added). + next if implementation_signature&.owner == mod + + # We validate the remaining cases here: (a) methods defined directly on `mod` without a + # signature and (b) methods from ancestors (note that these ancestors can come before or + # after the abstract module in the inheritance chain -- the former coming from + # walking `mod.ancestors` above). + abstract_signature = Methods.signature_for_method(abstract_method) + # We allow implementation methods to be defined without a signature. + # In that case, get its untyped signature. + implementation_signature ||= Methods::Signature.new_untyped( + method: implementation_method, + mode: Methods::Modes.override + ) + SignatureValidation.validate_override_shape(implementation_signature, abstract_signature) + SignatureValidation.validate_override_types(implementation_signature, abstract_signature) + end + + method_type = mod.singleton_class? ? "class" : "instance" + if !unimplemented_methods.empty? + raise "Missing implementation for abstract #{method_type} method(s) in #{mod}:\n" \ + "#{unimplemented_methods.join("\n")}\n" \ + "If #{mod} is meant to be an abstract class/module, you can call " \ + "`abstract!` or `interface!`. Otherwise, you must implement the method(s)." + end + end + + private_class_method def self.validate_interface_all_abstract(mod, method_names) + violations = method_names.map do |method_name| + method = mod.instance_method(method_name) + if !AbstractUtils.abstract_method?(method) + describe_method(method, show_owner: false) + end + end.compact + + if !violations.empty? + raise "`#{mod}` is declared as an interface, but the following methods are not declared " \ + "with `abstract`:\n#{violations.join("\n")}" + end + end + + private_class_method def self.validate_interface(mod) + interface_methods = T::Utils.methods_excluding_object(mod) + validate_interface_all_abstract(mod, interface_methods) + validate_interface_all_public(mod, interface_methods) + end + + private_class_method def self.validate_interface_all_public(mod, method_names) + violations = method_names.map do |method_name| + if !mod.public_method_defined?(method_name) + describe_method(mod.instance_method(method_name), show_owner: false) + end + end.compact + + if !violations.empty? + raise "All methods on an interface must be public. If you intend to have non-public " \ + "methods, declare your class/module using `abstract!` instead of `interface!`. " \ + "The following methods on `#{mod}` are not public: \n#{violations.join("\n")}" + end + end + + private_class_method def self.describe_method(method, show_owner: true) + loc = if method.source_location + method.source_location.join(':') + else + "" + end + + owner = if show_owner + " declared in #{method.owner}" + else + "" + end + + " * `#{method.name}`#{owner} at #{loc}" + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/casts.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/casts.rb new file mode 100644 index 0000000000..f771090814 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/casts.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +# typed: false + +module T::Private + module Casts + def self.cast(value, type, cast_method:) + begin + error = T::Utils.coerce(type).error_message_for_obj(value) + return value unless error + + caller_loc = T.must(caller_locations(2..2)).first + + suffix = "Caller: #{T.must(caller_loc).path}:#{T.must(caller_loc).lineno}" + + raise TypeError.new("#{cast_method}: #{error}\n#{suffix}") + rescue TypeError => e # raise into rescue to ensure e.backtrace is populated + T::Configuration.inline_type_error_handler(e, {kind: cast_method, value: value, type: type}) + value + end + end + + # there's a lot of shared logic with the above one, but factoring + # it out like this makes it easier to hopefully one day delete + # this one + def self.cast_recursive(value, type, cast_method:) + begin + error = T::Utils.coerce(type).error_message_for_obj_recursive(value) + return value unless error + + caller_loc = T.must(caller_locations(2..2)).first + + suffix = "Caller: #{T.must(caller_loc).path}:#{T.must(caller_loc).lineno}" + + raise TypeError.new("#{cast_method}: #{error}\n#{suffix}") + rescue TypeError => e # raise into rescue to ensure e.backtrace is populated + T::Configuration.inline_type_error_handler(e, {kind: cast_method, value: value, type: type}) + value + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/class_utils.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/class_utils.rb new file mode 100644 index 0000000000..269b70cbee --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/class_utils.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true +# typed: false + +# Cut down version of Chalk::Tools::ClassUtils with only :replace_method functionality. +# Extracted to a separate namespace so the type system can be used standalone. +module T::Private::ClassUtils + class ReplacedMethod + def initialize(mod, old_method, new_method, overwritten, visibility) + if old_method.name != new_method.name + raise "Method names must match. old=#{old_method.name} new=#{new_method.name}" + end + @mod = mod + @old_method = old_method + @new_method = new_method + @overwritten = overwritten + @name = old_method.name + @visibility = visibility + @restored = false + end + + def restore + # The check below would also catch this, but this makes the failure mode much clearer + if @restored + raise "Method '#{@name}' on '#{@mod}' was already restored" + end + + if @mod.instance_method(@name) != @new_method + raise "Trying to restore #{@mod}##{@name} but the method has changed since the call to replace_method" + end + + @restored = true + + if @overwritten + # The original method was overwritten. Overwrite again to restore it. + T::Configuration.without_ruby_warnings do + @mod.send(:define_method, @old_method.name, @old_method) + end + else + # The original method was in an ancestor. Restore it by removing the overriding method. + @mod.send(:remove_method, @old_method.name) + end + + # Restore the visibility. Note that we need to do this even when we call remove_method + # above, because the module may have set custom visibility for a method it inherited. + @mod.send(@visibility, @old_method.name) + + nil + end + + def bind(obj) + @old_method.bind(obj) + end + + def to_s + @old_method.to_s + end + end + + # `name` must be an instance method (for class methods, pass in mod.singleton_class) + private_class_method def self.visibility_method_name(mod, name) + if mod.public_method_defined?(name) + :public + elsif mod.protected_method_defined?(name) + :protected + elsif mod.private_method_defined?(name) + :private + else + raise NameError.new("undefined method `#{name}` for `#{mod}`") + end + end + + # Replaces a method, either by overwriting it (if it is defined directly on `mod`) or by + # overriding it (if it is defined by one of mod's ancestors). Returns a ReplacedMethod instance + # on which you can call `bind(...).call(...)` to call the original method, or `restore` to + # restore the original method (by overwriting or removing the override). + def self.replace_method(mod, name, &blk) + original_method = mod.instance_method(name) + original_visibility = visibility_method_name(mod, name) + original_owner = original_method.owner + + mod.ancestors.each do |ancestor| + break if ancestor == mod + if ancestor == original_owner + # If we get here, that means the method we're trying to replace exists on a *prepended* + # mixin, which means in order to supersede it, we'd need to create a method on a new + # module that we'd prepend before `ancestor`. The problem with that approach is there'd + # be no way to remove that new module after prepending it, so we'd be left with these + # empty anonymous modules in the ancestor chain after calling `restore`. + # + # That's not necessarily a deal breaker, but for now, we're keeping it as unsupported. + raise "You're trying to replace `#{name}` on `#{mod}`, but that method exists in a " \ + "prepended module (#{ancestor}), which we don't currently support." + end + end + + overwritten = original_owner == mod + T::Configuration.without_ruby_warnings do + T::Private::DeclState.current.without_on_method_added do + mod.send(:define_method, name, &blk) + if blk.arity < 0 && mod.respond_to?(:ruby2_keywords, true) + mod.send(:ruby2_keywords, name) + end + end + end + mod.send(original_visibility, name) + new_method = mod.instance_method(name) + + ReplacedMethod.new(mod, original_method, new_method, overwritten, original_visibility) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/compiler.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/compiler.rb new file mode 100644 index 0000000000..fed86b40f3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/compiler.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# typed: true + +module T::Private + module Compiler + # If this code ever runs, the caller is running interpreted (or the + # compiler didn't see the call to `running_compiled?` statically.) + # + # The Sorbet Compiler replaces calls to this method unconditionally (no + # runtime guards) to return `true` when compiling a file. + def self.running_compiled? + false + end + + # Returns `nil` because the compiler isn't running. + # + # The Sorbet Compiler replaces calls to this method unconditionally (no + # runtime guards) to return a String showing the Sorbet Compiler's version + # string. + def self.compiler_version + nil + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/decl_state.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/decl_state.rb new file mode 100644 index 0000000000..8eeae57e4c --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/decl_state.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# typed: true + +class T::Private::DeclState + def self.current + Thread.current[:opus_types__decl_state] ||= self.new + end + + def self.current=(other) + Thread.current[:opus_types__decl_state] = other + end + + attr_accessor :active_declaration + attr_accessor :skip_on_method_added + + def reset! + self.active_declaration = nil + end + + def without_on_method_added + begin + # explicit 'self' is needed here + old_value = self.skip_on_method_added + self.skip_on_method_added = true + yield + ensure + self.skip_on_method_added = old_value + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/final.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/final.rb new file mode 100644 index 0000000000..9ca747248e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/final.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true +# typed: false + +module T::Private::Final + module NoInherit + def inherited(arg) + super(arg) + raise "#{self} was declared as final and cannot be inherited" + end + end + + module NoIncludeExtend + def included(arg) + super(arg) + raise "#{self} was declared as final and cannot be included" + end + + def extended(arg) + super(arg) + raise "#{self} was declared as final and cannot be extended" + end + end + + def self.declare(mod) + if !mod.is_a?(Module) + raise "#{mod} is not a class or module and cannot be declared as final with `final!`" + end + if final_module?(mod) + raise "#{mod} was already declared as final and cannot be re-declared as final" + end + if T::AbstractUtils.abstract_module?(mod) + raise "#{mod} was already declared as abstract and cannot be declared as final" + end + if T::Private::Sealed.sealed_module?(mod) + raise "#{mod} was already declared as sealed and cannot be declared as final" + end + mod.extend(mod.is_a?(Class) ? NoInherit : NoIncludeExtend) + mark_as_final_module(mod) + mark_as_final_module(mod.singleton_class) + T::Private::Methods.install_hooks(mod) + end + + def self.final_module?(mod) + mod.instance_variable_defined?(:@sorbet_final_module) + end + + private_class_method def self.mark_as_final_module(mod) + mod.instance_variable_set(:@sorbet_final_module, true) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/_methods.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/_methods.rb new file mode 100644 index 0000000000..1720892a95 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/_methods.rb @@ -0,0 +1,581 @@ +# frozen_string_literal: true +# typed: false + +module T::Private::Methods + @installed_hooks = {} + @signatures_by_method = {} + @sig_wrappers = {} + @sigs_that_raised = {} + # stores method names that were declared final without regard for where. + # enables early rejection of names that we know can't induce final method violations. + @was_ever_final_names = {} + # maps from a module's object_id to the set of final methods declared in that module. + # we also overload entries slightly: if the value is nil, that means that the + # module has final methods somewhere along its ancestor chain, but does not itself + # have any final methods. + # + # we need the latter information to know whether we need to check along the ancestor + # chain for final method violations. we need the former information because we + # care about exactly where a final method is defined (e.g. including the same module + # twice is permitted). we could do this with two tables, but it seems slightly + # cleaner with a single table. + # Effectively T::Hash[Module, T.nilable(Set))] + @modules_with_final = Hash.new {|hash, key| hash[key] = nil} + # this stores the old [included, extended] hooks for Module and inherited hook for Class that we override when + # enabling final checks for when those hooks are called. the 'hooks' here don't have anything to do with the 'hooks' + # in installed_hooks. + @old_hooks = nil + + ARG_NOT_PROVIDED = Object.new + PROC_TYPE = Object.new + + DeclarationBlock = Struct.new(:mod, :loc, :blk, :final, :raw) + + def self.declare_sig(mod, loc, arg, &blk) + T::Private::DeclState.current.active_declaration = _declare_sig_internal(mod, loc, arg, &blk) + + nil + end + + # See tests for how to use this. But you shouldn't be using this. + def self._declare_sig(mod, arg=nil, &blk) + _declare_sig_internal(mod, caller_locations(1, 1).first, arg, raw: true, &blk) + end + + private_class_method def self._declare_sig_internal(mod, loc, arg, raw: false, &blk) + install_hooks(mod) + + if T::Private::DeclState.current.active_declaration + T::Private::DeclState.current.reset! + raise "You called sig twice without declaring a method in between" + end + + if !arg.nil? && arg != :final + raise "Invalid argument to `sig`: #{arg}" + end + + DeclarationBlock.new(mod, loc, blk, arg == :final, raw) + end + + def self._with_declared_signature(mod, declblock, &blk) + # If declblock is provided, this code is equivalent to the check in + # _declare_sig_internal, above. + # If declblock is not provided and we have an active declaration, we are + # obviously doing something wrong. + if T::Private::DeclState.current.active_declaration + T::Private::DeclState.current.reset! + raise "You called sig twice without declaring a method in between" + end + if declblock + T::Private::DeclState.current.active_declaration = declblock + end + mod.module_exec(&blk) + end + + def self.start_proc + DeclBuilder.new(PROC_TYPE, false) + end + + def self.finalize_proc(decl) + decl.finalized = true + + if decl.mode != Modes.standard + raise "Procs cannot have override/abstract modifiers" + end + if decl.mod != PROC_TYPE + raise "You are passing a DeclBuilder as a type. Did you accidentally use `self` inside a `sig` block?" + end + if decl.returns == ARG_NOT_PROVIDED + raise "Procs must specify a return type" + end + if decl.on_failure != ARG_NOT_PROVIDED + raise "Procs cannot use .on_failure" + end + + if decl.params == ARG_NOT_PROVIDED + decl.params = {} + end + + T::Types::Proc.new(decl.params, decl.returns) + end + + # Returns the signature for a method whose definition was preceded by `sig`. + # + # @param method [UnboundMethod] + # @return [T::Private::Methods::Signature] + def self.signature_for_method(method) + signature_for_key(method_to_key(method)) + end + + private_class_method def self.signature_for_key(key) + maybe_run_sig_block_for_key(key) + + # If a subclass Sub inherits a method `foo` from Base, then + # Sub.instance_method(:foo) != Base.instance_method(:foo) even though they resolve to the + # same method. Similarly, Foo.method(:bar) != Foo.singleton_class.instance_method(:bar). + # So, we always do the look up by the method on the owner (Base in this example). + @signatures_by_method[key] + end + + # when target includes a module with instance methods source_method_names, ensure there is zero intersection between + # the final instance methods of target and source_method_names. so, for every m in source_method_names, check if there + # is already a method defined on one of target_ancestors with the same name that is final. + # + # we assume that source_method_names has already been filtered to only include method + # names that were declared final at one point. + def self._check_final_ancestors(target, target_ancestors, source_method_names, source) + source_ancestors = nil + # use reverse_each to check farther-up ancestors first, for better error messages. + target_ancestors.reverse_each do |ancestor| + final_methods = @modules_with_final.fetch(ancestor.object_id, nil) + # In this case, either ancestor didn't have any final methods anywhere in its + # ancestor chain, or ancestor did have final methods somewhere in its ancestor + # chain, but no final methods defined in ancestor itself. Either way, there + # are no final methods to check here, so we can move on to the next ancestor. + next unless final_methods + source_method_names.each do |method_name| + next unless final_methods.include?(method_name) + + # If we get here, we are defining a method that some ancestor declared as + # final. however, we permit a final method to be defined multiple + # times if it is the same final method being defined each time. + if source + if !source_ancestors + source_ancestors = source.ancestors + # filter out things without actual final methods just to make sure that + # the below checks (which should be uncommon) go as quickly as possible. + source_ancestors.select! do |a| + @modules_with_final.fetch(a.object_id, nil) + end + end + # final-ness means that there should be no more than one index for which + # the below block returns true. + defining_ancestor_idx = source_ancestors.index do |a| + @modules_with_final.fetch(a.object_id).include?(method_name) + end + next if defining_ancestor_idx && source_ancestors[defining_ancestor_idx] == ancestor + end + + definition_file, definition_line = T::Private::Methods.signature_for_method(ancestor.instance_method(method_name)).method.source_location + is_redefined = target == ancestor + caller_loc = caller_locations&.find {|l| !l.to_s.match?(%r{sorbet-runtime[^/]*/lib/})} + extra_info = "\n" + if caller_loc + extra_info = (is_redefined ? "Redefined" : "Overridden") + " here: #{caller_loc.path}:#{caller_loc.lineno}\n" + end + + error_message = "The method `#{method_name}` on #{ancestor} was declared as final and cannot be " + + (is_redefined ? "redefined" : "overridden in #{target}") + pretty_message = "#{error_message}\n" \ + "Made final here: #{definition_file}:#{definition_line}\n" \ + "#{extra_info}" + + begin + raise pretty_message + rescue => e + # sig_validation_error_handler raises by default; on the off chance that + # it doesn't raise, we need to ensure that the rest of signature building + # sees a consistent state. This sig failed to validate, so we should get + # rid of it. If we don't do this, errors of the form "You called sig + # twice without declaring a method in between" will non-deterministically + # crop up in tests. + T::Private::DeclState.current.reset! + T::Configuration.sig_validation_error_handler(e, {}) + end + end + end + end + + def self.add_module_with_final_method(mod, method_name, is_singleton_method) + m = is_singleton_method ? mod.singleton_class : mod + mid = m.object_id + methods = @modules_with_final[mid] + if methods.nil? + methods = {} + @modules_with_final[mid] = methods + end + methods[method_name] = true + nil + end + + def self.note_module_deals_with_final(mod) + # Side-effectfully initialize the value if it's not already there + @modules_with_final[mod.object_id] + @modules_with_final[mod.singleton_class.object_id] + end + + # Only public because it needs to get called below inside the replace_method blocks below. + def self._on_method_added(hook_mod, method_name, is_singleton_method: false) + if T::Private::DeclState.current.skip_on_method_added + return + end + + current_declaration = T::Private::DeclState.current.active_declaration + mod = is_singleton_method ? hook_mod.singleton_class : hook_mod + + if T::Private::Final.final_module?(mod) && (current_declaration.nil? || !current_declaration.final) + raise "#{mod} was declared as final but its method `#{method_name}` was not declared as final" + end + # Don't compute mod.ancestors if we don't need to bother checking final-ness. + if @was_ever_final_names.include?(method_name) && @modules_with_final.include?(mod.object_id) + _check_final_ancestors(mod, mod.ancestors, [method_name], nil) + # We need to fetch the active declaration again, as _check_final_ancestors + # may have reset it (see the comment in that method for details). + current_declaration = T::Private::DeclState.current.active_declaration + end + + if current_declaration.nil? + return + end + T::Private::DeclState.current.reset! + + if method_name == :method_added || method_name == :singleton_method_added + raise( + "Putting a `sig` on `#{method_name}` is not supported" \ + " (sorbet-runtime uses this method internally to perform `sig` validation logic)" + ) + end + + original_method = mod.instance_method(method_name) + sig_block = lambda do + T::Private::Methods.run_sig(hook_mod, method_name, original_method, current_declaration) + end + + # Always replace the original method with this wrapper, + # which is called only on the *first* invocation. + # This wrapper is very slow, so it will subsequently re-wrap with a much faster wrapper + # (or unwrap back to the original method). + key = method_owner_and_name_to_key(mod, method_name) + unless current_declaration.raw + T::Private::ClassUtils.replace_method(mod, method_name) do |*args, &blk| + method_sig = T::Private::Methods.maybe_run_sig_block_for_key(key) + method_sig ||= T::Private::Methods._handle_missing_method_signature( + self, + original_method, + __callee__, + ) + + # Should be the same logic as CallValidation.wrap_method_if_needed but we + # don't want that extra layer of indirection in the callstack + if method_sig.mode == T::Private::Methods::Modes.abstract + # We're in an interface method, keep going up the chain + if defined?(super) + super(*args, &blk) + else + raise NotImplementedError.new("The method `#{method_sig.method_name}` on #{mod} is declared as `abstract`. It does not have an implementation.") + end + # Note, this logic is duplicated (intentionally, for micro-perf) at `CallValidation.wrap_method_if_needed`, + # make sure to keep changes in sync. + elsif method_sig.check_level == :always || (method_sig.check_level == :tests && T::Private::RuntimeLevels.check_tests?) + CallValidation.validate_call(self, original_method, method_sig, args, blk) + elsif T::Configuration::AT_LEAST_RUBY_2_7 + original_method.bind_call(self, *args, &blk) + else + original_method.bind(self).call(*args, &blk) + end + end + end + + @sig_wrappers[key] = sig_block + if current_declaration.final + @was_ever_final_names[method_name] = true + # use hook_mod, not mod, because for example, we want class C to be marked as having final if we def C.foo as + # final. change this to mod to see some final_method tests fail. + note_module_deals_with_final(hook_mod) + add_module_with_final_method(hook_mod, method_name, is_singleton_method) + end + end + + def self._handle_missing_method_signature(receiver, original_method, callee) + method_sig = T::Private::Methods.signature_for_method(original_method) + if !method_sig + raise "`sig` not present for method `#{callee}` on #{receiver.inspect} but you're trying to run it anyways. " \ + "This should only be executed if you used `alias_method` to grab a handle to a method after `sig`ing it, but that clearly isn't what you are doing. " \ + "Maybe look to see if an exception was thrown in your `sig` lambda or somehow else your `sig` wasn't actually applied to the method." + end + + if receiver.class <= original_method.owner + receiving_class = receiver.class + elsif receiver.singleton_class <= original_method.owner + receiving_class = receiver.singleton_class + elsif receiver.is_a?(Module) && receiver <= original_method.owner + receiving_class = receiver + else + raise "#{receiver} is not related to #{original_method} - how did we get here?" + end + + # Check for a case where `alias` or `alias_method` was called for a + # method which had already had a `sig` applied. In that case, we want + # to avoid hitting this slow path again, by moving to a faster validator + # just like we did or will for the original method. + # + # If this isn't an `alias` or `alias_method` case, we're probably in the + # middle of some metaprogramming using a Method object, e.g. a pattern like + # `arr.map(&method(:foo))`. There's nothing really we can do to optimize + # that here. + receiving_method = receiving_class.instance_method(callee) + if receiving_method != original_method && receiving_method.original_name == original_method.name + aliasing_mod = receiving_method.owner + method_sig = method_sig.as_alias(callee) + unwrap_method(aliasing_mod, method_sig, original_method) + end + + method_sig + end + + # Executes the `sig` block, and converts the resulting Declaration + # to a Signature. + def self.run_sig(hook_mod, method_name, original_method, declaration_block) + current_declaration = + begin + run_builder(declaration_block) + rescue DeclBuilder::BuilderError => e + T::Configuration.sig_builder_error_handler(e, declaration_block.loc) + nil + end + + signature = + if current_declaration + build_sig(hook_mod, method_name, original_method, current_declaration, declaration_block.loc) + else + Signature.new_untyped(method: original_method) + end + + unwrap_method(signature.method.owner, signature, original_method) + signature + end + + def self.run_builder(declaration_block) + builder = DeclBuilder.new(declaration_block.mod, declaration_block.raw) + builder + .instance_exec(&declaration_block.blk) + .finalize! + .decl + end + + def self.build_sig(hook_mod, method_name, original_method, current_declaration, loc) + begin + # We allow `sig` in the current module's context (normal case) and + if hook_mod != current_declaration.mod && + # inside `class << self`, and + hook_mod.singleton_class != current_declaration.mod && + # on `self` at the top level of a file + current_declaration.mod != TOP_SELF + raise "A method (#{method_name}) is being added on a different class/module (#{hook_mod}) than the " \ + "last call to `sig` (#{current_declaration.mod}). Make sure each call " \ + "to `sig` is immediately followed by a method definition on the same " \ + "class/module." + end + + signature = Signature.new( + method: original_method, + method_name: method_name, + raw_arg_types: current_declaration.params, + raw_return_type: current_declaration.returns, + bind: current_declaration.bind, + mode: current_declaration.mode, + check_level: current_declaration.checked, + on_failure: current_declaration.on_failure, + override_allow_incompatible: current_declaration.override_allow_incompatible, + defined_raw: current_declaration.raw, + ) + + SignatureValidation.validate(signature) + signature + rescue => e + super_method = original_method&.super_method + super_signature = signature_for_method(super_method) if super_method + + T::Configuration.sig_validation_error_handler( + e, + method: original_method, + declaration: current_declaration, + signature: signature, + super_signature: super_signature + ) + + Signature.new_untyped(method: original_method) + end + end + + def self.unwrap_method(mod, signature, original_method) + maybe_wrapped_method = CallValidation.wrap_method_if_needed(mod, signature, original_method) + @signatures_by_method[method_to_key(maybe_wrapped_method)] = signature + end + + def self.has_sig_block_for_method(method) + has_sig_block_for_key(method_to_key(method)) + end + + private_class_method def self.has_sig_block_for_key(key) + @sig_wrappers.key?(key) + end + + def self.maybe_run_sig_block_for_method(method) + maybe_run_sig_block_for_key(method_to_key(method)) + end + + # Only public so that it can be accessed in the closure for _on_method_added + def self.maybe_run_sig_block_for_key(key) + run_sig_block_for_key(key) if has_sig_block_for_key(key) + end + + def self.run_sig_block_for_method(method) + run_sig_block_for_key(method_to_key(method)) + end + + private_class_method def self.run_sig_block_for_key(key) + blk = @sig_wrappers[key] + if !blk + sig = @signatures_by_method[key] + if sig + # We already ran the sig block, perhaps in another thread. + return sig + else + raise "No `sig` wrapper for #{key_to_method(key)}" + end + end + + begin + sig = blk.call + rescue + @sigs_that_raised[key] = true + raise + end + if @sigs_that_raised[key] + raise "A previous invocation of #{key_to_method(key)} raised, and the current one succeeded. Please don't do that." + end + + @sig_wrappers.delete(key) + sig + end + + def self.run_all_sig_blocks + loop do + break if @sig_wrappers.empty? + key, = @sig_wrappers.first + run_sig_block_for_key(key) + end + end + + def self.all_checked_tests_sigs + @signatures_by_method.values.select {|sig| sig.check_level == :tests} + end + + # the module target is adding the methods from the module source to itself. we need to check that for all instance + # methods M on source, M is not defined on any of target's ancestors. + def self._hook_impl(target, singleton_class, source) + # we do not need to call add_was_ever_final here, because we have already marked + # any such methods when source was originally defined. + if !@modules_with_final.include?(target.object_id) + if !@modules_with_final.include?(source.object_id) + return + end + note_module_deals_with_final(target) + install_hooks(target) + return + end + + methods = source.instance_methods + methods.select! do |method_name| + @was_ever_final_names.include?(method_name) + end + if methods.empty? + return + end + + target_ancestors = singleton_class ? target.singleton_class.ancestors : target.ancestors + _check_final_ancestors(target, target_ancestors, methods, source) + end + + def self.set_final_checks_on_hooks(enable) + is_enabled = !@old_hooks.nil? + if enable == is_enabled + return + end + if is_enabled + @old_hooks.each(&:restore) + @old_hooks = nil + else + old_included = T::Private::ClassUtils.replace_method(Module, :included) do |arg| + old_included.bind(self).call(arg) + ::T::Private::Methods._hook_impl(arg, false, self) + end + old_extended = T::Private::ClassUtils.replace_method(Module, :extended) do |arg| + old_extended.bind(self).call(arg) + ::T::Private::Methods._hook_impl(arg, true, self) + end + old_inherited = T::Private::ClassUtils.replace_method(Class, :inherited) do |arg| + old_inherited.bind(self).call(arg) + ::T::Private::Methods._hook_impl(arg, false, self) + end + @old_hooks = [old_included, old_extended, old_inherited] + end + end + + module MethodHooks + def method_added(name) + super(name) + ::T::Private::Methods._on_method_added(self, name, is_singleton_method: false) + end + end + + module SingletonMethodHooks + def singleton_method_added(name) + super(name) + ::T::Private::Methods._on_method_added(self, name, is_singleton_method: true) + end + end + + def self.install_hooks(mod) + return if @installed_hooks.include?(mod) + @installed_hooks[mod] = true + + if mod == TOP_SELF + # self at the top-level of a file is weirdly special in Ruby + # The Ruby VM on startup creates an `Object.new` and stashes it. + # Unlike when we're using sig inside a module, `self` is actually a + # normal object, not an instance of Module. + # + # Thus we can't ask things like mod.singleton_class? (since that's + # defined only on Module, not on Object) and even if we could, the places + # where we need to install the hooks are special. + mod.extend(SingletonMethodHooks) # def self.foo; end (at top level) + Object.extend(MethodHooks) # def foo; end (at top level) + return + end + + # See https://github.com/sorbet/sorbet/pull/3964 for an explanation of why this + # check (which theoretically should not be needed) is actually needed. + if !mod.is_a?(Module) + return + end + + if mod.singleton_class? + mod.include(SingletonMethodHooks) + else + mod.extend(MethodHooks) + end + mod.extend(SingletonMethodHooks) + end + + # use this directly if you don't want/need to box up the method into an object to pass to method_to_key. + private_class_method def self.method_owner_and_name_to_key(owner, name) + "#{owner.object_id}##{name}" + end + + private_class_method def self.method_to_key(method) + method_owner_and_name_to_key(method.owner, method.name) + end + + private_class_method def self.key_to_method(key) + id, name = key.split("#") + obj = ObjectSpace._id2ref(id.to_i) + obj.instance_method(name) + end +end + +# This has to be here, and can't be nested inside `T::Private::Methods`, +# because the value of `self` depends on lexical (nesting) scope, and we +# specifically need a reference to the file-level self, i.e. `main:Object` +T::Private::Methods::TOP_SELF = self diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/call_validation.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/call_validation.rb new file mode 100644 index 0000000000..1889daa991 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/call_validation.rb @@ -0,0 +1,221 @@ +# frozen_string_literal: true +# typed: false + +module T::Private::Methods::CallValidation + CallValidation = T::Private::Methods::CallValidation + Modes = T::Private::Methods::Modes + + # Wraps a method with a layer of validation for the given type signature. + # This wrapper is meant to be fast, and is applied by a previous wrapper, + # which was placed by `_on_method_added`. + # + # @param method_sig [T::Private::Methods::Signature] + # @return [UnboundMethod] the new wrapper method (or the original one if we didn't wrap it) + def self.wrap_method_if_needed(mod, method_sig, original_method) + original_visibility = visibility_method_name(mod, method_sig.method_name) + if method_sig.mode == T::Private::Methods::Modes.abstract + T::Private::ClassUtils.replace_method(mod, method_sig.method_name) do |*args, &blk| + # TODO: write a cop to ensure that abstract methods have an empty body + # + # We allow abstract methods to be implemented by things further down the ancestor chain. + # So, if a super method exists, call it. + if defined?(super) + super(*args, &blk) + else + raise NotImplementedError.new( + "The method `#{method_sig.method_name}` on #{mod} is declared as `abstract`. It does not have an implementation." + ) + end + end + # Do nothing in this case; this method was not wrapped in _on_method_added. + elsif method_sig.defined_raw + # Note, this logic is duplicated (intentionally, for micro-perf) at `Methods._on_method_added`, + # make sure to keep changes in sync. + # This is a trapdoor point for each method: + # if a given method is wrapped, it stays wrapped; and if not, it's never wrapped. + # (Therefore, we need the `@wrapped_tests_with_validation` check in `T::RuntimeLevels`.) + elsif method_sig.check_level == :always || (method_sig.check_level == :tests && T::Private::RuntimeLevels.check_tests?) + create_validator_method(mod, original_method, method_sig, original_visibility) + else + T::Configuration.without_ruby_warnings do + # get all the shims out of the way and put back the original method + T::Private::DeclState.current.without_on_method_added do + mod.send(:define_method, method_sig.method_name, original_method) + end + mod.send(original_visibility, method_sig.method_name) + end + end + # Return the newly created method (or the original one if we didn't replace it) + mod.instance_method(method_sig.method_name) + end + + @is_allowed_to_have_fast_path = true + def self.is_allowed_to_have_fast_path + @is_allowed_to_have_fast_path + end + + def self.disable_fast_path + @is_allowed_to_have_fast_path = false + end + + def self.create_validator_method(mod, original_method, method_sig, original_visibility) + has_fixed_arity = method_sig.kwarg_types.empty? && !method_sig.has_rest && !method_sig.has_keyrest && + original_method.parameters.all? {|(kind, _name)| kind == :req} + ok_for_fast_path = has_fixed_arity && !method_sig.bind && method_sig.arg_types.length < 5 && is_allowed_to_have_fast_path + + all_args_are_simple = ok_for_fast_path && method_sig.arg_types.all? {|_name, type| type.is_a?(T::Types::Simple)} + simple_method = all_args_are_simple && method_sig.return_type.is_a?(T::Types::Simple) + simple_procedure = all_args_are_simple && method_sig.return_type.is_a?(T::Private::Types::Void) + + T::Configuration.without_ruby_warnings do + T::Private::DeclState.current.without_on_method_added do + if simple_method + create_validator_method_fast(mod, original_method, method_sig) + elsif simple_procedure + create_validator_procedure_fast(mod, original_method, method_sig) + elsif ok_for_fast_path && method_sig.return_type.is_a?(T::Private::Types::Void) + create_validator_procedure_medium(mod, original_method, method_sig) + elsif ok_for_fast_path + create_validator_method_medium(mod, original_method, method_sig) + else + create_validator_slow(mod, original_method, method_sig) + end + end + end + mod.send(original_visibility, method_sig.method_name) + end + + def self.create_validator_slow(mod, original_method, method_sig) + mod.send(:define_method, method_sig.method_name) do |*args, &blk| + CallValidation.validate_call(self, original_method, method_sig, args, blk) + end + if mod.respond_to?(:ruby2_keywords, true) + mod.send(:ruby2_keywords, method_sig.method_name) + end + end + + def self.validate_call(instance, original_method, method_sig, args, blk) + # This method is called for every `sig`. It's critical to keep it fast and + # reduce number of allocations that happen here. + + if method_sig.bind + message = method_sig.bind.error_message_for_obj(instance) + if message + CallValidation.report_error( + method_sig, + message, + 'Bind', + nil, + method_sig.bind, + instance + ) + end + end + + # NOTE: We don't bother validating for missing or extra kwargs; + # the method call itself will take care of that. + method_sig.each_args_value_type(args) do |name, arg, type| + message = type.error_message_for_obj(arg) + if message + CallValidation.report_error( + method_sig, + message, + 'Parameter', + name, + type, + arg, + caller_offset: 2 + ) + end + end + + if method_sig.block_type + message = method_sig.block_type.error_message_for_obj(blk) + if message + CallValidation.report_error( + method_sig, + message, + 'Block parameter', + method_sig.block_name, + method_sig.block_type, + blk + ) + end + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = T::Configuration::AT_LEAST_RUBY_2_7 ? original_method.bind_call(instance, *args, &blk) : original_method.bind(instance).call(*args, &blk) + + # The only type that is allowed to change the return value is `.void`. + # It ignores what you returned and changes it to be a private singleton. + if method_sig.return_type.is_a?(T::Private::Types::Void) + T::Private::Types::Void::VOID + else + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + ) + end + return_value + end + end + + def self.report_error(method_sig, error_message, kind, name, type, value, caller_offset: 0) + caller_loc = T.must(caller_locations(3 + caller_offset, 1))[0] + definition_file, definition_line = method_sig.method.source_location + + pretty_message = "#{kind}#{name ? " '#{name}'" : ''}: #{error_message}\n" \ + "Caller: #{caller_loc.path}:#{caller_loc.lineno}\n" \ + "Definition: #{definition_file}:#{definition_line}" + + T::Configuration.call_validation_error_handler( + method_sig, + message: error_message, + pretty_message: pretty_message, + kind: kind, + name: name, + type: type, + value: value, + location: caller_loc + ) + end + + # `name` must be an instance method (for class methods, pass in mod.singleton_class) + private_class_method def self.visibility_method_name(mod, name) + if mod.public_method_defined?(name) + :public + elsif mod.protected_method_defined?(name) + :protected + elsif mod.private_method_defined?(name) + :private + else + raise NameError.new("undefined method `#{name}` for `#{mod}`") + end + end +end + +if T::Configuration::AT_LEAST_RUBY_2_7 + require_relative './call_validation_2_7' +else + require_relative './call_validation_2_6' +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/call_validation_2_6.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/call_validation_2_6.rb new file mode 100644 index 0000000000..753580dc36 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/call_validation_2_6.rb @@ -0,0 +1,1203 @@ +# frozen_string_literal: true +# typed: false + +# DO NOT EDIT. This file is autogenerated. To regenerate, run: +# +# bazel test //gems/sorbet-runtime:update_call_validation + +module T::Private::Methods::CallValidation + def self.create_validator_method_fast(mod, original_method, method_sig) + if method_sig.return_type.is_a?(T::Private::Types::Void) + raise 'Should have used create_validator_procedure_fast' + end + # trampoline to reduce stack frame size + if method_sig.arg_types.empty? + create_validator_method_fast0(mod, original_method, method_sig, method_sig.return_type.raw_type) + elsif method_sig.arg_types.length == 1 + create_validator_method_fast1(mod, original_method, method_sig, method_sig.return_type.raw_type, + method_sig.arg_types[0][1].raw_type) + elsif method_sig.arg_types.length == 2 + create_validator_method_fast2(mod, original_method, method_sig, method_sig.return_type.raw_type, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type) + elsif method_sig.arg_types.length == 3 + create_validator_method_fast3(mod, original_method, method_sig, method_sig.return_type.raw_type, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type, + method_sig.arg_types[2][1].raw_type) + elsif method_sig.arg_types.length == 4 + create_validator_method_fast4(mod, original_method, method_sig, method_sig.return_type.raw_type, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type, + method_sig.arg_types[2][1].raw_type, + method_sig.arg_types[3][1].raw_type) + else + raise 'should not happen' + end + end + + def self.create_validator_method_fast0(mod, original_method, method_sig, return_type) + mod.send(:define_method, method_sig.method_name) do |&blk| + # This method is a manually sped-up version of more general code in `validate_call` + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind(self).call(&blk) + unless return_value.is_a?(return_type) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_fast1(mod, original_method, method_sig, return_type, arg0_type) + mod.send(:define_method, method_sig.method_name) do |arg0, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind(self).call(arg0, &blk) + unless return_value.is_a?(return_type) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_fast2(mod, original_method, method_sig, return_type, arg0_type, arg1_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind(self).call(arg0, arg1, &blk) + unless return_value.is_a?(return_type) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_fast3(mod, original_method, method_sig, return_type, arg0_type, arg1_type, arg2_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2.is_a?(arg2_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind(self).call(arg0, arg1, arg2, &blk) + unless return_value.is_a?(return_type) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_fast4(mod, original_method, method_sig, return_type, arg0_type, arg1_type, arg2_type, arg3_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2.is_a?(arg2_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + unless arg3.is_a?(arg3_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[3][1].error_message_for_obj(arg3), + 'Parameter', + method_sig.arg_types[3][0], + arg3_type, + arg3, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk) + unless return_value.is_a?(return_type) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_procedure_fast(mod, original_method, method_sig) + # trampoline to reduce stack frame size + if method_sig.arg_types.empty? + create_validator_procedure_fast0(mod, original_method, method_sig) + elsif method_sig.arg_types.length == 1 + create_validator_procedure_fast1(mod, original_method, method_sig, + method_sig.arg_types[0][1].raw_type) + elsif method_sig.arg_types.length == 2 + create_validator_procedure_fast2(mod, original_method, method_sig, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type) + elsif method_sig.arg_types.length == 3 + create_validator_procedure_fast3(mod, original_method, method_sig, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type, + method_sig.arg_types[2][1].raw_type) + elsif method_sig.arg_types.length == 4 + create_validator_procedure_fast4(mod, original_method, method_sig, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type, + method_sig.arg_types[2][1].raw_type, + method_sig.arg_types[3][1].raw_type) + else + raise 'should not happen' + end + end + + def self.create_validator_procedure_fast0(mod, original_method, method_sig) + mod.send(:define_method, method_sig.method_name) do |&blk| + # This method is a manually sped-up version of more general code in `validate_call` + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind(self).call(&blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_fast1(mod, original_method, method_sig, arg0_type) + mod.send(:define_method, method_sig.method_name) do |arg0, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind(self).call(arg0, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_fast2(mod, original_method, method_sig, arg0_type, arg1_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind(self).call(arg0, arg1, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_fast3(mod, original_method, method_sig, arg0_type, arg1_type, arg2_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2.is_a?(arg2_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind(self).call(arg0, arg1, arg2, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_fast4(mod, original_method, method_sig, arg0_type, arg1_type, arg2_type, arg3_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2.is_a?(arg2_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + unless arg3.is_a?(arg3_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[3][1].error_message_for_obj(arg3), + 'Parameter', + method_sig.arg_types[3][0], + arg3_type, + arg3, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_method_medium(mod, original_method, method_sig) + if method_sig.return_type.is_a?(T::Private::Types::Void) + raise 'Should have used create_validator_procedure_medium' + end + # trampoline to reduce stack frame size + if method_sig.arg_types.empty? + create_validator_method_medium0(mod, original_method, method_sig, method_sig.return_type) + elsif method_sig.arg_types.length == 1 + create_validator_method_medium1(mod, original_method, method_sig, method_sig.return_type, + method_sig.arg_types[0][1]) + elsif method_sig.arg_types.length == 2 + create_validator_method_medium2(mod, original_method, method_sig, method_sig.return_type, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1]) + elsif method_sig.arg_types.length == 3 + create_validator_method_medium3(mod, original_method, method_sig, method_sig.return_type, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1], + method_sig.arg_types[2][1]) + elsif method_sig.arg_types.length == 4 + create_validator_method_medium4(mod, original_method, method_sig, method_sig.return_type, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1], + method_sig.arg_types[2][1], + method_sig.arg_types[3][1]) + else + raise 'should not happen' + end + end + + def self.create_validator_method_medium0(mod, original_method, method_sig, return_type) + mod.send(:define_method, method_sig.method_name) do |&blk| + # This method is a manually sped-up version of more general code in `validate_call` + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind(self).call(&blk) + unless return_type.valid?(return_value) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_medium1(mod, original_method, method_sig, return_type, arg0_type) + mod.send(:define_method, method_sig.method_name) do |arg0, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind(self).call(arg0, &blk) + unless return_type.valid?(return_value) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_medium2(mod, original_method, method_sig, return_type, arg0_type, arg1_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind(self).call(arg0, arg1, &blk) + unless return_type.valid?(return_value) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_medium3(mod, original_method, method_sig, return_type, arg0_type, arg1_type, arg2_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2_type.valid?(arg2) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind(self).call(arg0, arg1, arg2, &blk) + unless return_type.valid?(return_value) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_medium4(mod, original_method, method_sig, return_type, arg0_type, arg1_type, arg2_type, arg3_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2_type.valid?(arg2) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + unless arg3_type.valid?(arg3) + CallValidation.report_error( + method_sig, + method_sig.arg_types[3][1].error_message_for_obj(arg3), + 'Parameter', + method_sig.arg_types[3][0], + arg3_type, + arg3, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk) + unless return_type.valid?(return_value) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_procedure_medium(mod, original_method, method_sig) + # trampoline to reduce stack frame size + if method_sig.arg_types.empty? + create_validator_procedure_medium0(mod, original_method, method_sig) + elsif method_sig.arg_types.length == 1 + create_validator_procedure_medium1(mod, original_method, method_sig, + method_sig.arg_types[0][1]) + elsif method_sig.arg_types.length == 2 + create_validator_procedure_medium2(mod, original_method, method_sig, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1]) + elsif method_sig.arg_types.length == 3 + create_validator_procedure_medium3(mod, original_method, method_sig, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1], + method_sig.arg_types[2][1]) + elsif method_sig.arg_types.length == 4 + create_validator_procedure_medium4(mod, original_method, method_sig, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1], + method_sig.arg_types[2][1], + method_sig.arg_types[3][1]) + else + raise 'should not happen' + end + end + + def self.create_validator_procedure_medium0(mod, original_method, method_sig) + mod.send(:define_method, method_sig.method_name) do |&blk| + # This method is a manually sped-up version of more general code in `validate_call` + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind(self).call(&blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_medium1(mod, original_method, method_sig, arg0_type) + mod.send(:define_method, method_sig.method_name) do |arg0, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind(self).call(arg0, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_medium2(mod, original_method, method_sig, arg0_type, arg1_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind(self).call(arg0, arg1, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_medium3(mod, original_method, method_sig, arg0_type, arg1_type, arg2_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2_type.valid?(arg2) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind(self).call(arg0, arg1, arg2, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_medium4(mod, original_method, method_sig, arg0_type, arg1_type, arg2_type, arg3_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2_type.valid?(arg2) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + unless arg3_type.valid?(arg3) + CallValidation.report_error( + method_sig, + method_sig.arg_types[3][1].error_message_for_obj(arg3), + 'Parameter', + method_sig.arg_types[3][0], + arg3_type, + arg3, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind(self).call(arg0, arg1, arg2, arg3, &blk) + T::Private::Types::Void::VOID + end + end + +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/call_validation_2_7.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/call_validation_2_7.rb new file mode 100644 index 0000000000..1686db8977 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/call_validation_2_7.rb @@ -0,0 +1,1203 @@ +# frozen_string_literal: true +# typed: false + +# DO NOT EDIT. This file is autogenerated. To regenerate, run: +# +# bazel test //gems/sorbet-runtime:update_call_validation + +module T::Private::Methods::CallValidation + def self.create_validator_method_fast(mod, original_method, method_sig) + if method_sig.return_type.is_a?(T::Private::Types::Void) + raise 'Should have used create_validator_procedure_fast' + end + # trampoline to reduce stack frame size + if method_sig.arg_types.empty? + create_validator_method_fast0(mod, original_method, method_sig, method_sig.return_type.raw_type) + elsif method_sig.arg_types.length == 1 + create_validator_method_fast1(mod, original_method, method_sig, method_sig.return_type.raw_type, + method_sig.arg_types[0][1].raw_type) + elsif method_sig.arg_types.length == 2 + create_validator_method_fast2(mod, original_method, method_sig, method_sig.return_type.raw_type, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type) + elsif method_sig.arg_types.length == 3 + create_validator_method_fast3(mod, original_method, method_sig, method_sig.return_type.raw_type, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type, + method_sig.arg_types[2][1].raw_type) + elsif method_sig.arg_types.length == 4 + create_validator_method_fast4(mod, original_method, method_sig, method_sig.return_type.raw_type, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type, + method_sig.arg_types[2][1].raw_type, + method_sig.arg_types[3][1].raw_type) + else + raise 'should not happen' + end + end + + def self.create_validator_method_fast0(mod, original_method, method_sig, return_type) + mod.send(:define_method, method_sig.method_name) do |&blk| + # This method is a manually sped-up version of more general code in `validate_call` + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind_call(self, &blk) + unless return_value.is_a?(return_type) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_fast1(mod, original_method, method_sig, return_type, arg0_type) + mod.send(:define_method, method_sig.method_name) do |arg0, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind_call(self, arg0, &blk) + unless return_value.is_a?(return_type) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_fast2(mod, original_method, method_sig, return_type, arg0_type, arg1_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind_call(self, arg0, arg1, &blk) + unless return_value.is_a?(return_type) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_fast3(mod, original_method, method_sig, return_type, arg0_type, arg1_type, arg2_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2.is_a?(arg2_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind_call(self, arg0, arg1, arg2, &blk) + unless return_value.is_a?(return_type) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_fast4(mod, original_method, method_sig, return_type, arg0_type, arg1_type, arg2_type, arg3_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2.is_a?(arg2_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + unless arg3.is_a?(arg3_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[3][1].error_message_for_obj(arg3), + 'Parameter', + method_sig.arg_types[3][0], + arg3_type, + arg3, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind_call(self, arg0, arg1, arg2, arg3, &blk) + unless return_value.is_a?(return_type) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_procedure_fast(mod, original_method, method_sig) + # trampoline to reduce stack frame size + if method_sig.arg_types.empty? + create_validator_procedure_fast0(mod, original_method, method_sig) + elsif method_sig.arg_types.length == 1 + create_validator_procedure_fast1(mod, original_method, method_sig, + method_sig.arg_types[0][1].raw_type) + elsif method_sig.arg_types.length == 2 + create_validator_procedure_fast2(mod, original_method, method_sig, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type) + elsif method_sig.arg_types.length == 3 + create_validator_procedure_fast3(mod, original_method, method_sig, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type, + method_sig.arg_types[2][1].raw_type) + elsif method_sig.arg_types.length == 4 + create_validator_procedure_fast4(mod, original_method, method_sig, + method_sig.arg_types[0][1].raw_type, + method_sig.arg_types[1][1].raw_type, + method_sig.arg_types[2][1].raw_type, + method_sig.arg_types[3][1].raw_type) + else + raise 'should not happen' + end + end + + def self.create_validator_procedure_fast0(mod, original_method, method_sig) + mod.send(:define_method, method_sig.method_name) do |&blk| + # This method is a manually sped-up version of more general code in `validate_call` + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind_call(self, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_fast1(mod, original_method, method_sig, arg0_type) + mod.send(:define_method, method_sig.method_name) do |arg0, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind_call(self, arg0, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_fast2(mod, original_method, method_sig, arg0_type, arg1_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind_call(self, arg0, arg1, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_fast3(mod, original_method, method_sig, arg0_type, arg1_type, arg2_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2.is_a?(arg2_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind_call(self, arg0, arg1, arg2, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_fast4(mod, original_method, method_sig, arg0_type, arg1_type, arg2_type, arg3_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0.is_a?(arg0_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1.is_a?(arg1_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2.is_a?(arg2_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + unless arg3.is_a?(arg3_type) + CallValidation.report_error( + method_sig, + method_sig.arg_types[3][1].error_message_for_obj(arg3), + 'Parameter', + method_sig.arg_types[3][0], + arg3_type, + arg3, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind_call(self, arg0, arg1, arg2, arg3, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_method_medium(mod, original_method, method_sig) + if method_sig.return_type.is_a?(T::Private::Types::Void) + raise 'Should have used create_validator_procedure_medium' + end + # trampoline to reduce stack frame size + if method_sig.arg_types.empty? + create_validator_method_medium0(mod, original_method, method_sig, method_sig.return_type) + elsif method_sig.arg_types.length == 1 + create_validator_method_medium1(mod, original_method, method_sig, method_sig.return_type, + method_sig.arg_types[0][1]) + elsif method_sig.arg_types.length == 2 + create_validator_method_medium2(mod, original_method, method_sig, method_sig.return_type, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1]) + elsif method_sig.arg_types.length == 3 + create_validator_method_medium3(mod, original_method, method_sig, method_sig.return_type, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1], + method_sig.arg_types[2][1]) + elsif method_sig.arg_types.length == 4 + create_validator_method_medium4(mod, original_method, method_sig, method_sig.return_type, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1], + method_sig.arg_types[2][1], + method_sig.arg_types[3][1]) + else + raise 'should not happen' + end + end + + def self.create_validator_method_medium0(mod, original_method, method_sig, return_type) + mod.send(:define_method, method_sig.method_name) do |&blk| + # This method is a manually sped-up version of more general code in `validate_call` + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind_call(self, &blk) + unless return_type.valid?(return_value) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_medium1(mod, original_method, method_sig, return_type, arg0_type) + mod.send(:define_method, method_sig.method_name) do |arg0, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind_call(self, arg0, &blk) + unless return_type.valid?(return_value) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_medium2(mod, original_method, method_sig, return_type, arg0_type, arg1_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind_call(self, arg0, arg1, &blk) + unless return_type.valid?(return_value) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_medium3(mod, original_method, method_sig, return_type, arg0_type, arg1_type, arg2_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2_type.valid?(arg2) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind_call(self, arg0, arg1, arg2, &blk) + unless return_type.valid?(return_value) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_method_medium4(mod, original_method, method_sig, return_type, arg0_type, arg1_type, arg2_type, arg3_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2_type.valid?(arg2) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + unless arg3_type.valid?(arg3) + CallValidation.report_error( + method_sig, + method_sig.arg_types[3][1].error_message_for_obj(arg3), + 'Parameter', + method_sig.arg_types[3][0], + arg3_type, + arg3, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + return_value = original_method.bind_call(self, arg0, arg1, arg2, arg3, &blk) + unless return_type.valid?(return_value) + message = method_sig.return_type.error_message_for_obj(return_value) + if message + CallValidation.report_error( + method_sig, + message, + 'Return value', + nil, + method_sig.return_type, + return_value, + caller_offset: -1 + ) + end + end + return_value + end + end + + def self.create_validator_procedure_medium(mod, original_method, method_sig) + # trampoline to reduce stack frame size + if method_sig.arg_types.empty? + create_validator_procedure_medium0(mod, original_method, method_sig) + elsif method_sig.arg_types.length == 1 + create_validator_procedure_medium1(mod, original_method, method_sig, + method_sig.arg_types[0][1]) + elsif method_sig.arg_types.length == 2 + create_validator_procedure_medium2(mod, original_method, method_sig, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1]) + elsif method_sig.arg_types.length == 3 + create_validator_procedure_medium3(mod, original_method, method_sig, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1], + method_sig.arg_types[2][1]) + elsif method_sig.arg_types.length == 4 + create_validator_procedure_medium4(mod, original_method, method_sig, + method_sig.arg_types[0][1], + method_sig.arg_types[1][1], + method_sig.arg_types[2][1], + method_sig.arg_types[3][1]) + else + raise 'should not happen' + end + end + + def self.create_validator_procedure_medium0(mod, original_method, method_sig) + mod.send(:define_method, method_sig.method_name) do |&blk| + # This method is a manually sped-up version of more general code in `validate_call` + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind_call(self, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_medium1(mod, original_method, method_sig, arg0_type) + mod.send(:define_method, method_sig.method_name) do |arg0, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind_call(self, arg0, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_medium2(mod, original_method, method_sig, arg0_type, arg1_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind_call(self, arg0, arg1, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_medium3(mod, original_method, method_sig, arg0_type, arg1_type, arg2_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2_type.valid?(arg2) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind_call(self, arg0, arg1, arg2, &blk) + T::Private::Types::Void::VOID + end + end + + def self.create_validator_procedure_medium4(mod, original_method, method_sig, arg0_type, arg1_type, arg2_type, arg3_type) + mod.send(:define_method, method_sig.method_name) do |arg0, arg1, arg2, arg3, &blk| + # This method is a manually sped-up version of more general code in `validate_call` + unless arg0_type.valid?(arg0) + CallValidation.report_error( + method_sig, + method_sig.arg_types[0][1].error_message_for_obj(arg0), + 'Parameter', + method_sig.arg_types[0][0], + arg0_type, + arg0, + caller_offset: -1 + ) + end + + unless arg1_type.valid?(arg1) + CallValidation.report_error( + method_sig, + method_sig.arg_types[1][1].error_message_for_obj(arg1), + 'Parameter', + method_sig.arg_types[1][0], + arg1_type, + arg1, + caller_offset: -1 + ) + end + + unless arg2_type.valid?(arg2) + CallValidation.report_error( + method_sig, + method_sig.arg_types[2][1].error_message_for_obj(arg2), + 'Parameter', + method_sig.arg_types[2][0], + arg2_type, + arg2, + caller_offset: -1 + ) + end + + unless arg3_type.valid?(arg3) + CallValidation.report_error( + method_sig, + method_sig.arg_types[3][1].error_message_for_obj(arg3), + 'Parameter', + method_sig.arg_types[3][0], + arg3_type, + arg3, + caller_offset: -1 + ) + end + + # The following line breaks are intentional to show nice pry message + + + + + + + + + + + # PRY note: + # this code is sig validation code. + # Please issue `finish` to step out of it + + original_method.bind_call(self, arg0, arg1, arg2, arg3, &blk) + T::Private::Types::Void::VOID + end + end + +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/decl_builder.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/decl_builder.rb new file mode 100644 index 0000000000..b48b1d5b68 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/decl_builder.rb @@ -0,0 +1,232 @@ +# frozen_string_literal: true +# typed: true + +module T::Private::Methods + Declaration = Struct.new(:mod, :params, :returns, :bind, :mode, :checked, :finalized, :on_failure, :override_allow_incompatible, :type_parameters, :raw) + + class DeclBuilder + attr_reader :decl + + class BuilderError < StandardError; end + + private def check_live! + if decl.finalized + raise BuilderError.new("You can't modify a signature declaration after it has been used.") + end + end + + def initialize(mod, raw) + # TODO RUBYPLAT-1278 - with ruby 2.5, use kwargs here + @decl = Declaration.new( + mod, + ARG_NOT_PROVIDED, # params + ARG_NOT_PROVIDED, # returns + ARG_NOT_PROVIDED, # bind + Modes.standard, # mode + ARG_NOT_PROVIDED, # checked + false, # finalized + ARG_NOT_PROVIDED, # on_failure + nil, # override_allow_incompatible + ARG_NOT_PROVIDED, # type_parameters + raw + ) + end + + def params(**params) + check_live! + if !decl.params.equal?(ARG_NOT_PROVIDED) + raise BuilderError.new("You can't call .params twice") + end + + if params.empty? + raise BuilderError.new("params expects keyword arguments") + end + decl.params = params + + self + end + + def returns(type) + check_live! + if decl.returns.is_a?(T::Private::Types::Void) + raise BuilderError.new("You can't call .returns after calling .void.") + end + if !decl.returns.equal?(ARG_NOT_PROVIDED) + raise BuilderError.new("You can't call .returns multiple times in a signature.") + end + + decl.returns = type + + self + end + + def void + check_live! + if !decl.returns.equal?(ARG_NOT_PROVIDED) + raise BuilderError.new("You can't call .void after calling .returns.") + end + + decl.returns = T::Private::Types::Void.new + + self + end + + def bind(type) + check_live! + if !decl.bind.equal?(ARG_NOT_PROVIDED) + raise BuilderError.new("You can't call .bind multiple times in a signature.") + end + + decl.bind = type + + self + end + + def checked(level) + check_live! + + if !decl.checked.equal?(ARG_NOT_PROVIDED) + raise BuilderError.new("You can't call .checked multiple times in a signature.") + end + if (level == :never || level == :compiled) && !decl.on_failure.equal?(ARG_NOT_PROVIDED) + raise BuilderError.new("You can't use .checked(:#{level}) with .on_failure because .on_failure will have no effect.") + end + if !T::Private::RuntimeLevels::LEVELS.include?(level) + raise BuilderError.new("Invalid `checked` level '#{level}'. Use one of: #{T::Private::RuntimeLevels::LEVELS}.") + end + + decl.checked = level + + self + end + + def on_failure(*args) + check_live! + + if !decl.on_failure.equal?(ARG_NOT_PROVIDED) + raise BuilderError.new("You can't call .on_failure multiple times in a signature.") + end + if decl.checked == :never || decl.checked == :compiled + raise BuilderError.new("You can't use .on_failure with .checked(:#{decl.checked}) because .on_failure will have no effect.") + end + + decl.on_failure = args + + self + end + + def abstract + check_live! + + case decl.mode + when Modes.standard + decl.mode = Modes.abstract + when Modes.abstract + raise BuilderError.new(".abstract cannot be repeated in a single signature") + else + raise BuilderError.new("`.abstract` cannot be combined with `.override` or `.overridable`.") + end + + self + end + + def final + check_live! + raise BuilderError.new("The syntax for declaring a method final is `sig(:final) {...}`, not `sig {final. ...}`") + end + + def override(allow_incompatible: false) + check_live! + + case decl.mode + when Modes.standard + decl.mode = Modes.override + decl.override_allow_incompatible = allow_incompatible + when Modes.override, Modes.overridable_override + raise BuilderError.new(".override cannot be repeated in a single signature") + when Modes.overridable + decl.mode = Modes.overridable_override + else + raise BuilderError.new("`.override` cannot be combined with `.abstract`.") + end + + self + end + + def overridable + check_live! + + case decl.mode + when Modes.abstract + raise BuilderError.new("`.overridable` cannot be combined with `.#{decl.mode}`") + when Modes.override + decl.mode = Modes.overridable_override + when Modes.standard + decl.mode = Modes.overridable + when Modes.overridable, Modes.overridable_override + raise BuilderError.new(".overridable cannot be repeated in a single signature") + end + + self + end + + # Declares valid type paramaters which can be used with `T.type_parameter` in + # this `sig`. + # + # This is used for generic methods. Example usage: + # + # sig do + # type_parameters(:U) + # .params(blk: T.proc.params(arg0: Elem).returns(T.type_parameter(:U))) + # .returns(T::Array[T.type_parameter(:U)]) + # end + # def map(&blk); end + def type_parameters(*names) + check_live! + + names.each do |name| + raise BuilderError.new("not a symbol: #{name}") unless name.is_a?(Symbol) + end + + if !decl.type_parameters.equal?(ARG_NOT_PROVIDED) + raise BuilderError.new("You can't call .type_parameters multiple times in a signature.") + end + + decl.type_parameters = names + + self + end + + def finalize! + check_live! + + if decl.returns.equal?(ARG_NOT_PROVIDED) + raise BuilderError.new("You must provide a return type; use the `.returns` or `.void` builder methods.") + end + + if decl.bind.equal?(ARG_NOT_PROVIDED) + decl.bind = nil + end + if decl.checked.equal?(ARG_NOT_PROVIDED) + default_checked_level = T::Private::RuntimeLevels.default_checked_level + if (default_checked_level == :never || default_checked_level == :compiled) && !decl.on_failure.equal?(ARG_NOT_PROVIDED) + raise BuilderError.new("To use .on_failure you must additionally call .checked(:tests) or .checked(:always), otherwise, the .on_failure has no effect.") + end + decl.checked = default_checked_level + end + if decl.on_failure.equal?(ARG_NOT_PROVIDED) + decl.on_failure = nil + end + if decl.params.equal?(ARG_NOT_PROVIDED) + decl.params = {} + end + if decl.type_parameters.equal?(ARG_NOT_PROVIDED) + decl.type_parameters = {} + end + + decl.finalized = true + + self + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/modes.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/modes.rb new file mode 100644 index 0000000000..53d9a93195 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/modes.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# typed: true + +module T::Private::Methods::Modes + def self.standard + 'standard' + end + def self.abstract + 'abstract' + end + def self.overridable + 'overridable' + end + def self.override + 'override' + end + def self.overridable_override + 'overridable_override' + end + def self.untyped + 'untyped' + end + MODES = [self.standard, self.abstract, self.overridable, self.override, self.overridable_override, self.untyped].freeze + + OVERRIDABLE_MODES = [self.override, self.overridable, self.overridable_override, self.untyped, self.abstract].freeze + OVERRIDE_MODES = [self.override, self.overridable_override].freeze + NON_OVERRIDE_MODES = MODES - OVERRIDE_MODES +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/signature.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/signature.rb new file mode 100644 index 0000000000..bd15977bd5 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/signature.rb @@ -0,0 +1,225 @@ +# frozen_string_literal: true +# typed: true + +class T::Private::Methods::Signature + attr_reader :method, :method_name, :arg_types, :kwarg_types, :block_type, :block_name, + :rest_type, :rest_name, :keyrest_type, :keyrest_name, :bind, + :return_type, :mode, :req_arg_count, :req_kwarg_names, :has_rest, :has_keyrest, + :check_level, :parameters, :on_failure, :override_allow_incompatible, + :defined_raw + + def self.new_untyped(method:, mode: T::Private::Methods::Modes.untyped, parameters: method.parameters) + # Using `Untyped` ensures we'll get an error if we ever try validation on these. + not_typed = T::Private::Types::NotTyped.new + raw_return_type = not_typed + # Map missing parameter names to "argN" positionally + parameters = parameters.each_with_index.map do |(param_kind, param_name), index| + [param_kind, param_name || "arg#{index}"] + end + raw_arg_types = parameters.map do |_param_kind, param_name| + [param_name, not_typed] + end.to_h + + self.new( + method: method, + method_name: method.name, + raw_arg_types: raw_arg_types, + raw_return_type: raw_return_type, + bind: nil, + mode: mode, + check_level: :never, + parameters: parameters, + on_failure: nil, + ) + end + + def initialize(method:, method_name:, raw_arg_types:, raw_return_type:, bind:, mode:, check_level:, on_failure:, parameters: method.parameters, override_allow_incompatible: false, defined_raw: false) + @method = method + @method_name = method_name + @arg_types = [] + @kwarg_types = {} + @block_type = nil + @block_name = nil + @rest_type = nil + @rest_name = nil + @keyrest_type = nil + @keyrest_name = nil + @return_type = T::Utils.coerce(raw_return_type) + @bind = bind ? T::Utils.coerce(bind) : bind + @mode = mode + @check_level = check_level + @req_arg_count = 0 + @req_kwarg_names = [] + @has_rest = false + @has_keyrest = false + @parameters = parameters + @on_failure = on_failure + @override_allow_incompatible = override_allow_incompatible + @defined_raw = defined_raw + + declared_param_names = raw_arg_types.keys + # If sig params are declared but there is a single parameter with a missing name + # **and** the method ends with a "=", assume it is a writer method generated + # by attr_writer or attr_accessor + writer_method = declared_param_names != [nil] && parameters == [[:req]] && method_name[-1] == "=" + # For writer methods, map the single parameter to the method name without the "=" at the end + parameters = [[:req, method_name[0...-1].to_sym]] if writer_method + param_names = parameters.map {|_, name| name} + missing_names = param_names - declared_param_names + extra_names = declared_param_names - param_names + if !missing_names.empty? + raise "The declaration for `#{method.name}` is missing parameter(s): #{missing_names.join(', ')}" + end + if !extra_names.empty? + raise "The declaration for `#{method.name}` has extra parameter(s): #{extra_names.join(', ')}" + end + + if parameters.size != raw_arg_types.size + raise "The declaration for `#{method.name}` has arguments with duplicate names" + end + + parameters.zip(raw_arg_types) do |(param_kind, param_name), (type_name, raw_type)| + if type_name != param_name + hint = "" + # Ruby reorders params so that required keyword arguments + # always precede optional keyword arguments. We can't tell + # whether the culprit is the Ruby reordering or user error, so + # we error but include a note + if param_kind == :keyreq && parameters.any? {|k, _| k == :key} + hint = "\n\nNote: Any required keyword arguments must precede any optional keyword " \ + "arguments. If your method declaration matches your `def`, try reordering any " \ + "optional keyword parameters to the end of the method list." + end + + raise "Parameter `#{type_name}` is declared out of order (declared as arg number " \ + "#{declared_param_names.index(type_name) + 1}, defined in the method as arg number " \ + "#{param_names.index(type_name) + 1}).#{hint}\nMethod: #{method_desc}" + end + + type = T::Utils.coerce(raw_type) + + case param_kind + when :req + if @arg_types.length > @req_arg_count + # Note that this is actually is supported by Ruby, but it would add complexity to + # support it here, and I'm happy to discourage its use anyway. + # + # If you are seeing this error and surprised by it, it's possible that you have + # overridden the method described in the error message. For example, Rails defines + # def self.update!(id = :all, attributes) + # on AR models. If you have also defined `self.update!` on an AR model you might + # see this error. The simplest resolution is to rename your method. + raise "Required params after optional params are not supported in method declarations. Method: #{method_desc}" + end + @arg_types << [param_name, type] + @req_arg_count += 1 + when :opt + @arg_types << [param_name, type] + when :key, :keyreq + @kwarg_types[param_name] = type + if param_kind == :keyreq + @req_kwarg_names << param_name + end + when :block + @block_name = param_name + @block_type = type + when :rest + @has_rest = true + @rest_name = param_name + @rest_type = type + when :keyrest + @has_keyrest = true + @keyrest_name = param_name + @keyrest_type = type + else + raise "Unexpected param_kind: `#{param_kind}`. Method: #{method_desc}" + end + end + end + + attr_writer :method_name + protected :method_name= + + def as_alias(alias_name) + new_sig = clone + new_sig.method_name = alias_name + new_sig + end + + def arg_count + @arg_types.length + end + + def kwarg_names + @kwarg_types.keys + end + + def owner + @method.owner + end + + def dsl_method + "#{@mode}_method" + end + + # @return [Hash] a mapping like `{arg_name: [val, type], ...}`, for only those args actually present. + def each_args_value_type(args) + # Manually split out args and kwargs based on ruby's behavior. Do not try to implement this by + # getting ruby to determine the kwargs for you (e.g., by defining this method to take *args and + # **kwargs). That won't work, because ruby's behavior for determining kwargs is dependent on the + # the other parameters in the method definition, and our method definition here doesn't (and + # can't) match the definition of the method we're validating. In addition, Ruby has a bug that + # causes forwarding **kwargs to do the wrong thing: see https://bugs.ruby-lang.org/issues/10708 + # and https://bugs.ruby-lang.org/issues/11860. + args_length = args.length + if (args_length > @req_arg_count) && (!@kwarg_types.empty? || @has_keyrest) && args[-1].is_a?(Hash) + kwargs = args[-1] + args_length -= 1 + else + kwargs = EMPTY_HASH + end + + arg_types = @arg_types + + if @has_rest + rest_count = args_length - @arg_types.length + rest_count = 0 if rest_count.negative? + + arg_types += [[@rest_name, @rest_type]] * rest_count + + elsif (args_length < @req_arg_count) || (args_length > @arg_types.length) + expected_str = @req_arg_count.to_s + if @arg_types.length != @req_arg_count + expected_str += "..#{@arg_types.length}" + end + raise ArgumentError.new("wrong number of arguments (given #{args_length}, expected #{expected_str})") + end + + begin + it = 0 + while it < args_length + yield arg_types[it][0], args[it], arg_types[it][1] + it += 1 + end + end + + kwargs.each do |name, val| + type = @kwarg_types[name] + if !type && @has_keyrest + type = @keyrest_type + end + yield name, val, type if type + end + end + + def method_desc + loc = if @method.source_location + @method.source_location.join(':') + else + "" + end + "#{@method} at #{loc}" + end + + EMPTY_HASH = {}.freeze +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/signature_validation.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/signature_validation.rb new file mode 100644 index 0000000000..16188e0bf3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/methods/signature_validation.rb @@ -0,0 +1,225 @@ +# frozen_string_literal: true +# typed: true + +module T::Private::Methods::SignatureValidation + Methods = T::Private::Methods + Modes = Methods::Modes + + def self.validate(signature) + if signature.method_name == :initialize && signature.method.owner.is_a?(Class) + # Constructors are special. They look like overrides in terms of a super_method existing, + # but in practice, you never call them polymorphically. Conceptually, they're standard + # methods (this is consistent with how they're treated in other languages, e.g. Java) + if signature.mode != Modes.standard + raise "`initialize` should not use `.abstract` or `.implementation` or any other inheritance modifiers." + end + return + end + + super_method = signature.method.super_method + + if super_method && super_method.owner != signature.method.owner + Methods.maybe_run_sig_block_for_method(super_method) + super_signature = Methods.signature_for_method(super_method) + + # If the super_method has any kwargs we can't build a + # Signature for it, so we'll just skip validation in that case. + if !super_signature && !super_method.parameters.select {|kind, _| kind == :rest || kind == :kwrest}.empty? + nil + else + # super_signature can be nil when we're overriding a method (perhaps a builtin) that didn't use + # one of the method signature helpers. Use an untyped signature so we can still validate + # everything but types. + # + # We treat these signatures as overridable, that way people can use `.override` with + # overrides of builtins. In the future we could try to distinguish when the method is a + # builtin and treat non-builtins as non-overridable (so you'd be forced to declare them with + # `.overridable`). + # + super_signature ||= Methods::Signature.new_untyped(method: super_method) + + validate_override_mode(signature, super_signature) + validate_override_shape(signature, super_signature) + validate_override_types(signature, super_signature) + end + else + validate_non_override_mode(signature) + end + end + + private_class_method def self.pretty_mode(signature) + if signature.mode == Modes.overridable_override + '.overridable.override' + else + ".#{signature.mode}" + end + end + + def self.validate_override_mode(signature, super_signature) + case signature.mode + when *Modes::OVERRIDE_MODES + # Peaceful + when *Modes::NON_OVERRIDE_MODES + if super_signature.mode == Modes.standard + # Peaceful + elsif super_signature.mode == Modes.abstract + raise "You must use `.override` when overriding the abstract method `#{signature.method_name}`.\n" \ + " Abstract definition: #{method_loc_str(super_signature.method)}\n" \ + " Implementation definition: #{method_loc_str(signature.method)}\n" + elsif super_signature.mode != Modes.untyped + raise "You must use `.override` when overriding the existing method `#{signature.method_name}`.\n" \ + " Parent definition: #{method_loc_str(super_signature.method)}\n" \ + " Child definition: #{method_loc_str(signature.method)}\n" + end + else + raise "Unexpected mode: #{signature.mode}. Please report this bug at https://github.com/sorbet/sorbet/issues" + end + end + + def self.validate_non_override_mode(signature) + case signature.mode + when Modes.override + if signature.method_name == :each && signature.method.owner < Enumerable + # Enumerable#each is the only method in Sorbet's RBI payload that defines an abstract method. + # Enumerable#each does not actually exist at runtime, but it is required to be implemented by + # any class which includes Enumerable. We want to declare Enumerable#each as abstract so that + # people can call it anything which implements the Enumerable interface, and so that it's a + # static error to forget to implement it. + # + # This is a one-off hack, and we should think carefully before adding more methods here. + nil + else + raise "You marked `#{signature.method_name}` as #{pretty_mode(signature)}, but that method doesn't already exist in this class/module to be overriden.\n" \ + " Either check for typos and for missing includes or super classes to make the parent method shows up\n" \ + " ... or remove #{pretty_mode(signature)} here: #{method_loc_str(signature.method)}\n" + end + when Modes.standard, *Modes::NON_OVERRIDE_MODES + # Peaceful + nil + else + raise "Unexpected mode: #{signature.mode}. Please report this bug at https://github.com/sorbet/sorbet/issues" + end + + # Given a singleton class, we can check if it belongs to a + # module by looking at its superclass; given `module M`, + # `M.singleton_class.superclass == Module`, which is not true + # for any class. + owner = signature.method.owner + if (signature.mode == Modes.abstract || Modes::OVERRIDABLE_MODES.include?(signature.mode)) && + owner.singleton_class? && owner.superclass == Module + raise "Defining an overridable class method (via #{pretty_mode(signature)}) " \ + "on a module is not allowed. Class methods on " \ + "modules do not get inherited and thus cannot be overridden." + end + end + + def self.validate_override_shape(signature, super_signature) + return if signature.override_allow_incompatible + return if super_signature.mode == Modes.untyped + + method_name = signature.method_name + mode_verb = super_signature.mode == Modes.abstract ? 'implements' : 'overrides' + + if !signature.has_rest && signature.arg_count < super_signature.arg_count + raise "Your definition of `#{method_name}` must accept at least #{super_signature.arg_count} " \ + "positional arguments to be compatible with the method it #{mode_verb}: " \ + "#{base_override_loc_str(signature, super_signature)}" + end + + if !signature.has_rest && super_signature.has_rest + raise "Your definition of `#{method_name}` must have `*#{super_signature.rest_name}` " \ + "to be compatible with the method it #{mode_verb}: " \ + "#{base_override_loc_str(signature, super_signature)}" + end + + if signature.req_arg_count > super_signature.req_arg_count + raise "Your definition of `#{method_name}` must have no more than #{super_signature.req_arg_count} " \ + "required argument(s) to be compatible with the method it #{mode_verb}: " \ + "#{base_override_loc_str(signature, super_signature)}" + end + + if !signature.has_keyrest + # O(nm), but n and m are tiny here + missing_kwargs = super_signature.kwarg_names - signature.kwarg_names + if !missing_kwargs.empty? + raise "Your definition of `#{method_name}` is missing these keyword arg(s): #{missing_kwargs} " \ + "which are defined in the method it #{mode_verb}: " \ + "#{base_override_loc_str(signature, super_signature)}" + end + end + + if !signature.has_keyrest && super_signature.has_keyrest + raise "Your definition of `#{method_name}` must have `**#{super_signature.keyrest_name}` " \ + "to be compatible with the method it #{mode_verb}: " \ + "#{base_override_loc_str(signature, super_signature)}" + end + + # O(nm), but n and m are tiny here + extra_req_kwargs = signature.req_kwarg_names - super_signature.req_kwarg_names + if !extra_req_kwargs.empty? + raise "Your definition of `#{method_name}` has extra required keyword arg(s) " \ + "#{extra_req_kwargs} relative to the method it #{mode_verb}, making it incompatible: " \ + "#{base_override_loc_str(signature, super_signature)}" + end + + if super_signature.block_name && !signature.block_name + raise "Your definition of `#{method_name}` must accept a block parameter to be compatible " \ + "with the method it #{mode_verb}: " \ + "#{base_override_loc_str(signature, super_signature)}" + end + end + + def self.validate_override_types(signature, super_signature) + return if signature.override_allow_incompatible + return if super_signature.mode == Modes.untyped + return unless [signature, super_signature].all? do |sig| + sig.check_level == :always || sig.check_level == :compiled || (sig.check_level == :tests && T::Private::RuntimeLevels.check_tests?) + end + mode_noun = super_signature.mode == Modes.abstract ? 'implementation' : 'override' + + # arg types must be contravariant + super_signature.arg_types.zip(signature.arg_types).each_with_index do |((_super_name, super_type), (name, type)), index| + if !super_type.subtype_of?(type) + raise "Incompatible type for arg ##{index + 1} (`#{name}`) in signature for #{mode_noun} of method " \ + "`#{signature.method_name}`:\n" \ + "* Base: `#{super_type}` (in #{method_loc_str(super_signature.method)})\n" \ + "* #{mode_noun.capitalize}: `#{type}` (in #{method_loc_str(signature.method)})\n" \ + "(The types must be contravariant.)" + end + end + + # kwarg types must be contravariant + super_signature.kwarg_types.each do |name, super_type| + type = signature.kwarg_types[name] + if !super_type.subtype_of?(type) + raise "Incompatible type for arg `#{name}` in signature for #{mode_noun} of method `#{signature.method_name}`:\n" \ + "* Base: `#{super_type}` (in #{method_loc_str(super_signature.method)})\n" \ + "* #{mode_noun.capitalize}: `#{type}` (in #{method_loc_str(signature.method)})\n" \ + "(The types must be contravariant.)" + end + end + + # return types must be covariant + if !signature.return_type.subtype_of?(super_signature.return_type) + raise "Incompatible return type in signature for #{mode_noun} of method `#{signature.method_name}`:\n" \ + "* Base: `#{super_signature.return_type}` (in #{method_loc_str(super_signature.method)})\n" \ + "* #{mode_noun.capitalize}: `#{signature.return_type}` (in #{method_loc_str(signature.method)})\n" \ + "(The types must be covariant.)" + end + end + + private_class_method def self.base_override_loc_str(signature, super_signature) + mode_noun = super_signature.mode == Modes.abstract ? 'Implementation' : 'Override' + "\n * Base definition: in #{method_loc_str(super_signature.method)}" \ + "\n * #{mode_noun}: in #{method_loc_str(signature.method)}" + end + + private_class_method def self.method_loc_str(method) + loc = if method.source_location + method.source_location.join(':') + else + "" + end + "#{method.owner} at #{loc}" + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/mixins/mixins.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/mixins/mixins.rb new file mode 100644 index 0000000000..01eb42bd3a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/mixins/mixins.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# typed: true + +module T::Private + module MixesInClassMethods + def included(other) + mods = Abstract::Data.get(self, :class_methods_mixins) + mods.each {|mod| other.extend(mod)} + super + end + end + + module Mixins + def self.declare_mixes_in_class_methods(mixin, class_methods) + if mixin.is_a?(Class) + raise "Classes cannot be used as mixins, and so mixes_in_class_methods cannot be used on a Class." + end + + if Abstract::Data.key?(mixin, :class_methods_mixins) + class_methods = Abstract::Data.get(mixin, :class_methods_mixins) + class_methods + end + + mixin.singleton_class.include(MixesInClassMethods) + Abstract::Data.set(mixin, :class_methods_mixins, class_methods) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/retry.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/retry.rb new file mode 100644 index 0000000000..7b2822d394 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/retry.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +# typed: true + +module T::Private::Retry + + # A special singleton used for static analysis of exceptions. + module RETRY + freeze + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/runtime_levels.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/runtime_levels.rb new file mode 100644 index 0000000000..2454b21988 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/runtime_levels.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true +# typed: true + +# Used in `sig.checked(level)` to determine when runtime type checking +# is enabled on a method. +module T::Private::RuntimeLevels + LEVELS = [ + # Validate every call in every environment + :always, + # Validate in tests, but not in production + :tests, + # Don't even validate in tests, b/c too expensive, + # or b/c we fully trust the static typing + :never, + # Validate the sig when the file is using the Sorbet Compiler. + # Behaves like :never when interpreted. + :compiled, + ].freeze + + @check_tests = false + @wrapped_tests_with_validation = false + + @has_read_default_checked_level = false + @default_checked_level = :always + + def self.check_tests? + # Assume that this code path means that some `sig.checked(:tests)` + # has been wrapped (or not wrapped) already, which is a trapdoor + # for toggling `@check_tests`. + @wrapped_tests_with_validation = true + + @check_tests + end + + def self.enable_checking_in_tests + if !@check_tests && @wrapped_tests_with_validation + all_checked_tests_sigs = T::Private::Methods.all_checked_tests_sigs + locations = all_checked_tests_sigs.map {|sig| sig.method.source_location.join(':')}.join("\n- ") + raise "Toggle `:tests`-level runtime type checking earlier. " \ + "There are already some methods wrapped with `sig.checked(:tests)`:\n" \ + "- #{locations}" + end + + _toggle_checking_tests(true) + end + + def self.default_checked_level + @has_read_default_checked_level = true + @default_checked_level + end + + def self.default_checked_level=(default_checked_level) + if @has_read_default_checked_level + raise "Set the default checked level earlier. There are already some methods whose sig blocks have evaluated which would not be affected by the new default." + end + @default_checked_level = default_checked_level + end + + def self._toggle_checking_tests(checked) + @check_tests = checked + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/sealed.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/sealed.rb new file mode 100644 index 0000000000..62e19fb088 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/sealed.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true +# typed: false + +module T::Private::Sealed + module NoInherit + def inherited(child) + super + this_line = Kernel.caller.find {|line| !line.match(/in `inherited'$/)} + T::Private::Sealed.validate_inheritance(this_line, self, child, 'inherited') + @sorbet_sealed_module_all_subclasses << child + end + + def sealed_subclasses + @sorbet_sealed_module_all_subclasses_set ||= # rubocop:disable Naming/MemoizedInstanceVariableName + begin + require 'set' + Set.new(@sorbet_sealed_module_all_subclasses).freeze + end + end + end + + module NoIncludeExtend + def included(child) + super + this_line = Kernel.caller.find {|line| !line.match(/in `included'$/)} + T::Private::Sealed.validate_inheritance(this_line, self, child, 'included') + @sorbet_sealed_module_all_subclasses << child + end + + def extended(child) + super + this_line = Kernel.caller.find {|line| !line.match(/in `extended'$/)} + T::Private::Sealed.validate_inheritance(this_line, self, child, 'extended') + @sorbet_sealed_module_all_subclasses << child + end + + def sealed_subclasses + # this will freeze the set so that you can never get into a + # state where you use the subclasses list and then something + # else will add to it + @sorbet_sealed_module_all_subclasses_set ||= # rubocop:disable Naming/MemoizedInstanceVariableName + begin + require 'set' + Set.new(@sorbet_sealed_module_all_subclasses).freeze + end + end + end + + def self.declare(mod, decl_file) + if !mod.is_a?(Module) + raise "#{mod} is not a class or module and cannot be declared `sealed!`" + end + if sealed_module?(mod) + raise "#{mod} was already declared `sealed!` and cannot be re-declared `sealed!`" + end + if T::Private::Final.final_module?(mod) + raise "#{mod} was already declared `final!` and cannot be declared `sealed!`" + end + mod.extend(mod.is_a?(Class) ? NoInherit : NoIncludeExtend) + if !decl_file + raise "Couldn't determine declaration file for sealed class." + end + mod.instance_variable_set(:@sorbet_sealed_module_decl_file, decl_file) + mod.instance_variable_set(:@sorbet_sealed_module_all_subclasses, []) + end + + def self.sealed_module?(mod) + mod.instance_variable_defined?(:@sorbet_sealed_module_decl_file) + end + + def self.validate_inheritance(this_line, parent, child, verb) + this_file = this_line&.split(':')&.first + decl_file = parent.instance_variable_get(:@sorbet_sealed_module_decl_file) if sealed_module?(parent) + + if !this_file + raise "Could not use backtrace to determine file for #{verb} child #{child}" + end + if !decl_file + raise "#{parent} does not seem to be a sealed module (#{verb} by #{child})" + end + + if !this_file.start_with?(decl_file) + whitelist = T::Configuration.sealed_violation_whitelist + if !whitelist.nil? && whitelist.any? {|pattern| this_file =~ pattern} + return + end + + raise "#{parent} was declared sealed and can only be #{verb} in #{decl_file}, not #{this_file}" + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/not_typed.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/not_typed.rb new file mode 100644 index 0000000000..57196553b6 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/not_typed.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# typed: true + +# A placeholder for when an untyped thing must provide a type. +# Raises an exception if it is ever used for validation. +class T::Private::Types::NotTyped < T::Types::Base + ERROR_MESSAGE = "Validation is being done on a `NotTyped`. Please report this bug at https://github.com/sorbet/sorbet/issues" + + # overrides Base + def name + "" + end + + # overrides Base + def valid?(obj) + raise ERROR_MESSAGE + end + + # overrides Base + private def subtype_of_single?(other) + raise ERROR_MESSAGE + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/string_holder.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/string_holder.rb new file mode 100644 index 0000000000..b2295f7730 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/string_holder.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# typed: true + +# Holds a string. Useful for showing type aliases in error messages +class T::Private::Types::StringHolder < T::Types::Base + attr_reader :string + + def initialize(string) + @string = string + end + + # overrides Base + def name + string + end + + # overrides Base + def valid?(obj) + false + end + + # overrides Base + private def subtype_of_single?(other) + false + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/type_alias.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/type_alias.rb new file mode 100644 index 0000000000..de805c9659 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/type_alias.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# typed: true + +module T::Private::Types + # Wraps a proc for a type alias to defer its evaluation. + class TypeAlias < T::Types::Base + + def initialize(callable) + @callable = callable + end + + def aliased_type + @aliased_type ||= T::Utils.coerce(@callable.call) + end + + # overrides Base + def name + aliased_type.name + end + + # overrides Base + def recursively_valid?(obj) + aliased_type.recursively_valid?(obj) + end + + # overrides Base + def valid?(obj) + aliased_type.valid?(obj) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/void.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/void.rb new file mode 100644 index 0000000000..310fc56abc --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/private/types/void.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true +# typed: true + +# A marking class for when methods return void. +# Should never appear in types directly. +class T::Private::Types::Void < T::Types::Base + ERROR_MESSAGE = "Validation is being done on an `Void`. Please report this bug at https://github.com/sorbet/sorbet/issues" + + # The actual return value of `.void` methods. + # + # Uses `module VOID` because this gives it a readable name when someone + # examines it in Pry or with `#inspect` like: + # + # T::Private::Types::Void::VOID + # + module VOID + freeze + end + + # overrides Base + def name + "" + end + + # overrides Base + def valid?(obj) + raise ERROR_MESSAGE + end + + # overrides Base + private def subtype_of_single?(other) + raise ERROR_MESSAGE + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/_props.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/_props.rb new file mode 100644 index 0000000000..fae252aa04 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/_props.rb @@ -0,0 +1,169 @@ +# frozen_string_literal: true +# typed: true + +# A mixin for defining typed properties (attributes). +# To get serialization methods (to/from JSON-style hashes), add T::Props::Serializable. +# To get a constructor based on these properties, inherit from T::Struct. +module T::Props + extend T::Helpers + + ##### + # CAUTION: This mixin is used in hundreds of classes; we want to keep its surface area as narrow + # as possible and avoid polluting (and possibly conflicting with) the classes that use it. + # + # It currently has *zero* instance methods; let's try to keep it that way. + # For ClassMethods (below), try to add things to T::Props::Decorator instead unless you are sure + # it needs to be exposed here. + ##### + + module ClassMethods + extend T::Sig + extend T::Helpers + + def props + decorator.props + end + def plugins + @plugins ||= [] + end + + def decorator_class + Decorator + end + + def decorator + @decorator ||= decorator_class.new(self) + end + def reload_decorator! + @decorator = decorator_class.new(self) + end + + # Define a new property. See {file:README.md} for some concrete + # examples. + # + # Defining a property defines a method with the same name as the + # property, that returns the current value, and a `prop=` method + # to set its value. Properties will be inherited by subclasses of + # a document class. + # + # @param name [Symbol] The name of this property + # @param cls [Class,T::Types::Base] The type of this + # property. If the type is itself a `Document` subclass, this + # property will be recursively serialized/deserialized. + # @param rules [Hash] Options to control this property's behavior. + # @option rules [T::Boolean,Symbol] :optional If `true`, this property + # is never required to be set before an instance is serialized. + # If `:on_load` (default), when this property is missing or nil, a + # new model cannot be saved, and an existing model can only be + # saved if the property was already missing when it was loaded. + # If `false`, when the property is missing/nil after deserialization, it + # will be set to the default value (as defined by the `default` or + # `factory` option) or will raise if they are not present. + # Deprecated: For `Model`s, if `:optional` is set to the special value + # `:existing`, the property can be saved as nil even if it was + # deserialized with a non-nil value. (Deprecated because there should + # never be a need for this behavior; the new behavior of non-optional + # properties should be sufficient.) + # @option rules [Array] :enum An array of legal values; The + # property is required to take on one of those values. + # @option rules [T::Boolean] :dont_store If true, this property will + # not be saved on the hash resulting from + # {T::Props::Serializable#serialize} + # @option rules [Object] :ifunset A value to be returned if this + # property is requested but has never been set (is set to + # `nil`). It is applied at property-access time, and never saved + # back onto the object or into the database. + # + # ``:ifunset`` is considered **DEPRECATED** and should not be used + # in new code, in favor of just setting a default value. + # @option rules [Model, Symbol, Proc] :foreign A model class that this + # property is a reference to. Passing `:foreign` will define a + # `:"#{name}_"` method, that will load and return the + # corresponding foreign model. + # + # A symbol can be passed to avoid load-order dependencies; It + # will be lazily resolved relative to the enclosing module of the + # defining class. + # + # A callable (proc or method) can be passed to dynamically specify the + # foreign model. This will be passed the object instance so that other + # properties of the object can be used to determine the relevant model + # class. It should return a string/symbol class name or the foreign model + # class directly. + # + # @option rules [Object] :default A default value that will be set + # by `#initialize` if none is provided in the initialization + # hash. This will not affect objects loaded by {.from_hash}. + # @option rules [Proc] :factory A `Proc` that will be called to + # generate an initial value for this prop on `#initialize`, if + # none is provided. + # @option rules [T::Boolean] :immutable If true, this prop cannot be + # modified after an instance is created or loaded from a hash. + # @option rules [T::Boolean] :override It is an error to redeclare a + # `prop` that has already been declared (including on a + # superclass), unless `:override` is set to `true`. + # @option rules [Symbol, Array] :redaction A redaction directive that may + # be passed to Chalk::Tools::RedactionUtils.redact_with_directive to + # sanitize this parameter for display. Will define a + # `:"#{name}_redacted"` method, which will return the value in sanitized + # form. + # + # @return [void] + sig {params(name: Symbol, cls: T.untyped, rules: T.untyped).void} + def prop(name, cls, rules={}) + cls = T::Utils.coerce(cls) if !cls.is_a?(Module) + decorator.prop_defined(name, cls, rules) + end + + # Validates the value of the specified prop. This method allows the caller to + # validate a value for a prop without having to set the data on the instance. + # Throws if invalid. + # + # @param prop [Symbol] + # @param val [Object] + # @return [void] + def validate_prop_value(prop, val) + decorator.validate_prop_value(prop, val) + end + + # Needs to be documented + def plugin(mod) + decorator.plugin(mod) + end + + # Shorthand helper to define a `prop` with `immutable => true` + sig {params(name: Symbol, cls_or_args: T.untyped, args: T::Hash[Symbol, T.untyped]).void} + def const(name, cls_or_args, args={}) + if (cls_or_args.is_a?(Hash) && cls_or_args.key?(:immutable)) || args.key?(:immutable) + Kernel.raise ArgumentError.new("Cannot pass 'immutable' argument when using 'const' keyword to define a prop") + end + + if cls_or_args.is_a?(Hash) + self.prop(name, cls_or_args.merge(immutable: true)) + else + self.prop(name, cls_or_args, args.merge(immutable: true)) + end + end + + def included(child) + decorator.model_inherited(child) + super + end + + def prepended(child) + decorator.model_inherited(child) + super + end + + def extended(child) + decorator.model_inherited(child.singleton_class) + super + end + + def inherited(child) + decorator.model_inherited(child) + super + end + end + mixes_in_class_methods(ClassMethods) +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/constructor.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/constructor.rb new file mode 100644 index 0000000000..570c068ac4 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/constructor.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# typed: false + +module T::Props::Constructor + include T::Props::WeakConstructor +end + +module T::Props::Constructor::DecoratorMethods + extend T::Sig + + # Set values for all props that have no defaults. Override what `WeakConstructor` + # does in order to raise errors on nils instead of ignoring them. + # + # @return [Integer] A count of props that we successfully initialized (which + # we'll use to check for any unrecognized input.) + # + # checked(:never) - O(runtime object construction) + sig {params(instance: T::Props::Constructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never)} + def construct_props_without_defaults(instance, hash) + # Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator + # and therefore allocates for each entry. + result = 0 + props_without_defaults&.each_pair do |p, setter_proc| + begin + val = hash[p] + instance.instance_exec(val, &setter_proc) + if val || hash.key?(p) + result += 1 + end + rescue TypeError, T::Props::InvalidValueError + if !hash.key?(p) + raise ArgumentError.new("Missing required prop `#{p}` for class `#{instance.class.name}`") + else + raise + end + end + end + result + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/custom_type.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/custom_type.rb new file mode 100644 index 0000000000..0df6a0d863 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/custom_type.rb @@ -0,0 +1,108 @@ +# frozen_string_literal: true +# typed: strict + +module T::Props + module CustomType + extend T::Sig + extend T::Helpers + + abstract! + + include Kernel # for `is_a?` + + # Alias for backwards compatibility + sig(:final) do + params( + value: BasicObject, + ) + .returns(T::Boolean) + .checked(:never) + end + def instance?(value) + self.===(value) + end + + # Alias for backwards compatibility + sig(:final) do + params( + value: BasicObject, + ) + .returns(T::Boolean) + .checked(:never) + end + def valid?(value) + instance?(value) + end + + # Given an instance of this type, serialize that into a scalar type + # supported by T::Props. + # + # @param [Object] instance + # @return An instance of one of T::Configuration.scalar_types + sig {abstract.params(instance: T.untyped).returns(T.untyped).checked(:never)} + def serialize(instance); end + + # Given the serialized form of your type, this returns an instance + # of that custom type representing that value. + # + # @param scalar One of T::Configuration.scalar_types + # @return Object + sig {abstract.params(scalar: T.untyped).returns(T.untyped).checked(:never)} + def deserialize(scalar); end + + sig {override.params(_base: Module).void} + def self.included(_base) + super + + raise 'Please use "extend", not "include" to attach this module' + end + + sig(:final) {params(val: Object).returns(T::Boolean).checked(:never)} + def self.scalar_type?(val) + # We don't need to check for val's included modules in + # T::Configuration.scalar_types, because T::Configuration.scalar_types + # are all classes. + klass = T.let(val.class, T.nilable(Class)) + until klass.nil? + return true if T::Configuration.scalar_types.include?(klass.to_s) + klass = klass.superclass + end + false + end + + # We allow custom types to serialize to Arrays, so that we can + # implement set-like fields that store a unique-array, but forbid + # hashes; Custom hash types should be implemented via an emebdded + # T::Struct (or a subclass like Chalk::ODM::Document) or via T. + sig(:final) {params(val: Object).returns(T::Boolean).checked(:never)} + def self.valid_serialization?(val) + case val + when Array + val.each do |v| + return false unless scalar_type?(v) + end + + true + else + scalar_type?(val) + end + end + + sig(:final) do + params(instance: Object) + .returns(T.untyped) + .checked(:never) + end + def self.checked_serialize(instance) + val = T.cast(instance.class, T::Props::CustomType).serialize(instance) + unless valid_serialization?(val) + msg = "#{instance.class} did not serialize to a valid scalar type. It became a: #{val.class}" + if val.is_a?(Hash) + msg += "\nIf you want to store a structured Hash, consider using a T::Struct as your type." + end + raise TypeError.new(msg) + end + val + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/decorator.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/decorator.rb new file mode 100644 index 0000000000..679a32584b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/decorator.rb @@ -0,0 +1,669 @@ +# frozen_string_literal: true +# typed: strict + +# NB: This is not actually a decorator. It's just named that way for consistency +# with DocumentDecorator and ModelDecorator (which both seem to have been written +# with an incorrect understanding of the decorator pattern). These "decorators" +# should really just be static methods on private modules (we'd also want/need to +# replace decorator overrides in plugins with class methods that expose the necessary +# functionality). +class T::Props::Decorator + extend T::Sig + + Rules = T.type_alias {T::Hash[Symbol, T.untyped]} + DecoratedInstance = T.type_alias {Object} # Would be T::Props, but that produces circular reference errors in some circumstances + PropType = T.type_alias {T::Types::Base} + PropTypeOrClass = T.type_alias {T.any(PropType, Module)} + + class NoRulesError < StandardError; end + + EMPTY_PROPS = T.let({}.freeze, T::Hash[Symbol, Rules]) + private_constant :EMPTY_PROPS + + sig {params(klass: T.untyped).void.checked(:never)} + def initialize(klass) + @class = T.let(klass, T.all(Module, T::Props::ClassMethods)) + @class.plugins.each do |mod| + T::Props::Plugin::Private.apply_decorator_methods(mod, self) + end + @props = T.let(EMPTY_PROPS, T::Hash[Symbol, Rules]) + end + + # checked(:never) - O(prop accesses) + sig {returns(T::Hash[Symbol, Rules]).checked(:never)} + attr_reader :props + + sig {returns(T::Array[Symbol])} + def all_props + props.keys + end + + # checked(:never) - O(prop accesses) + sig {params(prop: T.any(Symbol, String)).returns(Rules).checked(:never)} + def prop_rules(prop) + props[prop.to_sym] || raise("No such prop: #{prop.inspect}") + end + + # checked(:never) - Rules hash is expensive to check + sig {params(prop: Symbol, rules: Rules).void.checked(:never)} + def add_prop_definition(prop, rules) + override = rules.delete(:override) + + if props.include?(prop) && !override + raise ArgumentError.new("Attempted to redefine prop #{prop.inspect} that's already defined without specifying :override => true: #{prop_rules(prop)}") + elsif !props.include?(prop) && override + raise ArgumentError.new("Attempted to override a prop #{prop.inspect} that doesn't already exist") + end + + @props = @props.merge(prop => rules.freeze).freeze + end + + # Heads up! + # + # There are already too many ad-hoc options on the prop DSL. + # + # We have already done a lot of work to remove unnecessary and confusing + # options. If you're considering adding a new rule key, please come chat with + # the Sorbet team first, as we'd really like to learn more about how to best + # solve the problem you're encountering. + VALID_RULE_KEYS = T.let(%i[ + enum + foreign + ifunset + immutable + override + redaction + sensitivity + without_accessors + clobber_existing_method! + extra + setter_validate + _tnilable + ].map {|k| [k, true]}.to_h.freeze, T::Hash[Symbol, T::Boolean]) + private_constant :VALID_RULE_KEYS + + sig {params(key: Symbol).returns(T::Boolean).checked(:never)} + def valid_rule_key?(key) + !!VALID_RULE_KEYS[key] + end + + # checked(:never) - O(prop accesses) + sig {returns(T.all(Module, T::Props::ClassMethods)).checked(:never)} + def decorated_class + @class + end + + # Accessors + + # Use this to validate that a value will validate for a given prop. Useful for knowing whether a value can be set on a model without setting it. + # + # checked(:never) - potentially O(prop accesses) depending on usage pattern + sig {params(prop: Symbol, val: T.untyped).void.checked(:never)} + def validate_prop_value(prop, val) + # We call `setter_proc` here without binding to an instance, so it'll run + # `instance_variable_set` if validation passes, but nothing will care. + # We only care about the validation. + prop_rules(prop).fetch(:setter_proc).call(val) + end + + # For performance, don't use named params here. + # Passing in rules here is purely a performance optimization. + # Unlike the other methods that take rules, this one calls prop_rules for + # the default, which raises if the prop doesn't exist (this maintains + # preexisting behavior). + # + # Note this path is NOT used by generated setters on instances, + # which are defined using `setter_proc` directly. + # + # checked(:never) - O(prop accesses) + sig do + params( + instance: DecoratedInstance, + prop: Symbol, + val: T.untyped, + rules: Rules + ) + .void + .checked(:never) + end + def prop_set(instance, prop, val, rules=prop_rules(prop)) + instance.instance_exec(val, &rules.fetch(:setter_proc)) + end + alias_method :set, :prop_set + + # Only Models have any custom get logic but we need to call this on + # non-Models since we don't know at code gen time what we have. + sig do + params( + instance: DecoratedInstance, + prop: Symbol, + value: T.untyped + ) + .returns(T.untyped) + .checked(:never) + end + def prop_get_logic(instance, prop, value) + value + end + + # For performance, don't use named params here. + # Passing in rules here is purely a performance optimization. + # + # Note this path is NOT used by generated getters on instances, + # unless `ifunset` is used on the prop, or `prop_get` is overridden. + # + # checked(:never) - O(prop accesses) + sig do + params( + instance: DecoratedInstance, + prop: T.any(String, Symbol), + rules: Rules + ) + .returns(T.untyped) + .checked(:never) + end + def prop_get(instance, prop, rules=prop_rules(prop)) + val = instance.instance_variable_get(rules[:accessor_key]) if instance.instance_variable_defined?(rules[:accessor_key]) + if !val.nil? + val + elsif (d = rules[:ifunset]) + T::Props::Utils.deep_clone_object(d) + else + nil + end + end + + sig do + params( + instance: DecoratedInstance, + prop: T.any(String, Symbol), + rules: Rules + ) + .returns(T.untyped) + .checked(:never) + end + def prop_get_if_set(instance, prop, rules=prop_rules(prop)) + instance.instance_variable_get(rules[:accessor_key]) if instance.instance_variable_defined?(rules[:accessor_key]) + end + alias_method :get, :prop_get_if_set # Alias for backwards compatibility + + # checked(:never) - O(prop accesses) + sig do + params( + instance: DecoratedInstance, + prop: Symbol, + foreign_class: Module, + rules: Rules, + opts: T::Hash[Symbol, T.untyped], + ) + .returns(T.untyped) + .checked(:never) + end + def foreign_prop_get(instance, prop, foreign_class, rules=prop_rules(prop), opts={}) + return if !(value = prop_get(instance, prop, rules)) + T.unsafe(foreign_class).load(value, {}, opts) + end + + # TODO: we should really be checking all the methods on `cls`, not just Object + BANNED_METHOD_NAMES = T.let(Object.instance_methods.each_with_object({}) {|x, acc| acc[x] = true}.freeze, T::Hash[Symbol, TrueClass]) + + # checked(:never) - Rules hash is expensive to check + sig do + params( + name: Symbol, + cls: Module, + rules: Rules, + type: PropTypeOrClass + ) + .void + .checked(:never) + end + def prop_validate_definition!(name, cls, rules, type) + validate_prop_name(name) + + if rules.key?(:pii) + raise ArgumentError.new("The 'pii:' option for props has been renamed " \ + "to 'sensitivity:' (in prop #{@class.name}.#{name})") + end + + if rules.keys.any? {|k| !valid_rule_key?(k)} + raise ArgumentError.new("At least one invalid prop arg supplied in #{self}: #{rules.keys.inspect}") + end + + if !rules[:clobber_existing_method!] && !rules[:without_accessors] && BANNED_METHOD_NAMES.include?(name.to_sym) + raise ArgumentError.new( + "#{name} can't be used as a prop in #{@class} because a method with " \ + "that name already exists (defined by #{@class.instance_method(name).owner} " \ + "at #{@class.instance_method(name).source_location || ''}). " \ + "(If using this name is unavoidable, try `without_accessors: true`.)" + ) + end + + extra = rules[:extra] + if !extra.nil? && !extra.is_a?(Hash) + raise ArgumentError.new("Extra metadata must be a Hash in prop #{@class.name}.#{name}") + end + + nil + end + + SAFE_NAME = T.let(/\A[A-Za-z_][A-Za-z0-9_-]*\z/.freeze, Regexp) + + # Used to validate both prop names and serialized forms + sig {params(name: T.any(Symbol, String)).void} + private def validate_prop_name(name) + if !name.match?(SAFE_NAME) + raise ArgumentError.new("Invalid prop name in #{@class.name}: #{name}") + end + end + + # This converts the type from a T::Type to a regular old ruby class. + sig {params(type: T::Types::Base).returns(Module)} + private def convert_type_to_class(type) + case type + when T::Types::TypedArray, T::Types::FixedArray + Array + when T::Types::TypedHash, T::Types::FixedHash + Hash + when T::Types::TypedSet + Set + when T::Types::Union + # The below unwraps our T.nilable types for T::Props if we can. + # This lets us do things like specify: const T.nilable(String), foreign: Opus::DB::Model::Merchant + non_nil_type = T::Utils.unwrap_nilable(type) + if non_nil_type + convert_type_to_class(non_nil_type) + else + Object + end + when T::Types::Simple + type.raw_type + else + # This isn't allowed unless whitelisted_for_underspecification is + # true, due to the check in prop_validate_definition + Object + end + end + + # Returns `true` when the type of the prop is nilable, or the field is typed + # as `T.untyped`, a `:default` is present in the rules hash, and its value is + # `nil`. The latter case is a workaround for explicitly not supporting the use + # of `T.nilable(T.untyped)`. + # + # checked(:never) - Rules hash is expensive to check + sig do + params( + cls: PropTypeOrClass, + rules: Rules, + ) + .void + .checked(:never) + end + private def prop_nilable?(cls, rules) + T::Utils::Nilable.is_union_with_nilclass(cls) || (cls == T.untyped && rules.key?(:default) && rules[:default].nil?) + end + + # checked(:never) - Rules hash is expensive to check + sig do + params( + name: T.any(Symbol, String), + cls: PropTypeOrClass, + rules: Rules, + ) + .void + .checked(:never) + end + def prop_defined(name, cls, rules={}) + cls = T::Utils.resolve_alias(cls) + + if prop_nilable?(cls, rules) + # :_tnilable is introduced internally for performance purpose so that clients do not need to call + # T::Utils::Nilable.is_tnilable(cls) again. + # It is strictly internal: clients should always use T::Props::Utils.required_prop?() or + # T::Props::Utils.optional_prop?() for checking whether a field is required or optional. + rules[:_tnilable] = true + end + + name = name.to_sym + type = cls + if !cls.is_a?(Module) + cls = convert_type_to_class(cls) + end + type_object = smart_coerce(type, enum: rules[:enum]) + + prop_validate_definition!(name, cls, rules, type_object) + + # Retrive the possible underlying object with T.nilable. + type = T::Utils::Nilable.get_underlying_type(type) + + sensitivity_and_pii = {sensitivity: rules[:sensitivity]} + normalize = T::Configuration.normalize_sensitivity_and_pii_handler + if normalize + sensitivity_and_pii = normalize.call(sensitivity_and_pii) + + # We check for Class so this is only applied on concrete + # documents/models; We allow mixins containing props to not + # specify their PII nature, as long as every class into which they + # are ultimately included does. + # + if sensitivity_and_pii[:pii] && @class.is_a?(Class) && !T.unsafe(@class).contains_pii? + raise ArgumentError.new( + 'Cannot include a pii prop in a class that declares `contains_no_pii`' + ) + end + end + + rules = rules.merge( + # TODO: The type of this element is confusing. We should refactor so that + # it can be always `type_object` (a PropType) or always `cls` (a Module) + type: type, + type_object: type_object, + accessor_key: "@#{name}".to_sym, + sensitivity: sensitivity_and_pii[:sensitivity], + pii: sensitivity_and_pii[:pii], + # extra arbitrary metadata attached by the code defining this property + extra: rules[:extra]&.freeze, + ) + + validate_not_missing_sensitivity(name, rules) + + # for backcompat (the `:array` key is deprecated but because the name is + # so generic it's really hard to be sure it's not being relied on anymore) + if type.is_a?(T::Types::TypedArray) + inner = T::Utils::Nilable.get_underlying_type(type.type) + if inner.is_a?(Module) + rules[:array] = inner + end + end + + rules[:setter_proc] = T::Props::Private::SetterFactory.build_setter_proc(@class, name, rules).freeze + + add_prop_definition(name, rules) + + # NB: using `without_accessors` doesn't make much sense unless you also define some other way to + # get at the property (e.g., Chalk::ODM::Document exposes `get` and `set`). + define_getter_and_setter(name, rules) unless rules[:without_accessors] + + handle_foreign_option(name, cls, rules, rules[:foreign]) if rules[:foreign] + handle_redaction_option(name, rules[:redaction]) if rules[:redaction] + end + + # checked(:never) - Rules hash is expensive to check + sig {params(name: Symbol, rules: Rules).void.checked(:never)} + private def define_getter_and_setter(name, rules) + T::Configuration.without_ruby_warnings do + if !rules[:immutable] + if method(:prop_set).owner != T::Props::Decorator + @class.send(:define_method, "#{name}=") do |val| + T.unsafe(self.class).decorator.prop_set(self, name, val, rules) + end + else + # Fast path (~4x faster as of Ruby 2.6) + @class.send(:define_method, "#{name}=", &rules.fetch(:setter_proc)) + end + end + + if method(:prop_get).owner != T::Props::Decorator || rules.key?(:ifunset) + @class.send(:define_method, name) do + T.unsafe(self.class).decorator.prop_get(self, name, rules) + end + else + # Fast path (~30x faster as of Ruby 2.6) + @class.send(:attr_reader, name) # send is used because `attr_reader` is private in 2.4 + end + end + end + + sig do + params(type: PropTypeOrClass, enum: T.untyped) + .returns(T::Types::Base) + end + private def smart_coerce(type, enum:) + # Backwards compatibility for pre-T::Types style + type = T::Utils.coerce(type) + if enum.nil? + type + else + nonnil_type = T::Utils.unwrap_nilable(type) + if nonnil_type + T.unsafe(T.nilable(T.all(nonnil_type, T.deprecated_enum(enum)))) + else + T.unsafe(T.all(T.unsafe(type), T.deprecated_enum(enum))) + end + end + end + + # checked(:never) - Rules hash is expensive to check + sig {params(prop_name: Symbol, rules: Rules).void.checked(:never)} + private def validate_not_missing_sensitivity(prop_name, rules) + if rules[:sensitivity].nil? + if rules[:redaction] + T::Configuration.hard_assert_handler( + "#{@class}##{prop_name} has a 'redaction:' annotation but no " \ + "'sensitivity:' annotation. This is probably wrong, because if a " \ + "prop needs redaction then it is probably sensitive. Add a " \ + "sensitivity annotation like 'sensitivity: Opus::Sensitivity::PII." \ + "whatever', or explicitly override this check with 'sensitivity: []'." + ) + end + # TODO(PRIVACYENG-982) Ideally we'd also check for 'password' and possibly + # other terms, but this interacts badly with ProtoDefinedDocument because + # the proto syntax currently can't declare "sensitivity: []" + if /\bsecret\b/.match?(prop_name) + T::Configuration.hard_assert_handler( + "#{@class}##{prop_name} has the word 'secret' in its name, but no " \ + "'sensitivity:' annotation. This is probably wrong, because if a " \ + "prop is named 'secret' then it is probably sensitive. Add a " \ + "sensitivity annotation like 'sensitivity: Opus::Sensitivity::NonPII." \ + "security_token', or explicitly override this check with " \ + "'sensitivity: []'." + ) + end + end + end + + # Create `#{prop_name}_redacted` method + sig do + params( + prop_name: Symbol, + redaction: T.untyped, + ) + .void + end + private def handle_redaction_option(prop_name, redaction) + redacted_method = "#{prop_name}_redacted" + + @class.send(:define_method, redacted_method) do + value = self.public_send(prop_name) + handler = T::Configuration.redaction_handler + if !handler + raise "Using `redaction:` on a prop requires specifying `T::Configuration.redaction_handler`" + end + handler.call(value, redaction) + end + end + + sig do + params( + option_sym: Symbol, + foreign: T.untyped, + valid_type_msg: String, + ) + .void + end + private def validate_foreign_option(option_sym, foreign, valid_type_msg:) + if foreign.is_a?(Symbol) || foreign.is_a?(String) + raise ArgumentError.new( + "Using a symbol/string for `#{option_sym}` is no longer supported. Instead, use a Proc " \ + "that returns the class, e.g., foreign: -> {Foo}" + ) + end + + if !foreign.is_a?(Proc) && !foreign.is_a?(Array) && !foreign.respond_to?(:load) + raise ArgumentError.new("The `#{option_sym}` option must be #{valid_type_msg}") + end + end + + # checked(:never) - Rules hash is expensive to check + sig do + params( + prop_name: T.any(String, Symbol), + rules: Rules, + foreign: T.untyped, + ) + .void + .checked(:never) + end + private def define_foreign_method(prop_name, rules, foreign) + fk_method = "#{prop_name}_" + + # n.b. there's no clear reason *not* to allow additional options + # here, but we're baking in `allow_direct_mutation` since we + # *haven't* allowed additional options in the past and want to + # default to keeping this interface narrow. + @class.send(:define_method, fk_method) do |allow_direct_mutation: nil| + foreign = T.let(foreign, T.untyped) + if foreign.is_a?(Proc) + resolved_foreign = foreign.call + if !resolved_foreign.respond_to?(:load) + raise ArgumentError.new( + "The `foreign` proc for `#{prop_name}` must return a model class. " \ + "Got `#{resolved_foreign.inspect}` instead." + ) + end + # `foreign` is part of the closure state, so this will persist to future invocations + # of the method, optimizing it so this only runs on the first invocation. + foreign = resolved_foreign + end + opts = if allow_direct_mutation.nil? + {} + else + {allow_direct_mutation: allow_direct_mutation} + end + + T.unsafe(self.class).decorator.foreign_prop_get(self, prop_name, foreign, rules, opts) + end + + force_fk_method = "#{fk_method}!" + @class.send(:define_method, force_fk_method) do |allow_direct_mutation: nil| + loaded_foreign = send(fk_method, allow_direct_mutation: allow_direct_mutation) + if !loaded_foreign + T::Configuration.hard_assert_handler( + 'Failed to load foreign model', + storytime: {method: force_fk_method, class: self.class} + ) + end + loaded_foreign + end + end + + # checked(:never) - Rules hash is expensive to check + sig do + params( + prop_name: Symbol, + prop_cls: Module, + rules: Rules, + foreign: T.untyped, + ) + .void + .checked(:never) + end + private def handle_foreign_option(prop_name, prop_cls, rules, foreign) + validate_foreign_option( + :foreign, foreign, valid_type_msg: "a model class or a Proc that returns one" + ) + + if prop_cls != String + raise ArgumentError.new("`foreign` can only be used with a prop type of String") + end + + if foreign.is_a?(Array) + # We don't support arrays with `foreign` because it's hard to both preserve ordering and + # keep them from being lurky performance hits by issuing a bunch of un-batched DB queries. + # We could potentially address that by porting over something like AmbiguousIDLoader. + raise ArgumentError.new( + "Using an array for `foreign` is no longer supported. Instead, please use a union type of " \ + "token types for the prop type, e.g., T.any(Opus::Autogen::Tokens::FooModelToken, Opus::Autogen::Tokens::BarModelToken)" + ) + end + + unless foreign.is_a?(Proc) + T::Configuration.soft_assert_handler(<<~MESSAGE, storytime: {prop: prop_name, value: foreign}, notify: 'jerry') + Please use a Proc that returns a model class instead of the model class itself as the argument to `foreign`. In other words: + + instead of `prop :foo, String, foreign: FooModel` + use `prop :foo, String, foreign: -> {FooModel}` + + MESSAGE + end + + define_foreign_method(prop_name, rules, foreign) + end + + # TODO: rename this to props_inherited + # + # This gets called when a module or class that extends T::Props gets included, extended, + # prepended, or inherited. + sig {params(child: Module).void.checked(:never)} + def model_inherited(child) + child.extend(T::Props::ClassMethods) + child = T.cast(child, T.all(Module, T::Props::ClassMethods)) + + child.plugins.concat(decorated_class.plugins) + decorated_class.plugins.each do |mod| + # NB: apply_class_methods must not be an instance method on the decorator itself, + # otherwise we'd have to call child.decorator here, which would create the decorator + # before any `decorator_class` override has a chance to take effect (see the comment below). + T::Props::Plugin::Private.apply_class_methods(mod, child) + end + + props.each do |name, rules| + copied_rules = rules.dup + # NB: Calling `child.decorator` here is a timb bomb that's going to give someone a really bad + # time. Any class that defines props and also overrides the `decorator_class` method is going + # to reach this line before its override take effect, turning it into a no-op. + child.decorator.add_prop_definition(name, copied_rules) + + # It's a bit tricky to support `prop_get` hooks added by plugins without + # sacrificing the `attr_reader` fast path or clobbering customized getters + # defined manually on a child. + # + # To make this work, we _do_ clobber getters defined on the child, but only if: + # (a) it's needed in order to support a `prop_get` hook, and + # (b) it's safe because the getter was defined by this file. + # + unless rules[:without_accessors] + if clobber_getter?(child, name) + child.send(:define_method, name) do + T.unsafe(self.class).decorator.prop_get(self, name, rules) + end + end + + if !rules[:immutable] && clobber_setter?(child, name) + child.send(:define_method, "#{name}=") do |val| + T.unsafe(self.class).decorator.prop_set(self, name, val, rules) + end + end + end + end + end + + sig {params(child: T.all(Module, T::Props::ClassMethods), prop: Symbol).returns(T::Boolean).checked(:never)} + private def clobber_getter?(child, prop) + !!(child.decorator.method(:prop_get).owner != method(:prop_get).owner && + child.instance_method(prop).source_location&.first == __FILE__) + end + + sig {params(child: T.all(Module, T::Props::ClassMethods), prop: Symbol).returns(T::Boolean).checked(:never)} + private def clobber_setter?(child, prop) + !!(child.decorator.method(:prop_set).owner != method(:prop_set).owner && + child.instance_method("#{prop}=").source_location&.first == __FILE__) + end + + sig {params(mod: Module).void.checked(:never)} + def plugin(mod) + decorated_class.plugins << mod + T::Props::Plugin::Private.apply_class_methods(mod, decorated_class) + T::Props::Plugin::Private.apply_decorator_methods(mod, self) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/errors.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/errors.rb new file mode 100644 index 0000000000..6977f20471 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/errors.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true +# typed: strict + +module T::Props + class Error < StandardError; end + class InvalidValueError < Error; end + class ImmutableProp < Error; end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/generated_code_validation.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/generated_code_validation.rb new file mode 100644 index 0000000000..91f256799d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/generated_code_validation.rb @@ -0,0 +1,277 @@ +# frozen_string_literal: true +# typed: true + +module T::Props + # Helper to validate generated code, to mitigate security concerns around + # `class_eval`. Not called by default; the expectation is this will be used + # in a test iterating over all T::Props::Serializable subclasses. + # + # We validate the exact expected structure of the generated methods as far + # as we can, and then where cloning produces an arbitrarily nested structure, + # we just validate a lack of side effects. + module GeneratedCodeValidation + extend Private::Parse + + class ValidationError < RuntimeError; end + + def self.validate_deserialize(source) + parsed = parse(source) + + # def %(hash) + # ... + # end + assert_equal(:def, parsed.type) + name, args, body = parsed.children + assert_equal(:__t_props_generated_deserialize, name) + assert_equal(s(:args, s(:arg, :hash)), args) + + assert_equal(:begin, body.type) + init, *prop_clauses, ret = body.children + + # found = % + # ... + # found + assert_equal(:lvasgn, init.type) + init_name, init_val = init.children + assert_equal(:found, init_name) + assert_equal(:int, init_val.type) + assert_equal(s(:lvar, :found), ret) + + prop_clauses.each_with_index do |clause, i| + if i.even? + validate_deserialize_hash_read(clause) + else + validate_deserialize_ivar_set(clause) + end + end + end + + def self.validate_serialize(source) + parsed = parse(source) + + # def %(strict) + # ... + # end + assert_equal(:def, parsed.type) + name, args, body = parsed.children + assert_equal(:__t_props_generated_serialize, name) + assert_equal(s(:args, s(:arg, :strict)), args) + + assert_equal(:begin, body.type) + init, *prop_clauses, ret = body.children + + # h = {} + # ... + # h + assert_equal(s(:lvasgn, :h, s(:hash)), init) + assert_equal(s(:lvar, :h), ret) + + prop_clauses.each do |clause| + validate_serialize_clause(clause) + end + end + + private_class_method def self.validate_serialize_clause(clause) + assert_equal(:if, clause.type) + condition, if_body, else_body = clause.children + + # if @%.nil? + assert_equal(:send, condition.type) + receiver, method = condition.children + assert_equal(:ivar, receiver.type) + assert_equal(:nil?, method) + + unless if_body.nil? + # required_prop_missing_from_serialize(%) if strict + assert_equal(:if, if_body.type) + if_strict_condition, if_strict_body, if_strict_else = if_body.children + assert_equal(s(:lvar, :strict), if_strict_condition) + assert_equal(:send, if_strict_body.type) + on_strict_receiver, on_strict_method, on_strict_arg = if_strict_body.children + assert_equal(nil, on_strict_receiver) + assert_equal(:required_prop_missing_from_serialize, on_strict_method) + assert_equal(:sym, on_strict_arg.type) + assert_equal(nil, if_strict_else) + end + + # h[%] = ... + assert_equal(:send, else_body.type) + receiver, method, h_key, h_val = else_body.children + assert_equal(s(:lvar, :h), receiver) + assert_equal(:[]=, method) + assert_equal(:str, h_key.type) + + validate_lack_of_side_effects(h_val, whitelisted_methods_for_serialize) + end + + private_class_method def self.validate_deserialize_hash_read(clause) + # val = hash[%s] + + assert_equal(:lvasgn, clause.type) + name, val = clause.children + assert_equal(:val, name) + assert_equal(:send, val.type) + receiver, method, arg = val.children + assert_equal(s(:lvar, :hash), receiver) + assert_equal(:[], method) + assert_equal(:str, arg.type) + end + + private_class_method def self.validate_deserialize_ivar_set(clause) + # %s = if val.nil? + # found -= 1 unless hash.key?(%s) + # %s + # else + # %s + # end + + assert_equal(:ivasgn, clause.type) + ivar_name, deser_val = clause.children + unless ivar_name.is_a?(Symbol) + raise ValidationError.new("Unexpected ivar: #{ivar_name}") + end + + assert_equal(:if, deser_val.type) + condition, if_body, else_body = deser_val.children + assert_equal(s(:send, s(:lvar, :val), :nil?), condition) + + assert_equal(:begin, if_body.type) + update_found, handle_nil = if_body.children + assert_equal(:if, update_found.type) + found_condition, found_if_body, found_else_body = update_found.children + assert_equal(:send, found_condition.type) + receiver, method, arg = found_condition.children + assert_equal(s(:lvar, :hash), receiver) + assert_equal(:key?, method) + assert_equal(:str, arg.type) + assert_equal(nil, found_if_body) + assert_equal(s(:op_asgn, s(:lvasgn, :found), :-, s(:int, 1)), found_else_body) + + validate_deserialize_handle_nil(handle_nil) + + if else_body.type == :kwbegin + rescue_expression, = else_body.children + assert_equal(:rescue, rescue_expression.type) + + try, rescue_body = rescue_expression.children + validate_lack_of_side_effects(try, whitelisted_methods_for_deserialize) + + assert_equal(:resbody, rescue_body.type) + exceptions, assignment, handler = rescue_body.children + assert_equal(:array, exceptions.type) + exceptions.children.each {|c| assert_equal(:const, c.type)} + assert_equal(:lvasgn, assignment.type) + assert_equal([:e], assignment.children) + + deserialization_error, val_return = handler.children + + assert_equal(:send, deserialization_error.type) + receiver, method, *args = deserialization_error.children + assert_equal(nil, receiver) + assert_equal(:raise_deserialization_error, method) + args.each {|a| validate_lack_of_side_effects(a, whitelisted_methods_for_deserialize)} + + validate_lack_of_side_effects(val_return, whitelisted_methods_for_deserialize) + else + validate_lack_of_side_effects(else_body, whitelisted_methods_for_deserialize) + end + end + + private_class_method def self.validate_deserialize_handle_nil(node) + case node.type + when :hash, :array, :str, :sym, :int, :float, :true, :false, :nil, :const # rubocop:disable Lint/BooleanSymbol + # Primitives and constants are safe + when :send + receiver, method, arg = node.children + if receiver.nil? + # required_prop_missing_from_deserialize(%) + assert_equal(:required_prop_missing_from_deserialize, method) + assert_equal(:sym, arg.type) + elsif receiver == self_class_decorator + # self.class.decorator.raise_nil_deserialize_error(%) + assert_equal(:raise_nil_deserialize_error, method) + assert_equal(:str, arg.type) + elsif method == :default + # self.class.decorator.props_with_defaults.fetch(%).default + assert_equal(:send, receiver.type) + inner_receiver, inner_method, inner_arg = receiver.children + assert_equal( + s(:send, self_class_decorator, :props_with_defaults), + inner_receiver, + ) + assert_equal(:fetch, inner_method) + assert_equal(:sym, inner_arg.type) + else + raise ValidationError.new("Unexpected receiver in nil handler: #{node.inspect}") + end + else + raise ValidationError.new("Unexpected nil handler: #{node.inspect}") + end + end + + private_class_method def self.self_class_decorator + @self_class_decorator ||= s(:send, s(:send, s(:self), :class), :decorator).freeze + end + + private_class_method def self.validate_lack_of_side_effects(node, whitelisted_methods_by_receiver_type) + case node.type + when :const + # This is ok, because we'll have validated what method has been called + # if applicable + when :hash, :array, :str, :sym, :int, :float, :true, :false, :nil, :self # rubocop:disable Lint/BooleanSymbol + # Primitives & self are ok + when :lvar, :arg, :ivar + # Reading local & instance variables & arguments is ok + unless node.children.all? {|c| c.is_a?(Symbol)} + raise ValidationError.new("Unexpected child for #{node.type}: #{node.inspect}") + end + when :args, :mlhs, :block, :begin, :if + # Blocks etc are read-only if their contents are read-only + node.children.each {|c| validate_lack_of_side_effects(c, whitelisted_methods_by_receiver_type) if c} + when :send + # Sends are riskier so check a whitelist + receiver, method, *args = node.children + if receiver + if receiver.type == :send + key = receiver + else + key = receiver.type + validate_lack_of_side_effects(receiver, whitelisted_methods_by_receiver_type) + end + + if !whitelisted_methods_by_receiver_type[key]&.include?(method) + raise ValidationError.new("Unexpected method #{method} called on #{receiver.inspect}") + end + end + args.each do |arg| + validate_lack_of_side_effects(arg, whitelisted_methods_by_receiver_type) + end + else + raise ValidationError.new("Unexpected node type #{node.type}: #{node.inspect}") + end + end + + private_class_method def self.assert_equal(expected, actual) + if expected != actual + raise ValidationError.new("Expected #{expected}, got #{actual}") + end + end + + # Method calls generated by SerdeTransform + private_class_method def self.whitelisted_methods_for_serialize + @whitelisted_methods_for_serialize ||= { + lvar: %i{dup map transform_values transform_keys each_with_object nil? []= serialize}, + ivar: %i[dup map transform_values transform_keys each_with_object serialize], + const: %i[checked_serialize deep_clone_object], + } + end + + # Method calls generated by SerdeTransform + private_class_method def self.whitelisted_methods_for_deserialize + @whitelisted_methods_for_deserialize ||= { + lvar: %i{dup map transform_values transform_keys each_with_object nil? []= to_f}, + const: %i[deserialize from_hash deep_clone_object], + } + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/has_lazily_specialized_methods.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/has_lazily_specialized_methods.rb new file mode 100644 index 0000000000..5c1acecb69 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/has_lazily_specialized_methods.rb @@ -0,0 +1,140 @@ +# frozen_string_literal: true +# typed: false + +module T::Props + + # Helper for generating methods that replace themselves with a specialized + # version on first use. The main use case is when we want to generate a + # method using the full set of props on a class; we can't do that during + # prop definition because we have no way of knowing whether we are defining + # the last prop. + # + # See go/M8yrvzX2 (Stripe-internal) for discussion of security considerations. + # In outline, while `class_eval` is a bit scary, we believe that as long as + # all inputs are defined in version control (and this is enforced by calling + # `disable_lazy_evaluation!` appropriately), risk isn't significantly higher + # than with build-time codegen. + module HasLazilySpecializedMethods + extend T::Sig + + class SourceEvaluationDisabled < RuntimeError + def initialize + super("Evaluation of lazily-defined methods is disabled") + end + end + + # Disable any future evaluation of lazily-defined methods. + # + # This is intended to be called after startup but before interacting with + # the outside world, to limit attack surface for our `class_eval` use. + # + # Note it does _not_ prevent explicit calls to `eagerly_define_lazy_methods!` + # from working. + sig {void} + def self.disable_lazy_evaluation! + @lazy_evaluation_disabled ||= true + end + + sig {returns(T::Boolean)} + def self.lazy_evaluation_enabled? + !defined?(@lazy_evaluation_disabled) || !@lazy_evaluation_disabled + end + + module DecoratorMethods + extend T::Sig + + sig {returns(T::Hash[Symbol, T.proc.returns(String)]).checked(:never)} + private def lazily_defined_methods + @lazily_defined_methods ||= {} + end + + sig {returns(T::Hash[Symbol, T.untyped]).checked(:never)} + private def lazily_defined_vm_methods + @lazily_defined_vm_methods ||= {} + end + + sig {params(name: Symbol).void} + private def eval_lazily_defined_method!(name) + if !HasLazilySpecializedMethods.lazy_evaluation_enabled? + raise SourceEvaluationDisabled.new + end + + source = lazily_defined_methods.fetch(name).call + + cls = decorated_class + cls.class_eval(source.to_s) + cls.send(:private, name) + end + + sig {params(name: Symbol).void} + private def eval_lazily_defined_vm_method!(name) + if !HasLazilySpecializedMethods.lazy_evaluation_enabled? + raise SourceEvaluationDisabled.new + end + + lazily_defined_vm_methods.fetch(name).call + + cls = decorated_class + cls.send(:private, name) + end + + sig {params(name: Symbol, blk: T.proc.returns(String)).void} + private def enqueue_lazy_method_definition!(name, &blk) + lazily_defined_methods[name] = blk + + cls = decorated_class + if cls.method_defined?(name) + # Ruby does not emit "method redefined" warnings for aliased methods + # (more robust than undef_method that would create a small window in which the method doesn't exist) + cls.send(:alias_method, name, name) + end + cls.send(:define_method, name) do |*args| + self.class.decorator.send(:eval_lazily_defined_method!, name) + send(name, *args) + end + if cls.respond_to?(:ruby2_keywords, true) + cls.send(:ruby2_keywords, name) + end + cls.send(:private, name) + end + + sig {params(name: Symbol, blk: T.untyped).void} + private def enqueue_lazy_vm_method_definition!(name, &blk) + lazily_defined_vm_methods[name] = blk + + cls = decorated_class + cls.send(:define_method, name) do |*args| + self.class.decorator.send(:eval_lazily_defined_vm_method!, name) + send(name, *args) + end + if cls.respond_to?(:ruby2_keywords, true) + cls.send(:ruby2_keywords, name) + end + cls.send(:private, name) + end + + sig {void} + def eagerly_define_lazy_methods! + return if lazily_defined_methods.empty? + + source = lazily_defined_methods.values.map(&:call).map(&:to_s).join("\n\n") + + cls = decorated_class + cls.class_eval(source) + lazily_defined_methods.each_key {|name| cls.send(:private, name)} + lazily_defined_methods.clear + end + + sig {void} + def eagerly_define_lazy_vm_methods! + return if lazily_defined_vm_methods.empty? + + lazily_defined_vm_methods.values.map(&:call) + + cls = decorated_class + lazily_defined_vm_methods.each_key {|name| cls.send(:private, name)} + lazily_defined_vm_methods.clear + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/optional.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/optional.rb new file mode 100644 index 0000000000..4f482beac3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/optional.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true +# typed: false + +module T::Props::Optional + include T::Props::Plugin +end + +############################################## + +# NB: This must stay in the same file where T::Props::Optional is defined due to +# T::Props::Decorator#apply_plugin; see https://git.corp.stripe.com/stripe-internal/pay-server/blob/fc7f15593b49875f2d0499ffecfd19798bac05b3/chalk/odm/lib/chalk-odm/document_decorator.rb#L716-L717 +module T::Props::Optional::DecoratorMethods + extend T::Sig + + # Heads up! + # + # There are already too many ad-hoc options on the prop DSL. + # + # We have already done a lot of work to remove unnecessary and confusing + # options. If you're considering adding a new rule key, please come chat with + # the Sorbet team first, as we'd really like to learn more about how to best + # solve the problem you're encountering. + VALID_RULE_KEYS = { + default: true, + factory: true, + }.freeze + private_constant :VALID_RULE_KEYS + + DEFAULT_SETTER_RULE_KEY = :_t_props_private_apply_default + private_constant :DEFAULT_SETTER_RULE_KEY + + def valid_rule_key?(key) + super || VALID_RULE_KEYS[key] + end + + def prop_optional?(prop) + prop_rules(prop)[:fully_optional] + end + + def compute_derived_rules(rules) + rules[:fully_optional] = !T::Props::Utils.need_nil_write_check?(rules) + rules[:need_nil_read_check] = T::Props::Utils.need_nil_read_check?(rules) + end + + # checked(:never) - O(runtime object construction) + sig {returns(T::Hash[Symbol, T::Props::Private::ApplyDefault]).checked(:never)} + attr_reader :props_with_defaults + + # checked(:never) - O(runtime object construction) + sig {returns(T::Hash[Symbol, T::Props::Private::SetterFactory::SetterProc]).checked(:never)} + attr_reader :props_without_defaults + + def add_prop_definition(prop, rules) + compute_derived_rules(rules) + + default_setter = T::Props::Private::ApplyDefault.for(decorated_class, rules) + if default_setter + @props_with_defaults ||= {} + @props_with_defaults[prop] = default_setter + props_without_defaults&.delete(prop) # Handle potential override + + rules[DEFAULT_SETTER_RULE_KEY] = default_setter + else + @props_without_defaults ||= {} + @props_without_defaults[prop] = rules.fetch(:setter_proc) + props_with_defaults&.delete(prop) # Handle potential override + end + + super + end + + def prop_validate_definition!(name, cls, rules, type) + result = super + + if rules.key?(:default) && rules.key?(:factory) + raise ArgumentError.new("Setting both :default and :factory is invalid. See: go/chalk-docs") + end + + result + end + + def has_default?(rules) + rules.include?(DEFAULT_SETTER_RULE_KEY) + end + + def get_default(rules, instance_class) + rules[DEFAULT_SETTER_RULE_KEY]&.default + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/plugin.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/plugin.rb new file mode 100644 index 0000000000..1423c172ed --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/plugin.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true +# typed: false + +module T::Props::Plugin + include T::Props + extend T::Helpers + + module ClassMethods + def included(child) + super + child.plugin(self) + end + end + mixes_in_class_methods(ClassMethods) + + module Private + # These need to be non-instance methods so we can use them without prematurely creating the + # child decorator in `model_inherited` (see comments there for details). + # + # The dynamic constant access below forces this file to be `typed: false` + def self.apply_class_methods(plugin, target) + if plugin.const_defined?('ClassMethods') + # FIXME: This will break preloading, selective test execution, etc if `mod::ClassMethods` + # is ever defined in a separate file from `mod`. + target.extend(plugin::ClassMethods) + end + end + + def self.apply_decorator_methods(plugin, target) + if plugin.const_defined?('DecoratorMethods') + # FIXME: This will break preloading, selective test execution, etc if `mod::DecoratorMethods` + # is ever defined in a separate file from `mod`. + target.extend(plugin::DecoratorMethods) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/pretty_printable.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/pretty_printable.rb new file mode 100644 index 0000000000..e821cd3435 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/pretty_printable.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true +# typed: true + +module T::Props::PrettyPrintable + include T::Props::Plugin + + # Return a string representation of this object and all of its props + def inspect + T.unsafe(T.cast(self, Object).class).decorator.inspect_instance(self) + end + + # Override the PP gem with something that's similar, but gives us a hook + # to do redaction + def pretty_inspect + T.unsafe(T.cast(self, Object).class).decorator.inspect_instance(self, multiline: true) + end + + module DecoratorMethods + extend T::Sig + + sig {params(key: Symbol).returns(T::Boolean).checked(:never)} + def valid_rule_key?(key) + super || key == :inspect + end + + sig do + params(instance: T::Props::PrettyPrintable, multiline: T::Boolean, indent: String) + .returns(String) + end + def inspect_instance(instance, multiline: false, indent: ' ') + components = + inspect_instance_components( + instance, + multiline: multiline, + indent: indent + ) + .reject(&:empty?) + + # Not using #<> here as that makes pry highlight these objects + # as if they were all comments, whereas this makes them look + # like the structured thing they are. + if multiline + "#{components[0]}:\n" + T.must(components[1..-1]).join("\n") + else + "<#{components.join(' ')}>" + end + end + + sig do + params(instance: T::Props::PrettyPrintable, multiline: T::Boolean, indent: String) + .returns(T::Array[String]) + end + private def inspect_instance_components(instance, multiline:, indent:) + pretty_props = T.unsafe(self).all_props.map do |prop| + [prop, inspect_prop_value(instance, prop, multiline: multiline, indent: indent)] + end + + joined_props = join_props_with_pretty_values( + pretty_props, + multiline: multiline, + indent: indent + ) + + [ + T.unsafe(self).decorated_class.to_s, + joined_props, + ] + end + + sig do + params(instance: T::Props::PrettyPrintable, prop: Symbol, multiline: T::Boolean, indent: String) + .returns(String) + .checked(:never) + end + private def inspect_prop_value(instance, prop, multiline:, indent:) + val = T.unsafe(self).get(instance, prop) + rules = T.unsafe(self).prop_rules(prop) + if (custom_inspect = rules[:inspect]) + if T::Utils.arity(custom_inspect) == 1 + custom_inspect.call(val) + else + custom_inspect.call(val, {multiline: multiline, indent: indent}) + end + elsif rules[:sensitivity] && !rules[:sensitivity].empty? && !val.nil? + "" + else + val.inspect + end + end + + sig do + params(pretty_kvs: T::Array[[Symbol, String]], multiline: T::Boolean, indent: String) + .returns(String) + end + private def join_props_with_pretty_values(pretty_kvs, multiline:, indent: ' ') + pairs = pretty_kvs + .sort_by {|k, _v| k.to_s} + .map {|k, v| "#{k}=#{v}"} + + if multiline + indent + pairs.join("\n#{indent}") + else + pairs.join(', ') + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/apply_default.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/apply_default.rb new file mode 100644 index 0000000000..b86f506f9a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/apply_default.rb @@ -0,0 +1,170 @@ +# frozen_string_literal: true +# typed: strict + +module T::Props + module Private + class ApplyDefault + extend T::Sig + extend T::Helpers + abstract! + + # checked(:never) - O(object construction x prop count) + sig {returns(SetterFactory::SetterProc).checked(:never)} + attr_reader :setter_proc + + # checked(:never) - We do this with `T.let` instead + sig {params(accessor_key: Symbol, setter_proc: SetterFactory::SetterProc).void.checked(:never)} + def initialize(accessor_key, setter_proc) + @accessor_key = T.let(accessor_key, Symbol) + @setter_proc = T.let(setter_proc, SetterFactory::SetterProc) + end + + # checked(:never) - O(object construction x prop count) + sig {abstract.returns(T.untyped).checked(:never)} + def default; end + + # checked(:never) - O(object construction x prop count) + sig {abstract.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never)} + def set_default(instance); end + + NO_CLONE_TYPES = T.let([TrueClass, FalseClass, NilClass, Symbol, Numeric, T::Enum].freeze, T::Array[Module]) + + # checked(:never) - Rules hash is expensive to check + sig {params(cls: Module, rules: T::Hash[Symbol, T.untyped]).returns(T.nilable(ApplyDefault)).checked(:never)} + def self.for(cls, rules) + accessor_key = rules.fetch(:accessor_key) + setter = rules.fetch(:setter_proc) + + if rules.key?(:factory) + ApplyDefaultFactory.new(cls, rules.fetch(:factory), accessor_key, setter) + elsif rules.key?(:default) + default = rules.fetch(:default) + case default + when *NO_CLONE_TYPES + return ApplyPrimitiveDefault.new(default, accessor_key, setter) + when String + if default.frozen? + return ApplyPrimitiveDefault.new(default, accessor_key, setter) + end + when Array + if default.empty? && default.class == Array + return ApplyEmptyArrayDefault.new(accessor_key, setter) + end + when Hash + if default.empty? && default.default.nil? && T.unsafe(default).default_proc.nil? && default.class == Hash + return ApplyEmptyHashDefault.new(accessor_key, setter) + end + end + + ApplyComplexDefault.new(default, accessor_key, setter) + else + nil + end + end + end + + class ApplyFixedDefault < ApplyDefault + abstract! + + # checked(:never) - We do this with `T.let` instead + sig {params(default: BasicObject, accessor_key: Symbol, setter_proc: SetterFactory::SetterProc).void.checked(:never)} + def initialize(default, accessor_key, setter_proc) + # FIXME: Ideally we'd check here that the default is actually a valid + # value for this field, but existing code relies on the fact that we don't. + # + # :( + # + # setter_proc.call(default) + @default = T.let(default, BasicObject) + super(accessor_key, setter_proc) + end + + # checked(:never) - O(object construction x prop count) + sig {override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never)} + def set_default(instance) + instance.instance_variable_set(@accessor_key, default) + end + end + + class ApplyPrimitiveDefault < ApplyFixedDefault + # checked(:never) - O(object construction x prop count) + sig {override.returns(T.untyped).checked(:never)} + attr_reader :default + end + + class ApplyComplexDefault < ApplyFixedDefault + # checked(:never) - O(object construction x prop count) + sig {override.returns(T.untyped).checked(:never)} + def default + T::Props::Utils.deep_clone_object(@default) + end + end + + # Special case since it's so common, and a literal `[]` is meaningfully + # faster than falling back to ApplyComplexDefault or even calling + # `some_empty_array.dup` + class ApplyEmptyArrayDefault < ApplyDefault + # checked(:never) - O(object construction x prop count) + sig {override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never)} + def set_default(instance) + instance.instance_variable_set(@accessor_key, []) + end + + # checked(:never) - O(object construction x prop count) + sig {override.returns(T::Array[T.untyped]).checked(:never)} + def default + [] + end + end + + # Special case since it's so common, and a literal `{}` is meaningfully + # faster than falling back to ApplyComplexDefault or even calling + # `some_empty_hash.dup` + class ApplyEmptyHashDefault < ApplyDefault + # checked(:never) - O(object construction x prop count) + sig {override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never)} + def set_default(instance) + instance.instance_variable_set(@accessor_key, {}) + end + + # checked(:never) - O(object construction x prop count) + sig {override.returns(T::Hash[T.untyped, T.untyped]).checked(:never)} + def default + {} + end + end + + class ApplyDefaultFactory < ApplyDefault + # checked(:never) - We do this with `T.let` instead + sig do + params( + cls: Module, + factory: T.any(Proc, Method), + accessor_key: Symbol, + setter_proc: SetterFactory::SetterProc, + ) + .void + .checked(:never) + end + def initialize(cls, factory, accessor_key, setter_proc) + @class = T.let(cls, Module) + @factory = T.let(factory, T.any(Proc, Method)) + super(accessor_key, setter_proc) + end + + # checked(:never) - O(object construction x prop count) + sig {override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never)} + def set_default(instance) + # Use the actual setter to validate the factory returns a legitimate + # value every time + instance.instance_exec(default, &@setter_proc) + end + + # checked(:never) - O(object construction x prop count) + sig {override.returns(T.untyped).checked(:never)} + def default + @class.class_exec(&@factory) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/deserializer_generator.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/deserializer_generator.rb new file mode 100644 index 0000000000..2393e1a284 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/deserializer_generator.rb @@ -0,0 +1,160 @@ +# frozen_string_literal: true +# typed: strict + +module T::Props + module Private + + # Generates a specialized `deserialize` implementation for a subclass of + # T::Props::Serializable. + # + # The basic idea is that we analyze the props and for each prop, generate + # the simplest possible logic as a block of Ruby source, so that we don't + # pay the cost of supporting types like T:::Hash[CustomType, SubstructType] + # when deserializing a simple Integer. Then we join those together, + # with a little shared logic to be able to detect when we get input keys + # that don't match any prop. + module DeserializerGenerator + extend T::Sig + + # Generate a method that takes a T::Hash[String, T.untyped] representing + # serialized props, sets instance variables for each prop found in the + # input, and returns the count of we props set (which we can use to check + # for unexpected input keys with minimal effect on the fast path). + sig do + params( + props: T::Hash[Symbol, T::Hash[Symbol, T.untyped]], + defaults: T::Hash[Symbol, T::Props::Private::ApplyDefault], + ) + .returns(String) + .checked(:never) + end + def self.generate(props, defaults) + stored_props = props.reject {|_, rules| rules[:dont_store]} + parts = stored_props.map do |prop, rules| + # All of these strings should already be validated (directly or + # indirectly) in `validate_prop_name`, so we don't bother with a nice + # error message, but we double check here to prevent a refactoring + # from introducing a security vulnerability. + raise unless T::Props::Decorator::SAFE_NAME.match?(prop.to_s) + + hash_key = rules.fetch(:serialized_form) + raise unless T::Props::Decorator::SAFE_NAME.match?(hash_key) + + ivar_name = rules.fetch(:accessor_key).to_s + raise unless ivar_name.start_with?('@') && T::Props::Decorator::SAFE_NAME.match?(ivar_name[1..-1]) + + transformation = SerdeTransform.generate( + T::Utils::Nilable.get_underlying_type_object(rules.fetch(:type_object)), + SerdeTransform::Mode::DESERIALIZE, + 'val' + ) + transformed_val = if transformation + # Rescuing exactly NoMethodError is intended as a temporary hack + # to preserve the semantics from before codegen. More generally + # we are inconsistent about typechecking on deser and need to decide + # our strategy here. + <<~RUBY + begin + #{transformation} + rescue NoMethodError => e + raise_deserialization_error( + #{prop.inspect}, + val, + e, + ) + val + end + RUBY + else + 'val' + end + + nil_handler = generate_nil_handler( + prop: prop, + serialized_form: hash_key, + default: defaults[prop], + nilable_type: T::Props::Utils.optional_prop?(rules), + raise_on_nil_write: !!rules[:raise_on_nil_write], + ) + + <<~RUBY + val = hash[#{hash_key.inspect}] + #{ivar_name} = if val.nil? + found -= 1 unless hash.key?(#{hash_key.inspect}) + #{nil_handler} + else + #{transformed_val} + end + RUBY + end + + <<~RUBY + def __t_props_generated_deserialize(hash) + found = #{stored_props.size} + #{parts.join("\n\n")} + found + end + RUBY + end + + # This is very similar to what we do in ApplyDefault, but has a few + # key differences that mean we don't just re-use the code: + # + # 1. Where the logic in construction is that we generate a default + # if & only if the prop key isn't present in the input, here we'll + # generate a default even to override an explicit nil, but only + # if the prop is actually required. + # 2. Since we're generating raw Ruby source, we can remove a layer + # of indirection for marginally better performance; this seems worth + # it for the common cases of literals and empty arrays/hashes. + # 3. We need to care about the distinction between `raise_on_nil_write` + # and actually non-nilable, where new-instance construction doesn't. + # + # So we fall back to ApplyDefault only when one of the cases just + # mentioned doesn't apply. + sig do + params( + prop: Symbol, + serialized_form: String, + default: T.nilable(ApplyDefault), + nilable_type: T::Boolean, + raise_on_nil_write: T::Boolean, + ) + .returns(String) + .checked(:never) + end + private_class_method def self.generate_nil_handler( + prop:, + serialized_form:, + default:, + nilable_type:, + raise_on_nil_write: + ) + if !nilable_type + case default + when NilClass + "self.class.decorator.raise_nil_deserialize_error(#{serialized_form.inspect})" + when ApplyPrimitiveDefault + literal = default.default + case literal + when String, Integer, Symbol, Float, TrueClass, FalseClass, NilClass + literal.inspect + else + "self.class.decorator.props_with_defaults.fetch(#{prop.inspect}).default" + end + when ApplyEmptyArrayDefault + '[]' + when ApplyEmptyHashDefault + '{}' + else + "self.class.decorator.props_with_defaults.fetch(#{prop.inspect}).default" + end + elsif raise_on_nil_write + "required_prop_missing_from_deserialize(#{prop.inspect})" + else + 'nil' + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/parser.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/parser.rb new file mode 100644 index 0000000000..2ccd574118 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/parser.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true +# typed: false + +module T::Props + module Private + module Parse + def parse(source) + @current_ruby ||= require_parser(:CurrentRuby) + @current_ruby.parse(source) + end + + def s(type, *children) + @node ||= require_parser(:AST, :Node) + @node.new(type, children) + end + + private def require_parser(*constants) + # This is an optional dependency for sorbet-runtime in general, + # but is required here + require 'parser/current' + + # Hack to work around the static checker thinking the constant is + # undefined + cls = Kernel.const_get(:Parser, true) + while (const = constants.shift) + cls = cls.const_get(const, false) + end + cls + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/serde_transform.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/serde_transform.rb new file mode 100644 index 0000000000..e0b37a376d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/serde_transform.rb @@ -0,0 +1,186 @@ +# frozen_string_literal: true +# typed: strict + +module T::Props + module Private + module SerdeTransform + extend T::Sig + + class Serialize; end + private_constant :Serialize + class Deserialize; end + private_constant :Deserialize + ModeType = T.type_alias {T.any(Serialize, Deserialize)} + private_constant :ModeType + + module Mode + SERIALIZE = T.let(Serialize.new.freeze, Serialize) + DESERIALIZE = T.let(Deserialize.new.freeze, Deserialize) + end + + NO_TRANSFORM_TYPES = T.let( + [TrueClass, FalseClass, NilClass, Symbol, String].freeze, + T::Array[Module], + ) + private_constant :NO_TRANSFORM_TYPES + + sig do + params( + type: T::Types::Base, + mode: ModeType, + varname: String, + ) + .returns(T.nilable(String)) + .checked(:never) + end + def self.generate(type, mode, varname) + case type + when T::Types::TypedArray + inner = generate(type.type, mode, 'v') + if inner.nil? + "#{varname}.dup" + else + "#{varname}.map {|v| #{inner}}" + end + when T::Types::TypedSet + inner = generate(type.type, mode, 'v') + if inner.nil? + "#{varname}.dup" + else + "Set.new(#{varname}) {|v| #{inner}}" + end + when T::Types::TypedHash + keys = generate(type.keys, mode, 'k') + values = generate(type.values, mode, 'v') + if keys && values + "#{varname}.each_with_object({}) {|(k,v),h| h[#{keys}] = #{values}}" + elsif keys + "#{varname}.transform_keys {|k| #{keys}}" + elsif values + "#{varname}.transform_values {|v| #{values}}" + else + "#{varname}.dup" + end + when T::Types::Simple + raw = type.raw_type + if NO_TRANSFORM_TYPES.any? {|cls| raw <= cls} + nil + elsif raw <= Float + case mode + when Deserialize then "#{varname}.to_f" + when Serialize then nil + else T.absurd(mode) + end + elsif raw <= Numeric + nil + elsif raw < T::Props::Serializable + handle_serializable_subtype(varname, raw, mode) + elsif raw.singleton_class < T::Props::CustomType + handle_custom_type(varname, T.unsafe(raw), mode) + elsif T::Configuration.scalar_types.include?(raw.name) + # It's a bit of a hack that this is separate from NO_TRANSFORM_TYPES + # and doesn't check inheritance (like `T::Props::CustomType.scalar_type?` + # does), but it covers the main use case (pay-server's custom `Boolean` + # module) without either requiring `T::Configuration.scalar_types` to + # accept modules instead of strings (which produces load-order issues + # and subtle behavior changes) or eating the performance cost of doing + # an inheritance check by manually crawling a class hierarchy and doing + # string comparisons. + nil + else + "T::Props::Utils.deep_clone_object(#{varname})" + end + when T::Types::Union + non_nil_type = T::Utils.unwrap_nilable(type) + if non_nil_type + inner = generate(non_nil_type, mode, varname) + if inner.nil? + nil + else + "#{varname}.nil? ? nil : #{inner}" + end + elsif type.types.all? {|t| generate(t, mode, varname).nil?} + # Handle, e.g., T::Boolean + nil + else + # We currently deep_clone_object if the type was T.any(Integer, Float). + # When we get better support for union types (maybe this specific + # union type, because it would be a replacement for + # Chalk::ODM::DeprecatedNumemric), we could opt to special case + # this union to have no specific serde transform (the only reason + # why Float has a special case is because round tripping through + # JSON might normalize Floats to Integers) + "T::Props::Utils.deep_clone_object(#{varname})" + end + when T::Types::Intersection + dynamic_fallback = "T::Props::Utils.deep_clone_object(#{varname})" + + # Transformations for any members of the intersection type where we + # know what we need to do and did not have to fall back to the + # dynamic deep clone method. + # + # NB: This deliberately does include `nil`, which means we know we + # don't need to do any transforming. + inner_known = type.types + .map {|t| generate(t, mode, varname)} + .reject {|t| t == dynamic_fallback} + .uniq + + if inner_known.size != 1 + # If there were no cases where we could tell what we need to do, + # e.g. if this is `T.all(SomethingWeird, WhoKnows)`, just use the + # dynamic fallback. + # + # If there were multiple cases and they weren't consistent, e.g. + # if this is `T.all(String, T::Array[Integer])`, the type is probably + # bogus/uninhabited, but use the dynamic fallback because we still + # don't have a better option, and this isn't the place to raise that + # error. + dynamic_fallback + else + # This is probably something like `T.all(String, SomeMarker)` or + # `T.all(SomeEnum, T.deprecated_enum(SomeEnum::FOO))` and we should + # treat it like String or SomeEnum even if we don't know what to do + # with the rest of the type. + inner_known.first + end + when T::Types::Enum + generate(T::Utils.lift_enum(type), mode, varname) + else + "T::Props::Utils.deep_clone_object(#{varname})" + end + end + + sig {params(varname: String, type: Module, mode: ModeType).returns(String).checked(:never)} + private_class_method def self.handle_serializable_subtype(varname, type, mode) + case mode + when Serialize + "#{varname}.serialize(strict)" + when Deserialize + type_name = T.must(module_name(type)) + "#{type_name}.from_hash(#{varname})" + else + T.absurd(mode) + end + end + + sig {params(varname: String, type: Module, mode: ModeType).returns(String).checked(:never)} + private_class_method def self.handle_custom_type(varname, type, mode) + case mode + when Serialize + "T::Props::CustomType.checked_serialize(#{varname})" + when Deserialize + type_name = T.must(module_name(type)) + "#{type_name}.deserialize(#{varname})" + else + T.absurd(mode) + end + end + + sig {params(type: Module).returns(T.nilable(String)).checked(:never)} + private_class_method def self.module_name(type) + T::Configuration.module_name_mangler.call(type) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/serializer_generator.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/serializer_generator.rb new file mode 100644 index 0000000000..0d49a46e0f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/serializer_generator.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true +# typed: strict + +module T::Props + module Private + + # Generates a specialized `serialize` implementation for a subclass of + # T::Props::Serializable. + # + # The basic idea is that we analyze the props and for each prop, generate + # the simplest possible logic as a block of Ruby source, so that we don't + # pay the cost of supporting types like T:::Hash[CustomType, SubstructType] + # when serializing a simple Integer. Then we join those together, + # with a little shared logic to be able to detect when we get input keys + # that don't match any prop. + module SerializerGenerator + extend T::Sig + + sig do + params( + props: T::Hash[Symbol, T::Hash[Symbol, T.untyped]], + ) + .returns(String) + .checked(:never) + end + def self.generate(props) + stored_props = props.reject {|_, rules| rules[:dont_store]} + parts = stored_props.map do |prop, rules| + # All of these strings should already be validated (directly or + # indirectly) in `validate_prop_name`, so we don't bother with a nice + # error message, but we double check here to prevent a refactoring + # from introducing a security vulnerability. + raise unless T::Props::Decorator::SAFE_NAME.match?(prop.to_s) + + hash_key = rules.fetch(:serialized_form) + raise unless T::Props::Decorator::SAFE_NAME.match?(hash_key) + + ivar_name = rules.fetch(:accessor_key).to_s + raise unless ivar_name.start_with?('@') && T::Props::Decorator::SAFE_NAME.match?(ivar_name[1..-1]) + + transformed_val = SerdeTransform.generate( + T::Utils::Nilable.get_underlying_type_object(rules.fetch(:type_object)), + SerdeTransform::Mode::SERIALIZE, + ivar_name + ) || ivar_name + + nil_asserter = + if rules[:fully_optional] + '' + else + "required_prop_missing_from_serialize(#{prop.inspect}) if strict" + end + + # Don't serialize values that are nil to save space (both the + # nil value itself and the field name in the serialized BSON + # document) + <<~RUBY + if #{ivar_name}.nil? + #{nil_asserter} + else + h[#{hash_key.inspect}] = #{transformed_val} + end + RUBY + end + + <<~RUBY + def __t_props_generated_serialize(strict) + h = {} + #{parts.join("\n\n")} + h + end + RUBY + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/setter_factory.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/setter_factory.rb new file mode 100644 index 0000000000..00c76ed1e7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/private/setter_factory.rb @@ -0,0 +1,197 @@ +# frozen_string_literal: true +# typed: strict + +module T::Props + module Private + module SetterFactory + extend T::Sig + + SetterProc = T.type_alias {T.proc.params(val: T.untyped).void} + ValidateProc = T.type_alias {T.proc.params(prop: Symbol, value: T.untyped).void} + + sig do + params( + klass: T.all(Module, T::Props::ClassMethods), + prop: Symbol, + rules: T::Hash[Symbol, T.untyped] + ) + .returns(SetterProc) + .checked(:never) + end + def self.build_setter_proc(klass, prop, rules) + # Our nil check works differently than a simple T.nilable for various + # reasons (including the `raise_on_nil_write` setting and the existence + # of defaults & factories), so unwrap any T.nilable and do a check + # manually. + non_nil_type = T::Utils::Nilable.get_underlying_type_object(rules.fetch(:type_object)) + accessor_key = rules.fetch(:accessor_key) + validate = rules[:setter_validate] + + # It seems like a bug that this affects the behavior of setters, but + # some existing code relies on this behavior + has_explicit_nil_default = rules.key?(:default) && rules.fetch(:default).nil? + + # Use separate methods in order to ensure that we only close over necessary + # variables + if !T::Props::Utils.need_nil_write_check?(rules) || has_explicit_nil_default + if validate.nil? && non_nil_type.is_a?(T::Types::Simple) + simple_nilable_proc(prop, accessor_key, non_nil_type.raw_type, klass) + else + nilable_proc(prop, accessor_key, non_nil_type, klass, validate) + end + else + if validate.nil? && non_nil_type.is_a?(T::Types::Simple) + simple_non_nil_proc(prop, accessor_key, non_nil_type.raw_type, klass) + else + non_nil_proc(prop, accessor_key, non_nil_type, klass, validate) + end + end + end + + sig do + params( + prop: Symbol, + accessor_key: Symbol, + non_nil_type: Module, + klass: T.all(Module, T::Props::ClassMethods), + ) + .returns(SetterProc) + end + private_class_method def self.simple_non_nil_proc(prop, accessor_key, non_nil_type, klass) + proc do |val| + unless val.is_a?(non_nil_type) + T::Props::Private::SetterFactory.raise_pretty_error( + klass, + prop, + T::Utils.coerce(non_nil_type), + val, + ) + end + instance_variable_set(accessor_key, val) + end + end + + sig do + params( + prop: Symbol, + accessor_key: Symbol, + non_nil_type: T::Types::Base, + klass: T.all(Module, T::Props::ClassMethods), + validate: T.nilable(ValidateProc) + ) + .returns(SetterProc) + end + private_class_method def self.non_nil_proc(prop, accessor_key, non_nil_type, klass, validate) + proc do |val| + # this use of recursively_valid? is intentional: unlike for + # methods, we want to make sure data at the 'edge' + # (e.g. models that go into databases or structs serialized + # from disk) are correct, so we use more thorough runtime + # checks there + if non_nil_type.recursively_valid?(val) + validate&.call(prop, val) + else + T::Props::Private::SetterFactory.raise_pretty_error( + klass, + prop, + non_nil_type, + val, + ) + end + instance_variable_set(accessor_key, val) + end + end + + sig do + params( + prop: Symbol, + accessor_key: Symbol, + non_nil_type: Module, + klass: T.all(Module, T::Props::ClassMethods), + ) + .returns(SetterProc) + end + private_class_method def self.simple_nilable_proc(prop, accessor_key, non_nil_type, klass) + proc do |val| + if val.nil? + instance_variable_set(accessor_key, nil) + elsif val.is_a?(non_nil_type) + instance_variable_set(accessor_key, val) + else + T::Props::Private::SetterFactory.raise_pretty_error( + klass, + prop, + T::Utils.coerce(non_nil_type), + val, + ) + instance_variable_set(accessor_key, val) + end + end + end + + sig do + params( + prop: Symbol, + accessor_key: Symbol, + non_nil_type: T::Types::Base, + klass: T.all(Module, T::Props::ClassMethods), + validate: T.nilable(ValidateProc), + ) + .returns(SetterProc) + end + private_class_method def self.nilable_proc(prop, accessor_key, non_nil_type, klass, validate) + proc do |val| + if val.nil? + instance_variable_set(accessor_key, nil) + # this use of recursively_valid? is intentional: unlike for + # methods, we want to make sure data at the 'edge' + # (e.g. models that go into databases or structs serialized + # from disk) are correct, so we use more thorough runtime + # checks there + elsif non_nil_type.recursively_valid?(val) + validate&.call(prop, val) + instance_variable_set(accessor_key, val) + else + T::Props::Private::SetterFactory.raise_pretty_error( + klass, + prop, + non_nil_type, + val, + ) + instance_variable_set(accessor_key, val) + end + end + end + + sig do + params( + klass: T.all(Module, T::Props::ClassMethods), + prop: Symbol, + type: T.any(T::Types::Base, Module), + val: T.untyped, + ) + .void + end + def self.raise_pretty_error(klass, prop, type, val) + base_message = "Can't set #{klass.name}.#{prop} to #{val.inspect} (instance of #{val.class}) - need a #{type}" + + pretty_message = "Parameter '#{prop}': #{base_message}\n" + caller_loc = caller_locations&.find {|l| !l.to_s.include?('sorbet-runtime/lib/types/props')} + if caller_loc + pretty_message += "Caller: #{caller_loc.path}:#{caller_loc.lineno}\n" + end + + T::Configuration.call_validation_error_handler( + nil, + message: base_message, + pretty_message: pretty_message, + kind: 'Parameter', + name: prop, + type: type, + value: val, + location: caller_loc, + ) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/serializable.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/serializable.rb new file mode 100644 index 0000000000..2e2ea1b749 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/serializable.rb @@ -0,0 +1,374 @@ +# frozen_string_literal: true +# typed: false + +module T::Props::Serializable + include T::Props::Plugin + # Required because we have special handling for `optional: false` + include T::Props::Optional + # Required because we have special handling for extra_props + include T::Props::PrettyPrintable + + # Serializes this object to a hash, suitable for conversion to + # JSON/BSON. + # + # @param strict [T::Boolean] (true) If false, do not raise an + # exception if this object has mandatory props with missing + # values. + # @return [Hash] A serialization of this object. + def serialize(strict=true) + begin + h = __t_props_generated_serialize(strict) + rescue => e + msg = self.class.decorator.message_with_generated_source_context( + e, + :__t_props_generated_serialize, + :generate_serialize_source + ) + if msg + begin + raise e.class.new(msg) + rescue ArgumentError + raise TypeError.new(msg) + end + else + raise + end + end + + h.merge!(@_extra_props) if defined?(@_extra_props) + h + end + + private def __t_props_generated_serialize(strict) + # No-op; will be overridden if there are any props. + # + # To see the definition for class `Foo`, run `Foo.decorator.send(:generate_serialize_source)` + {} + end + + # Populates the property values on this object with the values + # from a hash. In general, prefer to use {.from_hash} to construct + # a new instance, instead of loading into an existing instance. + # + # @param hash [Hash] The hash to take property + # values from. + # @param strict [T::Boolean] (false) If true, raise an exception if + # the hash contains keys that do not correspond to any known + # props on this instance. + # @return [void] + def deserialize(hash, strict=false) + begin + hash_keys_matching_props = __t_props_generated_deserialize(hash) + rescue => e + msg = self.class.decorator.message_with_generated_source_context( + e, + :__t_props_generated_deserialize, + :generate_deserialize_source + ) + if msg + begin + raise e.class.new(msg) + rescue ArgumentError + raise TypeError.new(msg) + end + else + raise + end + end + + if hash.size > hash_keys_matching_props + serialized_forms = self.class.decorator.prop_by_serialized_forms + extra = hash.reject {|k, _| serialized_forms.key?(k)} + + # `extra` could still be empty here if the input matches a `dont_store` prop; + # historically, we just ignore those + if !extra.empty? + if strict + raise "Unknown properties for #{self.class.name}: #{extra.keys.inspect}" + else + @_extra_props = extra + end + end + end + end + + private def __t_props_generated_deserialize(hash) + # No-op; will be overridden if there are any props. + # + # To see the definition for class `Foo`, run `Foo.decorator.send(:generate_deserialize_source)` + 0 + end + + # with() will clone the old object to the new object and merge the specified props to the new object. + def with(changed_props) + with_existing_hash(changed_props, existing_hash: self.serialize) + end + + private def recursive_stringify_keys(obj) + if obj.is_a?(Hash) + new_obj = obj.class.new + obj.each do |k, v| + new_obj[k.to_s] = recursive_stringify_keys(v) + end + elsif obj.is_a?(Array) + new_obj = obj.map {|v| recursive_stringify_keys(v)} + else + new_obj = obj + end + new_obj + end + + private def with_existing_hash(changed_props, existing_hash:) + serialized = existing_hash + new_val = self.class.from_hash(serialized.merge(recursive_stringify_keys(changed_props))) + old_extra = self.instance_variable_get(:@_extra_props) if self.instance_variable_defined?(:@_extra_props) + new_extra = new_val.instance_variable_get(:@_extra_props) if new_val.instance_variable_defined?(:@_extra_props) + if old_extra != new_extra + difference = + if old_extra + new_extra.reject {|k, v| old_extra[k] == v} + else + new_extra + end + raise ArgumentError.new("Unexpected arguments: input(#{changed_props}), unexpected(#{difference})") + end + new_val + end + + # Asserts if this property is missing during strict serialize + private def required_prop_missing_from_serialize(prop) + if defined?(@_required_props_missing_from_deserialize) && + @_required_props_missing_from_deserialize&.include?(prop) + # If the prop was already missing during deserialization, that means the application + # code already had to deal with a nil value, which means we wouldn't be accomplishing + # much by raising here (other than causing an unnecessary breakage). + T::Configuration.log_info_handler( + "chalk-odm: missing required property in serialize", + prop: prop, class: self.class.name, id: self.class.decorator.get_id(self) + ) + else + raise TypeError.new("#{self.class.name}.#{prop} not set for non-optional prop") + end + end + + # Marks this property as missing during deserialize + private def required_prop_missing_from_deserialize(prop) + @_required_props_missing_from_deserialize ||= Set[] + @_required_props_missing_from_deserialize << prop + nil + end + + private def raise_deserialization_error(prop_name, value, orig_error) + T::Configuration.soft_assert_handler( + 'Deserialization error (probably unexpected stored type)', + storytime: { + klass: self.class, + prop: prop_name, + value: value, + error: orig_error.message, + notify: 'djudd' + } + ) + end +end + +############################################## + +# NB: This must stay in the same file where T::Props::Serializable is defined due to +# T::Props::Decorator#apply_plugin; see https://git.corp.stripe.com/stripe-internal/pay-server/blob/fc7f15593b49875f2d0499ffecfd19798bac05b3/chalk/odm/lib/chalk-odm/document_decorator.rb#L716-L717 +module T::Props::Serializable::DecoratorMethods + include T::Props::HasLazilySpecializedMethods::DecoratorMethods + + # Heads up! + # + # There are already too many ad-hoc options on the prop DSL. + # + # We have already done a lot of work to remove unnecessary and confusing + # options. If you're considering adding a new rule key, please come chat with + # the Sorbet team first, as we'd really like to learn more about how to best + # solve the problem you're encountering. + VALID_RULE_KEYS = {dont_store: true, name: true, raise_on_nil_write: true}.freeze + private_constant :VALID_RULE_KEYS + + def valid_rule_key?(key) + super || VALID_RULE_KEYS[key] + end + + def required_props + @class.props.select {|_, v| T::Props::Utils.required_prop?(v)}.keys + end + + def prop_dont_store?(prop) + prop_rules(prop)[:dont_store] + end + def prop_by_serialized_forms + @class.prop_by_serialized_forms + end + + def from_hash(hash, strict=false) + raise ArgumentError.new("#{hash.inspect} provided to from_hash") if !(hash && hash.is_a?(Hash)) + + i = @class.allocate + i.deserialize(hash, strict) + + i + end + + def prop_serialized_form(prop) + prop_rules(prop)[:serialized_form] + end + + def serialized_form_prop(serialized_form) + prop_by_serialized_forms[serialized_form.to_s] || raise("No such serialized form: #{serialized_form.inspect}") + end + + def add_prop_definition(prop, rules) + rules[:serialized_form] = rules.fetch(:name, prop.to_s) + res = super + prop_by_serialized_forms[rules[:serialized_form]] = prop + if T::Configuration.use_vm_prop_serde? + enqueue_lazy_vm_method_definition!(:__t_props_generated_serialize) {generate_serialize2} + enqueue_lazy_vm_method_definition!(:__t_props_generated_deserialize) {generate_deserialize2} + else + enqueue_lazy_method_definition!(:__t_props_generated_serialize) {generate_serialize_source} + enqueue_lazy_method_definition!(:__t_props_generated_deserialize) {generate_deserialize_source} + end + res + end + + private def generate_serialize_source + T::Props::Private::SerializerGenerator.generate(props) + end + + private def generate_deserialize_source + T::Props::Private::DeserializerGenerator.generate( + props, + props_with_defaults || {}, + ) + end + + private def generate_serialize2 + T::Props::Private::SerializerGenerator.generate2(decorated_class, props) + end + + private def generate_deserialize2 + T::Props::Private::DeserializerGenerator.generate2( + decorated_class, + props, + props_with_defaults || {}, + ) + end + + def message_with_generated_source_context(error, generated_method, generate_source_method) + line_label = error.backtrace.find {|l| l.end_with?("in `#{generated_method}'")} + return unless line_label + + line_num = line_label.split(':')[1]&.to_i + return unless line_num + + source_lines = self.send(generate_source_method).split("\n") + previous_blank = source_lines[0...line_num].rindex(&:empty?) || 0 + next_blank = line_num + (source_lines[line_num..-1]&.find_index(&:empty?) || 0) + context = " #{source_lines[(previous_blank + 1)...next_blank].join("\n ")}" + <<~MSG + Error in #{decorated_class.name}##{generated_method}: #{error.message} + at line #{line_num - previous_blank - 1} in: + #{context} + MSG + end + + def raise_nil_deserialize_error(hkey) + msg = "Tried to deserialize a required prop from a nil value. It's "\ + "possible that a nil value exists in the database, so you should "\ + "provide a `default: or factory:` for this prop (see go/optional "\ + "for more details). If this is already the case, you probably "\ + "omitted a required prop from the `fields:` option when doing a "\ + "partial load." + storytime = {prop: hkey, klass: decorated_class.name} + + # Notify the model owner if it exists, and always notify the API owner. + begin + if T::Configuration.class_owner_finder && (owner = T::Configuration.class_owner_finder.call(decorated_class)) + T::Configuration.hard_assert_handler( + msg, + storytime: storytime, + project: owner + ) + end + ensure + T::Configuration.hard_assert_handler(msg, storytime: storytime) + end + end + + def prop_validate_definition!(name, cls, rules, type) + result = super + + if (rules_name = rules[:name]) + unless rules_name.is_a?(String) + raise ArgumentError.new("Invalid name in prop #{@class.name}.#{name}: #{rules_name.inspect}") + end + + validate_prop_name(rules_name) + end + + if !rules[:raise_on_nil_write].nil? && rules[:raise_on_nil_write] != true + raise ArgumentError.new("The value of `raise_on_nil_write` if specified must be `true` (given: #{rules[:raise_on_nil_write]}).") + end + + result + end + + def get_id(instance) + prop = prop_by_serialized_forms['_id'] + if prop + get(instance, prop) + else + nil + end + end + + EMPTY_EXTRA_PROPS = {}.freeze + private_constant :EMPTY_EXTRA_PROPS + + def extra_props(instance) + if instance.instance_variable_defined?(:@_extra_props) + instance.instance_variable_get(:@_extra_props) || EMPTY_EXTRA_PROPS + else + EMPTY_EXTRA_PROPS + end + end + + # overrides T::Props::PrettyPrintable + private def inspect_instance_components(instance, multiline:, indent:) + if (extra_props = extra_props(instance)) && !extra_props.empty? + pretty_kvs = extra_props.map {|k, v| [k.to_sym, v.inspect]} + extra = join_props_with_pretty_values(pretty_kvs, multiline: false) + super + ["@_extra_props=<#{extra}>"] + else + super + end + end +end + +############################################## + +# NB: This must stay in the same file where T::Props::Serializable is defined due to +# T::Props::Decorator#apply_plugin; see https://git.corp.stripe.com/stripe-internal/pay-server/blob/fc7f15593b49875f2d0499ffecfd19798bac05b3/chalk/odm/lib/chalk-odm/document_decorator.rb#L716-L717 +module T::Props::Serializable::ClassMethods + def prop_by_serialized_forms + @prop_by_serialized_forms ||= {} + end + + # Allocate a new instance and call {#deserialize} to load a new + # object from a hash. + # @return [Serializable] + def from_hash(hash, strict=false) + self.decorator.from_hash(hash, strict) + end + + # Equivalent to {.from_hash} with `strict` set to true. + # @return [Serializable] + def from_hash!(hash) + self.decorator.from_hash(hash, true) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/type_validation.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/type_validation.rb new file mode 100644 index 0000000000..ae3557783d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/type_validation.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true +# typed: false + +module T::Props::TypeValidation + include T::Props::Plugin + + BANNED_TYPES = [Object, BasicObject, Kernel].freeze + + class UnderspecifiedType < ArgumentError; end + + module DecoratorMethods + extend T::Sig + + sig {params(key: Symbol).returns(T::Boolean).checked(:never)} + def valid_rule_key?(key) + super || key == :DEPRECATED_underspecified_type + end + + sig do + params( + name: T.any(Symbol, String), + _cls: Module, + rules: T::Hash[Symbol, T.untyped], + type: T.any(T::Types::Base, Module) + ) + .void + end + def prop_validate_definition!(name, _cls, rules, type) + super + + if !rules[:DEPRECATED_underspecified_type] + validate_type(type, field_name: name) + elsif rules[:DEPRECATED_underspecified_type] && find_invalid_subtype(type).nil? + raise ArgumentError.new("DEPRECATED_underspecified_type set unnecessarily for #{@class.name}.#{name} - #{type} is a valid type") + end + end + + sig do + params( + type: T::Types::Base, + field_name: T.any(Symbol, String), + ) + .void + end + private def validate_type(type, field_name:) + if (invalid_subtype = find_invalid_subtype(type)) + raise UnderspecifiedType.new(type_error_message(invalid_subtype, field_name, type)) + end + end + + # Returns an invalid type, if any, found in the given top-level type. + # This might be the type itself, if it is e.g. "Object", or might be + # a subtype like the type of the values of a typed hash. + # + # If the type is fully valid, returns nil. + # + # checked(:never) - called potentially many times recursively + sig {params(type: T::Types::Base).returns(T.nilable(T::Types::Base)).checked(:never)} + private def find_invalid_subtype(type) + case type + when T::Types::TypedEnumerable + find_invalid_subtype(type.type) + when T::Types::FixedHash + type.types.values.map {|subtype| find_invalid_subtype(subtype)}.compact.first + when T::Types::Union, T::Types::FixedArray + # `T.any` is valid if all of the members are valid + type.types.map {|subtype| find_invalid_subtype(subtype)}.compact.first + when T::Types::Intersection + # `T.all` is valid if at least one of the members is valid + invalid = type.types.map {|subtype| find_invalid_subtype(subtype)}.compact + if invalid.length == type.types.length + invalid.first + else + nil + end + when T::Types::Enum, T::Types::ClassOf + nil + when T::Private::Types::TypeAlias + find_invalid_subtype(type.aliased_type) + when T::Types::Simple + # TODO Could we manage to define a whitelist, consisting of something + # like primitives, subdocs, DataInterfaces, and collections/enums/unions + # thereof? + if BANNED_TYPES.include?(type.raw_type) + type + else + nil + end + else + type + end + end + + sig do + params( + type: T::Types::Base, + field_name: T.any(Symbol, String), + orig_type: T::Types::Base, + ) + .returns(String) + end + private def type_error_message(type, field_name, orig_type) + msg_prefix = "#{@class.name}.#{field_name}: #{orig_type} is invalid in prop definition" + if type == orig_type + "#{msg_prefix}. Please choose a more specific type (T.untyped and ~equivalents like Object are banned)." + else + "#{msg_prefix}. Please choose a subtype more specific than #{type} (T.untyped and ~equivalents like Object are banned)." + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/utils.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/utils.rb new file mode 100644 index 0000000000..33d1abadce --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/utils.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true +# typed: true + +module T::Props::Utils + # Deep copy an object. The object must consist of Ruby primitive + # types and Hashes and Arrays. + def self.deep_clone_object(what, freeze: false) + result = case what + when true + true + when false + false + when Symbol, NilClass, Numeric + what + when Array + what.map {|v| deep_clone_object(v, freeze: freeze)} + when Hash + h = what.class.new + what.each do |k, v| + k.freeze if freeze + h[k] = deep_clone_object(v, freeze: freeze) + end + h + when Regexp + what.dup + when T::Enum + what + else + what.clone + end + freeze ? result.freeze : result + end + + # The prop_rules indicate whether we should check for reading a nil value for the prop/field. + # This is mostly for the compatibility check that we allow existing documents carry some nil prop/field. + def self.need_nil_read_check?(prop_rules) + # . :on_load allows nil read, but we need to check for the read for future writes + prop_rules[:optional] == :on_load || prop_rules[:raise_on_nil_write] + end + + # The prop_rules indicate whether we should check for writing a nil value for the prop/field. + def self.need_nil_write_check?(prop_rules) + need_nil_read_check?(prop_rules) || T::Props::Utils.required_prop?(prop_rules) + end + + def self.required_prop?(prop_rules) + # Clients should never reference :_tnilable as the implementation can change. + !prop_rules[:_tnilable] + end + + def self.optional_prop?(prop_rules) + # Clients should never reference :_tnilable as the implementation can change. + !!prop_rules[:_tnilable] + end + + def self.merge_serialized_optional_rule(prop_rules) + {'_tnilable' => true}.merge(prop_rules.merge('_tnilable' => true)) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/weak_constructor.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/weak_constructor.rb new file mode 100644 index 0000000000..3ffe1be695 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/props/weak_constructor.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true +# typed: false + +module T::Props::WeakConstructor + include T::Props::Optional + extend T::Sig + + # checked(:never) - O(runtime object construction) + sig {params(hash: T::Hash[Symbol, T.untyped]).void.checked(:never)} + def initialize(hash={}) + decorator = self.class.decorator + + hash_keys_matching_props = decorator.construct_props_with_defaults(self, hash) + + decorator.construct_props_without_defaults(self, hash) + + if hash_keys_matching_props < hash.size + raise ArgumentError.new("#{self.class}: Unrecognized properties: #{(hash.keys - decorator.props.keys).join(', ')}") + end + end +end + +module T::Props::WeakConstructor::DecoratorMethods + extend T::Sig + + # Set values for all props that have no defaults. Ignore any not present. + # + # @return [Integer] A count of props that we successfully initialized (which + # we'll use to check for any unrecognized input.) + # + # checked(:never) - O(runtime object construction) + sig {params(instance: T::Props::WeakConstructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never)} + def construct_props_without_defaults(instance, hash) + # Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator + # and therefore allocates for each entry. + result = 0 + props_without_defaults&.each_pair do |p, setter_proc| + if hash.key?(p) + instance.instance_exec(hash[p], &setter_proc) + result += 1 + end + end + result + end + + # Set values for all props that have defaults. Use the default if and only if + # the prop key isn't in the input. + # + # @return [Integer] A count of props that we successfully initialized (which + # we'll use to check for any unrecognized input.) + # + # checked(:never) - O(runtime object construction) + sig {params(instance: T::Props::WeakConstructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never)} + def construct_props_with_defaults(instance, hash) + # Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator + # and therefore allocates for each entry. + result = 0 + props_with_defaults&.each_pair do |p, default_struct| + if hash.key?(p) + instance.instance_exec(hash[p], &default_struct.setter_proc) + result += 1 + else + default_struct.set_default(instance) + end + end + result + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/sig.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/sig.rb new file mode 100644 index 0000000000..3112adf861 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/sig.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# typed: strict + +# Used as a mixin to any class so that you can call `sig`. +# Docs at https://sorbet.org/docs/sigs +module T::Sig + module WithoutRuntime + # At runtime, does nothing, but statically it is treated exactly the same + # as T::Sig#sig. Only use it in cases where you can't use T::Sig#sig. + def self.sig(arg0=nil, &blk); end + + original_verbose = $VERBOSE + $VERBOSE = false + + # At runtime, does nothing, but statically it is treated exactly the same + # as T::Sig#sig. Only use it in cases where you can't use T::Sig#sig. + T::Sig::WithoutRuntime.sig {params(arg0: T.nilable(Symbol), blk: T.proc.bind(T::Private::Methods::DeclBuilder).void).void} + def self.sig(arg0=nil, &blk); end # rubocop:disable Lint/DuplicateMethods + + $VERBOSE = original_verbose + end + + # Declares a method with type signatures and/or + # abstract/override/... helpers. See the documentation URL on + # {T::Helpers} + T::Sig::WithoutRuntime.sig {params(arg0: T.nilable(Symbol), blk: T.proc.bind(T::Private::Methods::DeclBuilder).void).void} + def sig(arg0=nil, &blk) + T::Private::Methods.declare_sig(self, Kernel.caller_locations(1, 1)&.first, arg0, &blk) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/struct.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/struct.rb new file mode 100644 index 0000000000..79e6b303d3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/struct.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true +# typed: true + +class T::InexactStruct + include T::Props + include T::Props::Serializable + include T::Props::Constructor +end + +class T::Struct < T::InexactStruct + def self.inherited(subclass) + super(subclass) + T::Private::ClassUtils.replace_method(subclass.singleton_class, :inherited) do |s| + super(s) + raise "#{self.name} is a subclass of T::Struct and cannot be subclassed" + end + end +end + +class T::ImmutableStruct < T::InexactStruct + extend T::Sig + + def self.inherited(subclass) + super(subclass) + + T::Private::ClassUtils.replace_method(subclass.singleton_class, :inherited) do |s| + super(s) + raise "#{self.name} is a subclass of T::ImmutableStruct and cannot be subclassed" + end + end + + # Matches the one in WeakConstructor, but freezes the object + sig {params(hash: T::Hash[Symbol, T.untyped]).void.checked(:never)} + def initialize(hash={}) + super + + freeze + end + + # Matches the signature in Props, but raises since this is an immutable struct and only const is allowed + sig {params(name: Symbol, cls: T.untyped, rules: T.untyped).void} + def self.prop(name, cls, rules={}) + return super if (cls.is_a?(Hash) && cls[:immutable]) || rules[:immutable] + + raise "Cannot use `prop` in #{self.name} because it is an immutable struct. Use `const` instead" + end + + def with(changed_props) + raise "Cannot use `with` in #{self.class.name} because it is an immutable struct" + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/attached_class.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/attached_class.rb new file mode 100644 index 0000000000..059956a68d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/attached_class.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # Modeling AttachedClass properly at runtime would require additional + # tracking, so at runtime we permit all values and rely on the static checker. + # As AttachedClass is modeled statically as a type member on every singleton + # class, this is consistent with the runtime behavior for all type members. + class AttachedClassType < Base + + def initialize(); end + + # overrides Base + def name + "T.attached_class" + end + + # overrides Base + def valid?(obj) + true + end + + # overrides Base + private def subtype_of_single?(other) + case other + when AttachedClassType + true + else + false + end + end + + module Private + INSTANCE = AttachedClassType.new.freeze + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/base.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/base.rb new file mode 100644 index 0000000000..cce89b178a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/base.rb @@ -0,0 +1,172 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + class Base + def self.method_added(method_name) + super(method_name) + # What is now `subtype_of_single?` used to be named `subtype_of?`. Make sure people don't + # override the wrong thing. + # + # NB: Outside of T::Types, we would enforce this by using `sig` and not declaring the method + # as overridable, but doing so here would result in a dependency cycle. + if method_name == :subtype_of? && self != T::Types::Base + raise "`subtype_of?` should not be overridden. You probably want to override " \ + "`subtype_of_single?` instead." + end + end + + # this will be redefined in certain subclasses + def recursively_valid?(obj) + valid?(obj) + end + + def valid?(obj) + raise NotImplementedError + end + + # @return [T::Boolean] This method must be implemented to return whether the subclass is a subtype + # of `type`. This should only be called by `subtype_of?`, which guarantees that `type` will be + # a "single" type, by which we mean it won't be a Union or an Intersection (c.f. + # `isSubTypeSingle` in sorbet). + private def subtype_of_single?(type) + raise NotImplementedError + end + + # Equality is based on name, so be sure the name reflects all relevant state when implementing. + def name + raise NotImplementedError + end + + # Mirrors ruby_typer::core::Types::isSubType + # See https://git.corp.stripe.com/stripe-internal/ruby-typer/blob/9fc8ed998c04ac0b96592ae6bb3493b8a925c5c1/core/types/subtyping.cc#L912-L950 + # + # This method cannot be overridden (see `method_added` above). + # Subclasses only need to implement `subtype_of_single?`). + def subtype_of?(t2) + t1 = self + + if t2.is_a?(T::Private::Types::TypeAlias) + t2 = t2.aliased_type + end + + if t1.is_a?(T::Private::Types::TypeAlias) + return t1.aliased_type.subtype_of?(t2) + end + + # pairs to cover: 1 (_, _) + # 2 (_, And) + # 3 (_, Or) + # 4 (And, _) + # 5 (And, And) + # 6 (And, Or) + # 7 (Or, _) + # 8 (Or, And) + # 9 (Or, Or) + + # Note: order of cases here matters! + if t1.is_a?(T::Types::Union) # 7, 8, 9 + # this will be incorrect if/when we have Type members + return t1.types.all? {|t1_member| t1_member.subtype_of?(t2)} + end + + if t2.is_a?(T::Types::Intersection) # 2, 5 + # this will be incorrect if/when we have Type members + return t2.types.all? {|t2_member| t1.subtype_of?(t2_member)} + end + + if t2.is_a?(T::Types::Union) + if t1.is_a?(T::Types::Intersection) # 6 + # dropping either of parts eagerly make subtype test be too strict. + # we have to try both cases, when we normally try only one + return t2.types.any? {|t2_member| t1.subtype_of?(t2_member)} || + t1.types.any? {|t1_member| t1_member.subtype_of?(t2)} + end + return t2.types.any? {|t2_member| t1.subtype_of?(t2_member)} # 3 + end + + if t1.is_a?(T::Types::Intersection) # 4 + # this will be incorrect if/when we have Type members + return t1.types.any? {|t1_member| t1_member.subtype_of?(t2)} + end + + # 1; Start with some special cases + if t1.is_a?(T::Private::Types::Void) + return t2.is_a?(T::Private::Types::Void) + end + + if t1.is_a?(T::Types::Untyped) || t2.is_a?(T::Types::Untyped) + return true + end + + # Rest of (1) + subtype_of_single?(t2) + end + + def to_s + name + end + + def describe_obj(obj) + # Would be redundant to print class and value in these common cases. + case obj + when nil, true, false + return "type #{obj.class}" + end + + # In rare cases, obj.inspect may fail, or be undefined, so rescue. + begin + # Default inspect behavior of, eg; `#` is ugly; just print the hash instead, which is more concise/readable. + if obj.method(:inspect).owner == Kernel + "type #{obj.class} with hash #{obj.hash}" + elsif T::Configuration.include_value_in_type_errors? + "type #{obj.class} with value #{T::Utils.string_truncate_middle(obj.inspect, 30, 30)}" + else + "type #{obj.class}" + end + rescue StandardError, SystemStackError + "type #{obj.class} with unprintable value" + end + end + + def error_message_for_obj(obj) + if valid?(obj) + nil + else + error_message(obj) + end + end + + def error_message_for_obj_recursive(obj) + if recursively_valid?(obj) + nil + else + error_message(obj) + end + end + + private def error_message(obj) + "Expected type #{self.name}, got #{describe_obj(obj)}" + end + + def validate!(obj) + err = error_message_for_obj(obj) + raise TypeError.new(err) if err + end + + ### Equality methods (necessary for deduping types with `uniq`) + + def hash + name.hash + end + + # Type equivalence, defined by serializing the type to a string (with + # `#name`) and comparing the resulting strings for equality. + def ==(other) + (T::Utils.resolve_alias(other).class == T::Utils.resolve_alias(self).class) && + other.name == self.name + end + + alias_method :eql?, :== + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/class_of.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/class_of.rb new file mode 100644 index 0000000000..d56f21d4c7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/class_of.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # Validates that an object belongs to the specified class. + class ClassOf < Base + attr_reader :type + + def initialize(type) + @type = type + end + + # overrides Base + def name + "T.class_of(#{@type})" + end + + # overrides Base + def valid?(obj) + obj.is_a?(Module) && obj <= @type + end + + # overrides Base + def subtype_of_single?(other) + case other + when ClassOf + @type <= other.type + when Simple + @type.is_a?(other.raw_type) + else + false + end + end + + # overrides Base + def describe_obj(obj) + obj.inspect + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/enum.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/enum.rb new file mode 100644 index 0000000000..97ecfe0c0c --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/enum.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # validates that the provided value is within a given set/enum + class Enum < Base + extend T::Sig + + attr_reader :values + + def initialize(values) + @values = values + end + + # overrides Base + def valid?(obj) + @values.member?(obj) + end + + # overrides Base + private def subtype_of_single?(other) + case other + when Enum + (other.values - @values).empty? + else + false + end + end + + # overrides Base + def name + "T.deprecated_enum([#{@values.map(&:inspect).join(', ')}])" + end + + # overrides Base + def describe_obj(obj) + obj.inspect + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/fixed_array.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/fixed_array.rb new file mode 100644 index 0000000000..3bed082bcc --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/fixed_array.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true +# https://jira.corp.stripe.com/browse/RUBYPLAT-1107 +# typed: false + +module T::Types + # Takes a list of types. Validates each item in an array using the type in the same position + # in the list. + class FixedArray < Base + attr_reader :types + + def initialize(types) + @types = types.map {|type| T::Utils.coerce(type)} + end + + # overrides Base + def name + "[#{@types.join(', ')}]" + end + + # overrides Base + def recursively_valid?(obj) + if obj.is_a?(Array) && obj.length == @types.length + i = 0 + while i < @types.length + if !@types[i].recursively_valid?(obj[i]) + return false + end + i += 1 + end + true + else + false + end + end + + # overrides Base + def valid?(obj) + if obj.is_a?(Array) && obj.length == @types.length + i = 0 + while i < @types.length + if !@types[i].valid?(obj[i]) + return false + end + i += 1 + end + true + else + false + end + end + + # overrides Base + private def subtype_of_single?(other) + case other + when FixedArray + # Properly speaking, covariance here is unsound since arrays + # can be mutated, but sorbet implements covariant tuples for + # ease of adoption. + @types.size == other.types.size && @types.zip(other.types).all? do |t1, t2| + t1.subtype_of?(t2) + end + else + false + end + end + + # This gives us better errors, e.g.: + # "Expected [String, Symbol], got [String, String]" + # instead of + # "Expected [String, Symbol], got Array". + # + # overrides Base + def describe_obj(obj) + if obj.is_a?(Array) + if obj.length == @types.length + item_classes = obj.map(&:class).join(', ') + "type [#{item_classes}]" + else + "array of size #{obj.length}" + end + else + super + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/fixed_hash.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/fixed_hash.rb new file mode 100644 index 0000000000..d8fddb3703 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/fixed_hash.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # Takes a hash of types. Validates each item in a hash using the type in the same position + # in the list. + class FixedHash < Base + attr_reader :types + + def initialize(types) + @types = types.transform_values {|v| T::Utils.coerce(v)} + end + + # overrides Base + def name + serialize_hash(@types) + end + + # overrides Base + def recursively_valid?(obj) + return false unless obj.is_a?(Hash) + return false if @types.any? {|key, type| !type.recursively_valid?(obj[key])} + return false if obj.any? {|key, _| !@types[key]} + true + end + + # overrides Base + def valid?(obj) + return false unless obj.is_a?(Hash) + return false if @types.any? {|key, type| !type.valid?(obj[key])} + return false if obj.any? {|key, _| !@types[key]} + true + end + + # overrides Base + private def subtype_of_single?(other) + case other + when FixedHash + # Using `subtype_of?` here instead of == would be unsound + @types == other.types + else + false + end + end + + # This gives us better errors, e.g.: + # `Expected {a: String}, got {a: TrueClass}` + # instead of + # `Expected {a: String}, got Hash`. + # + # overrides Base + def describe_obj(obj) + if obj.is_a?(Hash) + "type #{serialize_hash(obj.transform_values(&:class))}" + else + super + end + end + + private + + def serialize_hash(hash) + entries = hash.map do |(k, v)| + if Symbol === k && ":#{k}" == k.inspect + "#{k}: #{v}" + else + "#{k.inspect} => #{v}" + end + end + + "{#{entries.join(', ')}}" + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/intersection.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/intersection.rb new file mode 100644 index 0000000000..8e4b42f187 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/intersection.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # Takes a list of types. Validates that an object matches all of the types. + class Intersection < Base + attr_reader :types + + def initialize(types) + @types = types.flat_map do |type| + type = T::Utils.resolve_alias(type) + if type.is_a?(Intersection) + # Simplify nested intersections (mostly so `name` returns a nicer value) + type.types + else + T::Utils.coerce(type) + end + end.uniq + end + + # overrides Base + def name + "T.all(#{@types.map(&:name).sort.join(', ')})" + end + + # overrides Base + def recursively_valid?(obj) + @types.all? {|type| type.recursively_valid?(obj)} + end + + # overrides Base + def valid?(obj) + @types.all? {|type| type.valid?(obj)} + end + + # overrides Base + private def subtype_of_single?(other) + raise "This should never be reached if you're going through `subtype_of?` (and you should be)" + end + + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/noreturn.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/noreturn.rb new file mode 100644 index 0000000000..c285797480 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/noreturn.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # The bottom type + class NoReturn < Base + + def initialize; end + + # overrides Base + def name + "T.noreturn" + end + + # overrides Base + def valid?(obj) + false + end + + # overrides Base + private def subtype_of_single?(other) + true + end + + module Private + INSTANCE = NoReturn.new.freeze + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/proc.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/proc.rb new file mode 100644 index 0000000000..aece6a3a2f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/proc.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # Defines the type of a proc (a ruby callable). At runtime, only + # validates that the value is a `::Proc`. + # + # At present, we only support fixed-arity procs with no optional or + # keyword arguments. + class Proc < Base + attr_reader :arg_types + attr_reader :returns + + def initialize(arg_types, returns) + @arg_types = {} + arg_types.each do |key, raw_type| + @arg_types[key] = T::Utils.coerce(raw_type) + end + @returns = T::Utils.coerce(returns) + end + + # overrides Base + def name + args = [] + @arg_types.each do |k, v| + args << "#{k}: #{v.name}" + end + "T.proc.params(#{args.join(', ')}).returns(#{returns})" + end + + # overrides Base + def valid?(obj) + obj.is_a?(::Proc) + end + + # overrides Base + private def subtype_of_single?(other) + case other + when self.class + if arg_types.size != other.arg_types.size + return false + end + arg_types.values.zip(other.arg_types.values).all? do |a, b| + b.subtype_of?(a) + end && returns.subtype_of?(other.returns) + else + false + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/self_type.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/self_type.rb new file mode 100644 index 0000000000..e431a3e0f9 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/self_type.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # Modeling self-types properly at runtime would require additional tracking, + # so at runtime we permit all values and rely on the static checker. + class SelfType < Base + + def initialize(); end + + # overrides Base + def name + "T.self_type" + end + + # overrides Base + def valid?(obj) + true + end + + # overrides Base + private def subtype_of_single?(other) + case other + when SelfType + true + else + false + end + end + + module Private + INSTANCE = SelfType.new.freeze + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/simple.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/simple.rb new file mode 100644 index 0000000000..2789adbb67 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/simple.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # Validates that an object belongs to the specified class. + class Simple < Base + attr_reader :raw_type + + def initialize(raw_type) + @raw_type = raw_type + end + + # overrides Base + def name + # Memoize to mitigate pathological performance with anonymous modules (https://bugs.ruby-lang.org/issues/11119) + # + # `name` isn't normally a hot path for types, but it is used in initializing a T::Types::Union, + # and so in `T.nilable`, and so in runtime constructions like `x = T.let(nil, T.nilable(Integer))`. + @name ||= @raw_type.name.freeze + end + + # overrides Base + def valid?(obj) + obj.is_a?(@raw_type) + end + + # overrides Base + private def subtype_of_single?(other) + case other + when Simple + @raw_type <= other.raw_type + else + false + end + end + + # overrides Base + private def error_message(obj) + error_message = super(obj) + actual_name = obj.class.name + + return error_message unless name == actual_name + + <<~MSG.strip + #{error_message} + + The expected type and received object type have the same name but refer to different constants. + Expected type is #{name} with object id #{@raw_type.__id__}, but received type is #{actual_name} with object id #{obj.class.__id__}. + + There might be a constant reloading problem in your application. + MSG + end + + def to_nilable + @nilable ||= T::Types::Union.new([self, T::Utils::Nilable::NIL_TYPE]) + end + + module Private + module Pool + @cache = ObjectSpace::WeakMap.new + + def self.type_for_module(mod) + cached = @cache[mod] + return cached if cached + + type = if mod == ::Array + T::Array[T.untyped] + elsif mod == ::Hash + T::Hash[T.untyped, T.untyped] + elsif mod == ::Enumerable + T::Enumerable[T.untyped] + elsif mod == ::Enumerator + T::Enumerator[T.untyped] + elsif mod == ::Range + T::Range[T.untyped] + elsif !Object.autoload?(:Set) && Object.const_defined?(:Set) && mod == ::Set + T::Set[T.untyped] + else + Simple.new(mod) + end + + # Unfortunately, we still need to check if the module is frozen, + # since WeakMap adds a finalizer to the key that is added + # to the map, so that it can clear the map entry when the key is + # garbage collected. + # For a frozen object, though, adding a finalizer is not a valid + # operation, so this still raises if `mod` is frozen. + @cache[mod] = type unless mod.frozen? + type + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/t_enum.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/t_enum.rb new file mode 100644 index 0000000000..121368c7b6 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/t_enum.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # Validates that an object is equal to another T::Enum singleton value. + class TEnum < Base + attr_reader :val + + def initialize(val) + @val = val + end + + # overrides Base + def name + # Strips the #<...> off, just leaving the ... + # Reasoning: the user will have written something like + # T.any(MyEnum::A, MyEnum::B) + # in the type, so we should print what they wrote in errors, not: + # T.any(#, #) + @val.inspect[2..-2] + end + + # overrides Base + def valid?(obj) + @val == obj + end + + # overrides Base + private def subtype_of_single?(other) + case other + when TEnum + @val == other.val + else + false + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_member.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_member.rb new file mode 100644 index 0000000000..fadd2a7eea --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_member.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true +# typed: strict + +module T::Types + class TypeMember < TypeVariable + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_parameter.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_parameter.rb new file mode 100644 index 0000000000..ea82a07cc3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_parameter.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + class TypeParameter < Base + def initialize(name) + raise ArgumentError.new("not a symbol: #{name}") unless name.is_a?(Symbol) + @name = name + end + + def valid?(obj) + true + end + + def subtype_of_single?(type) + true + end + + def name + "T.type_parameter(:#{@name})" + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_template.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_template.rb new file mode 100644 index 0000000000..8c83de8949 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_template.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true +# typed: strict + +module T::Types + class TypeTemplate < TypeVariable + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_variable.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_variable.rb new file mode 100644 index 0000000000..187119167d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/type_variable.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # Since we do type erasure at runtime, this just validates the variance and + # provides some syntax for the static type checker + class TypeVariable < Base + attr_reader :variance + + VALID_VARIANCES = %i[in out invariant].freeze + + def initialize(variance) + case variance + when Hash then raise ArgumentError.new("Pass bounds using a block. Got: #{variance}") + when *VALID_VARIANCES then nil + else + raise TypeError.new("invalid variance #{variance}") + end + @variance = variance + end + + def valid?(obj) + true + end + + def subtype_of_single?(type) + true + end + + def name + Untyped.new.name + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_array.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_array.rb new file mode 100644 index 0000000000..0b5f3541a9 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_array.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + class TypedArray < TypedEnumerable + # overrides Base + def name + "T::Array[#{@type.name}]" + end + + def underlying_class + Array + end + + # overrides Base + def recursively_valid?(obj) + obj.is_a?(Array) && super + end + + # overrides Base + def valid?(obj) + obj.is_a?(Array) + end + + def new(*args) + Array.new(*T.unsafe(args)) + end + + class Untyped < TypedArray + def initialize + super(T.untyped) + end + + def valid?(obj) + obj.is_a?(Array) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_enumerable.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_enumerable.rb new file mode 100644 index 0000000000..65c2631f0a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_enumerable.rb @@ -0,0 +1,176 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # Note: All subclasses of Enumerable should add themselves to the + # `case` statement below in `describe_obj` in order to get better + # error messages. + class TypedEnumerable < Base + attr_reader :type + + def initialize(type) + @type = T::Utils.coerce(type) + end + + def underlying_class + Enumerable + end + + # overrides Base + def name + "T::Enumerable[#{@type.name}]" + end + + # overrides Base + def valid?(obj) + obj.is_a?(Enumerable) + end + + # overrides Base + def recursively_valid?(obj) + return false unless obj.is_a?(Enumerable) + case obj + when Array + begin + it = 0 + while it < obj.count + return false unless @type.recursively_valid?(obj[it]) + it += 1 + end + true + end + when Hash + return false unless @type.is_a?(FixedArray) + types = @type.types + return false if types.count != 2 + key_type = types[0] + value_type = types[1] + obj.each_pair do |key, val| + # Some objects (I'm looking at you Rack::Utils::HeaderHash) don't + # iterate over a [key, value] array, so we can't juse use the @type.recursively_valid?(v) + return false if !key_type.recursively_valid?(key) || !value_type.recursively_valid?(val) + end + true + when Enumerator::Lazy + # Enumerators can be unbounded: see `[:foo, :bar].cycle` + true + when Enumerator + # Enumerators can be unbounded: see `[:foo, :bar].cycle` + true + when Range + # A nil beginning or a nil end does not provide any type information. That is, nil in a range represents + # boundlessness, it does not express a type. For example `(nil...nil)` is not a T::Range[NilClass], its a range + # of unknown types (T::Range[T.untyped]). + # Similarly, `(nil...1)` is not a `T::Range[T.nilable(Integer)]`, it's a boundless range of Integer. + (obj.begin.nil? || @type.recursively_valid?(obj.begin)) && (obj.end.nil? || @type.recursively_valid?(obj.end)) + when Set + obj.each do |item| + return false unless @type.recursively_valid?(item) + end + + true + else + # We don't check the enumerable since it isn't guaranteed to be + # rewindable (e.g. STDIN) and it may be expensive to enumerate + # (e.g. an enumerator that makes an HTTP request)" + true + end + end + + # overrides Base + private def subtype_of_single?(other) + if other.class <= TypedEnumerable && + underlying_class <= other.underlying_class + # Enumerables are covariant because they are read only + # + # Properly speaking, many Enumerable subtypes (e.g. Set) + # should be invariant because they are mutable and support + # both reading and writing. However, Sorbet treats *all* + # Enumerable subclasses as covariant for ease of adoption. + @type.subtype_of?(other.type) + else + false + end + end + + # overrides Base + def describe_obj(obj) + return super unless obj.is_a?(Enumerable) + type_from_instance(obj).name + end + + private def type_from_instances(objs) + return objs.class unless objs.is_a?(Enumerable) + obtained_types = [] + begin + objs.each do |x| + obtained_types << type_from_instance(x) + end + rescue + return T.untyped # all we can do is go with the types we have so far + end + if obtained_types.count > 1 + # Multiple kinds of bad types showed up, we'll suggest a union + # type you might want. + Union.new(obtained_types) + elsif obtained_types.empty? + T.noreturn + else + # Everything was the same bad type, lets just show that + obtained_types.first + end + end + + private def type_from_instance(obj) + if [true, false].include?(obj) + return T::Boolean + elsif !obj.is_a?(Enumerable) + return obj.class + end + + case obj + when Array + T::Array[type_from_instances(obj)] + when Hash + inferred_key = type_from_instances(obj.keys) + inferred_val = type_from_instances(obj.values) + T::Hash[inferred_key, inferred_val] + when Range + # We can't get any information from `NilClass` in ranges (since nil is used to represent boundlessness). + typeable_objects = [obj.begin, obj.end].compact + if typeable_objects.empty? + T::Range[T.untyped] + else + T::Range[type_from_instances(typeable_objects)] + end + when Enumerator::Lazy + T::Enumerator::Lazy[type_from_instances(obj)] + when Enumerator + T::Enumerator[type_from_instances(obj)] + when Set + T::Set[type_from_instances(obj)] + when IO + # Short circuit for anything IO-like (File, etc.). In these cases, + # enumerating the object is a destructive operation and might hang. + obj.class + else + # This is a specialized enumerable type, just return the class. + if T::Configuration::AT_LEAST_RUBY_2_7 + Object.instance_method(:class).bind_call(obj) + else + Object.instance_method(:class).bind(obj).call + end + end + end + + class Untyped < TypedEnumerable + def initialize + super(T.untyped) + end + + def valid?(obj) + obj.is_a?(Enumerable) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_enumerator.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_enumerator.rb new file mode 100644 index 0000000000..e79341eb94 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_enumerator.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + class TypedEnumerator < TypedEnumerable + attr_reader :type + + def underlying_class + Enumerator + end + + # overrides Base + def name + "T::Enumerator[#{@type.name}]" + end + + # overrides Base + def recursively_valid?(obj) + obj.is_a?(Enumerator) && super + end + + # overrides Base + def valid?(obj) + obj.is_a?(Enumerator) + end + + def new(*args, &blk) + T.unsafe(Enumerator).new(*args, &blk) + end + + class Untyped < TypedEnumerator + def initialize + super(T.untyped) + end + + def valid?(obj) + obj.is_a?(Enumerator) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_enumerator_lazy.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_enumerator_lazy.rb new file mode 100644 index 0000000000..3569be398a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_enumerator_lazy.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + class TypedEnumeratorLazy < TypedEnumerable + attr_reader :type + + def underlying_class + Enumerator::Lazy + end + + # overrides Base + def name + "T::Enumerator::Lazy[#{@type.name}]" + end + + # overrides Base + def recursively_valid?(obj) + obj.is_a?(Enumerator::Lazy) && super + end + + # overrides Base + def valid?(obj) + obj.is_a?(Enumerator::Lazy) + end + + def new(*args, &blk) + T.unsafe(Enumerator::Lazy).new(*args, &blk) + end + + class Untyped < TypedEnumeratorLazy + def initialize + super(T.untyped) + end + + def valid?(obj) + obj.is_a?(Enumerator::Lazy) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_hash.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_hash.rb new file mode 100644 index 0000000000..f48e0c1595 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_hash.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + class TypedHash < TypedEnumerable + # Technically we don't need these, but they are a nice api + attr_reader :keys, :values + + def underlying_class + Hash + end + + def initialize(keys:, values:) + @keys = T::Utils.coerce(keys) + @values = T::Utils.coerce(values) + @type = T::Utils.coerce([keys, values]) + end + + # overrides Base + def name + "T::Hash[#{@keys.name}, #{@values.name}]" + end + + # overrides Base + def recursively_valid?(obj) + obj.is_a?(Hash) && super + end + + # overrides Base + def valid?(obj) + obj.is_a?(Hash) + end + + def new(*args, &blk) + Hash.new(*T.unsafe(args), &blk) + end + + class Untyped < TypedHash + def initialize + super(keys: T.untyped, values: T.untyped) + end + + def valid?(obj) + obj.is_a?(Hash) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_range.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_range.rb new file mode 100644 index 0000000000..50e2ef9d53 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_range.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + class TypedRange < TypedEnumerable + attr_reader :type + + def underlying_class + Hash + end + + # overrides Base + def name + "T::Range[#{@type.name}]" + end + + # overrides Base + def recursively_valid?(obj) + obj.is_a?(Range) && super + end + + # overrides Base + def valid?(obj) + obj.is_a?(Range) + end + + def new(*args) + T.unsafe(Range).new(*args) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_set.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_set.rb new file mode 100644 index 0000000000..8c1b2caee3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/typed_set.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + class TypedSet < TypedEnumerable + attr_reader :type + + def underlying_class + Hash + end + + # overrides Base + def name + "T::Set[#{@type.name}]" + end + + # overrides Base + def recursively_valid?(obj) + # Re-implements non_forcing_is_a? + return false if Object.autoload?(:Set) # Set is meant to be autoloaded but not yet loaded, this value can't be a Set + return false unless Object.const_defined?(:Set) # Set is not loaded yet + obj.is_a?(Set) && super + end + + # overrides Base + def valid?(obj) + # Re-implements non_forcing_is_a? + return false if Object.autoload?(:Set) # Set is meant to be autoloaded but not yet loaded, this value can't be a Set + return false unless Object.const_defined?(:Set) # Set is not loaded yet + obj.is_a?(Set) + end + + def new(*args) + # Fine for this to blow up, because hopefully if they're trying to make a + # Set, they don't mind putting (or already have put) a `require 'set'` in + # their program directly. + Set.new(*T.unsafe(args)) + end + + class Untyped < TypedSet + def initialize + super(T.untyped) + end + + def valid?(obj) + # Re-implements non_forcing_is_a? + return false if Object.autoload?(:Set) # Set is meant to be autoloaded but not yet loaded, this value can't be a Set + return false unless Object.const_defined?(:Set) # Set is not loaded yet + obj.is_a?(Set) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/union.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/union.rb new file mode 100644 index 0000000000..3729dc48de --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/union.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # Takes a list of types. Validates that an object matches at least one of the types. + class Union < Base + attr_reader :types + + def initialize(types) + @types = types.flat_map do |type| + type = T::Utils.coerce(type) + if type.is_a?(Union) + # Simplify nested unions (mostly so `name` returns a nicer value) + type.types + else + type + end + end.uniq + end + + # overrides Base + def name + type_shortcuts(@types) + end + + private def type_shortcuts(types) + if types.size == 1 + return types[0].name + end + nilable = T::Utils.coerce(NilClass) + trueclass = T::Utils.coerce(TrueClass) + falseclass = T::Utils.coerce(FalseClass) + if types.any? {|t| t == nilable} + remaining_types = types.reject {|t| t == nilable} + "T.nilable(#{type_shortcuts(remaining_types)})" + elsif types.any? {|t| t == trueclass} && types.any? {|t| t == falseclass} + remaining_types = types.reject {|t| t == trueclass || t == falseclass} + type_shortcuts([T::Private::Types::StringHolder.new("T::Boolean")] + remaining_types) + else + names = types.map(&:name).compact.sort + "T.any(#{names.join(', ')})" + end + end + + # overrides Base + def recursively_valid?(obj) + @types.any? {|type| type.recursively_valid?(obj)} + end + + # overrides Base + def valid?(obj) + @types.any? {|type| type.valid?(obj)} + end + + # overrides Base + private def subtype_of_single?(other) + raise "This should never be reached if you're going through `subtype_of?` (and you should be)" + end + + module Private + module Pool + EMPTY_ARRAY = [].freeze + private_constant :EMPTY_ARRAY + + # @param type_a [T::Types::Base] + # @param type_b [T::Types::Base] + # @param types [Array] optional array of additional T::Types::Base instances + def self.union_of_types(type_a, type_b, types=EMPTY_ARRAY) + if types.empty? + # We aren't guaranteed to detect a simple `T.nilable()` type here + # in cases where there are duplicate types, nested unions, etc. + # + # That's ok, because this is an optimization which isn't necessary for + # correctness. + if type_b == T::Utils::Nilable::NIL_TYPE && type_a.is_a?(T::Types::Simple) + type_a.to_nilable + elsif type_a == T::Utils::Nilable::NIL_TYPE && type_b.is_a?(T::Types::Simple) + type_b.to_nilable + else + Union.new([type_a, type_b]) + end + else + # This can't be a `T.nilable()` case unless there are duplicates, + # which is possible but unexpected. + Union.new([type_a, type_b] + types) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/untyped.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/untyped.rb new file mode 100644 index 0000000000..a06a633d42 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/types/untyped.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +# typed: true + +module T::Types + # A dynamic type, which permits whatever + class Untyped < Base + + def initialize; end + + # overrides Base + def name + "T.untyped" + end + + # overrides Base + def valid?(obj) + true + end + + # overrides Base + private def subtype_of_single?(other) + true + end + + module Private + INSTANCE = Untyped.new.freeze + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/utils.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/utils.rb new file mode 100644 index 0000000000..7897eaa38f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10175/lib/types/utils.rb @@ -0,0 +1,209 @@ +# frozen_string_literal: true +# typed: true + +module T::Utils + # Used to convert from a type specification to a `T::Types::Base`. + def self.coerce(val) + if val.is_a?(T::Private::Types::TypeAlias) + val.aliased_type + elsif val.is_a?(T::Types::Base) + val + elsif val.is_a?(Module) + T::Types::Simple::Private::Pool.type_for_module(val) + elsif val.is_a?(::Array) + T::Types::FixedArray.new(val) + elsif val.is_a?(::Hash) + T::Types::FixedHash.new(val) + elsif val.is_a?(T::Private::Methods::DeclBuilder) + T::Private::Methods.finalize_proc(val.decl) + elsif val.is_a?(::T::Enum) + T::Types::TEnum.new(val) + elsif val.is_a?(::String) + raise "Invalid String literal for type constraint. Must be an #{T::Types::Base}, a " \ + "class/module, or an array. Got a String with value `#{val}`." + else + raise "Invalid value for type constraint. Must be an #{T::Types::Base}, a " \ + "class/module, or an array. Got a `#{val.class}`." + end + end + + # Dynamically confirm that `value` is recursively a valid value of + # type `type`, including recursively through collections. Note that + # in some cases this runtime check can be very expensive, especially + # with large collections of objects. + def self.check_type_recursive!(value, type) + T::Private::Casts.cast_recursive(value, type, cast_method: "T.check_type_recursive!") + end + + # Returns the set of all methods (public, protected, private) defined on a module or its + # ancestors, excluding Object and its ancestors. Overrides of methods from Object (and its + # ancestors) are included. + def self.methods_excluding_object(mod) + # We can't just do mod.instance_methods - Object.instance_methods, because that would leave out + # any methods from Object that are overridden in mod. + mod.ancestors.flat_map do |ancestor| + # equivalent to checking Object.ancestors.include?(ancestor) + next [] if Object <= ancestor + ancestor.instance_methods(false) + ancestor.private_instance_methods(false) + end.uniq + end + + # Returns the signature for the `UnboundMethod`, or nil if it's not sig'd + # + # @example T::Utils.signature_for_method(x.method(:foo)) + def self.signature_for_method(method) + T::Private::Methods.signature_for_method(method) + end + + # Returns the signature for the instance method on the supplied module, or nil if it's not found or not typed. + # + # @example T::Utils.signature_for_instance_method(MyClass, :my_method) + def self.signature_for_instance_method(mod, method_name) + T::Private::Methods.signature_for_method(mod.instance_method(method_name)) + end + + def self.wrap_method_with_call_validation_if_needed(mod, method_sig, original_method) + T::Private::Methods::CallValidation.wrap_method_if_needed(mod, method_sig, original_method) + end + + # Unwraps all the sigs. + def self.run_all_sig_blocks + T::Private::Methods.run_all_sig_blocks + end + + # Return the underlying type for a type alias. Otherwise returns type. + def self.resolve_alias(type) + case type + when T::Private::Types::TypeAlias + type.aliased_type + else + type + end + end + + # Give a type which is a subclass of T::Types::Base, determines if the type is a simple nilable type (union of NilClass and something else). + # If so, returns the T::Types::Base of the something else. Otherwise, returns nil. + def self.unwrap_nilable(type) + case type + when T::Types::Union + non_nil_types = type.types.reject {|t| t == Nilable::NIL_TYPE} + return nil if type.types.length == non_nil_types.length + case non_nil_types.length + when 0 then nil + when 1 then non_nil_types.first + else + T::Types::Union::Private::Pool.union_of_types(non_nil_types[0], non_nil_types[1], non_nil_types[2..-1]) + end + else + nil + end + end + + # Returns the arity of a method, unwrapping the sig if needed + def self.arity(method) + arity = method.arity + return arity if arity != -1 || method.is_a?(Proc) + sig = T::Private::Methods.signature_for_method(method) + sig ? sig.method.arity : arity + end + + # Elide the middle of a string as needed and replace it with an ellipsis. + # Keep the given number of characters at the start and end of the string. + # + # This method operates on string length, not byte length. + # + # If the string is shorter than the requested truncation length, return it + # without adding an ellipsis. This method may return a longer string than + # the original if the characters removed are shorter than the ellipsis. + # + # @param [String] str + # + # @param [Fixnum] start_len The length of string before the ellipsis + # @param [Fixnum] end_len The length of string after the ellipsis + # + # @param [String] ellipsis The string to add in place of the elided text + # + # @return [String] + # + def self.string_truncate_middle(str, start_len, end_len, ellipsis='...') + return unless str + + raise ArgumentError.new('must provide start_len') unless start_len + raise ArgumentError.new('must provide end_len') unless end_len + + raise ArgumentError.new('start_len must be >= 0') if start_len < 0 + raise ArgumentError.new('end_len must be >= 0') if end_len < 0 + + str = str.to_s + return str if str.length <= start_len + end_len + + start_part = str[0...start_len - ellipsis.length] + end_part = end_len == 0 ? '' : str[-end_len..-1] + + "#{start_part}#{ellipsis}#{end_part}" + end + + def self.lift_enum(enum) + unless enum.is_a?(T::Types::Enum) + raise ArgumentError.new("#{enum.inspect} is not a T.deprecated_enum") + end + + classes = enum.values.map(&:class).uniq + if classes.empty? + T.untyped + elsif classes.length > 1 + T::Types::Union.new(classes) + else + T::Types::Simple::Private::Pool.type_for_module(classes.first) + end + end + + module Nilable + # :is_union_type, T::Boolean: whether the type is an T::Types::Union type + # :non_nilable_type, Class: if it is an T.nilable type, the corresponding underlying type; otherwise, nil. + TypeInfo = Struct.new(:is_union_type, :non_nilable_type) + + NIL_TYPE = T::Utils.coerce(NilClass) + + def self.get_type_info(prop_type) + if prop_type.is_a?(T::Types::Union) + non_nilable_type = T::Utils.unwrap_nilable(prop_type) + if non_nilable_type&.is_a?(T::Types::Simple) + non_nilable_type = non_nilable_type.raw_type + end + TypeInfo.new(true, non_nilable_type) + else + TypeInfo.new(false, nil) + end + end + + # Get the underlying type inside prop_type: + # - if the type is A, the function returns A + # - if the type is T.nilable(A), the function returns A + def self.get_underlying_type(prop_type) + type_info = get_type_info(prop_type) + if type_info.is_union_type + type_info.non_nilable_type || prop_type + elsif prop_type.is_a?(T::Types::Simple) + prop_type.raw_type + else + prop_type + end + end + + # The difference between this function and the above function is that the Sorbet type, like T::Types::Simple + # is preserved. + def self.get_underlying_type_object(prop_type) + T::Utils.unwrap_nilable(prop_type) || prop_type + end + + def self.is_union_with_nilclass(prop_type) + case prop_type + when T::Types::Union + prop_type.types.include?(NIL_TYPE) + else + false + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-stub-0.2.0/lib/sorbet-runtime-stub.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-stub-0.2.0/lib/sorbet-runtime-stub.rb deleted file mode 100644 index 3d6e9b7a28..0000000000 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-stub-0.2.0/lib/sorbet-runtime-stub.rb +++ /dev/null @@ -1,146 +0,0 @@ -# typed: ignore - -begin - gem "sorbet-runtime" - return -rescue Gem::LoadError -end - -module T - class << self - def absurd(value); end - def all(type_a, type_b, *types); end - def any(type_a, type_b, *types); end - def attached_class; end - def class_of(klass); end - def enum(values); end - def nilable(type); end - def noreturn; end - def self_type; end - def type_alias(type=nil, &_blk); end - def type_parameter(name); end - def untyped; end - - def assert_type!(value, _type, _checked: true) - value - end - - def cast(value, _type, _checked: true) - value - end - - def let(value, _type, _checked: true) - value - end - - def must(arg, _msg = nil) - arg - end - - def proc - T::Proc.new - end - - def reveal_type(value) - value - end - - def unsafe(value) - value - end - end - - module Sig - def sig(arg0=nil, &blk); end - end - - module Helpers - def abstract!; end - def interface!; end - def final!; end - def sealed!; end - def mixes_in_class_methods(mod); end - end - - module Generic - include T::Helpers - - def type_parameters(*params); end - def type_member(variance=:invariant, fixed: nil, lower: nil, upper: BasicObject); end - def type_template(variance=:invariant, fixed: nil, lower: nil, upper: BasicObject); end - - def [](*types) - self - end - end - - module Array - def self.[](type); end - end - - Boolean = Object.new.freeze - - module Configuration - def self.call_validation_error_handler(signature, opts); end - def self.call_validation_error_handler=(value); end - def self.default_checked_level=(default_checked_level); end - def self.enable_checking_for_sigs_marked_checked_tests; end - def self.enable_final_checks_on_hooks; end - def self.enable_legacy_t_enum_migration_mode; end - def self.reset_final_checks_on_hooks; end - def self.hard_assert_handler(str, extra); end - def self.hard_assert_handler=(value); end - def self.inline_type_error_handler(error); end - def self.inline_type_error_handler=(value); end - def self.log_info_handler(str, extra); end - def self.log_info_handler=(value); end - def self.scalar_types; end - def self.scalar_types=(values); end - def self.sealed_violation_whitelist; end - def self.sealed_violation_whitelist=(sealed_violation_whitelist); end - def self.sig_builder_error_handler(error, location); end - def self.sig_builder_error_handler=(value); end - def self.sig_validation_error_handler(error, opts); end - def self.sig_validation_error_handler=(value); end - def self.soft_assert_handler(str, extra); end - def self.soft_assert_handler=(value); end - end - - module Enumerable - def self.[](type); end - end - - module Enumerator - def self.[](type); end - end - - module Hash - def self.[](keys, values); end - end - - class Proc - def bind(*_) - self - end - - def params(*_param) - self - end - - def void - self - end - - def returns(_type) - self - end - end - - module Range - def self.[](type); end - end - - module Set - def self.[](type); end - end -end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo.rb similarity index 84% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo.rb index df447a9daf..b1b5344925 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo.rb @@ -3,6 +3,18 @@ # The top level module for TZInfo. module TZInfo + class << self + # Instructs the current {DataSource} to load all timezone and country data + # into memory (initializing the {DataSource} first if not previously + # accessed or set). + # + # This may be desirable in production environments to improve copy-on-write + # performance and to avoid flushing the constant cache every time a new + # timezone or country is loaded from {DataSources::RubyDataSource}. + def eager_load! + DataSource.get.eager_load! + end + end end # Object#untaint is a deprecated no-op in Ruby >= 2.7 and will be removed in diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/annual_rules.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/annual_rules.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/annual_rules.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/annual_rules.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/country.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/country.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/country.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/country.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/country_timezone.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/country_timezone.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/country_timezone.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/country_timezone.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_source.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_source.rb similarity index 97% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_source.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_source.rb index 6288aec221..952b435a15 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_source.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_source.rb @@ -247,6 +247,17 @@ module TZInfo raise_invalid_data_source('country_codes') end + # Loads all timezone and country data into memory. + # + # This may be desirable in production environments to improve copy-on-write + # performance and to avoid flushing the constant cache every time a new + # timezone or country is loaded from {DataSources::RubyDataSource}. + def eager_load! + timezone_identifiers.each {|identifier| load_timezone_info(identifier) } + country_codes.each {|code| load_country_info(code) } + nil + end + # @return [String] a description of the {DataSource}. def to_s "Default DataSource" diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/constant_offset_data_timezone_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/constant_offset_data_timezone_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/constant_offset_data_timezone_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/constant_offset_data_timezone_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/country_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/country_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/country_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/country_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/data_timezone_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/data_timezone_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/data_timezone_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/data_timezone_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/linked_timezone_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/linked_timezone_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/linked_timezone_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/linked_timezone_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/posix_time_zone_parser.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/posix_time_zone_parser.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/posix_time_zone_parser.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/posix_time_zone_parser.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/ruby_data_source.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/ruby_data_source.rb similarity index 98% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/ruby_data_source.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/ruby_data_source.rb index d2dbb26957..9c12322567 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/ruby_data_source.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/ruby_data_source.rb @@ -116,14 +116,14 @@ module TZInfo # @param identifier [Array] the component parts of a time zone # identifier (split on /). This must have already been validated. def require_definition(identifier) - require_data(*(['definitions'] + identifier)) + require_data('definitions', *identifier) end # Requires an index by its name. # # @param name [String] an index name. def require_index(name) - require_data(*['indexes', name]) + require_data('indexes', name) end # Requires a file from tzinfo/data. diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/timezone_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/timezone_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/timezone_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/timezone_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/transitions_data_timezone_info.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/transitions_data_timezone_info.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/transitions_data_timezone_info.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/transitions_data_timezone_info.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/zoneinfo_data_source.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/zoneinfo_data_source.rb similarity index 96% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/zoneinfo_data_source.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/zoneinfo_data_source.rb index cb76c3a2e8..cf77576f4c 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/zoneinfo_data_source.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/zoneinfo_data_source.rb @@ -78,6 +78,30 @@ module TZInfo DEFAULT_ALTERNATE_ISO3166_TAB_SEARCH_PATH = ['/usr/share/misc/iso3166.tab', '/usr/share/misc/iso3166'].freeze private_constant :DEFAULT_ALTERNATE_ISO3166_TAB_SEARCH_PATH + # Files and directories in the top level zoneinfo directory that will be + # excluded from the list of available time zones: + # + # - +VERSION is included on Mac OS X. + # - leapseconds is a list of leap seconds. + # - localtime is the current local timezone (may be a link). + # - posix, posixrules and right are directories containing other + # versions of the zoneinfo files. + # - SECURITY is included in the Arch Linux tzdata package. + # - src is a directory containing the tzdata source included on Solaris. + # - timeconfig is a symlink included on Slackware. + EXCLUDED_FILENAMES = [ + '+VERSION', + 'leapseconds', + 'localtime', + 'posix', + 'posixrules', + 'right', + 'SECURITY', + 'src', + 'timeconfig' + ].freeze + private_constant :EXCLUDED_FILENAMES + # Paths to be checked to find the system zoneinfo directory. # # @private @@ -394,15 +418,7 @@ module TZInfo def load_timezone_identifiers index = [] - # Ignoring particular files: - # +VERSION is included on Mac OS X. - # leapseconds is a list of leap seconds. - # localtime is the current local timezone (may be a link). - # posix, posixrules and right are directories containing other versions of the zoneinfo files. - # src is a directory containing the tzdata source included on Solaris. - # timeconfig is a symlink included on Slackware. - - enum_timezones([], ['+VERSION', 'leapseconds', 'localtime', 'posix', 'posixrules', 'right', 'src', 'timeconfig']) do |identifier| + enum_timezones([], EXCLUDED_FILENAMES) do |identifier| index << identifier.join('/').freeze end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/zoneinfo_reader.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/zoneinfo_reader.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_sources/zoneinfo_reader.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_sources/zoneinfo_reader.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_timezone.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_timezone.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/data_timezone.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/data_timezone.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/datetime_with_offset.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/datetime_with_offset.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/datetime_with_offset.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/datetime_with_offset.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1/country_definer.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1/country_definer.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1/country_definer.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1/country_definer.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1/country_index_definition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1/country_index_definition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1/country_index_definition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1/country_index_definition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1/timezone_definer.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1/timezone_definer.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1/timezone_definer.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1/timezone_definer.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1/timezone_definition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1/timezone_definition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1/timezone_definition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1/timezone_definition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1/timezone_index_definition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1/timezone_index_definition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format1/timezone_index_definition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format1/timezone_index_definition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/country_definer.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/country_definer.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/country_definer.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/country_definer.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/country_index_definer.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/country_index_definer.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/country_index_definer.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/country_index_definer.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/country_index_definition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/country_index_definition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/country_index_definition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/country_index_definition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/timezone_definer.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/timezone_definer.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/timezone_definer.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/timezone_definer.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/timezone_definition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/timezone_definition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/timezone_definition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/timezone_definition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/timezone_index_definer.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/timezone_index_definer.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/timezone_index_definer.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/timezone_index_definer.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/timezone_index_definition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/timezone_index_definition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/format2/timezone_index_definition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/format2/timezone_index_definition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/info_timezone.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/info_timezone.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/info_timezone.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/info_timezone.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/linked_timezone.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/linked_timezone.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/linked_timezone.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/linked_timezone.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/offset_timezone_period.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/offset_timezone_period.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/offset_timezone_period.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/offset_timezone_period.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/string_deduper.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/string_deduper.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/string_deduper.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/string_deduper.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/time_with_offset.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/time_with_offset.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/time_with_offset.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/time_with_offset.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timestamp.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timestamp.rb similarity index 95% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timestamp.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timestamp.rb index 5ab44f7848..9ec195c087 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timestamp.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timestamp.rb @@ -3,10 +3,11 @@ module TZInfo # A time represented as an `Integer` number of seconds since 1970-01-01 - # 00:00:00 UTC (ignoring leap seconds), the fraction through the second - # (sub_second as a `Rational`) and an optional UTC offset. Like Ruby's `Time` - # class, {Timestamp} can distinguish between a local time with a zero offset - # and a time specified explicitly as UTC. + # 00:00:00 UTC (ignoring leap seconds and using the proleptic Gregorian + # calendar), the fraction through the second (sub_second as a `Rational`) and + # an optional UTC offset. Like Ruby's `Time` class, {Timestamp} can + # distinguish between a local time with a zero offset and a time specified + # explicitly as UTC. class Timestamp include Comparable @@ -16,8 +17,8 @@ module TZInfo private_constant :JD_EPOCH class << self - # Returns a new {Timestamp} representing the (Gregorian calendar) date and - # time specified by the supplied parameters. + # Returns a new {Timestamp} representing the (proleptic Gregorian + # calendar) date and time specified by the supplied parameters. # # If `utc_offset` is `nil`, `:utc` or 0, the date and time parameters will # be interpreted as representing a UTC date and time. Otherwise the date @@ -37,7 +38,7 @@ module TZInfo # specified offset, an offset from UTC specified as an `Integer` number # of seconds or the `Symbol` `:utc`). # @return [Timestamp] a new {Timestamp} representing the specified - # (Gregorian calendar) date and time. + # (proleptic Gregorian calendar) date and time. # @raise [ArgumentError] if either of `year`, `month`, `day`, `hour`, # `minute`, or `second` is not an `Integer`. # @raise [ArgumentError] if `sub_second` is not a `Rational`, or the @@ -84,7 +85,8 @@ module TZInfo # When called with a block, the {Timestamp} representation of `value` is # passed to the block. The block must then return a {Timestamp}, which # will be converted back to the type of the initial value. If the initial - # value was a {Timestamp}, the block result will just be returned. + # value was a {Timestamp}, the block result will be returned. If the + # initial value was a `DateTime`, a Gregorian `DateTime` will be returned. # # The UTC offset of `value` can either be preserved (the {Timestamp} # representation will have the same UTC offset as `value`), ignored (the @@ -396,11 +398,11 @@ module TZInfo end end - # Converts this {Timestamp} to a `DateTime`. + # Converts this {Timestamp} to a Gregorian `DateTime`. # - # @return [DateTime] a DateTime representation of this {Timestamp}. If the - # UTC offset of this {Timestamp} is not specified, a UTC `DateTime` will - # be returned. + # @return [DateTime] a Gregorian `DateTime` representation of this + # {Timestamp}. If the UTC offset of this {Timestamp} is not specified, a + # UTC `DateTime` will be returned. def to_datetime new_datetime end @@ -408,7 +410,7 @@ module TZInfo # Converts this {Timestamp} to an `Integer` number of seconds since # 1970-01-01 00:00:00 UTC (ignoring leap seconds). # - # @return [Integer] an Integer representation of this {Timestamp} (the + # @return [Integer] an `Integer` representation of this {Timestamp} (the # number of seconds since 1970-01-01 00:00:00 UTC ignoring leap seconds). def to_i value @@ -492,7 +494,9 @@ module TZInfo # # @private def new_datetime(klass = DateTime) - datetime = klass.jd(JD_EPOCH + ((@value.to_r + @sub_second) / 86400)) + # Can't specify the start parameter unless the jd parameter is an exact number of days. + # Use #gregorian instead. + datetime = klass.jd(JD_EPOCH + ((@value.to_r + @sub_second) / 86400)).gregorian @utc_offset && @utc_offset != 0 ? datetime.new_offset(Rational(@utc_offset, 86400)) : datetime end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timestamp_with_offset.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timestamp_with_offset.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timestamp_with_offset.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timestamp_with_offset.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timezone.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timezone.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timezone_offset.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone_offset.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timezone_offset.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone_offset.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timezone_period.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone_period.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timezone_period.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone_period.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timezone_proxy.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone_proxy.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timezone_proxy.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone_proxy.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timezone_transition.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone_transition.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/timezone_transition.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/timezone_transition.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/transition_rule.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/transition_rule.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/transition_rule.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/transition_rule.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/transitions_timezone_period.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/transitions_timezone_period.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/transitions_timezone_period.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/transitions_timezone_period.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/untaint_ext.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/untaint_ext.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/untaint_ext.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/untaint_ext.rb diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/version.rb similarity index 83% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/version.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/version.rb index 6538121541..1b1599423f 100644 --- a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/version.rb +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/version.rb @@ -3,5 +3,5 @@ module TZInfo # The TZInfo version number. - VERSION = '2.0.4' + VERSION = '2.0.5' end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/with_offset.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/with_offset.rb similarity index 100% rename from Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.4/lib/tzinfo/with_offset.rb rename to Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/tzinfo-2.0.5/lib/tzinfo/with_offset.rb diff --git a/bin/brew b/bin/brew index 4c06f135a0..30e1fec5f2 100755 --- a/bin/brew +++ b/bin/brew @@ -75,7 +75,7 @@ HOMEBREW_LIBRARY="${HOMEBREW_REPOSITORY}/Library" # Copy and export all HOMEBREW_* variables previously mentioned in # manpage or used elsewhere by Homebrew. -for VAR in BAT_THEME BROWSER DISPLAY EDITOR NO_COLOR PATH TMUX DBUS_SESSION_BUS_ADDRESS +for VAR in BAT_THEME BROWSER DISPLAY EDITOR NO_COLOR TMUX DBUS_SESSION_BUS_ADDRESS do # Skip if variable value is empty. [[ -z "${!VAR}" ]] && continue @@ -109,6 +109,11 @@ then export CI="1" fi +# save the existing user path as HOMEBREW_PATH so it can be queried by +# e.g. brew doctor later. +HOMEBREW_PATH="${PATH}" +export HOMEBREW_PATH + # set from user environment # shellcheck disable=SC2154 if [[ -z "${HOMEBREW_NO_ENV_FILTERING}" ]] @@ -120,9 +125,7 @@ then HOME SHELL PATH TERM TERMINFO TERMINFO_DIRS COLUMNS DISPLAY LOGNAME USER CI SSH_AUTH_SOCK SUDO_ASKPASS http_proxy https_proxy ftp_proxy no_proxy all_proxy HTTPS_PROXY FTP_PROXY ALL_PROXY GITHUB_ACTIONS GITHUB_WORKSPACE GITHUB_ACTIONS_HOMEBREW_SELF_HOSTED - GITHUB_REPOSITORY GITHUB_RUN_ID GITHUB_SHA GITHUB_HEAD_REF GITHUB_BASE_REF GITHUB_REF - # TODO: remove the below after a few days - GITHUB_ACTIONS_HOMEBREW_MACOS_SELF_HOSTED + GITHUB_REPOSITORY GITHUB_RUN_ID GITHUB_RUN_ATTEMPT GITHUB_SHA GITHUB_HEAD_REF GITHUB_BASE_REF GITHUB_REF ) # Filter all but the specific variables. for VAR in "${ENV_VAR_NAMES[@]}" "${!HOMEBREW_@}" diff --git a/completions/bash/brew b/completions/bash/brew index 52f38dc610..7ee107cea1 100644 --- a/completions/bash/brew +++ b/completions/bash/brew @@ -312,6 +312,7 @@ _brew_abv() { --installed --json --quiet + --variations --verbose " return @@ -669,6 +670,25 @@ _brew_config() { esac } +_brew_contributions() { + local cur="${COMP_WORDS[COMP_CWORD]}" + case "${cur}" in + -*) + __brewcomp " + --debug + --from + --help + --quiet + --repositories + --to + --verbose + " + return + ;; + *) + esac +} + _brew_create() { local cur="${COMP_WORDS[COMP_CWORD]}" case "${cur}" in @@ -1044,6 +1064,7 @@ _brew_info() { --installed --json --quiet + --variations --verbose " return @@ -2477,6 +2498,7 @@ _brew() { commands) _brew_commands ;; completions) _brew_completions ;; config) _brew_config ;; + contributions) _brew_contributions ;; create) _brew_create ;; deps) _brew_deps ;; desc) _brew_desc ;; diff --git a/completions/fish/brew.fish b/completions/fish/brew.fish index a2388a139b..17e0059810 100644 --- a/completions/fish/brew.fish +++ b/completions/fish/brew.fish @@ -307,6 +307,7 @@ __fish_brew_complete_arg 'abv' -l help -d 'Show this message' __fish_brew_complete_arg 'abv' -l installed -d 'Print JSON of formulae that are currently installed' __fish_brew_complete_arg 'abv' -l json -d 'Print a JSON representation. Currently the default value for version is `v1` for formula. For formula and cask use `v2`. See the docs for examples of using the JSON output: https://docs.brew.sh/Querying-Brew' __fish_brew_complete_arg 'abv' -l quiet -d 'Make some output more quiet' +__fish_brew_complete_arg 'abv' -l variations -d 'Include the variations hash in each formula\'s JSON output' __fish_brew_complete_arg 'abv' -l verbose -d 'Show more verbose analytics data for formula' __fish_brew_complete_arg 'abv; and not __fish_seen_argument -l cask -l casks' -a '(__fish_brew_suggest_formulae_all)' __fish_brew_complete_arg 'abv; and not __fish_seen_argument -l formula -l formulae' -a '(__fish_brew_suggest_casks_all)' @@ -528,6 +529,16 @@ __fish_brew_complete_arg 'config' -l quiet -d 'Make some output more quiet' __fish_brew_complete_arg 'config' -l verbose -d 'Make some output more verbose' +__fish_brew_complete_cmd 'contributions' 'Contributions to Homebrew repos for a user' +__fish_brew_complete_arg 'contributions' -l debug -d 'Display any debugging information' +__fish_brew_complete_arg 'contributions' -l from -d 'Date (ISO-8601 format) to start searching contributions' +__fish_brew_complete_arg 'contributions' -l help -d 'Show this message' +__fish_brew_complete_arg 'contributions' -l quiet -d 'Make some output more quiet' +__fish_brew_complete_arg 'contributions' -l repositories -d 'Specify a comma-separated (no spaces) list of repositories to search. Supported repositories: `brew`, `core`, `cask`, `aliases`, `autoupdate`, `bundle`, `command-not-found`, `test-bot`, `services`, `cask-drivers`, `cask-fonts` and `cask-versions`.Omitting this flag, or specifying `--repositories=all`, will search all repositories' +__fish_brew_complete_arg 'contributions' -l to -d 'Date (ISO-8601 format) to stop searching contributions' +__fish_brew_complete_arg 'contributions' -l verbose -d 'Make some output more verbose' + + __fish_brew_complete_cmd 'create' 'Generate a formula or, with `--cask`, a cask for the downloadable file at URL and open it in the editor' __fish_brew_complete_arg 'create' -l HEAD -d 'Indicate that URL points to the package\'s repository rather than a file' __fish_brew_complete_arg 'create' -l autotools -d 'Create a basic template for an Autotools-style build' @@ -757,6 +768,7 @@ __fish_brew_complete_arg 'info' -l help -d 'Show this message' __fish_brew_complete_arg 'info' -l installed -d 'Print JSON of formulae that are currently installed' __fish_brew_complete_arg 'info' -l json -d 'Print a JSON representation. Currently the default value for version is `v1` for formula. For formula and cask use `v2`. See the docs for examples of using the JSON output: https://docs.brew.sh/Querying-Brew' __fish_brew_complete_arg 'info' -l quiet -d 'Make some output more quiet' +__fish_brew_complete_arg 'info' -l variations -d 'Include the variations hash in each formula\'s JSON output' __fish_brew_complete_arg 'info' -l verbose -d 'Show more verbose analytics data for formula' __fish_brew_complete_arg 'info; and not __fish_seen_argument -l cask -l casks' -a '(__fish_brew_suggest_formulae_all)' __fish_brew_complete_arg 'info; and not __fish_seen_argument -l formula -l formulae' -a '(__fish_brew_suggest_casks_all)' diff --git a/completions/internal_commands_list.txt b/completions/internal_commands_list.txt index 09af017ba6..408b5635d0 100644 --- a/completions/internal_commands_list.txt +++ b/completions/internal_commands_list.txt @@ -26,6 +26,7 @@ command commands completions config +contributions create deps desc diff --git a/completions/zsh/_brew b/completions/zsh/_brew index aa175d3830..e8b6c5d327 100644 --- a/completions/zsh/_brew +++ b/completions/zsh/_brew @@ -152,6 +152,7 @@ __brew_internal_commands() { 'commands:Show lists of built-in and external commands' 'completions:Control whether Homebrew automatically links external tap shell completion files' 'config:Show Homebrew and system configuration info useful for debugging' + 'contributions:Contributions to Homebrew repos for a user' 'create:Generate a formula or, with `--cask`, a cask for the downloadable file at URL and open it in the editor' 'deps:Show dependencies for formula' 'desc:Display formula'\''s name and one-line description' @@ -382,6 +383,7 @@ _brew_abv() { '(--all)--installed[Print JSON of formulae that are currently installed]' \ '--json[Print a JSON representation. Currently the default value for version is `v1` for formula. For formula and cask use `v2`. See the docs for examples of using the JSON output: https://docs.brew.sh/Querying-Brew]' \ '--quiet[Make some output more quiet]' \ + '--variations[Include the variations hash in each formula'\''s JSON output]' \ '--verbose[Show more verbose analytics data for formula]' \ - formula \ '(--cask)--formula[Treat all named arguments as formulae]' \ @@ -651,6 +653,18 @@ _brew_config() { '--verbose[Make some output more verbose]' } +# brew contributions +_brew_contributions() { + _arguments \ + '--debug[Display any debugging information]' \ + '--from[Date (ISO-8601 format) to start searching contributions]' \ + '--help[Show this message]' \ + '--quiet[Make some output more quiet]' \ + '--repositories[Specify a comma-separated (no spaces) list of repositories to search. Supported repositories: `brew`, `core`, `cask`, `aliases`, `autoupdate`, `bundle`, `command-not-found`, `test-bot`, `services`, `cask-drivers`, `cask-fonts` and `cask-versions`.Omitting this flag, or specifying `--repositories=all`, will search all repositories]' \ + '--to[Date (ISO-8601 format) to stop searching contributions]' \ + '--verbose[Make some output more verbose]' +} + # brew create _brew_create() { _arguments \ @@ -931,6 +945,7 @@ _brew_info() { '(--all)--installed[Print JSON of formulae that are currently installed]' \ '--json[Print a JSON representation. Currently the default value for version is `v1` for formula. For formula and cask use `v2`. See the docs for examples of using the JSON output: https://docs.brew.sh/Querying-Brew]' \ '--quiet[Make some output more quiet]' \ + '--variations[Include the variations hash in each formula'\''s JSON output]' \ '--verbose[Show more verbose analytics data for formula]' \ - formula \ '(--cask)--formula[Treat all named arguments as formulae]' \ diff --git a/docs/Acceptable-Formulae.md b/docs/Acceptable-Formulae.md index 40b5c62467..126c330054 100644 --- a/docs/Acceptable-Formulae.md +++ b/docs/Acceptable-Formulae.md @@ -7,7 +7,7 @@ own! ### Supported platforms in `homebrew/core` -The formula needs to build and pass tests on the latest 3 supported macOS versions ([x86_64 and Apple Silicon/ARM](Installation.md#macos-requirements)) and on x86_64 Linux. +The formula needs to build and pass tests on the latest 3 supported macOS versions ([x86_64 and Apple Silicon/ARM](Installation.md#macos-requirements)) and on x86_64 [Linux](Linux-CI.md). Please have a look at the continuous integration jobs on a pull request in `homebrew/core` to see the full list of OSs. If upstream does not support one of these platforms, an exception can be made and the formula can be disabled for that platform. diff --git a/docs/Cask-Cookbook.md b/docs/Cask-Cookbook.md index 577bd2cdf0..e1d26d6fe4 100644 --- a/docs/Cask-Cookbook.md +++ b/docs/Cask-Cookbook.md @@ -108,7 +108,7 @@ cask "" do [``](#token-reference) should match the Cask filename, without the `.rb` extension, enclosed in single quotes. -There are currently some arbitrary limitations on Cask tokens which are in the process of being removed. The Travis bot will catch any errors during the transition. +There are currently some arbitrary limitations on Cask tokens which are in the process of being removed. GitHub Actions will catch any errors during the transition. ## Stanza order diff --git a/docs/FAQ.md b/docs/FAQ.md index e9325489a9..6d37d8a629 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -78,10 +78,10 @@ Homebrew provides pre-built binary packages for many formulae. These are referre If available, bottled binaries will be used by default except under the following conditions: -* Options were passed to the install command, i.e. `brew install ` will use a bottled version of the formula, but `brew install --enable-bar ` will trigger a source build. * The `--build-from-source` option is invoked. * No bottle is available for the machine's currently running OS version. (Bottles for macOS are generated only for supported macOS versions.) * Homebrew is installed to a prefix other than the default (although some bottles support this). +* Formula options were passed to the install command. For example, `brew install ` will try to find a bottled binary, but `brew install --with-foo ` will trigger a source build. We aim to bottle everything. diff --git a/docs/Formula-Cookbook.md b/docs/Formula-Cookbook.md index 0355953b85..daf02b572e 100644 --- a/docs/Formula-Cookbook.md +++ b/docs/Formula-Cookbook.md @@ -544,6 +544,52 @@ Instead of `git diff | pbcopy`, for some editors `git diff >> path/to/your/formu If anything isn’t clear, you can usually figure it out by `grep`ping the `$(brew --repository homebrew/core)` directory. Please submit a pull request to amend this document if you think it will help! +### Handling different system configurations + +Often, formulae need different dependencies, resources, patches, conflicts, deprecations or `keg_only` statuses on different OSes and arches. In these cases, the components can be nested inside `on_macos`, `on_linux`, `on_arm` or `on_intel` blocks. For example, here's how to add `gcc` as a Linux-only dependency: + +```ruby +on_linux do + depends_on "gcc" +end +``` + +Components can also be declared for specific macOS versions or version ranges. For example, to declare a dependency only on High Sierra, nest the `depends_on` call inside an `on_high_sierra` block. Add an `:or_older` or `:or_newer` parameter to the `on_high_sierra` method to add the dependency to all macOS versions that meet the condition. For example, to add `gettext` as a build dependency on Mojave and all later macOS versions, use: + +```ruby +on_mojave :or_newer do + depends_on "gettext" => :build +end +``` + +Sometimes, a dependency is needed on certain macOS versions *and* on Linux. In these cases, a special `on_system` method can be used: + +```ruby +on_system :linux, macos: :sierra_or_older do + depends_on "gettext" => :build +end +``` + +To check multiple conditions, nest the corresponding blocks. For example, the following code adds a `gettext` build dependency when on ARM *and* macOS: + +```ruby +on_macos do + on_arm do + depends_on "gettext" => :build + end +end +``` + +#### Inside `def install` and `test do` + +Inside `def install` and `test do`, don't use these `on_*` methods. Instead, use `if` statements and the following conditionals: + +* `OS.mac?` and `OS.linux?` return `true` or `false` based on the OS +* `Hardware::CPU.intel?` and `Hardware::CPU.arm?` return `true` or `false` based on the arch +* `MacOS.version` returns the current macOS version. Use `==`, `<=` or `>=` to compare to symbols corresponding to macOS versions (e.g. `if MacOS.version >= :mojave`) + +See [`rust`](https://github.com/Homebrew/homebrew-core/blob/fe831237a7c24033a48f588a1578ba54f953f922/Formula/rust.rb#L72) for an example. + ### `livecheck` blocks When `brew livecheck` is unable to identify versions for a formula, we can control its behavior using a `livecheck` block. Here is a simple example to check a page for links containing a filename like `example-1.2.tar.gz`: diff --git a/docs/Homebrew-linuxbrew-core-Maintainer-Guide.md b/docs/Homebrew-linuxbrew-core-Maintainer-Guide.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/Linux-CI.md b/docs/Linux-CI.md new file mode 100644 index 0000000000..f69540771d --- /dev/null +++ b/docs/Linux-CI.md @@ -0,0 +1,35 @@ +# Linux CI in `homebrew/core` + +We currently use Ubuntu 16.04 for bottling in `homebrew/core`. + +### Ubuntu versus other distributions + +As of 2022, around 77% of our users are using Ubuntu. This is the reason why we have chosen this distribution for our base CI image. +We have been using Ubuntu for CI since version 14.04 with success. +The LTS versions have 5 year support. A new LTS version is released every 2 years. + +Our bottles are compatible with other distributions like Debian/CentOS, even when compiled on Ubuntu. + +### Past and next versions + +We are currently moving our CI to Ubuntu 22.04. This work will probably be done before end of 2022. +Moving from Ubuntu 16.04 to Ubuntu 22.04 (and thus skipping version 18.04 and 20.04) took more time than expected due to other more urgent issues we had to take care of. + +We plan to proceed with a more regular update from 2022 on. We aim to use the latest Ubuntu LTS version for our CI. + +We will start using the latest Ubuntu LTS version for our CI 3 months after it's release. Ideally the migration to the newest version will be done within 12 months after the LTS release, depending of course on the maintainer bandwidth to carry out such a migration. + +| Distribution | Glibc | GCC | Usage | +|---|---|---|---| +| Ubuntu 14.04 | 2.19 | 4 | From 2014 to 2017 | +| Ubuntu 16.04 | 2.23 | 5 | From 2017 to 2022 | +| Ubuntu 22.04 | 2.35 | 11 | From 2022 to 2024 | +| Ubuntu 24.04 | ? | ? | From 2024 to 2026 | + +### Why always using the latests version? + +Homebrew is a rolling-release package manager. We try to ship the newest things as quickest as possible, on macOS and Linux. + +When a formula needs a newer GCC because our host GCC in CI is too old, we need to make that formula depend on a newer Homebrew GCC. All C++ dependents of that formula immediately acquire a dependency on Homebrew GCC as well. While we have taken the steps to make sure this no longer holds up GCC updates, it still creates a maintenance headache. This problem is more likely for formula which are very actively maintained and try to use newer features of C++. We decided that we shouldn't be creating maintenance burdens for formulae which are doing the right thing by staying up to date. It makes a lot of sense for Homebrew maintainers to submit upstream fixes when formulae are not working with newer compilers. It makes a lot less sense for Homebrew maintainers to submit fixes because our host compiler is too old. + +Note that `glibc` will need to be installed for more users as their `glibc` version will often be too old: disk space is cheap and we have can handle this situation for our users. This situation will often arise when update to a new LTS version and adoption of the new Ubuntu is still low during the first months. For the same reasons as above: we prefer to stay on the bleeding edge and give our users a gentle nudge to think about updating their OS. diff --git a/docs/Manpage.md b/docs/Manpage.md index f74003edb1..c08de40f3c 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -295,6 +295,8 @@ If a *`formula`* or *`cask`* is provided, show summary of information about it. Print JSON of formulae that are currently installed. * `--all`: Print JSON of all available formulae. +* `--variations`: + Include the variations hash in each formula's JSON output. * `-v`, `--verbose`: Show more verbose analytics data for *`formula`*. * `--formula`: @@ -1079,6 +1081,19 @@ Display the source of a *`formula`* or *`cask`*. Display the path to the file being used when invoking `brew` *`cmd`*. +### `contributions` *`email|name`* [*`--repositories`*`=`] + +Contributions to Homebrew repos for a user. + +The first argument is a name (e.g. "BrewTestBot") or an email address (e.g. "brewtestbot@brew.sh"). + +* `--repositories`: + Specify a comma-separated (no spaces) list of repositories to search. Supported repositories: `brew`, `core`, `cask`, `aliases`, `autoupdate`, `bundle`, `command-not-found`, `test-bot`, `services`, `cask-drivers`, `cask-fonts` and `cask-versions`.Omitting this flag, or specifying `--repositories=all`, will search all repositories. +* `--from`: + Date (ISO-8601 format) to start searching contributions. +* `--to`: + Date (ISO-8601 format) to stop searching contributions. + ### `create` [*`options`*] *`URL`* Generate a formula or, with `--cask`, a cask for the downloadable file at *`URL`* @@ -1945,6 +1960,9 @@ example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just *Default:* `300`. +- `HOMEBREW_AUTOREMOVE` +
If set, calls to `brew cleanup` and `brew uninstall` will automatically remove unused formula dependents and if HOMEBREW_NO_INSTALL_CLEANUP is not set, `brew cleanup` will start running `brew autoremove` periodically. + - `HOMEBREW_BAT`
If set, use `bat` for the `brew cat` command. @@ -2125,7 +2143,7 @@ example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just
If set, do not check for broken linkage of dependents or outdated dependents after installing, upgrading or reinstalling formulae. This will result in fewer dependents (and their dependencies) being upgraded or reinstalled but may result in more breakage from running `brew install *`formula`*` or `brew upgrade *`formula`*`. - `HOMEBREW_NO_CLEANUP_FORMULAE` -
A comma-separated list of formulae. Homebrew will refuse to clean up a formula if it appears on this list. +
A comma-separated list of formulae. Homebrew will refuse to clean up or autoremove a formula if it appears on this list. - `HOMEBREW_NO_COLOR`
If set, do not print text with colour added. diff --git a/manpages/brew.1 b/manpages/brew.1 index 87c2999563..ed2d1ef1ff 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BREW" "1" "July 2022" "Homebrew" "brew" +.TH "BREW" "1" "August 2022" "Homebrew" "brew" . .SH "NAME" \fBbrew\fR \- The Missing Package Manager for macOS (or Linux) @@ -385,6 +385,10 @@ Print JSON of formulae that are currently installed\. Print JSON of all available formulae\. . .TP +\fB\-\-variations\fR +Include the variations hash in each formula\'s JSON output\. +. +.TP \fB\-v\fR, \fB\-\-verbose\fR Show more verbose analytics data for \fIformula\fR\. . @@ -1535,6 +1539,24 @@ Treat all named arguments as casks\. .SS "\fBcommand\fR \fIcommand\fR [\.\.\.]" Display the path to the file being used when invoking \fBbrew\fR \fIcmd\fR\. . +.SS "\fBcontributions\fR \fIemail|name\fR [\fI\-\-repositories\fR\fB=\fR]" +Contributions to Homebrew repos for a user\. +. +.P +The first argument is a name (e\.g\. "BrewTestBot") or an email address (e\.g\. "brewtestbot@brew\.sh")\. +. +.TP +\fB\-\-repositories\fR +Specify a comma\-separated (no spaces) list of repositories to search\. Supported repositories: \fBbrew\fR, \fBcore\fR, \fBcask\fR, \fBaliases\fR, \fBautoupdate\fR, \fBbundle\fR, \fBcommand\-not\-found\fR, \fBtest\-bot\fR, \fBservices\fR, \fBcask\-drivers\fR, \fBcask\-fonts\fR and \fBcask\-versions\fR\.Omitting this flag, or specifying \fB\-\-repositories=all\fR, will search all repositories\. +. +.TP +\fB\-\-from\fR +Date (ISO\-8601 format) to start searching contributions\. +. +.TP +\fB\-\-to\fR +Date (ISO\-8601 format) to stop searching contributions\. +. .SS "\fBcreate\fR [\fIoptions\fR] \fIURL\fR" Generate a formula or, with \fB\-\-cask\fR, a cask for the downloadable file at \fIURL\fR and open it in the editor\. Homebrew will attempt to automatically derive the formula name and version, but if it fails, you\'ll have to make your own template\. The \fBwget\fR formula serves as a simple example\. For the complete API, see: \fIhttps://rubydoc\.brew\.sh/Formula\fR . @@ -2757,6 +2779,12 @@ Run \fBbrew update\fR once every \fBHOMEBREW_AUTO_UPDATE_SECS\fR seconds before \fIDefault:\fR \fB300\fR\. . .TP +\fBHOMEBREW_AUTOREMOVE\fR +. +.br +If set, calls to \fBbrew cleanup\fR and \fBbrew uninstall\fR will automatically remove unused formula dependents and if HOMEBREW_NO_INSTALL_CLEANUP is not set, \fBbrew cleanup\fR will start running \fBbrew autoremove\fR periodically\. +. +.TP \fBHOMEBREW_BAT\fR . .br @@ -3096,7 +3124,7 @@ If set, do not check for broken linkage of dependents or outdated dependents aft \fBHOMEBREW_NO_CLEANUP_FORMULAE\fR . .br -A comma\-separated list of formulae\. Homebrew will refuse to clean up a formula if it appears on this list\. +A comma\-separated list of formulae\. Homebrew will refuse to clean up or autoremove a formula if it appears on this list\. . .TP \fBHOMEBREW_NO_COLOR\fR