diff --git a/.gitignore b/.gitignore index ca8d5f18ab..ac1c8e974d 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ # Unignore vendored gems !**/vendor/bundle/ruby/*/gems/*/lib !**/vendor/bundle/ruby/*/gems/rubocop-performance-*/config +!**/vendor/bundle/ruby/*/gems/rubocop-rails-*/config !**/vendor/bundle/ruby/*/gems/rubocop-rspec-*/config !**/vendor/bundle/ruby/*/gems/rubocop-sorbet-*/config diff --git a/Library/.rubocop.yml b/Library/.rubocop.yml index ca07033f9f..631e4e8826 100644 --- a/Library/.rubocop.yml +++ b/Library/.rubocop.yml @@ -13,33 +13,34 @@ AllCops: # enable all pending rubocops NewCops: enable Include: - - '**/*.rbi' + - "**/*.rbi" Exclude: - - 'Homebrew/sorbet/rbi/gems/**/*.rbi' - - 'Homebrew/sorbet/rbi/hidden-definitions/**/*.rbi' - - 'Homebrew/sorbet/rbi/todo.rbi' - - 'Homebrew/sorbet/rbi/upstream.rbi' - - 'Homebrew/bin/*' - - 'Homebrew/vendor/**/*' + - "Homebrew/sorbet/rbi/gems/**/*.rbi" + - "Homebrew/sorbet/rbi/hidden-definitions/**/*.rbi" + - "Homebrew/sorbet/rbi/todo.rbi" + - "Homebrew/sorbet/rbi/upstream.rbi" + - "Homebrew/bin/*" + - "Homebrew/vendor/**/*" + - "Taps/*/*/vendor/**/*" Cask/Desc: - Description: 'Ensure that the desc stanza conforms to various content and style checks.' + Description: "Ensure that the desc stanza conforms to various content and style checks." Enabled: true Cask/HomepageUrlTrailingSlash: - Description: 'Ensure that the homepage url has a slash after the domain name.' + Description: "Ensure that the homepage url has a slash after the domain name." Enabled: true Cask/NoDslVersion: - Description: 'Do not use the deprecated DSL version syntax in your cask header.' + Description: "Do not use the deprecated DSL version syntax in your cask header." Enabled: true Cask/StanzaGrouping: - Description: 'Ensure that cask stanzas are grouped correctly. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/readme.md#stanza-order' + Description: "Ensure that cask stanzas are grouped correctly. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/readme.md#stanza-order" Enabled: true Cask/StanzaOrder: - Description: 'Ensure that cask stanzas are sorted correctly. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/readme.md#stanza-order' + Description: "Ensure that cask stanzas are sorted correctly. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/readme.md#stanza-order" Enabled: true # enable all formulae audits @@ -105,9 +106,9 @@ Style/HashTransformValues: # Allow for license expressions Style/HashAsLastArrayItem: Exclude: - - 'Taps/*/*/*.rb' - - '/**/Formula/*.rb' - - '**/Formula/*.rb' + - "Taps/*/*/*.rb" + - "/**/Formula/*.rb" + - "**/Formula/*.rb" # Enabled now LineLength is lowish. Style/IfUnlessModifier: @@ -118,7 +119,7 @@ Style/NumericLiterals: MinDigits: 7 Strict: true Exclude: - - '**/Brewfile' + - "**/Brewfile" # Zero-prefixed octal literals are widely used and understood. Style/NumericLiteralPrefix: @@ -166,13 +167,30 @@ Performance/Caller: Performance/MethodObjectAsBlock: Enabled: false +# Cannot use ActiveSupport in RuboCops. +Rails: + Exclude: + - "Homebrew/rubocops/**/*" + +# Skip these as they only apply to actual Rails and not our ActiveSupport usage. +Rails/Date: + Enabled: false +Rails/Delegate: + Enabled: false +Rails/SkipsModelValidations: + Enabled: false +Rails/Pluck: + Enabled: false +Rails/TimeZone: + Enabled: false + # Don't allow cops to be disabled in casks and formulae. Style/DisableCopsWithinSourceCodeDirective: Enabled: true Include: - - 'Taps/*/*/*.rb' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' + - "Taps/*/*/*.rb" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" # make our hashes consistent Layout/HashAlignment: @@ -182,9 +200,9 @@ Layout/HashAlignment: # `system` is a special case and aligns on second argument, so allow this for formulae. Layout/ArgumentAlignment: Exclude: - - 'Taps/*/*/*.rb' - - '/**/Formula/*.rb' - - '**/Formula/*.rb' + - "Taps/*/*/*.rb" + - "/**/Formula/*.rb" + - "**/Formula/*.rb" # this is a bit less "floaty" Layout/CaseIndentation: @@ -208,120 +226,137 @@ Lint/AmbiguousBlockAssociation: Lint/DuplicateBranch: Exclude: - - 'Taps/*/*/*.rb' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' + - "Taps/*/*/*.rb" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" # needed for lazy_object magic Naming/MemoizedInstanceVariableName: Exclude: - - 'Homebrew/lazy_object.rb' + - "Homebrew/lazy_object.rb" # so many of these in formulae and can't be autocorrected # TODO: fix these as `ruby -w` complains about them. Lint/AmbiguousRegexpLiteral: Exclude: - - 'Taps/*/*/*.rb' - - '/**/Formula/*.rb' - - '**/Formula/*.rb' + - "Taps/*/*/*.rb" + - "/**/Formula/*.rb" + - "**/Formula/*.rb" # useful for metaprogramming in RSpec Lint/ConstantDefinitionInBlock: Exclude: - - '**/*_spec.rb' + - "**/*_spec.rb" # so many of these in formulae and can't be autocorrected Lint/ParenthesesAsGroupedExpression: Exclude: - - 'Taps/*/*/*.rb' - - '/**/Formula/*.rb' - - '**/Formula/*.rb' + - "Taps/*/*/*.rb" + - "/**/Formula/*.rb" + - "**/Formula/*.rb" # Most metrics don't make sense to apply for casks/formulae/taps. Metrics/AbcSize: Exclude: - - 'Taps/**/*' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' + - "Taps/**/*" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" Metrics/BlockLength: Exclude: - - 'Taps/**/*' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' + - "Taps/**/*" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" Metrics/ClassLength: Exclude: - - 'Taps/**/*' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' + - "Taps/**/*" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" Metrics/CyclomaticComplexity: Exclude: - - 'Taps/**/*' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' + - "Taps/**/*" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" Metrics/MethodLength: Exclude: - - 'Taps/**/*' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' + - "Taps/**/*" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" Metrics/ModuleLength: Exclude: - - 'Taps/**/*' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' + - "Taps/**/*" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" Metrics/PerceivedComplexity: Exclude: - - 'Taps/**/*' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' + - "Taps/**/*" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" # allow those that are standard # TODO: try to remove some of these Naming/MethodParameterName: AllowedNames: - - '_' - - 'a' - - 'b' - - 'cc' - - 'c1' - - 'c2' - - 'd' - - 'e' - - 'f' - - 'ff' - - 'fn' - - 'id' - - 'io' - - 'o' - - 'p' - - 'pr' - - 'r' - - 'rb' - - 's' - - 'to' - - 'v' + - "_" + - "a" + - "b" + - "cc" + - "c1" + - "c2" + - "d" + - "e" + - "f" + - "ff" + - "fn" + - "id" + - "io" + - "o" + - "p" + - "pr" + - "r" + - "rb" + - "s" + - "to" + - "v" # GitHub diff UI wraps beyond 118 characters Layout/LineLength: Max: 118 # ignore manpage comments and long single-line strings - IgnoredPatterns: ['#: ', ' url "', ' mirror "', ' plist_options ', - ' appcast "', ' executable: "', ' font "', ' homepage "', ' name "', - ' pkg "', ' pkgutil: "', '#{language}', '#{version.', - ' "/Library/Application Support/', '"/Library/Caches/', '"/Library/PreferencePanes/', - ' "~/Library/Application Support/', '"~/Library/Caches/', '"~/Application Support', - ' was verified as official when first introduced to the cask'] + IgnoredPatterns: + [ + "#: ", + ' url "', + ' mirror "', + " plist_options ", + ' appcast "', + ' executable: "', + ' font "', + ' homepage "', + ' name "', + ' pkg "', + ' pkgutil: "', + "#{language}", + "#{version.", + ' "/Library/Application Support/', + '"/Library/Caches/', + '"/Library/PreferencePanes/', + ' "~/Library/Application Support/', + '"~/Library/Caches/', + '"~/Application Support', + " was verified as official when first introduced to the cask", + ] Sorbet/FalseSigil: Exclude: - - 'Taps/**/*' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' - - 'Homebrew/test/**/Casks/**/*.rb' + - "Taps/**/*" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" + - "Homebrew/test/**/Casks/**/*.rb" Sorbet/StrictSigil: Enabled: true Include: - - '**/*.rbi' + - "**/*.rbi" # Try getting rid of these. Sorbet/ConstantsFromStrings: @@ -339,48 +374,48 @@ Style/AccessorGrouping: # make rspec formatting more flexible Style/BlockDelimiters: Exclude: - - 'Homebrew/**/*_spec.rb' - - 'Homebrew/**/shared_examples/**/*.rb' + - "Homebrew/**/*_spec.rb" + - "Homebrew/**/shared_examples/**/*.rb" # TODO: remove this when possible. Style/ClassVars: Exclude: - - '**/developer/bin/*' + - "**/developer/bin/*" # Don't enforce documentation in casks or formulae. Style/Documentation: Exclude: - - 'Taps/**/*' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' - - '**/*.rbi' + - "Taps/**/*" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" + - "**/*.rbi" Style/DocumentationMethod: Include: - - 'Homebrew/formula.rb' + - "Homebrew/formula.rb" # Not used for casks and formulae. Style/FrozenStringLiteralComment: EnforcedStyle: always Exclude: - - 'Taps/*/*/*.rb' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' - - 'Homebrew/test/**/Casks/**/*.rb' - - '**/*.rbi' - - '**/Brewfile' + - "Taps/*/*/*.rb" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" + - "Homebrew/test/**/Casks/**/*.rb" + - "**/*.rbi" + - "**/Brewfile" # TODO: remove this when possible. Style/GlobalVars: Exclude: - - '**/developer/bin/*' + - "**/developer/bin/*" # potential for errors in formulae too high with this Style/GuardClause: Exclude: - - 'Taps/*/*/*.rb' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' + - "Taps/*/*/*.rb" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" # avoid hash rockets where possible Style/HashSyntax: @@ -389,9 +424,9 @@ Style/HashSyntax: # so many of these in formulae and can't be autocorrected Style/StringConcatenation: Exclude: - - 'Taps/*/*/*.rb' - - '/**/{Formula,Casks}/*.rb' - - '**/{Formula,Casks}/*.rb' + - "Taps/*/*/*.rb" + - "/**/{Formula,Casks}/*.rb" + - "**/{Formula,Casks}/*.rb" # ruby style guide favorite Style/StringLiterals: diff --git a/Library/Homebrew/Gemfile b/Library/Homebrew/Gemfile index 00681d456d..0be5af4669 100644 --- a/Library/Homebrew/Gemfile +++ b/Library/Homebrew/Gemfile @@ -25,6 +25,7 @@ gem "mechanize" gem "patchelf" gem "plist" gem "rubocop-performance" +gem "rubocop-rails" gem "rubocop-rspec" gem "rubocop-sorbet" gem "ruby-macho" diff --git a/Library/Homebrew/Gemfile.lock b/Library/Homebrew/Gemfile.lock index d5cc461127..23e3b9abcb 100644 --- a/Library/Homebrew/Gemfile.lock +++ b/Library/Homebrew/Gemfile.lock @@ -70,6 +70,7 @@ GEM pry (0.13.1) coderay (~> 1.1) method_source (~> 1.0) + rack (2.2.3) rainbow (3.0.0) rdiscount (2.2.0.2) regexp_parser (2.0.0) @@ -115,6 +116,10 @@ GEM rubocop-performance (1.9.1) rubocop (>= 0.90.0, < 2.0) rubocop-ast (>= 0.4.0) + rubocop-rails (2.8.1) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 0.87.0) rubocop-rspec (2.0.0) rubocop (~> 1.0) rubocop-ast (>= 1.1.0) @@ -176,6 +181,7 @@ DEPENDENCIES rspec-wait rubocop rubocop-performance + rubocop-rails rubocop-rspec rubocop-sorbet ruby-macho diff --git a/Library/Homebrew/bintray.rb b/Library/Homebrew/bintray.rb index c925c1260d..5b9f8dee91 100644 --- a/Library/Homebrew/bintray.rb +++ b/Library/Homebrew/bintray.rb @@ -64,7 +64,7 @@ class Bintray url = "#{API_URL}/content/#{@bintray_org}/#{repo}/#{package}/#{version}/#{remote_file}" args = ["--upload-file", local_file] - args += ["--header", "X-Checksum-Sha2: #{sha256}"] unless sha256.blank? + args += ["--header", "X-Checksum-Sha2: #{sha256}"] if sha256.present? args << "--fail" unless warn_on_error result = T.unsafe(self).open_api(url, *args) @@ -167,7 +167,7 @@ class Bintray .select { |type,| type == :stderr } .map { |_, line| line } .join - raise if e.status.exitstatus != 22 && !stderr.include?("404 Not Found") + raise if e.status.exitstatus != 22 && stderr.exclude?("404 Not Found") false else @@ -185,7 +185,7 @@ class Bintray if result.success? result.stdout.match(/^X-Checksum-Sha2:\s+(\h{64})\b/i)&.values_at(1)&.first || "" else - raise Error if result.status.exitstatus != 22 && !result.stderr.include?("404 Not Found") + raise Error if result.status.exitstatus != 22 && result.stderr.exclude?("404 Not Found") nil end diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index 43ab29a917..a9c619c360 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -59,7 +59,7 @@ begin # Command-style help: `help ` is fine, but ` help` is not. help_flag = true help_cmd_index = i - elsif !cmd && !help_flag_list.include?(arg) + elsif !cmd && help_flag_list.exclude?(arg) cmd = ARGV.delete_at(i) cmd = Commands::HOMEBREW_INTERNAL_COMMAND_ALIASES.fetch(cmd, cmd) end diff --git a/Library/Homebrew/cask/audit.rb b/Library/Homebrew/cask/audit.rb index 22980038aa..279bbad1f8 100644 --- a/Library/Homebrew/cask/audit.rb +++ b/Library/Homebrew/cask/audit.rb @@ -483,7 +483,7 @@ module Cask add_warning "cask token mentions architecture" if token.end_with? "x86", "32_bit", "x86_64", "64_bit" - return unless token.end_with?("cocoa", "qt", "gtk", "wx", "java") && !%w[cocoa qt gtk wx java].include?(token) + return unless token.end_with?("cocoa", "qt", "gtk", "wx", "java") && %w[cocoa qt gtk wx java].exclude?(token) add_warning "cask token mentions framework" end @@ -525,11 +525,7 @@ module Cask end version_stanza = cask.version.to_s - adjusted_version_stanza = if cask.appcast.must_contain.blank? - version_stanza.match(/^[[:alnum:].]+/)[0] - else - cask.appcast.must_contain - end + adjusted_version_stanza = cask.appcast.must_contain.presence || version_stanza.match(/^[[:alnum:].]+/)[0] return if appcast_contents.include? adjusted_version_stanza add_error "appcast at URL '#{appcast_stanza}' does not contain"\ diff --git a/Library/Homebrew/cask/cmd/help.rb b/Library/Homebrew/cask/cmd/help.rb index 7a3a2cba4d..df5fcf3c97 100644 --- a/Library/Homebrew/cask/cmd/help.rb +++ b/Library/Homebrew/cask/cmd/help.rb @@ -35,7 +35,7 @@ module Cask end def self.commands - Cmd.command_classes.select(&:visible?).map { |klass| [klass.command_name, klass] }.to_h + Cmd.command_classes.select(&:visible?).index_by(&:command_name) end end end diff --git a/Library/Homebrew/cask/dsl.rb b/Library/Homebrew/cask/dsl.rb index b9f0ca2064..25e753ec2f 100644 --- a/Library/Homebrew/cask/dsl.rb +++ b/Library/Homebrew/cask/dsl.rb @@ -144,7 +144,7 @@ module Cask def language_eval return @language_eval if defined?(@language_eval) - return @language_eval = nil if @language_blocks.nil? || @language_blocks.empty? + return @language_eval = nil if @language_blocks.blank? raise CaskInvalidError.new(cask, "No default language specified.") if @language_blocks.default.nil? diff --git a/Library/Homebrew/cleanup.rb b/Library/Homebrew/cleanup.rb index 3eac30a117..2a8f57c92d 100644 --- a/Library/Homebrew/cleanup.rb +++ b/Library/Homebrew/cleanup.rb @@ -122,7 +122,7 @@ module Homebrew return true unless basename.to_s.match?(/\A#{Regexp.escape(name)}--#{Regexp.escape(cask.version)}\b/) - return true if scrub && !cask.versions.include?(cask.version) + return true if scrub && cask.versions.exclude?(cask.version) if cask.version.latest? return mtime < CLEANUP_DEFAULT_DAYS.days.ago && @@ -444,7 +444,7 @@ module Homebrew path.unlink end end - elsif path.directory? && !Keg::MUST_EXIST_SUBDIRECTORIES.include?(path) + elsif path.directory? && Keg::MUST_EXIST_SUBDIRECTORIES.exclude?(path) dirs << path end end diff --git a/Library/Homebrew/cmd/doctor.rb b/Library/Homebrew/cmd/doctor.rb index 5a3136f147..b243cd802f 100644 --- a/Library/Homebrew/cmd/doctor.rb +++ b/Library/Homebrew/cmd/doctor.rb @@ -63,7 +63,7 @@ module Homebrew end out = checks.send(method) - next if out.nil? || out.empty? + next if out.blank? if first_warning $stderr.puts <<~EOS diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index 7e23762270..5c3715a02e 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -79,12 +79,12 @@ module Homebrew only = :cask if args.cask? && !args.formula? if args.analytics? - if args.days.present? && !VALID_DAYS.include?(args.days) + if args.days.present? && VALID_DAYS.exclude?(args.days) raise UsageError, "--days must be one of #{VALID_DAYS.join(", ")}" end if args.category.present? - if args.named.present? && !VALID_FORMULA_CATEGORIES.include?(args.category) + if args.named.present? && VALID_FORMULA_CATEGORIES.exclude?(args.category) raise UsageError, "--category must be one of #{VALID_FORMULA_CATEGORIES.join(", ")} when querying formulae" end diff --git a/Library/Homebrew/cmd/list.rb b/Library/Homebrew/cmd/list.rb index 7b1008e8ff..5589ed7dd1 100644 --- a/Library/Homebrew/cmd/list.rb +++ b/Library/Homebrew/cmd/list.rb @@ -89,7 +89,7 @@ module Homebrew formula_names = args.no_named? ? Formula.installed : args.named.to_resolved_formulae full_formula_names = formula_names.map(&:full_name).sort(&tap_and_name_comparison) full_formula_names = Formatter.columns(full_formula_names) unless args.public_send(:'1?') - puts full_formula_names unless full_formula_names.blank? + puts full_formula_names if full_formula_names.present? end if args.cask? || (!args.formula? && args.no_named?) cask_names = if args.no_named? @@ -99,7 +99,7 @@ module Homebrew end full_cask_names = cask_names.map(&:full_name).sort(&tap_and_name_comparison) full_cask_names = Formatter.columns(full_cask_names) unless args.public_send(:'1?') - puts full_cask_names unless full_cask_names.blank? + puts full_cask_names if full_cask_names.present? end elsif args.cask? list_casks(args: args) diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb index 480023574c..d2bed58275 100644 --- a/Library/Homebrew/cmd/search.rb +++ b/Library/Homebrew/cmd/search.rb @@ -119,7 +119,7 @@ module Homebrew count = all_formulae.count + all_casks.count - if $stdout.tty? && (reason = MissingFormula.reason(query, silent: true)) && !local_casks.include?(query) + if $stdout.tty? && (reason = MissingFormula.reason(query, silent: true)) && local_casks.exclude?(query) if count.positive? puts puts "If you meant #{query.inspect} specifically:" diff --git a/Library/Homebrew/cmd/tap-info.rb b/Library/Homebrew/cmd/tap-info.rb index 81284e8c0d..4d6cd7436d 100644 --- a/Library/Homebrew/cmd/tap-info.rb +++ b/Library/Homebrew/cmd/tap-info.rb @@ -80,7 +80,7 @@ module Homebrew end info += ", private" if tap.private? info += "\n#{tap.path} (#{tap.path.abv})" - info += "\nFrom: #{tap.remote.blank? ? "N/A" : tap.remote}" + info += "\nFrom: #{tap.remote.presence || "N/A"}" else info += "Not installed" end diff --git a/Library/Homebrew/cxxstdlib.rb b/Library/Homebrew/cxxstdlib.rb index e6ef4838d6..ead686989c 100644 --- a/Library/Homebrew/cxxstdlib.rb +++ b/Library/Homebrew/cxxstdlib.rb @@ -20,7 +20,7 @@ class CxxStdlib end def self.create(type, compiler) - raise ArgumentError, "Invalid C++ stdlib type: #{type}" if type && ![:libstdcxx, :libcxx].include?(type) + raise ArgumentError, "Invalid C++ stdlib type: #{type}" if type && [:libstdcxx, :libcxx].exclude?(type) apple_compiler = compiler.to_s.match?(GNU_GCC_REGEXP) ? false : true CxxStdlib.new(type, compiler, apple_compiler) diff --git a/Library/Homebrew/dependencies_helpers.rb b/Library/Homebrew/dependencies_helpers.rb index 98507958db..dfb2dd0017 100644 --- a/Library/Homebrew/dependencies_helpers.rb +++ b/Library/Homebrew/dependencies_helpers.rb @@ -47,7 +47,7 @@ module DependenciesHelpers if dep.recommended? klass.prune if ignores.include?("recommended?") || dependent.build.without?(dep) elsif dep.optional? - klass.prune if !includes.include?("optional?") && !dependent.build.with?(dep) + klass.prune if includes.exclude?("optional?") && !dependent.build.with?(dep) elsif dep.build? || dep.test? keep = false keep ||= dep.test? && includes.include?("test?") && dependent == root_dependent diff --git a/Library/Homebrew/extend/ENV/shared.rb b/Library/Homebrew/extend/ENV/shared.rb index eac0a305d4..0557a96608 100644 --- a/Library/Homebrew/extend/ENV/shared.rb +++ b/Library/Homebrew/extend/ENV/shared.rb @@ -82,7 +82,7 @@ module SharedEnvExtension value = value.to_s Array(keys).each do |key| old_value = self[key] - self[key] = if old_value.nil? || old_value.empty? + self[key] = if old_value.blank? value else old_value + separator + value @@ -95,7 +95,7 @@ module SharedEnvExtension value = value.to_s Array(keys).each do |key| old_value = self[key] - self[key] = if old_value.nil? || old_value.empty? + self[key] = if old_value.blank? value else value + separator + old_value diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb index f2e00e41c6..29b282ed11 100644 --- a/Library/Homebrew/extend/pathname.rb +++ b/Library/Homebrew/extend/pathname.rb @@ -301,7 +301,7 @@ class Pathname sig { params(expected: T.nilable(Checksum)).void } def verify_checksum(expected) - raise ChecksumMissingError if expected.nil? || expected.empty? + raise ChecksumMissingError if expected.blank? actual = Checksum.new(expected.hash_type, send(expected.hash_type).downcase) raise ChecksumMismatchError.new(self, expected, actual) unless expected == actual diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index f384768a13..c3227514ec 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -260,13 +260,13 @@ class Formula end def validate_attributes! - raise FormulaValidationError.new(full_name, :name, name) if name.nil? || name.empty? || name =~ /\s/ + raise FormulaValidationError.new(full_name, :name, name) if name.blank? || name =~ /\s/ url = active_spec.url - raise FormulaValidationError.new(full_name, :url, url) if url.nil? || url.empty? || url =~ /\s/ + raise FormulaValidationError.new(full_name, :url, url) if url.blank? || url =~ /\s/ val = version.respond_to?(:to_str) ? version.to_str : version - return unless val.nil? || val.empty? || val =~ /\s/ + return unless val.blank? || val =~ /\s/ raise FormulaValidationError.new(full_name, :version, val) end diff --git a/Library/Homebrew/formula_auditor.rb b/Library/Homebrew/formula_auditor.rb index 1835029ae4..c5d5c97408 100644 --- a/Library/Homebrew/formula_auditor.rb +++ b/Library/Homebrew/formula_auditor.rb @@ -367,7 +367,7 @@ module Homebrew def audit_homepage homepage = formula.homepage - return if homepage.nil? || homepage.empty? + return if homepage.blank? return unless @online diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 2f9667d99c..908287cf5e 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -364,7 +364,7 @@ class FormulaInstaller return if only_deps? - if build_bottle? && (arch = @bottle_arch) && !Hardware::CPU.optimization_flags.include?(arch.to_sym) + if build_bottle? && (arch = @bottle_arch) && Hardware::CPU.optimization_flags.exclude?(arch.to_sym) raise CannotInstallFormulaError, "Unrecognized architecture for --bottle-arch: #{arch}" end @@ -537,9 +537,7 @@ class FormulaInstaller req_deps = [] formulae = [formula] formula_deps_map = Dependency.expand(formula) - .each_with_object({}) do |dep, hash| - hash[dep.name] = dep - end + .index_by(&:name) while f = formulae.pop runtime_requirements = runtime_requirements(f) @@ -594,9 +592,9 @@ class FormulaInstaller end if pour_bottle && !Keg.bottle_dependencies.empty? - bottle_deps = if !Keg.bottle_dependencies.include?(formula.name) + bottle_deps = if Keg.bottle_dependencies.exclude?(formula.name) Keg.bottle_dependencies - elsif !Keg.relocation_formulae.include?(formula.name) + elsif Keg.relocation_formulae.exclude?(formula.name) Keg.relocation_formulae else [] diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index 86a014e155..28e3864742 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -248,7 +248,7 @@ module Formulary attr_reader :tap def initialize(tapped_name, from: nil) - warn = ![:keg, :rack].include?(from) + warn = [:keg, :rack].exclude?(from) name, path = formula_name_path(tapped_name, warn: warn) super name, path end diff --git a/Library/Homebrew/keg_relocate.rb b/Library/Homebrew/keg_relocate.rb index 6fd598cfa1..0ab2e24079 100644 --- a/Library/Homebrew/keg_relocate.rb +++ b/Library/Homebrew/keg_relocate.rb @@ -171,7 +171,7 @@ class Keg libtool_files = [] path.find do |pn| - next if pn.symlink? || pn.directory? || !Keg::LIBTOOL_EXTENSIONS.include?(pn.extname) + next if pn.symlink? || pn.directory? || Keg::LIBTOOL_EXTENSIONS.exclude?(pn.extname) libtool_files << pn end diff --git a/Library/Homebrew/linkage_checker.rb b/Library/Homebrew/linkage_checker.rb index 9025bf0374..e356b501e1 100644 --- a/Library/Homebrew/linkage_checker.rb +++ b/Library/Homebrew/linkage_checker.rb @@ -270,9 +270,9 @@ class LinkageChecker def sort_by_formula_full_name!(arr) arr.sort! do |a, b| - if a.include?("/") && !b.include?("/") + if a.include?("/") && b.exclude?("/") 1 - elsif !a.include?("/") && b.include?("/") + elsif a.exclude?("/") && b.include?("/") -1 else a <=> b diff --git a/Library/Homebrew/livecheck/livecheck.rb b/Library/Homebrew/livecheck/livecheck.rb index 1c4d6d3699..9531265260 100644 --- a/Library/Homebrew/livecheck/livecheck.rb +++ b/Library/Homebrew/livecheck/livecheck.rb @@ -407,7 +407,7 @@ module Homebrew next end - if livecheck_strategy.present? && !strategies.include?(strategy) + if livecheck_strategy.present? && strategies.exclude?(strategy) odebug "#{strategy_name} strategy does not apply to this URL" next end diff --git a/Library/Homebrew/livecheck/strategy/gnu.rb b/Library/Homebrew/livecheck/strategy/gnu.rb index 083330b564..1d181d3992 100644 --- a/Library/Homebrew/livecheck/strategy/gnu.rb +++ b/Library/Homebrew/livecheck/strategy/gnu.rb @@ -50,7 +50,7 @@ module Homebrew # @param url [String] the URL to match against # @return [Boolean] def self.match?(url) - URL_MATCH_REGEX.match?(url) && !url.include?("savannah.") + URL_MATCH_REGEX.match?(url) && url.exclude?("savannah.") end # Generates a URL and regex (if one isn't provided) and passes them diff --git a/Library/Homebrew/os/mac.rb b/Library/Homebrew/os/mac.rb index 26f373068d..1d291b235f 100644 --- a/Library/Homebrew/os/mac.rb +++ b/Library/Homebrew/os/mac.rb @@ -185,7 +185,7 @@ module OS path = mdfind(*ids) .reject { |p| p.include?("/Backups.backupdb/") } .first - Pathname.new(path) unless path.nil? || path.empty? + Pathname.new(path) if path.present? end def mdfind(*ids) diff --git a/Library/Homebrew/rubocops.rb b/Library/Homebrew/rubocops.rb index 24a89b54ae..85a8b7ae15 100644 --- a/Library/Homebrew/rubocops.rb +++ b/Library/Homebrew/rubocops.rb @@ -6,6 +6,7 @@ require_relative "load_path" require "utils/sorbet" require "rubocop-performance" +require "rubocop-rails" require "rubocop-rspec" require "rubocop-sorbet" diff --git a/Library/Homebrew/sorbet/rbi/gems/rack@2.2.3.rbi b/Library/Homebrew/sorbet/rbi/gems/rack@2.2.3.rbi new file mode 100644 index 0000000000..a1119dbde9 --- /dev/null +++ b/Library/Homebrew/sorbet/rbi/gems/rack@2.2.3.rbi @@ -0,0 +1,188 @@ +# DO NOT EDIT MANUALLY +# This is an autogenerated file for types exported from the `rack` gem. +# Please instead update this file by running `tapioca sync`. + +# typed: true + +module Rack +end + +class Rack::QueryParser + def initialize(params_class, key_space_limit, param_depth_limit); end + + def key_space_limit; end + def make_params; end + def new_depth_limit(param_depth_limit); end + def new_space_limit(key_space_limit); end + def normalize_params(params, name, v, depth); end + def param_depth_limit; end + def parse_nested_query(qs, d = T.unsafe(nil)); end + def parse_query(qs, d = T.unsafe(nil), &unescaper); end + + private + + def params_hash_has_key?(hash, key); end + def params_hash_type?(obj); end + def unescape(s); end + + class << self + def make_default(key_space_limit, param_depth_limit); end + end +end + +Rack::QueryParser::COMMON_SEP = T.let(T.unsafe(nil), Hash) + +Rack::QueryParser::DEFAULT_SEP = T.let(T.unsafe(nil), Regexp) + +class Rack::QueryParser::InvalidParameterError < ::ArgumentError +end + +class Rack::QueryParser::ParameterTypeError < ::TypeError +end + +class Rack::QueryParser::Params + def initialize(limit); end + + def [](key); end + def []=(key, value); end + def key?(key); end + def to_h; end + def to_params_hash; end +end + +module Rack::Utils + + private + + def add_cookie_to_header(header, key, value); end + def add_remove_cookie_to_header(header, key, value = T.unsafe(nil)); end + def best_q_match(q_value_header, available_mimes); end + def build_nested_query(value, prefix = T.unsafe(nil)); end + def build_query(params); end + def byte_ranges(env, size); end + def clean_path_info(path_info); end + def clock_time; end + def delete_cookie_header!(header, key, value = T.unsafe(nil)); end + def escape(s); end + def escape_html(string); end + def escape_path(s); end + def get_byte_ranges(http_range, size); end + def make_delete_cookie_header(header, key, value); end + def parse_cookies(env); end + def parse_cookies_header(header); end + def parse_nested_query(qs, d = T.unsafe(nil)); end + def parse_query(qs, d = T.unsafe(nil), &unescaper); end + def q_values(q_value_header); end + def rfc2109(time); end + def rfc2822(time); end + def secure_compare(a, b); end + def select_best_encoding(available_encodings, accept_encoding); end + def set_cookie_header!(header, key, value); end + def status_code(status); end + def unescape(s, encoding = T.unsafe(nil)); end + def unescape_path(s); end + def valid_path?(path); end + + class << self + def add_cookie_to_header(header, key, value); end + def add_remove_cookie_to_header(header, key, value = T.unsafe(nil)); end + def best_q_match(q_value_header, available_mimes); end + def build_nested_query(value, prefix = T.unsafe(nil)); end + def build_query(params); end + def byte_ranges(env, size); end + def clean_path_info(path_info); end + def clock_time; end + def default_query_parser; end + def default_query_parser=(_arg0); end + def delete_cookie_header!(header, key, value = T.unsafe(nil)); end + def escape(s); end + def escape_html(string); end + def escape_path(s); end + def get_byte_ranges(http_range, size); end + def key_space_limit; end + def key_space_limit=(v); end + def make_delete_cookie_header(header, key, value); end + def multipart_part_limit; end + def multipart_part_limit=(_arg0); end + def param_depth_limit; end + def param_depth_limit=(v); end + def parse_cookies(env); end + def parse_cookies_header(header); end + def parse_nested_query(qs, d = T.unsafe(nil)); end + def parse_query(qs, d = T.unsafe(nil), &unescaper); end + def q_values(q_value_header); end + def rfc2109(time); end + def rfc2822(time); end + def secure_compare(a, b); end + def select_best_encoding(available_encodings, accept_encoding); end + def set_cookie_header!(header, key, value); end + def status_code(status); end + def unescape(s, encoding = T.unsafe(nil)); end + def unescape_path(s); end + def valid_path?(path); end + end +end + +Rack::Utils::COMMON_SEP = T.let(T.unsafe(nil), Hash) + +class Rack::Utils::Context + def initialize(app_f, app_r); end + + def app; end + def call(env); end + def context(env, app = T.unsafe(nil)); end + def for; end + def recontext(app); end +end + +Rack::Utils::DEFAULT_SEP = T.let(T.unsafe(nil), Regexp) + +Rack::Utils::ESCAPE_HTML = T.let(T.unsafe(nil), Hash) + +Rack::Utils::ESCAPE_HTML_PATTERN = T.let(T.unsafe(nil), Regexp) + +Rack::Utils::HTTP_STATUS_CODES = T.let(T.unsafe(nil), Hash) + +class Rack::Utils::HeaderHash < ::Hash + def initialize(hash = T.unsafe(nil)); end + + def [](k); end + def []=(k, v); end + def clear; end + def delete(k); end + def each; end + def has_key?(k); end + def include?(k); end + def key?(k); end + def member?(k); end + def merge(other); end + def merge!(other); end + def replace(other); end + def to_hash; end + + protected + + def names; end + + private + + def initialize_copy(other); end + + class << self + def [](headers); end + end +end + +Rack::Utils::InvalidParameterError = Rack::QueryParser::InvalidParameterError + +Rack::Utils::KeySpaceConstrainedParams = Rack::QueryParser::Params + +Rack::Utils::NULL_BYTE = T.let(T.unsafe(nil), String) + +Rack::Utils::PATH_SEPS = T.let(T.unsafe(nil), Regexp) + +Rack::Utils::ParameterTypeError = Rack::QueryParser::ParameterTypeError + +Rack::Utils::STATUS_WITH_NO_ENTITY_BODY = T.let(T.unsafe(nil), Hash) + +Rack::Utils::SYMBOL_TO_STATUS_CODE = T.let(T.unsafe(nil), Hash) diff --git a/Library/Homebrew/sorbet/rbi/gems/rubocop-rails@2.8.1.rbi b/Library/Homebrew/sorbet/rbi/gems/rubocop-rails@2.8.1.rbi new file mode 100644 index 0000000000..8a03e433de --- /dev/null +++ b/Library/Homebrew/sorbet/rbi/gems/rubocop-rails@2.8.1.rbi @@ -0,0 +1,1642 @@ +# DO NOT EDIT MANUALLY +# This is an autogenerated file for types exported from the `rubocop-rails` gem. +# Please instead update this file by running `tapioca sync`. + +# typed: true + +module RuboCop +end + +module RuboCop::Cop +end + +module RuboCop::Cop::ActiveRecordHelper + extend(::RuboCop::AST::NodePattern::Macros) + + def external_dependency_checksum; end + def find_belongs_to(param0); end + def find_set_table_name(param0); end + def foreign_key_of(belongs_to); end + def in_where?(node); end + def resolve_relation_into_column(name:, class_node:, table:); end + def schema; end + def table_name(class_node); end +end + +RuboCop::Cop::ActiveRecordHelper::WHERE_METHODS = T.let(T.unsafe(nil), Array) + +module RuboCop::Cop::IndexMethod + def autocorrect(node); end + def on_block(node); end + def on_csend(node); end + def on_send(node); end + + private + + def execute_correction(corrector, node, correction); end + def extract_captures(match); end + def handle_possible_offense(node, match, match_desc); end + def new_method_name; end + def on_bad_each_with_object(_node); end + def on_bad_hash_brackets_map(_node); end + def on_bad_map_to_h(_node); end + def on_bad_to_h(_node); end + def prepare_correction(node); end +end + +class RuboCop::Cop::IndexMethod::Autocorrection < ::Struct + def block_node; end + def block_node=(_); end + def leading; end + def leading=(_); end + def match; end + def match=(_); end + def set_new_arg_name(transformed_argname, corrector); end + def set_new_body_expression(transforming_body_expr, corrector); end + def set_new_method_name(new_method_name, corrector); end + def strip_prefix_and_suffix(node, corrector); end + def trailing; end + def trailing=(_); end + + class << self + def [](*_arg0); end + def from_each_with_object(node, match); end + def from_hash_brackets_map(node, match); end + def from_map_to_h(node, match); end + def from_to_h(node, match); end + def inspect; end + def members; end + def new(*_arg0); end + end +end + +class RuboCop::Cop::IndexMethod::Captures < ::Struct + def noop_transformation?; end + def transformed_argname; end + def transformed_argname=(_); end + def transforming_body_expr; end + def transforming_body_expr=(_); end + + class << self + def [](*_arg0); end + def inspect; end + def members; end + def new(*_arg0); end + end +end + +module RuboCop::Cop::Rails +end + +class RuboCop::Cop::Rails::ActionFilter < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + + def autocorrect(node); end + def on_block(node); end + def on_send(node); end + + private + + def bad_methods; end + def check_method_node(node); end + def good_methods; end + def message(node); end + def preferred_method(method); end +end + +RuboCop::Cop::Rails::ActionFilter::ACTION_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::ActionFilter::FILTER_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::ActionFilter::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ActiveRecordAliases < ::RuboCop::Cop::Cop + def autocorrect(node); end + def on_csend(node); end + def on_send(node); end +end + +RuboCop::Cop::Rails::ActiveRecordAliases::ALIASES = T.let(T.unsafe(nil), Hash) + +RuboCop::Cop::Rails::ActiveRecordAliases::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ActiveRecordCallbacksOrder < ::RuboCop::Cop::Cop + def autocorrect(node); end + def on_class(class_node); end + + private + + def begin_pos_with_comment(node); end + def buffer; end + def callback?(node); end + def defined_callbacks(class_node); end + def end_position_for(node); end + def left_siblings_of(node); end + def siblings_of(node); end + def source_range_with_comment(node); end + def start_line_position(node); end +end + +RuboCop::Cop::Rails::ActiveRecordCallbacksOrder::CALLBACKS_IN_ORDER = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::ActiveRecordCallbacksOrder::CALLBACKS_ORDER_MAP = T.let(T.unsafe(nil), Hash) + +RuboCop::Cop::Rails::ActiveRecordCallbacksOrder::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ActiveRecordOverride < ::RuboCop::Cop::Cop + def on_def(node); end + + private + + def active_model?(parent_class_name); end + def callback_names(method_name); end + def find_parent_class_name(node); end + def message(method_name); end +end + +RuboCop::Cop::Rails::ActiveRecordOverride::ACTIVE_RECORD_CLASSES = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::ActiveRecordOverride::BAD_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::ActiveRecordOverride::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ActiveSupportAliases < ::RuboCop::Cop::Cop + def append(param0 = T.unsafe(nil)); end + def autocorrect(node); end + def ends_with?(param0 = T.unsafe(nil)); end + def on_send(node); end + def prepend(param0 = T.unsafe(nil)); end + def starts_with?(param0 = T.unsafe(nil)); end + + private + + def register_offense(node, method_name); end +end + +RuboCop::Cop::Rails::ActiveSupportAliases::ALIASES = T.let(T.unsafe(nil), Hash) + +RuboCop::Cop::Rails::ActiveSupportAliases::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::AfterCommitOverride < ::RuboCop::Cop::Cop + def on_class(class_node); end + + private + + def after_commit_callback?(node); end + def class_send_nodes(class_node); end + def each_after_commit_callback(class_node); end + def named_callback?(node); end +end + +RuboCop::Cop::Rails::AfterCommitOverride::AFTER_COMMIT_CALLBACKS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::AfterCommitOverride::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ApplicationController < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::EnforceSuperclass) + + def autocorrect(node); end + def class_definition(param0 = T.unsafe(nil)); end + def class_new_definition(param0 = T.unsafe(nil)); end +end + +RuboCop::Cop::Rails::ApplicationController::BASE_PATTERN = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::ApplicationController::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::ApplicationController::SUPERCLASS = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ApplicationJob < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::EnforceSuperclass) + extend(::RuboCop::Cop::TargetRailsVersion) + + def autocorrect(node); end + def class_definition(param0 = T.unsafe(nil)); end + def class_new_definition(param0 = T.unsafe(nil)); end +end + +RuboCop::Cop::Rails::ApplicationJob::BASE_PATTERN = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::ApplicationJob::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::ApplicationJob::SUPERCLASS = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ApplicationMailer < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::EnforceSuperclass) + extend(::RuboCop::Cop::TargetRailsVersion) + + def autocorrect(node); end + def class_definition(param0 = T.unsafe(nil)); end + def class_new_definition(param0 = T.unsafe(nil)); end +end + +RuboCop::Cop::Rails::ApplicationMailer::BASE_PATTERN = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::ApplicationMailer::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::ApplicationMailer::SUPERCLASS = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ApplicationRecord < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::EnforceSuperclass) + extend(::RuboCop::Cop::TargetRailsVersion) + + def autocorrect(node); end + def class_definition(param0 = T.unsafe(nil)); end + def class_new_definition(param0 = T.unsafe(nil)); end +end + +RuboCop::Cop::Rails::ApplicationRecord::BASE_PATTERN = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::ApplicationRecord::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::ApplicationRecord::SUPERCLASS = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::AssertNot < ::RuboCop::Cop::Cop + def autocorrect(node); end + def offensive?(param0 = T.unsafe(nil)); end + def on_send(node); end + + private + + def corrected_source(source); end +end + +RuboCop::Cop::Rails::AssertNot::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::BelongsTo < ::RuboCop::Cop::Cop + extend(::RuboCop::Cop::TargetRailsVersion) + + def autocorrect(node); end + def match_belongs_to_with_options(param0 = T.unsafe(nil)); end + def on_send(node); end +end + +RuboCop::Cop::Rails::BelongsTo::SUPERFLOUS_REQUIRE_FALSE_MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::BelongsTo::SUPERFLOUS_REQUIRE_TRUE_MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::Blank < ::RuboCop::Cop::Cop + def autocorrect(node); end + def defining_blank?(param0 = T.unsafe(nil)); end + def nil_or_empty?(param0 = T.unsafe(nil)); end + def not_present?(param0 = T.unsafe(nil)); end + def on_if(node); end + def on_or(node); end + def on_send(node); end + def unless_present?(param0 = T.unsafe(nil)); end + + private + + def replacement(node); end + def unless_condition(node, method_call); end +end + +RuboCop::Cop::Rails::Blank::MSG_NIL_OR_EMPTY = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::Blank::MSG_NOT_PRESENT = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::Blank::MSG_UNLESS_PRESENT = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::BulkChangeTable < ::RuboCop::Cop::Cop + def on_def(node); end + def on_send(node); end + + private + + def add_offense_for_alter_methods(node); end + def add_offense_for_change_table(node); end + def call_to_combinable_alter_method?(child_node); end + def combinable_alter_methods; end + def combinable_transformations; end + def database; end + def database_from_yaml; end + def database_yaml; end + def include_bulk_options?(node); end + def support_bulk_alter?; end +end + +class RuboCop::Cop::Rails::BulkChangeTable::AlterMethodsRecorder + def initialize; end + + def flush; end + def offensive_nodes; end + def process(new_node); end +end + +RuboCop::Cop::Rails::BulkChangeTable::COMBINABLE_ALTER_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::BulkChangeTable::COMBINABLE_TRANSFORMATIONS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::BulkChangeTable::MIGRATION_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::BulkChangeTable::MSG_FOR_ALTER_METHODS = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::BulkChangeTable::MSG_FOR_CHANGE_TABLE = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::BulkChangeTable::MYSQL = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::BulkChangeTable::MYSQL_COMBINABLE_ALTER_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::BulkChangeTable::MYSQL_COMBINABLE_TRANSFORMATIONS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::BulkChangeTable::POSTGRESQL = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::BulkChangeTable::POSTGRESQL_COMBINABLE_ALTER_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::BulkChangeTable::POSTGRESQL_COMBINABLE_TRANSFORMATIONS = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Rails::ContentTag < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::RangeHelp) + extend(::RuboCop::Cop::TargetRailsVersion) + + def autocorrect(node); end + def on_send(node); end + + private + + def correction_range(node); end + def method_name?(node); end +end + +RuboCop::Cop::Rails::ContentTag::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::CreateTableWithTimestamps < ::RuboCop::Cop::Cop + def create_table_with_block?(param0 = T.unsafe(nil)); end + def create_table_with_timestamps_proc?(param0 = T.unsafe(nil)); end + def created_at_or_updated_at_included?(param0); end + def on_send(node); end + def timestamps_included?(param0); end + + private + + def time_columns_included?(node); end +end + +RuboCop::Cop::Rails::CreateTableWithTimestamps::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::Date < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + + def on_const(node); end + def on_csend(node); end + def on_send(node); end + + private + + def bad_days; end + def bad_methods; end + def check_date_node(node); end + def check_deprecated_methods(node); end + def extract_method_chain(node); end + def good_days; end + def good_methods; end + def method_send?(node); end + def safe_chain?(node); end + def safe_to_time?(node); end +end + +RuboCop::Cop::Rails::Date::BAD_DAYS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::Date::DEPRECATED_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::Date::DEPRECATED_MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::Date::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::Date::MSG_SEND = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::DefaultScope < ::RuboCop::Cop::Cop + def class_method_definition?(param0 = T.unsafe(nil)); end + def eigenclass_method_definition?(param0 = T.unsafe(nil)); end + def method_call?(param0 = T.unsafe(nil)); end + def on_defs(node); end + def on_sclass(node); end + def on_send(node); end +end + +RuboCop::Cop::Rails::DefaultScope::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::Delegate < ::RuboCop::Cop::Cop + def autocorrect(node); end + def delegate?(param0 = T.unsafe(nil)); end + def on_def(node); end + + private + + def arguments_match?(arg_array, body); end + def include_prefix_case?; end + def method_name_matches?(method_name, body); end + def prefixed_method_name(body); end + def private_or_protected_before(line); end + def private_or_protected_delegation(node); end + def private_or_protected_inline(line); end + def trivial_delegate?(def_node); end +end + +RuboCop::Cop::Rails::Delegate::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::DelegateAllowBlank < ::RuboCop::Cop::Cop + def allow_blank_option(param0 = T.unsafe(nil)); end + def autocorrect(pair_node); end + def on_send(node); end +end + +RuboCop::Cop::Rails::DelegateAllowBlank::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::DynamicFindBy < ::RuboCop::Cop::Cop + def autocorrect(node); end + def on_csend(node); end + def on_send(node); end + + private + + def allowed_invocation?(node); end + def allowed_method?(node); end + def allowed_receiver?(node); end + def autocorrect_argument_keywords(corrector, node, keywords); end + def autocorrect_method_name(corrector, node); end + def column_keywords(method); end + def static_method_name(method_name); end + def whitelisted?(node); end +end + +RuboCop::Cop::Rails::DynamicFindBy::METHOD_PATTERN = T.let(T.unsafe(nil), Regexp) + +RuboCop::Cop::Rails::DynamicFindBy::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::EnumHash < ::RuboCop::Cop::Cop + def array_pair?(param0 = T.unsafe(nil)); end + def autocorrect(node); end + def enum?(param0 = T.unsafe(nil)); end + def on_send(node); end + + private + + def enum_name(key); end + def source(elem); end +end + +RuboCop::Cop::Rails::EnumHash::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::EnumUniqueness < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::Duplication) + + def enum?(param0 = T.unsafe(nil)); end + def enum_values(param0 = T.unsafe(nil)); end + def on_send(node); end + + private + + def enum_name(key); end +end + +RuboCop::Cop::Rails::EnumUniqueness::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::EnvironmentComparison < ::RuboCop::Cop::Cop + def autocorrect(node); end + def comparing_str_env_with_rails_env_on_lhs?(param0 = T.unsafe(nil)); end + def comparing_str_env_with_rails_env_on_rhs?(param0 = T.unsafe(nil)); end + def comparing_sym_env_with_rails_env_on_lhs?(param0 = T.unsafe(nil)); end + def comparing_sym_env_with_rails_env_on_rhs?(param0 = T.unsafe(nil)); end + def content(param0 = T.unsafe(nil)); end + def on_send(node); end + + private + + def build_predicate_method(node); end + def build_predicate_method_for_rails_env_on_lhs(node); end + def build_predicate_method_for_rails_env_on_rhs(node); end + def rails_env_on_lhs?(node); end +end + +RuboCop::Cop::Rails::EnvironmentComparison::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::EnvironmentComparison::SYM_MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::Exit < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + + def on_send(node); end + + private + + def offending_node?(node); end + def right_argument_count?(arg_nodes); end + def right_method_name?(method_name); end + def right_receiver?(receiver_node); end +end + +RuboCop::Cop::Rails::Exit::EXPLICIT_RECEIVERS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::Exit::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::Exit::TARGET_METHODS = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Rails::FilePath < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + include(::RuboCop::Cop::RangeHelp) + + def file_join_nodes?(param0 = T.unsafe(nil)); end + def on_dstr(node); end + def on_send(node); end + def rails_root_join_nodes?(param0 = T.unsafe(nil)); end + def rails_root_nodes?(param0); end + + private + + def check_for_file_join_with_rails_root(node); end + def check_for_rails_root_join_with_slash_separated_path(node); end + def check_for_rails_root_join_with_string_arguments(node); end + def message(_node); end + def register_offense(node); end + def string_with_slash?(node); end +end + +RuboCop::Cop::Rails::FilePath::MSG_ARGUMENTS = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::FilePath::MSG_SLASHES = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::FindBy < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::RangeHelp) + + def autocorrect(node); end + def on_csend(node); end + def on_send(node); end + def where_first?(param0 = T.unsafe(nil)); end +end + +RuboCop::Cop::Rails::FindBy::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::FindBy::TARGET_SELECTORS = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Rails::FindById < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::RangeHelp) + + def autocorrect(node); end + def find_by?(param0 = T.unsafe(nil)); end + def on_send(node); end + def where_take?(param0 = T.unsafe(nil)); end + + private + + def build_find_by_bad_method(node, id_value); end + def build_good_method(id_value); end + def build_where_take_bad_method(id_value); end + def find_by_offense_range(node); end + def where_take_offense_range(node, where); end +end + +RuboCop::Cop::Rails::FindById::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::FindEach < ::RuboCop::Cop::Cop + def autocorrect(node); end + def on_send(node); end + + private + + def ignored_by_find_each?(relation_method); end + def method_chain(node); end +end + +RuboCop::Cop::Rails::FindEach::IGNORED_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::FindEach::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::FindEach::SCOPE_METHODS = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Rails::HasAndBelongsToMany < ::RuboCop::Cop::Cop + def on_send(node); end +end + +RuboCop::Cop::Rails::HasAndBelongsToMany::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::HasManyOrHasOneDependent < ::RuboCop::Cop::Cop + def active_resource_class?(param0); end + def association_with_options?(param0 = T.unsafe(nil)); end + def association_without_options?(param0 = T.unsafe(nil)); end + def dependent_option?(param0 = T.unsafe(nil)); end + def on_send(node); end + def present_option?(param0 = T.unsafe(nil)); end + def with_options_block(param0 = T.unsafe(nil)); end + + private + + def active_resource?(node); end + def contain_valid_options_in_with_options_block?(node); end + def valid_options?(options); end + def valid_options_in_with_options_block?(node); end +end + +RuboCop::Cop::Rails::HasManyOrHasOneDependent::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::HelperInstanceVariable < ::RuboCop::Cop::Cop + def on_ivar(node); end + def on_ivasgn(node); end +end + +RuboCop::Cop::Rails::HelperInstanceVariable::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::HttpPositionalArguments < ::RuboCop::Cop::Cop + extend(::RuboCop::Cop::TargetRailsVersion) + + def autocorrect(node); end + def http_request?(param0 = T.unsafe(nil)); end + def kwsplat_hash?(param0 = T.unsafe(nil)); end + def on_send(node); end + + private + + def convert_hash_data(data, type); end + def correction(node); end + def correction_template(node); end + def format_arg?(node); end + def needs_conversion?(data); end + def special_keyword_arg?(node); end +end + +RuboCop::Cop::Rails::HttpPositionalArguments::HTTP_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::HttpPositionalArguments::KEYWORD_ARGS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::HttpPositionalArguments::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::HttpStatus < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + + def autocorrect(node); end + def http_status(param0 = T.unsafe(nil)); end + def on_send(node); end + def status_code(param0 = T.unsafe(nil)); end + + private + + def checker_class; end +end + +class RuboCop::Cop::Rails::HttpStatus::NumericStyleChecker + def initialize(node); end + + def message; end + def node; end + def offensive?; end + def preferred_style; end + + private + + def number; end + def permitted_symbol?; end + def symbol; end +end + +RuboCop::Cop::Rails::HttpStatus::NumericStyleChecker::DEFAULT_MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::HttpStatus::NumericStyleChecker::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::HttpStatus::NumericStyleChecker::PERMITTED_STATUS = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Rails::HttpStatus::SymbolicStyleChecker + def initialize(node); end + + def message; end + def node; end + def offensive?; end + def preferred_style; end + + private + + def custom_http_status_code?; end + def number; end + def symbol; end +end + +RuboCop::Cop::Rails::HttpStatus::SymbolicStyleChecker::DEFAULT_MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::HttpStatus::SymbolicStyleChecker::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::IgnoredSkipActionFilterOption < ::RuboCop::Cop::Cop + def filter_options(param0 = T.unsafe(nil)); end + def on_send(node); end + + private + + def if_and_except?(options); end + def if_and_only?(options); end + def options_hash(options); end +end + +RuboCop::Cop::Rails::IgnoredSkipActionFilterOption::FILTERS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::IgnoredSkipActionFilterOption::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::IndexBy < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::IndexMethod) + + def on_bad_each_with_object(param0 = T.unsafe(nil)); end + def on_bad_hash_brackets_map(param0 = T.unsafe(nil)); end + def on_bad_map_to_h(param0 = T.unsafe(nil)); end + def on_bad_to_h(param0 = T.unsafe(nil)); end + + private + + def new_method_name; end +end + +class RuboCop::Cop::Rails::IndexWith < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::IndexMethod) + extend(::RuboCop::Cop::TargetRailsVersion) + + def on_bad_each_with_object(param0 = T.unsafe(nil)); end + def on_bad_hash_brackets_map(param0 = T.unsafe(nil)); end + def on_bad_map_to_h(param0 = T.unsafe(nil)); end + def on_bad_to_h(param0 = T.unsafe(nil)); end + + private + + def new_method_name; end +end + +class RuboCop::Cop::Rails::Inquiry < ::RuboCop::Cop::Cop + def on_send(node); end +end + +RuboCop::Cop::Rails::Inquiry::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::InverseOf < ::RuboCop::Cop::Cop + def as_option?(param0 = T.unsafe(nil)); end + def association_recv_arguments(param0 = T.unsafe(nil)); end + def conditions_option?(param0 = T.unsafe(nil)); end + def foreign_key_option?(param0 = T.unsafe(nil)); end + def inverse_of_nil_option?(param0 = T.unsafe(nil)); end + def inverse_of_option?(param0 = T.unsafe(nil)); end + def on_send(node); end + def options_contain_inverse_of?(options); end + def options_from_argument(param0 = T.unsafe(nil)); end + def options_ignoring_inverse_of?(options); end + def options_requiring_inverse_of?(options); end + def polymorphic_option?(param0 = T.unsafe(nil)); end + def same_context_in_with_options?(arg, recv); end + def scope?(arguments); end + def through_option?(param0 = T.unsafe(nil)); end + def with_options_arguments(recv, node); end + + private + + def message(options); end +end + +RuboCop::Cop::Rails::InverseOf::NIL_MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::InverseOf::SPECIFY_MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::LexicallyScopedActionFilter < ::RuboCop::Cop::Cop + def on_send(node); end + def only_or_except_filter_methods(param0 = T.unsafe(nil)); end + + private + + def array_values(node); end + def message(methods, parent); end +end + +RuboCop::Cop::Rails::LexicallyScopedActionFilter::FILTERS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::LexicallyScopedActionFilter::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::LinkToBlank < ::RuboCop::Cop::Cop + def autocorrect(node); end + def blank_target?(param0 = T.unsafe(nil)); end + def includes_noopener?(param0 = T.unsafe(nil)); end + def on_send(node); end + def rel_node?(param0 = T.unsafe(nil)); end + + private + + def add_rel(send_node, offence_node, corrector); end + def append_to_rel(rel_node, corrector); end + def contains_noopener?(value); end +end + +RuboCop::Cop::Rails::LinkToBlank::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::MailerName < ::RuboCop::Cop::Cop + def autocorrect(node); end + def class_definition?(param0 = T.unsafe(nil)); end + def class_new_definition?(param0 = T.unsafe(nil)); end + def mailer_base_class?(param0 = T.unsafe(nil)); end + def on_class(node); end + def on_send(node); end + + private + + def mailer_suffix?(mailer_name); end +end + +RuboCop::Cop::Rails::MailerName::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::MatchRoute < ::RuboCop::Cop::Cop + def autocorrect(node); end + def match_method_call?(param0 = T.unsafe(nil)); end + def on_send(node); end + def routes_draw?(param0 = T.unsafe(nil)); end + + private + + def extract_via(node); end + def http_method?(method); end + def http_method_and_options(node); end + def replacement(path_node, options_node); end + def via_pair(node); end + def within_routes?(node); end +end + +RuboCop::Cop::Rails::MatchRoute::HTTP_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::MatchRoute::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::NegateInclude < ::RuboCop::Cop::Cop + def autocorrect(node); end + def negate_include_call?(param0 = T.unsafe(nil)); end + def on_send(node); end +end + +RuboCop::Cop::Rails::NegateInclude::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::NotNullColumn < ::RuboCop::Cop::Cop + def add_not_null_column?(param0 = T.unsafe(nil)); end + def add_not_null_reference?(param0 = T.unsafe(nil)); end + def default_option?(param0 = T.unsafe(nil)); end + def null_false?(param0 = T.unsafe(nil)); end + def on_send(node); end + + private + + def check_add_column(node); end + def check_add_reference(node); end + def check_pairs(pairs); end +end + +RuboCop::Cop::Rails::NotNullColumn::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::OrderById < ::RuboCop::Cop::Base + include(::RuboCop::Cop::RangeHelp) + + def on_send(node); end + def order_by_id?(param0 = T.unsafe(nil)); end + + private + + def offense_range(node); end +end + +RuboCop::Cop::Rails::OrderById::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::Output < ::RuboCop::Cop::Cop + def io_output?(param0 = T.unsafe(nil)); end + def on_send(node); end + def output?(param0 = T.unsafe(nil)); end + + private + + def match_gvar?(sym); end +end + +RuboCop::Cop::Rails::Output::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::OutputSafety < ::RuboCop::Cop::Cop + def on_csend(node); end + def on_send(node); end + + private + + def looks_like_rails_html_safe?(node); end + def looks_like_rails_raw?(node); end + def looks_like_rails_safe_concat?(node); end + def non_interpolated_string?(node); end +end + +RuboCop::Cop::Rails::OutputSafety::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::Pick < ::RuboCop::Cop::Cop + extend(::RuboCop::Cop::TargetRailsVersion) + + def autocorrect(node); end + def on_send(node); end + def pick_candidate?(param0 = T.unsafe(nil)); end + + private + + def message(node); end +end + +RuboCop::Cop::Rails::Pick::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::Pluck < ::RuboCop::Cop::Cop + extend(::RuboCop::Cop::TargetRailsVersion) + + def autocorrect(node); end + def on_block(node); end + def pluck_candidate?(param0 = T.unsafe(nil)); end + + private + + def message(method, argument, element, value); end + def offense_range(node); end +end + +RuboCop::Cop::Rails::Pluck::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::PluckId < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::RangeHelp) + include(::RuboCop::Cop::ActiveRecordHelper) + + def autocorrect(node); end + def on_send(node); end + def pluck_id_call?(param0 = T.unsafe(nil)); end + + private + + def offense_range(node); end +end + +RuboCop::Cop::Rails::PluckId::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::PluckInWhere < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ActiveRecordHelper) + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + + def autocorrect(node); end + def on_send(node); end + + private + + def root_receiver(node); end +end + +RuboCop::Cop::Rails::PluckInWhere::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::PluralizationGrammar < ::RuboCop::Cop::Cop + def autocorrect(node); end + def on_send(node); end + + private + + def correct_method(method_name); end + def duration_method?(method_name); end + def literal_number?(node); end + def message(node); end + def offense?(node); end + def plural_method?(method_name); end + def plural_receiver?(number); end + def pluralize(method_name); end + def singular_method?(method_name); end + def singular_receiver?(number); end + def singularize(method_name); end +end + +RuboCop::Cop::Rails::PluralizationGrammar::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::PluralizationGrammar::PLURAL_DURATION_METHODS = T.let(T.unsafe(nil), Hash) + +RuboCop::Cop::Rails::PluralizationGrammar::SINGULAR_DURATION_METHODS = T.let(T.unsafe(nil), Hash) + +class RuboCop::Cop::Rails::Presence < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::RangeHelp) + + def autocorrect(node); end + def on_if(node); end + def redundant_negative_receiver_and_other(param0 = T.unsafe(nil)); end + def redundant_receiver_and_other(param0 = T.unsafe(nil)); end + + private + + def build_source_for_or_method(other); end + def ignore_if_node?(node); end + def ignore_other_node?(node); end + def message(node, receiver, other); end + def replacement(receiver, other); end +end + +RuboCop::Cop::Rails::Presence::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::Present < ::RuboCop::Cop::Cop + def autocorrect(node); end + def exists_and_not_empty?(param0 = T.unsafe(nil)); end + def not_blank?(param0 = T.unsafe(nil)); end + def on_and(node); end + def on_if(node); end + def on_or(node); end + def on_send(node); end + def unless_blank?(param0 = T.unsafe(nil)); end + + private + + def replacement(node); end + def unless_condition(node, method_call); end +end + +RuboCop::Cop::Rails::Present::MSG_EXISTS_AND_NOT_EMPTY = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::Present::MSG_NOT_BLANK = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::Present::MSG_UNLESS_BLANK = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::RakeEnvironment < ::RuboCop::Cop::Cop + def autocorrect(node); end + def on_block(node); end + def task_definition?(param0 = T.unsafe(nil)); end + + private + + def correct_task_dependency(task_name); end + def task_name(node); end + def with_dependencies?(node); end + def with_hash_style_dependencies?(hash_node); end +end + +RuboCop::Cop::Rails::RakeEnvironment::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ReadWriteAttribute < ::RuboCop::Cop::Cop + def autocorrect(node); end + def on_send(node); end + def read_write_attribute?(param0 = T.unsafe(nil)); end + + private + + def message(node); end + def read_attribute_replacement(node); end + def write_attribute_replacement(node); end +end + +RuboCop::Cop::Rails::ReadWriteAttribute::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::RedundantAllowNil < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::RangeHelp) + + def autocorrect(node); end + def on_send(node); end + + private + + def find_allow_nil_and_allow_blank(node); end + def next_sibling(node); end + def node_beg(node); end + def node_end(node); end + def offense(allow_nil_val, allow_blank_val, allow_nil); end + def previous_sibling(node); end +end + +RuboCop::Cop::Rails::RedundantAllowNil::MSG_ALLOW_NIL_FALSE = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::RedundantAllowNil::MSG_SAME = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::RedundantForeignKey < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::RangeHelp) + + def association_with_foreign_key(param0 = T.unsafe(nil)); end + def autocorrect(node); end + def on_send(node); end + + private + + def default_foreign_key(node, association_type, association_name, options); end + def find_as_option(options); end + def redundant?(node, association_type, association_name, options, foreign_key); end +end + +RuboCop::Cop::Rails::RedundantForeignKey::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::RedundantReceiverInWithOptions < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::RangeHelp) + + def all_block_nodes_in(param0); end + def all_send_nodes_in(param0); end + def autocorrect(node); end + def on_block(node); end + def with_options?(param0 = T.unsafe(nil)); end + + private + + def block_argument_range(node); end + def same_value?(arg_node, recv_node); end + def search_begin_pos_of_space_before_block_argument(begin_pos); end +end + +RuboCop::Cop::Rails::RedundantReceiverInWithOptions::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ReflectionClassName < ::RuboCop::Cop::Cop + def association_with_reflection(param0 = T.unsafe(nil)); end + def on_send(node); end + def reflection_class_name(param0 = T.unsafe(nil)); end +end + +RuboCop::Cop::Rails::ReflectionClassName::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::RefuteMethods < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + + def autocorrect(node); end + def offensive?(param0 = T.unsafe(nil)); end + def on_send(node); end + + private + + def bad_method?(method_name); end + def convert_good_method(bad_method); end + def offense_message(method_name); end +end + +RuboCop::Cop::Rails::RefuteMethods::ASSERT_NOT_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::RefuteMethods::CORRECTIONS = T.let(T.unsafe(nil), Hash) + +RuboCop::Cop::Rails::RefuteMethods::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::RefuteMethods::REFUTE_METHODS = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Rails::RelativeDateConstant < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::RangeHelp) + + def autocorrect(node); end + def on_casgn(node); end + def on_masgn(node); end + def on_or_asgn(node); end + def relative_date?(param0 = T.unsafe(nil)); end + def relative_date_assignment?(param0 = T.unsafe(nil)); end + def relative_date_or_assignment?(param0 = T.unsafe(nil)); end + + private + + def offense_range(name, value); end +end + +RuboCop::Cop::Rails::RelativeDateConstant::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::RenderInline < ::RuboCop::Cop::Cop + def on_send(node); end + def render_with_inline_option?(param0 = T.unsafe(nil)); end +end + +RuboCop::Cop::Rails::RenderInline::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::RenderPlainText < ::RuboCop::Cop::Cop + def autocorrect(node); end + def on_send(node); end + def render_plain_text?(param0 = T.unsafe(nil)); end + + private + + def compatible_content_type?(node); end + def find_content_type(node); end + def replacement(rest_options, option_value); end +end + +RuboCop::Cop::Rails::RenderPlainText::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::RequestReferer < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + + def autocorrect(node); end + def on_send(node); end + def referer?(param0 = T.unsafe(nil)); end + + private + + def message(_node); end + def wrong_method_name; end +end + +RuboCop::Cop::Rails::RequestReferer::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ReversibleMigration < ::RuboCop::Cop::Cop + def change_table_call(param0 = T.unsafe(nil)); end + def drop_table_call(param0 = T.unsafe(nil)); end + def irreversible_schema_statement_call(param0 = T.unsafe(nil)); end + def on_block(node); end + def on_send(node); end + def remove_column_call(param0 = T.unsafe(nil)); end + def remove_columns_call(param0 = T.unsafe(nil)); end + def remove_foreign_key_call(param0 = T.unsafe(nil)); end + def remove_index_call(param0 = T.unsafe(nil)); end + + private + + def all_hash_key?(args, *keys); end + def check_change_table_node(node, block); end + def check_change_table_offense(receiver, node); end + def check_drop_table_node(node); end + def check_irreversible_schema_statement_node(node); end + def check_remove_column_node(node); end + def check_remove_columns_node(node); end + def check_remove_foreign_key_node(node); end + def check_remove_index_node(node); end + def check_reversible_hash_node(node); end + def reversible_change_table_call?(node); end + def within_change_method?(node); end + def within_reversible_or_up_only_block?(node); end +end + +RuboCop::Cop::Rails::ReversibleMigration::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::SafeNavigation < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::RangeHelp) + + def autocorrect(node); end + def on_send(node); end + def try_call(param0 = T.unsafe(nil)); end + + private + + def replacement(method, params); end +end + +RuboCop::Cop::Rails::SafeNavigation::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::SafeNavigationWithBlank < ::RuboCop::Cop::Cop + def autocorrect(node); end + def on_if(node); end + def safe_navigation_blank_in_conditional?(param0 = T.unsafe(nil)); end +end + +RuboCop::Cop::Rails::SafeNavigationWithBlank::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::SaveBang < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::NegativeConditional) + + def after_leaving_scope(scope, _variable_table); end + def autocorrect(node); end + def check_assignment(assignment); end + def join_force?(force_class); end + def on_csend(node); end + def on_send(node); end + + private + + def add_offense_for_node(node, msg = T.unsafe(nil)); end + def allowed_receiver?(node); end + def argument?(node); end + def array_parent(node); end + def assignable_node(node); end + def call_to_persisted?(node); end + def check_used_in_condition_or_compound_boolean(node); end + def checked_immediately?(node); end + def conditional?(parent); end + def const_matches?(const, allowed_const); end + def expected_signature?(node); end + def explicit_return?(node); end + def find_method_with_sibling_index(node, sibling_index = T.unsafe(nil)); end + def hash_parent(node); end + def implicit_return?(node); end + def in_condition_or_compound_boolean?(node); end + def operator_or_single_negative?(node); end + def persist_method?(node, methods = T.unsafe(nil)); end + def persisted_referenced?(assignment); end + def receiver_chain_matches?(node, allowed_receiver); end + def return_value_assigned?(node); end + def right_assignment_node(assignment); end +end + +RuboCop::Cop::Rails::SaveBang::CREATE_CONDITIONAL_MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::SaveBang::CREATE_MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::SaveBang::CREATE_PERSIST_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::SaveBang::MODIFY_PERSIST_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::SaveBang::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::SaveBang::PERSIST_METHODS = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Rails::ScopeArgs < ::RuboCop::Cop::Cop + def on_send(node); end + def scope?(param0 = T.unsafe(nil)); end +end + +RuboCop::Cop::Rails::ScopeArgs::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::ShortI18n < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + + def autocorrect(node); end + def long_i18n?(param0 = T.unsafe(nil)); end + def on_send(node); end +end + +RuboCop::Cop::Rails::ShortI18n::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::ShortI18n::PREFERRED_METHODS = T.let(T.unsafe(nil), Hash) + +class RuboCop::Cop::Rails::SkipsModelValidations < ::RuboCop::Cop::Cop + def initialize(*_arg0); end + + def good_insert?(param0 = T.unsafe(nil)); end + def good_touch?(param0 = T.unsafe(nil)); end + def on_csend(node); end + def on_send(node); end + + private + + def allowed_method?(node); end + def allowed_methods; end + def forbidden_methods; end + def message(node); end +end + +RuboCop::Cop::Rails::SkipsModelValidations::METHODS_WITH_ARGUMENTS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::SkipsModelValidations::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::SquishedSQLHeredocs < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::Heredoc) + + def autocorrect(node); end + def on_heredoc(node); end + + private + + def message(node); end + def offense_detected?(node); end + def sql_heredoc?(node); end + def using_squish?(node); end +end + +RuboCop::Cop::Rails::SquishedSQLHeredocs::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::SquishedSQLHeredocs::SQL = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::SquishedSQLHeredocs::SQUISH = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::TimeZone < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + + def autocorrect(node); end + def on_const(node); end + + private + + def acceptable_methods(klass, method_name, node); end + def autocorrect_time_new(node, corrector); end + def build_message(klass, method_name, node); end + def check_localtime(node); end + def check_time_node(klass, node); end + def extract_method_chain(node); end + def flexible?; end + def good_methods; end + def method_from_time_class?(node); end + def method_send?(node); end + def need_check_localtime?(chain); end + def not_danger_chain?(chain); end + def offset_provided?(node); end + def remove_redundant_in_time_zone(corrector, node); end + def safe_method(method_name, node); end + def strict?; end +end + +RuboCop::Cop::Rails::TimeZone::ACCEPTED_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::TimeZone::DANGEROUS_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::TimeZone::GOOD_METHODS = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::TimeZone::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::TimeZone::MSG_ACCEPTABLE = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::TimeZone::MSG_LOCALTIME = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::UniqBeforePluck < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + include(::RuboCop::Cop::RangeHelp) + + def aggressive_node_match(param0 = T.unsafe(nil)); end + def autocorrect(node); end + def conservative_node_match(param0 = T.unsafe(nil)); end + def on_send(node); end + + private + + def dot_method_begin_pos(method, node); end + def dot_method_with_whitespace(method, node); end + def style_parameter_name; end +end + +RuboCop::Cop::Rails::UniqBeforePluck::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::UniqBeforePluck::NEWLINE = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::UniqBeforePluck::PATTERN = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::UniqueValidationWithoutIndex < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ActiveRecordHelper) + + def on_send(node); end + + private + + def array_node_to_array(node); end + def class_node(node); end + def column_names(node); end + def column_names_from_scope(node); end + def condition_part?(node); end + def find_schema_information(node); end + def find_scope(pairs); end + def include_column_names_in_expression_index?(index, column_names); end + def unfreeze_scope(scope); end + def uniqueness_part(node); end + def with_index?(klass, table, names); end +end + +RuboCop::Cop::Rails::UniqueValidationWithoutIndex::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::UnknownEnv < ::RuboCop::Cop::Cop + def on_send(node); end + def rails_env?(param0 = T.unsafe(nil)); end + def unknown_environment_equal?(param0 = T.unsafe(nil)); end + def unknown_environment_predicate?(param0 = T.unsafe(nil)); end + + private + + def collect_variable_like_names(_scope); end + def environments; end + def message(name); end + def unknown_env_name?(name); end + def unknown_env_predicate?(name); end +end + +RuboCop::Cop::Rails::UnknownEnv::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::UnknownEnv::MSG_SIMILAR = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::Validation < ::RuboCop::Cop::Cop + def autocorrect(node); end + def on_send(node); end + + private + + def braced_options(options); end + def correct_validate_type(corrector, node); end + def correct_validate_type_for_array(corrector, node, arguments, loc); end + def correct_validate_type_for_hash(corrector, node, arguments); end + def frozen_array_argument?(argument); end + def message(node); end + def preferred_method(method); end + def validate_type(node); end +end + +RuboCop::Cop::Rails::Validation::ALLOWLIST = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::Validation::DENYLIST = T.let(T.unsafe(nil), Array) + +RuboCop::Cop::Rails::Validation::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::Validation::TYPES = T.let(T.unsafe(nil), Array) + +class RuboCop::Cop::Rails::WhereExists < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::ConfigurableEnforcedStyle) + + def autocorrect(node); end + def exists_with_args?(param0 = T.unsafe(nil)); end + def on_send(node); end + def where_exists_call?(param0 = T.unsafe(nil)); end + + private + + def build_good_method(args); end + def build_good_method_exists(args); end + def build_good_method_where(args); end + def convertable_args?(args); end + def correction_range(node); end + def exists_style?; end + def find_offenses(node, &block); end + def where_style?; end +end + +RuboCop::Cop::Rails::WhereExists::MSG = T.let(T.unsafe(nil), String) + +class RuboCop::Cop::Rails::WhereNot < ::RuboCop::Cop::Cop + include(::RuboCop::Cop::RangeHelp) + + def autocorrect(node); end + def on_send(node); end + def where_method_call?(param0 = T.unsafe(nil)); end + + private + + def build_good_method(column, value); end + def extract_column_and_value(template_node, value_node); end + def offense_range(node); end +end + +RuboCop::Cop::Rails::WhereNot::IS_NOT_NULL_RE = T.let(T.unsafe(nil), Regexp) + +RuboCop::Cop::Rails::WhereNot::MSG = T.let(T.unsafe(nil), String) + +RuboCop::Cop::Rails::WhereNot::NOT_EQ_ANONYMOUS_RE = T.let(T.unsafe(nil), Regexp) + +RuboCop::Cop::Rails::WhereNot::NOT_EQ_NAMED_RE = T.let(T.unsafe(nil), Regexp) + +RuboCop::Cop::Rails::WhereNot::NOT_IN_ANONYMOUS_RE = T.let(T.unsafe(nil), Regexp) + +RuboCop::Cop::Rails::WhereNot::NOT_IN_NAMED_RE = T.let(T.unsafe(nil), Regexp) + +module RuboCop::Cop::TargetRailsVersion + def minimum_target_rails_version(version); end + def support_target_rails_version?(version); end +end + +RuboCop::NodePattern = RuboCop::AST::NodePattern + +RuboCop::ProcessedSource = RuboCop::AST::ProcessedSource + +module RuboCop::Rails +end + +RuboCop::Rails::CONFIG = T.let(T.unsafe(nil), Hash) + +module RuboCop::Rails::Inject + class << self + def defaults!; end + end +end + +module RuboCop::Rails::SchemaLoader + extend(::RuboCop::Rails::SchemaLoader) + + def db_schema_path; end + def load(target_ruby_version); end + def reset!; end + + private + + def load!(target_ruby_version); end + def parse(path, target_ruby_version); end +end + +class RuboCop::Rails::SchemaLoader::AddIndex < ::RuboCop::Rails::SchemaLoader::Index + def initialize(node); end + + def table_name; end +end + +class RuboCop::Rails::SchemaLoader::Column + def initialize(node); end + + def name; end + def not_null; end + def type; end + + private + + def analyze_keywords!(node); end +end + +class RuboCop::Rails::SchemaLoader::Index + def initialize(node); end + + def columns; end + def expression; end + def name; end + def unique; end + + private + + def analyze_keywords!(node); end + def build_columns_or_expr(columns); end +end + +class RuboCop::Rails::SchemaLoader::Schema + def initialize(ast); end + + def add_indicies; end + def add_indicies_by(table_name:); end + def table_by(name:); end + def tables; end + + private + + def build!(ast); end + def each_add_index(ast); end + def each_table(ast); end +end + +class RuboCop::Rails::SchemaLoader::Table + def initialize(node); end + + def columns; end + def indices; end + def name; end + def with_column?(name:); end + + private + + def build_columns(node); end + def build_indices(node); end + def each_content(node, &block); end +end + +module RuboCop::Rails::Version +end + +RuboCop::Rails::Version::STRING = T.let(T.unsafe(nil), String) + +RuboCop::Token = RuboCop::AST::Token diff --git a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi index 50e1d69f24..decbac3f71 100644 --- a/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi +++ b/Library/Homebrew/sorbet/rbi/hidden-definitions/hidden.rbi @@ -245,6 +245,15 @@ module ActiveSupport::Cache def self.lookup_store(store=T.unsafe(nil), *parameters); end end +class ActiveSupport::CachingKeyGenerator + def generate_key(*args); end + + def initialize(key_generator); end +end + +class ActiveSupport::CachingKeyGenerator +end + module ActiveSupport::Callbacks def run_callbacks(kind); end CALLBACK_FILTER_TYPES = ::T.let(nil, ::T.untyped) @@ -1648,6 +1657,21 @@ end class ActiveSupport::MessageVerifier end +module ActiveSupport::Messages +end + +class ActiveSupport::Messages::Metadata + def initialize(message, expires_at=T.unsafe(nil), purpose=T.unsafe(nil)); end + + def verify(purpose); end +end + +class ActiveSupport::Messages::Metadata + def self.verify(message, purpose); end + + def self.wrap(message, expires_at: T.unsafe(nil), expires_in: T.unsafe(nil), purpose: T.unsafe(nil)); end +end + module ActiveSupport::Messages::Rotator def initialize(*_, **options); end @@ -1673,6 +1697,9 @@ end module ActiveSupport::Messages::Rotator end +module ActiveSupport::Messages +end + module ActiveSupport::Multibyte end @@ -2345,6 +2372,15 @@ end class ActiveSupport::SafeBuffer end +module ActiveSupport::SecurityUtils +end + +module ActiveSupport::SecurityUtils + def self.fixed_length_secure_compare(a, b); end + + def self.secure_compare(a, b); end +end + class ActiveSupport::StringInquirer end @@ -2472,6 +2508,7 @@ ActiveSupport::TestCase::Assertion = Minitest::Assertion class ActiveSupport::TestCase extend ::ActiveSupport::Callbacks::ClassMethods extend ::ActiveSupport::DescendantsTracker + extend ::ActiveSupport::Testing::Declarative def self.__callbacks(); end def self.__callbacks=(val); end @@ -2501,6 +2538,9 @@ class ActiveSupport::TestCase def self.test_order=(new_order); end end +module ActiveSupport::Testing +end + module ActiveSupport::Testing::Assertions def assert_changes(expression, message=T.unsafe(nil), from: T.unsafe(nil), to: T.unsafe(nil), &block); end @@ -2519,6 +2559,27 @@ end module ActiveSupport::Testing::Assertions end +module ActiveSupport::Testing::ConstantLookup +end + +module ActiveSupport::Testing::ConstantLookup::ClassMethods + def determine_constant_from_test_name(test_name); end +end + +module ActiveSupport::Testing::ConstantLookup::ClassMethods +end + +module ActiveSupport::Testing::ConstantLookup + extend ::ActiveSupport::Concern +end + +module ActiveSupport::Testing::Declarative + def test(name, &block); end +end + +module ActiveSupport::Testing::Declarative +end + module ActiveSupport::Testing::Deprecation def assert_deprecated(match=T.unsafe(nil), deprecator=T.unsafe(nil), &block); end @@ -2538,6 +2599,74 @@ module ActiveSupport::Testing::FileFixtures extend ::ActiveSupport::Concern end +module ActiveSupport::Testing::Isolation + include ::ActiveSupport::Testing::Isolation::Forking + def run(); end +end + +module ActiveSupport::Testing::Isolation::Forking + def run_in_isolation(&blk); end +end + +module ActiveSupport::Testing::Isolation::Forking +end + +module ActiveSupport::Testing::Isolation::Subprocess + def run_in_isolation(&blk); end + ORIG_ARGV = ::T.let(nil, ::T.untyped) +end + +module ActiveSupport::Testing::Isolation::Subprocess +end + +module ActiveSupport::Testing::Isolation + def self.forking_env?(); end + + def self.included(klass); end +end + +class ActiveSupport::Testing::Parallelization + def <<(work); end + + def after_fork(worker); end + + def after_fork_hooks(); end + + def initialize(queue_size); end + + def run_cleanup(worker); end + + def run_cleanup_hooks(); end + + def shutdown(); end + + def start(); end +end + +class ActiveSupport::Testing::Parallelization::Server + include ::DRb::DRbUndumped + def <<(o); end + + def length(); end + + def pop(); end + + def record(reporter, result); end +end + +class ActiveSupport::Testing::Parallelization::Server +end + +class ActiveSupport::Testing::Parallelization + def self.after_fork_hook(&blk); end + + def self.after_fork_hooks(); end + + def self.run_cleanup_hook(&blk); end + + def self.run_cleanup_hooks(); end +end + module ActiveSupport::Testing::SetupAndTeardown def after_teardown(); end @@ -2548,6 +2677,37 @@ module ActiveSupport::Testing::SetupAndTeardown def self.prepended(klass); end end +class ActiveSupport::Testing::SimpleStubs + def stub_object(object, method_name, &block); end + + def stubbing(object, method_name); end + + def unstub_all!(); end +end + +class ActiveSupport::Testing::SimpleStubs::Stub + def method_name(); end + + def method_name=(_); end + + def object(); end + + def object=(_); end + + def original_method(); end + + def original_method=(_); end +end + +class ActiveSupport::Testing::SimpleStubs::Stub + def self.[](*_); end + + def self.members(); end +end + +class ActiveSupport::Testing::SimpleStubs +end + module ActiveSupport::Testing::TaggedLogging def before_setup(); end @@ -2574,6 +2734,9 @@ end module ActiveSupport::Testing::TimeHelpers end +module ActiveSupport::Testing +end + class ActiveSupport::TimeWithZone include ::DateAndTime::Compatibility include ::Comparable @@ -13076,8 +13239,6 @@ class Net::HTTP::Persistent def self.detect_idle_timeout(uri, max=T.unsafe(nil)); end end -Net::HTTP::ProxyMod = Net::HTTP::ProxyDelta - class Net::HTTPAlreadyReported HAS_BODY = ::T.let(nil, ::T.untyped) end @@ -13098,8 +13259,6 @@ end Net::HTTPFatalErrorCode = Net::HTTPClientError -Net::HTTPInformation::EXCEPTION_TYPE = Net::HTTPError - Net::HTTPInformationCode = Net::HTTPInformation class Net::HTTPLoopDetected @@ -13455,6 +13614,10 @@ class OpenSSL::BN def negative?(); end end +module OpenSSL::Buffering + include ::ActiveSupport::ToJsonWithActiveSupportEncoder +end + module OpenSSL::KDF end @@ -25768,6 +25931,1755 @@ class Racc::Parser Racc_YY_Parse_Method = ::T.let(nil, ::T.untyped) end +module Rack + CACHE_CONTROL = ::T.let(nil, ::T.untyped) + CONTENT_LENGTH = ::T.let(nil, ::T.untyped) + CONTENT_TYPE = ::T.let(nil, ::T.untyped) + DELETE = ::T.let(nil, ::T.untyped) + ETAG = ::T.let(nil, ::T.untyped) + EXPIRES = ::T.let(nil, ::T.untyped) + GET = ::T.let(nil, ::T.untyped) + HEAD = ::T.let(nil, ::T.untyped) + HTTPS = ::T.let(nil, ::T.untyped) + HTTP_COOKIE = ::T.let(nil, ::T.untyped) + HTTP_HOST = ::T.let(nil, ::T.untyped) + HTTP_PORT = ::T.let(nil, ::T.untyped) + HTTP_VERSION = ::T.let(nil, ::T.untyped) + LINK = ::T.let(nil, ::T.untyped) + OPTIONS = ::T.let(nil, ::T.untyped) + PATCH = ::T.let(nil, ::T.untyped) + PATH_INFO = ::T.let(nil, ::T.untyped) + POST = ::T.let(nil, ::T.untyped) + PUT = ::T.let(nil, ::T.untyped) + QUERY_STRING = ::T.let(nil, ::T.untyped) + RACK_ERRORS = ::T.let(nil, ::T.untyped) + RACK_HIJACK = ::T.let(nil, ::T.untyped) + RACK_HIJACK_IO = ::T.let(nil, ::T.untyped) + RACK_INPUT = ::T.let(nil, ::T.untyped) + RACK_IS_HIJACK = ::T.let(nil, ::T.untyped) + RACK_LOGGER = ::T.let(nil, ::T.untyped) + RACK_METHODOVERRIDE_ORIGINAL_METHOD = ::T.let(nil, ::T.untyped) + RACK_MULTIPART_BUFFER_SIZE = ::T.let(nil, ::T.untyped) + RACK_MULTIPART_TEMPFILE_FACTORY = ::T.let(nil, ::T.untyped) + RACK_MULTIPROCESS = ::T.let(nil, ::T.untyped) + RACK_MULTITHREAD = ::T.let(nil, ::T.untyped) + RACK_RECURSIVE_INCLUDE = ::T.let(nil, ::T.untyped) + RACK_REQUEST_COOKIE_HASH = ::T.let(nil, ::T.untyped) + RACK_REQUEST_COOKIE_STRING = ::T.let(nil, ::T.untyped) + RACK_REQUEST_FORM_HASH = ::T.let(nil, ::T.untyped) + RACK_REQUEST_FORM_INPUT = ::T.let(nil, ::T.untyped) + RACK_REQUEST_FORM_VARS = ::T.let(nil, ::T.untyped) + RACK_REQUEST_QUERY_HASH = ::T.let(nil, ::T.untyped) + RACK_REQUEST_QUERY_STRING = ::T.let(nil, ::T.untyped) + RACK_RUNONCE = ::T.let(nil, ::T.untyped) + RACK_SESSION = ::T.let(nil, ::T.untyped) + RACK_SESSION_OPTIONS = ::T.let(nil, ::T.untyped) + RACK_SESSION_UNPACKED_COOKIE_DATA = ::T.let(nil, ::T.untyped) + RACK_SHOWSTATUS_DETAIL = ::T.let(nil, ::T.untyped) + RACK_TEMPFILES = ::T.let(nil, ::T.untyped) + RACK_URL_SCHEME = ::T.let(nil, ::T.untyped) + RACK_VERSION = ::T.let(nil, ::T.untyped) + RELEASE = ::T.let(nil, ::T.untyped) + REQUEST_METHOD = ::T.let(nil, ::T.untyped) + REQUEST_PATH = ::T.let(nil, ::T.untyped) + SCRIPT_NAME = ::T.let(nil, ::T.untyped) + SERVER_NAME = ::T.let(nil, ::T.untyped) + SERVER_PORT = ::T.let(nil, ::T.untyped) + SERVER_PROTOCOL = ::T.let(nil, ::T.untyped) + SET_COOKIE = ::T.let(nil, ::T.untyped) + TRACE = ::T.let(nil, ::T.untyped) + TRANSFER_ENCODING = ::T.let(nil, ::T.untyped) + UNLINK = ::T.let(nil, ::T.untyped) + VERSION = ::T.let(nil, ::T.untyped) +end + +module Rack::Auth +end + +class Rack::Auth::AbstractHandler + def initialize(app, realm=T.unsafe(nil), &authenticator); end + + def realm(); end + + def realm=(realm); end +end + +class Rack::Auth::AbstractHandler +end + +class Rack::Auth::AbstractRequest + def initialize(env); end + + def params(); end + + def parts(); end + + def provided?(); end + + def request(); end + + def scheme(); end + + def valid?(); end + AUTHORIZATION_KEYS = ::T.let(nil, ::T.untyped) +end + +class Rack::Auth::AbstractRequest +end + +class Rack::Auth::Basic + def call(env); end +end + +class Rack::Auth::Basic::Request + def basic?(); end + + def credentials(); end + + def username(); end +end + +class Rack::Auth::Basic::Request +end + +class Rack::Auth::Basic +end + +module Rack::Auth::Digest +end + +class Rack::Auth::Digest::MD5 + def call(env); end + + def initialize(app, realm=T.unsafe(nil), opaque=T.unsafe(nil), &authenticator); end + + def opaque(); end + + def opaque=(opaque); end + + def passwords_hashed=(passwords_hashed); end + + def passwords_hashed?(); end + QOP = ::T.let(nil, ::T.untyped) +end + +class Rack::Auth::Digest::MD5 +end + +class Rack::Auth::Digest::Nonce + def digest(); end + + def fresh?(); end + + def initialize(timestamp=T.unsafe(nil), given_digest=T.unsafe(nil)); end + + def stale?(); end + + def valid?(); end +end + +class Rack::Auth::Digest::Nonce + def self.parse(string); end + + def self.private_key(); end + + def self.private_key=(private_key); end + + def self.time_limit(); end + + def self.time_limit=(time_limit); end +end + +class Rack::Auth::Digest::Params + def [](k); end + + def []=(k, v); end + + def initialize(); end + + def quote(str); end + UNQUOTED = ::T.let(nil, ::T.untyped) +end + +class Rack::Auth::Digest::Params + def self.dequote(str); end + + def self.parse(str); end + + def self.split_header_value(str); end +end + +class Rack::Auth::Digest::Request + def correct_uri?(); end + + def digest?(); end + + def method(); end + + def method_missing(sym, *args); end + + def nonce(); end + + def respond_to?(sym, *_); end +end + +class Rack::Auth::Digest::Request +end + +module Rack::Auth::Digest +end + +module Rack::Auth +end + +class Rack::BodyProxy + def close(); end + + def closed?(); end + + def initialize(body, &block); end + + def method_missing(method_name, *args, &block); end +end + +class Rack::BodyProxy +end + +class Rack::Builder + def call(env); end + + def freeze_app(); end + + def initialize(default_app=T.unsafe(nil), &block); end + + def map(path, &block); end + + def run(app); end + + def to_app(); end + + def use(middleware, *args, &block); end + + def warmup(prc=T.unsafe(nil), &block); end + UTF_8_BOM = ::T.let(nil, ::T.untyped) +end + +class Rack::Builder + def self.app(default_app=T.unsafe(nil), &block); end + + def self.load_file(path, opts=T.unsafe(nil)); end + + def self.new_from_string(builder_script, file=T.unsafe(nil)); end + + def self.parse_file(config, opts=T.unsafe(nil)); end +end + +class Rack::Cascade + def <<(app); end + + def add(app); end + + def apps(); end + + def call(env); end + + def include?(app); end + + def initialize(apps, cascade_for=T.unsafe(nil)); end + NotFound = ::T.let(nil, ::T.untyped) +end + +class Rack::Cascade +end + +class Rack::Chunked + include ::Rack::Utils + def call(env); end + + def chunkable_version?(ver); end + + def initialize(app); end +end + +class Rack::Chunked::Body + def close(); end + + def each(&block); end + + def initialize(body); end + TAIL = ::T.let(nil, ::T.untyped) + TERM = ::T.let(nil, ::T.untyped) +end + +class Rack::Chunked::Body +end + +class Rack::Chunked::TrailerBody +end + +class Rack::Chunked::TrailerBody +end + +class Rack::Chunked +end + +class Rack::CommonLogger + def call(env); end + + def initialize(app, logger=T.unsafe(nil)); end + FORMAT = ::T.let(nil, ::T.untyped) +end + +class Rack::CommonLogger +end + +class Rack::ConditionalGet + def call(env); end + + def initialize(app); end +end + +class Rack::ConditionalGet +end + +class Rack::Config + def call(env); end + + def initialize(app, &block); end +end + +class Rack::Config +end + +class Rack::ContentLength + include ::Rack::Utils + def call(env); end + + def initialize(app); end +end + +class Rack::ContentLength +end + +class Rack::ContentType + include ::Rack::Utils + def call(env); end + + def initialize(app, content_type=T.unsafe(nil)); end +end + +class Rack::ContentType +end + +class Rack::Deflater + def call(env); end + + def initialize(app, options=T.unsafe(nil)); end +end + +class Rack::Deflater::GzipStream + def close(); end + + def each(&block); end + + def initialize(body, mtime, sync); end + + def write(data); end +end + +class Rack::Deflater::GzipStream +end + +class Rack::Deflater +end + +class Rack::Directory + def call(env); end + + def check_bad_request(path_info); end + + def check_forbidden(path_info); end + + def entity_not_found(path_info); end + + def filesize_format(int); end + + def get(env); end + + def initialize(root, app=T.unsafe(nil)); end + + def list_directory(path_info, path, script_name); end + + def list_path(env, path, path_info, script_name); end + + def root(); end + + def stat(path); end + DIR_FILE = ::T.let(nil, ::T.untyped) + DIR_PAGE_FOOTER = ::T.let(nil, ::T.untyped) + DIR_PAGE_HEADER = ::T.let(nil, ::T.untyped) + FILESIZE_FORMAT = ::T.let(nil, ::T.untyped) +end + +class Rack::Directory::DirectoryBody +end + +class Rack::Directory::DirectoryBody +end + +class Rack::Directory +end + +class Rack::ETag + def call(env); end + + def initialize(app, no_cache_control=T.unsafe(nil), cache_control=T.unsafe(nil)); end + DEFAULT_CACHE_CONTROL = ::T.let(nil, ::T.untyped) + ETAG_STRING = ::T.let(nil, ::T.untyped) +end + +class Rack::ETag +end + +class Rack::Events + def call(env); end + + def initialize(app, handlers); end +end + +module Rack::Events::Abstract + def on_commit(req, res); end + + def on_error(req, res, e); end + + def on_finish(req, res); end + + def on_send(req, res); end + + def on_start(req, res); end +end + +module Rack::Events::Abstract +end + +class Rack::Events::BufferedResponse + def body(); end + + def initialize(status, headers, body); end + + def to_a(); end +end + +class Rack::Events::BufferedResponse +end + +class Rack::Events::EventedBodyProxy + def each(&blk); end + + def initialize(body, request, response, handlers, &block); end + + def request(); end + + def response(); end +end + +class Rack::Events::EventedBodyProxy +end + +class Rack::Events +end + +Rack::File = Rack::Files + +class Rack::Files + def call(env); end + + def get(env); end + + def initialize(root, headers=T.unsafe(nil), default_mime=T.unsafe(nil)); end + + def root(); end + + def serving(request, path); end + ALLOWED_VERBS = ::T.let(nil, ::T.untyped) + ALLOW_HEADER = ::T.let(nil, ::T.untyped) + MULTIPART_BOUNDARY = ::T.let(nil, ::T.untyped) +end + +class Rack::Files::BaseIterator + def bytesize(); end + + def close(); end + + def each(&blk); end + + def initialize(path, ranges, options); end + + def options(); end + + def path(); end + + def ranges(); end +end + +class Rack::Files::BaseIterator +end + +class Rack::Files::Iterator + def to_path(); end +end + +class Rack::Files::Iterator +end + +class Rack::Files +end + +class Rack::ForwardRequest + def env(); end + + def initialize(url, env=T.unsafe(nil)); end + + def url(); end +end + +class Rack::ForwardRequest +end + +module Rack::Handler +end + +class Rack::Handler::CGI +end + +class Rack::Handler::CGI + def self.run(app, **options); end + + def self.send_body(body); end + + def self.send_headers(status, headers); end + + def self.serve(app); end +end + +class Rack::Handler::WEBrick + def initialize(server, app); end +end + +class Rack::Handler::WEBrick + def self.run(app, **options); end + + def self.shutdown(); end + + def self.valid_options(); end +end + +module Rack::Handler + def self.default(); end + + def self.get(server); end + + def self.pick(server_names); end + + def self.register(server, klass); end + + def self.try_require(prefix, const_name); end +end + +class Rack::Head + def call(env); end + + def initialize(app); end +end + +class Rack::Head +end + +class Rack::Lint + include ::Rack::Lint::Assertion + def _call(env); end + + def call(env=T.unsafe(nil)); end + + def check_content_length(status, headers); end + + def check_content_type(status, headers); end + + def check_env(env); end + + def check_error(error); end + + def check_headers(header); end + + def check_hijack(env); end + + def check_hijack_response(headers, env); end + + def check_input(input); end + + def check_status(status); end + + def close(); end + + def each(&blk); end + + def initialize(app); end + + def verify_content_length(bytes); end +end + +module Rack::Lint::Assertion + def assert(message); end +end + +module Rack::Lint::Assertion +end + +class Rack::Lint::ErrorWrapper + include ::Rack::Lint::Assertion + def close(*args); end + + def flush(); end + + def initialize(error); end + + def puts(str); end + + def write(str); end +end + +class Rack::Lint::ErrorWrapper +end + +class Rack::Lint::HijackWrapper + include ::Rack::Lint::Assertion + def close(*args, &block); end + + def close_read(*args, &block); end + + def close_write(*args, &block); end + + def closed?(*args, &block); end + + def flush(*args, &block); end + + def initialize(io); end + + def read(*args, &block); end + + def read_nonblock(*args, &block); end + + def write(*args, &block); end + + def write_nonblock(*args, &block); end + REQUIRED_METHODS = ::T.let(nil, ::T.untyped) +end + +class Rack::Lint::HijackWrapper + extend ::Forwardable +end + +class Rack::Lint::InputWrapper + include ::Rack::Lint::Assertion + def close(*args); end + + def each(*args, &blk); end + + def gets(*args); end + + def initialize(input); end + + def read(*args); end + + def rewind(*args); end +end + +class Rack::Lint::InputWrapper +end + +class Rack::Lint::LintError +end + +class Rack::Lint::LintError +end + +class Rack::Lint +end + +class Rack::Lock + def call(env); end + + def initialize(app, mutex=T.unsafe(nil)); end +end + +class Rack::Lock +end + +class Rack::Logger + def call(env); end + + def initialize(app, level=T.unsafe(nil)); end +end + +class Rack::Logger +end + +class Rack::MediaType + SPLIT_PATTERN = ::T.let(nil, ::T.untyped) +end + +class Rack::MediaType + def self.params(content_type); end + + def self.type(content_type); end +end + +class Rack::MethodOverride + def call(env); end + + def initialize(app); end + + def method_override(env); end + ALLOWED_METHODS = ::T.let(nil, ::T.untyped) + HTTP_METHODS = ::T.let(nil, ::T.untyped) + HTTP_METHOD_OVERRIDE_HEADER = ::T.let(nil, ::T.untyped) + METHOD_OVERRIDE_PARAM_KEY = ::T.let(nil, ::T.untyped) +end + +class Rack::MethodOverride +end + +module Rack::Mime + MIME_TYPES = ::T.let(nil, ::T.untyped) +end + +module Rack::Mime + def self.match?(value, matcher); end + + def self.mime_type(ext, fallback=T.unsafe(nil)); end +end + +class Rack::MockRequest + def delete(uri, opts=T.unsafe(nil)); end + + def get(uri, opts=T.unsafe(nil)); end + + def head(uri, opts=T.unsafe(nil)); end + + def initialize(app); end + + def options(uri, opts=T.unsafe(nil)); end + + def patch(uri, opts=T.unsafe(nil)); end + + def post(uri, opts=T.unsafe(nil)); end + + def put(uri, opts=T.unsafe(nil)); end + + def request(method=T.unsafe(nil), uri=T.unsafe(nil), opts=T.unsafe(nil)); end + DEFAULT_ENV = ::T.let(nil, ::T.untyped) +end + +class Rack::MockRequest::FatalWarner + def flush(); end + + def puts(warning); end + + def string(); end + + def write(warning); end +end + +class Rack::MockRequest::FatalWarner +end + +class Rack::MockRequest::FatalWarning +end + +class Rack::MockRequest::FatalWarning +end + +class Rack::MockRequest + def self.env_for(uri=T.unsafe(nil), opts=T.unsafe(nil)); end + + def self.parse_uri_rfc2396(uri); end +end + +class Rack::MockResponse + def =~(other); end + + def cookie(name); end + + def cookies(); end + + def errors(); end + + def errors=(errors); end + + def initialize(status, headers, body, errors=T.unsafe(nil)); end + + def match(other); end + + def original_headers(); end +end + +class Rack::MockResponse + def self.[](*_); end +end + +module Rack::Multipart + ATTRIBUTE = ::T.let(nil, ::T.untyped) + ATTRIBUTE_CHAR = ::T.let(nil, ::T.untyped) + BROKEN_QUOTED = ::T.let(nil, ::T.untyped) + BROKEN_UNQUOTED = ::T.let(nil, ::T.untyped) + CONDISP = ::T.let(nil, ::T.untyped) + DISPPARM = ::T.let(nil, ::T.untyped) + EOL = ::T.let(nil, ::T.untyped) + EXTENDED_INITIAL_NAME = ::T.let(nil, ::T.untyped) + EXTENDED_INITIAL_PARAMETER = ::T.let(nil, ::T.untyped) + EXTENDED_INITIAL_VALUE = ::T.let(nil, ::T.untyped) + EXTENDED_OTHER_NAME = ::T.let(nil, ::T.untyped) + EXTENDED_OTHER_PARAMETER = ::T.let(nil, ::T.untyped) + EXTENDED_OTHER_VALUE = ::T.let(nil, ::T.untyped) + EXTENDED_PARAMETER = ::T.let(nil, ::T.untyped) + MULTIPART = ::T.let(nil, ::T.untyped) + MULTIPART_BOUNDARY = ::T.let(nil, ::T.untyped) + MULTIPART_CONTENT_DISPOSITION = ::T.let(nil, ::T.untyped) + MULTIPART_CONTENT_ID = ::T.let(nil, ::T.untyped) + MULTIPART_CONTENT_TYPE = ::T.let(nil, ::T.untyped) + REGULAR_PARAMETER = ::T.let(nil, ::T.untyped) + REGULAR_PARAMETER_NAME = ::T.let(nil, ::T.untyped) + RFC2183 = ::T.let(nil, ::T.untyped) + SECTION = ::T.let(nil, ::T.untyped) + TOKEN = ::T.let(nil, ::T.untyped) + VALUE = ::T.let(nil, ::T.untyped) +end + +class Rack::Multipart::Generator + def dump(); end + + def initialize(params, first=T.unsafe(nil)); end +end + +class Rack::Multipart::Generator +end + +class Rack::Multipart::MultipartPartLimitError +end + +class Rack::Multipart::MultipartPartLimitError +end + +class Rack::Multipart::Parser + def initialize(boundary, tempfile, bufsize, query_parser); end + + def on_read(content); end + + def result(); end + + def state(); end + BOUNDARY_REGEX = ::T.let(nil, ::T.untyped) + BUFSIZE = ::T.let(nil, ::T.untyped) + CHARSET = ::T.let(nil, ::T.untyped) + EMPTY = ::T.let(nil, ::T.untyped) + TEMPFILE_FACTORY = ::T.let(nil, ::T.untyped) + TEXT_PLAIN = ::T.let(nil, ::T.untyped) +end + +class Rack::Multipart::Parser::BoundedIO + def initialize(io, content_length); end + + def read(size, outbuf=T.unsafe(nil)); end + + def rewind(); end +end + +class Rack::Multipart::Parser::BoundedIO +end + +class Rack::Multipart::Parser::Collector + include ::Enumerable + def each(&blk); end + + def initialize(tempfile); end + + def on_mime_body(mime_index, content); end + + def on_mime_finish(mime_index); end + + def on_mime_head(mime_index, head, filename, content_type, name); end +end + +class Rack::Multipart::Parser::Collector::BufferPart + def close(); end + + def file?(); end +end + +class Rack::Multipart::Parser::Collector::BufferPart +end + +class Rack::Multipart::Parser::Collector::MimePart + def get_data(); end +end + +class Rack::Multipart::Parser::Collector::MimePart +end + +class Rack::Multipart::Parser::Collector::TempfilePart + def close(); end + + def file?(); end +end + +class Rack::Multipart::Parser::Collector::TempfilePart +end + +class Rack::Multipart::Parser::Collector +end + +class Rack::Multipart::Parser::MultipartInfo + def params(); end + + def params=(_); end + + def tmp_files(); end + + def tmp_files=(_); end +end + +class Rack::Multipart::Parser::MultipartInfo + def self.[](*_); end + + def self.members(); end +end + +class Rack::Multipart::Parser + def self.parse(io, content_length, content_type, tmpfile, bufsize, qp); end + + def self.parse_boundary(content_type); end +end + +class Rack::Multipart::UploadedFile + def content_type(); end + + def content_type=(content_type); end + + def initialize(filepath=T.unsafe(nil), ct=T.unsafe(nil), bin=T.unsafe(nil), path: T.unsafe(nil), content_type: T.unsafe(nil), binary: T.unsafe(nil), filename: T.unsafe(nil), io: T.unsafe(nil)); end + + def local_path(); end + + def method_missing(method_name, *args, &block); end + + def original_filename(); end + + def path(); end + + def respond_to?(*args); end +end + +class Rack::Multipart::UploadedFile +end + +module Rack::Multipart + def self.build_multipart(params, first=T.unsafe(nil)); end + + def self.extract_multipart(req, params=T.unsafe(nil)); end + + def self.parse_multipart(env, params=T.unsafe(nil)); end +end + +class Rack::NullLogger + def <<(msg); end + + def add(severity, message=T.unsafe(nil), progname=T.unsafe(nil), &block); end + + def call(env); end + + def close(); end + + def datetime_format(); end + + def datetime_format=(datetime_format); end + + def debug(progname=T.unsafe(nil), &block); end + + def debug?(); end + + def error(progname=T.unsafe(nil), &block); end + + def error?(); end + + def fatal(progname=T.unsafe(nil), &block); end + + def fatal?(); end + + def formatter(); end + + def formatter=(formatter); end + + def info(progname=T.unsafe(nil), &block); end + + def info?(); end + + def initialize(app); end + + def level(); end + + def level=(level); end + + def progname(); end + + def progname=(progname); end + + def sev_threshold(); end + + def sev_threshold=(sev_threshold); end + + def unknown(progname=T.unsafe(nil), &block); end + + def warn(progname=T.unsafe(nil), &block); end + + def warn?(); end +end + +class Rack::NullLogger +end + +class Rack::Recursive + def _call(env); end + + def call(env); end + + def include(env, path); end + + def initialize(app); end +end + +class Rack::Recursive +end + +class Rack::Reloader + def call(env); end + + def initialize(app, cooldown=T.unsafe(nil), backend=T.unsafe(nil)); end + + def reload!(stderr=T.unsafe(nil)); end + + def safe_load(file, mtime, stderr=T.unsafe(nil)); end +end + +module Rack::Reloader::Stat + def figure_path(file, paths); end + + def rotation(); end + + def safe_stat(file); end +end + +module Rack::Reloader::Stat +end + +class Rack::Reloader +end + +class Rack::Request + include ::Rack::Request::Env + include ::Rack::Request::Helpers + ALLOWED_SCHEMES = ::T.let(nil, ::T.untyped) + SCHEME_WHITELIST = ::T.let(nil, ::T.untyped) +end + +module Rack::Request::Env + def add_header(key, v); end + + def delete_header(name); end + + def each_header(&block); end + + def env(); end + + def fetch_header(name, &block); end + + def get_header(name); end + + def has_header?(name); end + + def initialize(env); end + + def set_header(name, v); end +end + +module Rack::Request::Env +end + +module Rack::Request::Helpers + def GET(); end + + def POST(); end + + def [](key); end + + def []=(key, value); end + + def accept_encoding(); end + + def accept_language(); end + + def authority(); end + + def base_url(); end + + def body(); end + + def content_charset(); end + + def content_length(); end + + def content_type(); end + + def cookies(); end + + def delete?(); end + + def delete_param(k); end + + def form_data?(); end + + def forwarded_authority(); end + + def forwarded_for(); end + + def forwarded_port(); end + + def fullpath(); end + + def get?(); end + + def head?(); end + + def host(); end + + def host_authority(); end + + def host_with_port(authority=T.unsafe(nil)); end + + def hostname(); end + + def ip(); end + + def link?(); end + + def logger(); end + + def media_type(); end + + def media_type_params(); end + + def multithread?(); end + + def options?(); end + + def params(); end + + def parseable_data?(); end + + def patch?(); end + + def path(); end + + def path_info(); end + + def path_info=(s); end + + def port(); end + + def post?(); end + + def put?(); end + + def query_string(); end + + def referer(); end + + def referrer(); end + + def request_method(); end + + def scheme(); end + + def script_name(); end + + def script_name=(s); end + + def server_authority(); end + + def server_name(); end + + def server_port(); end + + def session(); end + + def session_options(); end + + def ssl?(); end + + def trace?(); end + + def trusted_proxy?(ip); end + + def unlink?(); end + + def update_param(k, v); end + + def url(); end + + def user_agent(); end + + def values_at(*keys); end + + def xhr?(); end + DEFAULT_PORTS = ::T.let(nil, ::T.untyped) + FORM_DATA_MEDIA_TYPES = ::T.let(nil, ::T.untyped) + HTTP_X_FORWARDED_FOR = ::T.let(nil, ::T.untyped) + HTTP_X_FORWARDED_HOST = ::T.let(nil, ::T.untyped) + HTTP_X_FORWARDED_PORT = ::T.let(nil, ::T.untyped) + HTTP_X_FORWARDED_PROTO = ::T.let(nil, ::T.untyped) + HTTP_X_FORWARDED_SCHEME = ::T.let(nil, ::T.untyped) + HTTP_X_FORWARDED_SSL = ::T.let(nil, ::T.untyped) + PARSEABLE_DATA_MEDIA_TYPES = ::T.let(nil, ::T.untyped) +end + +module Rack::Request::Helpers +end + +class Rack::Request + def self.ip_filter(); end + + def self.ip_filter=(ip_filter); end +end + +class Rack::Response + include ::Rack::Response::Helpers + def [](key); end + + def []=(key, v); end + + def body(); end + + def body=(body); end + + def chunked?(); end + + def close(); end + + def delete_header(key); end + + def each(&callback); end + + def empty?(); end + + def finish(&block); end + + def get_header(key); end + + def has_header?(key); end + + def header(); end + + def headers(); end + + def initialize(body=T.unsafe(nil), status=T.unsafe(nil), headers=T.unsafe(nil)); end + + def length(); end + + def length=(length); end + + def redirect(target, status=T.unsafe(nil)); end + + def set_header(key, v); end + + def status(); end + + def status=(status); end + + def to_a(&block); end + + def write(chunk); end + CHUNKED = ::T.let(nil, ::T.untyped) + STATUS_WITH_NO_ENTITY_BODY = ::T.let(nil, ::T.untyped) +end + +module Rack::Response::Helpers + def accepted?(); end + + def add_header(key, v); end + + def append(chunk); end + + def bad_request?(); end + + def buffered_body!(); end + + def cache!(duration=T.unsafe(nil), directive: T.unsafe(nil)); end + + def cache_control(); end + + def cache_control=(v); end + + def client_error?(); end + + def content_length(); end + + def content_type(); end + + def content_type=(content_type); end + + def created?(); end + + def delete_cookie(key, value=T.unsafe(nil)); end + + def do_not_cache!(); end + + def etag(); end + + def etag=(v); end + + def forbidden?(); end + + def include?(header); end + + def informational?(); end + + def invalid?(); end + + def location(); end + + def location=(location); end + + def media_type(); end + + def media_type_params(); end + + def method_not_allowed?(); end + + def moved_permanently?(); end + + def no_content?(); end + + def not_found?(); end + + def ok?(); end + + def precondition_failed?(); end + + def redirect?(); end + + def redirection?(); end + + def server_error?(); end + + def set_cookie(key, value); end + + def set_cookie_header(); end + + def set_cookie_header=(v); end + + def successful?(); end + + def unauthorized?(); end + + def unprocessable?(); end +end + +module Rack::Response::Helpers +end + +class Rack::Response::Raw + include ::Rack::Response::Helpers + def delete_header(key); end + + def get_header(key); end + + def has_header?(key); end + + def headers(); end + + def initialize(status, headers); end + + def set_header(key, v); end + + def status(); end + + def status=(status); end +end + +class Rack::Response::Raw +end + +class Rack::Response + def self.[](status, headers, body); end +end + +class Rack::RewindableInput + def close(); end + + def each(&block); end + + def gets(); end + + def initialize(io); end + + def read(*args); end + + def rewind(); end +end + +class Rack::RewindableInput +end + +class Rack::Runtime + def call(env); end + + def initialize(app, name=T.unsafe(nil)); end + FORMAT_STRING = ::T.let(nil, ::T.untyped) + HEADER_NAME = ::T.let(nil, ::T.untyped) +end + +class Rack::Runtime +end + +class Rack::Sendfile + def call(env); end + + def initialize(app, variation=T.unsafe(nil), mappings=T.unsafe(nil)); end +end + +class Rack::Sendfile +end + +class Rack::Server + def app(); end + + def default_options(); end + + def initialize(options=T.unsafe(nil)); end + + def middleware(); end + + def options(); end + + def options=(options); end + + def server(); end + + def start(&block); end +end + +class Rack::Server::Options + def handler_opts(options); end + + def parse!(args); end +end + +class Rack::Server::Options +end + +class Rack::Server + def self.default_middleware_by_environment(); end + + def self.logging_middleware(); end + + def self.middleware(); end + + def self.start(options=T.unsafe(nil)); end +end + +module Rack::Session +end + +module Rack::Session::Abstract +end + +class Rack::Session::Abstract::ID + def find_session(req, sid); end +end + +class Rack::Session::Abstract::ID + def self.inherited(klass); end +end + +class Rack::Session::Abstract::Persisted + def call(env); end + + def commit_session(req, res); end + + def context(env, app=T.unsafe(nil)); end + + def default_options(); end + + def initialize(app, options=T.unsafe(nil)); end + + def key(); end + + def sid_secure(); end + DEFAULT_OPTIONS = ::T.let(nil, ::T.untyped) +end + +class Rack::Session::Abstract::Persisted +end + +class Rack::Session::Abstract::PersistedSecure + def extract_session_id(*_); end + + def generate_sid(*_); end +end + +class Rack::Session::Abstract::PersistedSecure::SecureSessionHash +end + +class Rack::Session::Abstract::PersistedSecure::SecureSessionHash +end + +class Rack::Session::Abstract::PersistedSecure +end + +class Rack::Session::Abstract::SessionHash + include ::Enumerable + def [](key); end + + def []=(key, value); end + + def clear(); end + + def delete(key); end + + def destroy(); end + + def dig(key, *keys); end + + def each(&block); end + + def empty?(); end + + def exists?(); end + + def fetch(key, default=T.unsafe(nil), &block); end + + def has_key?(key); end + + def id(); end + + def id=(id); end + + def include?(key); end + + def initialize(store, req); end + + def key?(key); end + + def keys(); end + + def loaded?(); end + + def merge!(hash); end + + def options(); end + + def replace(hash); end + + def store(key, value); end + + def to_hash(); end + + def update(hash); end + + def values(); end + Unspecified = ::T.let(nil, ::T.untyped) +end + +class Rack::Session::Abstract::SessionHash + def self.find(req); end + + def self.set(req, session); end + + def self.set_options(req, options); end +end + +module Rack::Session::Abstract +end + +class Rack::Session::Cookie + def coder(); end +end + +class Rack::Session::Cookie::Base64 + def decode(str); end + + def encode(str); end +end + +class Rack::Session::Cookie::Base64::JSON + def encode(obj); end +end + +class Rack::Session::Cookie::Base64::JSON +end + +class Rack::Session::Cookie::Base64::Marshal +end + +class Rack::Session::Cookie::Base64::Marshal +end + +class Rack::Session::Cookie::Base64::ZipJSON + def encode(obj); end +end + +class Rack::Session::Cookie::Base64::ZipJSON +end + +class Rack::Session::Cookie::Base64 +end + +class Rack::Session::Cookie::Identity + def decode(str); end + + def encode(str); end +end + +class Rack::Session::Cookie::Identity +end + +class Rack::Session::Cookie::SessionId + def cookie_value(); end + + def initialize(session_id, cookie_value); end +end + +class Rack::Session::Cookie::SessionId +end + +class Rack::Session::Cookie +end + +class Rack::Session::Pool + def delete_session(req, session_id, options); end + + def find_session(req, sid); end + + def generate_sid(); end + + def mutex(); end + + def pool(); end + + def with_lock(req); end + + def write_session(req, session_id, new_session, options); end + DEFAULT_OPTIONS = ::T.let(nil, ::T.untyped) +end + +class Rack::Session::Pool +end + +class Rack::Session::SessionId + def cookie_value(); end + + def empty?(); end + + def initialize(public_id); end + + def private_id(); end + + def public_id(); end + ID_VERSION = ::T.let(nil, ::T.untyped) +end + +class Rack::Session::SessionId +end + +module Rack::Session +end + +class Rack::ShowExceptions + def call(env); end + + def dump_exception(exception); end + + def h(obj); end + + def initialize(app); end + + def prefers_plaintext?(env); end + + def pretty(env, exception); end + + def template(); end + CONTEXT = ::T.let(nil, ::T.untyped) + TEMPLATE = ::T.let(nil, ::T.untyped) +end + +class Rack::ShowExceptions +end + +class Rack::ShowStatus + def call(env); end + + def h(obj); end + + def initialize(app); end + TEMPLATE = ::T.let(nil, ::T.untyped) +end + +class Rack::ShowStatus +end + +class Rack::Static + def add_index_root?(path); end + + def applicable_rules(path); end + + def call(env); end + + def can_serve(path); end + + def initialize(app, options=T.unsafe(nil)); end + + def overwrite_file_path(path); end + + def route_file(path); end +end + +class Rack::Static +end + +class Rack::TempfileReaper + def call(env); end + + def initialize(app); end +end + +class Rack::TempfileReaper +end + +class Rack::URLMap + def call(env); end + + def initialize(map=T.unsafe(nil)); end + + def remap(map); end +end + +class Rack::URLMap +end + +module Rack + def self.release(); end + + def self.version(); end +end + class Random def self.bytes(_); end end @@ -26173,10 +28085,31 @@ class RuboCop::AST::NodePattern::Parser end module RuboCop::AST::NodePattern::Sets + SET_AFTER_ACTION_APPEND_AFTER_ACTION_APPEND_AROUND_ACTION_ETC = ::T.let(nil, ::T.untyped) + SET_AP_P_PP_ETC = ::T.let(nil, ::T.untyped) + SET_BELONGS_TO_HAS_ONE_HAS_MANY_HAS_AND_BELONGS_TO_MANY = ::T.let(nil, ::T.untyped) + SET_BINWRITE_SYSWRITE_WRITE_WRITE_NONBLOCK = ::T.let(nil, ::T.untyped) SET_BUILD_RECOMMENDED_TEST_OPTIONAL = ::T.let(nil, ::T.untyped) + SET_CREATED_AT_UPDATED_AT = ::T.let(nil, ::T.untyped) + SET_CREATED_AT_UPDATED_AT_2 = ::T.let(nil, ::T.untyped) SET_DEPENDS_ON_USES_FROM_MACOS = ::T.let(nil, ::T.untyped) + SET_EXECUTE_REMOVE_BELONGS_TO = ::T.let(nil, ::T.untyped) + SET_FIRST_TAKE = ::T.let(nil, ::T.untyped) + SET_GET_POST_PUT_ETC = ::T.let(nil, ::T.untyped) + SET_HAS_MANY_HAS_ONE = ::T.let(nil, ::T.untyped) + SET_HAS_MANY_HAS_ONE_BELONGS_TO = ::T.let(nil, ::T.untyped) SET_INCLUDE_WITH_WITHOUT = ::T.let(nil, ::T.untyped) + SET_INSERT_INSERT = ::T.let(nil, ::T.untyped) + SET_ONLY_EXCEPT = ::T.let(nil, ::T.untyped) + SET_REFERER_REFERRER = ::T.let(nil, ::T.untyped) + SET_RENDER_REDIRECT_TO = ::T.let(nil, ::T.untyped) + SET_RETURNING_UNIQUE_BY = ::T.let(nil, ::T.untyped) + SET_SINCE_FROM_NOW_AFTER_ETC = ::T.let(nil, ::T.untyped) + SET_SKIP_AFTER_ACTION_SKIP_AROUND_ACTION_SKIP_BEFORE_ACTION_SKIP_ACTION_CALLBACK = ::T.let(nil, ::T.untyped) SET_SYSTEM_SHELL_OUTPUT_PIPE_OUTPUT = ::T.let(nil, ::T.untyped) + SET_TRANSLATE_LOCALIZE = ::T.let(nil, ::T.untyped) + SET_TRY_TRY = ::T.let(nil, ::T.untyped) + SET_UNIQ_DISTINCT = ::T.let(nil, ::T.untyped) SET_WITH_WITHOUT = ::T.let(nil, ::T.untyped) end @@ -26376,6 +28309,56 @@ class RuboCop::Cop::FormulaCop def required_dependency_name?(param0, param1); end end +module RuboCop::Cop::RSpec::Rails +end + +class RuboCop::Cop::RSpec::Rails::HttpStatus + include ::RuboCop::Cop::ConfigurableEnforcedStyle + def http_status(param0=T.unsafe(nil)); end + + def on_send(node); end +end + +class RuboCop::Cop::RSpec::Rails::HttpStatus::NumericStyleChecker + def initialize(node); end + + def message(); end + + def node(); end + + def offensive?(); end + + def preferred_style(); end + ALLOWED_STATUSES = ::T.let(nil, ::T.untyped) + MSG = ::T.let(nil, ::T.untyped) +end + +class RuboCop::Cop::RSpec::Rails::HttpStatus::NumericStyleChecker +end + +class RuboCop::Cop::RSpec::Rails::HttpStatus::SymbolicStyleChecker + def initialize(node); end + + def message(); end + + def node(); end + + def offensive?(); end + + def preferred_style(); end + MSG = ::T.let(nil, ::T.untyped) +end + +class RuboCop::Cop::RSpec::Rails::HttpStatus::SymbolicStyleChecker +end + +class RuboCop::Cop::RSpec::Rails::HttpStatus + extend ::RuboCop::Cop::AutoCorrector +end + +module RuboCop::Cop::RSpec::Rails +end + module RuboCop::RSpec::ExpectOffense def expect_correction(correction, loop: T.unsafe(nil)); end @@ -28277,6 +30260,7 @@ class Socket IPV6_PATHMTU = ::T.let(nil, ::T.untyped) IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped) IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped) + IP_DONTFRAG = ::T.let(nil, ::T.untyped) IP_PORTRANGE = ::T.let(nil, ::T.untyped) IP_RECVDSTADDR = ::T.let(nil, ::T.untyped) IP_RECVIF = ::T.let(nil, ::T.untyped) @@ -28368,6 +30352,7 @@ module Socket::Constants IPV6_PATHMTU = ::T.let(nil, ::T.untyped) IPV6_RECVPATHMTU = ::T.let(nil, ::T.untyped) IPV6_USE_MIN_MTU = ::T.let(nil, ::T.untyped) + IP_DONTFRAG = ::T.let(nil, ::T.untyped) IP_PORTRANGE = ::T.let(nil, ::T.untyped) IP_RECVDSTADDR = ::T.let(nil, ::T.untyped) IP_RECVIF = ::T.let(nil, ::T.untyped) @@ -30602,6 +32587,46 @@ class Version::Token extend ::T::Private::Methods::SingletonMethodHooks end +WEBrick::HTTPAuth::Authenticator::AuthException = WEBrick::HTTPStatus::Unauthorized + +WEBrick::HTTPAuth::ProxyAuthenticator::AuthException = WEBrick::HTTPStatus::ProxyAuthenticationRequired + +class WEBrick::HTTPRequest + def body_reader(); end + + def readpartial(size, buf=T.unsafe(nil)); end + MAX_HEADER_LENGTH = ::T.let(nil, ::T.untyped) +end + +class WEBrick::HTTPResponse + def _rack_setup_header(); end + + def rack(); end + + def rack=(rack); end +end + +class WEBrick::HTTPResponse::ChunkedWrapper + def <<(*buf); end + + def initialize(socket, resp); end + + def write(buf); end +end + +class WEBrick::HTTPResponse::ChunkedWrapper +end + +class WEBrick::HTTPServer + def create_request(with_webrick_config); end + + def create_response(with_webrick_config); end +end + +class WEBrick::HTTPServlet::DefaultFileHandler + def multipart_body(body, parts, boundary, mtype, filesize); end +end + module Warning extend ::Warning end diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index a9fbd0038f..d7980f6518 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -514,9 +514,9 @@ module Kernel def tap_and_name_comparison proc do |a, b| - if a.include?("/") && !b.include?("/") + if a.include?("/") && b.exclude?("/") 1 - elsif !a.include?("/") && b.include?("/") + elsif a.exclude?("/") && b.include?("/") -1 else a <=> b diff --git a/Library/Homebrew/utils/curl.rb b/Library/Homebrew/utils/curl.rb index 7229bd2e2a..afcc85712c 100644 --- a/Library/Homebrew/utils/curl.rb +++ b/Library/Homebrew/utils/curl.rb @@ -71,7 +71,7 @@ module Utils env: { "SSL_CERT_FILE" => nil }.merge(env), **command_options - if !result.success? && !args.include?("--http1.1") + if !result.success? && args.exclude?("--http1.1") # This is a workaround for https://github.com/curl/curl/issues/1618. if result.status.exitstatus == 56 # Unexpected EOF out = curl_output("-V").stdout diff --git a/Library/Homebrew/utils/fork.rb b/Library/Homebrew/utils/fork.rb index 6b858996b6..e9eb1ea243 100644 --- a/Library/Homebrew/utils/fork.rb +++ b/Library/Homebrew/utils/fork.rb @@ -79,7 +79,7 @@ module Utils # without writing its Interrupt exception to the error pipe. raise Interrupt if $CHILD_STATUS.exitstatus == 130 - if data && !data.empty? + if data.present? error_hash = JSON.parse(T.must(data.lines.first)) e = ChildProcessError.new(error_hash) diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb index dfd585a567..8aeb60a21a 100644 --- a/Library/Homebrew/utils/github.rb +++ b/Library/Homebrew/utils/github.rb @@ -451,13 +451,11 @@ module GitHub next if commit.present? && commit != r["commit"]["oid"] next unless valid_associations.include? r["authorAssociation"] - email = if r["author"]["email"].blank? - "#{r["author"]["databaseId"]}+#{r["author"]["login"]}@users.noreply.github.com" - else - r["author"]["email"] - end + email = r["author"]["email"].presence || + "#{r["author"]["databaseId"]}+#{r["author"]["login"]}@users.noreply.github.com" - name = r["author"]["name"].presence || r["author"]["login"] + name = r["author"]["name"].presence || + r["author"]["login"] { "email" => email, diff --git a/Library/Homebrew/utils/shared_audits.rb b/Library/Homebrew/utils/shared_audits.rb index 6587672c8e..bd176425ea 100644 --- a/Library/Homebrew/utils/shared_audits.rb +++ b/Library/Homebrew/utils/shared_audits.rb @@ -107,7 +107,7 @@ module SharedAudits return if metadata.nil? - if metadata["fork"] && !GITHUB_FORK_ALLOWLIST.include?("#{user}/#{repo}") + if metadata["fork"] && GITHUB_FORK_ALLOWLIST.exclude?("#{user}/#{repo}") return "GitHub fork (not canonical repository)" end diff --git a/Library/Homebrew/vendor/bundle/bundler/setup.rb b/Library/Homebrew/vendor/bundle/bundler/setup.rb index 12e4b717f3..4265ec8814 100644 --- a/Library/Homebrew/vendor/bundle/bundler/setup.rb +++ b/Library/Homebrew/vendor/bundle/bundler/setup.rb @@ -13,9 +13,9 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/activesupport-6.0.3.4 $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/bindata-2.4.8/lib" $:.unshift "#{path}/" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/byebug-11.1.3" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/byebug-11.1.3" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/byebug-11.1.3/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/json-2.3.1" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/json-2.3.1" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/json-2.3.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/docile-1.3.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.12.3/lib" @@ -28,12 +28,12 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/highline-2.0.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/commander-4.5.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/connection_pool-2.2.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/diff-lcs-1.4.4/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/unf_ext-0.0.7.7" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/unf_ext-0.0.7.7" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unf_ext-0.0.7.7/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unf-0.1.4/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/domain_name-0.5.20190701/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/elftools-1.1.3/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/hpricot-0.8.6" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/hpricot-0.8.6" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/hpricot-0.8.6/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/http-cookie-1.0.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mime-types-data-3.2020.1104/lib" @@ -41,7 +41,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mime-types-3.3.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/net-http-digest_auth-1.4.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/net-http-persistent-4.0.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/mini_portile2-2.4.0/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/nokogiri-1.10.10" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/nokogiri-1.10.10" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/nokogiri-1.10.10/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ntlm-http-0.1.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/webrobots-0.1.2/lib" @@ -57,7 +57,8 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parlour-4.0.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.3.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.5.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/pry-0.13.1/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-19/2.6.0/rdiscount-2.2.0.2" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rack-2.2.3/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-20/2.6.0/rdiscount-2.2.0.2" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rdiscount-2.2.0.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/regexp_parser-2.0.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rexml-3.2.4/lib" @@ -69,7 +70,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-mocks-3.10.0/li $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-3.10.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-its-1.3.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-retry-0.6.2/lib" -$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.6111-universal-darwin-19/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.6111-universal-darwin-20/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.6111/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-sorbet-1.7.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rspec-wait-0.0.9/lib" @@ -78,6 +79,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.10 $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-1.7.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-1.3.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.9.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rails-2.8.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.0.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.5.1/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.5.0/lib" diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack.rb new file mode 100644 index 0000000000..e4494e5bac --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack.rb @@ -0,0 +1,141 @@ +# frozen_string_literal: true + +# Copyright (C) 2007-2019 Leah Neukirchen +# +# Rack is freely distributable under the terms of an MIT-style license. +# See MIT-LICENSE or https://opensource.org/licenses/MIT. + +# The Rack main module, serving as a namespace for all core Rack +# modules and classes. +# +# All modules meant for use in your application are autoloaded here, +# so it should be enough just to require 'rack' in your code. + +require_relative 'rack/version' + +module Rack + HTTP_HOST = 'HTTP_HOST' + HTTP_PORT = 'HTTP_PORT' + HTTP_VERSION = 'HTTP_VERSION' + HTTPS = 'HTTPS' + PATH_INFO = 'PATH_INFO' + REQUEST_METHOD = 'REQUEST_METHOD' + REQUEST_PATH = 'REQUEST_PATH' + SCRIPT_NAME = 'SCRIPT_NAME' + QUERY_STRING = 'QUERY_STRING' + SERVER_PROTOCOL = 'SERVER_PROTOCOL' + SERVER_NAME = 'SERVER_NAME' + SERVER_PORT = 'SERVER_PORT' + CACHE_CONTROL = 'Cache-Control' + EXPIRES = 'Expires' + CONTENT_LENGTH = 'Content-Length' + CONTENT_TYPE = 'Content-Type' + SET_COOKIE = 'Set-Cookie' + TRANSFER_ENCODING = 'Transfer-Encoding' + HTTP_COOKIE = 'HTTP_COOKIE' + ETAG = 'ETag' + + # HTTP method verbs + GET = 'GET' + POST = 'POST' + PUT = 'PUT' + PATCH = 'PATCH' + DELETE = 'DELETE' + HEAD = 'HEAD' + OPTIONS = 'OPTIONS' + LINK = 'LINK' + UNLINK = 'UNLINK' + TRACE = 'TRACE' + + # Rack environment variables + RACK_VERSION = 'rack.version' + RACK_TEMPFILES = 'rack.tempfiles' + RACK_ERRORS = 'rack.errors' + RACK_LOGGER = 'rack.logger' + RACK_INPUT = 'rack.input' + RACK_SESSION = 'rack.session' + RACK_SESSION_OPTIONS = 'rack.session.options' + RACK_SHOWSTATUS_DETAIL = 'rack.showstatus.detail' + RACK_MULTITHREAD = 'rack.multithread' + RACK_MULTIPROCESS = 'rack.multiprocess' + RACK_RUNONCE = 'rack.run_once' + RACK_URL_SCHEME = 'rack.url_scheme' + RACK_HIJACK = 'rack.hijack' + RACK_IS_HIJACK = 'rack.hijack?' + RACK_HIJACK_IO = 'rack.hijack_io' + RACK_RECURSIVE_INCLUDE = 'rack.recursive.include' + RACK_MULTIPART_BUFFER_SIZE = 'rack.multipart.buffer_size' + RACK_MULTIPART_TEMPFILE_FACTORY = 'rack.multipart.tempfile_factory' + RACK_REQUEST_FORM_INPUT = 'rack.request.form_input' + RACK_REQUEST_FORM_HASH = 'rack.request.form_hash' + RACK_REQUEST_FORM_VARS = 'rack.request.form_vars' + RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash' + RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string' + RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash' + RACK_REQUEST_QUERY_STRING = 'rack.request.query_string' + RACK_METHODOVERRIDE_ORIGINAL_METHOD = 'rack.methodoverride.original_method' + RACK_SESSION_UNPACKED_COOKIE_DATA = 'rack.session.unpacked_cookie_data' + + autoload :Builder, "rack/builder" + autoload :BodyProxy, "rack/body_proxy" + autoload :Cascade, "rack/cascade" + autoload :Chunked, "rack/chunked" + autoload :CommonLogger, "rack/common_logger" + autoload :ConditionalGet, "rack/conditional_get" + autoload :Config, "rack/config" + autoload :ContentLength, "rack/content_length" + autoload :ContentType, "rack/content_type" + autoload :ETag, "rack/etag" + autoload :Events, "rack/events" + autoload :File, "rack/file" + autoload :Files, "rack/files" + autoload :Deflater, "rack/deflater" + autoload :Directory, "rack/directory" + autoload :ForwardRequest, "rack/recursive" + autoload :Handler, "rack/handler" + autoload :Head, "rack/head" + autoload :Lint, "rack/lint" + autoload :Lock, "rack/lock" + autoload :Logger, "rack/logger" + autoload :MediaType, "rack/media_type" + autoload :MethodOverride, "rack/method_override" + autoload :Mime, "rack/mime" + autoload :NullLogger, "rack/null_logger" + autoload :Recursive, "rack/recursive" + autoload :Reloader, "rack/reloader" + autoload :RewindableInput, "rack/rewindable_input" + autoload :Runtime, "rack/runtime" + autoload :Sendfile, "rack/sendfile" + autoload :Server, "rack/server" + autoload :ShowExceptions, "rack/show_exceptions" + autoload :ShowStatus, "rack/show_status" + autoload :Static, "rack/static" + autoload :TempfileReaper, "rack/tempfile_reaper" + autoload :URLMap, "rack/urlmap" + autoload :Utils, "rack/utils" + autoload :Multipart, "rack/multipart" + + autoload :MockRequest, "rack/mock" + autoload :MockResponse, "rack/mock" + + autoload :Request, "rack/request" + autoload :Response, "rack/response" + + module Auth + autoload :Basic, "rack/auth/basic" + autoload :AbstractRequest, "rack/auth/abstract/request" + autoload :AbstractHandler, "rack/auth/abstract/handler" + module Digest + autoload :MD5, "rack/auth/digest/md5" + autoload :Nonce, "rack/auth/digest/nonce" + autoload :Params, "rack/auth/digest/params" + autoload :Request, "rack/auth/digest/request" + end + end + + module Session + autoload :Cookie, "rack/session/cookie" + autoload :Pool, "rack/session/pool" + autoload :Memcache, "rack/session/memcache" + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/abstract/handler.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/abstract/handler.rb new file mode 100644 index 0000000000..3ed87091c7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/abstract/handler.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Rack + module Auth + # Rack::Auth::AbstractHandler implements common authentication functionality. + # + # +realm+ should be set for all handlers. + + class AbstractHandler + + attr_accessor :realm + + def initialize(app, realm = nil, &authenticator) + @app, @realm, @authenticator = app, realm, authenticator + end + + + private + + def unauthorized(www_authenticate = challenge) + return [ 401, + { CONTENT_TYPE => 'text/plain', + CONTENT_LENGTH => '0', + 'WWW-Authenticate' => www_authenticate.to_s }, + [] + ] + end + + def bad_request + return [ 400, + { CONTENT_TYPE => 'text/plain', + CONTENT_LENGTH => '0' }, + [] + ] + end + + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/abstract/request.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/abstract/request.rb new file mode 100644 index 0000000000..34042c401b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/abstract/request.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Rack + module Auth + class AbstractRequest + + def initialize(env) + @env = env + end + + def request + @request ||= Request.new(@env) + end + + def provided? + !authorization_key.nil? && valid? + end + + def valid? + !@env[authorization_key].nil? + end + + def parts + @parts ||= @env[authorization_key].split(' ', 2) + end + + def scheme + @scheme ||= parts.first && parts.first.downcase + end + + def params + @params ||= parts.last + end + + + private + + AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION'] + + def authorization_key + @authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) } + end + + end + + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/basic.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/basic.rb new file mode 100644 index 0000000000..d5b4ea16da --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/basic.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require_relative 'abstract/handler' +require_relative 'abstract/request' +require 'base64' + +module Rack + module Auth + # Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617. + # + # Initialize with the Rack application that you want protecting, + # and a block that checks if a username and password pair are valid. + # + # See also: example/protectedlobster.rb + + class Basic < AbstractHandler + + def call(env) + auth = Basic::Request.new(env) + + return unauthorized unless auth.provided? + + return bad_request unless auth.basic? + + if valid?(auth) + env['REMOTE_USER'] = auth.username + + return @app.call(env) + end + + unauthorized + end + + + private + + def challenge + 'Basic realm="%s"' % realm + end + + def valid?(auth) + @authenticator.call(*auth.credentials) + end + + class Request < Auth::AbstractRequest + def basic? + "basic" == scheme && credentials.length == 2 + end + + def credentials + @credentials ||= Base64.decode64(params).split(':', 2) + end + + def username + credentials.first + end + end + + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/md5.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/md5.rb new file mode 100644 index 0000000000..04b103e258 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/md5.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +require_relative '../abstract/handler' +require_relative 'request' +require_relative 'params' +require_relative 'nonce' +require 'digest/md5' + +module Rack + module Auth + module Digest + # Rack::Auth::Digest::MD5 implements the MD5 algorithm version of + # HTTP Digest Authentication, as per RFC 2617. + # + # Initialize with the [Rack] application that you want protecting, + # and a block that looks up a plaintext password for a given username. + # + # +opaque+ needs to be set to a constant base64/hexadecimal string. + # + class MD5 < AbstractHandler + + attr_accessor :opaque + + attr_writer :passwords_hashed + + def initialize(app, realm = nil, opaque = nil, &authenticator) + @passwords_hashed = nil + if opaque.nil? and realm.respond_to? :values_at + realm, opaque, @passwords_hashed = realm.values_at :realm, :opaque, :passwords_hashed + end + super(app, realm, &authenticator) + @opaque = opaque + end + + def passwords_hashed? + !!@passwords_hashed + end + + def call(env) + auth = Request.new(env) + + unless auth.provided? + return unauthorized + end + + if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth) + return bad_request + end + + if valid?(auth) + if auth.nonce.stale? + return unauthorized(challenge(stale: true)) + else + env['REMOTE_USER'] = auth.username + + return @app.call(env) + end + end + + unauthorized + end + + + private + + QOP = 'auth' + + def params(hash = {}) + Params.new do |params| + params['realm'] = realm + params['nonce'] = Nonce.new.to_s + params['opaque'] = H(opaque) + params['qop'] = QOP + + hash.each { |k, v| params[k] = v } + end + end + + def challenge(hash = {}) + "Digest #{params(hash)}" + end + + def valid?(auth) + valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth) + end + + def valid_qop?(auth) + QOP == auth.qop + end + + def valid_opaque?(auth) + H(opaque) == auth.opaque + end + + def valid_nonce?(auth) + auth.nonce.valid? + end + + def valid_digest?(auth) + pw = @authenticator.call(auth.username) + pw && Rack::Utils.secure_compare(digest(auth, pw), auth.response) + end + + def md5(data) + ::Digest::MD5.hexdigest(data) + end + + alias :H :md5 + + def KD(secret, data) + H "#{secret}:#{data}" + end + + def A1(auth, password) + "#{auth.username}:#{auth.realm}:#{password}" + end + + def A2(auth) + "#{auth.method}:#{auth.uri}" + end + + def digest(auth, password) + password_hash = passwords_hashed? ? password : H(A1(auth, password)) + + KD password_hash, "#{auth.nonce}:#{auth.nc}:#{auth.cnonce}:#{QOP}:#{H A2(auth)}" + end + + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/nonce.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/nonce.rb new file mode 100644 index 0000000000..3216d973e0 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/nonce.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'digest/md5' +require 'base64' + +module Rack + module Auth + module Digest + # Rack::Auth::Digest::Nonce is the default nonce generator for the + # Rack::Auth::Digest::MD5 authentication handler. + # + # +private_key+ needs to set to a constant string. + # + # +time_limit+ can be optionally set to an integer (number of seconds), + # to limit the validity of the generated nonces. + + class Nonce + + class << self + attr_accessor :private_key, :time_limit + end + + def self.parse(string) + new(*Base64.decode64(string).split(' ', 2)) + end + + def initialize(timestamp = Time.now, given_digest = nil) + @timestamp, @given_digest = timestamp.to_i, given_digest + end + + def to_s + Base64.encode64("#{@timestamp} #{digest}").strip + end + + def digest + ::Digest::MD5.hexdigest("#{@timestamp}:#{self.class.private_key}") + end + + def valid? + digest == @given_digest + end + + def stale? + !self.class.time_limit.nil? && (Time.now.to_i - @timestamp) > self.class.time_limit + end + + def fresh? + !stale? + end + + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/params.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/params.rb new file mode 100644 index 0000000000..f611b3c35e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/params.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Rack + module Auth + module Digest + class Params < Hash + + def self.parse(str) + Params[*split_header_value(str).map do |param| + k, v = param.split('=', 2) + [k, dequote(v)] + end.flatten] + end + + def self.dequote(str) # From WEBrick::HTTPUtils + ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup + ret.gsub!(/\\(.)/, "\\1") + ret + end + + def self.split_header_value(str) + str.scan(/\w+\=(?:"[^\"]+"|[^,]+)/n) + end + + def initialize + super() + + yield self if block_given? + end + + def [](k) + super k.to_s + end + + def []=(k, v) + super k.to_s, v.to_s + end + + UNQUOTED = ['nc', 'stale'] + + def to_s + map do |k, v| + "#{k}=#{(UNQUOTED.include?(k) ? v.to_s : quote(v))}" + end.join(', ') + end + + def quote(str) # From WEBrick::HTTPUtils + '"' + str.gsub(/[\\\"]/o, "\\\1") + '"' + end + + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/request.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/request.rb new file mode 100644 index 0000000000..7b89b76052 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/auth/digest/request.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require_relative '../abstract/request' +require_relative 'params' +require_relative 'nonce' + +module Rack + module Auth + module Digest + class Request < Auth::AbstractRequest + def method + @env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] || @env[REQUEST_METHOD] + end + + def digest? + "digest" == scheme + end + + def correct_uri? + request.fullpath == uri + end + + def nonce + @nonce ||= Nonce.parse(params['nonce']) + end + + def params + @params ||= Params.parse(parts.last) + end + + def respond_to?(sym, *) + super or params.has_key? sym.to_s + end + + def method_missing(sym, *args) + return super unless params.has_key?(key = sym.to_s) + return params[key] if args.size == 0 + raise ArgumentError, "wrong number of arguments (#{args.size} for 0)" + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/body_proxy.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/body_proxy.rb new file mode 100644 index 0000000000..cfc0796a61 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/body_proxy.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Rack + # Proxy for response bodies allowing calling a block when + # the response body is closed (after the response has been fully + # sent to the client). + class BodyProxy + # Set the response body to wrap, and the block to call when the + # response has been fully sent. + def initialize(body, &block) + @body = body + @block = block + @closed = false + end + + # Return whether the wrapped body responds to the method. + def respond_to_missing?(method_name, include_all = false) + super or @body.respond_to?(method_name, include_all) + end + + # If not already closed, close the wrapped body and + # then call the block the proxy was initialized with. + def close + return if @closed + @closed = true + begin + @body.close if @body.respond_to? :close + ensure + @block.call + end + end + + # Whether the proxy is closed. The proxy starts as not closed, + # and becomes closed on the first call to close. + def closed? + @closed + end + + # Delegate missing methods to the wrapped body. + def method_missing(method_name, *args, &block) + @body.__send__(method_name, *args, &block) + end + ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/builder.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/builder.rb new file mode 100644 index 0000000000..816ecf6208 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/builder.rb @@ -0,0 +1,257 @@ +# frozen_string_literal: true + +module Rack + # Rack::Builder implements a small DSL to iteratively construct Rack + # applications. + # + # Example: + # + # require 'rack/lobster' + # app = Rack::Builder.new do + # use Rack::CommonLogger + # use Rack::ShowExceptions + # map "/lobster" do + # use Rack::Lint + # run Rack::Lobster.new + # end + # end + # + # run app + # + # Or + # + # app = Rack::Builder.app do + # use Rack::CommonLogger + # run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['OK']] } + # end + # + # run app + # + # +use+ adds middleware to the stack, +run+ dispatches to an application. + # You can use +map+ to construct a Rack::URLMap in a convenient way. + + class Builder + + # https://stackoverflow.com/questions/2223882/whats-the-difference-between-utf-8-and-utf-8-without-bom + UTF_8_BOM = '\xef\xbb\xbf' + + # Parse the given config file to get a Rack application. + # + # If the config file ends in +.ru+, it is treated as a + # rackup file and the contents will be treated as if + # specified inside a Rack::Builder block, using the given + # options. + # + # If the config file does not end in +.ru+, it is + # required and Rack will use the basename of the file + # to guess which constant will be the Rack application to run. + # The options given will be ignored in this case. + # + # Examples: + # + # Rack::Builder.parse_file('config.ru') + # # Rack application built using Rack::Builder.new + # + # Rack::Builder.parse_file('app.rb') + # # requires app.rb, which can be anywhere in Ruby's + # # load path. After requiring, assumes App constant + # # contains Rack application + # + # Rack::Builder.parse_file('./my_app.rb') + # # requires ./my_app.rb, which should be in the + # # process's current directory. After requiring, + # # assumes MyApp constant contains Rack application + def self.parse_file(config, opts = Server::Options.new) + if config.end_with?('.ru') + return self.load_file(config, opts) + else + require config + app = Object.const_get(::File.basename(config, '.rb').split('_').map(&:capitalize).join('')) + return app, {} + end + end + + # Load the given file as a rackup file, treating the + # contents as if specified inside a Rack::Builder block. + # + # Treats the first comment at the beginning of a line + # that starts with a backslash as options similar to + # options passed on a rackup command line. + # + # Ignores content in the file after +__END__+, so that + # use of +__END__+ will not result in a syntax error. + # + # Example config.ru file: + # + # $ cat config.ru + # + # #\ -p 9393 + # + # use Rack::ContentLength + # require './app.rb' + # run App + def self.load_file(path, opts = Server::Options.new) + options = {} + + cfgfile = ::File.read(path) + cfgfile.slice!(/\A#{UTF_8_BOM}/) if cfgfile.encoding == Encoding::UTF_8 + + if cfgfile[/^#\\(.*)/] && opts + warn "Parsing options from the first comment line is deprecated!" + options = opts.parse! $1.split(/\s+/) + end + + cfgfile.sub!(/^__END__\n.*\Z/m, '') + app = new_from_string cfgfile, path + + return app, options + end + + # Evaluate the given +builder_script+ string in the context of + # a Rack::Builder block, returning a Rack application. + def self.new_from_string(builder_script, file = "(rackup)") + # We want to build a variant of TOPLEVEL_BINDING with self as a Rack::Builder instance. + # We cannot use instance_eval(String) as that would resolve constants differently. + binding, builder = TOPLEVEL_BINDING.eval('Rack::Builder.new.instance_eval { [binding, self] }') + eval builder_script, binding, file + builder.to_app + end + + # Initialize a new Rack::Builder instance. +default_app+ specifies the + # default application if +run+ is not called later. If a block + # is given, it is evaluted in the context of the instance. + def initialize(default_app = nil, &block) + @use, @map, @run, @warmup, @freeze_app = [], nil, default_app, nil, false + instance_eval(&block) if block_given? + end + + # Create a new Rack::Builder instance and return the Rack application + # generated from it. + def self.app(default_app = nil, &block) + self.new(default_app, &block).to_app + end + + # Specifies middleware to use in a stack. + # + # class Middleware + # def initialize(app) + # @app = app + # end + # + # def call(env) + # env["rack.some_header"] = "setting an example" + # @app.call(env) + # end + # end + # + # use Middleware + # run lambda { |env| [200, { "Content-Type" => "text/plain" }, ["OK"]] } + # + # All requests through to this application will first be processed by the middleware class. + # The +call+ method in this example sets an additional environment key which then can be + # referenced in the application if required. + def use(middleware, *args, &block) + if @map + mapping, @map = @map, nil + @use << proc { |app| generate_map(app, mapping) } + end + @use << proc { |app| middleware.new(app, *args, &block) } + end + ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true) + + # Takes an argument that is an object that responds to #call and returns a Rack response. + # The simplest form of this is a lambda object: + # + # run lambda { |env| [200, { "Content-Type" => "text/plain" }, ["OK"]] } + # + # However this could also be a class: + # + # class Heartbeat + # def self.call(env) + # [200, { "Content-Type" => "text/plain" }, ["OK"]] + # end + # end + # + # run Heartbeat + def run(app) + @run = app + end + + # Takes a lambda or block that is used to warm-up the application. This block is called + # before the Rack application is returned by to_app. + # + # warmup do |app| + # client = Rack::MockRequest.new(app) + # client.get('/') + # end + # + # use SomeMiddleware + # run MyApp + def warmup(prc = nil, &block) + @warmup = prc || block + end + + # Creates a route within the application. Routes under the mapped path will be sent to + # the Rack application specified by run inside the block. Other requests will be sent to the + # default application specified by run outside the block. + # + # Rack::Builder.app do + # map '/heartbeat' do + # run Heartbeat + # end + # run App + # end + # + # The +use+ method can also be used inside the block to specify middleware to run under a specific path: + # + # Rack::Builder.app do + # map '/heartbeat' do + # use Middleware + # run Heartbeat + # end + # run App + # end + # + # This example includes a piece of middleware which will run before +/heartbeat+ requests hit +Heartbeat+. + # + # Note that providing a +path+ of +/+ will ignore any default application given in a +run+ statement + # outside the block. + def map(path, &block) + @map ||= {} + @map[path] = block + end + + # Freeze the app (set using run) and all middleware instances when building the application + # in to_app. + def freeze_app + @freeze_app = true + end + + # Return the Rack application generated by this instance. + def to_app + app = @map ? generate_map(@run, @map) : @run + fail "missing run or map statement" unless app + app.freeze if @freeze_app + app = @use.reverse.inject(app) { |a, e| e[a].tap { |x| x.freeze if @freeze_app } } + @warmup.call(app) if @warmup + app + end + + # Call the Rack application generated by this builder instance. Note that + # this rebuilds the Rack application and runs the warmup code (if any) + # every time it is called, so it should not be used if performance is important. + def call(env) + to_app.call(env) + end + + private + + # Generate a URLMap instance by generating new Rack applications for each + # map block in this instance. + def generate_map(default_app, mapping) + mapped = default_app ? { '/' => default_app } : {} + mapping.each { |r, b| mapped[r] = self.class.new(default_app, &b).to_app } + URLMap.new(mapped) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/cascade.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/cascade.rb new file mode 100644 index 0000000000..d71274c2b7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/cascade.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +module Rack + # Rack::Cascade tries a request on several apps, and returns the + # first response that is not 404 or 405 (or in a list of configured + # status codes). If all applications tried return one of the configured + # status codes, return the last response. + + class Cascade + # deprecated, no longer used + NotFound = [404, { CONTENT_TYPE => "text/plain" }, []] + + # An array of applications to try in order. + attr_reader :apps + + # Set the apps to send requests to, and what statuses result in + # cascading. Arguments: + # + # apps: An enumerable of rack applications. + # cascade_for: The statuses to use cascading for. If a response is received + # from an app, the next app is tried. + def initialize(apps, cascade_for = [404, 405]) + @apps = [] + apps.each { |app| add app } + + @cascade_for = {} + [*cascade_for].each { |status| @cascade_for[status] = true } + end + + # Call each app in order. If the responses uses a status that requires + # cascading, try the next app. If all responses require cascading, + # return the response from the last app. + def call(env) + return [404, { CONTENT_TYPE => "text/plain" }, []] if @apps.empty? + result = nil + last_body = nil + + @apps.each do |app| + # The SPEC says that the body must be closed after it has been iterated + # by the server, or if it is replaced by a middleware action. Cascade + # replaces the body each time a cascade happens. It is assumed that nil + # does not respond to close, otherwise the previous application body + # will be closed. The final application body will not be closed, as it + # will be passed to the server as a result. + last_body.close if last_body.respond_to? :close + + result = app.call(env) + return result unless @cascade_for.include?(result[0].to_i) + last_body = result[2] + end + + result + end + + # Append an app to the list of apps to cascade. This app will + # be tried last. + def add(app) + @apps << app + end + + # Whether the given app is one of the apps to cascade to. + def include?(app) + @apps.include?(app) + end + + alias_method :<<, :add + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/chunked.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/chunked.rb new file mode 100644 index 0000000000..84c6600140 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/chunked.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +module Rack + + # Middleware that applies chunked transfer encoding to response bodies + # when the response does not include a Content-Length header. + # + # This supports the Trailer response header to allow the use of trailing + # headers in the chunked encoding. However, using this requires you manually + # specify a response body that supports a +trailers+ method. Example: + # + # [200, { 'Trailer' => 'Expires'}, ["Hello", "World"]] + # # error raised + # + # body = ["Hello", "World"] + # def body.trailers + # { 'Expires' => Time.now.to_s } + # end + # [200, { 'Trailer' => 'Expires'}, body] + # # No exception raised + class Chunked + include Rack::Utils + + # A body wrapper that emits chunked responses. + class Body + TERM = "\r\n" + TAIL = "0#{TERM}" + + # Store the response body to be chunked. + def initialize(body) + @body = body + end + + # For each element yielded by the response body, yield + # the element in chunked encoding. + def each(&block) + term = TERM + @body.each do |chunk| + size = chunk.bytesize + next if size == 0 + + yield [size.to_s(16), term, chunk.b, term].join + end + yield TAIL + yield_trailers(&block) + yield term + end + + # Close the response body if the response body supports it. + def close + @body.close if @body.respond_to?(:close) + end + + private + + # Do nothing as this class does not support trailer headers. + def yield_trailers + end + end + + # A body wrapper that emits chunked responses and also supports + # sending Trailer headers. Note that the response body provided to + # initialize must have a +trailers+ method that returns a hash + # of trailer headers, and the rack response itself should have a + # Trailer header listing the headers that the +trailers+ method + # will return. + class TrailerBody < Body + private + + # Yield strings for each trailer header. + def yield_trailers + @body.trailers.each_pair do |k, v| + yield "#{k}: #{v}\r\n" + end + end + end + + def initialize(app) + @app = app + end + + # Whether the HTTP version supports chunked encoding (HTTP 1.1 does). + def chunkable_version?(ver) + case ver + # pre-HTTP/1.0 (informally "HTTP/0.9") HTTP requests did not have + # a version (nor response headers) + when 'HTTP/1.0', nil, 'HTTP/0.9' + false + else + true + end + end + + # If the rack app returns a response that should have a body, + # but does not have Content-Length or Transfer-Encoding headers, + # modify the response to use chunked Transfer-Encoding. + def call(env) + status, headers, body = @app.call(env) + headers = HeaderHash[headers] + + if chunkable_version?(env[SERVER_PROTOCOL]) && + !STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) && + !headers[CONTENT_LENGTH] && + !headers[TRANSFER_ENCODING] + + headers[TRANSFER_ENCODING] = 'chunked' + if headers['Trailer'] + body = TrailerBody.new(body) + else + body = Body.new(body) + end + end + + [status, headers, body] + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/common_logger.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/common_logger.rb new file mode 100644 index 0000000000..3810b26931 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/common_logger.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +module Rack + # Rack::CommonLogger forwards every request to the given +app+, and + # logs a line in the + # {Apache common log format}[http://httpd.apache.org/docs/1.3/logs.html#common] + # to the configured logger. + class CommonLogger + # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common + # + # lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 - + # + # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % + # + # The actual format is slightly different than the above due to the + # separation of SCRIPT_NAME and PATH_INFO, and because the elapsed + # time in seconds is included at the end. + FORMAT = %{%s - %s [%s] "%s %s%s%s %s" %d %s %0.4f\n} + + # +logger+ can be any object that supports the +write+ or +<<+ methods, + # which includes the standard library Logger. These methods are called + # with a single string argument, the log message. + # If +logger+ is nil, CommonLogger will fall back env['rack.errors']. + def initialize(app, logger = nil) + @app = app + @logger = logger + end + + # Log all requests in common_log format after a response has been + # returned. Note that if the app raises an exception, the request + # will not be logged, so if exception handling middleware are used, + # they should be loaded after this middleware. Additionally, because + # the logging happens after the request body has been fully sent, any + # exceptions raised during the sending of the response body will + # cause the request not to be logged. + def call(env) + began_at = Utils.clock_time + status, headers, body = @app.call(env) + headers = Utils::HeaderHash[headers] + body = BodyProxy.new(body) { log(env, status, headers, began_at) } + [status, headers, body] + end + + private + + # Log the request to the configured logger. + def log(env, status, header, began_at) + length = extract_content_length(header) + + msg = FORMAT % [ + env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-", + env["REMOTE_USER"] || "-", + Time.now.strftime("%d/%b/%Y:%H:%M:%S %z"), + env[REQUEST_METHOD], + env[SCRIPT_NAME], + env[PATH_INFO], + env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}", + env[SERVER_PROTOCOL], + status.to_s[0..3], + length, + Utils.clock_time - began_at ] + + logger = @logger || env[RACK_ERRORS] + # Standard library logger doesn't support write but it supports << which actually + # calls to write on the log device without formatting + if logger.respond_to?(:write) + logger.write(msg) + else + logger << msg + end + end + + # Attempt to determine the content length for the response to + # include it in the logged data. + def extract_content_length(headers) + value = headers[CONTENT_LENGTH] + !value || value.to_s == '0' ? '-' : value + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/conditional_get.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/conditional_get.rb new file mode 100644 index 0000000000..7b7808ac1f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/conditional_get.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +module Rack + + # Middleware that enables conditional GET using If-None-Match and + # If-Modified-Since. The application should set either or both of the + # Last-Modified or Etag response headers according to RFC 2616. When + # either of the conditions is met, the response body is set to be zero + # length and the response status is set to 304 Not Modified. + # + # Applications that defer response body generation until the body's each + # message is received will avoid response body generation completely when + # a conditional GET matches. + # + # Adapted from Michael Klishin's Merb implementation: + # https://github.com/wycats/merb/blob/master/merb-core/lib/merb-core/rack/middleware/conditional_get.rb + class ConditionalGet + def initialize(app) + @app = app + end + + # Return empty 304 response if the response has not been + # modified since the last request. + def call(env) + case env[REQUEST_METHOD] + when "GET", "HEAD" + status, headers, body = @app.call(env) + headers = Utils::HeaderHash[headers] + if status == 200 && fresh?(env, headers) + status = 304 + headers.delete(CONTENT_TYPE) + headers.delete(CONTENT_LENGTH) + original_body = body + body = Rack::BodyProxy.new([]) do + original_body.close if original_body.respond_to?(:close) + end + end + [status, headers, body] + else + @app.call(env) + end + end + + private + + # Return whether the response has not been modified since the + # last request. + def fresh?(env, headers) + # If-None-Match has priority over If-Modified-Since per RFC 7232 + if none_match = env['HTTP_IF_NONE_MATCH'] + etag_matches?(none_match, headers) + elsif (modified_since = env['HTTP_IF_MODIFIED_SINCE']) && (modified_since = to_rfc2822(modified_since)) + modified_since?(modified_since, headers) + end + end + + # Whether the ETag response header matches the If-None-Match request header. + # If so, the request has not been modified. + def etag_matches?(none_match, headers) + headers['ETag'] == none_match + end + + # Whether the Last-Modified response header matches the If-Modified-Since + # request header. If so, the request has not been modified. + def modified_since?(modified_since, headers) + last_modified = to_rfc2822(headers['Last-Modified']) and + modified_since >= last_modified + end + + # Return a Time object for the given string (which should be in RFC2822 + # format), or nil if the string cannot be parsed. + def to_rfc2822(since) + # shortest possible valid date is the obsolete: 1 Nov 97 09:55 A + # anything shorter is invalid, this avoids exceptions for common cases + # most common being the empty string + if since && since.length >= 16 + # NOTE: there is no trivial way to write this in a non exception way + # _rfc2822 returns a hash but is not that usable + Time.rfc2822(since) rescue nil + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/config.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/config.rb new file mode 100644 index 0000000000..41f6f7dd57 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/config.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Rack + # Rack::Config modifies the environment using the block given during + # initialization. + # + # Example: + # use Rack::Config do |env| + # env['my-key'] = 'some-value' + # end + class Config + def initialize(app, &block) + @app = app + @block = block + end + + def call(env) + @block.call(env) + @app.call(env) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/content_length.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/content_length.rb new file mode 100644 index 0000000000..9e2b5fc42a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/content_length.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Rack + + # Sets the Content-Length header on responses that do not specify + # a Content-Length or Transfer-Encoding header. Note that this + # does not fix responses that have an invalid Content-Length + # header specified. + class ContentLength + include Rack::Utils + + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + headers = HeaderHash[headers] + + if !STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) && + !headers[CONTENT_LENGTH] && + !headers[TRANSFER_ENCODING] + + obody = body + body, length = [], 0 + obody.each { |part| body << part; length += part.bytesize } + + body = BodyProxy.new(body) do + obody.close if obody.respond_to?(:close) + end + + headers[CONTENT_LENGTH] = length.to_s + end + + [status, headers, body] + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/content_type.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/content_type.rb new file mode 100644 index 0000000000..503f707062 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/content_type.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Rack + + # Sets the Content-Type header on responses which don't have one. + # + # Builder Usage: + # use Rack::ContentType, "text/plain" + # + # When no content type argument is provided, "text/html" is the + # default. + class ContentType + include Rack::Utils + + def initialize(app, content_type = "text/html") + @app, @content_type = app, content_type + end + + def call(env) + status, headers, body = @app.call(env) + headers = Utils::HeaderHash[headers] + + unless STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) + headers[CONTENT_TYPE] ||= @content_type + end + + [status, headers, body] + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/core_ext/regexp.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/core_ext/regexp.rb new file mode 100644 index 0000000000..a32fcdf629 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/core_ext/regexp.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Regexp has `match?` since Ruby 2.4 +# so to support Ruby < 2.4 we need to define this method + +module Rack + module RegexpExtensions + refine Regexp do + def match?(string, pos = 0) + !!match(string, pos) + end + end unless //.respond_to?(:match?) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/deflater.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/deflater.rb new file mode 100644 index 0000000000..e177fabb01 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/deflater.rb @@ -0,0 +1,144 @@ +# frozen_string_literal: true + +require "zlib" +require "time" # for Time.httpdate + +module Rack + # This middleware enables content encoding of http responses, + # usually for purposes of compression. + # + # Currently supported encodings: + # + # * gzip + # * identity (no transformation) + # + # This middleware automatically detects when encoding is supported + # and allowed. For example no encoding is made when a cache + # directive of 'no-transform' is present, when the response status + # code is one that doesn't allow an entity body, or when the body + # is empty. + # + # Note that despite the name, Deflater does not support the +deflate+ + # encoding. + class Deflater + (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4' + + # Creates Rack::Deflater middleware. Options: + # + # :if :: a lambda enabling / disabling deflation based on returned boolean value + # (e.g use Rack::Deflater, :if => lambda { |*, body| sum=0; body.each { |i| sum += i.length }; sum > 512 }). + # However, be aware that calling `body.each` inside the block will break cases where `body.each` is not idempotent, + # such as when it is an +IO+ instance. + # :include :: a list of content types that should be compressed. By default, all content types are compressed. + # :sync :: determines if the stream is going to be flushed after every chunk. Flushing after every chunk reduces + # latency for time-sensitive streaming applications, but hurts compression and throughput. + # Defaults to +true+. + def initialize(app, options = {}) + @app = app + @condition = options[:if] + @compressible_types = options[:include] + @sync = options.fetch(:sync, true) + end + + def call(env) + status, headers, body = @app.call(env) + headers = Utils::HeaderHash[headers] + + unless should_deflate?(env, status, headers, body) + return [status, headers, body] + end + + request = Request.new(env) + + encoding = Utils.select_best_encoding(%w(gzip identity), + request.accept_encoding) + + # Set the Vary HTTP header. + vary = headers["Vary"].to_s.split(",").map(&:strip) + unless vary.include?("*") || vary.include?("Accept-Encoding") + headers["Vary"] = vary.push("Accept-Encoding").join(",") + end + + case encoding + when "gzip" + headers['Content-Encoding'] = "gzip" + headers.delete(CONTENT_LENGTH) + mtime = headers["Last-Modified"] + mtime = Time.httpdate(mtime).to_i if mtime + [status, headers, GzipStream.new(body, mtime, @sync)] + when "identity" + [status, headers, body] + when nil + message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found." + bp = Rack::BodyProxy.new([message]) { body.close if body.respond_to?(:close) } + [406, { CONTENT_TYPE => "text/plain", CONTENT_LENGTH => message.length.to_s }, bp] + end + end + + # Body class used for gzip encoded responses. + class GzipStream + # Initialize the gzip stream. Arguments: + # body :: Response body to compress with gzip + # mtime :: The modification time of the body, used to set the + # modification time in the gzip header. + # sync :: Whether to flush each gzip chunk as soon as it is ready. + def initialize(body, mtime, sync) + @body = body + @mtime = mtime + @sync = sync + end + + # Yield gzip compressed strings to the given block. + def each(&block) + @writer = block + gzip = ::Zlib::GzipWriter.new(self) + gzip.mtime = @mtime if @mtime + @body.each { |part| + # Skip empty strings, as they would result in no output, + # and flushing empty parts would raise Zlib::BufError. + next if part.empty? + + gzip.write(part) + gzip.flush if @sync + } + ensure + gzip.close + end + + # Call the block passed to #each with the the gzipped data. + def write(data) + @writer.call(data) + end + + # Close the original body if possible. + def close + @body.close if @body.respond_to?(:close) + end + end + + private + + # Whether the body should be compressed. + def should_deflate?(env, status, headers, body) + # Skip compressing empty entity body responses and responses with + # no-transform set. + if Utils::STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) || + /\bno-transform\b/.match?(headers['Cache-Control'].to_s) || + headers['Content-Encoding']&.!~(/\bidentity\b/) + return false + end + + # Skip if @compressible_types are given and does not include request's content type + return false if @compressible_types && !(headers.has_key?('Content-Type') && @compressible_types.include?(headers['Content-Type'][/[^;]*/])) + + # Skip if @condition lambda is given and evaluates to false + return false if @condition && !@condition.call(env, status, headers, body) + + # No point in compressing empty body, also handles usage with + # Rack::Sendfile. + return false if headers[CONTENT_LENGTH] == '0' + + true + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/directory.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/directory.rb new file mode 100644 index 0000000000..be72be0144 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/directory.rb @@ -0,0 +1,199 @@ +# frozen_string_literal: true + +require 'time' + +module Rack + # Rack::Directory serves entries below the +root+ given, according to the + # path info of the Rack request. If a directory is found, the file's contents + # will be presented in an html based index. If a file is found, the env will + # be passed to the specified +app+. + # + # If +app+ is not specified, a Rack::Files of the same +root+ will be used. + + class Directory + DIR_FILE = "%s%s%s%s\n" + DIR_PAGE_HEADER = <<-PAGE + + %s + + + +

%s

+
+ + + + + + + + PAGE + DIR_PAGE_FOOTER = <<-PAGE +
NameSizeTypeLast Modified
+
+ + PAGE + + # Body class for directory entries, showing an index page with links + # to each file. + class DirectoryBody < Struct.new(:root, :path, :files) + # Yield strings for each part of the directory entry + def each + show_path = Utils.escape_html(path.sub(/^#{root}/, '')) + yield(DIR_PAGE_HEADER % [ show_path, show_path ]) + + unless path.chomp('/') == root + yield(DIR_FILE % DIR_FILE_escape(files.call('..'))) + end + + Dir.foreach(path) do |basename| + next if basename.start_with?('.') + next unless f = files.call(basename) + yield(DIR_FILE % DIR_FILE_escape(f)) + end + + yield(DIR_PAGE_FOOTER) + end + + private + + # Escape each element in the array of html strings. + def DIR_FILE_escape(htmls) + htmls.map { |e| Utils.escape_html(e) } + end + end + + # The root of the directory hierarchy. Only requests for files and + # directories inside of the root directory are supported. + attr_reader :root + + # Set the root directory and application for serving files. + def initialize(root, app = nil) + @root = ::File.expand_path(root) + @app = app || Files.new(@root) + @head = Head.new(method(:get)) + end + + def call(env) + # strip body if this is a HEAD call + @head.call env + end + + # Internals of request handling. Similar to call but does + # not remove body for HEAD requests. + def get(env) + script_name = env[SCRIPT_NAME] + path_info = Utils.unescape_path(env[PATH_INFO]) + + if client_error_response = check_bad_request(path_info) || check_forbidden(path_info) + client_error_response + else + path = ::File.join(@root, path_info) + list_path(env, path, path_info, script_name) + end + end + + # Rack response to use for requests with invalid paths, or nil if path is valid. + def check_bad_request(path_info) + return if Utils.valid_path?(path_info) + + body = "Bad Request\n" + [400, { CONTENT_TYPE => "text/plain", + CONTENT_LENGTH => body.bytesize.to_s, + "X-Cascade" => "pass" }, [body]] + end + + # Rack response to use for requests with paths outside the root, or nil if path is inside the root. + def check_forbidden(path_info) + return unless path_info.include? ".." + return if ::File.expand_path(::File.join(@root, path_info)).start_with?(@root) + + body = "Forbidden\n" + [403, { CONTENT_TYPE => "text/plain", + CONTENT_LENGTH => body.bytesize.to_s, + "X-Cascade" => "pass" }, [body]] + end + + # Rack response to use for directories under the root. + def list_directory(path_info, path, script_name) + url_head = (script_name.split('/') + path_info.split('/')).map do |part| + Utils.escape_path part + end + + # Globbing not safe as path could contain glob metacharacters + body = DirectoryBody.new(@root, path, ->(basename) do + stat = stat(::File.join(path, basename)) + next unless stat + + url = ::File.join(*url_head + [Utils.escape_path(basename)]) + mtime = stat.mtime.httpdate + if stat.directory? + type = 'directory' + size = '-' + url << '/' + if basename == '..' + basename = 'Parent Directory' + else + basename << '/' + end + else + type = Mime.mime_type(::File.extname(basename)) + size = filesize_format(stat.size) + end + + [ url, basename, size, type, mtime ] + end) + + [ 200, { CONTENT_TYPE => 'text/html; charset=utf-8' }, body ] + end + + # File::Stat for the given path, but return nil for missing/bad entries. + def stat(path) + ::File.stat(path) + rescue Errno::ENOENT, Errno::ELOOP + return nil + end + + # Rack response to use for files and directories under the root. + # Unreadable and non-file, non-directory entries will get a 404 response. + def list_path(env, path, path_info, script_name) + if (stat = stat(path)) && stat.readable? + return @app.call(env) if stat.file? + return list_directory(path_info, path, script_name) if stat.directory? + end + + entity_not_found(path_info) + end + + # Rack response to use for unreadable and non-file, non-directory entries. + def entity_not_found(path_info) + body = "Entity not found: #{path_info}\n" + [404, { CONTENT_TYPE => "text/plain", + CONTENT_LENGTH => body.bytesize.to_s, + "X-Cascade" => "pass" }, [body]] + end + + # Stolen from Ramaze + FILESIZE_FORMAT = [ + ['%.1fT', 1 << 40], + ['%.1fG', 1 << 30], + ['%.1fM', 1 << 20], + ['%.1fK', 1 << 10], + ] + + # Provide human readable file sizes + def filesize_format(int) + FILESIZE_FORMAT.each do |format, size| + return format % (int.to_f / size) if int >= size + end + + "#{int}B" + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/etag.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/etag.rb new file mode 100644 index 0000000000..aceb449ddc --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/etag.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require_relative '../rack' +require 'digest/sha2' + +module Rack + # Automatically sets the ETag header on all String bodies. + # + # The ETag header is skipped if ETag or Last-Modified headers are sent or if + # a sendfile body (body.responds_to :to_path) is given (since such cases + # should be handled by apache/nginx). + # + # On initialization, you can pass two parameters: a Cache-Control directive + # used when Etag is absent and a directive when it is present. The first + # defaults to nil, while the second defaults to "max-age=0, private, must-revalidate" + class ETag + ETAG_STRING = Rack::ETAG + DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate" + + def initialize(app, no_cache_control = nil, cache_control = DEFAULT_CACHE_CONTROL) + @app = app + @cache_control = cache_control + @no_cache_control = no_cache_control + end + + def call(env) + status, headers, body = @app.call(env) + + if etag_status?(status) && etag_body?(body) && !skip_caching?(headers) + original_body = body + digest, new_body = digest_body(body) + body = Rack::BodyProxy.new(new_body) do + original_body.close if original_body.respond_to?(:close) + end + headers[ETAG_STRING] = %(W/"#{digest}") if digest + end + + unless headers[CACHE_CONTROL] + if digest + headers[CACHE_CONTROL] = @cache_control if @cache_control + else + headers[CACHE_CONTROL] = @no_cache_control if @no_cache_control + end + end + + [status, headers, body] + end + + private + + def etag_status?(status) + status == 200 || status == 201 + end + + def etag_body?(body) + !body.respond_to?(:to_path) + end + + def skip_caching?(headers) + headers.key?(ETAG_STRING) || headers.key?('Last-Modified') + end + + def digest_body(body) + parts = [] + digest = nil + + body.each do |part| + parts << part + (digest ||= Digest::SHA256.new) << part unless part.empty? + end + + [digest && digest.hexdigest.byteslice(0, 32), parts] + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/events.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/events.rb new file mode 100644 index 0000000000..65055fdc51 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/events.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +module Rack + ### This middleware provides hooks to certain places in the request / + # response lifecycle. This is so that middleware that don't need to filter + # the response data can safely leave it alone and not have to send messages + # down the traditional "rack stack". + # + # The events are: + # + # * on_start(request, response) + # + # This event is sent at the start of the request, before the next + # middleware in the chain is called. This method is called with a request + # object, and a response object. Right now, the response object is always + # nil, but in the future it may actually be a real response object. + # + # * on_commit(request, response) + # + # The response has been committed. The application has returned, but the + # response has not been sent to the webserver yet. This method is always + # called with a request object and the response object. The response + # object is constructed from the rack triple that the application returned. + # Changes may still be made to the response object at this point. + # + # * on_send(request, response) + # + # The webserver has started iterating over the response body and presumably + # has started sending data over the wire. This method is always called with + # a request object and the response object. The response object is + # constructed from the rack triple that the application returned. Changes + # SHOULD NOT be made to the response object as the webserver has already + # started sending data. Any mutations will likely result in an exception. + # + # * on_finish(request, response) + # + # The webserver has closed the response, and all data has been written to + # the response socket. The request and response object should both be + # read-only at this point. The body MAY NOT be available on the response + # object as it may have been flushed to the socket. + # + # * on_error(request, response, error) + # + # An exception has occurred in the application or an `on_commit` event. + # This method will get the request, the response (if available) and the + # exception that was raised. + # + # ## Order + # + # `on_start` is called on the handlers in the order that they were passed to + # the constructor. `on_commit`, on_send`, `on_finish`, and `on_error` are + # called in the reverse order. `on_finish` handlers are called inside an + # `ensure` block, so they are guaranteed to be called even if something + # raises an exception. If something raises an exception in a `on_finish` + # method, then nothing is guaranteed. + + class Events + module Abstract + def on_start(req, res) + end + + def on_commit(req, res) + end + + def on_send(req, res) + end + + def on_finish(req, res) + end + + def on_error(req, res, e) + end + end + + class EventedBodyProxy < Rack::BodyProxy # :nodoc: + attr_reader :request, :response + + def initialize(body, request, response, handlers, &block) + super(body, &block) + @request = request + @response = response + @handlers = handlers + end + + def each + @handlers.reverse_each { |handler| handler.on_send request, response } + super + end + end + + class BufferedResponse < Rack::Response::Raw # :nodoc: + attr_reader :body + + def initialize(status, headers, body) + super(status, headers) + @body = body + end + + def to_a; [status, headers, body]; end + end + + def initialize(app, handlers) + @app = app + @handlers = handlers + end + + def call(env) + request = make_request env + on_start request, nil + + begin + status, headers, body = @app.call request.env + response = make_response status, headers, body + on_commit request, response + rescue StandardError => e + on_error request, response, e + on_finish request, response + raise + end + + body = EventedBodyProxy.new(body, request, response, @handlers) do + on_finish request, response + end + [response.status, response.headers, body] + end + + private + + def on_error(request, response, e) + @handlers.reverse_each { |handler| handler.on_error request, response, e } + end + + def on_commit(request, response) + @handlers.reverse_each { |handler| handler.on_commit request, response } + end + + def on_start(request, response) + @handlers.each { |handler| handler.on_start request, nil } + end + + def on_finish(request, response) + @handlers.reverse_each { |handler| handler.on_finish request, response } + end + + def make_request(env) + Rack::Request.new env + end + + def make_response(status, headers, body) + BufferedResponse.new status, headers, body + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/file.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/file.rb new file mode 100644 index 0000000000..fdcf9b3ec0 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/file.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require_relative 'files' + +module Rack + File = Files +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/files.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/files.rb new file mode 100644 index 0000000000..e745eb3984 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/files.rb @@ -0,0 +1,218 @@ +# frozen_string_literal: true + +require 'time' + +module Rack + # Rack::Files serves files below the +root+ directory given, according to the + # path info of the Rack request. + # e.g. when Rack::Files.new("/etc") is used, you can access 'passwd' file + # as http://localhost:9292/passwd + # + # Handlers can detect if bodies are a Rack::Files, and use mechanisms + # like sendfile on the +path+. + + class Files + ALLOWED_VERBS = %w[GET HEAD OPTIONS] + ALLOW_HEADER = ALLOWED_VERBS.join(', ') + MULTIPART_BOUNDARY = 'AaB03x' + + # @todo remove in 3.0 + def self.method_added(name) + if name == :response_body + raise "#{self.class}\#response_body is no longer supported." + end + super + end + + attr_reader :root + + def initialize(root, headers = {}, default_mime = 'text/plain') + @root = (::File.expand_path(root) if root) + @headers = headers + @default_mime = default_mime + @head = Rack::Head.new(lambda { |env| get env }) + end + + def call(env) + # HEAD requests drop the response body, including 4xx error messages. + @head.call env + end + + def get(env) + request = Rack::Request.new env + unless ALLOWED_VERBS.include? request.request_method + return fail(405, "Method Not Allowed", { 'Allow' => ALLOW_HEADER }) + end + + path_info = Utils.unescape_path request.path_info + return fail(400, "Bad Request") unless Utils.valid_path?(path_info) + + clean_path_info = Utils.clean_path_info(path_info) + path = ::File.join(@root, clean_path_info) + + available = begin + ::File.file?(path) && ::File.readable?(path) + rescue SystemCallError + # Not sure in what conditions this exception can occur, but this + # is a safe way to handle such an error. + # :nocov: + false + # :nocov: + end + + if available + serving(request, path) + else + fail(404, "File not found: #{path_info}") + end + end + + def serving(request, path) + if request.options? + return [200, { 'Allow' => ALLOW_HEADER, CONTENT_LENGTH => '0' }, []] + end + last_modified = ::File.mtime(path).httpdate + return [304, {}, []] if request.get_header('HTTP_IF_MODIFIED_SINCE') == last_modified + + headers = { "Last-Modified" => last_modified } + mime_type = mime_type path, @default_mime + headers[CONTENT_TYPE] = mime_type if mime_type + + # Set custom headers + headers.merge!(@headers) if @headers + + status = 200 + size = filesize path + + ranges = Rack::Utils.get_byte_ranges(request.get_header('HTTP_RANGE'), size) + if ranges.nil? + # No ranges: + ranges = [0..size - 1] + elsif ranges.empty? + # Unsatisfiable. Return error, and file size: + response = fail(416, "Byte range unsatisfiable") + response[1]["Content-Range"] = "bytes */#{size}" + return response + elsif ranges.size >= 1 + # Partial content + partial_content = true + + if ranges.size == 1 + range = ranges[0] + headers["Content-Range"] = "bytes #{range.begin}-#{range.end}/#{size}" + else + headers[CONTENT_TYPE] = "multipart/byteranges; boundary=#{MULTIPART_BOUNDARY}" + end + + status = 206 + body = BaseIterator.new(path, ranges, mime_type: mime_type, size: size) + size = body.bytesize + end + + headers[CONTENT_LENGTH] = size.to_s + + if request.head? + body = [] + elsif !partial_content + body = Iterator.new(path, ranges, mime_type: mime_type, size: size) + end + + [status, headers, body] + end + + class BaseIterator + attr_reader :path, :ranges, :options + + def initialize(path, ranges, options) + @path = path + @ranges = ranges + @options = options + end + + def each + ::File.open(path, "rb") do |file| + ranges.each do |range| + yield multipart_heading(range) if multipart? + + each_range_part(file, range) do |part| + yield part + end + end + + yield "\r\n--#{MULTIPART_BOUNDARY}--\r\n" if multipart? + end + end + + def bytesize + size = ranges.inject(0) do |sum, range| + sum += multipart_heading(range).bytesize if multipart? + sum += range.size + end + size += "\r\n--#{MULTIPART_BOUNDARY}--\r\n".bytesize if multipart? + size + end + + def close; end + + private + + def multipart? + ranges.size > 1 + end + + def multipart_heading(range) +<<-EOF +\r +--#{MULTIPART_BOUNDARY}\r +Content-Type: #{options[:mime_type]}\r +Content-Range: bytes #{range.begin}-#{range.end}/#{options[:size]}\r +\r +EOF + end + + def each_range_part(file, range) + file.seek(range.begin) + remaining_len = range.end - range.begin + 1 + while remaining_len > 0 + part = file.read([8192, remaining_len].min) + break unless part + remaining_len -= part.length + + yield part + end + end + end + + class Iterator < BaseIterator + alias :to_path :path + end + + private + + def fail(status, body, headers = {}) + body += "\n" + + [ + status, + { + CONTENT_TYPE => "text/plain", + CONTENT_LENGTH => body.size.to_s, + "X-Cascade" => "pass" + }.merge!(headers), + [body] + ] + end + + # The MIME type for the contents of the file located at @path + def mime_type(path, default_mime) + Mime.mime_type(::File.extname(path), default_mime) + end + + def filesize(path) + # We check via File::size? whether this file provides size info + # via stat (e.g. /proc files often don't), otherwise we have to + # figure it out by reading the whole file into memory. + ::File.size?(path) || ::File.read(path).bytesize + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler.rb new file mode 100644 index 0000000000..df17b238dd --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +module Rack + # *Handlers* connect web servers with Rack. + # + # Rack includes Handlers for Thin, WEBrick, FastCGI, CGI, SCGI + # and LiteSpeed. + # + # Handlers usually are activated by calling MyHandler.run(myapp). + # A second optional hash can be passed to include server-specific + # configuration. + module Handler + def self.get(server) + return unless server + server = server.to_s + + unless @handlers.include? server + load_error = try_require('rack/handler', server) + end + + if klass = @handlers[server] + const_get(klass) + else + const_get(server, false) + end + + rescue NameError => name_error + raise load_error || name_error + end + + # Select first available Rack handler given an `Array` of server names. + # Raises `LoadError` if no handler was found. + # + # > pick ['thin', 'webrick'] + # => Rack::Handler::WEBrick + def self.pick(server_names) + server_names = Array(server_names) + server_names.each do |server_name| + begin + return get(server_name.to_s) + rescue LoadError, NameError + end + end + + raise LoadError, "Couldn't find handler for: #{server_names.join(', ')}." + end + + SERVER_NAMES = %w(puma thin falcon webrick).freeze + private_constant :SERVER_NAMES + + def self.default + # Guess. + if ENV.include?("PHP_FCGI_CHILDREN") + Rack::Handler::FastCGI + elsif ENV.include?(REQUEST_METHOD) + Rack::Handler::CGI + elsif ENV.include?("RACK_HANDLER") + self.get(ENV["RACK_HANDLER"]) + else + pick SERVER_NAMES + end + end + + # Transforms server-name constants to their canonical form as filenames, + # then tries to require them but silences the LoadError if not found + # + # Naming convention: + # + # Foo # => 'foo' + # FooBar # => 'foo_bar.rb' + # FooBAR # => 'foobar.rb' + # FOObar # => 'foobar.rb' + # FOOBAR # => 'foobar.rb' + # FooBarBaz # => 'foo_bar_baz.rb' + def self.try_require(prefix, const_name) + file = const_name.gsub(/^[A-Z]+/) { |pre| pre.downcase }. + gsub(/[A-Z]+[^A-Z]/, '_\&').downcase + + require(::File.join(prefix, file)) + nil + rescue LoadError => error + error + end + + def self.register(server, klass) + @handlers ||= {} + @handlers[server.to_s] = klass.to_s + end + + autoload :CGI, "rack/handler/cgi" + autoload :FastCGI, "rack/handler/fastcgi" + autoload :WEBrick, "rack/handler/webrick" + autoload :LSWS, "rack/handler/lsws" + autoload :SCGI, "rack/handler/scgi" + autoload :Thin, "rack/handler/thin" + + register 'cgi', 'Rack::Handler::CGI' + register 'fastcgi', 'Rack::Handler::FastCGI' + register 'webrick', 'Rack::Handler::WEBrick' + register 'lsws', 'Rack::Handler::LSWS' + register 'scgi', 'Rack::Handler::SCGI' + register 'thin', 'Rack::Handler::Thin' + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/cgi.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/cgi.rb new file mode 100644 index 0000000000..1c11ab3606 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/cgi.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module Rack + module Handler + class CGI + def self.run(app, **options) + $stdin.binmode + serve app + end + + def self.serve(app) + env = ENV.to_hash + env.delete "HTTP_CONTENT_LENGTH" + + env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/" + + env.update( + RACK_VERSION => Rack::VERSION, + RACK_INPUT => Rack::RewindableInput.new($stdin), + RACK_ERRORS => $stderr, + RACK_MULTITHREAD => false, + RACK_MULTIPROCESS => true, + RACK_RUNONCE => true, + RACK_URL_SCHEME => ["yes", "on", "1"].include?(ENV[HTTPS]) ? "https" : "http" + ) + + env[QUERY_STRING] ||= "" + env[HTTP_VERSION] ||= env[SERVER_PROTOCOL] + env[REQUEST_PATH] ||= "/" + + status, headers, body = app.call(env) + begin + send_headers status, headers + send_body body + ensure + body.close if body.respond_to? :close + end + end + + def self.send_headers(status, headers) + $stdout.print "Status: #{status}\r\n" + headers.each { |k, vs| + vs.split("\n").each { |v| + $stdout.print "#{k}: #{v}\r\n" + } + } + $stdout.print "\r\n" + $stdout.flush + end + + def self.send_body(body) + body.each { |part| + $stdout.print part + $stdout.flush + } + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/fastcgi.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/fastcgi.rb new file mode 100644 index 0000000000..1df123e02a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/fastcgi.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +require 'fcgi' +require 'socket' + +if defined? FCGI::Stream + class FCGI::Stream + alias _rack_read_without_buffer read + + def read(n, buffer = nil) + buf = _rack_read_without_buffer n + buffer.replace(buf.to_s) if buffer + buf + end + end +end + +module Rack + module Handler + class FastCGI + def self.run(app, **options) + if options[:File] + STDIN.reopen(UNIXServer.new(options[:File])) + elsif options[:Port] + STDIN.reopen(TCPServer.new(options[:Host], options[:Port])) + end + FCGI.each { |request| + serve request, app + } + end + + def self.valid_options + environment = ENV['RACK_ENV'] || 'development' + default_host = environment == 'development' ? 'localhost' : '0.0.0.0' + + { + "Host=HOST" => "Hostname to listen on (default: #{default_host})", + "Port=PORT" => "Port to listen on (default: 8080)", + "File=PATH" => "Creates a Domain socket at PATH instead of a TCP socket. Ignores Host and Port if set.", + } + end + + def self.serve(request, app) + env = request.env + env.delete "HTTP_CONTENT_LENGTH" + + env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/" + + rack_input = RewindableInput.new(request.in) + + env.update( + RACK_VERSION => Rack::VERSION, + RACK_INPUT => rack_input, + RACK_ERRORS => request.err, + RACK_MULTITHREAD => false, + RACK_MULTIPROCESS => true, + RACK_RUNONCE => false, + RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http" + ) + + env[QUERY_STRING] ||= "" + env[HTTP_VERSION] ||= env[SERVER_PROTOCOL] + env[REQUEST_PATH] ||= "/" + env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" + env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == "" + + begin + status, headers, body = app.call(env) + begin + send_headers request.out, status, headers + send_body request.out, body + ensure + body.close if body.respond_to? :close + end + ensure + rack_input.close + request.finish + end + end + + def self.send_headers(out, status, headers) + out.print "Status: #{status}\r\n" + headers.each { |k, vs| + vs.split("\n").each { |v| + out.print "#{k}: #{v}\r\n" + } + } + out.print "\r\n" + out.flush + end + + def self.send_body(out, body) + body.each { |part| + out.print part + out.flush + } + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/lsws.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/lsws.rb new file mode 100644 index 0000000000..f12090bd62 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/lsws.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'lsapi' + +module Rack + module Handler + class LSWS + def self.run(app, **options) + while LSAPI.accept != nil + serve app + end + end + def self.serve(app) + env = ENV.to_hash + env.delete "HTTP_CONTENT_LENGTH" + env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/" + + rack_input = RewindableInput.new($stdin.read.to_s) + + env.update( + RACK_VERSION => Rack::VERSION, + RACK_INPUT => rack_input, + RACK_ERRORS => $stderr, + RACK_MULTITHREAD => false, + RACK_MULTIPROCESS => true, + RACK_RUNONCE => false, + RACK_URL_SCHEME => ["yes", "on", "1"].include?(ENV[HTTPS]) ? "https" : "http" + ) + + env[QUERY_STRING] ||= "" + env[HTTP_VERSION] ||= env[SERVER_PROTOCOL] + env[REQUEST_PATH] ||= "/" + status, headers, body = app.call(env) + begin + send_headers status, headers + send_body body + ensure + body.close if body.respond_to? :close + end + ensure + rack_input.close + end + def self.send_headers(status, headers) + print "Status: #{status}\r\n" + headers.each { |k, vs| + vs.split("\n").each { |v| + print "#{k}: #{v}\r\n" + } + } + print "\r\n" + STDOUT.flush + end + def self.send_body(body) + body.each { |part| + print part + STDOUT.flush + } + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/scgi.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/scgi.rb new file mode 100644 index 0000000000..e3b8d3c6f2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/scgi.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require 'scgi' +require 'stringio' + +module Rack + module Handler + class SCGI < ::SCGI::Processor + attr_accessor :app + + def self.run(app, **options) + options[:Socket] = UNIXServer.new(options[:File]) if options[:File] + new(options.merge(app: app, + host: options[:Host], + port: options[:Port], + socket: options[:Socket])).listen + end + + def self.valid_options + environment = ENV['RACK_ENV'] || 'development' + default_host = environment == 'development' ? 'localhost' : '0.0.0.0' + + { + "Host=HOST" => "Hostname to listen on (default: #{default_host})", + "Port=PORT" => "Port to listen on (default: 8080)", + } + end + + def initialize(settings = {}) + @app = settings[:app] + super(settings) + end + + def process_request(request, input_body, socket) + env = Hash[request] + env.delete "HTTP_CONTENT_TYPE" + env.delete "HTTP_CONTENT_LENGTH" + env[REQUEST_PATH], env[QUERY_STRING] = env["REQUEST_URI"].split('?', 2) + env[HTTP_VERSION] ||= env[SERVER_PROTOCOL] + env[PATH_INFO] = env[REQUEST_PATH] + env[QUERY_STRING] ||= "" + env[SCRIPT_NAME] = "" + + rack_input = StringIO.new(input_body) + rack_input.set_encoding(Encoding::BINARY) + + env.update( + RACK_VERSION => Rack::VERSION, + RACK_INPUT => rack_input, + RACK_ERRORS => $stderr, + RACK_MULTITHREAD => true, + RACK_MULTIPROCESS => true, + RACK_RUNONCE => false, + RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http" + ) + + status, headers, body = app.call(env) + begin + socket.write("Status: #{status}\r\n") + headers.each do |k, vs| + vs.split("\n").each { |v| socket.write("#{k}: #{v}\r\n")} + end + socket.write("\r\n") + body.each {|s| socket.write(s)} + ensure + body.close if body.respond_to? :close + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/thin.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/thin.rb new file mode 100644 index 0000000000..393a6e9869 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/thin.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require "thin" +require "thin/server" +require "thin/logging" +require "thin/backends/tcp_server" + +module Rack + module Handler + class Thin + def self.run(app, **options) + environment = ENV['RACK_ENV'] || 'development' + default_host = environment == 'development' ? 'localhost' : '0.0.0.0' + + host = options.delete(:Host) || default_host + port = options.delete(:Port) || 8080 + args = [host, port, app, options] + # Thin versions below 0.8.0 do not support additional options + args.pop if ::Thin::VERSION::MAJOR < 1 && ::Thin::VERSION::MINOR < 8 + server = ::Thin::Server.new(*args) + yield server if block_given? + server.start + end + + def self.valid_options + environment = ENV['RACK_ENV'] || 'development' + default_host = environment == 'development' ? 'localhost' : '0.0.0.0' + + { + "Host=HOST" => "Hostname to listen on (default: #{default_host})", + "Port=PORT" => "Port to listen on (default: 8080)", + } + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/webrick.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/webrick.rb new file mode 100644 index 0000000000..d2f389758a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/handler/webrick.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +require 'webrick' +require 'stringio' + +# This monkey patch allows for applications to perform their own chunking +# through WEBrick::HTTPResponse if rack is set to true. +class WEBrick::HTTPResponse + attr_accessor :rack + + alias _rack_setup_header setup_header + def setup_header + app_chunking = rack && @header['transfer-encoding'] == 'chunked' + + @chunked = app_chunking if app_chunking + + _rack_setup_header + + @chunked = false if app_chunking + end +end + +module Rack + module Handler + class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet + def self.run(app, **options) + environment = ENV['RACK_ENV'] || 'development' + default_host = environment == 'development' ? 'localhost' : nil + + if !options[:BindAddress] || options[:Host] + options[:BindAddress] = options.delete(:Host) || default_host + end + options[:Port] ||= 8080 + if options[:SSLEnable] + require 'webrick/https' + end + + @server = ::WEBrick::HTTPServer.new(options) + @server.mount "/", Rack::Handler::WEBrick, app + yield @server if block_given? + @server.start + end + + def self.valid_options + environment = ENV['RACK_ENV'] || 'development' + default_host = environment == 'development' ? 'localhost' : '0.0.0.0' + + { + "Host=HOST" => "Hostname to listen on (default: #{default_host})", + "Port=PORT" => "Port to listen on (default: 8080)", + } + end + + def self.shutdown + if @server + @server.shutdown + @server = nil + end + end + + def initialize(server, app) + super server + @app = app + end + + def service(req, res) + res.rack = true + env = req.meta_vars + env.delete_if { |k, v| v.nil? } + + rack_input = StringIO.new(req.body.to_s) + rack_input.set_encoding(Encoding::BINARY) + + env.update( + RACK_VERSION => Rack::VERSION, + RACK_INPUT => rack_input, + RACK_ERRORS => $stderr, + RACK_MULTITHREAD => true, + RACK_MULTIPROCESS => false, + RACK_RUNONCE => false, + RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http", + RACK_IS_HIJACK => true, + RACK_HIJACK => lambda { raise NotImplementedError, "only partial hijack is supported."}, + RACK_HIJACK_IO => nil + ) + + env[HTTP_VERSION] ||= env[SERVER_PROTOCOL] + env[QUERY_STRING] ||= "" + unless env[PATH_INFO] == "" + path, n = req.request_uri.path, env[SCRIPT_NAME].length + env[PATH_INFO] = path[n, path.length - n] + end + env[REQUEST_PATH] ||= [env[SCRIPT_NAME], env[PATH_INFO]].join + + status, headers, body = @app.call(env) + begin + res.status = status.to_i + io_lambda = nil + headers.each { |k, vs| + if k == RACK_HIJACK + io_lambda = vs + elsif k.downcase == "set-cookie" + res.cookies.concat vs.split("\n") + else + # Since WEBrick won't accept repeated headers, + # merge the values per RFC 1945 section 4.2. + res[k] = vs.split("\n").join(", ") + end + } + + if io_lambda + rd, wr = IO.pipe + res.body = rd + res.chunked = true + io_lambda.call wr + elsif body.respond_to?(:to_path) + res.body = ::File.open(body.to_path, 'rb') + else + body.each { |part| + res.body << part + } + end + ensure + body.close if body.respond_to? :close + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/head.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/head.rb new file mode 100644 index 0000000000..8025a27d51 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/head.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Rack + # Rack::Head returns an empty body for all HEAD requests. It leaves + # all other requests unchanged. + class Head + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + + if env[REQUEST_METHOD] == HEAD + [ + status, headers, Rack::BodyProxy.new([]) do + body.close if body.respond_to? :close + end + ] + else + [status, headers, body] + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/lint.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/lint.rb new file mode 100644 index 0000000000..16b5feea2a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/lint.rb @@ -0,0 +1,806 @@ +# frozen_string_literal: true + +require 'forwardable' + +module Rack + # Rack::Lint validates your application and the requests and + # responses according to the Rack spec. + + class Lint + def initialize(app) + @app = app + @content_length = nil + end + + # :stopdoc: + + class LintError < RuntimeError; end + module Assertion + def assert(message) + unless yield + raise LintError, message + end + end + end + include Assertion + + ## This specification aims to formalize the Rack protocol. You + ## can (and should) use Rack::Lint to enforce it. + ## + ## When you develop middleware, be sure to add a Lint before and + ## after to catch all mistakes. + + ## = Rack applications + + ## A Rack application is a Ruby object (not a class) that + ## responds to +call+. + def call(env = nil) + dup._call(env) + end + + def _call(env) + ## It takes exactly one argument, the *environment* + assert("No env given") { env } + check_env env + + env[RACK_INPUT] = InputWrapper.new(env[RACK_INPUT]) + env[RACK_ERRORS] = ErrorWrapper.new(env[RACK_ERRORS]) + + ## and returns an Array of exactly three values: + ary = @app.call(env) + assert("response #{ary.inspect} is not an Array , but #{ary.class}") { + ary.kind_of? Array + } + assert("response array #{ary.inspect} has #{ary.size} elements instead of 3") { + ary.size == 3 + } + + status, headers, @body = ary + ## The *status*, + check_status status + ## the *headers*, + check_headers headers + + hijack_proc = check_hijack_response headers, env + if hijack_proc && headers.is_a?(Hash) + headers[RACK_HIJACK] = hijack_proc + end + + ## and the *body*. + check_content_type status, headers + check_content_length status, headers + @head_request = env[REQUEST_METHOD] == HEAD + [status, headers, self] + end + + ## == The Environment + def check_env(env) + ## The environment must be an unfrozen instance of Hash that includes + ## CGI-like headers. The application is free to modify the + ## environment. + assert("env #{env.inspect} is not a Hash, but #{env.class}") { + env.kind_of? Hash + } + assert("env should not be frozen, but is") { + !env.frozen? + } + + ## + ## The environment is required to include these variables + ## (adopted from PEP333), except when they'd be empty, but see + ## below. + + ## REQUEST_METHOD:: The HTTP request method, such as + ## "GET" or "POST". This cannot ever + ## be an empty string, and so is + ## always required. + + ## SCRIPT_NAME:: The initial portion of the request + ## URL's "path" that corresponds to the + ## application object, so that the + ## application knows its virtual + ## "location". This may be an empty + ## string, if the application corresponds + ## to the "root" of the server. + + ## PATH_INFO:: The remainder of the request URL's + ## "path", designating the virtual + ## "location" of the request's target + ## within the application. This may be an + ## empty string, if the request URL targets + ## the application root and does not have a + ## trailing slash. This value may be + ## percent-encoded when originating from + ## a URL. + + ## QUERY_STRING:: The portion of the request URL that + ## follows the ?, if any. May be + ## empty, but is always required! + + ## SERVER_NAME:: When combined with SCRIPT_NAME and + ## PATH_INFO, these variables can be + ## used to complete the URL. Note, however, + ## that HTTP_HOST, if present, + ## should be used in preference to + ## SERVER_NAME for reconstructing + ## the request URL. + ## SERVER_NAME can never be an empty + ## string, and so is always required. + + ## SERVER_PORT:: An optional +Integer+ which is the port the + ## server is running on. Should be specified if + ## the server is running on a non-standard port. + + ## HTTP_ Variables:: Variables corresponding to the + ## client-supplied HTTP request + ## headers (i.e., variables whose + ## names begin with HTTP_). The + ## presence or absence of these + ## variables should correspond with + ## the presence or absence of the + ## appropriate HTTP header in the + ## request. See + ## {RFC3875 section 4.1.18}[https://tools.ietf.org/html/rfc3875#section-4.1.18] + ## for specific behavior. + + ## In addition to this, the Rack environment must include these + ## Rack-specific variables: + + ## rack.version:: The Array representing this version of Rack + ## See Rack::VERSION, that corresponds to + ## the version of this SPEC. + + ## rack.url_scheme:: +http+ or +https+, depending on the + ## request URL. + + ## rack.input:: See below, the input stream. + + ## rack.errors:: See below, the error stream. + + ## rack.multithread:: true if the application object may be + ## simultaneously invoked by another thread + ## in the same process, false otherwise. + + ## rack.multiprocess:: true if an equivalent application object + ## may be simultaneously invoked by another + ## process, false otherwise. + + ## rack.run_once:: true if the server expects + ## (but does not guarantee!) that the + ## application will only be invoked this one + ## time during the life of its containing + ## process. Normally, this will only be true + ## for a server based on CGI + ## (or something similar). + + ## rack.hijack?:: present and true if the server supports + ## connection hijacking. See below, hijacking. + + ## rack.hijack:: an object responding to #call that must be + ## called at least once before using + ## rack.hijack_io. + ## It is recommended #call return rack.hijack_io + ## as well as setting it in env if necessary. + + ## rack.hijack_io:: if rack.hijack? is true, and rack.hijack + ## has received #call, this will contain + ## an object resembling an IO. See hijacking. + + ## Additional environment specifications have approved to + ## standardized middleware APIs. None of these are required to + ## be implemented by the server. + + ## rack.session:: A hash like interface for storing + ## request session data. + ## The store must implement: + if session = env[RACK_SESSION] + ## store(key, value) (aliased as []=); + assert("session #{session.inspect} must respond to store and []=") { + session.respond_to?(:store) && session.respond_to?(:[]=) + } + + ## fetch(key, default = nil) (aliased as []); + assert("session #{session.inspect} must respond to fetch and []") { + session.respond_to?(:fetch) && session.respond_to?(:[]) + } + + ## delete(key); + assert("session #{session.inspect} must respond to delete") { + session.respond_to?(:delete) + } + + ## clear; + assert("session #{session.inspect} must respond to clear") { + session.respond_to?(:clear) + } + + ## to_hash (returning unfrozen Hash instance); + assert("session #{session.inspect} must respond to to_hash and return unfrozen Hash instance") { + session.respond_to?(:to_hash) && session.to_hash.kind_of?(Hash) && !session.to_hash.frozen? + } + end + + ## rack.logger:: A common object interface for logging messages. + ## The object must implement: + if logger = env[RACK_LOGGER] + ## info(message, &block) + assert("logger #{logger.inspect} must respond to info") { + logger.respond_to?(:info) + } + + ## debug(message, &block) + assert("logger #{logger.inspect} must respond to debug") { + logger.respond_to?(:debug) + } + + ## warn(message, &block) + assert("logger #{logger.inspect} must respond to warn") { + logger.respond_to?(:warn) + } + + ## error(message, &block) + assert("logger #{logger.inspect} must respond to error") { + logger.respond_to?(:error) + } + + ## fatal(message, &block) + assert("logger #{logger.inspect} must respond to fatal") { + logger.respond_to?(:fatal) + } + end + + ## rack.multipart.buffer_size:: An Integer hint to the multipart parser as to what chunk size to use for reads and writes. + if bufsize = env[RACK_MULTIPART_BUFFER_SIZE] + assert("rack.multipart.buffer_size must be an Integer > 0 if specified") { + bufsize.is_a?(Integer) && bufsize > 0 + } + end + + ## rack.multipart.tempfile_factory:: An object responding to #call with two arguments, the filename and content_type given for the multipart form field, and returning an IO-like object that responds to #<< and optionally #rewind. This factory will be used to instantiate the tempfile for each multipart form file upload field, rather than the default class of Tempfile. + if tempfile_factory = env[RACK_MULTIPART_TEMPFILE_FACTORY] + assert("rack.multipart.tempfile_factory must respond to #call") { tempfile_factory.respond_to?(:call) } + env[RACK_MULTIPART_TEMPFILE_FACTORY] = lambda do |filename, content_type| + io = tempfile_factory.call(filename, content_type) + assert("rack.multipart.tempfile_factory return value must respond to #<<") { io.respond_to?(:<<) } + io + end + end + + ## The server or the application can store their own data in the + ## environment, too. The keys must contain at least one dot, + ## and should be prefixed uniquely. The prefix rack. + ## is reserved for use with the Rack core distribution and other + ## accepted specifications and must not be used otherwise. + ## + + %w[REQUEST_METHOD SERVER_NAME QUERY_STRING + rack.version rack.input rack.errors + rack.multithread rack.multiprocess rack.run_once].each { |header| + assert("env missing required key #{header}") { env.include? header } + } + + ## The SERVER_PORT must be an Integer if set. + assert("env[SERVER_PORT] is not an Integer") do + server_port = env["SERVER_PORT"] + server_port.nil? || (Integer(server_port) rescue false) + end + + ## The SERVER_NAME must be a valid authority as defined by RFC7540. + assert("#{env[SERVER_NAME]} must be a valid authority") do + URI.parse("http://#{env[SERVER_NAME]}/") rescue false + end + + ## The HTTP_HOST must be a valid authority as defined by RFC7540. + assert("#{env[HTTP_HOST]} must be a valid authority") do + URI.parse("http://#{env[HTTP_HOST]}/") rescue false + end + + ## The environment must not contain the keys + ## HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH + ## (use the versions without HTTP_). + %w[HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH].each { |header| + assert("env contains #{header}, must use #{header[5, -1]}") { + not env.include? header + } + } + + ## The CGI keys (named without a period) must have String values. + ## If the string values for CGI keys contain non-ASCII characters, + ## they should use ASCII-8BIT encoding. + env.each { |key, value| + next if key.include? "." # Skip extensions + assert("env variable #{key} has non-string value #{value.inspect}") { + value.kind_of? String + } + next if value.encoding == Encoding::ASCII_8BIT + assert("env variable #{key} has value containing non-ASCII characters and has non-ASCII-8BIT encoding #{value.inspect} encoding: #{value.encoding}") { + value.b !~ /[\x80-\xff]/n + } + } + + ## There are the following restrictions: + + ## * rack.version must be an array of Integers. + assert("rack.version must be an Array, was #{env[RACK_VERSION].class}") { + env[RACK_VERSION].kind_of? Array + } + ## * rack.url_scheme must either be +http+ or +https+. + assert("rack.url_scheme unknown: #{env[RACK_URL_SCHEME].inspect}") { + %w[http https].include?(env[RACK_URL_SCHEME]) + } + + ## * There must be a valid input stream in rack.input. + check_input env[RACK_INPUT] + ## * There must be a valid error stream in rack.errors. + check_error env[RACK_ERRORS] + ## * There may be a valid hijack stream in rack.hijack_io + check_hijack env + + ## * The REQUEST_METHOD must be a valid token. + assert("REQUEST_METHOD unknown: #{env[REQUEST_METHOD]}") { + env[REQUEST_METHOD] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/ + } + + ## * The SCRIPT_NAME, if non-empty, must start with / + assert("SCRIPT_NAME must start with /") { + !env.include?(SCRIPT_NAME) || + env[SCRIPT_NAME] == "" || + env[SCRIPT_NAME] =~ /\A\// + } + ## * The PATH_INFO, if non-empty, must start with / + assert("PATH_INFO must start with /") { + !env.include?(PATH_INFO) || + env[PATH_INFO] == "" || + env[PATH_INFO] =~ /\A\// + } + ## * The CONTENT_LENGTH, if given, must consist of digits only. + assert("Invalid CONTENT_LENGTH: #{env["CONTENT_LENGTH"]}") { + !env.include?("CONTENT_LENGTH") || env["CONTENT_LENGTH"] =~ /\A\d+\z/ + } + + ## * One of SCRIPT_NAME or PATH_INFO must be + ## set. PATH_INFO should be / if + ## SCRIPT_NAME is empty. + assert("One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)") { + env[SCRIPT_NAME] || env[PATH_INFO] + } + ## SCRIPT_NAME never should be /, but instead be empty. + assert("SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/'") { + env[SCRIPT_NAME] != "/" + } + end + + ## === The Input Stream + ## + ## The input stream is an IO-like object which contains the raw HTTP + ## POST data. + def check_input(input) + ## When applicable, its external encoding must be "ASCII-8BIT" and it + ## must be opened in binary mode, for Ruby 1.9 compatibility. + assert("rack.input #{input} does not have ASCII-8BIT as its external encoding") { + input.external_encoding == Encoding::ASCII_8BIT + } if input.respond_to?(:external_encoding) + assert("rack.input #{input} is not opened in binary mode") { + input.binmode? + } if input.respond_to?(:binmode?) + + ## The input stream must respond to +gets+, +each+, +read+ and +rewind+. + [:gets, :each, :read, :rewind].each { |method| + assert("rack.input #{input} does not respond to ##{method}") { + input.respond_to? method + } + } + end + + class InputWrapper + include Assertion + + def initialize(input) + @input = input + end + + ## * +gets+ must be called without arguments and return a string, + ## or +nil+ on EOF. + def gets(*args) + assert("rack.input#gets called with arguments") { args.size == 0 } + v = @input.gets + assert("rack.input#gets didn't return a String") { + v.nil? or v.kind_of? String + } + v + end + + ## * +read+ behaves like IO#read. + ## Its signature is read([length, [buffer]]). + ## + ## If given, +length+ must be a non-negative Integer (>= 0) or +nil+, + ## and +buffer+ must be a String and may not be nil. + ## + ## If +length+ is given and not nil, then this method reads at most + ## +length+ bytes from the input stream. + ## + ## If +length+ is not given or nil, then this method reads + ## all data until EOF. + ## + ## When EOF is reached, this method returns nil if +length+ is given + ## and not nil, or "" if +length+ is not given or is nil. + ## + ## If +buffer+ is given, then the read data will be placed + ## into +buffer+ instead of a newly created String object. + def read(*args) + assert("rack.input#read called with too many arguments") { + args.size <= 2 + } + if args.size >= 1 + assert("rack.input#read called with non-integer and non-nil length") { + args.first.kind_of?(Integer) || args.first.nil? + } + assert("rack.input#read called with a negative length") { + args.first.nil? || args.first >= 0 + } + end + if args.size >= 2 + assert("rack.input#read called with non-String buffer") { + args[1].kind_of?(String) + } + end + + v = @input.read(*args) + + assert("rack.input#read didn't return nil or a String") { + v.nil? or v.kind_of? String + } + if args[0].nil? + assert("rack.input#read(nil) returned nil on EOF") { + !v.nil? + } + end + + v + end + + ## * +each+ must be called without arguments and only yield Strings. + def each(*args) + assert("rack.input#each called with arguments") { args.size == 0 } + @input.each { |line| + assert("rack.input#each didn't yield a String") { + line.kind_of? String + } + yield line + } + end + + ## * +rewind+ must be called without arguments. It rewinds the input + ## stream back to the beginning. It must not raise Errno::ESPIPE: + ## that is, it may not be a pipe or a socket. Therefore, handler + ## developers must buffer the input data into some rewindable object + ## if the underlying input stream is not rewindable. + def rewind(*args) + assert("rack.input#rewind called with arguments") { args.size == 0 } + assert("rack.input#rewind raised Errno::ESPIPE") { + begin + @input.rewind + true + rescue Errno::ESPIPE + false + end + } + end + + ## * +close+ must never be called on the input stream. + def close(*args) + assert("rack.input#close must not be called") { false } + end + end + + ## === The Error Stream + def check_error(error) + ## The error stream must respond to +puts+, +write+ and +flush+. + [:puts, :write, :flush].each { |method| + assert("rack.error #{error} does not respond to ##{method}") { + error.respond_to? method + } + } + end + + class ErrorWrapper + include Assertion + + def initialize(error) + @error = error + end + + ## * +puts+ must be called with a single argument that responds to +to_s+. + def puts(str) + @error.puts str + end + + ## * +write+ must be called with a single argument that is a String. + def write(str) + assert("rack.errors#write not called with a String") { str.kind_of? String } + @error.write str + end + + ## * +flush+ must be called without arguments and must be called + ## in order to make the error appear for sure. + def flush + @error.flush + end + + ## * +close+ must never be called on the error stream. + def close(*args) + assert("rack.errors#close must not be called") { false } + end + end + + class HijackWrapper + include Assertion + extend Forwardable + + REQUIRED_METHODS = [ + :read, :write, :read_nonblock, :write_nonblock, :flush, :close, + :close_read, :close_write, :closed? + ] + + def_delegators :@io, *REQUIRED_METHODS + + def initialize(io) + @io = io + REQUIRED_METHODS.each do |meth| + assert("rack.hijack_io must respond to #{meth}") { io.respond_to? meth } + end + end + end + + ## === Hijacking + # + # AUTHORS: n.b. The trailing whitespace between paragraphs is important and + # should not be removed. The whitespace creates paragraphs in the RDoc + # output. + # + ## ==== Request (before status) + def check_hijack(env) + if env[RACK_IS_HIJACK] + ## If rack.hijack? is true then rack.hijack must respond to #call. + original_hijack = env[RACK_HIJACK] + assert("rack.hijack must respond to call") { original_hijack.respond_to?(:call) } + env[RACK_HIJACK] = proc do + ## rack.hijack must return the io that will also be assigned (or is + ## already present, in rack.hijack_io. + io = original_hijack.call + HijackWrapper.new(io) + ## + ## rack.hijack_io must respond to: + ## read, write, read_nonblock, write_nonblock, flush, close, + ## close_read, close_write, closed? + ## + ## The semantics of these IO methods must be a best effort match to + ## those of a normal ruby IO or Socket object, using standard + ## arguments and raising standard exceptions. Servers are encouraged + ## to simply pass on real IO objects, although it is recognized that + ## this approach is not directly compatible with SPDY and HTTP 2.0. + ## + ## IO provided in rack.hijack_io should preference the + ## IO::WaitReadable and IO::WaitWritable APIs wherever supported. + ## + ## There is a deliberate lack of full specification around + ## rack.hijack_io, as semantics will change from server to server. + ## Users are encouraged to utilize this API with a knowledge of their + ## server choice, and servers may extend the functionality of + ## hijack_io to provide additional features to users. The purpose of + ## rack.hijack is for Rack to "get out of the way", as such, Rack only + ## provides the minimum of specification and support. + env[RACK_HIJACK_IO] = HijackWrapper.new(env[RACK_HIJACK_IO]) + io + end + else + ## + ## If rack.hijack? is false, then rack.hijack should not be set. + assert("rack.hijack? is false, but rack.hijack is present") { env[RACK_HIJACK].nil? } + ## + ## If rack.hijack? is false, then rack.hijack_io should not be set. + assert("rack.hijack? is false, but rack.hijack_io is present") { env[RACK_HIJACK_IO].nil? } + end + end + + ## ==== Response (after headers) + ## It is also possible to hijack a response after the status and headers + ## have been sent. + def check_hijack_response(headers, env) + + # this check uses headers like a hash, but the spec only requires + # headers respond to #each + headers = Rack::Utils::HeaderHash[headers] + + ## In order to do this, an application may set the special header + ## rack.hijack to an object that responds to call + ## accepting an argument that conforms to the rack.hijack_io + ## protocol. + ## + ## After the headers have been sent, and this hijack callback has been + ## called, the application is now responsible for the remaining lifecycle + ## of the IO. The application is also responsible for maintaining HTTP + ## semantics. Of specific note, in almost all cases in the current SPEC, + ## applications will have wanted to specify the header Connection:close in + ## HTTP/1.1, and not Connection:keep-alive, as there is no protocol for + ## returning hijacked sockets to the web server. For that purpose, use the + ## body streaming API instead (progressively yielding strings via each). + ## + ## Servers must ignore the body part of the response tuple when + ## the rack.hijack response API is in use. + + if env[RACK_IS_HIJACK] && headers[RACK_HIJACK] + assert('rack.hijack header must respond to #call') { + headers[RACK_HIJACK].respond_to? :call + } + original_hijack = headers[RACK_HIJACK] + proc do |io| + original_hijack.call HijackWrapper.new(io) + end + else + ## + ## The special response header rack.hijack must only be set + ## if the request env has rack.hijack? true. + assert('rack.hijack header must not be present if server does not support hijacking') { + headers[RACK_HIJACK].nil? + } + + nil + end + end + ## ==== Conventions + ## * Middleware should not use hijack unless it is handling the whole + ## response. + ## * Middleware may wrap the IO object for the response pattern. + ## * Middleware should not wrap the IO object for the request pattern. The + ## request pattern is intended to provide the hijacker with "raw tcp". + + ## == The Response + + ## === The Status + def check_status(status) + ## This is an HTTP status. When parsed as integer (+to_i+), it must be + ## greater than or equal to 100. + assert("Status must be >=100 seen as integer") { status.to_i >= 100 } + end + + ## === The Headers + def check_headers(header) + ## The header must respond to +each+, and yield values of key and value. + assert("headers object should respond to #each, but doesn't (got #{header.class} as headers)") { + header.respond_to? :each + } + + header.each { |key, value| + ## The header keys must be Strings. + assert("header key must be a string, was #{key.class}") { + key.kind_of? String + } + + ## Special headers starting "rack." are for communicating with the + ## server, and must not be sent back to the client. + next if key =~ /^rack\..+$/ + + ## The header must not contain a +Status+ key. + assert("header must not contain Status") { key.downcase != "status" } + ## The header must conform to RFC7230 token specification, i.e. cannot + ## contain non-printable ASCII, DQUOTE or "(),/:;<=>?@[\]{}". + assert("invalid header name: #{key}") { key !~ /[\(\),\/:;<=>\?@\[\\\]{}[:cntrl:]]/ } + + ## The values of the header must be Strings, + assert("a header value must be a String, but the value of " + + "'#{key}' is a #{value.class}") { value.kind_of? String } + ## consisting of lines (for multiple header values, e.g. multiple + ## Set-Cookie values) separated by "\\n". + value.split("\n").each { |item| + ## The lines must not contain characters below 037. + assert("invalid header value #{key}: #{item.inspect}") { + item !~ /[\000-\037]/ + } + } + } + end + + ## === The Content-Type + def check_content_type(status, headers) + headers.each { |key, value| + ## There must not be a Content-Type, when the +Status+ is 1xx, + ## 204 or 304. + if key.downcase == "content-type" + assert("Content-Type header found in #{status} response, not allowed") { + not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key? status.to_i + } + return + end + } + end + + ## === The Content-Length + def check_content_length(status, headers) + headers.each { |key, value| + if key.downcase == 'content-length' + ## There must not be a Content-Length header when the + ## +Status+ is 1xx, 204 or 304. + assert("Content-Length header found in #{status} response, not allowed") { + not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key? status.to_i + } + @content_length = value + end + } + end + + def verify_content_length(bytes) + if @head_request + assert("Response body was given for HEAD request, but should be empty") { + bytes == 0 + } + elsif @content_length + assert("Content-Length header was #{@content_length}, but should be #{bytes}") { + @content_length == bytes.to_s + } + end + end + + ## === The Body + def each + @closed = false + bytes = 0 + + ## The Body must respond to +each+ + assert("Response body must respond to each") do + @body.respond_to?(:each) + end + + @body.each { |part| + ## and must only yield String values. + assert("Body yielded non-string value #{part.inspect}") { + part.kind_of? String + } + bytes += part.bytesize + yield part + } + verify_content_length(bytes) + + ## + ## The Body itself should not be an instance of String, as this will + ## break in Ruby 1.9. + ## + ## If the Body responds to +close+, it will be called after iteration. If + ## the body is replaced by a middleware after action, the original body + ## must be closed first, if it responds to close. + # XXX howto: assert("Body has not been closed") { @closed } + + + ## + ## If the Body responds to +to_path+, it must return a String + ## identifying the location of a file whose contents are identical + ## to that produced by calling +each+; this may be used by the + ## server as an alternative, possibly more efficient way to + ## transport the response. + + if @body.respond_to?(:to_path) + assert("The file identified by body.to_path does not exist") { + ::File.exist? @body.to_path + } + end + + ## + ## The Body commonly is an Array of Strings, the application + ## instance itself, or a File-like object. + end + + def close + @closed = true + @body.close if @body.respond_to?(:close) + end + + # :startdoc: + + end +end + +## == Thanks +## Some parts of this specification are adopted from PEP333: Python +## Web Server Gateway Interface +## v1.0 (http://www.python.org/dev/peps/pep-0333/). I'd like to thank +## everyone involved in that effort. diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/lobster.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/lobster.rb new file mode 100644 index 0000000000..b86a625de0 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/lobster.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'zlib' + +module Rack + # Paste has a Pony, Rack has a Lobster! + class Lobster + LobsterString = Zlib::Inflate.inflate("eJx9kEEOwyAMBO99xd7MAcytUhPlJyj2 + P6jy9i4k9EQyGAnBarEXeCBqSkntNXsi/ZCvC48zGQoZKikGrFMZvgS5ZHd+aGWVuWwhVF0 + t1drVmiR42HcWNz5w3QanT+2gIvTVCiE1lm1Y0eU4JGmIIbaKwextKn8rvW+p5PIwFl8ZWJ + I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0]) + + LambdaLobster = lambda { |env| + if env[QUERY_STRING].include?("flip") + lobster = LobsterString.split("\n"). + map { |line| line.ljust(42).reverse }. + join("\n") + href = "?" + else + lobster = LobsterString + href = "?flip" + end + + content = ["Lobstericious!", + "
", lobster, "
", + "flip!"] + length = content.inject(0) { |a, e| a + e.size }.to_s + [200, { CONTENT_TYPE => "text/html", CONTENT_LENGTH => length }, content] + } + + def call(env) + req = Request.new(env) + if req.GET["flip"] == "left" + lobster = LobsterString.split("\n").map do |line| + line.ljust(42).reverse. + gsub('\\', 'TEMP'). + gsub('/', '\\'). + gsub('TEMP', '/'). + gsub('{', '}'). + gsub('(', ')') + end.join("\n") + href = "?flip=right" + elsif req.GET["flip"] == "crash" + raise "Lobster crashed" + else + lobster = LobsterString + href = "?flip=left" + end + + res = Response.new + res.write "Lobstericious!" + res.write "
"
+      res.write lobster
+      res.write "
" + res.write "

flip!

" + res.write "

crash!

" + res.finish + end + + end +end + +if $0 == __FILE__ + # :nocov: + require_relative '../rack' + Rack::Server.start( + app: Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), Port: 9292 + ) + # :nocov: +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/lock.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/lock.rb new file mode 100644 index 0000000000..4bae3a9034 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/lock.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'thread' + +module Rack + # Rack::Lock locks every request inside a mutex, so that every request + # will effectively be executed synchronously. + class Lock + def initialize(app, mutex = Mutex.new) + @app, @mutex = app, mutex + end + + def call(env) + @mutex.lock + @env = env + @old_rack_multithread = env[RACK_MULTITHREAD] + begin + response = @app.call(env.merge!(RACK_MULTITHREAD => false)) + returned = response << BodyProxy.new(response.pop) { unlock } + ensure + unlock unless returned + end + end + + private + + def unlock + @mutex.unlock + @env[RACK_MULTITHREAD] = @old_rack_multithread + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/logger.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/logger.rb new file mode 100644 index 0000000000..6c4bede0cf --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/logger.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'logger' + +module Rack + # Sets up rack.logger to write to rack.errors stream + class Logger + def initialize(app, level = ::Logger::INFO) + @app, @level = app, level + end + + def call(env) + logger = ::Logger.new(env[RACK_ERRORS]) + logger.level = @level + + env[RACK_LOGGER] = logger + @app.call(env) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/media_type.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/media_type.rb new file mode 100644 index 0000000000..41937c9947 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/media_type.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Rack + # Rack::MediaType parse media type and parameters out of content_type string + + class MediaType + SPLIT_PATTERN = %r{\s*[;,]\s*} + + class << self + # The media type (type/subtype) portion of the CONTENT_TYPE header + # without any media type parameters. e.g., when CONTENT_TYPE is + # "text/plain;charset=utf-8", the media-type is "text/plain". + # + # For more information on the use of media types in HTTP, see: + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 + def type(content_type) + return nil unless content_type + content_type.split(SPLIT_PATTERN, 2).first.tap &:downcase! + end + + # The media type parameters provided in CONTENT_TYPE as a Hash, or + # an empty Hash if no CONTENT_TYPE or media-type parameters were + # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8", + # this method responds with the following Hash: + # { 'charset' => 'utf-8' } + def params(content_type) + return {} if content_type.nil? + + content_type.split(SPLIT_PATTERN)[1..-1].each_with_object({}) do |s, hsh| + k, v = s.split('=', 2) + + hsh[k.tap(&:downcase!)] = strip_doublequotes(v) + end + end + + private + + def strip_doublequotes(str) + (str.start_with?('"') && str.end_with?('"')) ? str[1..-2] : str + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/method_override.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/method_override.rb new file mode 100644 index 0000000000..453901fc60 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/method_override.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Rack + class MethodOverride + HTTP_METHODS = %w[GET HEAD PUT POST DELETE OPTIONS PATCH LINK UNLINK] + + METHOD_OVERRIDE_PARAM_KEY = "_method" + HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE" + ALLOWED_METHODS = %w[POST] + + def initialize(app) + @app = app + end + + def call(env) + if allowed_methods.include?(env[REQUEST_METHOD]) + method = method_override(env) + if HTTP_METHODS.include?(method) + env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] = env[REQUEST_METHOD] + env[REQUEST_METHOD] = method + end + end + + @app.call(env) + end + + def method_override(env) + req = Request.new(env) + method = method_override_param(req) || + env[HTTP_METHOD_OVERRIDE_HEADER] + begin + method.to_s.upcase + rescue ArgumentError + env[RACK_ERRORS].puts "Invalid string for method" + end + end + + private + + def allowed_methods + ALLOWED_METHODS + end + + def method_override_param(req) + req.POST[METHOD_OVERRIDE_PARAM_KEY] + rescue Utils::InvalidParameterError, Utils::ParameterTypeError + req.get_header(RACK_ERRORS).puts "Invalid or incomplete POST params" + rescue EOFError + req.get_header(RACK_ERRORS).puts "Bad request content body" + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/mime.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/mime.rb new file mode 100644 index 0000000000..f6c02c1fd6 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/mime.rb @@ -0,0 +1,685 @@ +# frozen_string_literal: true + +module Rack + module Mime + # Returns String with mime type if found, otherwise use +fallback+. + # +ext+ should be filename extension in the '.ext' format that + # File.extname(file) returns. + # +fallback+ may be any object + # + # Also see the documentation for MIME_TYPES + # + # Usage: + # Rack::Mime.mime_type('.foo') + # + # This is a shortcut for: + # Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream') + + def mime_type(ext, fallback = 'application/octet-stream') + MIME_TYPES.fetch(ext.to_s.downcase, fallback) + end + module_function :mime_type + + # Returns true if the given value is a mime match for the given mime match + # specification, false otherwise. + # + # Rack::Mime.match?('text/html', 'text/*') => true + # Rack::Mime.match?('text/plain', '*') => true + # Rack::Mime.match?('text/html', 'application/json') => false + + def match?(value, matcher) + v1, v2 = value.split('/', 2) + m1, m2 = matcher.split('/', 2) + + (m1 == '*' || v1 == m1) && (m2.nil? || m2 == '*' || m2 == v2) + end + module_function :match? + + # List of most common mime-types, selected various sources + # according to their usefulness in a webserving scope for Ruby + # users. + # + # To amend this list with your local mime.types list you can use: + # + # require 'webrick/httputils' + # list = WEBrick::HTTPUtils.load_mime_types('/etc/mime.types') + # Rack::Mime::MIME_TYPES.merge!(list) + # + # N.B. On Ubuntu the mime.types file does not include the leading period, so + # users may need to modify the data before merging into the hash. + + MIME_TYPES = { + ".123" => "application/vnd.lotus-1-2-3", + ".3dml" => "text/vnd.in3d.3dml", + ".3g2" => "video/3gpp2", + ".3gp" => "video/3gpp", + ".a" => "application/octet-stream", + ".acc" => "application/vnd.americandynamics.acc", + ".ace" => "application/x-ace-compressed", + ".acu" => "application/vnd.acucobol", + ".aep" => "application/vnd.audiograph", + ".afp" => "application/vnd.ibm.modcap", + ".ai" => "application/postscript", + ".aif" => "audio/x-aiff", + ".aiff" => "audio/x-aiff", + ".ami" => "application/vnd.amiga.ami", + ".appcache" => "text/cache-manifest", + ".apr" => "application/vnd.lotus-approach", + ".asc" => "application/pgp-signature", + ".asf" => "video/x-ms-asf", + ".asm" => "text/x-asm", + ".aso" => "application/vnd.accpac.simply.aso", + ".asx" => "video/x-ms-asf", + ".atc" => "application/vnd.acucorp", + ".atom" => "application/atom+xml", + ".atomcat" => "application/atomcat+xml", + ".atomsvc" => "application/atomsvc+xml", + ".atx" => "application/vnd.antix.game-component", + ".au" => "audio/basic", + ".avi" => "video/x-msvideo", + ".bat" => "application/x-msdownload", + ".bcpio" => "application/x-bcpio", + ".bdm" => "application/vnd.syncml.dm+wbxml", + ".bh2" => "application/vnd.fujitsu.oasysprs", + ".bin" => "application/octet-stream", + ".bmi" => "application/vnd.bmi", + ".bmp" => "image/bmp", + ".box" => "application/vnd.previewsystems.box", + ".btif" => "image/prs.btif", + ".bz" => "application/x-bzip", + ".bz2" => "application/x-bzip2", + ".c" => "text/x-c", + ".c4g" => "application/vnd.clonk.c4group", + ".cab" => "application/vnd.ms-cab-compressed", + ".cc" => "text/x-c", + ".ccxml" => "application/ccxml+xml", + ".cdbcmsg" => "application/vnd.contact.cmsg", + ".cdkey" => "application/vnd.mediastation.cdkey", + ".cdx" => "chemical/x-cdx", + ".cdxml" => "application/vnd.chemdraw+xml", + ".cdy" => "application/vnd.cinderella", + ".cer" => "application/pkix-cert", + ".cgm" => "image/cgm", + ".chat" => "application/x-chat", + ".chm" => "application/vnd.ms-htmlhelp", + ".chrt" => "application/vnd.kde.kchart", + ".cif" => "chemical/x-cif", + ".cii" => "application/vnd.anser-web-certificate-issue-initiation", + ".cil" => "application/vnd.ms-artgalry", + ".cla" => "application/vnd.claymore", + ".class" => "application/octet-stream", + ".clkk" => "application/vnd.crick.clicker.keyboard", + ".clkp" => "application/vnd.crick.clicker.palette", + ".clkt" => "application/vnd.crick.clicker.template", + ".clkw" => "application/vnd.crick.clicker.wordbank", + ".clkx" => "application/vnd.crick.clicker", + ".clp" => "application/x-msclip", + ".cmc" => "application/vnd.cosmocaller", + ".cmdf" => "chemical/x-cmdf", + ".cml" => "chemical/x-cml", + ".cmp" => "application/vnd.yellowriver-custom-menu", + ".cmx" => "image/x-cmx", + ".com" => "application/x-msdownload", + ".conf" => "text/plain", + ".cpio" => "application/x-cpio", + ".cpp" => "text/x-c", + ".cpt" => "application/mac-compactpro", + ".crd" => "application/x-mscardfile", + ".crl" => "application/pkix-crl", + ".crt" => "application/x-x509-ca-cert", + ".csh" => "application/x-csh", + ".csml" => "chemical/x-csml", + ".csp" => "application/vnd.commonspace", + ".css" => "text/css", + ".csv" => "text/csv", + ".curl" => "application/vnd.curl", + ".cww" => "application/prs.cww", + ".cxx" => "text/x-c", + ".daf" => "application/vnd.mobius.daf", + ".davmount" => "application/davmount+xml", + ".dcr" => "application/x-director", + ".dd2" => "application/vnd.oma.dd2+xml", + ".ddd" => "application/vnd.fujixerox.ddd", + ".deb" => "application/x-debian-package", + ".der" => "application/x-x509-ca-cert", + ".dfac" => "application/vnd.dreamfactory", + ".diff" => "text/x-diff", + ".dis" => "application/vnd.mobius.dis", + ".djv" => "image/vnd.djvu", + ".djvu" => "image/vnd.djvu", + ".dll" => "application/x-msdownload", + ".dmg" => "application/octet-stream", + ".dna" => "application/vnd.dna", + ".doc" => "application/msword", + ".docm" => "application/vnd.ms-word.document.macroEnabled.12", + ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ".dot" => "application/msword", + ".dotm" => "application/vnd.ms-word.template.macroEnabled.12", + ".dotx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template", + ".dp" => "application/vnd.osgi.dp", + ".dpg" => "application/vnd.dpgraph", + ".dsc" => "text/prs.lines.tag", + ".dtd" => "application/xml-dtd", + ".dts" => "audio/vnd.dts", + ".dtshd" => "audio/vnd.dts.hd", + ".dv" => "video/x-dv", + ".dvi" => "application/x-dvi", + ".dwf" => "model/vnd.dwf", + ".dwg" => "image/vnd.dwg", + ".dxf" => "image/vnd.dxf", + ".dxp" => "application/vnd.spotfire.dxp", + ".ear" => "application/java-archive", + ".ecelp4800" => "audio/vnd.nuera.ecelp4800", + ".ecelp7470" => "audio/vnd.nuera.ecelp7470", + ".ecelp9600" => "audio/vnd.nuera.ecelp9600", + ".ecma" => "application/ecmascript", + ".edm" => "application/vnd.novadigm.edm", + ".edx" => "application/vnd.novadigm.edx", + ".efif" => "application/vnd.picsel", + ".ei6" => "application/vnd.pg.osasli", + ".eml" => "message/rfc822", + ".eol" => "audio/vnd.digital-winds", + ".eot" => "application/vnd.ms-fontobject", + ".eps" => "application/postscript", + ".es3" => "application/vnd.eszigno3+xml", + ".esf" => "application/vnd.epson.esf", + ".etx" => "text/x-setext", + ".exe" => "application/x-msdownload", + ".ext" => "application/vnd.novadigm.ext", + ".ez" => "application/andrew-inset", + ".ez2" => "application/vnd.ezpix-album", + ".ez3" => "application/vnd.ezpix-package", + ".f" => "text/x-fortran", + ".f77" => "text/x-fortran", + ".f90" => "text/x-fortran", + ".fbs" => "image/vnd.fastbidsheet", + ".fdf" => "application/vnd.fdf", + ".fe_launch" => "application/vnd.denovo.fcselayout-link", + ".fg5" => "application/vnd.fujitsu.oasysgp", + ".fli" => "video/x-fli", + ".flo" => "application/vnd.micrografx.flo", + ".flv" => "video/x-flv", + ".flw" => "application/vnd.kde.kivio", + ".flx" => "text/vnd.fmi.flexstor", + ".fly" => "text/vnd.fly", + ".fm" => "application/vnd.framemaker", + ".fnc" => "application/vnd.frogans.fnc", + ".for" => "text/x-fortran", + ".fpx" => "image/vnd.fpx", + ".fsc" => "application/vnd.fsc.weblaunch", + ".fst" => "image/vnd.fst", + ".ftc" => "application/vnd.fluxtime.clip", + ".fti" => "application/vnd.anser-web-funds-transfer-initiation", + ".fvt" => "video/vnd.fvt", + ".fzs" => "application/vnd.fuzzysheet", + ".g3" => "image/g3fax", + ".gac" => "application/vnd.groove-account", + ".gdl" => "model/vnd.gdl", + ".gem" => "application/octet-stream", + ".gemspec" => "text/x-script.ruby", + ".ghf" => "application/vnd.groove-help", + ".gif" => "image/gif", + ".gim" => "application/vnd.groove-identity-message", + ".gmx" => "application/vnd.gmx", + ".gph" => "application/vnd.flographit", + ".gqf" => "application/vnd.grafeq", + ".gram" => "application/srgs", + ".grv" => "application/vnd.groove-injector", + ".grxml" => "application/srgs+xml", + ".gtar" => "application/x-gtar", + ".gtm" => "application/vnd.groove-tool-message", + ".gtw" => "model/vnd.gtw", + ".gv" => "text/vnd.graphviz", + ".gz" => "application/x-gzip", + ".h" => "text/x-c", + ".h261" => "video/h261", + ".h263" => "video/h263", + ".h264" => "video/h264", + ".hbci" => "application/vnd.hbci", + ".hdf" => "application/x-hdf", + ".hh" => "text/x-c", + ".hlp" => "application/winhlp", + ".hpgl" => "application/vnd.hp-hpgl", + ".hpid" => "application/vnd.hp-hpid", + ".hps" => "application/vnd.hp-hps", + ".hqx" => "application/mac-binhex40", + ".htc" => "text/x-component", + ".htke" => "application/vnd.kenameaapp", + ".htm" => "text/html", + ".html" => "text/html", + ".hvd" => "application/vnd.yamaha.hv-dic", + ".hvp" => "application/vnd.yamaha.hv-voice", + ".hvs" => "application/vnd.yamaha.hv-script", + ".icc" => "application/vnd.iccprofile", + ".ice" => "x-conference/x-cooltalk", + ".ico" => "image/vnd.microsoft.icon", + ".ics" => "text/calendar", + ".ief" => "image/ief", + ".ifb" => "text/calendar", + ".ifm" => "application/vnd.shana.informed.formdata", + ".igl" => "application/vnd.igloader", + ".igs" => "model/iges", + ".igx" => "application/vnd.micrografx.igx", + ".iif" => "application/vnd.shana.informed.interchange", + ".imp" => "application/vnd.accpac.simply.imp", + ".ims" => "application/vnd.ms-ims", + ".ipk" => "application/vnd.shana.informed.package", + ".irm" => "application/vnd.ibm.rights-management", + ".irp" => "application/vnd.irepository.package+xml", + ".iso" => "application/octet-stream", + ".itp" => "application/vnd.shana.informed.formtemplate", + ".ivp" => "application/vnd.immervision-ivp", + ".ivu" => "application/vnd.immervision-ivu", + ".jad" => "text/vnd.sun.j2me.app-descriptor", + ".jam" => "application/vnd.jam", + ".jar" => "application/java-archive", + ".java" => "text/x-java-source", + ".jisp" => "application/vnd.jisp", + ".jlt" => "application/vnd.hp-jlyt", + ".jnlp" => "application/x-java-jnlp-file", + ".joda" => "application/vnd.joost.joda-archive", + ".jp2" => "image/jp2", + ".jpeg" => "image/jpeg", + ".jpg" => "image/jpeg", + ".jpgv" => "video/jpeg", + ".jpm" => "video/jpm", + ".js" => "application/javascript", + ".json" => "application/json", + ".karbon" => "application/vnd.kde.karbon", + ".kfo" => "application/vnd.kde.kformula", + ".kia" => "application/vnd.kidspiration", + ".kml" => "application/vnd.google-earth.kml+xml", + ".kmz" => "application/vnd.google-earth.kmz", + ".kne" => "application/vnd.kinar", + ".kon" => "application/vnd.kde.kontour", + ".kpr" => "application/vnd.kde.kpresenter", + ".ksp" => "application/vnd.kde.kspread", + ".ktz" => "application/vnd.kahootz", + ".kwd" => "application/vnd.kde.kword", + ".latex" => "application/x-latex", + ".lbd" => "application/vnd.llamagraphics.life-balance.desktop", + ".lbe" => "application/vnd.llamagraphics.life-balance.exchange+xml", + ".les" => "application/vnd.hhe.lesson-player", + ".link66" => "application/vnd.route66.link66+xml", + ".log" => "text/plain", + ".lostxml" => "application/lost+xml", + ".lrm" => "application/vnd.ms-lrm", + ".ltf" => "application/vnd.frogans.ltf", + ".lvp" => "audio/vnd.lucent.voice", + ".lwp" => "application/vnd.lotus-wordpro", + ".m3u" => "audio/x-mpegurl", + ".m3u8" => "application/x-mpegurl", + ".m4a" => "audio/mp4a-latm", + ".m4v" => "video/mp4", + ".ma" => "application/mathematica", + ".mag" => "application/vnd.ecowin.chart", + ".man" => "text/troff", + ".manifest" => "text/cache-manifest", + ".mathml" => "application/mathml+xml", + ".mbk" => "application/vnd.mobius.mbk", + ".mbox" => "application/mbox", + ".mc1" => "application/vnd.medcalcdata", + ".mcd" => "application/vnd.mcd", + ".mdb" => "application/x-msaccess", + ".mdi" => "image/vnd.ms-modi", + ".mdoc" => "text/troff", + ".me" => "text/troff", + ".mfm" => "application/vnd.mfmp", + ".mgz" => "application/vnd.proteus.magazine", + ".mid" => "audio/midi", + ".midi" => "audio/midi", + ".mif" => "application/vnd.mif", + ".mime" => "message/rfc822", + ".mj2" => "video/mj2", + ".mlp" => "application/vnd.dolby.mlp", + ".mmd" => "application/vnd.chipnuts.karaoke-mmd", + ".mmf" => "application/vnd.smaf", + ".mml" => "application/mathml+xml", + ".mmr" => "image/vnd.fujixerox.edmics-mmr", + ".mng" => "video/x-mng", + ".mny" => "application/x-msmoney", + ".mov" => "video/quicktime", + ".movie" => "video/x-sgi-movie", + ".mp3" => "audio/mpeg", + ".mp4" => "video/mp4", + ".mp4a" => "audio/mp4", + ".mp4s" => "application/mp4", + ".mp4v" => "video/mp4", + ".mpc" => "application/vnd.mophun.certificate", + ".mpd" => "application/dash+xml", + ".mpeg" => "video/mpeg", + ".mpg" => "video/mpeg", + ".mpga" => "audio/mpeg", + ".mpkg" => "application/vnd.apple.installer+xml", + ".mpm" => "application/vnd.blueice.multipass", + ".mpn" => "application/vnd.mophun.application", + ".mpp" => "application/vnd.ms-project", + ".mpy" => "application/vnd.ibm.minipay", + ".mqy" => "application/vnd.mobius.mqy", + ".mrc" => "application/marc", + ".ms" => "text/troff", + ".mscml" => "application/mediaservercontrol+xml", + ".mseq" => "application/vnd.mseq", + ".msf" => "application/vnd.epson.msf", + ".msh" => "model/mesh", + ".msi" => "application/x-msdownload", + ".msl" => "application/vnd.mobius.msl", + ".msty" => "application/vnd.muvee.style", + ".mts" => "model/vnd.mts", + ".mus" => "application/vnd.musician", + ".mvb" => "application/x-msmediaview", + ".mwf" => "application/vnd.mfer", + ".mxf" => "application/mxf", + ".mxl" => "application/vnd.recordare.musicxml", + ".mxml" => "application/xv+xml", + ".mxs" => "application/vnd.triscape.mxs", + ".mxu" => "video/vnd.mpegurl", + ".n" => "application/vnd.nokia.n-gage.symbian.install", + ".nc" => "application/x-netcdf", + ".ngdat" => "application/vnd.nokia.n-gage.data", + ".nlu" => "application/vnd.neurolanguage.nlu", + ".nml" => "application/vnd.enliven", + ".nnd" => "application/vnd.noblenet-directory", + ".nns" => "application/vnd.noblenet-sealer", + ".nnw" => "application/vnd.noblenet-web", + ".npx" => "image/vnd.net-fpx", + ".nsf" => "application/vnd.lotus-notes", + ".oa2" => "application/vnd.fujitsu.oasys2", + ".oa3" => "application/vnd.fujitsu.oasys3", + ".oas" => "application/vnd.fujitsu.oasys", + ".obd" => "application/x-msbinder", + ".oda" => "application/oda", + ".odc" => "application/vnd.oasis.opendocument.chart", + ".odf" => "application/vnd.oasis.opendocument.formula", + ".odg" => "application/vnd.oasis.opendocument.graphics", + ".odi" => "application/vnd.oasis.opendocument.image", + ".odp" => "application/vnd.oasis.opendocument.presentation", + ".ods" => "application/vnd.oasis.opendocument.spreadsheet", + ".odt" => "application/vnd.oasis.opendocument.text", + ".oga" => "audio/ogg", + ".ogg" => "application/ogg", + ".ogv" => "video/ogg", + ".ogx" => "application/ogg", + ".org" => "application/vnd.lotus-organizer", + ".otc" => "application/vnd.oasis.opendocument.chart-template", + ".otf" => "application/vnd.oasis.opendocument.formula-template", + ".otg" => "application/vnd.oasis.opendocument.graphics-template", + ".oth" => "application/vnd.oasis.opendocument.text-web", + ".oti" => "application/vnd.oasis.opendocument.image-template", + ".otm" => "application/vnd.oasis.opendocument.text-master", + ".ots" => "application/vnd.oasis.opendocument.spreadsheet-template", + ".ott" => "application/vnd.oasis.opendocument.text-template", + ".oxt" => "application/vnd.openofficeorg.extension", + ".p" => "text/x-pascal", + ".p10" => "application/pkcs10", + ".p12" => "application/x-pkcs12", + ".p7b" => "application/x-pkcs7-certificates", + ".p7m" => "application/pkcs7-mime", + ".p7r" => "application/x-pkcs7-certreqresp", + ".p7s" => "application/pkcs7-signature", + ".pas" => "text/x-pascal", + ".pbd" => "application/vnd.powerbuilder6", + ".pbm" => "image/x-portable-bitmap", + ".pcl" => "application/vnd.hp-pcl", + ".pclxl" => "application/vnd.hp-pclxl", + ".pcx" => "image/x-pcx", + ".pdb" => "chemical/x-pdb", + ".pdf" => "application/pdf", + ".pem" => "application/x-x509-ca-cert", + ".pfr" => "application/font-tdpfr", + ".pgm" => "image/x-portable-graymap", + ".pgn" => "application/x-chess-pgn", + ".pgp" => "application/pgp-encrypted", + ".pic" => "image/x-pict", + ".pict" => "image/pict", + ".pkg" => "application/octet-stream", + ".pki" => "application/pkixcmp", + ".pkipath" => "application/pkix-pkipath", + ".pl" => "text/x-script.perl", + ".plb" => "application/vnd.3gpp.pic-bw-large", + ".plc" => "application/vnd.mobius.plc", + ".plf" => "application/vnd.pocketlearn", + ".pls" => "application/pls+xml", + ".pm" => "text/x-script.perl-module", + ".pml" => "application/vnd.ctc-posml", + ".png" => "image/png", + ".pnm" => "image/x-portable-anymap", + ".pntg" => "image/x-macpaint", + ".portpkg" => "application/vnd.macports.portpkg", + ".pot" => "application/vnd.ms-powerpoint", + ".potm" => "application/vnd.ms-powerpoint.template.macroEnabled.12", + ".potx" => "application/vnd.openxmlformats-officedocument.presentationml.template", + ".ppa" => "application/vnd.ms-powerpoint", + ".ppam" => "application/vnd.ms-powerpoint.addin.macroEnabled.12", + ".ppd" => "application/vnd.cups-ppd", + ".ppm" => "image/x-portable-pixmap", + ".pps" => "application/vnd.ms-powerpoint", + ".ppsm" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", + ".ppsx" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow", + ".ppt" => "application/vnd.ms-powerpoint", + ".pptm" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12", + ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", + ".prc" => "application/vnd.palm", + ".pre" => "application/vnd.lotus-freelance", + ".prf" => "application/pics-rules", + ".ps" => "application/postscript", + ".psb" => "application/vnd.3gpp.pic-bw-small", + ".psd" => "image/vnd.adobe.photoshop", + ".ptid" => "application/vnd.pvi.ptid1", + ".pub" => "application/x-mspublisher", + ".pvb" => "application/vnd.3gpp.pic-bw-var", + ".pwn" => "application/vnd.3m.post-it-notes", + ".py" => "text/x-script.python", + ".pya" => "audio/vnd.ms-playready.media.pya", + ".pyv" => "video/vnd.ms-playready.media.pyv", + ".qam" => "application/vnd.epson.quickanime", + ".qbo" => "application/vnd.intu.qbo", + ".qfx" => "application/vnd.intu.qfx", + ".qps" => "application/vnd.publishare-delta-tree", + ".qt" => "video/quicktime", + ".qtif" => "image/x-quicktime", + ".qxd" => "application/vnd.quark.quarkxpress", + ".ra" => "audio/x-pn-realaudio", + ".rake" => "text/x-script.ruby", + ".ram" => "audio/x-pn-realaudio", + ".rar" => "application/x-rar-compressed", + ".ras" => "image/x-cmu-raster", + ".rb" => "text/x-script.ruby", + ".rcprofile" => "application/vnd.ipunplugged.rcprofile", + ".rdf" => "application/rdf+xml", + ".rdz" => "application/vnd.data-vision.rdz", + ".rep" => "application/vnd.businessobjects", + ".rgb" => "image/x-rgb", + ".rif" => "application/reginfo+xml", + ".rl" => "application/resource-lists+xml", + ".rlc" => "image/vnd.fujixerox.edmics-rlc", + ".rld" => "application/resource-lists-diff+xml", + ".rm" => "application/vnd.rn-realmedia", + ".rmp" => "audio/x-pn-realaudio-plugin", + ".rms" => "application/vnd.jcp.javame.midlet-rms", + ".rnc" => "application/relax-ng-compact-syntax", + ".roff" => "text/troff", + ".rpm" => "application/x-redhat-package-manager", + ".rpss" => "application/vnd.nokia.radio-presets", + ".rpst" => "application/vnd.nokia.radio-preset", + ".rq" => "application/sparql-query", + ".rs" => "application/rls-services+xml", + ".rsd" => "application/rsd+xml", + ".rss" => "application/rss+xml", + ".rtf" => "application/rtf", + ".rtx" => "text/richtext", + ".ru" => "text/x-script.ruby", + ".s" => "text/x-asm", + ".saf" => "application/vnd.yamaha.smaf-audio", + ".sbml" => "application/sbml+xml", + ".sc" => "application/vnd.ibm.secure-container", + ".scd" => "application/x-msschedule", + ".scm" => "application/vnd.lotus-screencam", + ".scq" => "application/scvp-cv-request", + ".scs" => "application/scvp-cv-response", + ".sdkm" => "application/vnd.solent.sdkm+xml", + ".sdp" => "application/sdp", + ".see" => "application/vnd.seemail", + ".sema" => "application/vnd.sema", + ".semd" => "application/vnd.semd", + ".semf" => "application/vnd.semf", + ".setpay" => "application/set-payment-initiation", + ".setreg" => "application/set-registration-initiation", + ".sfd" => "application/vnd.hydrostatix.sof-data", + ".sfs" => "application/vnd.spotfire.sfs", + ".sgm" => "text/sgml", + ".sgml" => "text/sgml", + ".sh" => "application/x-sh", + ".shar" => "application/x-shar", + ".shf" => "application/shf+xml", + ".sig" => "application/pgp-signature", + ".sit" => "application/x-stuffit", + ".sitx" => "application/x-stuffitx", + ".skp" => "application/vnd.koan", + ".slt" => "application/vnd.epson.salt", + ".smi" => "application/smil+xml", + ".snd" => "audio/basic", + ".so" => "application/octet-stream", + ".spf" => "application/vnd.yamaha.smaf-phrase", + ".spl" => "application/x-futuresplash", + ".spot" => "text/vnd.in3d.spot", + ".spp" => "application/scvp-vp-response", + ".spq" => "application/scvp-vp-request", + ".src" => "application/x-wais-source", + ".srt" => "text/srt", + ".srx" => "application/sparql-results+xml", + ".sse" => "application/vnd.kodak-descriptor", + ".ssf" => "application/vnd.epson.ssf", + ".ssml" => "application/ssml+xml", + ".stf" => "application/vnd.wt.stf", + ".stk" => "application/hyperstudio", + ".str" => "application/vnd.pg.format", + ".sus" => "application/vnd.sus-calendar", + ".sv4cpio" => "application/x-sv4cpio", + ".sv4crc" => "application/x-sv4crc", + ".svd" => "application/vnd.svd", + ".svg" => "image/svg+xml", + ".svgz" => "image/svg+xml", + ".swf" => "application/x-shockwave-flash", + ".swi" => "application/vnd.arastra.swi", + ".t" => "text/troff", + ".tao" => "application/vnd.tao.intent-module-archive", + ".tar" => "application/x-tar", + ".tbz" => "application/x-bzip-compressed-tar", + ".tcap" => "application/vnd.3gpp2.tcap", + ".tcl" => "application/x-tcl", + ".tex" => "application/x-tex", + ".texi" => "application/x-texinfo", + ".texinfo" => "application/x-texinfo", + ".text" => "text/plain", + ".tif" => "image/tiff", + ".tiff" => "image/tiff", + ".tmo" => "application/vnd.tmobile-livetv", + ".torrent" => "application/x-bittorrent", + ".tpl" => "application/vnd.groove-tool-template", + ".tpt" => "application/vnd.trid.tpt", + ".tr" => "text/troff", + ".tra" => "application/vnd.trueapp", + ".trm" => "application/x-msterminal", + ".ts" => "video/mp2t", + ".tsv" => "text/tab-separated-values", + ".ttf" => "application/octet-stream", + ".twd" => "application/vnd.simtech-mindmapper", + ".txd" => "application/vnd.genomatix.tuxedo", + ".txf" => "application/vnd.mobius.txf", + ".txt" => "text/plain", + ".ufd" => "application/vnd.ufdl", + ".umj" => "application/vnd.umajin", + ".unityweb" => "application/vnd.unity", + ".uoml" => "application/vnd.uoml+xml", + ".uri" => "text/uri-list", + ".ustar" => "application/x-ustar", + ".utz" => "application/vnd.uiq.theme", + ".uu" => "text/x-uuencode", + ".vcd" => "application/x-cdlink", + ".vcf" => "text/x-vcard", + ".vcg" => "application/vnd.groove-vcard", + ".vcs" => "text/x-vcalendar", + ".vcx" => "application/vnd.vcx", + ".vis" => "application/vnd.visionary", + ".viv" => "video/vnd.vivo", + ".vrml" => "model/vrml", + ".vsd" => "application/vnd.visio", + ".vsf" => "application/vnd.vsf", + ".vtt" => "text/vtt", + ".vtu" => "model/vnd.vtu", + ".vxml" => "application/voicexml+xml", + ".war" => "application/java-archive", + ".wasm" => "application/wasm", + ".wav" => "audio/x-wav", + ".wax" => "audio/x-ms-wax", + ".wbmp" => "image/vnd.wap.wbmp", + ".wbs" => "application/vnd.criticaltools.wbs+xml", + ".wbxml" => "application/vnd.wap.wbxml", + ".webm" => "video/webm", + ".wm" => "video/x-ms-wm", + ".wma" => "audio/x-ms-wma", + ".wmd" => "application/x-ms-wmd", + ".wmf" => "application/x-msmetafile", + ".wml" => "text/vnd.wap.wml", + ".wmlc" => "application/vnd.wap.wmlc", + ".wmls" => "text/vnd.wap.wmlscript", + ".wmlsc" => "application/vnd.wap.wmlscriptc", + ".wmv" => "video/x-ms-wmv", + ".wmx" => "video/x-ms-wmx", + ".wmz" => "application/x-ms-wmz", + ".woff" => "application/font-woff", + ".woff2" => "application/font-woff2", + ".wpd" => "application/vnd.wordperfect", + ".wpl" => "application/vnd.ms-wpl", + ".wps" => "application/vnd.ms-works", + ".wqd" => "application/vnd.wqd", + ".wri" => "application/x-mswrite", + ".wrl" => "model/vrml", + ".wsdl" => "application/wsdl+xml", + ".wspolicy" => "application/wspolicy+xml", + ".wtb" => "application/vnd.webturbo", + ".wvx" => "video/x-ms-wvx", + ".x3d" => "application/vnd.hzn-3d-crossword", + ".xar" => "application/vnd.xara", + ".xbd" => "application/vnd.fujixerox.docuworks.binder", + ".xbm" => "image/x-xbitmap", + ".xdm" => "application/vnd.syncml.dm+xml", + ".xdp" => "application/vnd.adobe.xdp+xml", + ".xdw" => "application/vnd.fujixerox.docuworks", + ".xenc" => "application/xenc+xml", + ".xer" => "application/patch-ops-error+xml", + ".xfdf" => "application/vnd.adobe.xfdf", + ".xfdl" => "application/vnd.xfdl", + ".xhtml" => "application/xhtml+xml", + ".xif" => "image/vnd.xiff", + ".xla" => "application/vnd.ms-excel", + ".xlam" => "application/vnd.ms-excel.addin.macroEnabled.12", + ".xls" => "application/vnd.ms-excel", + ".xlsb" => "application/vnd.ms-excel.sheet.binary.macroEnabled.12", + ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ".xlsm" => "application/vnd.ms-excel.sheet.macroEnabled.12", + ".xlt" => "application/vnd.ms-excel", + ".xltx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template", + ".xml" => "application/xml", + ".xo" => "application/vnd.olpc-sugar", + ".xop" => "application/xop+xml", + ".xpm" => "image/x-xpixmap", + ".xpr" => "application/vnd.is-xpr", + ".xps" => "application/vnd.ms-xpsdocument", + ".xpw" => "application/vnd.intercon.formnet", + ".xsl" => "application/xml", + ".xslt" => "application/xslt+xml", + ".xsm" => "application/vnd.syncml+xml", + ".xspf" => "application/xspf+xml", + ".xul" => "application/vnd.mozilla.xul+xml", + ".xwd" => "image/x-xwindowdump", + ".xyz" => "chemical/x-xyz", + ".yaml" => "text/yaml", + ".yml" => "text/yaml", + ".zaz" => "application/vnd.zzazz.deck+xml", + ".zip" => "application/zip", + ".zmm" => "application/vnd.handheld-entertainment+xml", + } + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/mock.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/mock.rb new file mode 100644 index 0000000000..5b2512ca09 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/mock.rb @@ -0,0 +1,273 @@ +# frozen_string_literal: true + +require 'uri' +require 'stringio' +require_relative '../rack' +require 'cgi/cookie' + +module Rack + # Rack::MockRequest helps testing your Rack application without + # actually using HTTP. + # + # After performing a request on a URL with get/post/put/patch/delete, it + # returns a MockResponse with useful helper methods for effective + # testing. + # + # You can pass a hash with additional configuration to the + # get/post/put/patch/delete. + # :input:: A String or IO-like to be used as rack.input. + # :fatal:: Raise a FatalWarning if the app writes to rack.errors. + # :lint:: If true, wrap the application in a Rack::Lint. + + class MockRequest + class FatalWarning < RuntimeError + end + + class FatalWarner + def puts(warning) + raise FatalWarning, warning + end + + def write(warning) + raise FatalWarning, warning + end + + def flush + end + + def string + "" + end + end + + DEFAULT_ENV = { + RACK_VERSION => Rack::VERSION, + RACK_INPUT => StringIO.new, + RACK_ERRORS => StringIO.new, + RACK_MULTITHREAD => true, + RACK_MULTIPROCESS => true, + RACK_RUNONCE => false, + }.freeze + + def initialize(app) + @app = app + end + + # Make a GET request and return a MockResponse. See #request. + def get(uri, opts = {}) request(GET, uri, opts) end + # Make a POST request and return a MockResponse. See #request. + def post(uri, opts = {}) request(POST, uri, opts) end + # Make a PUT request and return a MockResponse. See #request. + def put(uri, opts = {}) request(PUT, uri, opts) end + # Make a PATCH request and return a MockResponse. See #request. + def patch(uri, opts = {}) request(PATCH, uri, opts) end + # Make a DELETE request and return a MockResponse. See #request. + def delete(uri, opts = {}) request(DELETE, uri, opts) end + # Make a HEAD request and return a MockResponse. See #request. + def head(uri, opts = {}) request(HEAD, uri, opts) end + # Make an OPTIONS request and return a MockResponse. See #request. + def options(uri, opts = {}) request(OPTIONS, uri, opts) end + + # Make a request using the given request method for the given + # uri to the rack application and return a MockResponse. + # Options given are passed to MockRequest.env_for. + def request(method = GET, uri = "", opts = {}) + env = self.class.env_for(uri, opts.merge(method: method)) + + if opts[:lint] + app = Rack::Lint.new(@app) + else + app = @app + end + + errors = env[RACK_ERRORS] + status, headers, body = app.call(env) + MockResponse.new(status, headers, body, errors) + ensure + body.close if body.respond_to?(:close) + end + + # For historical reasons, we're pinning to RFC 2396. + # URI::Parser = URI::RFC2396_Parser + def self.parse_uri_rfc2396(uri) + @parser ||= URI::Parser.new + @parser.parse(uri) + end + + # Return the Rack environment used for a request to +uri+. + # All options that are strings are added to the returned environment. + # Options: + # :fatal :: Whether to raise an exception if request outputs to rack.errors + # :input :: The rack.input to set + # :method :: The HTTP request method to use + # :params :: The params to use + # :script_name :: The SCRIPT_NAME to set + def self.env_for(uri = "", opts = {}) + uri = parse_uri_rfc2396(uri) + uri.path = "/#{uri.path}" unless uri.path[0] == ?/ + + env = DEFAULT_ENV.dup + + env[REQUEST_METHOD] = (opts[:method] ? opts[:method].to_s.upcase : GET).b + env[SERVER_NAME] = (uri.host || "example.org").b + env[SERVER_PORT] = (uri.port ? uri.port.to_s : "80").b + env[QUERY_STRING] = (uri.query.to_s).b + env[PATH_INFO] = ((!uri.path || uri.path.empty?) ? "/" : uri.path).b + env[RACK_URL_SCHEME] = (uri.scheme || "http").b + env[HTTPS] = (env[RACK_URL_SCHEME] == "https" ? "on" : "off").b + + env[SCRIPT_NAME] = opts[:script_name] || "" + + if opts[:fatal] + env[RACK_ERRORS] = FatalWarner.new + else + env[RACK_ERRORS] = StringIO.new + end + + if params = opts[:params] + if env[REQUEST_METHOD] == GET + params = Utils.parse_nested_query(params) if params.is_a?(String) + params.update(Utils.parse_nested_query(env[QUERY_STRING])) + env[QUERY_STRING] = Utils.build_nested_query(params) + elsif !opts.has_key?(:input) + opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" + if params.is_a?(Hash) + if data = Rack::Multipart.build_multipart(params) + opts[:input] = data + opts["CONTENT_LENGTH"] ||= data.length.to_s + opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Rack::Multipart::MULTIPART_BOUNDARY}" + else + opts[:input] = Utils.build_nested_query(params) + end + else + opts[:input] = params + end + end + end + + empty_str = String.new + opts[:input] ||= empty_str + if String === opts[:input] + rack_input = StringIO.new(opts[:input]) + else + rack_input = opts[:input] + end + + rack_input.set_encoding(Encoding::BINARY) + env[RACK_INPUT] = rack_input + + env["CONTENT_LENGTH"] ||= env[RACK_INPUT].size.to_s if env[RACK_INPUT].respond_to?(:size) + + opts.each { |field, value| + env[field] = value if String === field + } + + env + end + end + + # Rack::MockResponse provides useful helpers for testing your apps. + # Usually, you don't create the MockResponse on your own, but use + # MockRequest. + + class MockResponse < Rack::Response + class << self + alias [] new + end + + # Headers + attr_reader :original_headers, :cookies + + # Errors + attr_accessor :errors + + def initialize(status, headers, body, errors = StringIO.new("")) + @original_headers = headers + @errors = errors.string if errors.respond_to?(:string) + @cookies = parse_cookies_from_header + + super(body, status, headers) + + buffered_body! + end + + def =~(other) + body =~ other + end + + def match(other) + body.match other + end + + def body + # FIXME: apparently users of MockResponse expect the return value of + # MockResponse#body to be a string. However, the real response object + # returns the body as a list. + # + # See spec_showstatus.rb: + # + # should "not replace existing messages" do + # ... + # res.body.should == "foo!" + # end + buffer = String.new + + super.each do |chunk| + buffer << chunk + end + + return buffer + end + + def empty? + [201, 204, 304].include? status + end + + def cookie(name) + cookies.fetch(name, nil) + end + + private + + def parse_cookies_from_header + cookies = Hash.new + if original_headers.has_key? 'Set-Cookie' + set_cookie_header = original_headers.fetch('Set-Cookie') + set_cookie_header.split("\n").each do |cookie| + cookie_name, cookie_filling = cookie.split('=', 2) + cookie_attributes = identify_cookie_attributes cookie_filling + parsed_cookie = CGI::Cookie.new( + 'name' => cookie_name.strip, + 'value' => cookie_attributes.fetch('value'), + 'path' => cookie_attributes.fetch('path', nil), + 'domain' => cookie_attributes.fetch('domain', nil), + 'expires' => cookie_attributes.fetch('expires', nil), + 'secure' => cookie_attributes.fetch('secure', false) + ) + cookies.store(cookie_name, parsed_cookie) + end + end + cookies + end + + def identify_cookie_attributes(cookie_filling) + cookie_bits = cookie_filling.split(';') + cookie_attributes = Hash.new + cookie_attributes.store('value', cookie_bits[0].strip) + cookie_bits.each do |bit| + if bit.include? '=' + cookie_attribute, attribute_value = bit.split('=') + cookie_attributes.store(cookie_attribute.strip, attribute_value.strip) + if cookie_attribute.include? 'max-age' + cookie_attributes.store('expires', Time.now + attribute_value.strip.to_i) + end + end + if bit.include? 'secure' + cookie_attributes.store('secure', true) + end + end + cookie_attributes + end + + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart.rb new file mode 100644 index 0000000000..45f43bb68f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require_relative 'multipart/parser' + +module Rack + # A multipart form data parser, adapted from IOWA. + # + # Usually, Rack::Request#POST takes care of calling this. + module Multipart + autoload :UploadedFile, 'rack/multipart/uploaded_file' + autoload :Generator, 'rack/multipart/generator' + + EOL = "\r\n" + MULTIPART_BOUNDARY = "AaB03x" + MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|ni + TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/ + CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i + VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/ + BROKEN_QUOTED = /^#{CONDISP}.*;\s*filename="(.*?)"(?:\s*$|\s*;\s*#{TOKEN}=)/i + BROKEN_UNQUOTED = /^#{CONDISP}.*;\s*filename=(#{TOKEN})/i + MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni + MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:.*;\s*name=(#{VALUE})/ni + MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni + # Updated definitions from RFC 2231 + ATTRIBUTE_CHAR = %r{[^ \t\v\n\r)(><@,;:\\"/\[\]?='*%]} + ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/ + SECTION = /\*[0-9]+/ + REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/ + REGULAR_PARAMETER = /(#{REGULAR_PARAMETER_NAME})=(#{VALUE})/ + EXTENDED_OTHER_NAME = /#{ATTRIBUTE}\*[1-9][0-9]*\*/ + EXTENDED_OTHER_VALUE = /%[0-9a-fA-F]{2}|#{ATTRIBUTE_CHAR}/ + EXTENDED_OTHER_PARAMETER = /(#{EXTENDED_OTHER_NAME})=(#{EXTENDED_OTHER_VALUE}*)/ + EXTENDED_INITIAL_NAME = /#{ATTRIBUTE}(?:\*0)?\*/ + EXTENDED_INITIAL_VALUE = /[a-zA-Z0-9\-]*'[a-zA-Z0-9\-]*'#{EXTENDED_OTHER_VALUE}*/ + EXTENDED_INITIAL_PARAMETER = /(#{EXTENDED_INITIAL_NAME})=(#{EXTENDED_INITIAL_VALUE})/ + EXTENDED_PARAMETER = /#{EXTENDED_INITIAL_PARAMETER}|#{EXTENDED_OTHER_PARAMETER}/ + DISPPARM = /;\s*(?:#{REGULAR_PARAMETER}|#{EXTENDED_PARAMETER})\s*/ + RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i + + class << self + def parse_multipart(env, params = Rack::Utils.default_query_parser) + extract_multipart Rack::Request.new(env), params + end + + def extract_multipart(req, params = Rack::Utils.default_query_parser) + io = req.get_header(RACK_INPUT) + io.rewind + content_length = req.content_length + content_length = content_length.to_i if content_length + + tempfile = req.get_header(RACK_MULTIPART_TEMPFILE_FACTORY) || Parser::TEMPFILE_FACTORY + bufsize = req.get_header(RACK_MULTIPART_BUFFER_SIZE) || Parser::BUFSIZE + + info = Parser.parse io, content_length, req.get_header('CONTENT_TYPE'), tempfile, bufsize, params + req.set_header(RACK_TEMPFILES, info.tmp_files) + info.params + end + + def build_multipart(params, first = true) + Generator.new(params, first).dump + end + end + + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart/generator.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart/generator.rb new file mode 100644 index 0000000000..f798a98c51 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart/generator.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +module Rack + module Multipart + class Generator + def initialize(params, first = true) + @params, @first = params, first + + if @first && !@params.is_a?(Hash) + raise ArgumentError, "value must be a Hash" + end + end + + def dump + return nil if @first && !multipart? + return flattened_params unless @first + + flattened_params.map do |name, file| + if file.respond_to?(:original_filename) + if file.path + ::File.open(file.path, 'rb') do |f| + f.set_encoding(Encoding::BINARY) + content_for_tempfile(f, file, name) + end + else + content_for_tempfile(file, file, name) + end + else + content_for_other(file, name) + end + end.join << "--#{MULTIPART_BOUNDARY}--\r" + end + + private + def multipart? + query = lambda { |value| + case value + when Array + value.any?(&query) + when Hash + value.values.any?(&query) + when Rack::Multipart::UploadedFile + true + end + } + + @params.values.any?(&query) + end + + def flattened_params + @flattened_params ||= begin + h = Hash.new + @params.each do |key, value| + k = @first ? key.to_s : "[#{key}]" + + case value + when Array + value.map { |v| + Multipart.build_multipart(v, false).each { |subkey, subvalue| + h["#{k}[]#{subkey}"] = subvalue + } + } + when Hash + Multipart.build_multipart(value, false).each { |subkey, subvalue| + h[k + subkey] = subvalue + } + else + h[k] = value + end + end + h + end + end + + def content_for_tempfile(io, file, name) + length = ::File.stat(file.path).size if file.path + filename = "; filename=\"#{Utils.escape(file.original_filename)}\"" if file.original_filename +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"#{filename}\r +Content-Type: #{file.content_type}\r +#{"Content-Length: #{length}\r\n" if length}\r +#{io.read}\r +EOF + end + + def content_for_other(file, name) +<<-EOF +--#{MULTIPART_BOUNDARY}\r +Content-Disposition: form-data; name="#{name}"\r +\r +#{file}\r +EOF + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart/parser.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart/parser.rb new file mode 100644 index 0000000000..2eb38380b0 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart/parser.rb @@ -0,0 +1,364 @@ +# frozen_string_literal: true + +require 'strscan' + +module Rack + module Multipart + class MultipartPartLimitError < Errno::EMFILE; end + + class Parser + (require_relative '../core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4' + + BUFSIZE = 1_048_576 + TEXT_PLAIN = "text/plain" + TEMPFILE_FACTORY = lambda { |filename, content_type| + Tempfile.new(["RackMultipart", ::File.extname(filename.gsub("\0", '%00'))]) + } + + BOUNDARY_REGEX = /\A([^\n]*(?:\n|\Z))/ + + class BoundedIO # :nodoc: + def initialize(io, content_length) + @io = io + @content_length = content_length + @cursor = 0 + end + + def read(size, outbuf = nil) + return if @cursor >= @content_length + + left = @content_length - @cursor + + str = if left < size + @io.read left, outbuf + else + @io.read size, outbuf + end + + if str + @cursor += str.bytesize + else + # Raise an error for mismatching Content-Length and actual contents + raise EOFError, "bad content body" + end + + str + end + + def rewind + @io.rewind + end + end + + MultipartInfo = Struct.new :params, :tmp_files + EMPTY = MultipartInfo.new(nil, []) + + def self.parse_boundary(content_type) + return unless content_type + data = content_type.match(MULTIPART) + return unless data + data[1] + end + + def self.parse(io, content_length, content_type, tmpfile, bufsize, qp) + return EMPTY if 0 == content_length + + boundary = parse_boundary content_type + return EMPTY unless boundary + + io = BoundedIO.new(io, content_length) if content_length + outbuf = String.new + + parser = new(boundary, tmpfile, bufsize, qp) + parser.on_read io.read(bufsize, outbuf) + + loop do + break if parser.state == :DONE + parser.on_read io.read(bufsize, outbuf) + end + + io.rewind + parser.result + end + + class Collector + class MimePart < Struct.new(:body, :head, :filename, :content_type, :name) + def get_data + data = body + if filename == "" + # filename is blank which means no file has been selected + return + elsif filename + body.rewind if body.respond_to?(:rewind) + + # Take the basename of the upload's original filename. + # This handles the full Windows paths given by Internet Explorer + # (and perhaps other broken user agents) without affecting + # those which give the lone filename. + fn = filename.split(/[\/\\]/).last + + data = { filename: fn, type: content_type, + name: name, tempfile: body, head: head } + end + + yield data + end + end + + class BufferPart < MimePart + def file?; false; end + def close; end + end + + class TempfilePart < MimePart + def file?; true; end + def close; body.close; end + end + + include Enumerable + + def initialize(tempfile) + @tempfile = tempfile + @mime_parts = [] + @open_files = 0 + end + + def each + @mime_parts.each { |part| yield part } + end + + def on_mime_head(mime_index, head, filename, content_type, name) + if filename + body = @tempfile.call(filename, content_type) + body.binmode if body.respond_to?(:binmode) + klass = TempfilePart + @open_files += 1 + else + body = String.new + klass = BufferPart + end + + @mime_parts[mime_index] = klass.new(body, head, filename, content_type, name) + + check_open_files + end + + def on_mime_body(mime_index, content) + @mime_parts[mime_index].body << content + end + + def on_mime_finish(mime_index) + end + + private + + def check_open_files + if Utils.multipart_part_limit > 0 + if @open_files >= Utils.multipart_part_limit + @mime_parts.each(&:close) + raise MultipartPartLimitError, 'Maximum file multiparts in content reached' + end + end + end + end + + attr_reader :state + + def initialize(boundary, tempfile, bufsize, query_parser) + @query_parser = query_parser + @params = query_parser.make_params + @boundary = "--#{boundary}" + @bufsize = bufsize + + @full_boundary = @boundary + @end_boundary = @boundary + '--' + @state = :FAST_FORWARD + @mime_index = 0 + @collector = Collector.new tempfile + + @sbuf = StringScanner.new("".dup) + @body_regex = /(?:#{EOL})?#{Regexp.quote(@boundary)}(?:#{EOL}|--)/m + @rx_max_size = EOL.size + @boundary.bytesize + [EOL.size, '--'.size].max + @head_regex = /(.*?#{EOL})#{EOL}/m + end + + def on_read(content) + handle_empty_content!(content) + @sbuf.concat content + run_parser + end + + def result + @collector.each do |part| + part.get_data do |data| + tag_multipart_encoding(part.filename, part.content_type, part.name, data) + @query_parser.normalize_params(@params, part.name, data, @query_parser.param_depth_limit) + end + end + MultipartInfo.new @params.to_params_hash, @collector.find_all(&:file?).map(&:body) + end + + private + + def run_parser + loop do + case @state + when :FAST_FORWARD + break if handle_fast_forward == :want_read + when :CONSUME_TOKEN + break if handle_consume_token == :want_read + when :MIME_HEAD + break if handle_mime_head == :want_read + when :MIME_BODY + break if handle_mime_body == :want_read + when :DONE + break + end + end + end + + def handle_fast_forward + if consume_boundary + @state = :MIME_HEAD + else + raise EOFError, "bad content body" if @sbuf.rest_size >= @bufsize + :want_read + end + end + + def handle_consume_token + tok = consume_boundary + # break if we're at the end of a buffer, but not if it is the end of a field + @state = if tok == :END_BOUNDARY || (@sbuf.eos? && tok != :BOUNDARY) + :DONE + else + :MIME_HEAD + end + end + + def handle_mime_head + if @sbuf.scan_until(@head_regex) + head = @sbuf[1] + content_type = head[MULTIPART_CONTENT_TYPE, 1] + if name = head[MULTIPART_CONTENT_DISPOSITION, 1] + name = Rack::Auth::Digest::Params::dequote(name) + else + name = head[MULTIPART_CONTENT_ID, 1] + end + + filename = get_filename(head) + + if name.nil? || name.empty? + name = filename || "#{content_type || TEXT_PLAIN}[]".dup + end + + @collector.on_mime_head @mime_index, head, filename, content_type, name + @state = :MIME_BODY + else + :want_read + end + end + + def handle_mime_body + if (body_with_boundary = @sbuf.check_until(@body_regex)) # check but do not advance the pointer yet + body = body_with_boundary.sub(/#{@body_regex}\z/m, '') # remove the boundary from the string + @collector.on_mime_body @mime_index, body + @sbuf.pos += body.length + 2 # skip \r\n after the content + @state = :CONSUME_TOKEN + @mime_index += 1 + else + # Save what we have so far + if @rx_max_size < @sbuf.rest_size + delta = @sbuf.rest_size - @rx_max_size + @collector.on_mime_body @mime_index, @sbuf.peek(delta) + @sbuf.pos += delta + @sbuf.string = @sbuf.rest + end + :want_read + end + end + + def full_boundary; @full_boundary; end + + def consume_boundary + while read_buffer = @sbuf.scan_until(BOUNDARY_REGEX) + case read_buffer.strip + when full_boundary then return :BOUNDARY + when @end_boundary then return :END_BOUNDARY + end + return if @sbuf.eos? + end + end + + def get_filename(head) + filename = nil + case head + when RFC2183 + params = Hash[*head.scan(DISPPARM).flat_map(&:compact)] + + if filename = params['filename'] + filename = $1 if filename =~ /^"(.*)"$/ + elsif filename = params['filename*'] + encoding, _, filename = filename.split("'", 3) + end + when BROKEN_QUOTED, BROKEN_UNQUOTED + filename = $1 + end + + return unless filename + + if filename.scan(/%.?.?/).all? { |s| /%[0-9a-fA-F]{2}/.match?(s) } + filename = Utils.unescape_path(filename) + end + + filename.scrub! + + if filename !~ /\\[^\\"]/ + filename = filename.gsub(/\\(.)/, '\1') + end + + if encoding + filename.force_encoding ::Encoding.find(encoding) + end + + filename + end + + CHARSET = "charset" + + def tag_multipart_encoding(filename, content_type, name, body) + name = name.to_s + encoding = Encoding::UTF_8 + + name.force_encoding(encoding) + + return if filename + + if content_type + list = content_type.split(';') + type_subtype = list.first + type_subtype.strip! + if TEXT_PLAIN == type_subtype + rest = list.drop 1 + rest.each do |param| + k, v = param.split('=', 2) + k.strip! + v.strip! + v = v[1..-2] if v.start_with?('"') && v.end_with?('"') + encoding = Encoding.find v if k == CHARSET + end + end + end + + name.force_encoding(encoding) + body.force_encoding(encoding) + end + + def handle_empty_content!(content) + if content.nil? || content.empty? + raise EOFError + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart/uploaded_file.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart/uploaded_file.rb new file mode 100644 index 0000000000..9eaf691277 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/multipart/uploaded_file.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Rack + module Multipart + class UploadedFile + # The filename, *not* including the path, of the "uploaded" file + attr_reader :original_filename + + # The content type of the "uploaded" file + attr_accessor :content_type + + def initialize(filepath = nil, ct = "text/plain", bin = false, + path: filepath, content_type: ct, binary: bin, filename: nil, io: nil) + if io + @tempfile = io + @original_filename = filename + else + raise "#{path} file does not exist" unless ::File.exist?(path) + @original_filename = filename || ::File.basename(path) + @tempfile = Tempfile.new([@original_filename, ::File.extname(path)], encoding: Encoding::BINARY) + @tempfile.binmode if binary + FileUtils.copy_file(path, @tempfile.path) + end + @content_type = content_type + end + + def path + @tempfile.path if @tempfile.respond_to?(:path) + end + alias_method :local_path, :path + + def respond_to?(*args) + super or @tempfile.respond_to?(*args) + end + + def method_missing(method_name, *args, &block) #:nodoc: + @tempfile.__send__(method_name, *args, &block) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/null_logger.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/null_logger.rb new file mode 100644 index 0000000000..3eff73d683 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/null_logger.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Rack + class NullLogger + def initialize(app) + @app = app + end + + def call(env) + env[RACK_LOGGER] = self + @app.call(env) + end + + def info(progname = nil, &block); end + def debug(progname = nil, &block); end + def warn(progname = nil, &block); end + def error(progname = nil, &block); end + def fatal(progname = nil, &block); end + def unknown(progname = nil, &block); end + def info? ; end + def debug? ; end + def warn? ; end + def error? ; end + def fatal? ; end + def level ; end + def progname ; end + def datetime_format ; end + def formatter ; end + def sev_threshold ; end + def level=(level); end + def progname=(progname); end + def datetime_format=(datetime_format); end + def formatter=(formatter); end + def sev_threshold=(sev_threshold); end + def close ; end + def add(severity, message = nil, progname = nil, &block); end + def <<(msg); end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/query_parser.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/query_parser.rb new file mode 100644 index 0000000000..dbbb18e5a2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/query_parser.rb @@ -0,0 +1,217 @@ +# frozen_string_literal: true + +module Rack + class QueryParser + (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4' + + DEFAULT_SEP = /[&;] */n + COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n } + + # ParameterTypeError is the error that is raised when incoming structural + # parameters (parsed by parse_nested_query) contain conflicting types. + class ParameterTypeError < TypeError; end + + # InvalidParameterError is the error that is raised when incoming structural + # parameters (parsed by parse_nested_query) contain invalid format or byte + # sequence. + class InvalidParameterError < ArgumentError; end + + def self.make_default(key_space_limit, param_depth_limit) + new Params, key_space_limit, param_depth_limit + end + + attr_reader :key_space_limit, :param_depth_limit + + def initialize(params_class, key_space_limit, param_depth_limit) + @params_class = params_class + @key_space_limit = key_space_limit + @param_depth_limit = param_depth_limit + end + + # Stolen from Mongrel, with some small modifications: + # Parses a query string by breaking it up at the '&' + # and ';' characters. You can also use this to parse + # cookies by changing the characters used in the second + # parameter (which defaults to '&;'). + def parse_query(qs, d = nil, &unescaper) + unescaper ||= method(:unescape) + + params = make_params + + (qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p| + next if p.empty? + k, v = p.split('=', 2).map!(&unescaper) + + if cur = params[k] + if cur.class == Array + params[k] << v + else + params[k] = [cur, v] + end + else + params[k] = v + end + end + + return params.to_h + end + + # parse_nested_query expands a query string into structural types. Supported + # types are Arrays, Hashes and basic value types. It is possible to supply + # query strings with parameters of conflicting types, in this case a + # ParameterTypeError is raised. Users are encouraged to return a 400 in this + # case. + def parse_nested_query(qs, d = nil) + params = make_params + + unless qs.nil? || qs.empty? + (qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p| + k, v = p.split('=', 2).map! { |s| unescape(s) } + + normalize_params(params, k, v, param_depth_limit) + end + end + + return params.to_h + rescue ArgumentError => e + raise InvalidParameterError, e.message, e.backtrace + end + + # normalize_params recursively expands parameters into structural types. If + # the structural types represented by two different parameter names are in + # conflict, a ParameterTypeError is raised. + def normalize_params(params, name, v, depth) + raise RangeError if depth <= 0 + + name =~ %r(\A[\[\]]*([^\[\]]+)\]*) + k = $1 || '' + after = $' || '' + + if k.empty? + if !v.nil? && name == "[]" + return Array(v) + else + return + end + end + + if after == '' + params[k] = v + elsif after == "[" + params[name] = v + elsif after == "[]" + params[k] ||= [] + raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + params[k] << v + elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) + child_key = $1 + params[k] ||= [] + raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key) + normalize_params(params[k].last, child_key, v, depth - 1) + else + params[k] << normalize_params(make_params, child_key, v, depth - 1) + end + else + params[k] ||= make_params + raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k]) + params[k] = normalize_params(params[k], after, v, depth - 1) + end + + params + end + + def make_params + @params_class.new @key_space_limit + end + + def new_space_limit(key_space_limit) + self.class.new @params_class, key_space_limit, param_depth_limit + end + + def new_depth_limit(param_depth_limit) + self.class.new @params_class, key_space_limit, param_depth_limit + end + + private + + def params_hash_type?(obj) + obj.kind_of?(@params_class) + end + + def params_hash_has_key?(hash, key) + return false if /\[\]/.match?(key) + + key.split(/[\[\]]+/).inject(hash) do |h, part| + next h if part == '' + return false unless params_hash_type?(h) && h.key?(part) + h[part] + end + + true + end + + def unescape(s) + Utils.unescape(s) + end + + class Params + def initialize(limit) + @limit = limit + @size = 0 + @params = {} + end + + def [](key) + @params[key] + end + + def []=(key, value) + @size += key.size if key && !@params.key?(key) + raise RangeError, 'exceeded available parameter key space' if @size > @limit + @params[key] = value + end + + def key?(key) + @params.key?(key) + end + + # Recursively unwraps nested `Params` objects and constructs an object + # of the same shape, but using the objects' internal representations + # (Ruby hashes) in place of the objects. The result is a hash consisting + # purely of Ruby primitives. + # + # Mutation warning! + # + # 1. This method mutates the internal representation of the `Params` + # objects in order to save object allocations. + # + # 2. The value you get back is a reference to the internal hash + # representation, not a copy. + # + # 3. Because the `Params` object's internal representation is mutable + # through the `#[]=` method, it is not thread safe. The result of + # getting the hash representation while another thread is adding a + # key to it is non-deterministic. + # + def to_h + @params.each do |key, value| + case value + when self + # Handle circular references gracefully. + @params[key] = @params + when Params + @params[key] = value.to_h + when Array + value.map! { |v| v.kind_of?(Params) ? v.to_h : v } + else + # Ignore anything that is not a `Params` object or + # a collection that can contain one. + end + end + @params + end + alias_method :to_params_hash, :to_h + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/recursive.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/recursive.rb new file mode 100644 index 0000000000..6971cbfd69 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/recursive.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require 'uri' + +module Rack + # Rack::ForwardRequest gets caught by Rack::Recursive and redirects + # the current request to the app at +url+. + # + # raise ForwardRequest.new("/not-found") + # + + class ForwardRequest < Exception + attr_reader :url, :env + + def initialize(url, env = {}) + @url = URI(url) + @env = env + + @env[PATH_INFO] = @url.path + @env[QUERY_STRING] = @url.query if @url.query + @env[HTTP_HOST] = @url.host if @url.host + @env[HTTP_PORT] = @url.port if @url.port + @env[RACK_URL_SCHEME] = @url.scheme if @url.scheme + + super "forwarding to #{url}" + end + end + + # Rack::Recursive allows applications called down the chain to + # include data from other applications (by using + # rack['rack.recursive.include'][...] or raise a + # ForwardRequest to redirect internally. + + class Recursive + def initialize(app) + @app = app + end + + def call(env) + dup._call(env) + end + + def _call(env) + @script_name = env[SCRIPT_NAME] + @app.call(env.merge(RACK_RECURSIVE_INCLUDE => method(:include))) + rescue ForwardRequest => req + call(env.merge(req.env)) + end + + def include(env, path) + unless path.index(@script_name) == 0 && (path[@script_name.size] == ?/ || + path[@script_name.size].nil?) + raise ArgumentError, "can only include below #{@script_name}, not #{path}" + end + + env = env.merge(PATH_INFO => path, + SCRIPT_NAME => @script_name, + REQUEST_METHOD => GET, + "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "", + RACK_INPUT => StringIO.new("")) + @app.call(env) + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/reloader.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/reloader.rb new file mode 100644 index 0000000000..2f17f50b83 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/reloader.rb @@ -0,0 +1,114 @@ +# frozen_string_literal: true + +# Copyright (C) 2009-2018 Michael Fellinger +# Rack::Reloader is subject to the terms of an MIT-style license. +# See MIT-LICENSE or https://opensource.org/licenses/MIT. + +require 'pathname' + +module Rack + + # High performant source reloader + # + # This class acts as Rack middleware. + # + # What makes it especially suited for use in a production environment is that + # any file will only be checked once and there will only be made one system + # call stat(2). + # + # Please note that this will not reload files in the background, it does so + # only when actively called. + # + # It is performing a check/reload cycle at the start of every request, but + # also respects a cool down time, during which nothing will be done. + class Reloader + (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4' + + def initialize(app, cooldown = 10, backend = Stat) + @app = app + @cooldown = cooldown + @last = (Time.now - cooldown) + @cache = {} + @mtimes = {} + @reload_mutex = Mutex.new + + extend backend + end + + def call(env) + if @cooldown and Time.now > @last + @cooldown + if Thread.list.size > 1 + @reload_mutex.synchronize{ reload! } + else + reload! + end + + @last = Time.now + end + + @app.call(env) + end + + def reload!(stderr = $stderr) + rotation do |file, mtime| + previous_mtime = @mtimes[file] ||= mtime + safe_load(file, mtime, stderr) if mtime > previous_mtime + end + end + + # A safe Kernel::load, issuing the hooks depending on the results + def safe_load(file, mtime, stderr = $stderr) + load(file) + stderr.puts "#{self.class}: reloaded `#{file}'" + file + rescue LoadError, SyntaxError => ex + stderr.puts ex + ensure + @mtimes[file] = mtime + end + + module Stat + def rotation + files = [$0, *$LOADED_FEATURES].uniq + paths = ['./', *$LOAD_PATH].uniq + + files.map{|file| + next if /\.(so|bundle)$/.match?(file) # cannot reload compiled files + + found, stat = figure_path(file, paths) + next unless found && stat && mtime = stat.mtime + + @cache[file] = found + + yield(found, mtime) + }.compact + end + + # Takes a relative or absolute +file+ name, a couple possible +paths+ that + # the +file+ might reside in. Returns the full path and File::Stat for the + # path. + def figure_path(file, paths) + found = @cache[file] + found = file if !found and Pathname.new(file).absolute? + found, stat = safe_stat(found) + return found, stat if found + + paths.find do |possible_path| + path = ::File.join(possible_path, file) + found, stat = safe_stat(path) + return ::File.expand_path(found), stat if found + end + + return false, false + end + + def safe_stat(file) + return unless file + stat = ::File.stat(file) + return file, stat if stat.file? + rescue Errno::ENOENT, Errno::ENOTDIR, Errno::ESRCH + @cache.delete(file) and false + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/request.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/request.rb new file mode 100644 index 0000000000..750a0dc44f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/request.rb @@ -0,0 +1,659 @@ +# frozen_string_literal: true + +module Rack + # Rack::Request provides a convenient interface to a Rack + # environment. It is stateless, the environment +env+ passed to the + # constructor will be directly modified. + # + # req = Rack::Request.new(env) + # req.post? + # req.params["data"] + + class Request + (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4' + + class << self + attr_accessor :ip_filter + end + + self.ip_filter = lambda { |ip| /\A127\.0\.0\.1\Z|\A(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\.|\A::1\Z|\Afd[0-9a-f]{2}:.+|\Alocalhost\Z|\Aunix\Z|\Aunix:/i.match?(ip) } + ALLOWED_SCHEMES = %w(https http).freeze + SCHEME_WHITELIST = ALLOWED_SCHEMES + if Object.respond_to?(:deprecate_constant) + deprecate_constant :SCHEME_WHITELIST + end + + def initialize(env) + @params = nil + super(env) + end + + def params + @params ||= super + end + + def update_param(k, v) + super + @params = nil + end + + def delete_param(k) + v = super + @params = nil + v + end + + module Env + # The environment of the request. + attr_reader :env + + def initialize(env) + @env = env + super() + end + + # Predicate method to test to see if `name` has been set as request + # specific data + def has_header?(name) + @env.key? name + end + + # Get a request specific value for `name`. + def get_header(name) + @env[name] + end + + # If a block is given, it yields to the block if the value hasn't been set + # on the request. + def fetch_header(name, &block) + @env.fetch(name, &block) + end + + # Loops through each key / value pair in the request specific data. + def each_header(&block) + @env.each(&block) + end + + # Set a request specific value for `name` to `v` + def set_header(name, v) + @env[name] = v + end + + # Add a header that may have multiple values. + # + # Example: + # request.add_header 'Accept', 'image/png' + # request.add_header 'Accept', '*/*' + # + # assert_equal 'image/png,*/*', request.get_header('Accept') + # + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 + def add_header(key, v) + if v.nil? + get_header key + elsif has_header? key + set_header key, "#{get_header key},#{v}" + else + set_header key, v + end + end + + # Delete a request specific value for `name`. + def delete_header(name) + @env.delete name + end + + def initialize_copy(other) + @env = other.env.dup + end + end + + module Helpers + # The set of form-data media-types. Requests that do not indicate + # one of the media types present in this list will not be eligible + # for form-data / param parsing. + FORM_DATA_MEDIA_TYPES = [ + 'application/x-www-form-urlencoded', + 'multipart/form-data' + ] + + # The set of media-types. Requests that do not indicate + # one of the media types present in this list will not be eligible + # for param parsing like soap attachments or generic multiparts + PARSEABLE_DATA_MEDIA_TYPES = [ + 'multipart/related', + 'multipart/mixed' + ] + + # Default ports depending on scheme. Used to decide whether or not + # to include the port in a generated URI. + DEFAULT_PORTS = { 'http' => 80, 'https' => 443, 'coffee' => 80 } + + # The address of the client which connected to the proxy. + HTTP_X_FORWARDED_FOR = 'HTTP_X_FORWARDED_FOR' + + # The contents of the host/:authority header sent to the proxy. + HTTP_X_FORWARDED_HOST = 'HTTP_X_FORWARDED_HOST' + + # The value of the scheme sent to the proxy. + HTTP_X_FORWARDED_SCHEME = 'HTTP_X_FORWARDED_SCHEME' + + # The protocol used to connect to the proxy. + HTTP_X_FORWARDED_PROTO = 'HTTP_X_FORWARDED_PROTO' + + # The port used to connect to the proxy. + HTTP_X_FORWARDED_PORT = 'HTTP_X_FORWARDED_PORT' + + # Another way for specifing https scheme was used. + HTTP_X_FORWARDED_SSL = 'HTTP_X_FORWARDED_SSL' + + def body; get_header(RACK_INPUT) end + def script_name; get_header(SCRIPT_NAME).to_s end + def script_name=(s); set_header(SCRIPT_NAME, s.to_s) end + + def path_info; get_header(PATH_INFO).to_s end + def path_info=(s); set_header(PATH_INFO, s.to_s) end + + def request_method; get_header(REQUEST_METHOD) end + def query_string; get_header(QUERY_STRING).to_s end + def content_length; get_header('CONTENT_LENGTH') end + def logger; get_header(RACK_LOGGER) end + def user_agent; get_header('HTTP_USER_AGENT') end + def multithread?; get_header(RACK_MULTITHREAD) end + + # the referer of the client + def referer; get_header('HTTP_REFERER') end + alias referrer referer + + def session + fetch_header(RACK_SESSION) do |k| + set_header RACK_SESSION, default_session + end + end + + def session_options + fetch_header(RACK_SESSION_OPTIONS) do |k| + set_header RACK_SESSION_OPTIONS, {} + end + end + + # Checks the HTTP request method (or verb) to see if it was of type DELETE + def delete?; request_method == DELETE end + + # Checks the HTTP request method (or verb) to see if it was of type GET + def get?; request_method == GET end + + # Checks the HTTP request method (or verb) to see if it was of type HEAD + def head?; request_method == HEAD end + + # Checks the HTTP request method (or verb) to see if it was of type OPTIONS + def options?; request_method == OPTIONS end + + # Checks the HTTP request method (or verb) to see if it was of type LINK + def link?; request_method == LINK end + + # Checks the HTTP request method (or verb) to see if it was of type PATCH + def patch?; request_method == PATCH end + + # Checks the HTTP request method (or verb) to see if it was of type POST + def post?; request_method == POST end + + # Checks the HTTP request method (or verb) to see if it was of type PUT + def put?; request_method == PUT end + + # Checks the HTTP request method (or verb) to see if it was of type TRACE + def trace?; request_method == TRACE end + + # Checks the HTTP request method (or verb) to see if it was of type UNLINK + def unlink?; request_method == UNLINK end + + def scheme + if get_header(HTTPS) == 'on' + 'https' + elsif get_header(HTTP_X_FORWARDED_SSL) == 'on' + 'https' + elsif forwarded_scheme + forwarded_scheme + else + get_header(RACK_URL_SCHEME) + end + end + + # The authority of the incoming request as defined by RFC3976. + # https://tools.ietf.org/html/rfc3986#section-3.2 + # + # In HTTP/1, this is the `host` header. + # In HTTP/2, this is the `:authority` pseudo-header. + def authority + forwarded_authority || host_authority || server_authority + end + + # The authority as defined by the `SERVER_NAME` and `SERVER_PORT` + # variables. + def server_authority + host = self.server_name + port = self.server_port + + if host + if port + "#{host}:#{port}" + else + host + end + end + end + + def server_name + get_header(SERVER_NAME) + end + + def server_port + if port = get_header(SERVER_PORT) + Integer(port) + end + end + + def cookies + hash = fetch_header(RACK_REQUEST_COOKIE_HASH) do |key| + set_header(key, {}) + end + + string = get_header(HTTP_COOKIE) + + unless string == get_header(RACK_REQUEST_COOKIE_STRING) + hash.replace Utils.parse_cookies_header(string) + set_header(RACK_REQUEST_COOKIE_STRING, string) + end + + hash + end + + def content_type + content_type = get_header('CONTENT_TYPE') + content_type.nil? || content_type.empty? ? nil : content_type + end + + def xhr? + get_header("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest" + end + + # The `HTTP_HOST` header. + def host_authority + get_header(HTTP_HOST) + end + + def host_with_port(authority = self.authority) + host, _, port = split_authority(authority) + + if port == DEFAULT_PORTS[self.scheme] + host + else + authority + end + end + + # Returns a formatted host, suitable for being used in a URI. + def host + split_authority(self.authority)[0] + end + + # Returns an address suitable for being to resolve to an address. + # In the case of a domain name or IPv4 address, the result is the same + # as +host+. In the case of IPv6 or future address formats, the square + # brackets are removed. + def hostname + split_authority(self.authority)[1] + end + + def port + if authority = self.authority + _, _, port = split_authority(self.authority) + + if port + return port + end + end + + if forwarded_port = self.forwarded_port + return forwarded_port.first + end + + if scheme = self.scheme + if port = DEFAULT_PORTS[self.scheme] + return port + end + end + + self.server_port + end + + def forwarded_for + if value = get_header(HTTP_X_FORWARDED_FOR) + split_header(value).map do |authority| + split_authority(wrap_ipv6(authority))[1] + end + end + end + + def forwarded_port + if value = get_header(HTTP_X_FORWARDED_PORT) + split_header(value).map(&:to_i) + end + end + + def forwarded_authority + if value = get_header(HTTP_X_FORWARDED_HOST) + wrap_ipv6(split_header(value).first) + end + end + + def ssl? + scheme == 'https' || scheme == 'wss' + end + + def ip + remote_addresses = split_header(get_header('REMOTE_ADDR')) + external_addresses = reject_trusted_ip_addresses(remote_addresses) + + unless external_addresses.empty? + return external_addresses.first + end + + if forwarded_for = self.forwarded_for + unless forwarded_for.empty? + # The forwarded for addresses are ordered: client, proxy1, proxy2. + # So we reject all the trusted addresses (proxy*) and return the + # last client. Or if we trust everyone, we just return the first + # address. + return reject_trusted_ip_addresses(forwarded_for).last || forwarded_for.first + end + end + + # If all the addresses are trusted, and we aren't forwarded, just return + # the first remote address, which represents the source of the request. + remote_addresses.first + end + + # The media type (type/subtype) portion of the CONTENT_TYPE header + # without any media type parameters. e.g., when CONTENT_TYPE is + # "text/plain;charset=utf-8", the media-type is "text/plain". + # + # For more information on the use of media types in HTTP, see: + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7 + def media_type + MediaType.type(content_type) + end + + # The media type parameters provided in CONTENT_TYPE as a Hash, or + # an empty Hash if no CONTENT_TYPE or media-type parameters were + # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8", + # this method responds with the following Hash: + # { 'charset' => 'utf-8' } + def media_type_params + MediaType.params(content_type) + end + + # The character set of the request body if a "charset" media type + # parameter was given, or nil if no "charset" was specified. Note + # that, per RFC2616, text/* media types that specify no explicit + # charset are to be considered ISO-8859-1. + def content_charset + media_type_params['charset'] + end + + # Determine whether the request body contains form-data by checking + # the request Content-Type for one of the media-types: + # "application/x-www-form-urlencoded" or "multipart/form-data". The + # list of form-data media types can be modified through the + # +FORM_DATA_MEDIA_TYPES+ array. + # + # A request body is also assumed to contain form-data when no + # Content-Type header is provided and the request_method is POST. + def form_data? + type = media_type + meth = get_header(RACK_METHODOVERRIDE_ORIGINAL_METHOD) || get_header(REQUEST_METHOD) + + (meth == POST && type.nil?) || FORM_DATA_MEDIA_TYPES.include?(type) + end + + # Determine whether the request body contains data by checking + # the request media_type against registered parse-data media-types + def parseable_data? + PARSEABLE_DATA_MEDIA_TYPES.include?(media_type) + end + + # Returns the data received in the query string. + def GET + if get_header(RACK_REQUEST_QUERY_STRING) == query_string + get_header(RACK_REQUEST_QUERY_HASH) + else + query_hash = parse_query(query_string, '&;') + set_header(RACK_REQUEST_QUERY_STRING, query_string) + set_header(RACK_REQUEST_QUERY_HASH, query_hash) + end + end + + # Returns the data received in the request body. + # + # This method support both application/x-www-form-urlencoded and + # multipart/form-data. + def POST + if get_header(RACK_INPUT).nil? + raise "Missing rack.input" + elsif get_header(RACK_REQUEST_FORM_INPUT) == get_header(RACK_INPUT) + get_header(RACK_REQUEST_FORM_HASH) + elsif form_data? || parseable_data? + unless set_header(RACK_REQUEST_FORM_HASH, parse_multipart) + form_vars = get_header(RACK_INPUT).read + + # Fix for Safari Ajax postings that always append \0 + # form_vars.sub!(/\0\z/, '') # performance replacement: + form_vars.slice!(-1) if form_vars.end_with?("\0") + + set_header RACK_REQUEST_FORM_VARS, form_vars + set_header RACK_REQUEST_FORM_HASH, parse_query(form_vars, '&') + + get_header(RACK_INPUT).rewind + end + set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT) + get_header RACK_REQUEST_FORM_HASH + else + {} + end + end + + # The union of GET and POST data. + # + # Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params. + def params + self.GET.merge(self.POST) + end + + # Destructively update a parameter, whether it's in GET and/or POST. Returns nil. + # + # The parameter is updated wherever it was previous defined, so GET, POST, or both. If it wasn't previously defined, it's inserted into GET. + # + # env['rack.input'] is not touched. + def update_param(k, v) + found = false + if self.GET.has_key?(k) + found = true + self.GET[k] = v + end + if self.POST.has_key?(k) + found = true + self.POST[k] = v + end + unless found + self.GET[k] = v + end + end + + # Destructively delete a parameter, whether it's in GET or POST. Returns the value of the deleted parameter. + # + # If the parameter is in both GET and POST, the POST value takes precedence since that's how #params works. + # + # env['rack.input'] is not touched. + def delete_param(k) + post_value, get_value = self.POST.delete(k), self.GET.delete(k) + post_value || get_value + end + + def base_url + "#{scheme}://#{host_with_port}" + end + + # Tries to return a remake of the original request URL as a string. + def url + base_url + fullpath + end + + def path + script_name + path_info + end + + def fullpath + query_string.empty? ? path : "#{path}?#{query_string}" + end + + def accept_encoding + parse_http_accept_header(get_header("HTTP_ACCEPT_ENCODING")) + end + + def accept_language + parse_http_accept_header(get_header("HTTP_ACCEPT_LANGUAGE")) + end + + def trusted_proxy?(ip) + Rack::Request.ip_filter.call(ip) + end + + # shortcut for request.params[key] + def [](key) + if $VERBOSE + warn("Request#[] is deprecated and will be removed in a future version of Rack. Please use request.params[] instead") + end + + params[key.to_s] + end + + # shortcut for request.params[key] = value + # + # Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params. + def []=(key, value) + if $VERBOSE + warn("Request#[]= is deprecated and will be removed in a future version of Rack. Please use request.params[]= instead") + end + + params[key.to_s] = value + end + + # like Hash#values_at + def values_at(*keys) + keys.map { |key| params[key] } + end + + private + + def default_session; {}; end + + # Assist with compatibility when processing `X-Forwarded-For`. + def wrap_ipv6(host) + # Even thought IPv6 addresses should be wrapped in square brackets, + # sometimes this is not done in various legacy/underspecified headers. + # So we try to fix this situation for compatibility reasons. + + # Try to detect IPv6 addresses which aren't escaped yet: + if !host.start_with?('[') && host.count(':') > 1 + "[#{host}]" + else + host + end + end + + def parse_http_accept_header(header) + header.to_s.split(/\s*,\s*/).map do |part| + attribute, parameters = part.split(/\s*;\s*/, 2) + quality = 1.0 + if parameters and /\Aq=([\d.]+)/ =~ parameters + quality = $1.to_f + end + [attribute, quality] + end + end + + def query_parser + Utils.default_query_parser + end + + def parse_query(qs, d = '&') + query_parser.parse_nested_query(qs, d) + end + + def parse_multipart + Rack::Multipart.extract_multipart(self, query_parser) + end + + def split_header(value) + value ? value.strip.split(/[,\s]+/) : [] + end + + AUTHORITY = /^ + # The host: + (? + # An IPv6 address: + (\[(?.*)\]) + | + # An IPv4 address: + (?[\d\.]+) + | + # A hostname: + (?[a-zA-Z0-9\.\-]+) + ) + # The optional port: + (:(?\d+))? + $/x + + private_constant :AUTHORITY + + def split_authority(authority) + if match = AUTHORITY.match(authority) + if address = match[:ip6] + return match[:host], address, match[:port]&.to_i + else + return match[:host], match[:host], match[:port]&.to_i + end + end + + # Give up! + return authority, authority, nil + end + + def reject_trusted_ip_addresses(ip_addresses) + ip_addresses.reject { |ip| trusted_proxy?(ip) } + end + + def forwarded_scheme + allowed_scheme(get_header(HTTP_X_FORWARDED_SCHEME)) || + allowed_scheme(extract_proto_header(get_header(HTTP_X_FORWARDED_PROTO))) + end + + def allowed_scheme(header) + header if ALLOWED_SCHEMES.include?(header) + end + + def extract_proto_header(header) + if header + if (comma_index = header.index(',')) + header[0, comma_index] + else + header + end + end + end + end + + include Env + include Helpers + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/response.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/response.rb new file mode 100644 index 0000000000..fd6d2f5d55 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/response.rb @@ -0,0 +1,318 @@ +# frozen_string_literal: true + +require 'time' + +module Rack + # Rack::Response provides a convenient interface to create a Rack + # response. + # + # It allows setting of headers and cookies, and provides useful + # defaults (an OK response with empty headers and body). + # + # You can use Response#write to iteratively generate your response, + # but note that this is buffered by Rack::Response until you call + # +finish+. +finish+ however can take a block inside which calls to + # +write+ are synchronous with the Rack response. + # + # Your application's +call+ should end returning Response#finish. + class Response + def self.[](status, headers, body) + self.new(body, status, headers) + end + + CHUNKED = 'chunked' + STATUS_WITH_NO_ENTITY_BODY = Utils::STATUS_WITH_NO_ENTITY_BODY + + attr_accessor :length, :status, :body + attr_reader :headers + + # @deprecated Use {#headers} instead. + alias header headers + + # Initialize the response object with the specified body, status + # and headers. + # + # @param body [nil, #each, #to_str] the response body. + # @param status [Integer] the integer status as defined by the + # HTTP protocol RFCs. + # @param headers [#each] a list of key-value header pairs which + # conform to the HTTP protocol RFCs. + # + # Providing a body which responds to #to_str is legacy behaviour. + def initialize(body = nil, status = 200, headers = {}) + @status = status.to_i + @headers = Utils::HeaderHash[headers] + + @writer = self.method(:append) + + @block = nil + + # Keep track of whether we have expanded the user supplied body. + if body.nil? + @body = [] + @buffered = true + @length = 0 + elsif body.respond_to?(:to_str) + @body = [body] + @buffered = true + @length = body.to_str.bytesize + else + @body = body + @buffered = false + @length = 0 + end + + yield self if block_given? + end + + def redirect(target, status = 302) + self.status = status + self.location = target + end + + def chunked? + CHUNKED == get_header(TRANSFER_ENCODING) + end + + # Generate a response array consistent with the requirements of the SPEC. + # @return [Array] a 3-tuple suitable of `[status, headers, body]` + # which is suitable to be returned from the middleware `#call(env)` method. + def finish(&block) + if STATUS_WITH_NO_ENTITY_BODY[status.to_i] + delete_header CONTENT_TYPE + delete_header CONTENT_LENGTH + close + return [@status, @headers, []] + else + if block_given? + @block = block + return [@status, @headers, self] + else + return [@status, @headers, @body] + end + end + end + + alias to_a finish # For *response + + def each(&callback) + @body.each(&callback) + @buffered = true + + if @block + @writer = callback + @block.call(self) + end + end + + # Append to body and update Content-Length. + # + # NOTE: Do not mix #write and direct #body access! + # + def write(chunk) + buffered_body! + + @writer.call(chunk.to_s) + end + + def close + @body.close if @body.respond_to?(:close) + end + + def empty? + @block == nil && @body.empty? + end + + def has_header?(key); headers.key? key; end + def get_header(key); headers[key]; end + def set_header(key, v); headers[key] = v; end + def delete_header(key); headers.delete key; end + + alias :[] :get_header + alias :[]= :set_header + + module Helpers + def invalid?; status < 100 || status >= 600; end + + def informational?; status >= 100 && status < 200; end + def successful?; status >= 200 && status < 300; end + def redirection?; status >= 300 && status < 400; end + def client_error?; status >= 400 && status < 500; end + def server_error?; status >= 500 && status < 600; end + + def ok?; status == 200; end + def created?; status == 201; end + def accepted?; status == 202; end + def no_content?; status == 204; end + def moved_permanently?; status == 301; end + def bad_request?; status == 400; end + def unauthorized?; status == 401; end + def forbidden?; status == 403; end + def not_found?; status == 404; end + def method_not_allowed?; status == 405; end + def precondition_failed?; status == 412; end + def unprocessable?; status == 422; end + + def redirect?; [301, 302, 303, 307, 308].include? status; end + + def include?(header) + has_header? header + end + + # Add a header that may have multiple values. + # + # Example: + # response.add_header 'Vary', 'Accept-Encoding' + # response.add_header 'Vary', 'Cookie' + # + # assert_equal 'Accept-Encoding,Cookie', response.get_header('Vary') + # + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 + def add_header(key, v) + if v.nil? + get_header key + elsif has_header? key + set_header key, "#{get_header key},#{v}" + else + set_header key, v + end + end + + # Get the content type of the response. + def content_type + get_header CONTENT_TYPE + end + + # Set the content type of the response. + def content_type=(content_type) + set_header CONTENT_TYPE, content_type + end + + def media_type + MediaType.type(content_type) + end + + def media_type_params + MediaType.params(content_type) + end + + def content_length + cl = get_header CONTENT_LENGTH + cl ? cl.to_i : cl + end + + def location + get_header "Location" + end + + def location=(location) + set_header "Location", location + end + + def set_cookie(key, value) + cookie_header = get_header SET_COOKIE + set_header SET_COOKIE, ::Rack::Utils.add_cookie_to_header(cookie_header, key, value) + end + + def delete_cookie(key, value = {}) + set_header SET_COOKIE, ::Rack::Utils.add_remove_cookie_to_header(get_header(SET_COOKIE), key, value) + end + + def set_cookie_header + get_header SET_COOKIE + end + + def set_cookie_header=(v) + set_header SET_COOKIE, v + end + + def cache_control + get_header CACHE_CONTROL + end + + def cache_control=(v) + set_header CACHE_CONTROL, v + end + + # Specifies that the content shouldn't be cached. Overrides `cache!` if already called. + def do_not_cache! + set_header CACHE_CONTROL, "no-cache, must-revalidate" + set_header EXPIRES, Time.now.httpdate + end + + # Specify that the content should be cached. + # @param duration [Integer] The number of seconds until the cache expires. + # @option directive [String] The cache control directive, one of "public", "private", "no-cache" or "no-store". + def cache!(duration = 3600, directive: "public") + unless headers[CACHE_CONTROL] =~ /no-cache/ + set_header CACHE_CONTROL, "#{directive}, max-age=#{duration}" + set_header EXPIRES, (Time.now + duration).httpdate + end + end + + def etag + get_header ETAG + end + + def etag=(v) + set_header ETAG, v + end + + protected + + def buffered_body! + return if @buffered + + if @body.is_a?(Array) + # The user supplied body was an array: + @body = @body.compact + @body.each do |part| + @length += part.to_s.bytesize + end + else + # Turn the user supplied body into a buffered array: + body = @body + @body = Array.new + + body.each do |part| + @writer.call(part.to_s) + end + + body.close if body.respond_to?(:close) + end + + @buffered = true + end + + def append(chunk) + @body << chunk + + unless chunked? + @length += chunk.bytesize + set_header(CONTENT_LENGTH, @length.to_s) + end + + return chunk + end + end + + include Helpers + + class Raw + include Helpers + + attr_reader :headers + attr_accessor :status + + def initialize(status, headers) + @status = status + @headers = headers + end + + def has_header?(key); headers.key? key; end + def get_header(key); headers[key]; end + def set_header(key, v); headers[key] = v; end + def delete_header(key); headers.delete key; end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/rewindable_input.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/rewindable_input.rb new file mode 100644 index 0000000000..91b9d1eb36 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/rewindable_input.rb @@ -0,0 +1,94 @@ +# -*- encoding: binary -*- +# frozen_string_literal: true + +require 'tempfile' + +module Rack + # Class which can make any IO object rewindable, including non-rewindable ones. It does + # this by buffering the data into a tempfile, which is rewindable. + # + # rack.input is required to be rewindable, so if your input stream IO is non-rewindable + # by nature (e.g. a pipe or a socket) then you can wrap it in an object of this class + # to easily make it rewindable. + # + # Don't forget to call #close when you're done. This frees up temporary resources that + # RewindableInput uses, though it does *not* close the original IO object. + class RewindableInput + def initialize(io) + @io = io + @rewindable_io = nil + @unlinked = false + end + + def gets + make_rewindable unless @rewindable_io + @rewindable_io.gets + end + + def read(*args) + make_rewindable unless @rewindable_io + @rewindable_io.read(*args) + end + + def each(&block) + make_rewindable unless @rewindable_io + @rewindable_io.each(&block) + end + + def rewind + make_rewindable unless @rewindable_io + @rewindable_io.rewind + end + + # Closes this RewindableInput object without closing the originally + # wrapped IO object. Cleans up any temporary resources that this RewindableInput + # has created. + # + # This method may be called multiple times. It does nothing on subsequent calls. + def close + if @rewindable_io + if @unlinked + @rewindable_io.close + else + @rewindable_io.close! + end + @rewindable_io = nil + end + end + + private + + def make_rewindable + # Buffer all data into a tempfile. Since this tempfile is private to this + # RewindableInput object, we chmod it so that nobody else can read or write + # it. On POSIX filesystems we also unlink the file so that it doesn't + # even have a file entry on the filesystem anymore, though we can still + # access it because we have the file handle open. + @rewindable_io = Tempfile.new('RackRewindableInput') + @rewindable_io.chmod(0000) + @rewindable_io.set_encoding(Encoding::BINARY) if @rewindable_io.respond_to?(:set_encoding) + @rewindable_io.binmode + if filesystem_has_posix_semantics? + raise 'Unlink failed. IO closed.' if @rewindable_io.closed? + @unlinked = true + end + + buffer = "".dup + while @io.read(1024 * 4, buffer) + entire_buffer_written_out = false + while !entire_buffer_written_out + written = @rewindable_io.write(buffer) + entire_buffer_written_out = written == buffer.bytesize + if !entire_buffer_written_out + buffer.slice!(0 .. written - 1) + end + end + end + @rewindable_io.rewind + end + + def filesystem_has_posix_semantics? + RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/ + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/runtime.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/runtime.rb new file mode 100644 index 0000000000..d9b2d8ed19 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/runtime.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Rack + # Sets an "X-Runtime" response header, indicating the response + # time of the request, in seconds + # + # You can put it right before the application to see the processing + # time, or before all the other middlewares to include time for them, + # too. + class Runtime + FORMAT_STRING = "%0.6f" # :nodoc: + HEADER_NAME = "X-Runtime" # :nodoc: + + def initialize(app, name = nil) + @app = app + @header_name = HEADER_NAME + @header_name += "-#{name}" if name + end + + def call(env) + start_time = Utils.clock_time + status, headers, body = @app.call(env) + headers = Utils::HeaderHash[headers] + + request_time = Utils.clock_time - start_time + + unless headers.key?(@header_name) + headers[@header_name] = FORMAT_STRING % request_time + end + + [status, headers, body] + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/sendfile.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/sendfile.rb new file mode 100644 index 0000000000..3d5e786ff7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/sendfile.rb @@ -0,0 +1,162 @@ +# frozen_string_literal: true + +module Rack + + # = Sendfile + # + # The Sendfile middleware intercepts responses whose body is being + # served from a file and replaces it with a server specific X-Sendfile + # header. The web server is then responsible for writing the file contents + # to the client. This can dramatically reduce the amount of work required + # by the Ruby backend and takes advantage of the web server's optimized file + # delivery code. + # + # In order to take advantage of this middleware, the response body must + # respond to +to_path+ and the request must include an X-Sendfile-Type + # header. Rack::Files and other components implement +to_path+ so there's + # rarely anything you need to do in your application. The X-Sendfile-Type + # header is typically set in your web servers configuration. The following + # sections attempt to document + # + # === Nginx + # + # Nginx supports the X-Accel-Redirect header. This is similar to X-Sendfile + # but requires parts of the filesystem to be mapped into a private URL + # hierarchy. + # + # The following example shows the Nginx configuration required to create + # a private "/files/" area, enable X-Accel-Redirect, and pass the special + # X-Sendfile-Type and X-Accel-Mapping headers to the backend: + # + # location ~ /files/(.*) { + # internal; + # alias /var/www/$1; + # } + # + # location / { + # proxy_redirect off; + # + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # + # proxy_set_header X-Sendfile-Type X-Accel-Redirect; + # proxy_set_header X-Accel-Mapping /var/www/=/files/; + # + # proxy_pass http://127.0.0.1:8080/; + # } + # + # Note that the X-Sendfile-Type header must be set exactly as shown above. + # The X-Accel-Mapping header should specify the location on the file system, + # followed by an equals sign (=), followed name of the private URL pattern + # that it maps to. The middleware performs a simple substitution on the + # resulting path. + # + # See Also: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile + # + # === lighttpd + # + # Lighttpd has supported some variation of the X-Sendfile header for some + # time, although only recent version support X-Sendfile in a reverse proxy + # configuration. + # + # $HTTP["host"] == "example.com" { + # proxy-core.protocol = "http" + # proxy-core.balancer = "round-robin" + # proxy-core.backends = ( + # "127.0.0.1:8000", + # "127.0.0.1:8001", + # ... + # ) + # + # proxy-core.allow-x-sendfile = "enable" + # proxy-core.rewrite-request = ( + # "X-Sendfile-Type" => (".*" => "X-Sendfile") + # ) + # } + # + # See Also: http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModProxyCore + # + # === Apache + # + # X-Sendfile is supported under Apache 2.x using a separate module: + # + # https://tn123.org/mod_xsendfile/ + # + # Once the module is compiled and installed, you can enable it using + # XSendFile config directive: + # + # RequestHeader Set X-Sendfile-Type X-Sendfile + # ProxyPassReverse / http://localhost:8001/ + # XSendFile on + # + # === Mapping parameter + # + # The third parameter allows for an overriding extension of the + # X-Accel-Mapping header. Mappings should be provided in tuples of internal to + # external. The internal values may contain regular expression syntax, they + # will be matched with case indifference. + + class Sendfile + def initialize(app, variation = nil, mappings = []) + @app = app + @variation = variation + @mappings = mappings.map do |internal, external| + [/^#{internal}/i, external] + end + end + + def call(env) + status, headers, body = @app.call(env) + if body.respond_to?(:to_path) + case type = variation(env) + when 'X-Accel-Redirect' + path = ::File.expand_path(body.to_path) + if url = map_accel_path(env, path) + headers[CONTENT_LENGTH] = '0' + # '?' must be percent-encoded because it is not query string but a part of path + headers[type] = ::Rack::Utils.escape_path(url).gsub('?', '%3F') + obody = body + body = Rack::BodyProxy.new([]) do + obody.close if obody.respond_to?(:close) + end + else + env[RACK_ERRORS].puts "X-Accel-Mapping header missing" + end + when 'X-Sendfile', 'X-Lighttpd-Send-File' + path = ::File.expand_path(body.to_path) + headers[CONTENT_LENGTH] = '0' + headers[type] = path + obody = body + body = Rack::BodyProxy.new([]) do + obody.close if obody.respond_to?(:close) + end + when '', nil + else + env[RACK_ERRORS].puts "Unknown x-sendfile variation: '#{type}'.\n" + end + end + [status, headers, body] + end + + private + def variation(env) + @variation || + env['sendfile.type'] || + env['HTTP_X_SENDFILE_TYPE'] + end + + def map_accel_path(env, path) + if mapping = @mappings.find { |internal, _| internal =~ path } + path.sub(*mapping) + elsif mapping = env['HTTP_X_ACCEL_MAPPING'] + mapping.split(',').map(&:strip).each do |m| + internal, external = m.split('=', 2).map(&:strip) + new_path = path.sub(/^#{internal}/i, external) + return new_path unless path == new_path + end + path + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/server.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/server.rb new file mode 100644 index 0000000000..c1f2f5caa3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/server.rb @@ -0,0 +1,466 @@ +# frozen_string_literal: true + +require 'optparse' +require 'fileutils' + +module Rack + + class Server + (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4' + + class Options + def parse!(args) + options = {} + opt_parser = OptionParser.new("", 24, ' ') do |opts| + opts.banner = "Usage: rackup [ruby options] [rack options] [rackup config]" + + opts.separator "" + opts.separator "Ruby options:" + + lineno = 1 + opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line| + eval line, TOPLEVEL_BINDING, "-e", lineno + lineno += 1 + } + + opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") { + options[:debug] = true + } + opts.on("-w", "--warn", "turn warnings on for your script") { + options[:warn] = true + } + opts.on("-q", "--quiet", "turn off logging") { + options[:quiet] = true + } + + opts.on("-I", "--include PATH", + "specify $LOAD_PATH (may be used more than once)") { |path| + (options[:include] ||= []).concat(path.split(":")) + } + + opts.on("-r", "--require LIBRARY", + "require the library, before executing your script") { |library| + (options[:require] ||= []) << library + } + + opts.separator "" + opts.separator "Rack options:" + opts.on("-b", "--builder BUILDER_LINE", "evaluate a BUILDER_LINE of code as a builder script") { |line| + options[:builder] = line + } + + opts.on("-s", "--server SERVER", "serve using SERVER (thin/puma/webrick)") { |s| + options[:server] = s + } + + opts.on("-o", "--host HOST", "listen on HOST (default: localhost)") { |host| + options[:Host] = host + } + + opts.on("-p", "--port PORT", "use PORT (default: 9292)") { |port| + options[:Port] = port + } + + opts.on("-O", "--option NAME[=VALUE]", "pass VALUE to the server as option NAME. If no VALUE, sets it to true. Run '#{$0} -s SERVER -h' to get a list of options for SERVER") { |name| + name, value = name.split('=', 2) + value = true if value.nil? + options[name.to_sym] = value + } + + opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development)") { |e| + options[:environment] = e + } + + opts.on("-D", "--daemonize", "run daemonized in the background") { |d| + options[:daemonize] = d ? true : false + } + + opts.on("-P", "--pid FILE", "file to store PID") { |f| + options[:pid] = ::File.expand_path(f) + } + + opts.separator "" + opts.separator "Profiling options:" + + opts.on("--heap HEAPFILE", "Build the application, then dump the heap to HEAPFILE") do |e| + options[:heapfile] = e + end + + opts.on("--profile PROFILE", "Dump CPU or Memory profile to PROFILE (defaults to a tempfile)") do |e| + options[:profile_file] = e + end + + opts.on("--profile-mode MODE", "Profile mode (cpu|wall|object)") do |e| + { cpu: true, wall: true, object: true }.fetch(e.to_sym) do + raise OptionParser::InvalidOption, "unknown profile mode: #{e}" + end + options[:profile_mode] = e.to_sym + end + + opts.separator "" + opts.separator "Common options:" + + opts.on_tail("-h", "-?", "--help", "Show this message") do + puts opts + puts handler_opts(options) + + exit + end + + opts.on_tail("--version", "Show version") do + puts "Rack #{Rack.version} (Release: #{Rack.release})" + exit + end + end + + begin + opt_parser.parse! args + rescue OptionParser::InvalidOption => e + warn e.message + abort opt_parser.to_s + end + + options[:config] = args.last if args.last && !args.last.empty? + options + end + + def handler_opts(options) + begin + info = [] + server = Rack::Handler.get(options[:server]) || Rack::Handler.default + if server && server.respond_to?(:valid_options) + info << "" + info << "Server-specific options for #{server.name}:" + + has_options = false + server.valid_options.each do |name, description| + next if /^(Host|Port)[^a-zA-Z]/.match?(name.to_s) # ignore handler's host and port options, we do our own. + info << " -O %-21s %s" % [name, description] + has_options = true + end + return "" if !has_options + end + info.join("\n") + rescue NameError, LoadError + return "Warning: Could not find handler specified (#{options[:server] || 'default'}) to determine handler-specific options" + end + end + end + + # Start a new rack server (like running rackup). This will parse ARGV and + # provide standard ARGV rackup options, defaulting to load 'config.ru'. + # + # Providing an options hash will prevent ARGV parsing and will not include + # any default options. + # + # This method can be used to very easily launch a CGI application, for + # example: + # + # Rack::Server.start( + # :app => lambda do |e| + # [200, {'Content-Type' => 'text/html'}, ['hello world']] + # end, + # :server => 'cgi' + # ) + # + # Further options available here are documented on Rack::Server#initialize + def self.start(options = nil) + new(options).start + end + + attr_writer :options + + # Options may include: + # * :app + # a rack application to run (overrides :config and :builder) + # * :builder + # a string to evaluate a Rack::Builder from + # * :config + # a rackup configuration file path to load (.ru) + # * :environment + # this selects the middleware that will be wrapped around + # your application. Default options available are: + # - development: CommonLogger, ShowExceptions, and Lint + # - deployment: CommonLogger + # - none: no extra middleware + # note: when the server is a cgi server, CommonLogger is not included. + # * :server + # choose a specific Rack::Handler, e.g. cgi, fcgi, webrick + # * :daemonize + # if true, the server will daemonize itself (fork, detach, etc) + # * :pid + # path to write a pid file after daemonize + # * :Host + # the host address to bind to (used by supporting Rack::Handler) + # * :Port + # the port to bind to (used by supporting Rack::Handler) + # * :AccessLog + # webrick access log options (or supporting Rack::Handler) + # * :debug + # turn on debug output ($DEBUG = true) + # * :warn + # turn on warnings ($-w = true) + # * :include + # add given paths to $LOAD_PATH + # * :require + # require the given libraries + # + # Additional options for profiling app initialization include: + # * :heapfile + # location for ObjectSpace.dump_all to write the output to + # * :profile_file + # location for CPU/Memory (StackProf) profile output (defaults to a tempfile) + # * :profile_mode + # StackProf profile mode (cpu|wall|object) + def initialize(options = nil) + @ignore_options = [] + + if options + @use_default_options = false + @options = options + @app = options[:app] if options[:app] + else + argv = defined?(SPEC_ARGV) ? SPEC_ARGV : ARGV + @use_default_options = true + @options = parse_options(argv) + end + end + + def options + merged_options = @use_default_options ? default_options.merge(@options) : @options + merged_options.reject { |k, v| @ignore_options.include?(k) } + end + + def default_options + environment = ENV['RACK_ENV'] || 'development' + default_host = environment == 'development' ? 'localhost' : '0.0.0.0' + + { + environment: environment, + pid: nil, + Port: 9292, + Host: default_host, + AccessLog: [], + config: "config.ru" + } + end + + def app + @app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config + end + + class << self + def logging_middleware + lambda { |server| + /CGI/.match?(server.server.name) || server.options[:quiet] ? nil : [Rack::CommonLogger, $stderr] + } + end + + def default_middleware_by_environment + m = Hash.new {|h, k| h[k] = []} + m["deployment"] = [ + [Rack::ContentLength], + logging_middleware, + [Rack::TempfileReaper] + ] + m["development"] = [ + [Rack::ContentLength], + logging_middleware, + [Rack::ShowExceptions], + [Rack::Lint], + [Rack::TempfileReaper] + ] + + m + end + + def middleware + default_middleware_by_environment + end + end + + def middleware + self.class.middleware + end + + def start(&block) + if options[:warn] + $-w = true + end + + if includes = options[:include] + $LOAD_PATH.unshift(*includes) + end + + Array(options[:require]).each do |library| + require library + end + + if options[:debug] + $DEBUG = true + require 'pp' + p options[:server] + pp wrapped_app + pp app + end + + check_pid! if options[:pid] + + # Touch the wrapped app, so that the config.ru is loaded before + # daemonization (i.e. before chdir, etc). + handle_profiling(options[:heapfile], options[:profile_mode], options[:profile_file]) do + wrapped_app + end + + daemonize_app if options[:daemonize] + + write_pid if options[:pid] + + trap(:INT) do + if server.respond_to?(:shutdown) + server.shutdown + else + exit + end + end + + server.run(wrapped_app, **options, &block) + end + + def server + @_server ||= Rack::Handler.get(options[:server]) + + unless @_server + @_server = Rack::Handler.default + + # We already speak FastCGI + @ignore_options = [:File, :Port] if @_server.to_s == 'Rack::Handler::FastCGI' + end + + @_server + end + + private + def build_app_and_options_from_config + if !::File.exist? options[:config] + abort "configuration #{options[:config]} not found" + end + + app, options = Rack::Builder.parse_file(self.options[:config], opt_parser) + @options.merge!(options) { |key, old, new| old } + app + end + + def handle_profiling(heapfile, profile_mode, filename) + if heapfile + require "objspace" + ObjectSpace.trace_object_allocations_start + yield + GC.start + ::File.open(heapfile, "w") { |f| ObjectSpace.dump_all(output: f) } + exit + end + + if profile_mode + require "stackprof" + require "tempfile" + + make_profile_name(filename) do |filename| + ::File.open(filename, "w") do |f| + StackProf.run(mode: profile_mode, out: f) do + yield + end + puts "Profile written to: #{filename}" + end + end + exit + end + + yield + end + + def make_profile_name(filename) + if filename + yield filename + else + ::Dir::Tmpname.create("profile.dump") do |tmpname, _, _| + yield tmpname + end + end + end + + def build_app_from_string + Rack::Builder.new_from_string(self.options[:builder]) + end + + def parse_options(args) + # Don't evaluate CGI ISINDEX parameters. + # http://www.meb.uni-bonn.de/docs/cgi/cl.html + args.clear if ENV.include?(REQUEST_METHOD) + + @options = opt_parser.parse!(args) + @options[:config] = ::File.expand_path(options[:config]) + ENV["RACK_ENV"] = options[:environment] + @options + end + + def opt_parser + Options.new + end + + def build_app(app) + middleware[options[:environment]].reverse_each do |middleware| + middleware = middleware.call(self) if middleware.respond_to?(:call) + next unless middleware + klass, *args = middleware + app = klass.new(app, *args) + end + app + end + + def wrapped_app + @wrapped_app ||= build_app app + end + + def daemonize_app + # Cannot be covered as it forks + # :nocov: + Process.daemon + # :nocov: + end + + def write_pid + ::File.open(options[:pid], ::File::CREAT | ::File::EXCL | ::File::WRONLY ){ |f| f.write("#{Process.pid}") } + at_exit { ::FileUtils.rm_f(options[:pid]) } + rescue Errno::EEXIST + check_pid! + retry + end + + def check_pid! + case pidfile_process_status + when :running, :not_owned + $stderr.puts "A server is already running. Check #{options[:pid]}." + exit(1) + when :dead + ::File.delete(options[:pid]) + end + end + + def pidfile_process_status + return :exited unless ::File.exist?(options[:pid]) + + pid = ::File.read(options[:pid]).to_i + return :dead if pid == 0 + + Process.kill(0, pid) + :running + rescue Errno::ESRCH + :dead + rescue Errno::EPERM + :not_owned + end + + end + +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/abstract/id.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/abstract/id.rb new file mode 100644 index 0000000000..638bd3b3b0 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/abstract/id.rb @@ -0,0 +1,523 @@ +# frozen_string_literal: true + +# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net +# bugrep: Andreas Zehnder + +require_relative '../../../rack' +require 'time' +require 'securerandom' +require 'digest/sha2' + +module Rack + + module Session + + class SessionId + ID_VERSION = 2 + + attr_reader :public_id + + def initialize(public_id) + @public_id = public_id + end + + def private_id + "#{ID_VERSION}::#{hash_sid(public_id)}" + end + + alias :cookie_value :public_id + alias :to_s :public_id + + def empty?; false; end + def inspect; public_id.inspect; end + + private + + def hash_sid(sid) + Digest::SHA256.hexdigest(sid) + end + end + + module Abstract + # SessionHash is responsible to lazily load the session from store. + + class SessionHash + include Enumerable + attr_writer :id + + Unspecified = Object.new + + def self.find(req) + req.get_header RACK_SESSION + end + + def self.set(req, session) + req.set_header RACK_SESSION, session + end + + def self.set_options(req, options) + req.set_header RACK_SESSION_OPTIONS, options.dup + end + + def initialize(store, req) + @store = store + @req = req + @loaded = false + end + + def id + return @id if @loaded or instance_variable_defined?(:@id) + @id = @store.send(:extract_session_id, @req) + end + + def options + @req.session_options + end + + def each(&block) + load_for_read! + @data.each(&block) + end + + def [](key) + load_for_read! + @data[key.to_s] + end + + def dig(key, *keys) + load_for_read! + @data.dig(key.to_s, *keys) + end + + def fetch(key, default = Unspecified, &block) + load_for_read! + if default == Unspecified + @data.fetch(key.to_s, &block) + else + @data.fetch(key.to_s, default, &block) + end + end + + def has_key?(key) + load_for_read! + @data.has_key?(key.to_s) + end + alias :key? :has_key? + alias :include? :has_key? + + def []=(key, value) + load_for_write! + @data[key.to_s] = value + end + alias :store :[]= + + def clear + load_for_write! + @data.clear + end + + def destroy + clear + @id = @store.send(:delete_session, @req, id, options) + end + + def to_hash + load_for_read! + @data.dup + end + + def update(hash) + load_for_write! + @data.update(stringify_keys(hash)) + end + alias :merge! :update + + def replace(hash) + load_for_write! + @data.replace(stringify_keys(hash)) + end + + def delete(key) + load_for_write! + @data.delete(key.to_s) + end + + def inspect + if loaded? + @data.inspect + else + "#<#{self.class}:0x#{self.object_id.to_s(16)} not yet loaded>" + end + end + + def exists? + return @exists if instance_variable_defined?(:@exists) + @data = {} + @exists = @store.send(:session_exists?, @req) + end + + def loaded? + @loaded + end + + def empty? + load_for_read! + @data.empty? + end + + def keys + load_for_read! + @data.keys + end + + def values + load_for_read! + @data.values + end + + private + + def load_for_read! + load! if !loaded? && exists? + end + + def load_for_write! + load! unless loaded? + end + + def load! + @id, session = @store.send(:load_session, @req) + @data = stringify_keys(session) + @loaded = true + end + + def stringify_keys(other) + # Use transform_keys after dropping Ruby 2.4 support + hash = {} + other.to_hash.each do |key, value| + hash[key.to_s] = value + end + hash + end + end + + # ID sets up a basic framework for implementing an id based sessioning + # service. Cookies sent to the client for maintaining sessions will only + # contain an id reference. Only #find_session, #write_session and + # #delete_session are required to be overwritten. + # + # All parameters are optional. + # * :key determines the name of the cookie, by default it is + # 'rack.session' + # * :path, :domain, :expire_after, :secure, and :httponly set the related + # cookie options as by Rack::Response#set_cookie + # * :skip will not a set a cookie in the response nor update the session state + # * :defer will not set a cookie in the response but still update the session + # state if it is used with a backend + # * :renew (implementation dependent) will prompt the generation of a new + # session id, and migration of data to be referenced at the new id. If + # :defer is set, it will be overridden and the cookie will be set. + # * :sidbits sets the number of bits in length that a generated session + # id will be. + # + # These options can be set on a per request basis, at the location of + # env['rack.session.options']. Additionally the id of the + # session can be found within the options hash at the key :id. It is + # highly not recommended to change its value. + # + # Is Rack::Utils::Context compatible. + # + # Not included by default; you must require 'rack/session/abstract/id' + # to use. + + class Persisted + DEFAULT_OPTIONS = { + key: RACK_SESSION, + path: '/', + domain: nil, + expire_after: nil, + secure: false, + httponly: true, + defer: false, + renew: false, + sidbits: 128, + cookie_only: true, + secure_random: ::SecureRandom + }.freeze + + attr_reader :key, :default_options, :sid_secure + + def initialize(app, options = {}) + @app = app + @default_options = self.class::DEFAULT_OPTIONS.merge(options) + @key = @default_options.delete(:key) + @cookie_only = @default_options.delete(:cookie_only) + @same_site = @default_options.delete(:same_site) + initialize_sid + end + + def call(env) + context(env) + end + + def context(env, app = @app) + req = make_request env + prepare_session(req) + status, headers, body = app.call(req.env) + res = Rack::Response::Raw.new status, headers + commit_session(req, res) + [status, headers, body] + end + + private + + def make_request(env) + Rack::Request.new env + end + + def initialize_sid + @sidbits = @default_options[:sidbits] + @sid_secure = @default_options[:secure_random] + @sid_length = @sidbits / 4 + end + + # Generate a new session id using Ruby #rand. The size of the + # session id is controlled by the :sidbits option. + # Monkey patch this to use custom methods for session id generation. + + def generate_sid(secure = @sid_secure) + if secure + secure.hex(@sid_length) + else + "%0#{@sid_length}x" % Kernel.rand(2**@sidbits - 1) + end + rescue NotImplementedError + generate_sid(false) + end + + # Sets the lazy session at 'rack.session' and places options and session + # metadata into 'rack.session.options'. + + def prepare_session(req) + session_was = req.get_header RACK_SESSION + session = session_class.new(self, req) + req.set_header RACK_SESSION, session + req.set_header RACK_SESSION_OPTIONS, @default_options.dup + session.merge! session_was if session_was + end + + # Extracts the session id from provided cookies and passes it and the + # environment to #find_session. + + def load_session(req) + sid = current_session_id(req) + sid, session = find_session(req, sid) + [sid, session || {}] + end + + # Extract session id from request object. + + def extract_session_id(request) + sid = request.cookies[@key] + sid ||= request.params[@key] unless @cookie_only + sid + end + + # Returns the current session id from the SessionHash. + + def current_session_id(req) + req.get_header(RACK_SESSION).id + end + + # Check if the session exists or not. + + def session_exists?(req) + value = current_session_id(req) + value && !value.empty? + end + + # Session should be committed if it was loaded, any of specific options like :renew, :drop + # or :expire_after was given and the security permissions match. Skips if skip is given. + + def commit_session?(req, session, options) + if options[:skip] + false + else + has_session = loaded_session?(session) || forced_session_update?(session, options) + has_session && security_matches?(req, options) + end + end + + def loaded_session?(session) + !session.is_a?(session_class) || session.loaded? + end + + def forced_session_update?(session, options) + force_options?(options) && session && !session.empty? + end + + def force_options?(options) + options.values_at(:max_age, :renew, :drop, :defer, :expire_after).any? + end + + def security_matches?(request, options) + return true unless options[:secure] + request.ssl? + end + + # Acquires the session from the environment and the session id from + # the session options and passes them to #write_session. If successful + # and the :defer option is not true, a cookie will be added to the + # response with the session's id. + + def commit_session(req, res) + session = req.get_header RACK_SESSION + options = session.options + + if options[:drop] || options[:renew] + session_id = delete_session(req, session.id || generate_sid, options) + return unless session_id + end + + return unless commit_session?(req, session, options) + + session.send(:load!) unless loaded_session?(session) + session_id ||= session.id + session_data = session.to_hash.delete_if { |k, v| v.nil? } + + if not data = write_session(req, session_id, session_data, options) + req.get_header(RACK_ERRORS).puts("Warning! #{self.class.name} failed to save session. Content dropped.") + elsif options[:defer] and not options[:renew] + req.get_header(RACK_ERRORS).puts("Deferring cookie for #{session_id}") if $VERBOSE + else + cookie = Hash.new + cookie[:value] = cookie_value(data) + cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after] + cookie[:expires] = Time.now + options[:max_age] if options[:max_age] + + if @same_site.respond_to? :call + cookie[:same_site] = @same_site.call(req, res) + else + cookie[:same_site] = @same_site + end + set_cookie(req, res, cookie.merge!(options)) + end + end + public :commit_session + + def cookie_value(data) + data + end + + # Sets the cookie back to the client with session id. We skip the cookie + # setting if the value didn't change (sid is the same) or expires was given. + + def set_cookie(request, res, cookie) + if request.cookies[@key] != cookie[:value] || cookie[:expires] + res.set_cookie_header = + Utils.add_cookie_to_header(res.set_cookie_header, @key, cookie) + end + end + + # Allow subclasses to prepare_session for different Session classes + + def session_class + SessionHash + end + + # All thread safety and session retrieval procedures should occur here. + # Should return [session_id, session]. + # If nil is provided as the session id, generation of a new valid id + # should occur within. + + def find_session(env, sid) + raise '#find_session not implemented.' + end + + # All thread safety and session storage procedures should occur here. + # Must return the session id if the session was saved successfully, or + # false if the session could not be saved. + + def write_session(req, sid, session, options) + raise '#write_session not implemented.' + end + + # All thread safety and session destroy procedures should occur here. + # Should return a new session id or nil if options[:drop] + + def delete_session(req, sid, options) + raise '#delete_session not implemented' + end + end + + class PersistedSecure < Persisted + class SecureSessionHash < SessionHash + def [](key) + if key == "session_id" + load_for_read! + id.public_id if id + else + super + end + end + end + + def generate_sid(*) + public_id = super + + SessionId.new(public_id) + end + + def extract_session_id(*) + public_id = super + public_id && SessionId.new(public_id) + end + + private + + def session_class + SecureSessionHash + end + + def cookie_value(data) + data.cookie_value + end + end + + class ID < Persisted + def self.inherited(klass) + k = klass.ancestors.find { |kl| kl.respond_to?(:superclass) && kl.superclass == ID } + unless k.instance_variable_defined?(:"@_rack_warned") + warn "#{klass} is inheriting from #{ID}. Inheriting from #{ID} is deprecated, please inherit from #{Persisted} instead" if $VERBOSE + k.instance_variable_set(:"@_rack_warned", true) + end + super + end + + # All thread safety and session retrieval procedures should occur here. + # Should return [session_id, session]. + # If nil is provided as the session id, generation of a new valid id + # should occur within. + + def find_session(req, sid) + get_session req.env, sid + end + + # All thread safety and session storage procedures should occur here. + # Must return the session id if the session was saved successfully, or + # false if the session could not be saved. + + def write_session(req, sid, session, options) + set_session req.env, sid, session, options + end + + # All thread safety and session destroy procedures should occur here. + # Should return a new session id or nil if options[:drop] + + def delete_session(req, sid, options) + destroy_session req.env, sid, options + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/cookie.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/cookie.rb new file mode 100644 index 0000000000..bb541396f7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/cookie.rb @@ -0,0 +1,203 @@ +# frozen_string_literal: true + +require 'openssl' +require 'zlib' +require_relative 'abstract/id' +require 'json' +require 'base64' + +module Rack + + module Session + + # Rack::Session::Cookie provides simple cookie based session management. + # By default, the session is a Ruby Hash stored as base64 encoded marshalled + # data set to :key (default: rack.session). The object that encodes the + # session data is configurable and must respond to +encode+ and +decode+. + # Both methods must take a string and return a string. + # + # When the secret key is set, cookie data is checked for data integrity. + # The old secret key is also accepted and allows graceful secret rotation. + # + # Example: + # + # use Rack::Session::Cookie, :key => 'rack.session', + # :domain => 'foo.com', + # :path => '/', + # :expire_after => 2592000, + # :secret => 'change_me', + # :old_secret => 'also_change_me' + # + # All parameters are optional. + # + # Example of a cookie with no encoding: + # + # Rack::Session::Cookie.new(application, { + # :coder => Rack::Session::Cookie::Identity.new + # }) + # + # Example of a cookie with custom encoding: + # + # Rack::Session::Cookie.new(application, { + # :coder => Class.new { + # def encode(str); str.reverse; end + # def decode(str); str.reverse; end + # }.new + # }) + # + + class Cookie < Abstract::PersistedSecure + # Encode session cookies as Base64 + class Base64 + def encode(str) + ::Base64.strict_encode64(str) + end + + def decode(str) + ::Base64.decode64(str) + end + + # Encode session cookies as Marshaled Base64 data + class Marshal < Base64 + def encode(str) + super(::Marshal.dump(str)) + end + + def decode(str) + return unless str + ::Marshal.load(super(str)) rescue nil + end + end + + # N.B. Unlike other encoding methods, the contained objects must be a + # valid JSON composite type, either a Hash or an Array. + class JSON < Base64 + def encode(obj) + super(::JSON.dump(obj)) + end + + def decode(str) + return unless str + ::JSON.parse(super(str)) rescue nil + end + end + + class ZipJSON < Base64 + def encode(obj) + super(Zlib::Deflate.deflate(::JSON.dump(obj))) + end + + def decode(str) + return unless str + ::JSON.parse(Zlib::Inflate.inflate(super(str))) + rescue + nil + end + end + end + + # Use no encoding for session cookies + class Identity + def encode(str); str; end + def decode(str); str; end + end + + attr_reader :coder + + def initialize(app, options = {}) + @secrets = options.values_at(:secret, :old_secret).compact + @hmac = options.fetch(:hmac, OpenSSL::Digest::SHA1) + + warn <<-MSG unless secure?(options) + SECURITY WARNING: No secret option provided to Rack::Session::Cookie. + This poses a security threat. It is strongly recommended that you + provide a secret to prevent exploits that may be possible from crafted + cookies. This will not be supported in future versions of Rack, and + future versions will even invalidate your existing user cookies. + + Called from: #{caller[0]}. + MSG + @coder = options[:coder] ||= Base64::Marshal.new + super(app, options.merge!(cookie_only: true)) + end + + private + + def find_session(req, sid) + data = unpacked_cookie_data(req) + data = persistent_session_id!(data) + [data["session_id"], data] + end + + def extract_session_id(request) + unpacked_cookie_data(request)["session_id"] + end + + def unpacked_cookie_data(request) + request.fetch_header(RACK_SESSION_UNPACKED_COOKIE_DATA) do |k| + session_data = request.cookies[@key] + + if @secrets.size > 0 && session_data + session_data, _, digest = session_data.rpartition('--') + session_data = nil unless digest_match?(session_data, digest) + end + + request.set_header(k, coder.decode(session_data) || {}) + end + end + + def persistent_session_id!(data, sid = nil) + data ||= {} + data["session_id"] ||= sid || generate_sid + data + end + + class SessionId < DelegateClass(Session::SessionId) + attr_reader :cookie_value + + def initialize(session_id, cookie_value) + super(session_id) + @cookie_value = cookie_value + end + end + + def write_session(req, session_id, session, options) + session = session.merge("session_id" => session_id) + session_data = coder.encode(session) + + if @secrets.first + session_data << "--#{generate_hmac(session_data, @secrets.first)}" + end + + if session_data.size > (4096 - @key.size) + req.get_header(RACK_ERRORS).puts("Warning! Rack::Session::Cookie data size exceeds 4K.") + nil + else + SessionId.new(session_id, session_data) + end + end + + def delete_session(req, session_id, options) + # Nothing to do here, data is in the client + generate_sid unless options[:drop] + end + + def digest_match?(data, digest) + return unless data && digest + @secrets.any? do |secret| + Rack::Utils.secure_compare(digest, generate_hmac(data, secret)) + end + end + + def generate_hmac(data, secret) + OpenSSL::HMAC.hexdigest(@hmac.new, secret, data) + end + + def secure?(options) + @secrets.size >= 1 || + (options[:coder] && options[:let_coder_handle_secure_encoding]) + end + + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/memcache.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/memcache.rb new file mode 100644 index 0000000000..6a60117407 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/memcache.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'rack/session/dalli' + +module Rack + module Session + warn "Rack::Session::Memcache is deprecated, please use Rack::Session::Dalli from 'dalli' gem instead." + Memcache = Dalli + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/pool.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/pool.rb new file mode 100644 index 0000000000..4885605f5d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/session/pool.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +# AUTHOR: blink ; blink#ruby-lang@irc.freenode.net +# THANKS: +# apeiros, for session id generation, expiry setup, and threadiness +# sergio, threadiness and bugreps + +require_relative 'abstract/id' +require 'thread' + +module Rack + module Session + # Rack::Session::Pool provides simple cookie based session management. + # Session data is stored in a hash held by @pool. + # In the context of a multithreaded environment, sessions being + # committed to the pool is done in a merging manner. + # + # The :drop option is available in rack.session.options if you wish to + # explicitly remove the session from the session cache. + # + # Example: + # myapp = MyRackApp.new + # sessioned = Rack::Session::Pool.new(myapp, + # :domain => 'foo.com', + # :expire_after => 2592000 + # ) + # Rack::Handler::WEBrick.run sessioned + + class Pool < Abstract::PersistedSecure + attr_reader :mutex, :pool + DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge drop: false + + def initialize(app, options = {}) + super + @pool = Hash.new + @mutex = Mutex.new + end + + def generate_sid + loop do + sid = super + break sid unless @pool.key? sid.private_id + end + end + + def find_session(req, sid) + with_lock(req) do + unless sid and session = get_session_with_fallback(sid) + sid, session = generate_sid, {} + @pool.store sid.private_id, session + end + [sid, session] + end + end + + def write_session(req, session_id, new_session, options) + with_lock(req) do + @pool.store session_id.private_id, new_session + session_id + end + end + + def delete_session(req, session_id, options) + with_lock(req) do + @pool.delete(session_id.public_id) + @pool.delete(session_id.private_id) + generate_sid unless options[:drop] + end + end + + def with_lock(req) + @mutex.lock if req.multithread? + yield + ensure + @mutex.unlock if @mutex.locked? + end + + private + + def get_session_with_fallback(sid) + @pool[sid.private_id] || @pool[sid.public_id] + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/show_exceptions.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/show_exceptions.rb new file mode 100644 index 0000000000..07e6038806 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/show_exceptions.rb @@ -0,0 +1,390 @@ +# frozen_string_literal: true + +require 'ostruct' +require 'erb' + +module Rack + # Rack::ShowExceptions catches all exceptions raised from the app it + # wraps. It shows a useful backtrace with the sourcefile and + # clickable context, the whole Rack environment and the request + # data. + # + # Be careful when you use this on public-facing sites as it could + # reveal information helpful to attackers. + + class ShowExceptions + CONTEXT = 7 + + def initialize(app) + @app = app + end + + def call(env) + @app.call(env) + rescue StandardError, LoadError, SyntaxError => e + exception_string = dump_exception(e) + + env[RACK_ERRORS].puts(exception_string) + env[RACK_ERRORS].flush + + if accepts_html?(env) + content_type = "text/html" + body = pretty(env, e) + else + content_type = "text/plain" + body = exception_string + end + + [ + 500, + { + CONTENT_TYPE => content_type, + CONTENT_LENGTH => body.bytesize.to_s, + }, + [body], + ] + end + + def prefers_plaintext?(env) + !accepts_html?(env) + end + + def accepts_html?(env) + Rack::Utils.best_q_match(env["HTTP_ACCEPT"], %w[text/html]) + end + private :accepts_html? + + def dump_exception(exception) + string = "#{exception.class}: #{exception.message}\n".dup + string << exception.backtrace.map { |l| "\t#{l}" }.join("\n") + string + end + + def pretty(env, exception) + req = Rack::Request.new(env) + + # This double assignment is to prevent an "unused variable" warning. + # Yes, it is dumb, but I don't like Ruby yelling at me. + path = path = (req.script_name + req.path_info).squeeze("/") + + # This double assignment is to prevent an "unused variable" warning. + # Yes, it is dumb, but I don't like Ruby yelling at me. + frames = frames = exception.backtrace.map { |line| + frame = OpenStruct.new + if line =~ /(.*?):(\d+)(:in `(.*)')?/ + frame.filename = $1 + frame.lineno = $2.to_i + frame.function = $4 + + begin + lineno = frame.lineno - 1 + lines = ::File.readlines(frame.filename) + frame.pre_context_lineno = [lineno - CONTEXT, 0].max + frame.pre_context = lines[frame.pre_context_lineno...lineno] + frame.context_line = lines[lineno].chomp + frame.post_context_lineno = [lineno + CONTEXT, lines.size].min + frame.post_context = lines[lineno + 1..frame.post_context_lineno] + rescue + end + + frame + else + nil + end + }.compact + + template.result(binding) + end + + def template + TEMPLATE + end + + def h(obj) # :nodoc: + case obj + when String + Utils.escape_html(obj) + else + Utils.escape_html(obj.inspect) + end + end + + # :stopdoc: + + # adapted from Django + # Copyright (c) Django Software Foundation and individual contributors. + # Used under the modified BSD license: + # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 + TEMPLATE = ERB.new(<<-'HTML'.gsub(/^ /, '')) + + + + + + <%=h exception.class %> at <%=h path %> + + + + + +
+

<%=h exception.class %> at <%=h path %>

+

<%=h exception.message %>

+ + + + + + +
Ruby + <% if first = frames.first %> + <%=h first.filename %>: in <%=h first.function %>, line <%=h frames.first.lineno %> + <% else %> + unknown location + <% end %> +
Web<%=h req.request_method %> <%=h(req.host + path)%>
+ +

Jump to:

+ +
+ +
+

Traceback (innermost first)

+
    + <% frames.each { |frame| %> +
  • + <%=h frame.filename %>: in <%=h frame.function %> + + <% if frame.context_line %> +
    + <% if frame.pre_context %> +
      + <% frame.pre_context.each { |line| %> +
    1. <%=h line %>
    2. + <% } %> +
    + <% end %> + +
      +
    1. <%=h frame.context_line %>...
    + + <% if frame.post_context %> +
      + <% frame.post_context.each { |line| %> +
    1. <%=h line %>
    2. + <% } %> +
    + <% end %> +
    + <% end %> +
  • + <% } %> +
+
+ +
+

Request information

+ +

GET

+ <% if req.GET and not req.GET.empty? %> + + + + + + + + + <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val.inspect %>
+ <% else %> +

No GET data.

+ <% end %> + +

POST

+ <% if ((req.POST and not req.POST.empty?) rescue (no_post_data = "Invalid POST data"; nil)) %> + + + + + + + + + <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val.inspect %>
+ <% else %> +

<%= no_post_data || "No POST data" %>.

+ <% end %> + + + + <% unless req.cookies.empty? %> + + + + + + + + + <% req.cookies.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val.inspect %>
+ <% else %> +

No cookie data.

+ <% end %> + +

Rack ENV

+ + + + + + + + + <% env.sort_by { |k, v| k.to_s }.each { |key, val| %> + + + + + <% } %> + +
VariableValue
<%=h key %>
<%=h val.inspect %>
+ +
+ +
+

+ You're seeing this error because you use Rack::ShowExceptions. +

+
+ + + + HTML + + # :startdoc: + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/show_status.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/show_status.rb new file mode 100644 index 0000000000..a99bdaf33a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/show_status.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +require 'erb' + +module Rack + # Rack::ShowStatus catches all empty responses and replaces them + # with a site explaining the error. + # + # Additional details can be put into rack.showstatus.detail + # and will be shown as HTML. If such details exist, the error page + # is always rendered, even if the reply was not empty. + + class ShowStatus + def initialize(app) + @app = app + @template = ERB.new(TEMPLATE) + end + + def call(env) + status, headers, body = @app.call(env) + headers = Utils::HeaderHash[headers] + empty = headers[CONTENT_LENGTH].to_i <= 0 + + # client or server error, or explicit message + if (status.to_i >= 400 && empty) || env[RACK_SHOWSTATUS_DETAIL] + # This double assignment is to prevent an "unused variable" warning. + # Yes, it is dumb, but I don't like Ruby yelling at me. + req = req = Rack::Request.new(env) + + message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s + + # This double assignment is to prevent an "unused variable" warning. + # Yes, it is dumb, but I don't like Ruby yelling at me. + detail = detail = env[RACK_SHOWSTATUS_DETAIL] || message + + body = @template.result(binding) + size = body.bytesize + [status, headers.merge(CONTENT_TYPE => "text/html", CONTENT_LENGTH => size.to_s), [body]] + else + [status, headers, body] + end + end + + def h(obj) # :nodoc: + case obj + when String + Utils.escape_html(obj) + else + Utils.escape_html(obj.inspect) + end + end + + # :stopdoc: + +# adapted from Django +# Copyright (c) Django Software Foundation and individual contributors. +# Used under the modified BSD license: +# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 +TEMPLATE = <<'HTML' + + + + + <%=h message %> at <%=h req.script_name + req.path_info %> + + + + +
+

<%=h message %> (<%= status.to_i %>)

+ + + + + + + + + +
Request Method:<%=h req.request_method %>
Request URL:<%=h req.url %>
+
+
+

<%=h detail %>

+
+ +
+

+ You're seeing this error because you use Rack::ShowStatus. +

+
+ + +HTML + + # :startdoc: + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/static.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/static.rb new file mode 100644 index 0000000000..8cb58b2fd7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/static.rb @@ -0,0 +1,187 @@ +# frozen_string_literal: true + +module Rack + + # The Rack::Static middleware intercepts requests for static files + # (javascript files, images, stylesheets, etc) based on the url prefixes or + # route mappings passed in the options, and serves them using a Rack::Files + # object. This allows a Rack stack to serve both static and dynamic content. + # + # Examples: + # + # Serve all requests beginning with /media from the "media" folder located + # in the current directory (ie media/*): + # + # use Rack::Static, :urls => ["/media"] + # + # Same as previous, but instead of returning 404 for missing files under + # /media, call the next middleware: + # + # use Rack::Static, :urls => ["/media"], :cascade => true + # + # Serve all requests beginning with /css or /images from the folder "public" + # in the current directory (ie public/css/* and public/images/*): + # + # use Rack::Static, :urls => ["/css", "/images"], :root => "public" + # + # Serve all requests to / with "index.html" from the folder "public" in the + # current directory (ie public/index.html): + # + # use Rack::Static, :urls => {"/" => 'index.html'}, :root => 'public' + # + # Serve all requests normally from the folder "public" in the current + # directory but uses index.html as default route for "/" + # + # use Rack::Static, :urls => [""], :root => 'public', :index => + # 'index.html' + # + # Set custom HTTP Headers for based on rules: + # + # use Rack::Static, :root => 'public', + # :header_rules => [ + # [rule, {header_field => content, header_field => content}], + # [rule, {header_field => content}] + # ] + # + # Rules for selecting files: + # + # 1) All files + # Provide the :all symbol + # :all => Matches every file + # + # 2) Folders + # Provide the folder path as a string + # '/folder' or '/folder/subfolder' => Matches files in a certain folder + # + # 3) File Extensions + # Provide the file extensions as an array + # ['css', 'js'] or %w(css js) => Matches files ending in .css or .js + # + # 4) Regular Expressions / Regexp + # Provide a regular expression + # %r{\.(?:css|js)\z} => Matches files ending in .css or .js + # /\.(?:eot|ttf|otf|woff2|woff|svg)\z/ => Matches files ending in + # the most common web font formats (.eot, .ttf, .otf, .woff2, .woff, .svg) + # Note: This Regexp is available as a shortcut, using the :fonts rule + # + # 5) Font Shortcut + # Provide the :fonts symbol + # :fonts => Uses the Regexp rule stated right above to match all common web font endings + # + # Rule Ordering: + # Rules are applied in the order that they are provided. + # List rather general rules above special ones. + # + # Complete example use case including HTTP header rules: + # + # use Rack::Static, :root => 'public', + # :header_rules => [ + # # Cache all static files in public caches (e.g. Rack::Cache) + # # as well as in the browser + # [:all, {'Cache-Control' => 'public, max-age=31536000'}], + # + # # Provide web fonts with cross-origin access-control-headers + # # Firefox requires this when serving assets using a Content Delivery Network + # [:fonts, {'Access-Control-Allow-Origin' => '*'}] + # ] + # + class Static + (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4' + + def initialize(app, options = {}) + @app = app + @urls = options[:urls] || ["/favicon.ico"] + @index = options[:index] + @gzip = options[:gzip] + @cascade = options[:cascade] + root = options[:root] || Dir.pwd + + # HTTP Headers + @header_rules = options[:header_rules] || [] + # Allow for legacy :cache_control option while prioritizing global header_rules setting + @header_rules.unshift([:all, { CACHE_CONTROL => options[:cache_control] }]) if options[:cache_control] + + @file_server = Rack::Files.new(root) + end + + def add_index_root?(path) + @index && route_file(path) && path.end_with?('/') + end + + def overwrite_file_path(path) + @urls.kind_of?(Hash) && @urls.key?(path) || add_index_root?(path) + end + + def route_file(path) + @urls.kind_of?(Array) && @urls.any? { |url| path.index(url) == 0 } + end + + def can_serve(path) + route_file(path) || overwrite_file_path(path) + end + + def call(env) + path = env[PATH_INFO] + + if can_serve(path) + if overwrite_file_path(path) + env[PATH_INFO] = (add_index_root?(path) ? path + @index : @urls[path]) + elsif @gzip && env['HTTP_ACCEPT_ENCODING'] && /\bgzip\b/.match?(env['HTTP_ACCEPT_ENCODING']) + path = env[PATH_INFO] + env[PATH_INFO] += '.gz' + response = @file_server.call(env) + env[PATH_INFO] = path + + if response[0] == 404 + response = nil + elsif response[0] == 304 + # Do nothing, leave headers as is + else + if mime_type = Mime.mime_type(::File.extname(path), 'text/plain') + response[1][CONTENT_TYPE] = mime_type + end + response[1]['Content-Encoding'] = 'gzip' + end + end + + path = env[PATH_INFO] + response ||= @file_server.call(env) + + if @cascade && response[0] == 404 + return @app.call(env) + end + + headers = response[1] + applicable_rules(path).each do |rule, new_headers| + new_headers.each { |field, content| headers[field] = content } + end + + response + else + @app.call(env) + end + end + + # Convert HTTP header rules to HTTP headers + def applicable_rules(path) + @header_rules.find_all do |rule, new_headers| + case rule + when :all + true + when :fonts + /\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path) + when String + path = ::Rack::Utils.unescape(path) + path.start_with?(rule) || path.start_with?('/' + rule) + when Array + /\.(#{rule.join('|')})\z/.match?(path) + when Regexp + rule.match?(path) + else + false + end + end + end + + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/tempfile_reaper.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/tempfile_reaper.rb new file mode 100644 index 0000000000..9b04fefc24 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/tempfile_reaper.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Rack + + # Middleware tracks and cleans Tempfiles created throughout a request (i.e. Rack::Multipart) + # Ideas/strategy based on posts by Eric Wong and Charles Oliver Nutter + # https://groups.google.com/forum/#!searchin/rack-devel/temp/rack-devel/brK8eh-MByw/sw61oJJCGRMJ + class TempfileReaper + def initialize(app) + @app = app + end + + def call(env) + env[RACK_TEMPFILES] ||= [] + status, headers, body = @app.call(env) + body_proxy = BodyProxy.new(body) do + env[RACK_TEMPFILES].each(&:close!) unless env[RACK_TEMPFILES].nil? + end + [status, headers, body_proxy] + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/urlmap.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/urlmap.rb new file mode 100644 index 0000000000..31a642c418 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/urlmap.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +require 'set' + +module Rack + # Rack::URLMap takes a hash mapping urls or paths to apps, and + # dispatches accordingly. Support for HTTP/1.1 host names exists if + # the URLs start with http:// or https://. + # + # URLMap modifies the SCRIPT_NAME and PATH_INFO such that the part + # relevant for dispatch is in the SCRIPT_NAME, and the rest in the + # PATH_INFO. This should be taken care of when you need to + # reconstruct the URL in order to create links. + # + # URLMap dispatches in such a way that the longest paths are tried + # first, since they are most specific. + + class URLMap + def initialize(map = {}) + remap(map) + end + + def remap(map) + @known_hosts = Set[] + @mapping = map.map { |location, app| + if location =~ %r{\Ahttps?://(.*?)(/.*)} + host, location = $1, $2 + @known_hosts << host + else + host = nil + end + + unless location[0] == ?/ + raise ArgumentError, "paths need to start with /" + end + + location = location.chomp('/') + match = Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", nil, 'n') + + [host, location, match, app] + }.sort_by do |(host, location, _, _)| + [host ? -host.size : Float::INFINITY, -location.size] + end + end + + def call(env) + path = env[PATH_INFO] + script_name = env[SCRIPT_NAME] + http_host = env[HTTP_HOST] + server_name = env[SERVER_NAME] + server_port = env[SERVER_PORT] + + is_same_server = casecmp?(http_host, server_name) || + casecmp?(http_host, "#{server_name}:#{server_port}") + + is_host_known = @known_hosts.include? http_host + + @mapping.each do |host, location, match, app| + unless casecmp?(http_host, host) \ + || casecmp?(server_name, host) \ + || (!host && is_same_server) \ + || (!host && !is_host_known) # If we don't have a matching host, default to the first without a specified host + next + end + + next unless m = match.match(path.to_s) + + rest = m[1] + next unless !rest || rest.empty? || rest[0] == ?/ + + env[SCRIPT_NAME] = (script_name + location) + env[PATH_INFO] = rest + + return app.call(env) + end + + [404, { CONTENT_TYPE => "text/plain", "X-Cascade" => "pass" }, ["Not Found: #{path}"]] + + ensure + env[PATH_INFO] = path + env[SCRIPT_NAME] = script_name + end + + private + def casecmp?(v1, v2) + # if both nil, or they're the same string + return true if v1 == v2 + + # if either are nil... (but they're not the same) + return false if v1.nil? + return false if v2.nil? + + # otherwise check they're not case-insensitive the same + v1.casecmp(v2).zero? + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/utils.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/utils.rb new file mode 100644 index 0000000000..d3b3b1d420 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/utils.rb @@ -0,0 +1,613 @@ +# -*- encoding: binary -*- +# frozen_string_literal: true + +require 'uri' +require 'fileutils' +require 'set' +require 'tempfile' +require 'time' + +require_relative 'query_parser' + +module Rack + # Rack::Utils contains a grab-bag of useful methods for writing web + # applications adopted from all kinds of Ruby libraries. + + module Utils + (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4' + + ParameterTypeError = QueryParser::ParameterTypeError + InvalidParameterError = QueryParser::InvalidParameterError + DEFAULT_SEP = QueryParser::DEFAULT_SEP + COMMON_SEP = QueryParser::COMMON_SEP + KeySpaceConstrainedParams = QueryParser::Params + + class << self + attr_accessor :default_query_parser + end + # The default number of bytes to allow parameter keys to take up. + # This helps prevent a rogue client from flooding a Request. + self.default_query_parser = QueryParser.make_default(65536, 100) + + module_function + + # URI escapes. (CGI style space to +) + def escape(s) + URI.encode_www_form_component(s) + end + + # Like URI escaping, but with %20 instead of +. Strictly speaking this is + # true URI escaping. + def escape_path(s) + ::URI::DEFAULT_PARSER.escape s + end + + # Unescapes the **path** component of a URI. See Rack::Utils.unescape for + # unescaping query parameters or form components. + def unescape_path(s) + ::URI::DEFAULT_PARSER.unescape s + end + + # Unescapes a URI escaped string with +encoding+. +encoding+ will be the + # target encoding of the string returned, and it defaults to UTF-8 + def unescape(s, encoding = Encoding::UTF_8) + URI.decode_www_form_component(s, encoding) + end + + class << self + attr_accessor :multipart_part_limit + end + + # The maximum number of parts a request can contain. Accepting too many part + # can lead to the server running out of file handles. + # Set to `0` for no limit. + self.multipart_part_limit = (ENV['RACK_MULTIPART_PART_LIMIT'] || 128).to_i + + def self.param_depth_limit + default_query_parser.param_depth_limit + end + + def self.param_depth_limit=(v) + self.default_query_parser = self.default_query_parser.new_depth_limit(v) + end + + def self.key_space_limit + default_query_parser.key_space_limit + end + + def self.key_space_limit=(v) + self.default_query_parser = self.default_query_parser.new_space_limit(v) + end + + if defined?(Process::CLOCK_MONOTONIC) + def clock_time + Process.clock_gettime(Process::CLOCK_MONOTONIC) + end + else + # :nocov: + def clock_time + Time.now.to_f + end + # :nocov: + end + + def parse_query(qs, d = nil, &unescaper) + Rack::Utils.default_query_parser.parse_query(qs, d, &unescaper) + end + + def parse_nested_query(qs, d = nil) + Rack::Utils.default_query_parser.parse_nested_query(qs, d) + end + + def build_query(params) + params.map { |k, v| + if v.class == Array + build_query(v.map { |x| [k, x] }) + else + v.nil? ? escape(k) : "#{escape(k)}=#{escape(v)}" + end + }.join("&") + end + + def build_nested_query(value, prefix = nil) + case value + when Array + value.map { |v| + build_nested_query(v, "#{prefix}[]") + }.join("&") + when Hash + value.map { |k, v| + build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k)) + }.delete_if(&:empty?).join('&') + when nil + prefix + else + raise ArgumentError, "value must be a Hash" if prefix.nil? + "#{prefix}=#{escape(value)}" + end + end + + def q_values(q_value_header) + q_value_header.to_s.split(/\s*,\s*/).map do |part| + value, parameters = part.split(/\s*;\s*/, 2) + quality = 1.0 + if parameters && (md = /\Aq=([\d.]+)/.match(parameters)) + quality = md[1].to_f + end + [value, quality] + end + end + + # Return best accept value to use, based on the algorithm + # in RFC 2616 Section 14. If there are multiple best + # matches (same specificity and quality), the value returned + # is arbitrary. + def best_q_match(q_value_header, available_mimes) + values = q_values(q_value_header) + + matches = values.map do |req_mime, quality| + match = available_mimes.find { |am| Rack::Mime.match?(am, req_mime) } + next unless match + [match, quality] + end.compact.sort_by do |match, quality| + (match.split('/', 2).count('*') * -10) + quality + end.last + matches && matches.first + end + + ESCAPE_HTML = { + "&" => "&", + "<" => "<", + ">" => ">", + "'" => "'", + '"' => """, + "/" => "/" + } + + ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys) + + # Escape ampersands, brackets and quotes to their HTML/XML entities. + def escape_html(string) + string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] } + end + + def select_best_encoding(available_encodings, accept_encoding) + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + + expanded_accept_encoding = [] + + accept_encoding.each do |m, q| + preference = available_encodings.index(m) || available_encodings.size + + if m == "*" + (available_encodings - accept_encoding.map(&:first)).each do |m2| + expanded_accept_encoding << [m2, q, preference] + end + else + expanded_accept_encoding << [m, q, preference] + end + end + + encoding_candidates = expanded_accept_encoding + .sort_by { |_, q, p| [-q, p] } + .map!(&:first) + + unless encoding_candidates.include?("identity") + encoding_candidates.push("identity") + end + + expanded_accept_encoding.each do |m, q| + encoding_candidates.delete(m) if q == 0.0 + end + + (encoding_candidates & available_encodings)[0] + end + + def parse_cookies(env) + parse_cookies_header env[HTTP_COOKIE] + end + + def parse_cookies_header(header) + # According to RFC 6265: + # The syntax for cookie headers only supports semicolons + # User Agent -> Server == + # Cookie: SID=31d4d96e407aad42; lang=en-US + return {} unless header + header.split(/[;] */n).each_with_object({}) do |cookie, cookies| + next if cookie.empty? + key, value = cookie.split('=', 2) + cookies[key] = (unescape(value) rescue value) unless cookies.key?(key) + end + end + + def add_cookie_to_header(header, key, value) + case value + when Hash + domain = "; domain=#{value[:domain]}" if value[:domain] + path = "; path=#{value[:path]}" if value[:path] + max_age = "; max-age=#{value[:max_age]}" if value[:max_age] + expires = "; expires=#{value[:expires].httpdate}" if value[:expires] + secure = "; secure" if value[:secure] + httponly = "; HttpOnly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only]) + same_site = + case value[:same_site] + when false, nil + nil + when :none, 'None', :None + '; SameSite=None' + when :lax, 'Lax', :Lax + '; SameSite=Lax' + when true, :strict, 'Strict', :Strict + '; SameSite=Strict' + else + raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}" + end + value = value[:value] + end + value = [value] unless Array === value + + cookie = "#{escape(key)}=#{value.map { |v| escape v }.join('&')}#{domain}" \ + "#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}" + + case header + when nil, '' + cookie + when String + [header, cookie].join("\n") + when Array + (header + [cookie]).join("\n") + else + raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}" + end + end + + def set_cookie_header!(header, key, value) + header[SET_COOKIE] = add_cookie_to_header(header[SET_COOKIE], key, value) + nil + end + + def make_delete_cookie_header(header, key, value) + case header + when nil, '' + cookies = [] + when String + cookies = header.split("\n") + when Array + cookies = header + end + + key = escape(key) + domain = value[:domain] + path = value[:path] + regexp = if domain + if path + /\A#{key}=.*(?:domain=#{domain}(?:;|$).*path=#{path}(?:;|$)|path=#{path}(?:;|$).*domain=#{domain}(?:;|$))/ + else + /\A#{key}=.*domain=#{domain}(?:;|$)/ + end + elsif path + /\A#{key}=.*path=#{path}(?:;|$)/ + else + /\A#{key}=/ + end + + cookies.reject! { |cookie| regexp.match? cookie } + + cookies.join("\n") + end + + def delete_cookie_header!(header, key, value = {}) + header[SET_COOKIE] = add_remove_cookie_to_header(header[SET_COOKIE], key, value) + nil + end + + # Adds a cookie that will *remove* a cookie from the client. Hence the + # strange method name. + def add_remove_cookie_to_header(header, key, value = {}) + new_header = make_delete_cookie_header(header, key, value) + + add_cookie_to_header(new_header, key, + { value: '', path: nil, domain: nil, + max_age: '0', + expires: Time.at(0) }.merge(value)) + + end + + def rfc2822(time) + time.rfc2822 + end + + # Modified version of stdlib time.rb Time#rfc2822 to use '%d-%b-%Y' instead + # of '% %b %Y'. + # It assumes that the time is in GMT to comply to the RFC 2109. + # + # NOTE: I'm not sure the RFC says it requires GMT, but is ambiguous enough + # that I'm certain someone implemented only that option. + # Do not use %a and %b from Time.strptime, it would use localized names for + # weekday and month. + # + def rfc2109(time) + wday = Time::RFC2822_DAY_NAME[time.wday] + mon = Time::RFC2822_MONTH_NAME[time.mon - 1] + time.strftime("#{wday}, %d-#{mon}-%Y %H:%M:%S GMT") + end + + # Parses the "Range:" header, if present, into an array of Range objects. + # Returns nil if the header is missing or syntactically invalid. + # Returns an empty array if none of the ranges are satisfiable. + def byte_ranges(env, size) + warn "`byte_ranges` is deprecated, please use `get_byte_ranges`" if $VERBOSE + get_byte_ranges env['HTTP_RANGE'], size + end + + def get_byte_ranges(http_range, size) + # See + return nil unless http_range && http_range =~ /bytes=([^;]+)/ + ranges = [] + $1.split(/,\s*/).each do |range_spec| + return nil unless range_spec =~ /(\d*)-(\d*)/ + r0, r1 = $1, $2 + if r0.empty? + return nil if r1.empty? + # suffix-byte-range-spec, represents trailing suffix of file + r0 = size - r1.to_i + r0 = 0 if r0 < 0 + r1 = size - 1 + else + r0 = r0.to_i + if r1.empty? + r1 = size - 1 + else + r1 = r1.to_i + return nil if r1 < r0 # backwards range is syntactically invalid + r1 = size - 1 if r1 >= size + end + end + ranges << (r0..r1) if r0 <= r1 + end + ranges + end + + # Constant time string comparison. + # + # NOTE: the values compared should be of fixed length, such as strings + # that have already been processed by HMAC. This should not be used + # on variable length plaintext strings because it could leak length info + # via timing attacks. + def secure_compare(a, b) + return false unless a.bytesize == b.bytesize + + l = a.unpack("C*") + + r, i = 0, -1 + b.each_byte { |v| r |= v ^ l[i += 1] } + r == 0 + end + + # Context allows the use of a compatible middleware at different points + # in a request handling stack. A compatible middleware must define + # #context which should take the arguments env and app. The first of which + # would be the request environment. The second of which would be the rack + # application that the request would be forwarded to. + class Context + attr_reader :for, :app + + def initialize(app_f, app_r) + raise 'running context does not respond to #context' unless app_f.respond_to? :context + @for, @app = app_f, app_r + end + + def call(env) + @for.context(env, @app) + end + + def recontext(app) + self.class.new(@for, app) + end + + def context(env, app = @app) + recontext(app).call(env) + end + end + + # A case-insensitive Hash that preserves the original case of a + # header when set. + # + # @api private + class HeaderHash < Hash # :nodoc: + def self.[](headers) + if headers.is_a?(HeaderHash) && !headers.frozen? + return headers + else + return self.new(headers) + end + end + + def initialize(hash = {}) + super() + @names = {} + hash.each { |k, v| self[k] = v } + end + + # on dup/clone, we need to duplicate @names hash + def initialize_copy(other) + super + @names = other.names.dup + end + + # on clear, we need to clear @names hash + def clear + super + @names.clear + end + + def each + super do |k, v| + yield(k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v) + end + end + + def to_hash + hash = {} + each { |k, v| hash[k] = v } + hash + end + + def [](k) + super(k) || super(@names[k.downcase]) + end + + def []=(k, v) + canonical = k.downcase.freeze + delete k if @names[canonical] && @names[canonical] != k # .delete is expensive, don't invoke it unless necessary + @names[canonical] = k + super k, v + end + + def delete(k) + canonical = k.downcase + result = super @names.delete(canonical) + result + end + + def include?(k) + super || @names.include?(k.downcase) + end + + alias_method :has_key?, :include? + alias_method :member?, :include? + alias_method :key?, :include? + + def merge!(other) + other.each { |k, v| self[k] = v } + self + end + + def merge(other) + hash = dup + hash.merge! other + end + + def replace(other) + clear + other.each { |k, v| self[k] = v } + self + end + + protected + def names + @names + end + end + + # Every standard HTTP code mapped to the appropriate message. + # Generated with: + # curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv | \ + # ruby -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \ + # puts "#{m[1]} => \x27#{m[2].strip}\x27,"' + HTTP_STATUS_CODES = { + 100 => 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + 103 => 'Early Hints', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', + 208 => 'Already Reported', + 226 => 'IM Used', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 306 => '(Unused)', + 307 => 'Temporary Redirect', + 308 => 'Permanent Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Payload Too Large', + 414 => 'URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Range Not Satisfiable', + 417 => 'Expectation Failed', + 421 => 'Misdirected Request', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 425 => 'Too Early', + 426 => 'Upgrade Required', + 428 => 'Precondition Required', + 429 => 'Too Many Requests', + 431 => 'Request Header Fields Too Large', + 451 => 'Unavailable for Legal Reasons', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates', + 507 => 'Insufficient Storage', + 508 => 'Loop Detected', + 509 => 'Bandwidth Limit Exceeded', + 510 => 'Not Extended', + 511 => 'Network Authentication Required' + } + + # Responses with HTTP status codes that should not have an entity body + STATUS_WITH_NO_ENTITY_BODY = Hash[((100..199).to_a << 204 << 304).product([true])] + + SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message| + [message.downcase.gsub(/\s|-|'/, '_').to_sym, code] + }.flatten] + + def status_code(status) + if status.is_a?(Symbol) + SYMBOL_TO_STATUS_CODE.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" } + else + status.to_i + end + end + + PATH_SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact) + + def clean_path_info(path_info) + parts = path_info.split PATH_SEPS + + clean = [] + + parts.each do |part| + next if part.empty? || part == '.' + part == '..' ? clean.pop : clean << part + end + + clean_path = clean.join(::File::SEPARATOR) + clean_path.prepend("/") if parts.empty? || parts.first.empty? + clean_path + end + + NULL_BYTE = "\0" + + def valid_path?(path) + path.valid_encoding? && !path.include?(NULL_BYTE) + end + + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/version.rb new file mode 100644 index 0000000000..aad9c5915a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rack-2.2.3/lib/rack/version.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# Copyright (C) 2007-2019 Leah Neukirchen +# +# Rack is freely distributable under the terms of an MIT-style license. +# See MIT-LICENSE or https://opensource.org/licenses/MIT. + +# The Rack main module, serving as a namespace for all core Rack +# modules and classes. +# +# All modules meant for use in your application are autoloaded here, +# so it should be enough just to require 'rack' in your code. + +module Rack + # The Rack protocol version number implemented. + VERSION = [1, 3] + + # Return the Rack protocol version as a dotted string. + def self.version + VERSION.join(".") + end + + RELEASE = "2.2.3" + + # Return the Rack release as a dotted string. + def self.release + RELEASE + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/config/default.yml b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/config/default.yml new file mode 100644 index 0000000000..02abf38546 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/config/default.yml @@ -0,0 +1,726 @@ +# Common configuration. + +inherit_mode: + merge: + - Exclude + +AllCops: + Exclude: + - bin/* + - db/schema.rb + # What version of Rails is the inspected code using? If a value is specified + # for TargetRailsVersion then it is used. Acceptable values are specificed + # as a float (i.e. 5.1); the patch version of Rails should not be included. + # If TargetRailsVersion is not set, RuboCop will parse the Gemfile.lock or + # gems.locked file to find the version of Rails that has been bound to the + # application. If neither of those files exist, RuboCop will use Rails 5.0 + # as the default. + TargetRailsVersion: ~ + +Rails/ActionFilter: + Description: 'Enforces consistent use of action filter methods.' + Enabled: true + VersionAdded: '0.19' + EnforcedStyle: action + SupportedStyles: + - action + - filter + Include: + - app/controllers/**/*.rb + +Rails/ActiveRecordAliases: + Description: >- + Avoid Active Record aliases: + Use `update` instead of `update_attributes`. + Use `update!` instead of `update_attributes!`. + Enabled: true + VersionAdded: '0.53' + SafeAutoCorrect: false + +Rails/ActiveRecordCallbacksOrder: + Description: 'Order callback declarations in the order in which they will be executed.' + StyleGuide: 'https://rails.rubystyle.guide/#callbacks-order' + Enabled: 'pending' + VersionAdded: '2.7' + Include: + - app/models/**/*.rb + +Rails/ActiveRecordOverride: + Description: >- + Check for overriding Active Record methods instead of using + callbacks. + Enabled: true + VersionAdded: '0.67' + Include: + - app/models/**/*.rb + +Rails/ActiveSupportAliases: + Description: >- + Avoid ActiveSupport aliases of standard ruby methods: + `String#starts_with?`, `String#ends_with?`, + `Array#append`, `Array#prepend`. + Enabled: true + VersionAdded: '0.48' + +Rails/AfterCommitOverride: + Description: >- + This cop enforces that there is only one call to `after_commit` + (and its aliases - `after_create_commit`, `after_update_commit`, + and `after_destroy_commit`) with the same callback name per model. + Enabled: 'pending' + VersionAdded: '2.8' + +Rails/ApplicationController: + Description: 'Check that controllers subclass ApplicationController.' + Enabled: true + SafeAutoCorrect: false + VersionAdded: '2.4' + VersionChanged: '2.5' + +Rails/ApplicationJob: + Description: 'Check that jobs subclass ApplicationJob.' + Enabled: true + SafeAutoCorrect: false + VersionAdded: '0.49' + VersionChanged: '2.5' + +Rails/ApplicationMailer: + Description: 'Check that mailers subclass ApplicationMailer.' + Enabled: true + SafeAutoCorrect: false + VersionAdded: '2.4' + VersionChanged: '2.5' + +Rails/ApplicationRecord: + Description: 'Check that models subclass ApplicationRecord.' + Enabled: true + SafeAutoCorrect: false + VersionAdded: '0.49' + VersionChanged: '2.5' + +Rails/AssertNot: + Description: 'Use `assert_not` instead of `assert !`.' + Enabled: true + VersionAdded: '0.56' + Include: + - '**/test/**/*' + +Rails/BelongsTo: + Description: >- + Use `optional: true` instead of `required: false` for + `belongs_to` relations. + Enabled: true + VersionAdded: '0.62' + +Rails/Blank: + Description: 'Enforces use of `blank?`.' + Enabled: true + VersionAdded: '0.48' + VersionChanged: '0.67' + # Convert usages of `nil? || empty?` to `blank?` + NilOrEmpty: true + # Convert usages of `!present?` to `blank?` + NotPresent: true + # Convert usages of `unless present?` to `if blank?` + UnlessPresent: true + +Rails/BulkChangeTable: + Description: 'Check whether alter queries are combinable.' + Enabled: true + VersionAdded: '0.57' + Database: null + SupportedDatabases: + - mysql + - postgresql + Include: + - db/migrate/*.rb + +Rails/ContentTag: + Description: 'Use `tag` instead of `content_tag`.' + Reference: + - 'https://github.com/rails/rails/issues/25195' + - 'https://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-content_tag' + Enabled: true + VersionAdded: '2.6' + +Rails/CreateTableWithTimestamps: + Description: >- + Checks the migration for which timestamps are not included + when creating a new table. + Enabled: true + VersionAdded: '0.52' + Include: + - db/migrate/*.rb + +Rails/Date: + Description: >- + Checks the correct usage of date aware methods, + such as Date.today, Date.current etc. + Enabled: true + VersionAdded: '0.30' + VersionChanged: '0.33' + # The value `strict` disallows usage of `Date.today`, `Date.current`, + # `Date#to_time` etc. + # The value `flexible` allows usage of `Date.current`, `Date.yesterday`, etc + # (but not `Date.today`) which are overridden by ActiveSupport to handle current + # time zone. + EnforcedStyle: flexible + SupportedStyles: + - strict + - flexible + +Rails/DefaultScope: + Description: 'Avoid use of `default_scope`.' + StyleGuide: 'https://rails.rubystyle.guide#avoid-default-scope' + Enabled: false + VersionAdded: '2.7' + +Rails/Delegate: + Description: 'Prefer delegate method for delegations.' + Enabled: true + VersionAdded: '0.21' + VersionChanged: '0.50' + # When set to true, using the target object as a prefix of the + # method name without using the `delegate` method will be a + # violation. When set to false, this case is legal. + EnforceForPrefixed: true + +Rails/DelegateAllowBlank: + Description: 'Do not use allow_blank as an option to delegate.' + Enabled: true + VersionAdded: '0.44' + +Rails/DynamicFindBy: + Description: 'Use `find_by` instead of dynamic `find_by_*`.' + StyleGuide: 'https://rails.rubystyle.guide#find_by' + Enabled: true + VersionAdded: '0.44' + VersionChanged: '2.6' + # The `Whitelist` has been deprecated, Please use `AllowedMethods` instead. + Whitelist: + - find_by_sql + AllowedMethods: + - find_by_sql + AllowedReceivers: + - Gem::Specification + +Rails/EnumHash: + Description: 'Prefer hash syntax over array syntax when defining enums.' + StyleGuide: 'https://rails.rubystyle.guide#enums' + Enabled: true + VersionAdded: '2.3' + Include: + - app/models/**/*.rb + +Rails/EnumUniqueness: + Description: 'Avoid duplicate integers in hash-syntax `enum` declaration.' + Enabled: true + VersionAdded: '0.46' + Include: + - app/models/**/*.rb + +Rails/EnvironmentComparison: + Description: "Favor `Rails.env.production?` over `Rails.env == 'production'`." + Enabled: true + VersionAdded: '0.52' + +Rails/Exit: + Description: >- + Favor `fail`, `break`, `return`, etc. over `exit` in + application or library code outside of Rake files to avoid + exits during unit testing or running in production. + Enabled: true + VersionAdded: '0.41' + Include: + - app/**/*.rb + - config/**/*.rb + - lib/**/*.rb + Exclude: + - lib/**/*.rake + +Rails/FilePath: + Description: 'Use `Rails.root.join` for file path joining.' + Enabled: true + VersionAdded: '0.47' + VersionChanged: '2.4' + EnforcedStyle: slashes + SupportedStyles: + - slashes + - arguments + +Rails/FindBy: + Description: 'Prefer find_by over where.first.' + StyleGuide: 'https://rails.rubystyle.guide#find_by' + Enabled: true + VersionAdded: '0.30' + Include: + - app/models/**/*.rb + +Rails/FindById: + Description: >- + Favor the use of `find` over `where.take!`, `find_by!`, and `find_by_id!` when you + need to retrieve a single record by primary key when you expect it to be found. + StyleGuide: 'https://rails.rubystyle.guide/#find' + Enabled: 'pending' + VersionAdded: '2.7' + +Rails/FindEach: + Description: 'Prefer all.find_each over all.find.' + StyleGuide: 'https://rails.rubystyle.guide#find-each' + Enabled: true + VersionAdded: '0.30' + Include: + - app/models/**/*.rb + +Rails/HasAndBelongsToMany: + Description: 'Prefer has_many :through to has_and_belongs_to_many.' + StyleGuide: 'https://rails.rubystyle.guide#has-many-through' + Enabled: true + VersionAdded: '0.12' + Include: + - app/models/**/*.rb + +Rails/HasManyOrHasOneDependent: + Description: 'Define the dependent option to the has_many and has_one associations.' + StyleGuide: 'https://rails.rubystyle.guide#has_many-has_one-dependent-option' + Enabled: true + VersionAdded: '0.50' + Include: + - app/models/**/*.rb + +Rails/HelperInstanceVariable: + Description: 'Do not use instance variables in helpers.' + Enabled: true + VersionAdded: '2.0' + Include: + - app/helpers/**/*.rb + +Rails/HttpPositionalArguments: + Description: 'Use keyword arguments instead of positional arguments in http method calls.' + Enabled: true + VersionAdded: '0.44' + Include: + - 'spec/**/*' + - 'test/**/*' + +Rails/HttpStatus: + Description: 'Enforces use of symbolic or numeric value to define HTTP status.' + Enabled: true + VersionAdded: '0.54' + EnforcedStyle: symbolic + SupportedStyles: + - numeric + - symbolic + +Rails/IgnoredSkipActionFilterOption: + Description: 'Checks that `if` and `only` (or `except`) are not used together as options of `skip_*` action filter.' + Reference: 'https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-_normalize_callback_options' + Enabled: true + VersionAdded: '0.63' + Include: + - app/controllers/**/*.rb + +Rails/IndexBy: + Description: 'Prefer `index_by` over `each_with_object`, `to_h`, or `map`.' + Enabled: true + VersionAdded: '2.5' + VersionChanged: '2.8' + +Rails/IndexWith: + Description: 'Prefer `index_with` over `each_with_object`, `to_h`, or `map`.' + Enabled: true + VersionAdded: '2.5' + VersionChanged: '2.8' + +Rails/Inquiry: + Description: "Prefer Ruby's comparison operators over Active Support's `Array#inquiry` and `String#inquiry`." + StyleGuide: 'https://rails.rubystyle.guide/#inquiry' + Enabled: 'pending' + VersionAdded: '2.7' + +Rails/InverseOf: + Description: 'Checks for associations where the inverse cannot be determined automatically.' + Enabled: true + VersionAdded: '0.52' + Include: + - app/models/**/*.rb + +Rails/LexicallyScopedActionFilter: + Description: "Checks that methods specified in the filter's `only` or `except` options are explicitly defined in the controller." + StyleGuide: 'https://rails.rubystyle.guide#lexically-scoped-action-filter' + Enabled: true + Safe: false + VersionAdded: '0.52' + Include: + - app/controllers/**/*.rb + +Rails/LinkToBlank: + Description: 'Checks that `link_to` with a `target: "_blank"` have a `rel: "noopener"` option passed to them.' + Reference: + - https://mathiasbynens.github.io/rel-noopener/ + - https://html.spec.whatwg.org/multipage/links.html#link-type-noopener + - https://html.spec.whatwg.org/multipage/links.html#link-type-noreferrer + Enabled: true + VersionAdded: '0.62' + +Rails/MailerName: + Description: 'Mailer should end with `Mailer` suffix.' + StyleGuide: 'https://rails.rubystyle.guide/#mailer-name' + Enabled: 'pending' + SafeAutoCorrect: false + VersionAdded: '2.7' + Include: + - app/mailers/**/*.rb + +Rails/MatchRoute: + Description: >- + Don't use `match` to define any routes unless there is a need to map multiple request types + among [:get, :post, :patch, :put, :delete] to a single action using the `:via` option. + StyleGuide: 'https://rails.rubystyle.guide/#no-match-routes' + Enabled: 'pending' + VersionAdded: '2.7' + Include: + - config/routes.rb + - config/routes/**/*.rb + +Rails/NegateInclude: + Description: 'Prefer `collection.exclude?(obj)` over `!collection.include?(obj)`.' + StyleGuide: 'https://rails.rubystyle.guide#exclude' + Enabled: 'pending' + VersionAdded: '2.7' + +Rails/NotNullColumn: + Description: 'Do not add a NOT NULL column without a default value.' + Enabled: true + VersionAdded: '0.43' + Include: + - db/migrate/*.rb + +Rails/OrderById: + Description: >- + Do not use the `id` column for ordering. + Use a timestamp column to order chronologically. + StyleGuide: 'https://rails.rubystyle.guide/#order-by-id' + Enabled: false + VersionAdded: '2.8' + +Rails/Output: + Description: 'Checks for calls to puts, print, etc.' + Enabled: true + VersionAdded: '0.15' + VersionChanged: '0.19' + Include: + - app/**/*.rb + - config/**/*.rb + - db/**/*.rb + - lib/**/*.rb + +Rails/OutputSafety: + Description: 'The use of `html_safe` or `raw` may be a security risk.' + Enabled: true + VersionAdded: '0.41' + +Rails/Pick: + Description: 'Prefer `pick` over `pluck(...).first`.' + StyleGuide: 'https://rails.rubystyle.guide#pick' + Enabled: true + Safe: false + VersionAdded: '2.6' + +Rails/Pluck: + Description: 'Prefer `pluck` over `map { ... }`.' + StyleGuide: 'https://rails.rubystyle.guide#pluck' + Enabled: 'pending' + VersionAdded: '2.7' + +Rails/PluckId: + Description: 'Use `ids` instead of `pluck(:id)` or `pluck(primary_key)`.' + StyleGuide: 'https://rails.rubystyle.guide/#ids' + Enabled: false + Safe: false + VersionAdded: '2.7' + +Rails/PluckInWhere: + Description: 'Use `select` instead of `pluck` in `where` query methods.' + Enabled: 'pending' + Safe: false + VersionAdded: '2.7' + VersionChanged: '2.8' + EnforcedStyle: conservative + SupportedStyles: + - conservative + - aggressive + +Rails/PluralizationGrammar: + Description: 'Checks for incorrect grammar when using methods like `3.day.ago`.' + Enabled: true + VersionAdded: '0.35' + +Rails/Presence: + Description: 'Checks code that can be written more easily using `Object#presence` defined by Active Support.' + Enabled: true + VersionAdded: '0.52' + +Rails/Present: + Description: 'Enforces use of `present?`.' + Enabled: true + VersionAdded: '0.48' + VersionChanged: '0.67' + # Convert usages of `!nil? && !empty?` to `present?` + NotNilAndNotEmpty: true + # Convert usages of `!blank?` to `present?` + NotBlank: true + # Convert usages of `unless blank?` to `if present?` + UnlessBlank: true + +Rails/RakeEnvironment: + Description: 'Include `:environment` as a dependency for all Rake tasks.' + Enabled: true + Safe: false + VersionAdded: '2.4' + VersionChanged: '2.6' + Include: + - '**/Rakefile' + - '**/*.rake' + Exclude: + - 'lib/capistrano/tasks/**/*.rake' + +Rails/ReadWriteAttribute: + Description: >- + Checks for read_attribute(:attr) and + write_attribute(:attr, val). + StyleGuide: 'https://rails.rubystyle.guide#read-attribute' + Enabled: true + VersionAdded: '0.20' + VersionChanged: '0.29' + Include: + - app/models/**/*.rb + +Rails/RedundantAllowNil: + Description: >- + Finds redundant use of `allow_nil` when `allow_blank` is set to + certain values in model validations. + Enabled: true + VersionAdded: '0.67' + Include: + - app/models/**/*.rb + +Rails/RedundantForeignKey: + Description: 'Checks for associations where the `:foreign_key` option is redundant.' + Enabled: true + VersionAdded: '2.6' + +Rails/RedundantReceiverInWithOptions: + Description: 'Checks for redundant receiver in `with_options`.' + Enabled: true + VersionAdded: '0.52' + +Rails/ReflectionClassName: + Description: 'Use a string for `class_name` option value in the definition of a reflection.' + Enabled: true + VersionAdded: '0.64' + +Rails/RefuteMethods: + Description: 'Use `assert_not` methods instead of `refute` methods.' + Enabled: true + VersionAdded: '0.56' + EnforcedStyle: assert_not + SupportedStyles: + - assert_not + - refute + Include: + - '**/test/**/*' + +Rails/RelativeDateConstant: + Description: 'Do not assign relative date to constants.' + Enabled: true + VersionAdded: '0.48' + VersionChanged: '0.59' + AutoCorrect: false + +Rails/RenderInline: + Description: 'Prefer using a template over inline rendering.' + StyleGuide: 'https://rails.rubystyle.guide/#inline-rendering' + Enabled: 'pending' + VersionAdded: '2.7' + +Rails/RenderPlainText: + Description: 'Prefer `render plain:` over `render text:`.' + StyleGuide: 'https://rails.rubystyle.guide/#plain-text-rendering' + Enabled: 'pending' + VersionAdded: '2.7' + # Convert only when `content_type` is explicitly set to `text/plain`. + ContentTypeCompatibility: true + +Rails/RequestReferer: + Description: 'Use consistent syntax for request.referer.' + Enabled: true + VersionAdded: '0.41' + EnforcedStyle: referer + SupportedStyles: + - referer + - referrer + +Rails/ReversibleMigration: + Description: 'Checks whether the change method of the migration file is reversible.' + StyleGuide: 'https://rails.rubystyle.guide#reversible-migration' + Reference: 'https://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html' + Enabled: true + VersionAdded: '0.47' + Include: + - db/migrate/*.rb + +Rails/SafeNavigation: + Description: "Use Ruby's safe navigation operator (`&.`) instead of `try!`." + Enabled: true + VersionAdded: '0.43' + # This will convert usages of `try` to use safe navigation as well as `try!`. + # `try` and `try!` work slightly differently. `try!` and safe navigation will + # both raise a `NoMethodError` if the receiver of the method call does not + # implement the intended method. `try` will not raise an exception for this. + ConvertTry: false + +Rails/SafeNavigationWithBlank: + Description: 'Avoid `foo&.blank?` in conditionals.' + Enabled: true + VersionAdded: '2.4' + # While the safe navigation operator is generally a good idea, when + # checking `foo&.blank?` in a conditional, `foo` being `nil` will actually + # do the opposite of what the author intends. + # + # foo&.blank? #=> nil + # foo.blank? #=> true + SafeAutoCorrect: false + +Rails/SaveBang: + Description: 'Identifies possible cases where Active Record save! or related should be used.' + StyleGuide: 'https://rails.rubystyle.guide#save-bang' + Enabled: false + VersionAdded: '0.42' + VersionChanged: '0.59' + AllowImplicitReturn: true + AllowedReceivers: [] + SafeAutoCorrect: false + +Rails/ScopeArgs: + Description: 'Checks the arguments of ActiveRecord scopes.' + Enabled: true + VersionAdded: '0.19' + Include: + - app/models/**/*.rb + +Rails/ShortI18n: + Description: 'Use the short form of the I18n methods: `t` instead of `translate` and `l` instead of `localize`.' + StyleGuide: 'https://rails.rubystyle.guide/#short-i18n' + Enabled: 'pending' + VersionAdded: '2.7' + EnforcedStyle: conservative + SupportedStyles: + - conservative + - aggressive + +Rails/SkipsModelValidations: + Description: >- + Use methods that skips model validations with caution. + See reference for more information. + Reference: 'https://guides.rubyonrails.org/active_record_validations.html#skipping-validations' + Enabled: true + VersionAdded: '0.47' + VersionChanged: '2.7' + ForbiddenMethods: + - decrement! + - decrement_counter + - increment! + - increment_counter + - insert + - insert! + - insert_all + - insert_all! + - toggle! + - touch + - touch_all + - update_all + - update_attribute + - update_column + - update_columns + - update_counters + - upsert + - upsert_all + AllowedMethods: [] + +Rails/SquishedSQLHeredocs: + Description: 'Checks SQL heredocs to use `.squish`.' + StyleGuide: 'https://rails.rubystyle.guide/#squished-heredocs' + Enabled: 'pending' + VersionAdded: '2.8' + +Rails/TimeZone: + Description: 'Checks the correct usage of time zone aware methods.' + StyleGuide: 'https://rails.rubystyle.guide#time' + Reference: 'http://danilenko.org/2012/7/6/rails_timezones' + Enabled: true + Safe: false + VersionAdded: '0.30' + VersionChanged: '0.68' + # The value `strict` means that `Time` should be used with `zone`. + # The value `flexible` allows usage of `in_time_zone` instead of `zone`. + EnforcedStyle: flexible + SupportedStyles: + - strict + - flexible + +Rails/UniqBeforePluck: + Description: 'Prefer the use of uniq or distinct before pluck.' + Enabled: true + VersionAdded: '0.40' + VersionChanged: '2.8' + EnforcedStyle: conservative + SupportedStyles: + - conservative + - aggressive + SafeAutoCorrect: false + AutoCorrect: false + +Rails/UniqueValidationWithoutIndex: + Description: 'Uniqueness validation should be with a unique index.' + Enabled: true + VersionAdded: '2.5' + Include: + - app/models/**/*.rb + +Rails/UnknownEnv: + Description: 'Use correct environment name.' + Enabled: true + VersionAdded: '0.51' + Environments: + - development + - test + - production + +Rails/Validation: + Description: 'Use validates :attribute, hash of validations.' + Enabled: true + VersionAdded: '0.9' + VersionChanged: '0.41' + Include: + - app/models/**/*.rb + +Rails/WhereExists: + Description: 'Prefer `exists?(...)` over `where(...).exists?`.' + Enabled: 'pending' + EnforcedStyle: exists + SupportedStyles: + - exists + - where + VersionAdded: '2.7' + VersionChanged: '2.8' + +Rails/WhereNot: + Description: 'Use `where.not(...)` instead of manually constructing negated SQL in `where`.' + StyleGuide: 'https://rails.rubystyle.guide/#where-not' + Enabled: 'pending' + VersionAdded: '2.8' + +# Accept `redirect_to(...) and return` and similar cases. +Style/AndOr: + EnforcedStyle: conditionals diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop-rails.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop-rails.rb new file mode 100644 index 0000000000..fb215b534c --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop-rails.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'rubocop' +require 'rack/utils' +require 'active_support/inflector' + +require_relative 'rubocop/rails' +require_relative 'rubocop/rails/version' +require_relative 'rubocop/rails/inject' +require_relative 'rubocop/rails/schema_loader' +require_relative 'rubocop/rails/schema_loader/schema' + +RuboCop::Rails::Inject.defaults! + +require_relative 'rubocop/cop/rails_cops' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/mixin/active_record_helper.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/mixin/active_record_helper.rb new file mode 100644 index 0000000000..2611c068d3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/mixin/active_record_helper.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + # A mixin to extend cops for Active Record features + module ActiveRecordHelper + extend NodePattern::Macros + + WHERE_METHODS = %i[where rewhere].freeze + + def_node_search :find_set_table_name, <<~PATTERN + (send self :table_name= {str sym}) + PATTERN + + def_node_search :find_belongs_to, <<~PATTERN + (send nil? :belongs_to {str sym} ...) + PATTERN + + def external_dependency_checksum + return @external_dependency_checksum if defined?(@external_dependency_checksum) + + schema_path = RuboCop::Rails::SchemaLoader.db_schema_path + return nil if schema_path.nil? + + schema_code = File.read(schema_path) + + @external_dependency_checksum ||= Digest::SHA1.hexdigest(schema_code) + end + + def schema + RuboCop::Rails::SchemaLoader.load(target_ruby_version) + end + + def table_name(class_node) + table_name = find_set_table_name(class_node).to_a.last&.first_argument + return table_name.value.to_s if table_name + + namespaces = class_node.each_ancestor(:class, :module) + [class_node, *namespaces] + .reverse + .map { |klass| klass.identifier.children[1] }.join('_') + .tableize + end + + # Resolve relation into column name. + # It just returns column_name if the column exists. + # Or it tries to resolve column_name as a relation. + # It returns `nil` if it can't resolve. + # + # @param name [String] + # @param class_node [RuboCop::AST::Node] + # @param table [RuboCop::Rails::SchemaLoader::Table] + # @return [String, nil] + def resolve_relation_into_column(name:, class_node:, table:) + return unless table + return name if table.with_column?(name: name) + + find_belongs_to(class_node) do |belongs_to| + next unless belongs_to.first_argument.value.to_s == name + + fk = foreign_key_of(belongs_to) || "#{name}_id" + return fk if table.with_column?(name: fk) + end + nil + end + + def foreign_key_of(belongs_to) + options = belongs_to.last_argument + return unless options.hash_type? + + options.each_pair.find do |pair| + next unless pair.key.sym_type? && pair.key.value == :foreign_key + next unless pair.value.sym_type? || pair.value.str_type? + + break pair.value.value.to_s + end + end + + def in_where?(node) + send_node = node.each_ancestor(:send).first + send_node && WHERE_METHODS.include?(send_node.method_name) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/mixin/index_method.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/mixin/index_method.rb new file mode 100644 index 0000000000..71f25b9e91 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/mixin/index_method.rb @@ -0,0 +1,178 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + # Common functionality for Rails/IndexBy and Rails/IndexWith + module IndexMethod # rubocop:disable Metrics/ModuleLength + def on_block(node) + on_bad_each_with_object(node) do |*match| + handle_possible_offense(node, match, 'each_with_object') + end + + return if target_ruby_version < 2.6 + + on_bad_to_h(node) do |*match| + handle_possible_offense(node, match, 'to_h { ... }') + end + end + + def on_send(node) + on_bad_map_to_h(node) do |*match| + handle_possible_offense(node, match, 'map { ... }.to_h') + end + + on_bad_hash_brackets_map(node) do |*match| + handle_possible_offense(node, match, 'Hash[map { ... }]') + end + end + + def on_csend(node) + on_bad_map_to_h(node) do |*match| + handle_possible_offense(node, match, 'map { ... }.to_h') + end + end + + def autocorrect(node) + lambda do |corrector| + correction = prepare_correction(node) + execute_correction(corrector, node, correction) + end + end + + private + + # @abstract Implemented with `def_node_matcher` + def on_bad_each_with_object(_node) + raise NotImplementedError + end + + # @abstract Implemented with `def_node_matcher` + def on_bad_to_h(_node) + raise NotImplementedError + end + + # @abstract Implemented with `def_node_matcher` + def on_bad_map_to_h(_node) + raise NotImplementedError + end + + # @abstract Implemented with `def_node_matcher` + def on_bad_hash_brackets_map(_node) + raise NotImplementedError + end + + def handle_possible_offense(node, match, match_desc) + captures = extract_captures(match) + + return if captures.noop_transformation? + + add_offense( + node, + message: "Prefer `#{new_method_name}` over `#{match_desc}`." + ) + end + + def extract_captures(match) + argname, body_expr = *match + Captures.new(argname, body_expr) + end + + def new_method_name + raise NotImplementedError + end + + def prepare_correction(node) + if (match = on_bad_each_with_object(node)) + Autocorrection.from_each_with_object(node, match) + elsif (match = on_bad_to_h(node)) + Autocorrection.from_to_h(node, match) + elsif (match = on_bad_map_to_h(node)) + Autocorrection.from_map_to_h(node, match) + elsif (match = on_bad_hash_brackets_map(node)) + Autocorrection.from_hash_brackets_map(node, match) + else + raise 'unreachable' + end + end + + def execute_correction(corrector, node, correction) + correction.strip_prefix_and_suffix(node, corrector) + correction.set_new_method_name(new_method_name, corrector) + + captures = extract_captures(correction.match) + correction.set_new_arg_name(captures.transformed_argname, corrector) + correction.set_new_body_expression( + captures.transforming_body_expr, + corrector + ) + end + + # Internal helper class to hold match data + Captures = Struct.new( + :transformed_argname, + :transforming_body_expr + ) do + def noop_transformation? + transforming_body_expr.lvar_type? && + transforming_body_expr.children == [transformed_argname] + end + end + + # Internal helper class to hold autocorrect data + Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do # rubocop:disable Metrics/BlockLength + def self.from_each_with_object(node, match) + new(match, node, 0, 0) + end + + def self.from_to_h(node, match) + new(match, node, 0, 0) + end + + def self.from_map_to_h(node, match) + strip_trailing_chars = 0 + + unless node.parent&.block_type? + map_range = node.children.first.source_range + node_range = node.source_range + strip_trailing_chars = node_range.end_pos - map_range.end_pos + end + + new(match, node.children.first, 0, strip_trailing_chars) + end + + def self.from_hash_brackets_map(node, match) + new(match, node.children.last, 'Hash['.length, ']'.length) + end + + def strip_prefix_and_suffix(node, corrector) + expression = node.loc.expression + corrector.remove_leading(expression, leading) + corrector.remove_trailing(expression, trailing) + end + + def set_new_method_name(new_method_name, corrector) + range = block_node.send_node.loc.selector + if (send_end = block_node.send_node.loc.end) + # If there are arguments (only true in the `each_with_object` case) + range = range.begin.join(send_end) + end + corrector.replace(range, new_method_name) + end + + def set_new_arg_name(transformed_argname, corrector) + corrector.replace( + block_node.arguments.loc.expression, + "|#{transformed_argname}|" + ) + end + + def set_new_body_expression(transforming_body_expr, corrector) + corrector.replace( + block_node.body.loc.expression, + transforming_body_expr.loc.expression.source + ) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/mixin/target_rails_version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/mixin/target_rails_version.rb new file mode 100644 index 0000000000..6f9021407f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/mixin/target_rails_version.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + # Common functionality for checking target rails version. + module TargetRailsVersion + def minimum_target_rails_version(version) + @minimum_target_rails_version = version + end + + def support_target_rails_version?(version) + @minimum_target_rails_version <= version + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/action_filter.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/action_filter.rb new file mode 100644 index 0000000000..dea8b1ae7e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/action_filter.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop enforces the consistent use of action filter methods. + # + # The cop is configurable and can enforce the use of the older + # something_filter methods or the newer something_action methods. + # + # @example EnforcedStyle: action (default) + # # bad + # after_filter :do_stuff + # append_around_filter :do_stuff + # skip_after_filter :do_stuff + # + # # good + # after_action :do_stuff + # append_around_action :do_stuff + # skip_after_action :do_stuff + # + # @example EnforcedStyle: filter + # # bad + # after_action :do_stuff + # append_around_action :do_stuff + # skip_after_action :do_stuff + # + # # good + # after_filter :do_stuff + # append_around_filter :do_stuff + # skip_after_filter :do_stuff + class ActionFilter < Cop + include ConfigurableEnforcedStyle + + MSG = 'Prefer `%s` over `%s`.' + + FILTER_METHODS = %i[ + after_filter + append_after_filter + append_around_filter + append_before_filter + around_filter + before_filter + prepend_after_filter + prepend_around_filter + prepend_before_filter + skip_after_filter + skip_around_filter + skip_before_filter + skip_filter + ].freeze + + ACTION_METHODS = %i[ + after_action + append_after_action + append_around_action + append_before_action + around_action + before_action + prepend_after_action + prepend_around_action + prepend_before_action + skip_after_action + skip_around_action + skip_before_action + skip_action_callback + ].freeze + + def on_block(node) + check_method_node(node.send_node) + end + + def on_send(node) + check_method_node(node) unless node.receiver + end + + def autocorrect(node) + lambda do |corrector| + corrector.replace(node.loc.selector, + preferred_method(node.loc.selector.source).to_s) + end + end + + private + + def check_method_node(node) + return unless bad_methods.include?(node.method_name) + + add_offense(node, location: :selector) + end + + def message(node) + format(MSG, prefer: preferred_method(node.method_name), + current: node.method_name) + end + + def bad_methods + style == :action ? FILTER_METHODS : ACTION_METHODS + end + + def good_methods + style == :action ? ACTION_METHODS : FILTER_METHODS + end + + def preferred_method(method) + good_methods[bad_methods.index(method.to_sym)] + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_record_aliases.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_record_aliases.rb new file mode 100644 index 0000000000..437dde77bd --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_record_aliases.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # Checks that ActiveRecord aliases are not used. The direct method names + # are more clear and easier to read. + # + # @example + # #bad + # Book.update_attributes!(author: 'Alice') + # + # #good + # Book.update!(author: 'Alice') + class ActiveRecordAliases < Cop + MSG = 'Use `%s` instead of `%s`.' + + ALIASES = { + update_attributes: :update, + update_attributes!: :update! + }.freeze + + def on_send(node) + ALIASES.each do |bad, good| + next unless node.method?(bad) + + add_offense(node, + message: format(MSG, prefer: good, current: bad), + location: :selector, + severity: :warning) + break + end + end + + alias on_csend on_send + + def autocorrect(node) + lambda do |corrector| + corrector.replace( + node.loc.selector, + ALIASES[node.method_name].to_s + ) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_record_callbacks_order.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_record_callbacks_order.rb new file mode 100644 index 0000000000..d04e64d050 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_record_callbacks_order.rb @@ -0,0 +1,143 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that Active Record callbacks are declared + # in the order in which they will be executed. + # + # @example + # # bad + # class Person < ApplicationRecord + # after_commit :after_commit_callback + # before_validation :before_validation_callback + # end + # + # # good + # class Person < ApplicationRecord + # before_validation :before_validation_callback + # after_commit :after_commit_callback + # end + # + class ActiveRecordCallbacksOrder < Cop + MSG = '`%s` is supposed to appear before `%s`.' + + CALLBACKS_IN_ORDER = %i[ + after_initialize + before_validation + after_validation + before_save + around_save + before_create + around_create + after_create + before_update + around_update + after_update + before_destroy + around_destroy + after_destroy + after_save + after_commit + after_rollback + after_find + after_touch + ].freeze + + CALLBACKS_ORDER_MAP = CALLBACKS_IN_ORDER.each_with_index.to_h.freeze + + def on_class(class_node) + previous_index = -1 + previous_callback = nil + + defined_callbacks(class_node).each do |node| + callback = node.method_name + index = CALLBACKS_ORDER_MAP[callback] + + if index < previous_index + message = format(MSG, current: callback, + previous: previous_callback) + add_offense(node, message: message) + end + previous_index = index + previous_callback = callback + end + end + + # Autocorrect by swapping between two nodes autocorrecting them + def autocorrect(node) + previous = left_siblings_of(node).reverse_each.find do |sibling| + callback?(sibling) + end + + current_range = source_range_with_comment(node) + previous_range = source_range_with_comment(previous) + + lambda do |corrector| + corrector.insert_before(previous_range, current_range.source) + corrector.remove(current_range) + end + end + + private + + def defined_callbacks(class_node) + class_def = class_node.body + + if class_def + class_def.each_child_node.select { |c| callback?(c) } + else + [] + end + end + + def callback?(node) + node.send_type? && CALLBACKS_ORDER_MAP.key?(node.method_name) + end + + def left_siblings_of(node) + siblings_of(node)[0, node.sibling_index] + end + + def siblings_of(node) + node.parent.children + end + + def source_range_with_comment(node) + begin_pos = begin_pos_with_comment(node) + end_pos = end_position_for(node) + + Parser::Source::Range.new(buffer, begin_pos, end_pos) + end + + def end_position_for(node) + end_line = buffer.line_for_position(node.loc.expression.end_pos) + buffer.line_range(end_line).end_pos + end + + def begin_pos_with_comment(node) + annotation_line = node.first_line - 1 + first_comment = nil + + processed_source.comments_before_line(annotation_line) + .reverse_each do |comment| + if comment.location.line == annotation_line + first_comment = comment + annotation_line -= 1 + end + end + + start_line_position(first_comment || node) + end + + def start_line_position(node) + buffer.line_range(node.loc.line).begin_pos - 1 + end + + def buffer + processed_source.buffer + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_record_override.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_record_override.rb new file mode 100644 index 0000000000..c7aeef2f22 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_record_override.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # Checks for overriding built-in Active Record methods instead of using + # callbacks. + # + # @example + # # bad + # class Book < ApplicationRecord + # def save + # self.title = title.upcase! + # super + # end + # end + # + # # good + # class Book < ApplicationRecord + # before_save :upcase_title + # + # def upcase_title + # self.title = title.upcase! + # end + # end + # + class ActiveRecordOverride < Cop + MSG = + 'Use %s callbacks instead of overriding the Active Record ' \ + 'method `%s`.' + BAD_METHODS = %i[create destroy save update].freeze + ACTIVE_RECORD_CLASSES = %w[ApplicationRecord ActiveModel::Base + ActiveRecord::Base].freeze + + def on_def(node) + return unless BAD_METHODS.include?(node.method_name) + + parent_class_name = find_parent_class_name(node) + return unless active_model?(parent_class_name) + + return unless node.descendants.any?(&:zsuper_type?) + + add_offense(node, message: message(node.method_name)) + end + + private + + def active_model?(parent_class_name) + ACTIVE_RECORD_CLASSES.include?(parent_class_name) + end + + def callback_names(method_name) + names = %w[before_ around_ after_].map do |prefix| + "`#{prefix}#{method_name}`" + end + + names[-1] = "or #{names.last}" + + names.join(', ') + end + + def message(method_name) + format(MSG, prefer: callback_names(method_name), bad: method_name) + end + + def find_parent_class_name(node) + return nil unless node + + if node.class_type? + parent_class_name = node.node_parts[1] + + return nil if parent_class_name.nil? + + return parent_class_name.source + end + + find_parent_class_name(node.parent) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_support_aliases.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_support_aliases.rb new file mode 100644 index 0000000000..940effd5ef --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/active_support_aliases.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that ActiveSupport aliases to core ruby methods + # are not used. + # + # @example + # # good + # 'some_string'.start_with?('prefix') + # 'some_string'.end_with?('suffix') + # [1, 2, 'a'] << 'b' + # [1, 2, 'a'].unshift('b') + # + # # bad + # 'some_string'.starts_with?('prefix') + # 'some_string'.ends_with?('suffix') + # [1, 2, 'a'].append('b') + # [1, 2, 'a'].prepend('b') + # + class ActiveSupportAliases < Cop + MSG = 'Use `%s` instead of `%s`.' + + ALIASES = { + starts_with?: { + original: :start_with?, matcher: '(send str :starts_with? _)' + }, + ends_with?: { + original: :end_with?, matcher: '(send str :ends_with? _)' + }, + append: { original: :<<, matcher: '(send array :append _)' }, + prepend: { original: :unshift, matcher: '(send array :prepend _)' } + }.freeze + + ALIASES.each do |aliased_method, options| + def_node_matcher aliased_method, options[:matcher] + end + + def on_send(node) + ALIASES.each_key do |aliased_method| + register_offense(node, aliased_method) if + public_send(aliased_method, node) + end + end + + def autocorrect(node) + return false if append(node) + + lambda do |corrector| + method_name = node.loc.selector.source + replacement = ALIASES[method_name.to_sym][:original] + corrector.replace(node.loc.selector, replacement.to_s) + end + end + + private + + def register_offense(node, method_name) + add_offense( + node, + message: format(MSG, prefer: ALIASES[method_name][:original], + current: method_name) + ) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/after_commit_override.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/after_commit_override.rb new file mode 100644 index 0000000000..f144f42f47 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/after_commit_override.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop enforces that there is only one call to `after_commit` + # (and its aliases - `after_create_commit`, `after_update_commit`, + # and `after_destroy_commit`) with the same callback name per model. + # + # @example + # # bad + # # This won't be triggered. + # after_create_commit :log_action + # + # # This will override the callback added by + # # after_create_commit. + # after_update_commit :log_action + # + # # bad + # # This won't be triggered. + # after_commit :log_action, on: :create + # # This won't be triggered. + # after_update_commit :log_action + # # This will override both previous callbacks. + # after_commit :log_action, on: :destroy + # + # # good + # after_save_commit :log_action + # + # # good + # after_create_commit :log_create_action + # after_update_commit :log_update_action + # + class AfterCommitOverride < Cop + MSG = 'There can only be one `after_*_commit :%s` hook defined for a model.' + + AFTER_COMMIT_CALLBACKS = %i[ + after_commit + after_create_commit + after_update_commit + after_save_commit + after_destroy_commit + ].freeze + + def on_class(class_node) + seen_callback_names = {} + + each_after_commit_callback(class_node) do |node| + callback_name = node.arguments[0].value + if seen_callback_names.key?(callback_name) + add_offense(node, message: format(MSG, name: callback_name)) + else + seen_callback_names[callback_name] = true + end + end + end + + private + + def each_after_commit_callback(class_node) + class_send_nodes(class_node).each do |node| + yield node if after_commit_callback?(node) && named_callback?(node) + end + end + + def class_send_nodes(class_node) + class_def = class_node.body + + return [] unless class_def + + if class_def.send_type? + [class_def] + else + class_def.each_child_node(:send).to_a + end + end + + def after_commit_callback?(node) + AFTER_COMMIT_CALLBACKS.include?(node.method_name) + end + + def named_callback?(node) + name = node.first_argument + return false unless name + + name.sym_type? + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_controller.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_controller.rb new file mode 100644 index 0000000000..2e0c6df956 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_controller.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that controllers subclass ApplicationController. + # + # @example + # + # # good + # class MyController < ApplicationController + # # ... + # end + # + # # bad + # class MyController < ActionController::Base + # # ... + # end + class ApplicationController < Cop + MSG = 'Controllers should subclass `ApplicationController`.' + SUPERCLASS = 'ApplicationController' + BASE_PATTERN = '(const (const nil? :ActionController) :Base)' + + # rubocop:disable Layout/ClassStructure + include RuboCop::Cop::EnforceSuperclass + # rubocop:enable Layout/ClassStructure + + def autocorrect(node) + lambda do |corrector| + corrector.replace(node.source_range, self.class::SUPERCLASS) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_job.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_job.rb new file mode 100644 index 0000000000..e9cf6fa2c7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_job.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that jobs subclass ApplicationJob with Rails 5.0. + # + # @example + # + # # good + # class Rails5Job < ApplicationJob + # # ... + # end + # + # # bad + # class Rails4Job < ActiveJob::Base + # # ... + # end + class ApplicationJob < Cop + extend TargetRailsVersion + + minimum_target_rails_version 5.0 + + MSG = 'Jobs should subclass `ApplicationJob`.' + SUPERCLASS = 'ApplicationJob' + BASE_PATTERN = '(const (const nil? :ActiveJob) :Base)' + + # rubocop:disable Layout/ClassStructure + include RuboCop::Cop::EnforceSuperclass + # rubocop:enable Layout/ClassStructure + + def autocorrect(node) + lambda do |corrector| + corrector.replace(node.source_range, self.class::SUPERCLASS) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_mailer.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_mailer.rb new file mode 100644 index 0000000000..bc451da738 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_mailer.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that mailers subclass ApplicationMailer with Rails 5.0. + # + # @example + # + # # good + # class MyMailer < ApplicationMailer + # # ... + # end + # + # # bad + # class MyMailer < ActionMailer::Base + # # ... + # end + class ApplicationMailer < Cop + extend TargetRailsVersion + + minimum_target_rails_version 5.0 + + MSG = 'Mailers should subclass `ApplicationMailer`.' + SUPERCLASS = 'ApplicationMailer' + BASE_PATTERN = '(const (const nil? :ActionMailer) :Base)' + + # rubocop:disable Layout/ClassStructure + include RuboCop::Cop::EnforceSuperclass + # rubocop:enable Layout/ClassStructure + + def autocorrect(node) + lambda do |corrector| + corrector.replace(node.source_range, self.class::SUPERCLASS) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_record.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_record.rb new file mode 100644 index 0000000000..7d75cdaf5f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/application_record.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that models subclass ApplicationRecord with Rails 5.0. + # + # @example + # + # # good + # class Rails5Model < ApplicationRecord + # # ... + # end + # + # # bad + # class Rails4Model < ActiveRecord::Base + # # ... + # end + class ApplicationRecord < Cop + extend TargetRailsVersion + + minimum_target_rails_version 5.0 + + MSG = 'Models should subclass `ApplicationRecord`.' + SUPERCLASS = 'ApplicationRecord' + BASE_PATTERN = '(const (const nil? :ActiveRecord) :Base)' + + # rubocop:disable Layout/ClassStructure + include RuboCop::Cop::EnforceSuperclass + # rubocop:enable Layout/ClassStructure + + def autocorrect(node) + lambda do |corrector| + corrector.replace(node.source_range, self.class::SUPERCLASS) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/assert_not.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/assert_not.rb new file mode 100644 index 0000000000..730eec7ea2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/assert_not.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # + # Use `assert_not` instead of `assert !`. + # + # @example + # # bad + # assert !x + # + # # good + # assert_not x + # + class AssertNot < RuboCop::Cop::Cop + MSG = 'Prefer `assert_not` over `assert !`.' + + def_node_matcher :offensive?, '(send nil? :assert (send ... :!) ...)' + + def on_send(node) + add_offense(node) if offensive?(node) + end + + def autocorrect(node) + expression = node.loc.expression + + lambda do |corrector| + corrector.replace( + expression, + corrected_source(expression.source) + ) + end + end + + private + + def corrected_source(source) + source.gsub(/^assert(\(| ) *! */, 'assert_not\\1') + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/belongs_to.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/belongs_to.rb new file mode 100644 index 0000000000..9b0c3cd254 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/belongs_to.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop looks for belongs_to associations where we control whether the + # association is required via the deprecated `required` option instead. + # + # Since Rails 5, belongs_to associations are required by default and this + # can be controlled through the use of `optional: true`. + # + # From the release notes: + # + # belongs_to will now trigger a validation error by default if the + # association is not present. You can turn this off on a + # per-association basis with optional: true. Also deprecate required + # option in favor of optional for belongs_to. (Pull Request) + # + # In the case that the developer is doing `required: false`, we + # definitely want to autocorrect to `optional: true`. + # + # However, without knowing whether they've set overridden the default + # value of `config.active_record.belongs_to_required_by_default`, we + # can't say whether it's safe to remove `required: true` or whether we + # should replace it with `optional: false` (or, similarly, remove a + # superfluous `optional: false`). Therefore, in the cases we're using + # `required: true`, we'll simply invert it to `optional: false` and the + # user can remove depending on their defaults. + # + # @example + # # bad + # class Post < ApplicationRecord + # belongs_to :blog, required: false + # end + # + # # good + # class Post < ApplicationRecord + # belongs_to :blog, optional: true + # end + # + # # bad + # class Post < ApplicationRecord + # belongs_to :blog, required: true + # end + # + # # good + # class Post < ApplicationRecord + # belongs_to :blog, optional: false + # end + # + # @see https://guides.rubyonrails.org/5_0_release_notes.html + # @see https://github.com/rails/rails/pull/18937 + class BelongsTo < Cop + extend TargetRailsVersion + + minimum_target_rails_version 5.0 + + SUPERFLOUS_REQUIRE_FALSE_MSG = + 'You specified `required: false`, in Rails > 5.0 the required ' \ + 'option is deprecated and you want to use `optional: true`.' + + SUPERFLOUS_REQUIRE_TRUE_MSG = + 'You specified `required: true`, in Rails > 5.0 the required ' \ + 'option is deprecated and you want to use `optional: false`. ' \ + 'In most configurations, this is the default and you can omit ' \ + 'this option altogether' + + def_node_matcher :match_belongs_to_with_options, <<~PATTERN + (send _ :belongs_to _ + (hash <$(pair (sym :required) ${true false}) ...>) + ) + PATTERN + + def on_send(node) + match_belongs_to_with_options(node) do |_option_node, option_value| + message = + if option_value.true_type? + SUPERFLOUS_REQUIRE_TRUE_MSG + elsif option_value.false_type? + SUPERFLOUS_REQUIRE_FALSE_MSG + end + + add_offense(node, message: message, location: :selector) + end + end + + def autocorrect(node) + option_node, option_value = match_belongs_to_with_options(node) + return unless option_node + + lambda do |corrector| + if option_value.true_type? + corrector.replace(option_node.loc.expression, 'optional: false') + elsif option_value.false_type? + corrector.replace(option_node.loc.expression, 'optional: true') + end + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/blank.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/blank.rb new file mode 100644 index 0000000000..821af08457 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/blank.rb @@ -0,0 +1,164 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for code that can be written with simpler conditionals + # using `Object#blank?` defined by Active Support. + # + # Interaction with `Style/UnlessElse`: + # The configuration of `NotPresent` will not produce an offense in the + # context of `unless else` if `Style/UnlessElse` is inabled. This is + # to prevent interference between the auto-correction of the two cops. + # + # @example NilOrEmpty: true (default) + # # Converts usages of `nil? || empty?` to `blank?` + # + # # bad + # foo.nil? || foo.empty? + # foo == nil || foo.empty? + # + # # good + # foo.blank? + # + # @example NotPresent: true (default) + # # Converts usages of `!present?` to `blank?` + # + # # bad + # !foo.present? + # + # # good + # foo.blank? + # + # @example UnlessPresent: true (default) + # # Converts usages of `unless present?` to `if blank?` + # + # # bad + # something unless foo.present? + # + # # good + # something if foo.blank? + # + # # bad + # unless foo.present? + # something + # end + # + # # good + # if foo.blank? + # something + # end + # + # # good + # def blank? + # !present? + # end + class Blank < Cop + MSG_NIL_OR_EMPTY = 'Use `%s` instead of `%s`.' + MSG_NOT_PRESENT = 'Use `%s` instead of `%s`.' + MSG_UNLESS_PRESENT = 'Use `if %s` instead of ' \ + '`%s`.' + + # `(send nil $_)` is not actually a valid match for an offense. Nodes + # that have a single method call on the left hand side + # (`bar || foo.empty?`) will blow up when checking + # `(send (:nil) :== $_)`. + def_node_matcher :nil_or_empty?, <<~PATTERN + (or + { + (send $_ :!) + (send $_ :nil?) + (send $_ :== nil) + (send nil :== $_) + } + { + (send $_ :empty?) + (send (send (send $_ :empty?) :!) :!) + } + ) + PATTERN + + def_node_matcher :not_present?, '(send (send $_ :present?) :!)' + + def_node_matcher :defining_blank?, '(def :blank? (args) ...)' + + def_node_matcher :unless_present?, <<~PATTERN + (:if $(send $_ :present?) {nil? (...)} ...) + PATTERN + + def on_send(node) + return unless cop_config['NotPresent'] + + not_present?(node) do |receiver| + # accepts !present? if its in the body of a `blank?` method + next if defining_blank?(node.parent) + + add_offense(node, + message: format(MSG_NOT_PRESENT, + prefer: replacement(receiver), + current: node.source)) + end + end + + def on_or(node) + return unless cop_config['NilOrEmpty'] + + nil_or_empty?(node) do |var1, var2| + return unless var1 == var2 + + add_offense(node, + message: format(MSG_NIL_OR_EMPTY, + prefer: replacement(var1), + current: node.source)) + end + end + + def on_if(node) + return unless cop_config['UnlessPresent'] + return unless node.unless? + return if node.else? && config.for_cop('Style/UnlessElse')['Enabled'] + + unless_present?(node) do |method_call, receiver| + range = unless_condition(node, method_call) + + add_offense(node, + location: range, + message: format(MSG_UNLESS_PRESENT, + prefer: replacement(receiver), + current: range.source)) + end + end + + def autocorrect(node) + lambda do |corrector| + method_call, variable1 = unless_present?(node) + + if method_call + corrector.replace(node.loc.keyword, 'if') + range = method_call.loc.expression + else + variable1, _variable2 = nil_or_empty?(node) || not_present?(node) + range = node.loc.expression + end + + corrector.replace(range, replacement(variable1)) + end + end + + private + + def unless_condition(node, method_call) + if node.modifier_form? + node.loc.keyword.join(node.loc.expression.end) + else + node.loc.expression.begin.join(method_call.loc.expression) + end + end + + def replacement(node) + node.respond_to?(:source) ? "#{node.source}.blank?" : 'blank?' + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/bulk_change_table.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/bulk_change_table.rb new file mode 100644 index 0000000000..18f17743a4 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/bulk_change_table.rb @@ -0,0 +1,293 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This Cop checks whether alter queries are combinable. + # If combinable queries are detected, it suggests to you + # to use `change_table` with `bulk: true` instead. + # This option causes the migration to generate a single + # ALTER TABLE statement combining multiple column alterations. + # + # The `bulk` option is only supported on the MySQL and + # the PostgreSQL (5.2 later) adapter; thus it will + # automatically detect an adapter from `development` environment + # in `config/database.yml` when the `Database` option is not set. + # If the adapter is not `mysql2` or `postgresql`, + # this Cop ignores offenses. + # + # @example + # # bad + # def change + # add_column :users, :name, :string, null: false + # add_column :users, :nickname, :string + # + # # ALTER TABLE `users` ADD `name` varchar(255) NOT NULL + # # ALTER TABLE `users` ADD `nickname` varchar(255) + # end + # + # # good + # def change + # change_table :users, bulk: true do |t| + # t.string :name, null: false + # t.string :nickname + # end + # + # # ALTER TABLE `users` ADD `name` varchar(255) NOT NULL, + # # ADD `nickname` varchar(255) + # end + # + # @example + # # bad + # def change + # change_table :users do |t| + # t.string :name, null: false + # t.string :nickname + # end + # end + # + # # good + # def change + # change_table :users, bulk: true do |t| + # t.string :name, null: false + # t.string :nickname + # end + # end + # + # # good + # # When you don't want to combine alter queries. + # def change + # change_table :users, bulk: false do |t| + # t.string :name, null: false + # t.string :nickname + # end + # end + # + # @see https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_table + # @see https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html + class BulkChangeTable < Cop + MSG_FOR_CHANGE_TABLE = <<~MSG.chomp + You can combine alter queries using `bulk: true` options. + MSG + MSG_FOR_ALTER_METHODS = <<~MSG.chomp + You can use `change_table :%s, bulk: true` to combine alter queries. + MSG + + MYSQL = 'mysql' + POSTGRESQL = 'postgresql' + + MIGRATION_METHODS = %i[change up down].freeze + + COMBINABLE_TRANSFORMATIONS = %i[ + primary_key + column + string + text + integer + bigint + float + decimal + numeric + datetime + timestamp + time + date + binary + boolean + json + virtual + remove + change + timestamps + remove_timestamps + ].freeze + + COMBINABLE_ALTER_METHODS = %i[ + add_column + remove_column + remove_columns + change_column + add_timestamps + remove_timestamps + ].freeze + + MYSQL_COMBINABLE_TRANSFORMATIONS = %i[ + rename + index + remove_index + ].freeze + + MYSQL_COMBINABLE_ALTER_METHODS = %i[ + rename_column + add_index + remove_index + ].freeze + + POSTGRESQL_COMBINABLE_TRANSFORMATIONS = %i[ + change_default + ].freeze + + POSTGRESQL_COMBINABLE_ALTER_METHODS = %i[ + change_column_default + ].freeze + + def on_def(node) + return unless support_bulk_alter? + return unless MIGRATION_METHODS.include?(node.method_name) + return unless node.body + + recorder = AlterMethodsRecorder.new + + node.body.child_nodes.each do |child_node| + if call_to_combinable_alter_method? child_node + recorder.process(child_node) + else + recorder.flush + end + end + + recorder.offensive_nodes.each { |n| add_offense_for_alter_methods(n) } + end + + def on_send(node) + return unless support_bulk_alter? + return unless node.command?(:change_table) + return if include_bulk_options?(node) + return unless node.block_node + + send_nodes = node.block_node.body.each_child_node(:send).to_a + + transformations = send_nodes.select do |send_node| + combinable_transformations.include?(send_node.method_name) + end + + add_offense_for_change_table(node) if transformations.size > 1 + end + + private + + # @param node [RuboCop::AST::SendNode] (send nil? :change_table ...) + def include_bulk_options?(node) + # arguments: [{(sym :table)(str "table")} (hash (pair (sym :bulk) _))] + options = node.arguments[1] + return false unless options + + options.hash_type? && + options.keys.any? { |key| key.sym_type? && key.value == :bulk } + end + + def database + cop_config['Database'] || database_from_yaml + end + + def database_from_yaml + return nil unless database_yaml + + case database_yaml['adapter'] + when 'mysql2' + MYSQL + when 'postgresql' + POSTGRESQL + end + end + + def database_yaml + return nil unless File.exist?('config/database.yml') + + yaml = YAML.load_file('config/database.yml') + return nil unless yaml.is_a? Hash + + config = yaml['development'] + return nil unless config.is_a?(Hash) + + config + rescue Psych::SyntaxError + nil + end + + def support_bulk_alter? + case database + when MYSQL + true + when POSTGRESQL + # Add bulk alter support for PostgreSQL in 5.2.0 + # @see https://github.com/rails/rails/pull/31331 + target_rails_version >= 5.2 + else + false + end + end + + def call_to_combinable_alter_method?(child_node) + child_node.send_type? && + combinable_alter_methods.include?(child_node.method_name) + end + + def combinable_alter_methods + case database + when MYSQL + COMBINABLE_ALTER_METHODS + MYSQL_COMBINABLE_ALTER_METHODS + when POSTGRESQL + COMBINABLE_ALTER_METHODS + POSTGRESQL_COMBINABLE_ALTER_METHODS + end + end + + def combinable_transformations + case database + when MYSQL + COMBINABLE_TRANSFORMATIONS + MYSQL_COMBINABLE_TRANSFORMATIONS + when POSTGRESQL + COMBINABLE_TRANSFORMATIONS + POSTGRESQL_COMBINABLE_TRANSFORMATIONS + end + end + + # @param node [RuboCop::AST::SendNode] + def add_offense_for_alter_methods(node) + # arguments: [{(sym :table)(str "table")} ...] + table_node = node.arguments[0] + return unless table_node.is_a? RuboCop::AST::BasicLiteralNode + + message = format(MSG_FOR_ALTER_METHODS, table: table_node.value) + add_offense(node, message: message) + end + + # @param node [RuboCop::AST::SendNode] + def add_offense_for_change_table(node) + add_offense(node, message: MSG_FOR_CHANGE_TABLE) + end + + # Record combinable alter methods and register offensive nodes. + class AlterMethodsRecorder + def initialize + @nodes = [] + @offensive_nodes = [] + end + + # @param new_node [RuboCop::AST::SendNode] + def process(new_node) + # arguments: [{(sym :table)(str "table")} ...] + table_node = new_node.arguments[0] + if table_node.is_a? RuboCop::AST::BasicLiteralNode + flush unless @nodes.all? do |node| + node.arguments[0].value.to_s == table_node.value.to_s + end + @nodes << new_node + else + flush + end + end + + def flush + @offensive_nodes << @nodes.first if @nodes.size > 1 + @nodes = [] + end + + def offensive_nodes + flush + @offensive_nodes + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/content_tag.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/content_tag.rb new file mode 100644 index 0000000000..b251c143d5 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/content_tag.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that `tag` is used instead of `content_tag` + # because `content_tag` is legacy syntax. + # + # NOTE: Allow `content_tag` when the first argument is a variable because + # `content_tag(name)` is simpler rather than `tag.public_send(name)`. + # + # @example + # # bad + # content_tag(:p, 'Hello world!') + # content_tag(:br) + # + # # good + # tag.p('Hello world!') + # tag.br + # content_tag(name, 'Hello world!') + class ContentTag < Cop + include RangeHelp + extend TargetRailsVersion + + minimum_target_rails_version 5.1 + + MSG = 'Use `tag` instead of `content_tag`.' + + def on_send(node) + return unless node.method?(:content_tag) + + first_argument = node.first_argument + return unless first_argument + + return if first_argument.variable? || first_argument.send_type? || first_argument.const_type? + + add_offense(node) + end + + def autocorrect(node) + lambda do |corrector| + if method_name?(node.first_argument) + range = correction_range(node) + + rest_args = node.arguments.drop(1) + replacement = "tag.#{node.first_argument.value.to_s.underscore}(#{rest_args.map(&:source).join(', ')})" + + corrector.replace(range, replacement) + else + corrector.replace(node.loc.selector, 'tag') + end + end + end + + private + + def method_name?(node) + return false unless node.str_type? || node.sym_type? + + /^[a-zA-Z_][a-zA-Z_\-0-9]*$/.match?(node.value) + end + + def correction_range(node) + range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/create_table_with_timestamps.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/create_table_with_timestamps.rb new file mode 100644 index 0000000000..73ee5a5759 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/create_table_with_timestamps.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks the migration for which timestamps are not included + # when creating a new table. + # In many cases, timestamps are useful information and should be added. + # + # @example + # # bad + # create_table :users + # + # # bad + # create_table :users do |t| + # t.string :name + # t.string :email + # end + # + # # good + # create_table :users do |t| + # t.string :name + # t.string :email + # + # t.timestamps + # end + # + # # good + # create_table :users do |t| + # t.string :name + # t.string :email + # + # t.datetime :created_at, default: -> { 'CURRENT_TIMESTAMP' } + # end + # + # # good + # create_table :users do |t| + # t.string :name + # t.string :email + # + # t.datetime :updated_at, default: -> { 'CURRENT_TIMESTAMP' } + # end + class CreateTableWithTimestamps < Cop + MSG = 'Add timestamps when creating a new table.' + + def_node_matcher :create_table_with_block?, <<~PATTERN + (block + (send nil? :create_table ...) + (args (arg _var)) + _) + PATTERN + + def_node_matcher :create_table_with_timestamps_proc?, <<~PATTERN + (send nil? :create_table (sym _) ... (block-pass (sym :timestamps))) + PATTERN + + def_node_search :timestamps_included?, <<~PATTERN + (send _var :timestamps ...) + PATTERN + + def_node_search :created_at_or_updated_at_included?, <<~PATTERN + (send _var :datetime + {(sym {:created_at :updated_at})(str {"created_at" "updated_at"})} + ...) + PATTERN + + def on_send(node) + return unless node.command?(:create_table) + + parent = node.parent + + if create_table_with_block?(parent) + add_offense(parent) if parent.body.nil? || !time_columns_included?(parent.body) + elsif create_table_with_timestamps_proc?(node) + # nothing to do + else + add_offense(node) + end + end + + private + + def time_columns_included?(node) + timestamps_included?(node) || created_at_or_updated_at_included?(node) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/date.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/date.rb new file mode 100644 index 0000000000..8ea8fd94b4 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/date.rb @@ -0,0 +1,161 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for the correct use of Date methods, + # such as Date.today, Date.current etc. + # + # Using `Date.today` is dangerous, because it doesn't know anything about + # Rails time zone. You must use `Time.zone.today` instead. + # + # The cop also reports warnings when you are using `to_time` method, + # because it doesn't know about Rails time zone either. + # + # Two styles are supported for this cop. When EnforcedStyle is 'strict' + # then the Date methods `today`, `current`, `yesterday`, and `tomorrow` + # are prohibited and the usage of both `to_time` + # and 'to_time_in_current_zone' are reported as warning. + # + # When EnforcedStyle is 'flexible' then only `Date.today` is prohibited + # and only `to_time` is reported as warning. + # + # @example EnforcedStyle: strict + # # bad + # Date.current + # Date.yesterday + # Date.today + # date.to_time + # + # # good + # Time.zone.today + # Time.zone.today - 1.day + # + # @example EnforcedStyle: flexible (default) + # # bad + # Date.today + # date.to_time + # + # # good + # Time.zone.today + # Time.zone.today - 1.day + # Date.current + # Date.yesterday + # date.in_time_zone + # + class Date < Cop + include ConfigurableEnforcedStyle + + MSG = 'Do not use `Date.%s` without zone. Use ' \ + '`Time.zone.%s` instead.' + + MSG_SEND = 'Do not use `%s` on Date objects, because they ' \ + 'know nothing about the time zone in use.' + + BAD_DAYS = %i[today current yesterday tomorrow].freeze + + DEPRECATED_METHODS = [ + { deprecated: 'to_time_in_current_zone', relevant: 'in_time_zone' } + ].freeze + + DEPRECATED_MSG = '`%s` is deprecated. ' \ + 'Use `%s` instead.' + + def on_const(node) + mod, klass = *node.children + # we should only check core Date class (`Date` or `::Date`) + return unless (mod.nil? || mod.cbase_type?) && method_send?(node) + + check_date_node(node.parent) if klass == :Date + end + + def on_send(node) + return unless node.receiver && bad_methods.include?(node.method_name) + + return if safe_chain?(node) || safe_to_time?(node) + + check_deprecated_methods(node) + + add_offense(node, location: :selector, + message: format(MSG_SEND, method: node.method_name)) + end + alias on_csend on_send + + private + + def check_deprecated_methods(node) + DEPRECATED_METHODS.each do |method| + next unless node.method?(method[:deprecated].to_sym) + + add_offense(node, location: :selector, + message: format(DEPRECATED_MSG, + deprecated: method[:deprecated], + relevant: method[:relevant])) + end + end + + def check_date_node(node) + chain = extract_method_chain(node) + + return if (chain & bad_days).empty? + + method_name = (chain & bad_days).join('.') + + day = method_name + day = 'today' if method_name == 'current' + + add_offense(node, location: :selector, + message: format(MSG, + method_called: method_name, + day: day)) + end + + def extract_method_chain(node) + [node, *node.each_ancestor(:send)].map(&:method_name) + end + + # checks that parent node of send_type + # and receiver is the given node + def method_send?(node) + return false unless node.parent&.send_type? + + node.parent.receiver == node + end + + def safe_chain?(node) + chain = extract_method_chain(node) + + (chain & bad_methods).empty? || !(chain & good_methods).empty? + end + + def safe_to_time?(node) + return unless node.method?(:to_time) + + if node.receiver.str_type? + zone_regexp = /([+-][\d:]+|\dZ)\z/ + + node.receiver.str_content.match(zone_regexp) + else + node.arguments.one? + end + end + + def good_days + style == :strict ? [] : %i[current yesterday tomorrow] + end + + def bad_days + BAD_DAYS - good_days + end + + def bad_methods + %i[to_time to_time_in_current_zone] + end + + def good_methods + style == :strict ? [] : TimeZone::ACCEPTED_METHODS + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/default_scope.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/default_scope.rb new file mode 100644 index 0000000000..6a61b9604f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/default_scope.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop looks for uses of `default_scope`. + # + # @example + # # bad + # default_scope -> { where(hidden: false) } + # + # # good + # scope :published, -> { where(hidden: false) } + # + # # bad + # def self.default_scope + # where(hidden: false) + # end + # + # # good + # def self.published + # where(hidden: false) + # end + # + class DefaultScope < Cop + MSG = 'Avoid use of `default_scope`. It is better to use explicitly named scopes.' + + def_node_matcher :method_call?, <<~PATTERN + (send nil? :default_scope ...) + PATTERN + + def_node_matcher :class_method_definition?, <<~PATTERN + (defs _ :default_scope args ...) + PATTERN + + def_node_matcher :eigenclass_method_definition?, <<~PATTERN + (sclass (self) $(def :default_scope args ...)) + PATTERN + + def on_send(node) + add_offense(node, location: :selector) if method_call?(node) + end + + def on_defs(node) + add_offense(node, location: :name) if class_method_definition?(node) + end + + def on_sclass(node) + eigenclass_method_definition?(node) { |default_scope| add_offense(default_scope, location: :name) } + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/delegate.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/delegate.rb new file mode 100644 index 0000000000..a274855bb1 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/delegate.rb @@ -0,0 +1,130 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop looks for delegations that could have been created + # automatically with the `delegate` method. + # + # Safe navigation `&.` is ignored because Rails' `allow_nil` + # option checks not just for nil but also delegates if nil + # responds to the delegated method. + # + # The `EnforceForPrefixed` option (defaulted to `true`) means that + # using the target object as a prefix of the method name + # without using the `delegate` method will be a violation. + # When set to `false`, this case is legal. + # + # @example + # # bad + # def bar + # foo.bar + # end + # + # # good + # delegate :bar, to: :foo + # + # # good + # def bar + # foo&.bar + # end + # + # # good + # private + # def bar + # foo.bar + # end + # + # @example EnforceForPrefixed: true (default) + # # bad + # def foo_bar + # foo.bar + # end + # + # # good + # delegate :bar, to: :foo, prefix: true + # + # @example EnforceForPrefixed: false + # # good + # def foo_bar + # foo.bar + # end + # + # # good + # delegate :bar, to: :foo, prefix: true + class Delegate < Cop + MSG = 'Use `delegate` to define delegations.' + + def_node_matcher :delegate?, <<~PATTERN + (def _method_name _args + (send (send nil? _) _ ...)) + PATTERN + + def on_def(node) + return unless trivial_delegate?(node) + return if private_or_protected_delegation(node) + + add_offense(node, location: :keyword) + end + + def autocorrect(node) + delegation = ["delegate :#{node.body.method_name}", + "to: :#{node.body.receiver.method_name}"] + + delegation << ['prefix: true'] if node.method?(prefixed_method_name(node.body)) + + lambda do |corrector| + corrector.replace(node.source_range, delegation.join(', ')) + end + end + + private + + def trivial_delegate?(def_node) + delegate?(def_node) && + method_name_matches?(def_node.method_name, def_node.body) && + arguments_match?(def_node.arguments, def_node.body) + end + + def arguments_match?(arg_array, body) + argument_array = body.arguments + + return false if arg_array.size != argument_array.size + + arg_array.zip(argument_array).all? do |arg, argument| + arg.arg_type? && + argument.lvar_type? && + arg.children == argument.children + end + end + + def method_name_matches?(method_name, body) + method_name == body.method_name || + include_prefix_case? && method_name == prefixed_method_name(body) + end + + def include_prefix_case? + cop_config['EnforceForPrefixed'] + end + + def prefixed_method_name(body) + [body.receiver.method_name, body.method_name].join('_').to_sym + end + + def private_or_protected_delegation(node) + line = node.first_line + private_or_protected_before(line) || + private_or_protected_inline(line) + end + + def private_or_protected_before(line) + (processed_source[0..line].map(&:strip) & %w[private protected]).any? + end + + def private_or_protected_inline(line) + processed_source[line - 1].strip.match?(/\A(private )|(protected )/) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/delegate_allow_blank.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/delegate_allow_blank.rb new file mode 100644 index 0000000000..78ddf361d8 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/delegate_allow_blank.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop looks for delegations that pass :allow_blank as an option + # instead of :allow_nil. :allow_blank is not a valid option to pass + # to ActiveSupport#delegate. + # + # @example + # # bad + # delegate :foo, to: :bar, allow_blank: true + # + # # good + # delegate :foo, to: :bar, allow_nil: true + class DelegateAllowBlank < Cop + MSG = '`allow_blank` is not a valid option, use `allow_nil`.' + + def_node_matcher :allow_blank_option, <<~PATTERN + (send nil? :delegate _ (hash <$(pair (sym :allow_blank) true) ...>)) + PATTERN + + def on_send(node) + allow_blank_option(node) do |offending_node| + add_offense(offending_node) + end + end + + def autocorrect(pair_node) + lambda do |corrector| + corrector.replace(pair_node.key.source_range, 'allow_nil') + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/dynamic_find_by.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/dynamic_find_by.rb new file mode 100644 index 0000000000..e86efd6d26 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/dynamic_find_by.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks dynamic `find_by_*` methods. + # Use `find_by` instead of dynamic method. + # See. https://rails.rubystyle.guide#find_by + # + # @example + # # bad + # User.find_by_name(name) + # User.find_by_name_and_email(name) + # User.find_by_email!(name) + # + # # good + # User.find_by(name: name) + # User.find_by(name: name, email: email) + # User.find_by!(email: email) + # + # @example AllowedMethods: find_by_sql + # # bad + # User.find_by_query(users_query) + # + # # good + # User.find_by_sql(users_sql) + # + # @example AllowedReceivers: Gem::Specification + # # bad + # Specification.find_by_name('backend').gem_dir + # + # # good + # Gem::Specification.find_by_name('backend').gem_dir + class DynamicFindBy < Cop + MSG = 'Use `%s` instead of dynamic `%s`.' + METHOD_PATTERN = /^find_by_(.+?)(!)?$/.freeze + + def on_send(node) + return if allowed_invocation?(node) + + method_name = node.method_name + static_name = static_method_name(method_name) + return unless static_name + return if node.arguments.any?(&:splat_type?) + + add_offense(node, + message: format(MSG, static_name: static_name, + method: method_name)) + end + alias on_csend on_send + + def autocorrect(node) + keywords = column_keywords(node.method_name) + + return if keywords.size != node.arguments.size + + lambda do |corrector| + autocorrect_method_name(corrector, node) + autocorrect_argument_keywords(corrector, node, keywords) + end + end + + private + + def allowed_invocation?(node) + allowed_method?(node) || allowed_receiver?(node) || + whitelisted?(node) + end + + def allowed_method?(node) + return unless cop_config['AllowedMethods'] + + cop_config['AllowedMethods'].include?(node.method_name.to_s) + end + + def allowed_receiver?(node) + return unless cop_config['AllowedReceivers'] && node.receiver + + cop_config['AllowedReceivers'].include?(node.receiver.source) + end + + # config option `WhiteList` will be deprecated soon + def whitelisted?(node) + whitelist_config = cop_config['Whitelist'] + return unless whitelist_config + + whitelist_config.include?(node.method_name.to_s) + end + + def autocorrect_method_name(corrector, node) + corrector.replace(node.loc.selector, + static_method_name(node.method_name.to_s)) + end + + def autocorrect_argument_keywords(corrector, node, keywords) + keywords.each.with_index do |keyword, idx| + corrector.insert_before(node.arguments[idx].loc.expression, keyword) + end + end + + def column_keywords(method) + keyword_string = method.to_s[METHOD_PATTERN, 1] + keyword_string.split('_and_').map { |keyword| "#{keyword}: " } + end + + # Returns static method name. + # If code isn't wrong, returns nil + def static_method_name(method_name) + match = METHOD_PATTERN.match(method_name) + return nil unless match + + match[2] ? 'find_by!' : 'find_by' + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/enum_hash.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/enum_hash.rb new file mode 100644 index 0000000000..fa36006d5e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/enum_hash.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop looks for enums written with array syntax. + # + # When using array syntax, adding an element in a + # position other than the last causes all previous + # definitions to shift. Explicitly specifying the + # value for each key prevents this from happening. + # + # @example + # # bad + # enum status: [:active, :archived] + # + # # good + # enum status: { active: 0, archived: 1 } + # + class EnumHash < Cop + MSG = 'Enum defined as an array found in `%s` enum declaration. '\ + 'Use hash syntax instead.' + + def_node_matcher :enum?, <<~PATTERN + (send nil? :enum (hash $...)) + PATTERN + + def_node_matcher :array_pair?, <<~PATTERN + (pair $_ $array) + PATTERN + + def on_send(node) + enum?(node) do |pairs| + pairs.each do |pair| + key, array = array_pair?(pair) + next unless key + + add_offense(array, message: format(MSG, enum: enum_name(key))) + end + end + end + + def autocorrect(node) + hash = node.children.each_with_index.map do |elem, index| + "#{source(elem)} => #{index}" + end.join(', ') + + ->(corrector) { corrector.replace(node.loc.expression, "{#{hash}}") } + end + + private + + def enum_name(key) + case key.type + when :sym, :str + key.value + else + key.source + end + end + + def source(elem) + case elem.type + when :str + elem.value.dump + when :sym + elem.value.inspect + else + elem.source + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/enum_uniqueness.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/enum_uniqueness.rb new file mode 100644 index 0000000000..7c5f13b300 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/enum_uniqueness.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop looks for duplicate values in enum declarations. + # + # @example + # # bad + # enum status: { active: 0, archived: 0 } + # + # # good + # enum status: { active: 0, archived: 1 } + # + # # bad + # enum status: [:active, :archived, :active] + # + # # good + # enum status: [:active, :archived] + class EnumUniqueness < Cop + include Duplication + + MSG = 'Duplicate value `%s` found in `%s` ' \ + 'enum declaration.' + + def_node_matcher :enum?, <<~PATTERN + (send nil? :enum (hash $...)) + PATTERN + + def_node_matcher :enum_values, <<~PATTERN + (pair $_ ${array hash}) + PATTERN + + def on_send(node) + enum?(node) do |pairs| + pairs.each do |pair| + enum_values(pair) do |key, args| + items = args.values + + next unless duplicates?(items) + + consecutive_duplicates(items).each do |item| + add_offense(item, message: format( + MSG, value: item.source, enum: enum_name(key) + )) + end + end + end + end + end + + private + + def enum_name(key) + case key.type + when :sym, :str + key.value + else + key.source + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/environment_comparison.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/environment_comparison.rb new file mode 100644 index 0000000000..154b3df91e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/environment_comparison.rb @@ -0,0 +1,114 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that Rails.env is compared using `.production?`-like + # methods instead of equality against a string or symbol. + # + # @example + # # bad + # Rails.env == 'production' + # + # # bad, always returns false + # Rails.env == :test + # + # # good + # Rails.env.production? + class EnvironmentComparison < Cop + MSG = 'Favor `%sRails.env.%s?` over `%s`.' + + SYM_MSG = 'Do not compare `Rails.env` with a symbol, it will always ' \ + 'evaluate to `false`.' + + def_node_matcher :comparing_str_env_with_rails_env_on_lhs?, <<~PATTERN + (send + (send (const {nil? cbase} :Rails) :env) + {:== :!=} + $str + ) + PATTERN + + def_node_matcher :comparing_str_env_with_rails_env_on_rhs?, <<~PATTERN + (send + $str + {:== :!=} + (send (const {nil? cbase} :Rails) :env) + ) + PATTERN + + def_node_matcher :comparing_sym_env_with_rails_env_on_lhs?, <<~PATTERN + (send + (send (const {nil? cbase} :Rails) :env) + {:== :!=} + $sym + ) + PATTERN + + def_node_matcher :comparing_sym_env_with_rails_env_on_rhs?, <<~PATTERN + (send + $sym + {:== :!=} + (send (const {nil? cbase} :Rails) :env) + ) + PATTERN + + def_node_matcher :content, <<~PATTERN + ({str sym} $_) + PATTERN + + def on_send(node) + if (env_node = comparing_str_env_with_rails_env_on_lhs?(node) || + comparing_str_env_with_rails_env_on_rhs?(node)) + env, = *env_node + bang = node.method?(:!=) ? '!' : '' + + add_offense(node, message: format( + MSG, bang: bang, env: env, source: node.source + )) + end + + if comparing_sym_env_with_rails_env_on_lhs?(node) || + comparing_sym_env_with_rails_env_on_rhs?(node) + add_offense(node, message: SYM_MSG) + end + end + + def autocorrect(node) + lambda do |corrector| + replacement = build_predicate_method(node) + + corrector.replace(node.source_range, replacement) + end + end + + private + + def build_predicate_method(node) + if rails_env_on_lhs?(node) + build_predicate_method_for_rails_env_on_lhs(node) + else + build_predicate_method_for_rails_env_on_rhs(node) + end + end + + def rails_env_on_lhs?(node) + comparing_str_env_with_rails_env_on_lhs?(node) || + comparing_sym_env_with_rails_env_on_lhs?(node) + end + + def build_predicate_method_for_rails_env_on_lhs(node) + bang = node.method?(:!=) ? '!' : '' + + "#{bang}#{node.receiver.source}.#{content(node.first_argument)}?" + end + + def build_predicate_method_for_rails_env_on_rhs(node) + bang = node.method?(:!=) ? '!' : '' + + "#{bang}#{node.first_argument.source}.#{content(node.receiver)}?" + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/exit.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/exit.rb new file mode 100644 index 0000000000..1db315edc9 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/exit.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop enforces that `exit` calls are not used within a rails app. + # Valid options are instead to raise an error, break, return, or some + # other form of stopping execution of current request. + # + # There are two obvious cases where `exit` is particularly harmful: + # + # * Usage in library code for your application. Even though Rails will + # rescue from a `SystemExit` and continue on, unit testing that library + # code will result in specs exiting (potentially silently if `exit(0)` + # is used.) + # * Usage in application code outside of the web process could result in + # the program exiting, which could result in the code failing to run and + # do its job. + # + # @example + # # bad + # exit(0) + # + # # good + # raise 'a bad error has happened' + class Exit < Cop + include ConfigurableEnforcedStyle + + MSG = 'Do not use `exit` in Rails applications.' + TARGET_METHODS = %i[exit exit!].freeze + EXPLICIT_RECEIVERS = %i[Kernel Process].freeze + + def on_send(node) + add_offense(node, location: :selector) if offending_node?(node) + end + + private + + def offending_node?(node) + right_method_name?(node.method_name) && + right_argument_count?(node.arguments) && + right_receiver?(node.receiver) + end + + def right_method_name?(method_name) + TARGET_METHODS.include?(method_name) + end + + # More than 1 argument likely means it is a different + # `exit` implementation than the one we are preventing. + def right_argument_count?(arg_nodes) + arg_nodes.size <= 1 + end + + # Only register if exit is being called explicitly on `Kernel`, + # `Process`, or if receiver node is nil for plain `exit` calls. + def right_receiver?(receiver_node) + return true unless receiver_node + + _a, receiver_node_class, _c = *receiver_node + + EXPLICIT_RECEIVERS.include?(receiver_node_class) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/file_path.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/file_path.rb new file mode 100644 index 0000000000..d5b2cc20d1 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/file_path.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop is used to identify usages of file path joining process + # to use `Rails.root.join` clause. It is used to add uniformity when + # joining paths. + # + # @example EnforcedStyle: arguments + # # bad + # Rails.root.join('app/models/goober') + # File.join(Rails.root, 'app/models/goober') + # "#{Rails.root}/app/models/goober" + # + # # good + # Rails.root.join('app', 'models', 'goober') + # + # @example EnforcedStyle: slashes (default) + # # bad + # Rails.root.join('app', 'models', 'goober') + # File.join(Rails.root, 'app/models/goober') + # "#{Rails.root}/app/models/goober" + # + # # good + # Rails.root.join('app/models/goober') + # + class FilePath < Cop + include ConfigurableEnforcedStyle + include RangeHelp + + MSG_SLASHES = 'Please use `Rails.root.join(\'path/to\')` ' \ + 'instead.' + MSG_ARGUMENTS = 'Please use `Rails.root.join(\'path\', \'to\')` ' \ + 'instead.' + + def_node_matcher :file_join_nodes?, <<~PATTERN + (send (const nil? :File) :join ...) + PATTERN + + def_node_search :rails_root_nodes?, <<~PATTERN + (send (const nil? :Rails) :root) + PATTERN + + def_node_matcher :rails_root_join_nodes?, <<~PATTERN + (send (send (const nil? :Rails) :root) :join ...) + PATTERN + + def on_dstr(node) + return unless rails_root_nodes?(node) + return unless node.children.last.str_type? + return unless node.children.last.source.start_with?('.') || + node.children.last.source.include?(File::SEPARATOR) + + register_offense(node) + end + + def on_send(node) + check_for_file_join_with_rails_root(node) + check_for_rails_root_join_with_slash_separated_path(node) + check_for_rails_root_join_with_string_arguments(node) + end + + private + + def check_for_file_join_with_rails_root(node) + return unless file_join_nodes?(node) + return unless node.arguments.any? { |e| rails_root_nodes?(e) } + + register_offense(node) + end + + def check_for_rails_root_join_with_string_arguments(node) + return unless style == :slashes + return unless rails_root_nodes?(node) + return unless rails_root_join_nodes?(node) + return unless node.arguments.size > 1 + return unless node.arguments.all?(&:str_type?) + + register_offense(node) + end + + def check_for_rails_root_join_with_slash_separated_path(node) + return unless style == :arguments + return unless rails_root_nodes?(node) + return unless rails_root_join_nodes?(node) + return unless node.arguments.any? { |arg| string_with_slash?(arg) } + + register_offense(node) + end + + def string_with_slash?(node) + node.str_type? && node.source.include?('/') + end + + def register_offense(node) + line_range = node.loc.column...node.loc.last_column + source_range = source_range(processed_source.buffer, node.first_line, + line_range) + add_offense(node, location: source_range) + end + + def message(_node) + format(style == :arguments ? MSG_ARGUMENTS : MSG_SLASHES) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/find_by.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/find_by.rb new file mode 100644 index 0000000000..c894e40f34 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/find_by.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop is used to identify usages of `where.first` and + # change them to use `find_by` instead. + # + # @example + # # bad + # User.where(name: 'Bruce').first + # User.where(name: 'Bruce').take + # + # # good + # User.find_by(name: 'Bruce') + class FindBy < Cop + include RangeHelp + + MSG = 'Use `find_by` instead of `where.%s`.' + TARGET_SELECTORS = %i[first take].freeze + + def_node_matcher :where_first?, <<~PATTERN + (send ({send csend} _ :where ...) {:first :take}) + PATTERN + + def on_send(node) + return unless where_first?(node) + + range = range_between(node.receiver.loc.selector.begin_pos, + node.loc.selector.end_pos) + + add_offense(node, location: range, + message: format(MSG, method: node.method_name)) + end + alias on_csend on_send + + def autocorrect(node) + # Don't autocorrect where(...).first, because it can return different + # results from find_by. (They order records differently, so the + # 'first' record can be different.) + return if node.method?(:first) + + where_loc = node.receiver.loc.selector + first_loc = range_between(node.loc.dot.begin_pos, + node.loc.selector.end_pos) + + lambda do |corrector| + corrector.replace(where_loc, 'find_by') + corrector.replace(first_loc, '') + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/find_by_id.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/find_by_id.rb new file mode 100644 index 0000000000..7d7837ec78 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/find_by_id.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop enforces that `ActiveRecord#find` is used instead of + # `where.take!`, `find_by!`, and `find_by_id!` to retrieve a single record + # by primary key when you expect it to be found. + # + # @example + # # bad + # User.where(id: id).take! + # User.find_by_id!(id) + # User.find_by!(id: id) + # + # # good + # User.find(id) + # + class FindById < Cop + include RangeHelp + + MSG = 'Use `%s` instead of `%s`.' + + def_node_matcher :where_take?, <<~PATTERN + (send + $(send _ :where + (hash + (pair (sym :id) $_))) :take!) + PATTERN + + def_node_matcher :find_by?, <<~PATTERN + { + (send _ :find_by_id! $_) + (send _ :find_by! (hash (pair (sym :id) $_))) + } + PATTERN + + def on_send(node) + where_take?(node) do |where, id_value| + range = where_take_offense_range(node, where) + + good_method = build_good_method(id_value) + bad_method = build_where_take_bad_method(id_value) + message = format(MSG, good_method: good_method, bad_method: bad_method) + + add_offense(node, location: range, message: message) + end + + find_by?(node) do |id_value| + range = find_by_offense_range(node) + + good_method = build_good_method(id_value) + bad_method = build_find_by_bad_method(node, id_value) + message = format(MSG, good_method: good_method, bad_method: bad_method) + + add_offense(node, location: range, message: message) + end + end + + def autocorrect(node) + if (matches = where_take?(node)) + where, id_value = *matches + range = where_take_offense_range(node, where) + elsif (id_value = find_by?(node)) + range = find_by_offense_range(node) + end + + lambda do |corrector| + replacement = build_good_method(id_value) + corrector.replace(range, replacement) + end + end + + private + + def where_take_offense_range(node, where) + range_between(where.loc.selector.begin_pos, node.loc.expression.end_pos) + end + + def find_by_offense_range(node) + range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos) + end + + def build_good_method(id_value) + "find(#{id_value.source})" + end + + def build_where_take_bad_method(id_value) + "where(id: #{id_value.source}).take!" + end + + def build_find_by_bad_method(node, id_value) + case node.method_name + when :find_by_id! + "find_by_id!(#{id_value.source})" + when :find_by! + "find_by!(id: #{id_value.source})" + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/find_each.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/find_each.rb new file mode 100644 index 0000000000..302fc33b6e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/find_each.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop is used to identify usages of `all.each` and + # change them to use `all.find_each` instead. + # + # @example + # # bad + # User.all.each + # + # # good + # User.all.find_each + class FindEach < Cop + MSG = 'Use `find_each` instead of `each`.' + + SCOPE_METHODS = %i[ + all eager_load includes joins left_joins left_outer_joins not preload + references unscoped where + ].freeze + IGNORED_METHODS = %i[order limit select].freeze + + def on_send(node) + return unless node.receiver&.send_type? && + node.method?(:each) + + return unless SCOPE_METHODS.include?(node.receiver.method_name) + return if method_chain(node).any? { |m| ignored_by_find_each?(m) } + + add_offense(node, location: :selector) + end + + def autocorrect(node) + ->(corrector) { corrector.replace(node.loc.selector, 'find_each') } + end + + private + + def method_chain(node) + node.each_node(:send).map(&:method_name) + end + + def ignored_by_find_each?(relation_method) + # Active Record's #find_each ignores various extra parameters + IGNORED_METHODS.include?(relation_method) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/has_and_belongs_to_many.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/has_and_belongs_to_many.rb new file mode 100644 index 0000000000..4ef8c2631e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/has_and_belongs_to_many.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for the use of the has_and_belongs_to_many macro. + # + # @example + # # bad + # # has_and_belongs_to_many :ingredients + # + # # good + # # has_many :ingredients, through: :recipe_ingredients + class HasAndBelongsToMany < Cop + MSG = 'Prefer `has_many :through` to `has_and_belongs_to_many`.' + + def on_send(node) + return unless node.command?(:has_and_belongs_to_many) + + add_offense(node, location: :selector) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb new file mode 100644 index 0000000000..4956f746f2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop looks for `has_many` or `has_one` associations that don't + # specify a `:dependent` option. + # It doesn't register an offense if `:through` option was specified. + # + # @example + # # bad + # class User < ActiveRecord::Base + # has_many :comments + # has_one :avatar + # end + # + # # good + # class User < ActiveRecord::Base + # has_many :comments, dependent: :restrict_with_exception + # has_one :avatar, dependent: :destroy + # has_many :patients, through: :appointments + # end + class HasManyOrHasOneDependent < Cop + MSG = 'Specify a `:dependent` option.' + + def_node_search :active_resource_class?, <<~PATTERN + (const (const nil? :ActiveResource) :Base) + PATTERN + + def_node_matcher :association_without_options?, <<~PATTERN + (send nil? {:has_many :has_one} _) + PATTERN + + def_node_matcher :association_with_options?, <<~PATTERN + (send nil? {:has_many :has_one} _ (hash $...)) + PATTERN + + def_node_matcher :dependent_option?, <<~PATTERN + (pair (sym :dependent) !nil) + PATTERN + + def_node_matcher :present_option?, <<~PATTERN + (pair (sym :through) !nil) + PATTERN + + def_node_matcher :with_options_block, <<~PATTERN + (block + (send nil? :with_options + (hash $...)) + (args) ...) + PATTERN + + def on_send(node) + return if active_resource?(node.parent) + return if !association_without_options?(node) && valid_options?(association_with_options?(node)) + return if valid_options_in_with_options_block?(node) + + add_offense(node, location: :selector) + end + + private + + def valid_options_in_with_options_block?(node) + return true unless node.parent + + n = node.parent.begin_type? ? node.parent.parent : node.parent + + contain_valid_options_in_with_options_block?(n) + end + + def contain_valid_options_in_with_options_block?(node) + if with_options_block(node) + return true if valid_options?(with_options_block(node)) + + return false unless node.parent + + return true if contain_valid_options_in_with_options_block?( + node.parent.parent + ) + end + + false + end + + def valid_options?(options) + return true unless options + return true if options.any? do |o| + dependent_option?(o) || present_option?(o) + end + + false + end + + def active_resource?(node) + return false if node.nil? + + active_resource_class?(node) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/helper_instance_variable.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/helper_instance_variable.rb new file mode 100644 index 0000000000..e8f50ad287 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/helper_instance_variable.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for use of the helper methods which reference + # instance variables. + # + # Relying on instance variables makes it difficult to re-use helper + # methods. + # + # If it seems awkward to explicitly pass in each dependent + # variable, consider moving the behaviour elsewhere, for + # example to a model, decorator or presenter. + # + # @example + # # bad + # def welcome_message + # "Hello #{@user.name}" + # end + # + # # good + # def welcome_message(user) + # "Hello #{user.name}" + # end + class HelperInstanceVariable < Cop + MSG = 'Do not use instance variables in helpers.' + + def on_ivar(node) + add_offense(node) + end + + def on_ivasgn(node) + return if node.parent.or_asgn_type? + + add_offense(node, location: :name) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/http_positional_arguments.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/http_positional_arguments.rb new file mode 100644 index 0000000000..03ab9c4e26 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/http_positional_arguments.rb @@ -0,0 +1,123 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop is used to identify usages of http methods like `get`, `post`, + # `put`, `patch` without the usage of keyword arguments in your tests and + # change them to use keyword args. This cop only applies to Rails >= 5. + # If you are running Rails < 5 you should disable the + # Rails/HttpPositionalArguments cop or set your TargetRailsVersion in your + # .rubocop.yml file to 4.2. + # + # @example + # # bad + # get :new, { user_id: 1} + # + # # good + # get :new, params: { user_id: 1 } + # get :new, **options + class HttpPositionalArguments < Cop + extend TargetRailsVersion + + MSG = 'Use keyword arguments instead of ' \ + 'positional arguments for http call: `%s`.' + KEYWORD_ARGS = %i[ + method params session body flash xhr as headers env to + ].freeze + HTTP_METHODS = %i[get post put patch delete head].freeze + + minimum_target_rails_version 5.0 + + def_node_matcher :http_request?, <<~PATTERN + (send nil? {#{HTTP_METHODS.map(&:inspect).join(' ')}} !nil? $_ ...) + PATTERN + + def_node_matcher :kwsplat_hash?, <<~PATTERN + (hash (kwsplat _)) + PATTERN + + def on_send(node) + http_request?(node) do |data| + return unless needs_conversion?(data) + + add_offense(node, location: :selector, + message: format(MSG, verb: node.method_name)) + end + end + + # given a pre Rails 5 method: get :new, {user_id: @user.id}, {} + # + # @return lambda of auto correct procedure + # the result should look like: + # get :new, params: { user_id: @user.id }, session: {} + # the http_method is the method used to call the controller + # the controller node can be a symbol, method, object or string + # that represents the path/action on the Rails controller + # the data is the http parameters and environment sent in + # the Rails 5 http call + def autocorrect(node) + lambda do |corrector| + corrector.replace(node.loc.expression, correction(node)) + end + end + + private + + def needs_conversion?(data) + return true unless data.hash_type? + return false if kwsplat_hash?(data) + + data.each_pair.none? do |pair| + special_keyword_arg?(pair.key) || + format_arg?(pair.key) && data.pairs.one? + end + end + + def special_keyword_arg?(node) + node.sym_type? && KEYWORD_ARGS.include?(node.value) + end + + def format_arg?(node) + node.sym_type? && node.value == :format + end + + def convert_hash_data(data, type) + return '' if data.hash_type? && data.empty? + + hash_data = if data.hash_type? + format('{ %s }', + data: data.pairs.map(&:source).join(', ')) + else + # user supplies an object, + # no need to surround with braces + data.source + end + + format(', %s: %s', type: type, hash_data: hash_data) + end + + def correction(node) + http_path, *data = *node.arguments + + controller_action = http_path.source + params = convert_hash_data(data.first, 'params') + session = convert_hash_data(data.last, 'session') if data.size > 1 + + format(correction_template(node), name: node.method_name, + action: controller_action, + params: params, + session: session) + end + + def correction_template(node) + if parentheses?(node) + '%s(%s%s%s)' + else + '%s %s%s%s' + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/http_status.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/http_status.rb new file mode 100644 index 0000000000..e6dffc73d4 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/http_status.rb @@ -0,0 +1,162 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # Enforces use of symbolic or numeric value to define HTTP status. + # + # @example EnforcedStyle: symbolic (default) + # # bad + # render :foo, status: 200 + # render json: { foo: 'bar' }, status: 200 + # render plain: 'foo/bar', status: 304 + # redirect_to root_url, status: 301 + # + # # good + # render :foo, status: :ok + # render json: { foo: 'bar' }, status: :ok + # render plain: 'foo/bar', status: :not_modified + # redirect_to root_url, status: :moved_permanently + # + # @example EnforcedStyle: numeric + # # bad + # render :foo, status: :ok + # render json: { foo: 'bar' }, status: :not_found + # render plain: 'foo/bar', status: :not_modified + # redirect_to root_url, status: :moved_permanently + # + # # good + # render :foo, status: 200 + # render json: { foo: 'bar' }, status: 404 + # render plain: 'foo/bar', status: 304 + # redirect_to root_url, status: 301 + # + class HttpStatus < Cop + include ConfigurableEnforcedStyle + + def_node_matcher :http_status, <<~PATTERN + { + (send nil? {:render :redirect_to} _ $hash) + (send nil? {:render :redirect_to} $hash) + } + PATTERN + + def_node_matcher :status_code, <<~PATTERN + (hash <(pair (sym :status) ${int sym}) ...>) + PATTERN + + def on_send(node) + http_status(node) do |hash_node| + status = status_code(hash_node) + return unless status + + checker = checker_class.new(status) + return unless checker.offensive? + + add_offense(checker.node, message: checker.message) + end + end + + def autocorrect(node) + lambda do |corrector| + checker = checker_class.new(node) + corrector.replace(node.loc.expression, checker.preferred_style) + end + end + + private + + def checker_class + case style + when :symbolic + SymbolicStyleChecker + when :numeric + NumericStyleChecker + end + end + + # :nodoc: + class SymbolicStyleChecker + MSG = 'Prefer `%s` over `%s` ' \ + 'to define HTTP status code.' + DEFAULT_MSG = 'Prefer `symbolic` over `numeric` ' \ + 'to define HTTP status code.' + + attr_reader :node + + def initialize(node) + @node = node + end + + def offensive? + !node.sym_type? && !custom_http_status_code? + end + + def message + format(MSG, prefer: preferred_style, current: number.to_s) + end + + def preferred_style + symbol.inspect + end + + private + + def symbol + ::Rack::Utils::SYMBOL_TO_STATUS_CODE.key(number) + end + + def number + node.children.first + end + + def custom_http_status_code? + node.int_type? && + !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(number) + end + end + + # :nodoc: + class NumericStyleChecker + MSG = 'Prefer `%s` over `%s` ' \ + 'to define HTTP status code.' + DEFAULT_MSG = 'Prefer `numeric` over `symbolic` ' \ + 'to define HTTP status code.' + PERMITTED_STATUS = %i[error success missing redirect].freeze + + attr_reader :node + + def initialize(node) + @node = node + end + + def offensive? + !node.int_type? && !permitted_symbol? + end + + def message + format(MSG, prefer: preferred_style, current: symbol.inspect) + end + + def preferred_style + number.to_s + end + + private + + def number + ::Rack::Utils::SYMBOL_TO_STATUS_CODE[symbol] + end + + def symbol + node.value + end + + def permitted_symbol? + node.sym_type? && PERMITTED_STATUS.include?(node.value) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb new file mode 100644 index 0000000000..e82b137b1f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that `if` and `only` (or `except`) are not used together + # as options of `skip_*` action filter. + # + # The `if` option will be ignored when `if` and `only` are used together. + # Similarly, the `except` option will be ignored when `if` and `except` + # are used together. + # + # @example + # # bad + # class MyPageController < ApplicationController + # skip_before_action :login_required, + # only: :show, if: :trusted_origin? + # end + # + # # good + # class MyPageController < ApplicationController + # skip_before_action :login_required, + # if: -> { trusted_origin? && action_name == "show" } + # end + # + # @example + # # bad + # class MyPageController < ApplicationController + # skip_before_action :login_required, + # except: :admin, if: :trusted_origin? + # end + # + # # good + # class MyPageController < ApplicationController + # skip_before_action :login_required, + # if: -> { trusted_origin? && action_name != "admin" } + # end + # + # @see https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-_normalize_callback_options + class IgnoredSkipActionFilterOption < Cop + MSG = <<~MSG.chomp.freeze + `%s` option will be ignored when `%s` and `%s` are used together. + MSG + + FILTERS = %w[ + :skip_after_action + :skip_around_action + :skip_before_action + :skip_action_callback + ].freeze + + def_node_matcher :filter_options, <<~PATTERN + (send + nil? + {#{FILTERS.join(' ')}} + _ + $_) + PATTERN + + def on_send(node) + options = filter_options(node) + return unless options + return unless options.hash_type? + + options = options_hash(options) + + if if_and_only?(options) + add_offense(options[:if], + message: format(MSG, prefer: :only, ignore: :if)) + elsif if_and_except?(options) + add_offense(options[:except], + message: format(MSG, prefer: :if, ignore: :except)) + end + end + + private + + def options_hash(options) + options.pairs + .select { |pair| pair.key.sym_type? } + .map { |pair| [pair.key.value, pair] }.to_h + end + + def if_and_only?(options) + options.key?(:if) && options.key?(:only) + end + + def if_and_except?(options) + options.key?(:if) && options.key?(:except) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/index_by.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/index_by.rb new file mode 100644 index 0000000000..40a117323c --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/index_by.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop looks for uses of `each_with_object({}) { ... }`, + # `map { ... }.to_h`, and `Hash[map { ... }]` that are transforming + # an enumerable into a hash where the values are the original elements. + # Rails provides the `index_by` method for this purpose. + # + # @example + # # bad + # [1, 2, 3].each_with_object({}) { |el, h| h[foo(el)] = el } + # [1, 2, 3].to_h { |el| [foo(el), el] } + # [1, 2, 3].map { |el| [foo(el), el] }.to_h + # Hash[[1, 2, 3].collect { |el| [foo(el), el] }] + # + # # good + # [1, 2, 3].index_by { |el| foo(el) } + class IndexBy < Cop + include IndexMethod + + def_node_matcher :on_bad_each_with_object, <<~PATTERN + (block + ({send csend} _ :each_with_object (hash)) + (args (arg $_el) (arg _memo)) + ({send csend} (lvar _memo) :[]= $!`_memo (lvar _el))) + PATTERN + + def_node_matcher :on_bad_to_h, <<~PATTERN + (block + ({send csend} _ :to_h) + (args (arg $_el)) + (array $_ (lvar _el))) + PATTERN + + def_node_matcher :on_bad_map_to_h, <<~PATTERN + ({send csend} + (block + ({send csend} _ {:map :collect}) + (args (arg $_el)) + (array $_ (lvar _el))) + :to_h) + PATTERN + + def_node_matcher :on_bad_hash_brackets_map, <<~PATTERN + (send + (const _ :Hash) + :[] + (block + ({send csend} _ {:map :collect}) + (args (arg $_el)) + (array $_ (lvar _el)))) + PATTERN + + private + + def new_method_name + 'index_by' + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/index_with.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/index_with.rb new file mode 100644 index 0000000000..2bc01b327f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/index_with.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop looks for uses of `each_with_object({}) { ... }`, + # `map { ... }.to_h`, and `Hash[map { ... }]` that are transforming + # an enumerable into a hash where the keys are the original elements. + # Rails provides the `index_with` method for this purpose. + # + # @example + # # bad + # [1, 2, 3].each_with_object({}) { |el, h| h[el] = foo(el) } + # [1, 2, 3].to_h { |el| [el, foo(el)] } + # [1, 2, 3].map { |el| [el, foo(el)] }.to_h + # Hash[[1, 2, 3].collect { |el| [el, foo(el)] }] + # + # # good + # [1, 2, 3].index_with { |el| foo(el) } + class IndexWith < Cop + extend TargetRailsVersion + include IndexMethod + + minimum_target_rails_version 6.0 + + def_node_matcher :on_bad_each_with_object, <<~PATTERN + (block + ({send csend} _ :each_with_object (hash)) + (args (arg $_el) (arg _memo)) + ({send csend} (lvar _memo) :[]= (lvar _el) $!`_memo)) + PATTERN + + def_node_matcher :on_bad_to_h, <<~PATTERN + (block + ({send csend} _ :to_h) + (args (arg $_el)) + (array (lvar _el) $_)) + PATTERN + + def_node_matcher :on_bad_map_to_h, <<~PATTERN + ({send csend} + (block + ({send csend} _ {:map :collect}) + (args (arg $_el)) + (array (lvar _el) $_)) + :to_h) + PATTERN + + def_node_matcher :on_bad_hash_brackets_map, <<~PATTERN + (send + (const _ :Hash) + :[] + (block + ({send csend} _ {:map :collect}) + (args (arg $_el)) + (array (lvar _el) $_))) + PATTERN + + private + + def new_method_name + 'index_with' + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/inquiry.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/inquiry.rb new file mode 100644 index 0000000000..f5ea160187 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/inquiry.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that Active Support's `inquiry` method is not used. + # + # @example + # # bad - String#inquiry + # ruby = 'two'.inquiry + # ruby.two? + # + # # good + # ruby = 'two' + # ruby == 'two' + # + # # bad - Array#inquiry + # pets = %w(cat dog).inquiry + # pets.gopher? + # + # # good + # pets = %w(cat dog) + # pets.include? 'cat' + # + class Inquiry < Cop + MSG = "Prefer Ruby's comparison operators over Active Support's `inquiry`." + + def on_send(node) + return unless node.method?(:inquiry) && node.arguments.empty? + return unless (receiver = node.receiver) + return if !receiver.str_type? && !receiver.array_type? + + add_offense(node, location: :selector) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/inverse_of.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/inverse_of.rb new file mode 100644 index 0000000000..afd723bdbe --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/inverse_of.rb @@ -0,0 +1,242 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop looks for has_(one|many) and belongs_to associations where + # Active Record can't automatically determine the inverse association + # because of a scope or the options used. Using the blog with order scope + # example below, traversing the a Blog's association in both directions + # with `blog.posts.first.blog` would cause the `blog` to be loaded from + # the database twice. + # + # `:inverse_of` must be manually specified for Active Record to use the + # associated object in memory, or set to `false` to opt-out. Note that + # setting `nil` does not stop Active Record from trying to determine the + # inverse automatically, and is not considered a valid value for this. + # + # @example + # # good + # class Blog < ApplicationRecord + # has_many :posts + # end + # + # class Post < ApplicationRecord + # belongs_to :blog + # end + # + # @example + # # bad + # class Blog < ApplicationRecord + # has_many :posts, -> { order(published_at: :desc) } + # end + # + # class Post < ApplicationRecord + # belongs_to :blog + # end + # + # # good + # class Blog < ApplicationRecord + # has_many(:posts, + # -> { order(published_at: :desc) }, + # inverse_of: :blog) + # end + # + # class Post < ApplicationRecord + # belongs_to :blog + # end + # + # # good + # class Blog < ApplicationRecord + # with_options inverse_of: :blog do + # has_many :posts, -> { order(published_at: :desc) } + # end + # end + # + # class Post < ApplicationRecord + # belongs_to :blog + # end + # + # # good + # # When you don't want to use the inverse association. + # class Blog < ApplicationRecord + # has_many(:posts, + # -> { order(published_at: :desc) }, + # inverse_of: false) + # end + # + # @example + # # bad + # class Picture < ApplicationRecord + # belongs_to :imageable, polymorphic: true + # end + # + # class Employee < ApplicationRecord + # has_many :pictures, as: :imageable + # end + # + # class Product < ApplicationRecord + # has_many :pictures, as: :imageable + # end + # + # # good + # class Picture < ApplicationRecord + # belongs_to :imageable, polymorphic: true + # end + # + # class Employee < ApplicationRecord + # has_many :pictures, as: :imageable, inverse_of: :imageable + # end + # + # class Product < ApplicationRecord + # has_many :pictures, as: :imageable, inverse_of: :imageable + # end + # + # @example + # # bad + # # However, RuboCop can not detect this pattern... + # class Physician < ApplicationRecord + # has_many :appointments + # has_many :patients, through: :appointments + # end + # + # class Appointment < ApplicationRecord + # belongs_to :physician + # belongs_to :patient + # end + # + # class Patient < ApplicationRecord + # has_many :appointments + # has_many :physicians, through: :appointments + # end + # + # # good + # class Physician < ApplicationRecord + # has_many :appointments + # has_many :patients, through: :appointments + # end + # + # class Appointment < ApplicationRecord + # belongs_to :physician, inverse_of: :appointments + # belongs_to :patient, inverse_of: :appointments + # end + # + # class Patient < ApplicationRecord + # has_many :appointments + # has_many :physicians, through: :appointments + # end + # + # @see https://guides.rubyonrails.org/association_basics.html#bi-directional-associations + # @see https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Setting+Inverses + class InverseOf < Cop + SPECIFY_MSG = 'Specify an `:inverse_of` option.' + NIL_MSG = 'You specified `inverse_of: nil`, you probably meant to ' \ + 'use `inverse_of: false`.' + + def_node_matcher :association_recv_arguments, <<~PATTERN + (send $_ {:has_many :has_one :belongs_to} _ $...) + PATTERN + + def_node_matcher :options_from_argument, <<~PATTERN + (hash $...) + PATTERN + + def_node_matcher :conditions_option?, <<~PATTERN + (pair (sym :conditions) !nil) + PATTERN + + def_node_matcher :through_option?, <<~PATTERN + (pair (sym :through) !nil) + PATTERN + + def_node_matcher :polymorphic_option?, <<~PATTERN + (pair (sym :polymorphic) !nil) + PATTERN + + def_node_matcher :as_option?, <<~PATTERN + (pair (sym :as) !nil) + PATTERN + + def_node_matcher :foreign_key_option?, <<~PATTERN + (pair (sym :foreign_key) !nil) + PATTERN + + def_node_matcher :inverse_of_option?, <<~PATTERN + (pair (sym :inverse_of) !nil) + PATTERN + + def_node_matcher :inverse_of_nil_option?, <<~PATTERN + (pair (sym :inverse_of) nil) + PATTERN + + def on_send(node) + recv, arguments = association_recv_arguments(node) + return unless arguments + + with_options = with_options_arguments(recv, node) + + options = arguments.concat(with_options).flat_map do |arg| + options_from_argument(arg) + end + return if options_ignoring_inverse_of?(options) + + return unless scope?(arguments) || + options_requiring_inverse_of?(options) + + return if options_contain_inverse_of?(options) + + add_offense(node, message: message(options), location: :selector) + end + + def scope?(arguments) + arguments.any?(&:block_type?) + end + + def options_requiring_inverse_of?(options) + required = options.any? do |opt| + conditions_option?(opt) || + foreign_key_option?(opt) + end + + return required if target_rails_version >= 5.2 + + required || options.any? { |opt| as_option?(opt) } + end + + def options_ignoring_inverse_of?(options) + options.any? do |opt| + through_option?(opt) || polymorphic_option?(opt) + end + end + + def options_contain_inverse_of?(options) + options.any? { |opt| inverse_of_option?(opt) } + end + + def with_options_arguments(recv, node) + blocks = node.each_ancestor(:block).select do |block| + block.send_node.command?(:with_options) && + same_context_in_with_options?(block.arguments.first, recv) + end + blocks.flat_map { |n| n.send_node.arguments } + end + + def same_context_in_with_options?(arg, recv) + return true if arg.nil? && recv.nil? + + arg && recv && arg.children[0] == recv.children[0] + end + + private + + def message(options) + if options.any? { |opt| inverse_of_nil_option?(opt) } + NIL_MSG + else + SPECIFY_MSG + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb new file mode 100644 index 0000000000..60957b1632 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb @@ -0,0 +1,175 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that methods specified in the filter's `only` or + # `except` options are defined within the same class or module. + # + # You can technically specify methods of superclass or methods added by + # mixins on the filter, but these can confuse developers. If you specify + # methods that are defined in other classes or modules, you should + # define the filter in that class or module. + # + # If you rely on behaviour defined in the superclass actions, you must + # remember to invoke `super` in the subclass actions. + # + # @example + # # bad + # class LoginController < ApplicationController + # before_action :require_login, only: %i[index settings logout] + # + # def index + # end + # end + # + # # good + # class LoginController < ApplicationController + # before_action :require_login, only: %i[index settings logout] + # + # def index + # end + # + # def settings + # end + # + # def logout + # end + # end + # + # @example + # # bad + # module FooMixin + # extend ActiveSupport::Concern + # + # included do + # before_action proc { authenticate }, only: :foo + # end + # end + # + # # good + # module FooMixin + # extend ActiveSupport::Concern + # + # included do + # before_action proc { authenticate }, only: :foo + # end + # + # def foo + # # something + # end + # end + # + # @example + # class ContentController < ApplicationController + # def update + # @content.update(content_attributes) + # end + # end + # + # class ArticlesController < ContentController + # before_action :load_article, only: [:update] + # + # # the cop requires this method, but it relies on behaviour defined + # # in the superclass, so needs to invoke `super` + # def update + # super + # end + # + # private + # + # def load_article + # @content = Article.find(params[:article_id]) + # end + # end + class LexicallyScopedActionFilter < Cop + MSG = '%s not explicitly defined on the %s.' + + FILTERS = %w[ + :after_action + :append_after_action + :append_around_action + :append_before_action + :around_action + :before_action + :prepend_after_action + :prepend_around_action + :prepend_before_action + :skip_after_action + :skip_around_action + :skip_before_action + :skip_action_callback + ].freeze + + def_node_matcher :only_or_except_filter_methods, <<~PATTERN + (send + nil? + {#{FILTERS.join(' ')}} + _ + (hash + (pair + (sym {:only :except}) + $_))) + PATTERN + + def on_send(node) + methods_node = only_or_except_filter_methods(node) + return unless methods_node + + parent = node.each_ancestor(:class, :module).first + return unless parent + + block = parent.each_child_node(:begin).first + return unless block + + defined_methods = block.each_child_node(:def).map(&:method_name) + methods = array_values(methods_node).reject do |method| + defined_methods.include?(method) + end + + message = message(methods, parent) + add_offense(node, message: message) unless methods.empty? + end + + private + + # @param node [RuboCop::AST::Node] + # @return [Array] + def array_values(node) # rubocop:disable Metrics/MethodLength + case node.type + when :str + [node.str_content.to_sym] + when :sym + [node.value] + when :array + node.values.map do |v| + case v.type + when :str + v.str_content.to_sym + when :sym + v.value + end + end.compact + else + [] + end + end + + # @param methods [Array] + # @param parent [RuboCop::AST::Node] + # @return [String] + def message(methods, parent) + if methods.size == 1 + format(MSG, + action: "`#{methods[0]}` is", + type: parent.type) + else + format(MSG, + action: "`#{methods.join('`, `')}` are", + type: parent.type) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/link_to_blank.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/link_to_blank.rb new file mode 100644 index 0000000000..79e976b27b --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/link_to_blank.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for calls to `link_to` that contain a + # `target: '_blank'` but no `rel: 'noopener'`. This can be a security + # risk as the loaded page will have control over the previous page + # and could change its location for phishing purposes. + # + # The option `rel: 'noreferrer'` also blocks this behavior + # and removes the http-referrer header. + # + # @example + # # bad + # link_to 'Click here', url, target: '_blank' + # + # # good + # link_to 'Click here', url, target: '_blank', rel: 'noopener' + # + # # good + # link_to 'Click here', url, target: '_blank', rel: 'noreferrer' + class LinkToBlank < Cop + MSG = 'Specify a `:rel` option containing noopener.' + + def_node_matcher :blank_target?, <<~PATTERN + (pair {(sym :target) (str "target")} {(str "_blank") (sym :_blank)}) + PATTERN + + def_node_matcher :includes_noopener?, <<~PATTERN + (pair {(sym :rel) (str "rel")} ({str sym} #contains_noopener?)) + PATTERN + + def_node_matcher :rel_node?, <<~PATTERN + (pair {(sym :rel) (str "rel")} (str _)) + PATTERN + + # rubocop:disable Metrics/CyclomaticComplexity + def on_send(node) + return unless node.method?(:link_to) + + option_nodes = node.each_child_node(:hash) + + option_nodes.map(&:children).each do |options| + blank = options.find { |o| blank_target?(o) } + add_offense(blank) if blank && options.none? { |o| includes_noopener?(o) } + end + end + # rubocop:enable Metrics/CyclomaticComplexity + + def autocorrect(node) + lambda do |corrector| + send_node = node.parent.parent + + option_nodes = send_node.each_child_node(:hash) + rel_node = nil + option_nodes.map(&:children).each do |options| + rel_node ||= options.find { |o| rel_node?(o) } + end + + if rel_node + append_to_rel(rel_node, corrector) + else + add_rel(send_node, node, corrector) + end + end + end + + private + + def append_to_rel(rel_node, corrector) + existing_rel = rel_node.children.last.value + str_range = rel_node.children.last.loc.expression.adjust( + begin_pos: 1, + end_pos: -1 + ) + corrector.replace(str_range, "#{existing_rel} noopener") + end + + def add_rel(send_node, offence_node, corrector) + opening_quote = offence_node.children.last.source[0] + closing_quote = opening_quote == ':' ? '' : opening_quote + new_rel_exp = ", rel: #{opening_quote}noopener#{closing_quote}" + range = send_node.arguments.last.source_range + + corrector.insert_after(range, new_rel_exp) + end + + def contains_noopener?(value) + return false unless value + + rel_array = value.to_s.split(' ') + rel_array.include?('noopener') || rel_array.include?('noreferrer') + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/mailer_name.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/mailer_name.rb new file mode 100644 index 0000000000..9019660500 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/mailer_name.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop enforces that mailer names end with `Mailer` suffix. + # + # Without the `Mailer` suffix it isn't immediately apparent what's a mailer + # and which views are related to the mailer. + # + # @example + # # bad + # class User < ActionMailer::Base + # end + # + # class User < ApplicationMailer + # end + # + # # good + # class UserMailer < ActionMailer::Base + # end + # + # class UserMailer < ApplicationMailer + # end + # + class MailerName < Cop + MSG = 'Mailer should end with `Mailer` suffix.' + + def_node_matcher :mailer_base_class?, <<~PATTERN + { + (const (const nil? :ActionMailer) :Base) + (const nil? :ApplicationMailer) + } + PATTERN + + def_node_matcher :class_definition?, <<~PATTERN + (class $(const _ !#mailer_suffix?) #mailer_base_class? ...) + PATTERN + + def_node_matcher :class_new_definition?, <<~PATTERN + (send (const nil? :Class) :new #mailer_base_class?) + PATTERN + + def on_class(node) + class_definition?(node) do |name_node| + add_offense(name_node) + end + end + + def on_send(node) + return unless class_new_definition?(node) + + casgn_parent = node.each_ancestor(:casgn).first + return unless casgn_parent + + name = casgn_parent.children[1] + add_offense(casgn_parent, location: :name) unless mailer_suffix?(name) + end + + def autocorrect(node) + lambda do |corrector| + if node.casgn_type? + name = node.children[1] + corrector.replace(node.loc.name, "#{name}Mailer") + else + name = node.children.last + corrector.replace(node.source_range, "#{name}Mailer") + end + end + end + + private + + def mailer_suffix?(mailer_name) + mailer_name.to_s.end_with?('Mailer') + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/match_route.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/match_route.rb new file mode 100644 index 0000000000..d230b800b0 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/match_route.rb @@ -0,0 +1,119 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop identifies places where defining routes with `match` + # can be replaced with a specific HTTP method. + # + # Don't use `match` to define any routes unless there is a need to map multiple request types + # among [:get, :post, :patch, :put, :delete] to a single action using the `:via` option. + # + # @example + # # bad + # match ':controller/:action/:id' + # match 'photos/:id', to: 'photos#show', via: :get + # + # # good + # get ':controller/:action/:id' + # get 'photos/:id', to: 'photos#show' + # match 'photos/:id', to: 'photos#show', via: [:get, :post] + # match 'photos/:id', to: 'photos#show', via: :all + # + class MatchRoute < Cop + MSG = 'Use `%s` instead of `match` to define a route.' + HTTP_METHODS = %i[get post put patch delete].freeze + + def_node_matcher :match_method_call?, <<~PATTERN + (send nil? :match $_ $(hash ...) ?) + PATTERN + + def on_send(node) + match_method_call?(node) do |path_node, options_node| + return unless within_routes?(node) + + options_node = path_node.hash_type? ? path_node : options_node.first + + if options_node.nil? + message = format(MSG, http_method: 'get') + add_offense(node, message: message) + else + via = extract_via(options_node) + if via.size == 1 && http_method?(via.first) + message = format(MSG, http_method: via.first) + add_offense(node, message: message) + end + end + end + end + + def autocorrect(node) + match_method_call?(node) do |path_node, options_node| + options_node = options_node.first + + lambda do |corrector| + corrector.replace(node, replacement(path_node, options_node)) + end + end + end + + private + + def_node_matcher :routes_draw?, <<~PATTERN + (send (send _ :routes) :draw) + PATTERN + + def within_routes?(node) + node.each_ancestor(:block).any? { |a| routes_draw?(a.send_node) } + end + + def extract_via(node) + via_pair = via_pair(node) + return %i[get] unless via_pair + + _, via = *via_pair + + if via.basic_literal? + [via.value] + elsif via.array_type? + via.values.map(&:value) + else + [] + end + end + + def via_pair(node) + node.pairs.find { |p| p.key.value == :via } + end + + def http_method?(method) + HTTP_METHODS.include?(method.to_sym) + end + + def replacement(path_node, options_node) + if path_node.hash_type? + http_method, options = *http_method_and_options(path_node) + "#{http_method} #{options.map(&:source).join(', ')}" + elsif options_node.nil? + "get #{path_node.source}" + else + http_method, options = *http_method_and_options(options_node) + + if options.any? + "#{http_method} #{path_node.source}, #{options.map(&:source).join(', ')}" + else + "#{http_method} #{path_node.source}" + end + end + end + + def http_method_and_options(node) + via_pair = via_pair(node) + http_method = extract_via(node).first + rest_pairs = node.pairs - [via_pair] + [http_method, rest_pairs] + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/negate_include.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/negate_include.rb new file mode 100644 index 0000000000..04acdffc7f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/negate_include.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop enforces the use of `collection.exclude?(obj)` + # over `!collection.include?(obj)`. + # + # @example + # # bad + # !array.include?(2) + # !hash.include?(:key) + # + # # good + # array.exclude?(2) + # hash.exclude?(:key) + # + class NegateInclude < Cop + MSG = 'Use `.exclude?` and remove the negation part.' + + def_node_matcher :negate_include_call?, <<~PATTERN + (send (send $_ :include? $_) :!) + PATTERN + + def on_send(node) + add_offense(node) if negate_include_call?(node) + end + + def autocorrect(node) + negate_include_call?(node) do |receiver, obj| + lambda do |corrector| + corrector.replace(node, "#{receiver.source}.exclude?(#{obj.source})") + end + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/not_null_column.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/not_null_column.rb new file mode 100644 index 0000000000..119871769a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/not_null_column.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for add_column call with NOT NULL constraint + # in migration file. + # + # @example + # # bad + # add_column :users, :name, :string, null: false + # add_reference :products, :category, null: false + # + # # good + # add_column :users, :name, :string, null: true + # add_column :users, :name, :string, null: false, default: '' + # add_reference :products, :category + # add_reference :products, :category, null: false, default: 1 + class NotNullColumn < Cop + MSG = 'Do not add a NOT NULL column without a default value.' + + def_node_matcher :add_not_null_column?, <<~PATTERN + (send nil? :add_column _ _ _ (hash $...)) + PATTERN + + def_node_matcher :add_not_null_reference?, <<~PATTERN + (send nil? :add_reference _ _ (hash $...)) + PATTERN + + def_node_matcher :null_false?, <<~PATTERN + (pair (sym :null) (false)) + PATTERN + + def_node_matcher :default_option?, <<~PATTERN + (pair (sym :default) !nil) + PATTERN + + def on_send(node) + check_add_column(node) + check_add_reference(node) + end + + private + + def check_add_column(node) + pairs = add_not_null_column?(node) + check_pairs(pairs) + end + + def check_add_reference(node) + pairs = add_not_null_reference?(node) + check_pairs(pairs) + end + + def check_pairs(pairs) + return unless pairs + return if pairs.any? { |pair| default_option?(pair) } + + null_false = pairs.find { |pair| null_false?(pair) } + return unless null_false + + add_offense(null_false) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/order_by_id.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/order_by_id.rb new file mode 100644 index 0000000000..4cc13db266 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/order_by_id.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for places where ordering by `id` column is used. + # + # Don't use the `id` column for ordering. The sequence of ids is not guaranteed + # to be in any particular order, despite often (incidentally) being chronological. + # Use a timestamp column to order chronologically. As a bonus the intent is clearer. + # + # NOTE: Make sure the changed order column does not introduce performance + # bottlenecks and appropriate database indexes are added. + # + # @example + # # bad + # scope :chronological, -> { order(id: :asc) } + # scope :chronological, -> { order(primary_key => :asc) } + # + # # good + # scope :chronological, -> { order(created_at: :asc) } + # + class OrderById < Base + include RangeHelp + + MSG = 'Do not use the `id` column for ordering. '\ + 'Use a timestamp column to order chronologically.' + + def_node_matcher :order_by_id?, <<~PATTERN + (send _ :order + { + (sym :id) + (hash (pair (sym :id) _)) + (send _ :primary_key) + (hash (pair (send _ :primary_key) _)) + }) + PATTERN + + def on_send(node) + return unless node.method?(:order) + + add_offense(offense_range(node)) if order_by_id?(node) + end + + private + + def offense_range(node) + range_between(node.loc.selector.begin_pos, node.source_range.end_pos) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/output.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/output.rb new file mode 100644 index 0000000000..1c8c804030 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/output.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for the use of output calls like puts and print + # + # @example + # # bad + # puts 'A debug message' + # pp 'A debug message' + # print 'A debug message' + # + # # good + # Rails.logger.debug 'A debug message' + class Output < Cop + MSG = 'Do not write to stdout. ' \ + "Use Rails's logger if you want to log." + + def_node_matcher :output?, <<~PATTERN + (send nil? {:ap :p :pp :pretty_print :print :puts} ...) + PATTERN + + def_node_matcher :io_output?, <<~PATTERN + (send + { + (gvar #match_gvar?) + {(const nil? :STDOUT) (const nil? :STDERR)} + } + {:binwrite :syswrite :write :write_nonblock} + ...) + PATTERN + + def on_send(node) + return unless (output?(node) || io_output?(node)) && + node.arguments? + + add_offense(node, location: :selector) + end + + private + + def match_gvar?(sym) + %i[$stdout $stderr].include?(sym) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/output_safety.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/output_safety.rb new file mode 100644 index 0000000000..4c52a07a9a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/output_safety.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for the use of output safety calls like `html_safe`, + # `raw`, and `safe_concat`. These methods do not escape content. They + # simply return a SafeBuffer containing the content as is. Instead, + # use `safe_join` to join content and escape it and concat to + # concatenate content and escape it, ensuring its safety. + # + # @example + # user_content = "hi" + # + # # bad + # "

#{user_content}

".html_safe + # # => ActiveSupport::SafeBuffer "

hi

" + # + # # good + # content_tag(:p, user_content) + # # => ActiveSupport::SafeBuffer "

<b>hi</b>

" + # + # # bad + # out = "" + # out << "
  • #{user_content}
  • " + # out << "
  • #{user_content}
  • " + # out.html_safe + # # => ActiveSupport::SafeBuffer "
  • hi
  • hi
  • " + # + # # good + # out = [] + # out << content_tag(:li, user_content) + # out << content_tag(:li, user_content) + # safe_join(out) + # # => ActiveSupport::SafeBuffer + # # "
  • <b>hi</b>
  • <b>hi</b>
  • " + # + # # bad + # out = "

    trusted content

    ".html_safe + # out.safe_concat(user_content) + # # => ActiveSupport::SafeBuffer "

    trusted_content

    hi" + # + # # good + # out = "

    trusted content

    ".html_safe + # out.concat(user_content) + # # => ActiveSupport::SafeBuffer + # # "

    trusted_content

    <b>hi</b>" + # + # # safe, though maybe not good style + # out = "trusted content" + # result = out.concat(user_content) + # # => String "trusted contenthi" + # # because when rendered in ERB the String will be escaped: + # # <%= result %> + # # => trusted content<b>hi</b> + # + # # bad + # (user_content + " " + content_tag(:span, user_content)).html_safe + # # => ActiveSupport::SafeBuffer "hi hi" + # + # # good + # safe_join([user_content, " ", content_tag(:span, user_content)]) + # # => ActiveSupport::SafeBuffer + # # "<b>hi</b> <b>hi</b>" + class OutputSafety < Cop + MSG = 'Tagging a string as html safe may be a security risk.' + + def on_send(node) + return if non_interpolated_string?(node) + + return unless looks_like_rails_html_safe?(node) || + looks_like_rails_raw?(node) || + looks_like_rails_safe_concat?(node) + + add_offense(node, location: :selector) + end + alias on_csend on_send + + private + + def non_interpolated_string?(node) + node.receiver&.str_type? && !node.receiver.dstr_type? + end + + def looks_like_rails_html_safe?(node) + node.receiver && node.method?(:html_safe) && !node.arguments? + end + + def looks_like_rails_raw?(node) + node.command?(:raw) && node.arguments.one? + end + + def looks_like_rails_safe_concat?(node) + node.method?(:safe_concat) && node.arguments.one? + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pick.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pick.rb new file mode 100644 index 0000000000..fd9cd92e48 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pick.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop enforces the use of `pick` over `pluck(...).first`. + # + # Using `pluck` followed by `first` creates an intermediate array, which + # `pick` avoids. When called on an Active Record relation, `pick` adds a + # limit to the query so that only one value is fetched from the database. + # + # @example + # # bad + # Model.pluck(:a).first + # [{ a: :b, c: :d }].pluck(:a, :b).first + # + # # good + # Model.pick(:a) + # [{ a: :b, c: :d }].pick(:a, :b) + class Pick < Cop + extend TargetRailsVersion + + MSG = 'Prefer `pick(%s)` over `pluck(%s).first`.' + + minimum_target_rails_version 6.0 + + def_node_matcher :pick_candidate?, <<~PATTERN + (send (send _ :pluck ...) :first) + PATTERN + + def on_send(node) + pick_candidate?(node) do + range = node.receiver.loc.selector.join(node.loc.selector) + add_offense(node, location: range) + end + end + + def autocorrect(node) + first_range = node.receiver.source_range.end.join(node.loc.selector) + + lambda do |corrector| + corrector.remove(first_range) + corrector.replace(node.receiver.loc.selector, 'pick') + end + end + + private + + def message(node) + format(MSG, args: node.receiver.arguments.map(&:source).join(', ')) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluck.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluck.rb new file mode 100644 index 0000000000..c31fcfa2f8 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluck.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop enforces the use of `pluck` over `map`. + # + # `pluck` can be used instead of `map` to extract a single key from each + # element in an enumerable. When called on an Active Record relation, it + # results in a more efficient query that only selects the necessary key. + # + # @example + # # bad + # Post.published.map { |post| post[:title] } + # [{ a: :b, c: :d }].collect { |el| el[:a] } + # + # # good + # Post.published.pluck(:title) + # [{ a: :b, c: :d }].pluck(:a) + class Pluck < Cop + extend TargetRailsVersion + + MSG = 'Prefer `pluck(:%s)` over `%s { |%s| %s[:%s] }`.' + + minimum_target_rails_version 5.0 + + def_node_matcher :pluck_candidate?, <<~PATTERN + (block (send _ ${:map :collect}) (args (arg $_argument)) (send (lvar $_element) :[] (sym $_value))) + PATTERN + + def on_block(node) + pluck_candidate?(node) do |method, argument, element, value| + next unless argument == element + + add_offense(node, location: offense_range(node), message: message(method, argument, element, value)) + end + end + + def autocorrect(node) + _method, _argument, _element, value = pluck_candidate?(node) + + lambda do |corrector| + corrector.replace(offense_range(node), "pluck(:#{value})") + end + end + + private + + def offense_range(node) + node.send_node.loc.selector.join(node.loc.end) + end + + def message(method, argument, element, value) + format(MSG, method: method, argument: argument, element: element, value: value) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluck_id.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluck_id.rb new file mode 100644 index 0000000000..cf94877f67 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluck_id.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop enforces the use of `ids` over `pluck(:id)` and `pluck(primary_key)`. + # + # @example + # # bad + # User.pluck(:id) + # user.posts.pluck(:id) + # + # def self.user_ids + # pluck(primary_key) + # end + # + # # good + # User.ids + # user.posts.ids + # + # def self.user_ids + # ids + # end + # + class PluckId < Cop + include RangeHelp + include ActiveRecordHelper + + MSG = 'Use `ids` instead of `%s`.' + + def_node_matcher :pluck_id_call?, <<~PATTERN + (send _ :pluck {(sym :id) (send nil? :primary_key)}) + PATTERN + + def on_send(node) + return if !pluck_id_call?(node) || in_where?(node) + + range = offense_range(node) + message = format(MSG, bad_method: range.source) + + add_offense(node, location: range, message: message) + end + + def autocorrect(node) + lambda do |corrector| + corrector.replace(offense_range(node), 'ids') + end + end + + private + + def offense_range(node) + range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluck_in_where.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluck_in_where.rb new file mode 100644 index 0000000000..bed118a8e7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluck_in_where.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop identifies places where `pluck` is used in `where` query methods + # and can be replaced with `select`. + # + # Since `pluck` is an eager method and hits the database immediately, + # using `select` helps to avoid additional database queries. + # + # This cop has two different enforcement modes. When the EnforcedStyle + # is conservative (the default) then only calls to `pluck` on a constant + # (i.e. a model class) in the `where` is used as offenses. + # + # When the EnforcedStyle is aggressive then all calls to `pluck` in the + # `where` is used as offenses. This may lead to false positives + # as the cop cannot replace to `select` between calls to `pluck` on an + # `ActiveRecord::Relation` instance vs a call to `pluck` on an `Array` instance. + # + # @example + # # bad + # Post.where(user_id: User.active.pluck(:id)) + # + # # good + # Post.where(user_id: User.active.select(:id)) + # Post.where(user_id: active_users.select(:id)) + # + # @example EnforcedStyle: conservative (default) + # # good + # Post.where(user_id: active_users.pluck(:id)) + # + # @example EnforcedStyle: aggressive + # # bad + # Post.where(user_id: active_users.pluck(:id)) + # + class PluckInWhere < Cop + include ActiveRecordHelper + include ConfigurableEnforcedStyle + + MSG = 'Use `select` instead of `pluck` within `where` query method.' + + def on_send(node) + return unless node.method?(:pluck) && in_where?(node) + return if style == :conservative && !root_receiver(node)&.const_type? + + add_offense(node, location: :selector) + end + + def autocorrect(node) + lambda do |corrector| + corrector.replace(node.loc.selector, 'select') + end + end + + private + + def root_receiver(node) + receiver = node.receiver + + if receiver&.send_type? + root_receiver(receiver) + else + receiver + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluralization_grammar.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluralization_grammar.rb new file mode 100644 index 0000000000..5bfbbd7464 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/pluralization_grammar.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for correct grammar when using ActiveSupport's + # core extensions to the numeric classes. + # + # @example + # # bad + # 3.day.ago + # 1.months.ago + # + # # good + # 3.days.ago + # 1.month.ago + class PluralizationGrammar < Cop + SINGULAR_DURATION_METHODS = { second: :seconds, + minute: :minutes, + hour: :hours, + day: :days, + week: :weeks, + fortnight: :fortnights, + month: :months, + year: :years }.freeze + + PLURAL_DURATION_METHODS = SINGULAR_DURATION_METHODS.invert.freeze + + MSG = 'Prefer `%s.%s`.' + + def on_send(node) + return unless duration_method?(node.method_name) + return unless literal_number?(node.receiver) + + return unless offense?(node) + + add_offense(node) + end + + def autocorrect(node) + lambda do |corrector| + method_name = node.loc.selector.source + + corrector.replace(node.loc.selector, correct_method(method_name)) + end + end + + private + + def message(node) + number, = *node.receiver + + format(MSG, number: number, + correct: correct_method(node.method_name.to_s)) + end + + def correct_method(method_name) + if plural_method?(method_name) + singularize(method_name) + else + pluralize(method_name) + end + end + + def offense?(node) + number, = *node.receiver + + singular_receiver?(number) && plural_method?(node.method_name) || + plural_receiver?(number) && singular_method?(node.method_name) + end + + def plural_method?(method_name) + method_name.to_s.end_with?('s') + end + + def singular_method?(method_name) + !plural_method?(method_name) + end + + def singular_receiver?(number) + number.abs == 1 + end + + def plural_receiver?(number) + !singular_receiver?(number) + end + + def literal_number?(node) + node && (node.int_type? || node.float_type?) + end + + def pluralize(method_name) + SINGULAR_DURATION_METHODS.fetch(method_name.to_sym).to_s + end + + def singularize(method_name) + PLURAL_DURATION_METHODS.fetch(method_name.to_sym).to_s + end + + def duration_method?(method_name) + SINGULAR_DURATION_METHODS.key?(method_name) || + PLURAL_DURATION_METHODS.key?(method_name) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/presence.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/presence.rb new file mode 100644 index 0000000000..9f720761a9 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/presence.rb @@ -0,0 +1,144 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks code that can be written more easily using + # `Object#presence` defined by Active Support. + # + # @example + # # bad + # a.present? ? a : nil + # + # # bad + # !a.present? ? nil : a + # + # # bad + # a.blank? ? nil : a + # + # # bad + # !a.blank? ? a : nil + # + # # good + # a.presence + # + # @example + # # bad + # a.present? ? a : b + # + # # bad + # !a.present? ? b : a + # + # # bad + # a.blank? ? b : a + # + # # bad + # !a.blank? ? a : b + # + # # good + # a.presence || b + class Presence < Cop + include RangeHelp + + MSG = 'Use `%s` instead of `%s`.' + + def_node_matcher :redundant_receiver_and_other, <<~PATTERN + { + (if + (send $_recv :present?) + _recv + $!begin + ) + (if + (send $_recv :blank?) + $!begin + _recv + ) + } + PATTERN + + def_node_matcher :redundant_negative_receiver_and_other, <<~PATTERN + { + (if + (send (send $_recv :present?) :!) + $!begin + _recv + ) + (if + (send (send $_recv :blank?) :!) + _recv + $!begin + ) + } + PATTERN + + def on_if(node) + return if ignore_if_node?(node) + + redundant_receiver_and_other(node) do |receiver, other| + add_offense(node, message: message(node, receiver, other)) unless ignore_other_node?(other) || receiver.nil? + end + + redundant_negative_receiver_and_other(node) do |receiver, other| + add_offense(node, message: message(node, receiver, other)) unless ignore_other_node?(other) || receiver.nil? + end + end + + def autocorrect(node) + lambda do |corrector| + redundant_receiver_and_other(node) do |receiver, other| + corrector.replace(node.source_range, replacement(receiver, other)) + end + + redundant_negative_receiver_and_other(node) do |receiver, other| + corrector.replace(node.source_range, replacement(receiver, other)) + end + end + end + + private + + def ignore_if_node?(node) + node.elsif? + end + + def ignore_other_node?(node) + node && (node.if_type? || node.rescue_type? || node.while_type?) + end + + def message(node, receiver, other) + format(MSG, + prefer: replacement(receiver, other), + current: node.source) + end + + def replacement(receiver, other) + or_source = if other&.send_type? + build_source_for_or_method(other) + elsif other.nil? || other.nil_type? + '' + else + " || #{other.source}" + end + + "#{receiver.source}.presence" + or_source + end + + def build_source_for_or_method(other) + if other.parenthesized? || other.method?('[]') || !other.arguments? + " || #{other.source}" + else + method = range_between( + other.source_range.begin_pos, + other.first_argument.source_range.begin_pos - 1 + ).source + + arguments = other.arguments.map(&:source).join(', ') + + " || #{method}(#{arguments})" + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/present.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/present.rb new file mode 100644 index 0000000000..36a0d897b6 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/present.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for code that can be written with simpler conditionals + # using `Object#present?` defined by Active Support. + # + # Interaction with `Style/UnlessElse`: + # The configuration of `NotBlank` will not produce an offense in the + # context of `unless else` if `Style/UnlessElse` is inabled. This is + # to prevent interference between the auto-correction of the two cops. + # + # @example NotNilAndNotEmpty: true (default) + # # Converts usages of `!nil? && !empty?` to `present?` + # + # # bad + # !foo.nil? && !foo.empty? + # + # # bad + # foo != nil && !foo.empty? + # + # # good + # foo.present? + # + # @example NotBlank: true (default) + # # Converts usages of `!blank?` to `present?` + # + # # bad + # !foo.blank? + # + # # bad + # not foo.blank? + # + # # good + # foo.present? + # + # @example UnlessBlank: true (default) + # # Converts usages of `unless blank?` to `if present?` + # + # # bad + # something unless foo.blank? + # + # # good + # something if foo.present? + class Present < Cop + MSG_NOT_BLANK = 'Use `%s` instead of `%s`.' + MSG_EXISTS_AND_NOT_EMPTY = 'Use `%s` instead of ' \ + '`%s`.' + MSG_UNLESS_BLANK = 'Use `if %s` instead of ' \ + '`%s`.' + + def_node_matcher :exists_and_not_empty?, <<~PATTERN + (and + { + (send (send $_ :nil?) :!) + (send (send $_ :!) :!) + (send $_ :!= nil) + $_ + } + { + (send (send $_ :empty?) :!) + } + ) + PATTERN + + def_node_matcher :not_blank?, '(send (send $_ :blank?) :!)' + + def_node_matcher :unless_blank?, <<~PATTERN + (:if $(send $_ :blank?) {nil? (...)} ...) + PATTERN + + def on_send(node) + return unless cop_config['NotBlank'] + + not_blank?(node) do |receiver| + add_offense(node, + message: format(MSG_NOT_BLANK, + prefer: replacement(receiver), + current: node.source)) + end + end + + def on_and(node) + return unless cop_config['NotNilAndNotEmpty'] + + exists_and_not_empty?(node) do |var1, var2| + return unless var1 == var2 + + add_offense(node, + message: format(MSG_EXISTS_AND_NOT_EMPTY, + prefer: replacement(var1), + current: node.source)) + end + end + + def on_or(node) + return unless cop_config['NilOrEmpty'] + + exists_and_not_empty?(node) do |var1, var2| + return unless var1 == var2 + + add_offense(node, message: MSG_EXISTS_AND_NOT_EMPTY) + end + end + + def on_if(node) + return unless cop_config['UnlessBlank'] + return unless node.unless? + return if node.else? && config.for_cop('Style/UnlessElse')['Enabled'] + + unless_blank?(node) do |method_call, receiver| + range = unless_condition(node, method_call) + msg = format(MSG_UNLESS_BLANK, prefer: replacement(receiver), + current: range.source) + add_offense(node, location: range, message: msg) + end + end + + def autocorrect(node) + lambda do |corrector| + method_call, variable1 = unless_blank?(node) + + if method_call + corrector.replace(node.loc.keyword, 'if') + range = method_call.loc.expression + else + variable1, _variable2 = + exists_and_not_empty?(node) || not_blank?(node) + range = node.loc.expression + end + + corrector.replace(range, replacement(variable1)) + end + end + + private + + def unless_condition(node, method_call) + if node.modifier_form? + node.loc.keyword.join(node.loc.expression.end) + else + node.loc.expression.begin.join(method_call.loc.expression) + end + end + + def replacement(node) + node.respond_to?(:source) ? "#{node.source}.present?" : 'present?' + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/rake_environment.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/rake_environment.rb new file mode 100644 index 0000000000..17ab9dfcc7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/rake_environment.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for Rake tasks without the `:environment` task + # dependency. The `:environment` task loads application code for other + # Rake tasks. Without it, tasks cannot make use of application code like + # models. + # + # You can ignore the offense if the task satisfies at least one of the + # following conditions: + # + # * The task does not need application code. + # * The task invokes the `:environment` task. + # + # @example + # # bad + # task :foo do + # do_something + # end + # + # # good + # task foo: :environment do + # do_something + # end + # + class RakeEnvironment < Cop + MSG = 'Include `:environment` task as a dependency for all Rake tasks.' + + def_node_matcher :task_definition?, <<~PATTERN + (block $(send nil? :task ...) ...) + PATTERN + + def on_block(node) + task_definition?(node) do |task_method| + return if task_name(task_method) == :default + return if with_dependencies?(task_method) + + add_offense(task_method) + end + end + + def autocorrect(node) + lambda do |corrector| + task_name = node.arguments[0] + task_dependency = correct_task_dependency(task_name) + + corrector.replace(task_name.loc.expression, task_dependency) + end + end + + private + + def correct_task_dependency(task_name) + if task_name.sym_type? + "#{task_name.source.delete(':|\'|"')}: :environment" + else + "#{task_name.source} => :environment" + end + end + + def task_name(node) + first_arg = node.arguments[0] + case first_arg&.type + when :sym, :str + first_arg.value.to_sym + when :hash + return nil if first_arg.children.size != 1 + + pair = first_arg.children.first + key = pair.children.first + case key.type + when :sym, :str + key.value.to_sym + end + end + end + + def with_dependencies?(node) + first_arg = node.arguments[0] + return false unless first_arg + + if first_arg.hash_type? + with_hash_style_dependencies?(first_arg) + else + task_args = node.arguments[1] + return false unless task_args + return false unless task_args.hash_type? + + with_hash_style_dependencies?(task_args) + end + end + + def with_hash_style_dependencies?(hash_node) + deps = hash_node.pairs.first&.value + return false unless deps + + case deps.type + when :array + !deps.values.empty? + else + true + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/read_write_attribute.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/read_write_attribute.rb new file mode 100644 index 0000000000..d8908d0b26 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/read_write_attribute.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for the use of the `read_attribute` or `write_attribute` + # methods and recommends square brackets instead. + # + # If an attribute is missing from the instance (for example, when + # initialized by a partial `select`) then `read_attribute` + # will return nil, but square brackets will raise + # an `ActiveModel::MissingAttributeError`. + # + # Explicitly raising an error in this situation is preferable, and that + # is why rubocop recommends using square brackets. + # + # @example + # + # # bad + # x = read_attribute(:attr) + # write_attribute(:attr, val) + # + # # good + # x = self[:attr] + # self[:attr] = val + class ReadWriteAttribute < Cop + MSG = 'Prefer `%s` over `%s`.' + + def_node_matcher :read_write_attribute?, <<~PATTERN + { + (send nil? :read_attribute _) + (send nil? :write_attribute _ _) + } + PATTERN + + def on_send(node) + return unless read_write_attribute?(node) + + add_offense(node, location: :selector) + end + + def autocorrect(node) + case node.method_name + when :read_attribute + replacement = read_attribute_replacement(node) + when :write_attribute + replacement = write_attribute_replacement(node) + end + + ->(corrector) { corrector.replace(node.source_range, replacement) } + end + + private + + def message(node) + if node.method?(:read_attribute) + format(MSG, prefer: 'self[:attr]', current: 'read_attribute(:attr)') + else + format(MSG, prefer: 'self[:attr] = val', + current: 'write_attribute(:attr, val)') + end + end + + def read_attribute_replacement(node) + "self[#{node.first_argument.source}]" + end + + def write_attribute_replacement(node) + "self[#{node.first_argument.source}] = #{node.last_argument.source}" + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/redundant_allow_nil.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/redundant_allow_nil.rb new file mode 100644 index 0000000000..6466274010 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/redundant_allow_nil.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # Checks Rails model validations for a redundant `allow_nil` when + # `allow_blank` is present. + # + # @example + # # bad + # validates :x, length: { is: 5 }, allow_nil: true, allow_blank: true + # + # # bad + # validates :x, length: { is: 5 }, allow_nil: false, allow_blank: true + # + # # bad + # validates :x, length: { is: 5 }, allow_nil: false, allow_blank: false + # + # # good + # validates :x, length: { is: 5 }, allow_blank: true + # + # # good + # validates :x, length: { is: 5 }, allow_blank: false + # + # # good + # # Here, `nil` is valid but `''` is not + # validates :x, length: { is: 5 }, allow_nil: true, allow_blank: false + # + class RedundantAllowNil < Cop + include RangeHelp + + MSG_SAME = + '`allow_nil` is redundant when `allow_blank` has the same value.' + + MSG_ALLOW_NIL_FALSE = + '`allow_nil: false` is redundant when `allow_blank` is true.' + + def on_send(node) + return unless node.method?(:validates) + + allow_nil, allow_blank = find_allow_nil_and_allow_blank(node) + return unless allow_nil && allow_blank + + allow_nil_val = allow_nil.children.last + allow_blank_val = allow_blank.children.last + + offense(allow_nil_val, allow_blank_val, allow_nil) + end + + def autocorrect(node) + prv_sib = previous_sibling(node) + nxt_sib = next_sibling(node) + + lambda do |corrector| + if nxt_sib + corrector.remove(range_between(node_beg(node), node_beg(nxt_sib))) + elsif prv_sib + corrector.remove(range_between(node_end(prv_sib), node_end(node))) + else + corrector.remove(node.loc.expression) + end + end + end + + private + + def offense(allow_nil_val, allow_blank_val, allow_nil) + if allow_nil_val.type == allow_blank_val.type + add_offense(allow_nil, message: MSG_SAME) + elsif allow_nil_val.false_type? && allow_blank_val.true_type? + add_offense(allow_nil, message: MSG_ALLOW_NIL_FALSE) + end + end + + def find_allow_nil_and_allow_blank(node) + allow_nil = nil + allow_blank = nil + + node.each_descendant do |descendant| + next unless descendant.pair_type? + + key = descendant.children.first.source + + allow_nil = descendant if key == 'allow_nil' + allow_blank = descendant if key == 'allow_blank' + + break if allow_nil && allow_blank + end + + [allow_nil, allow_blank] + end + + def previous_sibling(node) + node.parent.children[node.sibling_index - 1] + end + + def next_sibling(node) + node.parent.children[node.sibling_index + 1] + end + + def node_beg(node) + node.loc.expression.begin_pos + end + + def node_end(node) + node.loc.expression.end_pos + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/redundant_foreign_key.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/redundant_foreign_key.rb new file mode 100644 index 0000000000..ebba1c9730 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/redundant_foreign_key.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop detects cases where the `:foreign_key` option on associations + # is redundant. + # + # @example + # # bad + # class Post + # has_many :comments, foreign_key: 'post_id' + # end + # + # class Comment + # belongs_to :post, foreign_key: 'post_id' + # end + # + # # good + # class Post + # has_many :comments + # end + # + # class Comment + # belongs_to :author, foreign_key: 'user_id' + # end + class RedundantForeignKey < Cop + include RangeHelp + + MSG = 'Specifying the default value for `foreign_key` is redundant.' + + def_node_matcher :association_with_foreign_key, <<~PATTERN + (send nil? ${:belongs_to :has_one :has_many :has_and_belongs_to_many} ({sym str} $_) + $(hash <$(pair (sym :foreign_key) ({sym str} $_)) ...>) + ) + PATTERN + + def on_send(node) + association_with_foreign_key(node) do |type, name, options, foreign_key_pair, foreign_key| + if redundant?(node, type, name, options, foreign_key) + add_offense(node, location: foreign_key_pair.loc.expression) + end + end + end + + def autocorrect(node) + _type, _name, _options, foreign_key_pair, _foreign_key = association_with_foreign_key(node) + range = range_with_surrounding_space(range: foreign_key_pair.source_range, side: :left) + range = range_with_surrounding_comma(range, :left) + + lambda do |corrector| + corrector.remove(range) + end + end + + private + + def redundant?(node, association_type, association_name, options, foreign_key) + foreign_key.to_s == default_foreign_key(node, association_type, association_name, options) + end + + def default_foreign_key(node, association_type, association_name, options) + if association_type == :belongs_to + "#{association_name}_id" + elsif (as = find_as_option(options)) + "#{as}_id" + else + node.parent_module_name&.foreign_key + end + end + + def find_as_option(options) + options.pairs.find do |pair| + pair.key.sym_type? && pair.key.value == :as + end&.value&.value + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb new file mode 100644 index 0000000000..307bc1da48 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb @@ -0,0 +1,133 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for redundant receiver in `with_options`. + # Receiver is implicit from Rails 4.2 or higher. + # + # @example + # # bad + # class Account < ApplicationRecord + # with_options dependent: :destroy do |assoc| + # assoc.has_many :customers + # assoc.has_many :products + # assoc.has_many :invoices + # assoc.has_many :expenses + # end + # end + # + # # good + # class Account < ApplicationRecord + # with_options dependent: :destroy do + # has_many :customers + # has_many :products + # has_many :invoices + # has_many :expenses + # end + # end + # + # @example + # # bad + # with_options options: false do |merger| + # merger.invoke(merger.something) + # end + # + # # good + # with_options options: false do + # invoke(something) + # end + # + # # good + # client = Client.new + # with_options options: false do |merger| + # client.invoke(merger.something, something) + # end + # + # # ok + # # When `with_options` includes a block, all scoping scenarios + # # cannot be evaluated. Thus, it is ok to include the explicit + # # receiver. + # with_options options: false do |merger| + # merger.invoke + # with_another_method do |another_receiver| + # merger.invoke(another_receiver) + # end + # end + class RedundantReceiverInWithOptions < Cop + include RangeHelp + + MSG = 'Redundant receiver in `with_options`.' + + def_node_matcher :with_options?, <<~PATTERN + (block + (send nil? :with_options + (...)) + (args + $_arg) + $_body) + PATTERN + + def_node_search :all_block_nodes_in, <<~PATTERN + (block ...) + PATTERN + + def_node_search :all_send_nodes_in, <<~PATTERN + (send ...) + PATTERN + + def on_block(node) + with_options?(node) do |arg, body| + return if body.nil? + return unless all_block_nodes_in(body).count.zero? + + send_nodes = all_send_nodes_in(body) + + if send_nodes.all? { |n| same_value?(arg, n.receiver) } + send_nodes.each do |send_node| + receiver = send_node.receiver + add_offense(send_node, location: receiver.source_range) + end + end + end + end + + def autocorrect(node) + lambda do |corrector| + corrector.remove(node.receiver.source_range) + corrector.remove(node.loc.dot) + corrector.remove(block_argument_range(node)) + end + end + + private + + def block_argument_range(node) + block_node = node.each_ancestor(:block).first + block_argument = block_node.children[1].source_range + + range_between( + search_begin_pos_of_space_before_block_argument( + block_argument.begin_pos + ), + block_argument.end_pos + ) + end + + def search_begin_pos_of_space_before_block_argument(begin_pos) + position = begin_pos - 1 + + if processed_source.raw_source[position] == ' ' + search_begin_pos_of_space_before_block_argument(position) + else + begin_pos + end + end + + def same_value?(arg_node, recv_node) + recv_node && recv_node.children[0] == arg_node.children[0] + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/reflection_class_name.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/reflection_class_name.rb new file mode 100644 index 0000000000..336b95fc26 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/reflection_class_name.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks if the value of the option `class_name`, in + # the definition of a reflection is a string. + # + # @example + # # bad + # has_many :accounts, class_name: Account + # has_many :accounts, class_name: Account.name + # + # # good + # has_many :accounts, class_name: 'Account' + class ReflectionClassName < Cop + MSG = 'Use a string value for `class_name`.' + + def_node_matcher :association_with_reflection, <<~PATTERN + (send nil? {:has_many :has_one :belongs_to} _ _ ? + (hash <$#reflection_class_name ...>) + ) + PATTERN + + def_node_matcher :reflection_class_name, <<~PATTERN + (pair (sym :class_name) [!dstr !str !sym]) + PATTERN + + def on_send(node) + association_with_reflection(node) do |reflection_class_name| + add_offense(node, location: reflection_class_name.loc.expression) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/refute_methods.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/refute_methods.rb new file mode 100644 index 0000000000..70bfe97a79 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/refute_methods.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # + # Use `assert_not` methods instead of `refute` methods. + # + # @example EnforcedStyle: assert_not (default) + # # bad + # refute false + # refute_empty [1, 2, 3] + # refute_equal true, false + # + # # good + # assert_not false + # assert_not_empty [1, 2, 3] + # assert_not_equal true, false + # + # @example EnforcedStyle: refute + # # bad + # assert_not false + # assert_not_empty [1, 2, 3] + # assert_not_equal true, false + # + # # good + # refute false + # refute_empty [1, 2, 3] + # refute_equal true, false + # + class RefuteMethods < Cop + include ConfigurableEnforcedStyle + + MSG = 'Prefer `%s` over `%s`.' + + CORRECTIONS = { + refute: :assert_not, + refute_empty: :assert_not_empty, + refute_equal: :assert_not_equal, + refute_in_delta: :assert_not_in_delta, + refute_in_epsilon: :assert_not_in_epsilon, + refute_includes: :assert_not_includes, + refute_instance_of: :assert_not_instance_of, + refute_kind_of: :assert_not_kind_of, + refute_nil: :assert_not_nil, + refute_operator: :assert_not_operator, + refute_predicate: :assert_not_predicate, + refute_respond_to: :assert_not_respond_to, + refute_same: :assert_not_same, + refute_match: :assert_no_match + }.freeze + + REFUTE_METHODS = CORRECTIONS.keys.freeze + ASSERT_NOT_METHODS = CORRECTIONS.values.freeze + + def_node_matcher :offensive?, '(send nil? #bad_method? ...)' + + def on_send(node) + return unless offensive?(node) + + message = offense_message(node.method_name) + add_offense(node, location: :selector, message: message) + end + + def autocorrect(node) + bad_method = node.method_name + good_method = convert_good_method(bad_method) + + lambda do |corrector| + corrector.replace(node.loc.selector, good_method.to_s) + end + end + + private + + def bad_method?(method_name) + if style == :assert_not + REFUTE_METHODS.include?(method_name) + else + ASSERT_NOT_METHODS.include?(method_name) + end + end + + def offense_message(method_name) + format( + MSG, + bad_method: method_name, + good_method: convert_good_method(method_name) + ) + end + + def convert_good_method(bad_method) + if style == :assert_not + CORRECTIONS.fetch(bad_method) + else + CORRECTIONS.invert.fetch(bad_method) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/relative_date_constant.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/relative_date_constant.rb new file mode 100644 index 0000000000..6beaeca876 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/relative_date_constant.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks whether constant value isn't relative date. + # Because the relative date will be evaluated only once. + # + # @example + # # bad + # class SomeClass + # EXPIRED_AT = 1.week.since + # end + # + # # good + # class SomeClass + # EXPIRES = 1.week + # + # def self.expired_at + # EXPIRES.since + # end + # end + # + # # good + # class SomeClass + # def self.expired_at + # 1.week.since + # end + # end + class RelativeDateConstant < Cop + include RangeHelp + + MSG = 'Do not assign %s to constants as it ' \ + 'will be evaluated only once.' + + def on_casgn(node) + relative_date_assignment?(node) do |method_name| + add_offense(node, message: format(MSG, method_name: method_name)) + end + end + + def on_masgn(node) + lhs, rhs = *node + + return unless rhs&.array_type? + + lhs.children.zip(rhs.children).each do |(name, value)| + next unless name.casgn_type? + + relative_date?(value) do |method_name| + add_offense(node, + location: offense_range(name, value), + message: format(MSG, method_name: method_name)) + end + end + end + + def on_or_asgn(node) + relative_date_or_assignment?(node) do |method_name| + add_offense(node, message: format(MSG, method_name: method_name)) + end + end + + def autocorrect(node) + return unless node.casgn_type? + + scope, const_name, value = *node + return unless scope.nil? + + indent = ' ' * node.loc.column + new_code = ["def self.#{const_name.downcase}", + "#{indent}#{value.source}", + 'end'].join("\n#{indent}") + ->(corrector) { corrector.replace(node.source_range, new_code) } + end + + private + + def offense_range(name, value) + range_between(name.loc.expression.begin_pos, value.loc.expression.end_pos) + end + + def_node_matcher :relative_date_assignment?, <<~PATTERN + { + (casgn _ _ (send _ ${:since :from_now :after :ago :until :before})) + (casgn _ _ ({erange irange} _ (send _ ${:since :from_now :after :ago :until :before}))) + (casgn _ _ ({erange irange} (send _ ${:since :from_now :after :ago :until :before}) _)) + } + PATTERN + + def_node_matcher :relative_date_or_assignment?, <<~PATTERN + (:or_asgn (casgn _ _) (send _ ${:since :from_now :after :ago :until :before})) + PATTERN + + def_node_matcher :relative_date?, <<~PATTERN + { + ({erange irange} _ (send _ ${:since :from_now :after :ago :until :before})) + ({erange irange} (send _ ${:since :from_now :after :ago :until :before}) _) + (send _ ${:since :from_now :after :ago :until :before}) + } + PATTERN + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/render_inline.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/render_inline.rb new file mode 100644 index 0000000000..5c8f0638be --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/render_inline.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop looks for inline rendering within controller actions. + # + # @example + # # bad + # class ProductsController < ApplicationController + # def index + # render inline: "<% products.each do |p| %>

    <%= p.name %>

    <% end %>", type: :erb + # end + # end + # + # # good + # # app/views/products/index.html.erb + # # <% products.each do |p| %> + # #

    <%= p.name %>

    + # # <% end %> + # + # class ProductsController < ApplicationController + # def index + # end + # end + # + class RenderInline < Cop + MSG = 'Prefer using a template over inline rendering.' + + def_node_matcher :render_with_inline_option?, <<~PATTERN + (send nil? :render (hash <(pair {(sym :inline) (str "inline")} _) ...>)) + PATTERN + + def on_send(node) + add_offense(node) if render_with_inline_option?(node) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/render_plain_text.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/render_plain_text.rb new file mode 100644 index 0000000000..fb1bb9ef41 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/render_plain_text.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop identifies places where `render text:` can be + # replaced with `render plain:`. + # + # @example + # # bad - explicit MIME type to `text/plain` + # render text: 'Ruby!', content_type: 'text/plain' + # + # # good - short and precise + # render plain: 'Ruby!' + # + # # good - explicit MIME type not to `text/plain` + # render text: 'Ruby!', content_type: 'text/html' + # + # @example ContentTypeCompatibility: true (default) + # # good - sets MIME type to `text/html` + # render text: 'Ruby!' + # + # @example ContentTypeCompatibility: false + # # bad - sets MIME type to `text/html` + # render text: 'Ruby!' + # + class RenderPlainText < Cop + MSG = 'Prefer `render plain:` over `render text:`.' + + def_node_matcher :render_plain_text?, <<~PATTERN + (send nil? :render $(hash <$(pair (sym :text) $_) ...>)) + PATTERN + + def on_send(node) + render_plain_text?(node) do |options_node, _option_node, _option_value| + content_type_node = find_content_type(options_node) + add_offense(node) if compatible_content_type?(content_type_node) + end + end + + def autocorrect(node) + render_plain_text?(node) do |options_node, option_node, option_value| + content_type_node = find_content_type(options_node) + rest_options = options_node.pairs - [option_node, content_type_node].compact + + lambda do |corrector| + corrector.replace( + node, + replacement(rest_options, option_value) + ) + end + end + end + + private + + def find_content_type(node) + node.pairs.find { |p| p.key.value.to_sym == :content_type } + end + + def compatible_content_type?(node) + (node && node.value.value == 'text/plain') || + (!node && !cop_config['ContentTypeCompatibility']) + end + + def replacement(rest_options, option_value) + if rest_options.any? + "render plain: #{option_value.source}, #{rest_options.map(&:source).join(', ')}" + else + "render plain: #{option_value.source}" + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/request_referer.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/request_referer.rb new file mode 100644 index 0000000000..f6413cce45 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/request_referer.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for consistent uses of `request.referer` or + # `request.referrer`, depending on the cop's configuration. + # + # @example EnforcedStyle: referer (default) + # # bad + # request.referrer + # + # # good + # request.referer + # + # @example EnforcedStyle: referrer + # # bad + # request.referer + # + # # good + # request.referrer + class RequestReferer < Cop + include ConfigurableEnforcedStyle + + MSG = 'Use `request.%s` instead of ' \ + '`request.%s`.' + + def_node_matcher :referer?, <<~PATTERN + (send (send nil? :request) {:referer :referrer}) + PATTERN + + def on_send(node) + referer?(node) do + return unless node.method?(wrong_method_name) + + add_offense(node.source_range, location: node.source_range) + end + end + + def autocorrect(node) + ->(corrector) { corrector.replace(node, "request.#{style}") } + end + + private + + def message(_node) + format(MSG, prefer: style, current: wrong_method_name) + end + + def wrong_method_name + style == :referer ? :referrer : :referer + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/reversible_migration.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/reversible_migration.rb new file mode 100644 index 0000000000..948f65da75 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/reversible_migration.rb @@ -0,0 +1,368 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks whether the change method of the migration file is + # reversible. + # + # @example + # # bad + # def change + # change_table :users do |t| + # t.remove :name + # end + # end + # + # # good + # def change + # create_table :users do |t| + # t.string :name + # end + # end + # + # # good + # def change + # reversible do |dir| + # change_table :users do |t| + # dir.up do + # t.column :name, :string + # end + # + # dir.down do + # t.remove :name + # end + # end + # end + # end + # + # @example + # # drop_table + # + # # bad + # def change + # drop_table :users + # end + # + # # good + # def change + # drop_table :users do |t| + # t.string :name + # end + # end + # + # @example + # # change_column_default + # + # # bad + # def change + # change_column_default(:suppliers, :qualification, 'new') + # end + # + # # good + # def change + # change_column_default(:posts, :state, from: nil, to: "draft") + # end + # + # @example + # # remove_column + # + # # bad + # def change + # remove_column(:suppliers, :qualification) + # end + # + # # good + # def change + # remove_column(:suppliers, :qualification, :string) + # end + # + # @example + # # remove_foreign_key + # + # # bad + # def change + # remove_foreign_key :accounts, column: :owner_id + # end + # + # # good + # def change + # remove_foreign_key :accounts, :branches + # end + # + # # good + # def change + # remove_foreign_key :accounts, to_table: :branches + # end + # + # @example + # # change_table + # + # # bad + # def change + # change_table :users do |t| + # t.remove :name + # t.change_default :authorized, 1 + # t.change :price, :string + # end + # end + # + # # good + # def change + # change_table :users do |t| + # t.string :name + # end + # end + # + # # good + # def change + # reversible do |dir| + # change_table :users do |t| + # dir.up do + # t.change :price, :string + # end + # + # dir.down do + # t.change :price, :integer + # end + # end + # end + # end + # + # @example + # # remove_columns + # + # # bad + # def change + # remove_columns :users, :name, :email + # end + # + # # good + # def change + # reversible do |dir| + # dir.up do + # remove_columns :users, :name, :email + # end + # + # dir.down do + # add_column :users, :name, :string + # add_column :users, :email, :string + # end + # end + # end + # + # # good (Rails >= 6.1, see https://github.com/rails/rails/pull/36589) + # def change + # remove_columns :users, :name, :email, type: :string + # end + # + # @example + # # remove_index + # + # # bad + # def change + # remove_index :users, name: :index_users_on_email + # end + # + # # good + # def change + # remove_index :users, :email + # end + # + # # good + # def change + # remove_index :users, column: :email + # end + # + # @see https://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html + class ReversibleMigration < Cop + MSG = '%s is not reversible.' + + def_node_matcher :irreversible_schema_statement_call, <<~PATTERN + (send nil? ${:execute :remove_belongs_to} ...) + PATTERN + + def_node_matcher :drop_table_call, <<~PATTERN + (send nil? :drop_table ...) + PATTERN + + def_node_matcher :remove_column_call, <<~PATTERN + (send nil? :remove_column $...) + PATTERN + + def_node_matcher :remove_foreign_key_call, <<~PATTERN + (send nil? :remove_foreign_key _ $_) + PATTERN + + def_node_matcher :change_table_call, <<~PATTERN + (send nil? :change_table $_ ...) + PATTERN + + def_node_matcher :remove_columns_call, <<~PATTERN + (send nil? :remove_columns ... $_) + PATTERN + + def_node_matcher :remove_index_call, <<~PATTERN + (send nil? :remove_index _ $_) + PATTERN + + def on_send(node) + return unless within_change_method?(node) + return if within_reversible_or_up_only_block?(node) + + check_irreversible_schema_statement_node(node) + check_drop_table_node(node) + check_reversible_hash_node(node) + check_remove_column_node(node) + check_remove_foreign_key_node(node) + check_remove_columns_node(node) + check_remove_index_node(node) + end + + def on_block(node) + return unless within_change_method?(node) + return if within_reversible_or_up_only_block?(node) + return if node.body.nil? + + check_change_table_node(node.send_node, node.body) + end + + private + + def check_irreversible_schema_statement_node(node) + irreversible_schema_statement_call(node) do |method_name| + add_offense(node, message: format(MSG, action: method_name)) + end + end + + def check_drop_table_node(node) + drop_table_call(node) do + unless node.parent.block_type? + add_offense( + node, + message: format(MSG, action: 'drop_table(without block)') + ) + end + end + end + + def check_reversible_hash_node(node) + return if reversible_change_table_call?(node) + + add_offense( + node, + message: format( + MSG, action: "#{node.method_name}(without :from and :to)" + ) + ) + end + + def check_remove_column_node(node) + remove_column_call(node) do |args| + if args.to_a.size < 3 + add_offense( + node, + message: format(MSG, action: 'remove_column(without type)') + ) + end + end + end + + def check_remove_foreign_key_node(node) + remove_foreign_key_call(node) do |arg| + if arg.hash_type? && !all_hash_key?(arg, :to_table) + add_offense( + node, + message: format(MSG, + action: 'remove_foreign_key(without table)') + ) + end + end + end + + def check_change_table_node(node, block) + change_table_call(node) do |arg| + if block.send_type? + check_change_table_offense(arg, block) + else + block.each_child_node(:send) do |child_node| + check_change_table_offense(arg, child_node) + end + end + end + end + + def check_remove_columns_node(node) + remove_columns_call(node) do |args| + unless all_hash_key?(args, :type) && target_rails_version >= 6.1 + action = target_rails_version >= 6.1 ? 'remove_columns(without type)' : 'remove_columns' + + add_offense( + node, + message: format(MSG, action: action) + ) + end + end + end + + def check_remove_index_node(node) + remove_index_call(node) do |args| + if args.hash_type? && !all_hash_key?(args, :column) + add_offense( + node, + message: format(MSG, action: 'remove_index(without column)') + ) + end + end + end + + def check_change_table_offense(receiver, node) + method_name = node.method_name + return if receiver != node.receiver && + reversible_change_table_call?(node) + + add_offense( + node, + message: format(MSG, action: "change_table(with #{method_name})") + ) + end + + def reversible_change_table_call?(node) + case node.method_name + when :change, :remove + false + when :change_default, :change_column_default, :change_table_comment, + :change_column_comment + all_hash_key?(node.arguments.last, :from, :to) + else + true + end + end + + def within_change_method?(node) + node.each_ancestor(:def).any? do |ancestor| + ancestor.method?(:change) + end + end + + def within_reversible_or_up_only_block?(node) + node.each_ancestor(:block).any? do |ancestor| + ancestor.block_type? && + ancestor.send_node.method?(:reversible) || + ancestor.send_node.method?(:up_only) + end + end + + def all_hash_key?(args, *keys) + return false unless args&.hash_type? + + hash_keys = args.keys.map do |key| + key.children.first.to_sym + end + + (hash_keys & keys).sort == keys + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/safe_navigation.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/safe_navigation.rb new file mode 100644 index 0000000000..45f8e211bb --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/safe_navigation.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop converts usages of `try!` to `&.`. It can also be configured + # to convert `try`. It will convert code to use safe navigation. + # + # @example ConvertTry: false (default) + # # bad + # foo.try!(:bar) + # foo.try!(:bar, baz) + # foo.try!(:bar) { |e| e.baz } + # + # foo.try!(:[], 0) + # + # # good + # foo.try(:bar) + # foo.try(:bar, baz) + # foo.try(:bar) { |e| e.baz } + # + # foo&.bar + # foo&.bar(baz) + # foo&.bar { |e| e.baz } + # + # @example ConvertTry: true + # # bad + # foo.try!(:bar) + # foo.try!(:bar, baz) + # foo.try!(:bar) { |e| e.baz } + # foo.try(:bar) + # foo.try(:bar, baz) + # foo.try(:bar) { |e| e.baz } + # + # # good + # foo&.bar + # foo&.bar(baz) + # foo&.bar { |e| e.baz } + class SafeNavigation < Cop + include RangeHelp + + MSG = 'Use safe navigation (`&.`) instead of `%s`.' + + def_node_matcher :try_call, <<~PATTERN + (send !nil? ${:try :try!} $_ ...) + PATTERN + + def on_send(node) + try_call(node) do |try_method, dispatch| + return if try_method == :try && !cop_config['ConvertTry'] + return unless dispatch.sym_type? && dispatch.value.match?(/\w+[=!?]?/) + + add_offense(node, message: format(MSG, try: try_method)) + end + end + + def autocorrect(node) + method_node, *params = *node.arguments + method = method_node.source[1..-1] + + range = range_between(node.loc.dot.begin_pos, + node.loc.expression.end_pos) + + lambda do |corrector| + corrector.replace(range, replacement(method, params)) + end + end + + private + + def replacement(method, params) + new_params = params.map(&:source).join(', ') + + if method.end_with?('=') + "&.#{method[0...-1]} = #{new_params}" + elsif params.empty? + "&.#{method}" + else + "&.#{method}(#{new_params})" + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/safe_navigation_with_blank.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/safe_navigation_with_blank.rb new file mode 100644 index 0000000000..ab9d3e281e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/safe_navigation_with_blank.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks to make sure safe navigation isn't used with `blank?` in + # a conditional. + # + # While the safe navigation operator is generally a good idea, when + # checking `foo&.blank?` in a conditional, `foo` being `nil` will actually + # do the opposite of what the author intends. + # + # @example + # # bad + # do_something if foo&.blank? + # do_something unless foo&.blank? + # + # # good + # do_something if foo.blank? + # do_something unless foo.blank? + # + class SafeNavigationWithBlank < Cop + MSG = + 'Avoid calling `blank?` with the safe navigation operator ' \ + 'in conditionals.' + + def_node_matcher :safe_navigation_blank_in_conditional?, <<~PATTERN + (if $(csend ... :blank?) ...) + PATTERN + + def on_if(node) + return unless safe_navigation_blank_in_conditional?(node) + + add_offense(node) + end + + def autocorrect(node) + lambda do |corrector| + corrector.replace( + safe_navigation_blank_in_conditional?(node).location.dot, + '.' + ) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/save_bang.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/save_bang.rb new file mode 100644 index 0000000000..ee6066642f --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/save_bang.rb @@ -0,0 +1,338 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop identifies possible cases where Active Record save! or related + # should be used instead of save because the model might have failed to + # save and an exception is better than unhandled failure. + # + # This will allow: + # + # * update or save calls, assigned to a variable, + # or used as a condition in an if/unless/case statement. + # * create calls, assigned to a variable that then has a + # call to `persisted?`, or whose return value is checked by + # `persisted?` immediately + # * calls if the result is explicitly returned from methods and blocks, + # or provided as arguments. + # * calls whose signature doesn't look like an ActiveRecord + # persistence method. + # + # By default it will also allow implicit returns from methods and blocks. + # that behavior can be turned off with `AllowImplicitReturn: false`. + # + # You can permit receivers that are giving false positives with + # `AllowedReceivers: []` + # + # @example + # + # # bad + # user.save + # user.update(name: 'Joe') + # user.find_or_create_by(name: 'Joe') + # user.destroy + # + # # good + # unless user.save + # # ... + # end + # user.save! + # user.update!(name: 'Joe') + # user.find_or_create_by!(name: 'Joe') + # user.destroy! + # + # user = User.find_or_create_by(name: 'Joe') + # unless user.persisted? + # # ... + # end + # + # def save_user + # return user.save + # end + # + # @example AllowImplicitReturn: true (default) + # + # # good + # users.each { |u| u.save } + # + # def save_user + # user.save + # end + # + # @example AllowImplicitReturn: false + # + # # bad + # users.each { |u| u.save } + # def save_user + # user.save + # end + # + # # good + # users.each { |u| u.save! } + # + # def save_user + # user.save! + # end + # + # def save_user + # return user.save + # end + # + # @example AllowedReceivers: ['merchant.customers', 'Service::Mailer'] + # + # # bad + # merchant.create + # customers.builder.save + # Mailer.create + # + # module Service::Mailer + # self.create + # end + # + # # good + # merchant.customers.create + # MerchantService.merchant.customers.destroy + # Service::Mailer.update(message: 'Message') + # ::Service::Mailer.update + # Services::Service::Mailer.update(message: 'Message') + # Service::Mailer::update + # + class SaveBang < Cop + include NegativeConditional + + MSG = 'Use `%s` instead of `%s` if the return ' \ + 'value is not checked.' + CREATE_MSG = (MSG + + ' Or check `persisted?` on model returned from ' \ + '`%s`.').freeze + CREATE_CONDITIONAL_MSG = '`%s` returns a model which is ' \ + 'always truthy.' + + CREATE_PERSIST_METHODS = %i[create create_or_find_by + first_or_create find_or_create_by].freeze + MODIFY_PERSIST_METHODS = %i[save + update update_attributes destroy].freeze + PERSIST_METHODS = (CREATE_PERSIST_METHODS + + MODIFY_PERSIST_METHODS).freeze + + def join_force?(force_class) + force_class == VariableForce + end + + def after_leaving_scope(scope, _variable_table) + scope.variables.each_value do |variable| + variable.assignments.each do |assignment| + check_assignment(assignment) + end + end + end + + def check_assignment(assignment) + node = right_assignment_node(assignment) + + return unless node&.send_type? + return unless persist_method?(node, CREATE_PERSIST_METHODS) + return if persisted_referenced?(assignment) + + add_offense_for_node(node, CREATE_MSG) + end + + # rubocop:disable Metrics/CyclomaticComplexity + def on_send(node) + return unless persist_method?(node) + return if return_value_assigned?(node) + return if implicit_return?(node) + return if check_used_in_condition_or_compound_boolean(node) + return if argument?(node) + return if explicit_return?(node) + return if checked_immediately?(node) + + add_offense_for_node(node) + end + # rubocop:enable Metrics/CyclomaticComplexity + alias on_csend on_send + + def autocorrect(node) + save_loc = node.loc.selector + new_method = "#{node.method_name}!" + + ->(corrector) { corrector.replace(save_loc, new_method) } + end + + private + + def add_offense_for_node(node, msg = MSG) + name = node.method_name + full_message = format(msg, prefer: "#{name}!", current: name.to_s) + + add_offense(node, location: :selector, message: full_message) + end + + def right_assignment_node(assignment) + node = assignment.node.child_nodes.first + + return node unless node&.block_type? + + node.send_node + end + + def persisted_referenced?(assignment) + return unless assignment.referenced? + + assignment.variable.references.any? do |reference| + call_to_persisted?(reference.node.parent) + end + end + + def call_to_persisted?(node) + node.send_type? && node.method?(:persisted?) + end + + def assignable_node(node) + assignable = node.block_node || node + while node + node = hash_parent(node) || array_parent(node) + assignable = node if node + end + assignable + end + + def hash_parent(node) + pair = node.parent + return unless pair&.pair_type? + + hash = pair.parent + return unless hash&.hash_type? + + hash + end + + def array_parent(node) + array = node.parent + return unless array&.array_type? + + array + end + + def check_used_in_condition_or_compound_boolean(node) + return false unless in_condition_or_compound_boolean?(node) + + add_offense_for_node(node, CREATE_CONDITIONAL_MSG) unless MODIFY_PERSIST_METHODS.include?(node.method_name) + + true + end + + def in_condition_or_compound_boolean?(node) + node = node.block_node || node + parent = node.parent + return false unless parent + + operator_or_single_negative?(parent) || + (conditional?(parent) && node == parent.condition) + end + + def operator_or_single_negative?(node) + node.or_type? || node.and_type? || single_negative?(node) + end + + def conditional?(parent) + parent.if_type? || parent.case_type? + end + + def checked_immediately?(node) + node.parent && call_to_persisted?(node.parent) + end + + def allowed_receiver?(node) + return false unless node.receiver + return true if node.receiver.const_name == 'ENV' + return false unless cop_config['AllowedReceivers'] + + cop_config['AllowedReceivers'].any? do |allowed_receiver| + receiver_chain_matches?(node, allowed_receiver) + end + end + + def receiver_chain_matches?(node, allowed_receiver) + allowed_receiver.split('.').reverse.all? do |receiver_part| + node = node.receiver + return false unless node + + if node.variable? + node.node_parts.first == receiver_part.to_sym + elsif node.send_type? + node.method?(receiver_part.to_sym) + elsif node.const_type? + const_matches?(node.const_name, receiver_part) + end + end + end + + # Const == Const + # ::Const == ::Const + # ::Const == Const + # Const == ::Const + # NameSpace::Const == Const + # NameSpace::Const == NameSpace::Const + # NameSpace::Const != ::Const + # Const != NameSpace::Const + def const_matches?(const, allowed_const) + parts = allowed_const.split('::').reverse.zip( + const.split('::').reverse + ) + parts.all? do |(allowed_part, const_part)| + allowed_part == const_part.to_s + end + end + + def implicit_return?(node) + return false unless cop_config['AllowImplicitReturn'] + + node = assignable_node(node) + method, sibling_index = find_method_with_sibling_index(node.parent) + return unless method && (method.def_type? || method.block_type?) + + method.children.size == node.sibling_index + sibling_index + end + + def find_method_with_sibling_index(node, sibling_index = 1) + return node, sibling_index unless node&.or_type? + + sibling_index += 1 + + find_method_with_sibling_index(node.parent, sibling_index) + end + + def argument?(node) + assignable_node(node).argument? + end + + def explicit_return?(node) + ret = assignable_node(node).parent + ret && (ret.return_type? || ret.next_type?) + end + + def return_value_assigned?(node) + assignment = assignable_node(node).parent + assignment&.lvasgn_type? + end + + def persist_method?(node, methods = PERSIST_METHODS) + methods.include?(node.method_name) && + expected_signature?(node) && + !allowed_receiver?(node) + end + + # Check argument signature as no arguments or one hash + def expected_signature?(node) + !node.arguments? || + (node.arguments.one? && + node.method_name != :destroy && + (node.first_argument.hash_type? || + !node.first_argument.literal?)) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/scope_args.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/scope_args.rb new file mode 100644 index 0000000000..8155eecdc0 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/scope_args.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for scope calls where it was passed + # a method (usually a scope) instead of a lambda/proc. + # + # @example + # + # # bad + # scope :something, where(something: true) + # + # # good + # scope :something, -> { where(something: true) } + class ScopeArgs < Cop + MSG = 'Use `lambda`/`proc` instead of a plain method call.' + + def_node_matcher :scope?, '(send nil? :scope _ $send)' + + def on_send(node) + scope?(node) do |second_arg| + add_offense(second_arg) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/short_i18n.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/short_i18n.rb new file mode 100644 index 0000000000..ff22d850e2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/short_i18n.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop enforces that short forms of `I18n` methods are used: + # `t` instead of `translate` and `l` instead of `localize`. + # + # This cop has two different enforcement modes. When the EnforcedStyle + # is conservative (the default) then only `I18n.translate` and `I18n.localize` + # calls are added as offenses. + # + # When the EnforcedStyle is aggressive then all `translate` and `localize` calls + # without a receiver are added as offenses. + # + # @example + # # bad + # I18n.translate :key + # I18n.localize Time.now + # + # # good + # I18n.t :key + # I18n.l Time.now + # + # @example EnforcedStyle: conservative (default) + # # good + # translate :key + # localize Time.now + # t :key + # l Time.now + # + # @example EnforcedStyle: aggressive + # # bad + # translate :key + # localize Time.now + # + # # good + # t :key + # l Time.now + # + class ShortI18n < Cop + include ConfigurableEnforcedStyle + + MSG = 'Use `%s` instead of `%s`.' + + PREFERRED_METHODS = { + translate: :t, + localize: :l + }.freeze + + def_node_matcher :long_i18n?, <<~PATTERN + (send {nil? (const nil? :I18n)} ${:translate :localize} ...) + PATTERN + + def on_send(node) + return if style == :conservative && !node.receiver + + long_i18n?(node) do |method_name| + good_method = PREFERRED_METHODS[method_name] + message = format(MSG, good_method: good_method, bad_method: method_name) + + add_offense(node, location: :selector, message: message) + end + end + + def autocorrect(node) + long_i18n?(node) do |method_name| + lambda do |corrector| + corrector.replace(node.loc.selector, PREFERRED_METHODS[method_name]) + end + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/skips_model_validations.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/skips_model_validations.rb new file mode 100644 index 0000000000..d75f87ace7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/skips_model_validations.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for the use of methods which skip + # validations which are listed in + # https://guides.rubyonrails.org/active_record_validations.html#skipping-validations + # + # Methods may be ignored from this rule by configuring a `Whitelist`. + # + # @example + # # bad + # Article.first.decrement!(:view_count) + # DiscussionBoard.decrement_counter(:post_count, 5) + # Article.first.increment!(:view_count) + # DiscussionBoard.increment_counter(:post_count, 5) + # person.toggle :active + # product.touch + # Billing.update_all("category = 'authorized', author = 'David'") + # user.update_attribute(:website, 'example.com') + # user.update_columns(last_request_at: Time.current) + # Post.update_counters 5, comment_count: -1, action_count: 1 + # + # # good + # user.update(website: 'example.com') + # FileUtils.touch('file') + # + # @example Whitelist: ["touch"] + # # bad + # DiscussionBoard.decrement_counter(:post_count, 5) + # DiscussionBoard.increment_counter(:post_count, 5) + # person.toggle :active + # + # # good + # user.touch + # + class SkipsModelValidations < Cop + MSG = 'Avoid using `%s` because it skips validations.' + + METHODS_WITH_ARGUMENTS = %w[decrement! + decrement_counter + increment! + increment_counter + insert + insert! + insert_all + insert_all! + toggle! + update_all + update_attribute + update_column + update_columns + update_counters + upsert + upsert_all].freeze + + def_node_matcher :good_touch?, <<~PATTERN + { + (send (const nil? :FileUtils) :touch ...) + (send _ :touch {true false}) + } + PATTERN + + def_node_matcher :good_insert?, <<~PATTERN + (send _ {:insert :insert!} _ { + !(hash ...) + (hash <(pair (sym !{:returning :unique_by}) _) ...>) + } ...) + PATTERN + + def on_send(node) + return if allowed_methods.include?(node.method_name.to_s) + return unless forbidden_methods.include?(node.method_name.to_s) + return if allowed_method?(node) + return if good_touch?(node) + return if good_insert?(node) + + add_offense(node, location: :selector) + end + alias on_csend on_send + + def initialize(*) + super + @displayed_allowed_warning = false + @displayed_forbidden_warning = false + end + + private + + def message(node) + format(MSG, method: node.method_name) + end + + def allowed_method?(node) + METHODS_WITH_ARGUMENTS.include?(node.method_name.to_s) && + !node.arguments? + end + + def forbidden_methods + obsolete_result = cop_config['Blacklist'] + if obsolete_result + warn '`Blacklist` has been renamed to `ForbiddenMethods`.' unless @displayed_forbidden_warning + @displayed_forbidden_warning = true + return obsolete_result + end + + cop_config['ForbiddenMethods'] || [] + end + + def allowed_methods + obsolete_result = cop_config['Whitelist'] + if obsolete_result + warn '`Whitelist` has been renamed to `AllowedMethods`.' unless @displayed_allowed_warning + @displayed_allowed_warning = true + + return obsolete_result + end + + cop_config['AllowedMethods'] || [] + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/squished_sql_heredocs.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/squished_sql_heredocs.rb new file mode 100644 index 0000000000..497744076c --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/squished_sql_heredocs.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # + # Checks SQL heredocs to use `.squish`. + # + # @example + # # bad + # <<-SQL + # SELECT * FROM posts; + # SQL + # + # <<-SQL + # SELECT * FROM posts + # WHERE id = 1 + # SQL + # + # execute(<<~SQL, "Post Load") + # SELECT * FROM posts + # WHERE post_id = 1 + # SQL + # + # # good + # <<-SQL.squish + # SELECT * FROM posts; + # SQL + # + # <<~SQL.squish + # SELECT * FROM table + # WHERE id = 1 + # SQL + # + # execute(<<~SQL.squish, "Post Load") + # SELECT * FROM posts + # WHERE post_id = 1 + # SQL + # + class SquishedSQLHeredocs < Cop + include Heredoc + + SQL = 'SQL' + SQUISH = '.squish' + MSG = 'Use `%s` instead of `%s`.' + + def on_heredoc(node) + return unless offense_detected?(node) + + add_offense(node) + end + + def autocorrect(node) + lambda do |corrector| + corrector.insert_after(node, SQUISH) + end + end + + private + + def offense_detected?(node) + sql_heredoc?(node) && !using_squish?(node) + end + + def sql_heredoc?(node) + delimiter_string(node) == SQL + end + + def using_squish?(node) + node.parent&.send_type? && node.parent&.method?(:squish) + end + + def message(node) + format( + MSG, + expect: "#{node.source}#{SQUISH}", + current: node.source + ) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/time_zone.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/time_zone.rb new file mode 100644 index 0000000000..9591676961 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/time_zone.rb @@ -0,0 +1,247 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for the use of Time methods without zone. + # + # Built on top of Ruby on Rails style guide (https://rails.rubystyle.guide#time) + # and the article http://danilenko.org/2012/7/6/rails_timezones/ + # + # Two styles are supported for this cop. When EnforcedStyle is 'strict' + # then only use of Time.zone is allowed. + # + # When EnforcedStyle is 'flexible' then it's also allowed + # to use Time.in_time_zone. + # + # @example EnforcedStyle: strict + # # `strict` means that `Time` should be used with `zone`. + # + # # bad + # Time.now + # Time.parse('2015-03-02 19:05:37') + # + # # bad + # Time.current + # Time.at(timestamp).in_time_zone + # + # # good + # Time.zone.now + # Time.zone.parse('2015-03-02 19:05:37') + # + # @example EnforcedStyle: flexible (default) + # # `flexible` allows usage of `in_time_zone` instead of `zone`. + # + # # bad + # Time.now + # Time.parse('2015-03-02 19:05:37') + # + # # good + # Time.zone.now + # Time.zone.parse('2015-03-02 19:05:37') + # + # # good + # Time.current + # Time.at(timestamp).in_time_zone + class TimeZone < Cop + include ConfigurableEnforcedStyle + + MSG = 'Do not use `%s` without zone. Use `%s` ' \ + 'instead.' + + MSG_ACCEPTABLE = 'Do not use `%s` without zone. ' \ + 'Use one of %s instead.' + + MSG_LOCALTIME = 'Do not use `Time.localtime` without ' \ + 'offset or zone.' + + GOOD_METHODS = %i[zone zone_default find_zone find_zone!].freeze + + DANGEROUS_METHODS = %i[now local new parse at current].freeze + + ACCEPTED_METHODS = %i[in_time_zone utc getlocal xmlschema iso8601 + jisx0301 rfc3339 httpdate to_i to_f].freeze + + def on_const(node) + mod, klass = *node + # we should only check core classes + # (`Time` or `::Time`) + return unless (mod.nil? || mod.cbase_type?) && method_send?(node) + + check_time_node(klass, node.parent) if klass == :Time + end + + def autocorrect(node) + lambda do |corrector| + # add `.zone`: `Time.at` => `Time.zone.at` + corrector.insert_after(node.children[0].source_range, '.zone') + + case node.method_name + when :current + # replace `Time.zone.current` => `Time.zone.now` + corrector.replace(node.loc.selector, 'now') + when :new + autocorrect_time_new(node, corrector) + end + + # prefer `Time` over `DateTime` class + corrector.replace(node.children.first.source_range, 'Time') if strict? + remove_redundant_in_time_zone(corrector, node) + end + end + + private + + def autocorrect_time_new(node, corrector) + if node.arguments? + corrector.replace(node.loc.selector, 'local') + else + corrector.replace(node.loc.selector, 'now') + end + end + + # remove redundant `.in_time_zone` from `Time.zone.now.in_time_zone` + def remove_redundant_in_time_zone(corrector, node) + time_methods_called = extract_method_chain(node) + return unless time_methods_called.include?(:in_time_zone) || + time_methods_called.include?(:zone) + + while node&.send_type? + if node.children.last == :in_time_zone + in_time_zone_with_dot = + node.loc.selector.adjust(begin_pos: -1) + corrector.remove(in_time_zone_with_dot) + end + node = node.parent + end + end + + def check_time_node(klass, node) + chain = extract_method_chain(node) + return if not_danger_chain?(chain) + + return check_localtime(node) if need_check_localtime?(chain) + + method_name = (chain & DANGEROUS_METHODS).join('.') + + return if offset_provided?(node) + + message = build_message(klass, method_name, node) + + add_offense(node, location: :selector, message: message) + end + + def build_message(klass, method_name, node) + if flexible? + format( + MSG_ACCEPTABLE, + current: "#{klass}.#{method_name}", + prefer: acceptable_methods(klass, method_name, node).join(', ') + ) + else + safe_method_name = safe_method(method_name, node) + format(MSG, + current: "#{klass}.#{method_name}", + prefer: "Time.zone.#{safe_method_name}") + end + end + + def extract_method_chain(node) + chain = [] + while !node.nil? && node.send_type? + chain << node.method_name if method_from_time_class?(node) + node = node.parent + end + chain + end + + # Only add the method to the chain if the method being + # called is part of the time class. + def method_from_time_class?(node) + receiver, method_name, *_args = *node + if (receiver.is_a? RuboCop::AST::Node) && !receiver.cbase_type? + method_from_time_class?(receiver) + else + method_name == :Time + end + end + + # checks that parent node of send_type + # and receiver is the given node + def method_send?(node) + return false unless node.parent&.send_type? + + node.parent.receiver == node + end + + def safe_method(method_name, node) + if %w[new current].include?(method_name) + node.arguments? ? 'local' : 'now' + else + method_name + end + end + + def check_localtime(node) + selector_node = node + + while node&.send_type? + break if node.method?(:localtime) + + node = node.parent + end + + return if node.arguments? + + add_offense(selector_node, + location: :selector, message: MSG_LOCALTIME) + end + + def not_danger_chain?(chain) + (chain & DANGEROUS_METHODS).empty? || !(chain & good_methods).empty? + end + + def need_check_localtime?(chain) + flexible? && chain.include?(:localtime) + end + + def flexible? + style == :flexible + end + + def strict? + style == :strict + end + + def good_methods + if strict? + GOOD_METHODS + else + GOOD_METHODS + [:current] + ACCEPTED_METHODS + end + end + + def acceptable_methods(klass, method_name, node) + acceptable = [ + "`Time.zone.#{safe_method(method_name, node)}`", + "`#{klass}.current`" + ] + + ACCEPTED_METHODS.each do |am| + acceptable << "`#{klass}.#{method_name}.#{am}`" + end + + acceptable + end + + # Time.new can be called with a time zone offset + # When it is, that should be considered safe + # Example: + # Time.new(1988, 3, 15, 3, 0, 0, "-05:00") + def offset_provided?(node) + node.arguments.size >= 7 + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/uniq_before_pluck.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/uniq_before_pluck.rb new file mode 100644 index 0000000000..c74d3f6d2d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/uniq_before_pluck.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # Prefer the use of distinct, before pluck instead of after. + # + # The use of distinct before pluck is preferred because it executes within + # the database. + # + # This cop has two different enforcement modes. When the EnforcedStyle + # is conservative (the default) then only calls to pluck on a constant + # (i.e. a model class) before distinct are added as offenses. + # + # When the EnforcedStyle is aggressive then all calls to pluck before + # distinct are added as offenses. This may lead to false positives + # as the cop cannot distinguish between calls to pluck on an + # ActiveRecord::Relation vs a call to pluck on an + # ActiveRecord::Associations::CollectionProxy. + # + # This cop is unsafe because the behavior may change depending on the + # database collation. + # Autocorrect is disabled by default for this cop since it may generate + # false positives. + # + # @example EnforcedStyle: conservative (default) + # # bad + # Model.pluck(:id).uniq + # + # # good + # Model.distinct.pluck(:id) + # + # @example EnforcedStyle: aggressive + # # bad + # # this will return a Relation that pluck is called on + # Model.where(cond: true).pluck(:id).uniq + # + # # bad + # # an association on an instance will return a CollectionProxy + # instance.assoc.pluck(:id).uniq + # + # # bad + # Model.pluck(:id).uniq + # + # # good + # Model.distinct.pluck(:id) + # + class UniqBeforePluck < RuboCop::Cop::Cop + include ConfigurableEnforcedStyle + include RangeHelp + + MSG = 'Use `distinct` before `pluck`.' + NEWLINE = "\n" + PATTERN = '[!^block (send (send %s :pluck ...) ' \ + '${:uniq :distinct} ...)]' + + def_node_matcher :conservative_node_match, + format(PATTERN, type: 'const') + + def_node_matcher :aggressive_node_match, + format(PATTERN, type: '_') + + def on_send(node) + method = if style == :conservative + conservative_node_match(node) + else + aggressive_node_match(node) + end + + return unless method + + add_offense(node, location: :selector) + end + + def autocorrect(node) + lambda do |corrector| + method = node.method_name + + corrector.remove(dot_method_with_whitespace(method, node)) + corrector.insert_before(node.receiver.loc.dot.begin, '.distinct') + end + end + + private + + def style_parameter_name + 'EnforcedStyle' + end + + def dot_method_with_whitespace(method, node) + range_between(dot_method_begin_pos(method, node), + node.loc.selector.end_pos) + end + + def dot_method_begin_pos(method, node) + lines = node.source.split(NEWLINE) + + if lines.last.strip == ".#{method}" + node.source.rindex(NEWLINE) + else + node.loc.dot.begin_pos + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/unique_validation_without_index.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/unique_validation_without_index.rb new file mode 100644 index 0000000000..06cdd8d0f3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/unique_validation_without_index.rb @@ -0,0 +1,165 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # When you define a uniqueness validation in Active Record model, + # you also should add a unique index for the column. There are two reasons + # First, duplicated records may occur even if Active Record's validation + # is defined. + # Second, it will cause slow queries. The validation executes a `SELECT` + # statement with the target column when inserting/updating a record. + # If the column does not have an index and the table is large, + # the query will be heavy. + # + # Note that the cop does nothing if db/schema.rb does not exist. + # + # @example + # # bad - if the schema does not have a unique index + # validates :account, uniqueness: true + # + # # good - if the schema has a unique index + # validates :account, uniqueness: true + # + # # good - even if the schema does not have a unique index + # validates :account, length: { minimum: MIN_LENGTH } + # + class UniqueValidationWithoutIndex < Cop + include ActiveRecordHelper + + MSG = 'Uniqueness validation should be with a unique index.' + + def on_send(node) + return unless node.method?(:validates) + return unless uniqueness_part(node) + return if condition_part?(node) + return unless schema + + klass, table, names = find_schema_information(node) + return unless names + return if with_index?(klass, table, names) + + add_offense(node) + end + + private + + def find_schema_information(node) + klass = class_node(node) + return unless klass + + table = schema.table_by(name: table_name(klass)) + names = column_names(node) + + [klass, table, names] + end + + def with_index?(klass, table, names) + # Compatibility for Rails 4.2. + add_indicies = schema.add_indicies_by(table_name: table_name(klass)) + + (table.indices + add_indicies).any? do |index| + index.unique && + (index.columns.to_set == names || + include_column_names_in_expression_index?(index, names)) + end + end + + def include_column_names_in_expression_index?(index, column_names) + return false unless (expression_index = index.expression) + + column_names.all? do |column_name| + expression_index.include?(column_name) + end + end + + def column_names(node) + arg = node.first_argument + return unless arg.str_type? || arg.sym_type? + + ret = [arg.value] + names_from_scope = column_names_from_scope(node) + ret.concat(names_from_scope) if names_from_scope + + ret.map! do |name| + klass = class_node(node) + resolve_relation_into_column( + name: name.to_s, + class_node: klass, + table: schema.table_by(name: table_name(klass)) + ) + end + ret.include?(nil) ? nil : ret.to_set + end + + def column_names_from_scope(node) + uniq = uniqueness_part(node) + return unless uniq.hash_type? + + scope = find_scope(uniq) + return unless scope + + scope = unfreeze_scope(scope) + + case scope.type + when :sym, :str + [scope.value] + when :array + array_node_to_array(scope) + end + end + + def find_scope(pairs) + pairs.each_pair.find do |pair| + key = pair.key + next unless key.sym_type? && key.value == :scope + + break pair.value + end + end + + def unfreeze_scope(scope) + scope.send_type? && scope.method?(:freeze) ? scope.children.first : scope + end + + def class_node(node) + node.each_ancestor.find(&:class_type?) + end + + def uniqueness_part(node) + pairs = node.arguments.last + return unless pairs.hash_type? + + pairs.each_pair.find do |pair| + next unless pair.key.sym_type? && pair.key.value == :uniqueness + + break pair.value + end + end + + def condition_part?(node) + pairs = node.arguments.last + return unless pairs.hash_type? + + pairs.each_pair.any? do |pair| + key = pair.key + next unless key.sym_type? + + key.value == :if || key.value == :unless + end + end + + def array_node_to_array(node) + node.values.map do |elm| + case elm.type + when :str, :sym + elm.value + else + return nil + end + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/unknown_env.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/unknown_env.rb new file mode 100644 index 0000000000..bf25f84409 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/unknown_env.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks that environments called with `Rails.env` predicates + # exist. + # By default the cop allows three environments which Rails ships with: + # `development`, `test`, and `production`. + # More can be added to the `Environments` config parameter. + # + # @example + # # bad + # Rails.env.proudction? + # Rails.env == 'proudction' + # + # # good + # Rails.env.production? + # Rails.env == 'production' + class UnknownEnv < Cop + MSG = 'Unknown environment `%s`.' + MSG_SIMILAR = 'Unknown environment `%s`. ' \ + 'Did you mean `%s`?' + + def_node_matcher :rails_env?, <<~PATTERN + (send + {(const nil? :Rails) (const (cbase) :Rails)} + :env) + PATTERN + + def_node_matcher :unknown_environment_predicate?, <<~PATTERN + (send #rails_env? $#unknown_env_predicate?) + PATTERN + + def_node_matcher :unknown_environment_equal?, <<~PATTERN + { + (send #rails_env? {:== :===} $(str #unknown_env_name?)) + (send $(str #unknown_env_name?) {:== :===} #rails_env?) + } + PATTERN + + def on_send(node) + unknown_environment_predicate?(node) do |name| + add_offense(node, location: :selector, message: message(name)) + end + + unknown_environment_equal?(node) do |str_node| + name = str_node.value + add_offense(str_node, message: message(name)) + end + end + + private + + def collect_variable_like_names(_scope) + environments + end + + def message(name) + name = name.to_s.chomp('?') + + # DidYouMean::SpellChecker is not available in all versions of Ruby, + # and even on versions where it *is* available (>= 2.3), it is not + # always required correctly. So we do a feature check first. See: + # https://github.com/rubocop-hq/rubocop/issues/7979 + similar_names = if defined?(DidYouMean::SpellChecker) + spell_checker = DidYouMean::SpellChecker.new(dictionary: environments) + spell_checker.correct(name) + else + [] + end + + if similar_names.empty? + format(MSG, name: name) + else + format(MSG_SIMILAR, name: name, similar: similar_names.join(', ')) + end + end + + def unknown_env_predicate?(name) + name = name.to_s + name.end_with?('?') && + !environments.include?(name[0..-2]) + end + + def unknown_env_name?(name) + !environments.include?(name) + end + + def environments + cop_config['Environments'] + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/validation.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/validation.rb new file mode 100644 index 0000000000..0e4423fdec --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/validation.rb @@ -0,0 +1,147 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop checks for the use of old-style attribute validation macros. + # + # @example + # # bad + # validates_acceptance_of :foo + # validates_confirmation_of :foo + # validates_exclusion_of :foo + # validates_format_of :foo + # validates_inclusion_of :foo + # validates_length_of :foo + # validates_numericality_of :foo + # validates_presence_of :foo + # validates_absence_of :foo + # validates_size_of :foo + # validates_uniqueness_of :foo + # + # # good + # validates :foo, acceptance: true + # validates :foo, confirmation: true + # validates :foo, exclusion: true + # validates :foo, format: true + # validates :foo, inclusion: true + # validates :foo, length: true + # validates :foo, numericality: true + # validates :foo, presence: true + # validates :foo, absence: true + # validates :foo, size: true + # validates :foo, uniqueness: true + # + class Validation < Cop + MSG = 'Prefer the new style validations `%s` over ' \ + '`%s`.' + + TYPES = %w[ + acceptance + confirmation + exclusion + format + inclusion + length + numericality + presence + absence + size + uniqueness + ].freeze + + DENYLIST = TYPES.map { |p| "validates_#{p}_of".to_sym }.freeze + ALLOWLIST = TYPES.map { |p| "validates :column, #{p}: value" }.freeze + + def on_send(node) + return unless !node.receiver && DENYLIST.include?(node.method_name) + + add_offense(node, location: :selector) + end + + def autocorrect(node) + last_argument = node.arguments.last + return if !last_argument.literal? && !last_argument.splat_type? && + !frozen_array_argument?(last_argument) + + lambda do |corrector| + corrector.replace(node.loc.selector, 'validates') + correct_validate_type(corrector, node) + end + end + + private + + def message(node) + format(MSG, prefer: preferred_method(node.method_name), + current: node.method_name) + end + + def preferred_method(method) + ALLOWLIST[DENYLIST.index(method.to_sym)] + end + + def correct_validate_type(corrector, node) + last_argument = node.last_argument + + if last_argument.hash_type? + correct_validate_type_for_hash(corrector, node, last_argument) + elsif last_argument.array_type? + loc = last_argument.loc + + correct_validate_type_for_array(corrector, node, last_argument, loc) + elsif frozen_array_argument?(last_argument) + arguments = node.last_argument.receiver + loc = arguments.parent.loc + + correct_validate_type_for_array(corrector, node, arguments, loc) + else + range = last_argument.source_range + + corrector.insert_after(range, ", #{validate_type(node)}: true") + end + end + + def correct_validate_type_for_hash(corrector, node, arguments) + corrector.replace( + arguments.loc.expression, + "#{validate_type(node)}: #{braced_options(arguments)}" + ) + end + + def correct_validate_type_for_array(corrector, node, arguments, loc) + attributes = [] + + arguments.each_child_node do |child_node| + attributes << if arguments.percent_literal? + ":#{child_node.source}" + else + child_node.source + end + end + + corrector.replace( + loc.expression, + "#{attributes.join(', ')}, #{validate_type(node)}: true" + ) + end + + def validate_type(node) + node.method_name.to_s.split('_')[1] + end + + def frozen_array_argument?(argument) + argument.send_type? && argument.method?(:freeze) + end + + def braced_options(options) + if options.braces? + options.source + else + "{ #{options.source} }" + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/where_exists.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/where_exists.rb new file mode 100644 index 0000000000..781f58385d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/where_exists.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop enforces consistent style when using `exists?`. + # + # Two styles are supported for this cop. When EnforcedStyle is 'exists' + # then the cop enforces `exists?(...)` over `where(...).exists?`. + # + # When EnforcedStyle is 'where' then the cop enforces + # `where(...).exists?` over `exists?(...)`. + # + # @example EnforcedStyle: exists (default) + # # bad + # User.where(name: 'john').exists? + # User.where(['name = ?', 'john']).exists? + # User.where('name = ?', 'john').exists? + # user.posts.where(published: true).exists? + # + # # good + # User.exists?(name: 'john') + # User.where('length(name) > 10').exists? + # user.posts.exists?(published: true) + # + # @example EnforcedStyle: where + # # bad + # User.exists?(name: 'john') + # User.exists?(['name = ?', 'john']) + # User.exists?('name = ?', 'john') + # user.posts.exists?(published: true) + # + # # good + # User.where(name: 'john').exists? + # User.where(['name = ?', 'john']).exists? + # User.where('name = ?', 'john').exists? + # user.posts.where(published: true).exists? + # User.where('length(name) > 10').exists? + class WhereExists < Cop + include ConfigurableEnforcedStyle + + MSG = 'Prefer `%s` over `%s`.' + + def_node_matcher :where_exists_call?, <<~PATTERN + (send (send _ :where $...) :exists?) + PATTERN + + def_node_matcher :exists_with_args?, <<~PATTERN + (send _ :exists? $...) + PATTERN + + def on_send(node) + find_offenses(node) do |args| + return unless convertable_args?(args) + + range = correction_range(node) + message = format(MSG, good_method: build_good_method(args), bad_method: range.source) + add_offense(node, location: range, message: message) + end + end + + def autocorrect(node) + args = find_offenses(node) + + lambda do |corrector| + corrector.replace( + correction_range(node), + build_good_method(args) + ) + end + end + + private + + def where_style? + style == :where + end + + def exists_style? + style == :exists + end + + def find_offenses(node, &block) + if exists_style? + where_exists_call?(node, &block) + elsif where_style? + exists_with_args?(node, &block) + end + end + + def convertable_args?(args) + return false if args.empty? + + args.size > 1 || args[0].hash_type? || args[0].array_type? + end + + def correction_range(node) + if exists_style? + node.receiver.loc.selector.join(node.loc.selector) + elsif where_style? + node.loc.selector.with(end_pos: node.loc.expression.end_pos) + end + end + + def build_good_method(args) + if exists_style? + build_good_method_exists(args) + elsif where_style? + build_good_method_where(args) + end + end + + def build_good_method_exists(args) + if args.size > 1 + "exists?([#{args.map(&:source).join(', ')}])" + else + "exists?(#{args[0].source})" + end + end + + def build_good_method_where(args) + if args.size > 1 + "where(#{args.map(&:source).join(', ')}).exists?" + else + "where(#{args[0].source}).exists?" + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/where_not.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/where_not.rb new file mode 100644 index 0000000000..4c406b6f9e --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails/where_not.rb @@ -0,0 +1,108 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # This cop identifies places where manually constructed SQL + # in `where` can be replaced with `where.not(...)`. + # + # @example + # # bad + # User.where('name != ?', 'Gabe') + # User.where('name != :name', name: 'Gabe') + # User.where('name <> ?', 'Gabe') + # User.where('name <> :name', name: 'Gabe') + # User.where('name IS NOT NULL') + # User.where('name NOT IN (?)', ['john', 'jane']) + # User.where('name NOT IN (:names)', names: ['john', 'jane']) + # + # # good + # User.where.not(name: 'Gabe') + # User.where.not(name: nil) + # User.where.not(name: ['john', 'jane']) + # + class WhereNot < Cop + include RangeHelp + + MSG = 'Use `%s` instead of manually constructing negated SQL in `where`.' + + def_node_matcher :where_method_call?, <<~PATTERN + { + (send _ :where (array $str_type? $_ ?)) + (send _ :where $str_type? $_ ?) + } + PATTERN + + def on_send(node) + where_method_call?(node) do |template_node, value_node| + value_node = value_node.first + + range = offense_range(node) + + column_and_value = extract_column_and_value(template_node, value_node) + return unless column_and_value + + good_method = build_good_method(*column_and_value) + message = format(MSG, good_method: good_method) + + add_offense(node, location: range, message: message) + end + end + + def autocorrect(node) + where_method_call?(node) do |template_node, value_node| + value_node = value_node.first + + lambda do |corrector| + range = offense_range(node) + + column, value = *extract_column_and_value(template_node, value_node) + replacement = build_good_method(column, value) + + corrector.replace(range, replacement) + end + end + end + + NOT_EQ_ANONYMOUS_RE = /\A([\w.]+)\s+(?:!=|<>)\s+\?\z/.freeze # column != ?, column <> ? + NOT_IN_ANONYMOUS_RE = /\A([\w.]+)\s+NOT\s+IN\s+\(\?\)\z/i.freeze # column NOT IN (?) + NOT_EQ_NAMED_RE = /\A([\w.]+)\s+(?:!=|<>)\s+:(\w+)\z/.freeze # column != :column, column <> :column + NOT_IN_NAMED_RE = /\A([\w.]+)\s+NOT\s+IN\s+\(:(\w+)\)\z/i.freeze # column NOT IN (:column) + IS_NOT_NULL_RE = /\A([\w.]+)\s+IS\s+NOT\s+NULL\z/i.freeze # column IS NOT NULL + + private + + def offense_range(node) + range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos) + end + + def extract_column_and_value(template_node, value_node) + value = + case template_node.value + when NOT_EQ_ANONYMOUS_RE, NOT_IN_ANONYMOUS_RE + value_node.source + when NOT_EQ_NAMED_RE, NOT_IN_NAMED_RE + return unless value_node.hash_type? + + pair = value_node.pairs.find { |p| p.key.value.to_sym == Regexp.last_match(2).to_sym } + pair.value.source + when IS_NOT_NULL_RE + 'nil' + else + return + end + + [Regexp.last_match(1), value] + end + + def build_good_method(column, value) + if column.include?('.') + "where.not('#{column}' => #{value})" + else + "where.not(#{column}: #{value})" + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails_cops.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails_cops.rb new file mode 100644 index 0000000000..8531298c27 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/cop/rails_cops.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +require_relative 'mixin/active_record_helper' +require_relative 'mixin/index_method' +require_relative 'mixin/target_rails_version' + +require_relative 'rails/action_filter' +require_relative 'rails/active_record_aliases' +require_relative 'rails/active_record_callbacks_order' +require_relative 'rails/active_record_override' +require_relative 'rails/active_support_aliases' +require_relative 'rails/after_commit_override' +require_relative 'rails/application_controller' +require_relative 'rails/application_job' +require_relative 'rails/application_mailer' +require_relative 'rails/application_record' +require_relative 'rails/assert_not' +require_relative 'rails/belongs_to' +require_relative 'rails/blank' +require_relative 'rails/bulk_change_table' +require_relative 'rails/content_tag' +require_relative 'rails/create_table_with_timestamps' +require_relative 'rails/date' +require_relative 'rails/default_scope' +require_relative 'rails/delegate' +require_relative 'rails/delegate_allow_blank' +require_relative 'rails/dynamic_find_by' +require_relative 'rails/enum_hash' +require_relative 'rails/enum_uniqueness' +require_relative 'rails/environment_comparison' +require_relative 'rails/exit' +require_relative 'rails/file_path' +require_relative 'rails/find_by' +require_relative 'rails/find_by_id' +require_relative 'rails/find_each' +require_relative 'rails/has_and_belongs_to_many' +require_relative 'rails/has_many_or_has_one_dependent' +require_relative 'rails/helper_instance_variable' +require_relative 'rails/http_positional_arguments' +require_relative 'rails/http_status' +require_relative 'rails/ignored_skip_action_filter_option' +require_relative 'rails/index_by' +require_relative 'rails/index_with' +require_relative 'rails/inquiry' +require_relative 'rails/inverse_of' +require_relative 'rails/lexically_scoped_action_filter' +require_relative 'rails/link_to_blank' +require_relative 'rails/mailer_name' +require_relative 'rails/match_route' +require_relative 'rails/negate_include' +require_relative 'rails/not_null_column' +require_relative 'rails/order_by_id' +require_relative 'rails/output' +require_relative 'rails/output_safety' +require_relative 'rails/pick' +require_relative 'rails/pluck' +require_relative 'rails/pluck_id' +require_relative 'rails/pluck_in_where' +require_relative 'rails/pluralization_grammar' +require_relative 'rails/presence' +require_relative 'rails/present' +require_relative 'rails/rake_environment' +require_relative 'rails/read_write_attribute' +require_relative 'rails/redundant_allow_nil' +require_relative 'rails/redundant_foreign_key' +require_relative 'rails/redundant_receiver_in_with_options' +require_relative 'rails/reflection_class_name' +require_relative 'rails/refute_methods' +require_relative 'rails/relative_date_constant' +require_relative 'rails/render_inline' +require_relative 'rails/render_plain_text' +require_relative 'rails/request_referer' +require_relative 'rails/reversible_migration' +require_relative 'rails/safe_navigation' +require_relative 'rails/safe_navigation_with_blank' +require_relative 'rails/save_bang' +require_relative 'rails/scope_args' +require_relative 'rails/short_i18n' +require_relative 'rails/skips_model_validations' +require_relative 'rails/squished_sql_heredocs' +require_relative 'rails/time_zone' +require_relative 'rails/uniq_before_pluck' +require_relative 'rails/unique_validation_without_index' +require_relative 'rails/unknown_env' +require_relative 'rails/validation' +require_relative 'rails/where_exists' +require_relative 'rails/where_not' diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails.rb new file mode 100644 index 0000000000..fdc6d8b477 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module RuboCop + # RuboCop Rails project namespace + module Rails + PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze + CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze + CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze + + private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT) + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/inject.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/inject.rb new file mode 100644 index 0000000000..da7ead5ea2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/inject.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module RuboCop + module Rails + # Because RuboCop doesn't yet support plugins, we have to monkey patch in a + # bit of our configuration. + module Inject + def self.defaults! + path = CONFIG_DEFAULT.to_s + hash = ConfigLoader.send(:load_yaml_configuration, path) + config = Config.new(hash, path).tap(&:make_excludes_absolute) + puts "configuration from #{path}" if ConfigLoader.debug? + config = ConfigLoader.merge_with_default(config, path, unset_nil: false) + ConfigLoader.instance_variable_set(:@default_configuration, config) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/schema_loader.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/schema_loader.rb new file mode 100644 index 0000000000..8025496d6a --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/schema_loader.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module RuboCop + module Rails + # It loads db/schema.rb and return Schema object. + # Cops refers database schema information with this module. + module SchemaLoader + extend self + + # It parses `db/schema.rb` and return it. + # It returns `nil` if it can't find `db/schema.rb`. + # So a cop that uses the loader should handle `nil` properly. + # + # @return [Schema, nil] + def load(target_ruby_version) + return @schema if defined?(@schema) + + @schema = load!(target_ruby_version) + end + + def reset! + return unless instance_variable_defined?(:@schema) + + remove_instance_variable(:@schema) + end + + def db_schema_path + path = Pathname.pwd + until path.root? + schema_path = path.join('db/schema.rb') + return schema_path if schema_path.exist? + + path = path.join('../').cleanpath + end + + nil + end + + private + + def load!(target_ruby_version) + path = db_schema_path + return unless path + + ast = parse(path, target_ruby_version) + Schema.new(ast) + end + + def parse(path, target_ruby_version) + klass_name = :"Ruby#{target_ruby_version.to_s.sub('.', '')}" + klass = ::Parser.const_get(klass_name) + parser = klass.new(RuboCop::AST::Builder.new) + + buffer = Parser::Source::Buffer.new(path, 1) + buffer.source = path.read + + parser.parse(buffer) + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/schema_loader/schema.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/schema_loader/schema.rb new file mode 100644 index 0000000000..9f844d110d --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/schema_loader/schema.rb @@ -0,0 +1,190 @@ +# frozen_string_literal: true + +module RuboCop + module Rails + module SchemaLoader + # Represent db/schema.rb + class Schema + attr_reader :tables, :add_indicies + + def initialize(ast) + @tables = [] + @add_indicies = [] + + build!(ast) + end + + def table_by(name:) + tables.find do |table| + table.name == name + end + end + + def add_indicies_by(table_name:) + add_indicies.select do |add_index| + add_index.table_name == table_name + end + end + + private + + def build!(ast) + raise "Unexpected type: #{ast.type}" unless ast.block_type? + + each_table(ast) do |table_def| + @tables << Table.new(table_def) + end + + # Compatibility for Rails 4.2. + each_add_index(ast) do |add_index_def| + @add_indicies << AddIndex.new(add_index_def) + end + end + + def each_table(ast) + case ast.body.type + when :begin + ast.body.children.each do |node| + next unless node.block_type? && node.method?(:create_table) + + yield(node) + end + else + yield ast.body + end + end + + def each_add_index(ast) + ast.body.children.each do |node| + next if !node&.send_type? || !node.method?(:add_index) + + yield(node) + end + end + end + + # Represent a table + class Table + attr_reader :name, :columns, :indices + + def initialize(node) + @name = node.send_node.first_argument.value + @columns = build_columns(node) + @indices = build_indices(node) + end + + def with_column?(name:) + @columns.any? { |c| c.name == name } + end + + private + + def build_columns(node) + each_content(node).map do |child| + next unless child&.send_type? + next if child.method?(:index) + + Column.new(child) + end.compact + end + + def build_indices(node) + each_content(node).map do |child| + next unless child&.send_type? + next unless child.method?(:index) + + Index.new(child) + end.compact + end + + def each_content(node, &block) + return enum_for(__method__, node) unless block_given? + + case node.body&.type + when :begin + node.body.children.each(&block) + else + yield(node.body) + end + end + end + + # Represent a column + class Column + attr_reader :name, :type, :not_null + + def initialize(node) + @name = node.first_argument.value + @type = node.method_name + @not_null = nil + + analyze_keywords!(node) + end + + private + + def analyze_keywords!(node) + pairs = node.arguments.last + return unless pairs.hash_type? + + pairs.each_pair do |k, v| + if k.value == :null + @not_null = v.true_type? ? false : true + end + end + end + end + + # Represent an index + class Index + attr_reader :name, :columns, :expression, :unique + + def initialize(node) + @columns, @expression = build_columns_or_expr(node.first_argument) + @unique = nil + + analyze_keywords!(node) + end + + private + + def build_columns_or_expr(columns) + if columns.array_type? + [columns.values.map(&:value), nil] + else + [[], columns.value] + end + end + + def analyze_keywords!(node) + pairs = node.arguments.last + return unless pairs.hash_type? + + pairs.each_pair do |k, v| + case k.value + when :name + @name = v.value + when :unique + @unique = true + end + end + end + end + + # Represent an `add_index` + class AddIndex < Index + attr_reader :table_name + + def initialize(node) + super(node) + + @table_name = node.first_argument.value + @columns, @expression = build_columns_or_expr(node.arguments[1]) + @unique = nil + + analyze_keywords!(node) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/version.rb b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/version.rb new file mode 100644 index 0000000000..5b183a2d69 --- /dev/null +++ b/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rails-2.8.1/lib/rubocop/rails/version.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module RuboCop + module Rails + # This module holds the RuboCop Rails version information. + module Version + STRING = '2.8.1' + end + end +end