diff --git a/.gitignore b/.gitignore index a4cd169ec1..835ed7c172 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,9 @@ **/.bundle/cache **/vendor/bundle **/vendor/ruby +**/vendor/bundle-standalone/ruby/*/bin **/vendor/bundle-standalone/ruby/*/cache +**/vendor/bundle-standalone/ruby/*/extensions **/vendor/bundle-standalone/ruby/*/gems/*/* **/vendor/bundle-standalone/ruby/*/specifications @@ -39,6 +41,17 @@ **/vendor/bundle-standalone/ruby/*/gems/thread_safe-*/lib **/vendor/bundle-standalone/ruby/*/gems/tzinfo-*/lib +# Ignore rubocop dependencies we don't wish to vendor +**/vendor/bundle-standalone/ruby/*/gems/ast-*/ +**/vendor/bundle-standalone/ruby/*/gems/jaro_winkler-*/ +**/vendor/bundle-standalone/ruby/*/gems/parallel-*/ +**/vendor/bundle-standalone/ruby/*/gems/parser-*/ +**/vendor/bundle-standalone/ruby/*/gems/powerpack-*/ +**/vendor/bundle-standalone/ruby/*/gems/rainbow-*/ +**/vendor/bundle-standalone/ruby/*/gems/rubocop-*/ +**/vendor/bundle-standalone/ruby/*/gems/ruby-progressbar-*/ +**/vendor/bundle-standalone/ruby/*/gems/unicode-display_width-*/ + # Ignore `bin` contents (again). /bin @@ -64,6 +77,8 @@ !/CHANGELOG.md !/CODE_OF_CONDUCT.md !/CONTRIBUTING.md +!/Dockerfile +!/Dockerfile.test.yml !/LICENSE.txt !/README.md diff --git a/.travis.yml b/.travis.yml index 2fcd11ce6f..d46c148abb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: ruby rvm: system +os: osx +osx_image: xcode10 cache: directories: @@ -11,38 +13,21 @@ branches: only: - master -matrix: - fast_finish: true - include: - - os: osx - osx_image: xcode10 - - os: linux - sudo: false +env: + - HOMEBREW_FORCE_HOMEBREW_ON_LINUX=1 before_install: - - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then - MACOS="1"; - HOMEBREW_REPOSITORY="$(brew --repo)"; - sudo chown -R "$USER" "$HOMEBREW_REPOSITORY"; - else - LINUX="1"; - export PATH="$PWD/bin:/usr/bin:/bin:/usr/local/bin"; - fi - # umask 022 fixes Linux `brew tests` failures; - - if [ "$LINUX" ]; then - umask 022; - fi + - HOMEBREW_REPOSITORY="$(brew --repo)" + - sudo chown -R "$USER" "$HOMEBREW_REPOSITORY" # trigger vendored ruby installation - brew help - - if [ "$MACOS" ]; then - mv "$HOMEBREW_REPOSITORY/Library/Taps" "$PWD/Library"; - sudo rm -rf "$HOMEBREW_REPOSITORY"; - sudo ln -s "$PWD" "$HOMEBREW_REPOSITORY"; - fi + - mv "$HOMEBREW_REPOSITORY/Library/Taps" "$PWD/Library" + - sudo rm -rf "$HOMEBREW_REPOSITORY" + - sudo ln -s "$PWD" "$HOMEBREW_REPOSITORY" - travis_retry git clone --depth=1 https://github.com/Homebrew/homebrew-test-bot Library/Taps/homebrew/homebrew-test-bot script: - - brew test-bot + - travis_wait 60 brew test-bot notifications: slack: machomebrew:1XNF7p1JRCdBUuKaeSwsWEc1 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..9c7e1dfda5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,43 @@ +FROM ubuntu:xenial +LABEL maintainer="Shaun Jackman " + +RUN apt-get update \ + && apt-get install -y --no-install-recommends software-properties-common \ + && add-apt-repository -y ppa:git-core/ppa \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + bzip2 \ + ca-certificates \ + curl \ + file \ + fonts-dejavu-core \ + g++ \ + git \ + locales \ + make \ + openssh-client \ + patch \ + sudo \ + uuid-runtime \ + && rm -rf /var/lib/apt/lists/* + +RUN localedef -i en_US -f UTF-8 en_US.UTF-8 \ + && useradd -m -s /bin/bash linuxbrew \ + && echo 'linuxbrew ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers +ADD . /home/linuxbrew/.linuxbrew/Homebrew +RUN cd /home/linuxbrew/.linuxbrew \ + && mkdir -p bin etc include lib opt sbin share var/homebrew/linked Cellar \ + && ln -s ../Homebrew/bin/brew /home/linuxbrew/.linuxbrew/bin/ \ + && chown -R linuxbrew: /home/linuxbrew/.linuxbrew \ + && cd /home/linuxbrew/.linuxbrew/Homebrew \ + && git remote set-url origin https://github.com/Homebrew/brew + +USER linuxbrew +WORKDIR /home/linuxbrew +ENV PATH=/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:$PATH \ + SHELL=/bin/bash \ + USER=linuxbrew + +# Install portable-ruby and tap homebrew/core. +RUN HOMEBREW_NO_ANALYTICS=1 HOMEBREW_NO_AUTO_UPDATE=1 brew tap homebrew/core \ + && rm -rf ~/.cache diff --git a/Dockerfile.test.yml b/Dockerfile.test.yml new file mode 100644 index 0000000000..79e6e7caa3 --- /dev/null +++ b/Dockerfile.test.yml @@ -0,0 +1,3 @@ +sut: + build: . + command: brew test-bot diff --git a/Library/.rubocop.yml b/Library/.rubocop.yml index 36281a4d62..d6cfcb03bc 100644 --- a/Library/.rubocop.yml +++ b/Library/.rubocop.yml @@ -5,9 +5,7 @@ AllCops: - '**/vendor/**/*' DisplayCopNames: false -require: - - ./Homebrew/rubocops.rb - - rubocop-rspec +require: ./Homebrew/rubocops.rb # enable all formulae audits FormulaAudit: diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index ba8e445c8d..fcc78728d7 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -37,8 +37,8 @@ begin homebrew_path = PATH.new(ENV["HOMEBREW_PATH"]) # Add SCM wrappers. - path.append(HOMEBREW_SHIMS_PATH/"scm") - homebrew_path.append(HOMEBREW_SHIMS_PATH/"scm") + path.prepend(HOMEBREW_SHIMS_PATH/"scm") + homebrew_path.prepend(HOMEBREW_SHIMS_PATH/"scm") ENV["PATH"] = path diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index 0c8337e544..003e19a32d 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -55,6 +55,12 @@ git() { "$HOMEBREW_LIBRARY/Homebrew/shims/scm/git" "$@" } +numeric() { + # Condense the exploded argument into a single return value. + # shellcheck disable=SC2086,SC2183 + printf "%01d%02d%02d%02d" ${1//./ } +} + HOMEBREW_VERSION="$(git -C "$HOMEBREW_REPOSITORY" describe --tags --dirty --abbrev=7 2>/dev/null)" HOMEBREW_USER_AGENT_VERSION="$HOMEBREW_VERSION" if [[ -z "$HOMEBREW_VERSION" ]] @@ -86,7 +92,6 @@ then HOMEBREW_OS_VERSION="macOS $HOMEBREW_MACOS_VERSION" # Don't change this from Mac OS X to match what macOS itself does in Safari on 10.12 HOMEBREW_OS_USER_AGENT_VERSION="Mac OS X $HOMEBREW_MACOS_VERSION" - HOMEBREW_BOTTLE_DEFAULT_DOMAIN="https://homebrew.bintray.com" # The system Curl is too old for some modern HTTPS certificates on # older macOS versions. @@ -100,7 +105,8 @@ then HOMEBREW_FORCE_BREWED_CURL="1" fi - # The system Git is too old for some Homebrew functionality we rely on. + # The system Git on macOS versions before Sierra is too old for some Homebrew functionality we rely on. + HOMEBREW_MINIMUM_GIT_VERSION="2.14.3" if [[ "$HOMEBREW_MACOS_VERSION_NUMERIC" -lt "101200" ]] then HOMEBREW_FORCE_BREWED_GIT="1" @@ -114,13 +120,38 @@ else [[ -n "$HOMEBREW_LINUX" ]] && HOMEBREW_OS_VERSION="$(lsb_release -sd 2>/dev/null)" : "${HOMEBREW_OS_VERSION:=$(uname -r)}" HOMEBREW_OS_USER_AGENT_VERSION="$HOMEBREW_OS_VERSION" - HOMEBREW_BOTTLE_DEFAULT_DOMAIN="https://linuxbrew.bintray.com" + + # Ensure the system Curl is a version that supports modern HTTPS certificates. + HOMEBREW_MINIMUM_CURL_VERSION="7.41.0" + system_curl_version_output="$($(command -v curl) --version 2>/dev/null)" + system_curl_name_and_version="${system_curl_version_output%% (*}" + if [[ $(numeric "${system_curl_name_and_version##* }") -lt $(numeric "$HOMEBREW_MINIMUM_CURL_VERSION") ]] + then + HOMEBREW_SYSTEM_CURL_TOO_OLD="1" + HOMEBREW_FORCE_BREWED_CURL="1" + fi + + # Ensure the system Git is at or newer than the minimum required version. + # Git 2.7.4 is the version of git on Ubuntu 16.04 LTS (Xenial Xerus). + HOMEBREW_MINIMUM_GIT_VERSION="2.7.0" + system_git_version_output="$($(command -v git) --version 2>/dev/null)" + if [[ $(numeric "${system_git_version_output##* }") -lt $(numeric "$HOMEBREW_MINIMUM_GIT_VERSION") ]] + then + HOMEBREW_FORCE_BREWED_GIT="1" + fi CACHE_HOME="${XDG_CACHE_HOME:-${HOME}/.cache}" HOMEBREW_CACHE="${HOMEBREW_CACHE:-${CACHE_HOME}/Homebrew}" HOMEBREW_SYSTEM_TEMP="/tmp" fi +if [[ -n "$HOMEBREW_MACOS" || -n "$HOMEBREW_FORCE_HOMEBREW_ON_LINUX" ]] +then + HOMEBREW_BOTTLE_DEFAULT_DOMAIN="https://homebrew.bintray.com" +else + HOMEBREW_BOTTLE_DEFAULT_DOMAIN="https://linuxbrew.bintray.com" +fi + HOMEBREW_TEMP="${HOMEBREW_TEMP:-${HOMEBREW_SYSTEM_TEMP}}" if [[ -n "$HOMEBREW_FORCE_BREWED_CURL" && @@ -148,8 +179,9 @@ else fi HOMEBREW_USER_AGENT="$HOMEBREW_PRODUCT/$HOMEBREW_USER_AGENT_VERSION ($HOMEBREW_SYSTEM; $HOMEBREW_PROCESSOR $HOMEBREW_OS_USER_AGENT_VERSION)" -HOMEBREW_CURL_VERSION="$("$HOMEBREW_CURL" --version 2>/dev/null | head -n1 | awk '{print $1"/"$2}')" -HOMEBREW_USER_AGENT_CURL="$HOMEBREW_USER_AGENT $HOMEBREW_CURL_VERSION" +curl_version_output="$("$HOMEBREW_CURL" --version 2>/dev/null)" +curl_name_and_version="${curl_version_output%% (*}" +HOMEBREW_USER_AGENT_CURL="$HOMEBREW_USER_AGENT ${curl_name_and_version// //}" # Declared in bin/brew export HOMEBREW_BREW_FILE @@ -167,6 +199,7 @@ export HOMEBREW_SYSTEM export HOMEBREW_CURL export HOMEBREW_SYSTEM_CURL_TOO_OLD export HOMEBREW_GIT +export HOMEBREW_MINIMUM_GIT_VERSION export HOMEBREW_PROCESSOR export HOMEBREW_PRODUCT export HOMEBREW_OS_VERSION diff --git a/Library/Homebrew/cask/artifact/abstract_uninstall.rb b/Library/Homebrew/cask/artifact/abstract_uninstall.rb index 6c5e295539..411c970811 100644 --- a/Library/Homebrew/cask/artifact/abstract_uninstall.rb +++ b/Library/Homebrew/cask/artifact/abstract_uninstall.rb @@ -169,7 +169,9 @@ module Cask end end - def uninstall_login_item(*login_items, command: nil, **_) + def uninstall_login_item(*login_items, command: nil, upgrade: false, **_) + return if upgrade + login_items.each do |name| ohai "Removing login item #{name}" command.run!( diff --git a/Library/Homebrew/cask/installer.rb b/Library/Homebrew/cask/installer.rb index 255283cd76..20609203fb 100644 --- a/Library/Homebrew/cask/installer.rb +++ b/Library/Homebrew/cask/installer.rb @@ -424,7 +424,7 @@ module Cask next unless artifact.respond_to?(:uninstall_phase) odebug "Un-installing artifact of class #{artifact.class}" - artifact.uninstall_phase(command: @command, verbose: verbose?, skip: clear, force: force?) + artifact.uninstall_phase(command: @command, verbose: verbose?, skip: clear, force: force?, upgrade: upgrade?) end end diff --git a/Library/Homebrew/cli_parser.rb b/Library/Homebrew/cli_parser.rb index 844bc9130c..352d6405aa 100644 --- a/Library/Homebrew/cli_parser.rb +++ b/Library/Homebrew/cli_parser.rb @@ -42,8 +42,12 @@ module Homebrew def switch(*names, description: nil, env: nil, required_for: nil, depends_on: nil) global_switch = names.first.is_a?(Symbol) - names, env, description = common_switch(*names) if global_switch - description = option_to_description(*names) if description.nil? + names, env, default_description = common_switch(*names) if global_switch + if description.nil? && global_switch + description = default_description + elsif description.nil? + description = option_to_description(*names) + end process_option(*names, description) @parser.on(*names, *wrap_option_desc(description)) do enable_switch(*names) @@ -72,20 +76,24 @@ module Homebrew end end - def flag(name, description: nil, required_for: nil, depends_on: nil) - if name.end_with? "=" + def flag(*names, description: nil, required_for: nil, depends_on: nil) + if names.any? { |name| name.end_with? "=" } required = OptionParser::REQUIRED_ARGUMENT - name.chomp! "=" else required = OptionParser::OPTIONAL_ARGUMENT end - description = option_to_description(name) if description.nil? - process_option(name, description) - @parser.on(name, *wrap_option_desc(description), required) do |option_value| - Homebrew.args[option_to_name(name)] = option_value + names.map! { |name| name.chomp "=" } + description = option_to_description(*names) if description.nil? + process_option(*names, description) + @parser.on(*names, *wrap_option_desc(description), required) do |option_value| + names.each do |name| + Homebrew.args[option_to_name(name)] = option_value + end end - set_constraints(name, required_for: required_for, depends_on: depends_on) + names.each do |name| + set_constraints(name, required_for: required_for, depends_on: depends_on) + end end def conflicts(*options) @@ -118,6 +126,7 @@ module Homebrew remaining_args = @parser.parse(cmdline_args) check_constraint_violations Homebrew.args[:remaining] = remaining_args + Homebrew.args.freeze @parser end diff --git a/Library/Homebrew/cmd/diy.rb b/Library/Homebrew/cmd/diy.rb index a2cdf6c1fa..08146bd69d 100644 --- a/Library/Homebrew/cmd/diy.rb +++ b/Library/Homebrew/cmd/diy.rb @@ -25,8 +25,10 @@ module Homebrew puts "-DCMAKE_INSTALL_PREFIX=#{prefix}" elsif File.file? "configure" puts "--prefix=#{prefix}" + elsif File.file? "meson.build" + puts "-Dprefix=#{prefix}" else - raise "Couldn't determine build system" + raise "Couldn't determine build system. You can manually put files into #{prefix}" end end diff --git a/Library/Homebrew/cmd/doctor.rb b/Library/Homebrew/cmd/doctor.rb index 1b36e99e24..eeb7a1918f 100644 --- a/Library/Homebrew/cmd/doctor.rb +++ b/Library/Homebrew/cmd/doctor.rb @@ -10,16 +10,39 @@ # `--list-checks` lists all audit methods require "diagnostic" +require "cli_parser" module Homebrew module_function + def doctor_args + Homebrew::CLI::Parser.new do + usage_banner <<~EOS + `doctor` [] + + Check your system for potential problems. Doctor exits with a non-zero status + if any potential problems are found. Please note that these warnings are just + used to help the Homebrew maintainers with debugging if you file an issue. If + everything you use Homebrew for is working fine: please don't worry or file + an issue; just ignore this. + EOS + switch "--list-checks", + description: "List all audit methods." + switch "-D", "--audit-debug", + description: "Enable debugging and profiling of audit methods." + switch :verbose + switch :debug + end + end + def doctor - inject_dump_stats!(Diagnostic::Checks, /^check_*/) if ARGV.switch? "D" + doctor_args.parse + + inject_dump_stats!(Diagnostic::Checks, /^check_*/) if args.audit_debug? checks = Diagnostic::Checks.new - if ARGV.include? "--list-checks" + if args.list_checks? puts checks.all.sort exit end @@ -36,7 +59,7 @@ module Homebrew first_warning = true methods.each do |method| - $stderr.puts "Checking #{method}" if ARGV.debug? + $stderr.puts "Checking #{method}" if args.debug? unless checks.respond_to?(method) Homebrew.failed = true puts "No check available by the name: #{method}" diff --git a/Library/Homebrew/cmd/gist-logs.rb b/Library/Homebrew/cmd/gist-logs.rb index 2afad99ec3..975acbd65d 100644 --- a/Library/Homebrew/cmd/gist-logs.rb +++ b/Library/Homebrew/cmd/gist-logs.rb @@ -1,4 +1,4 @@ -#: * `gist-logs` [`--new-issue`|`-n`] : +#: * `gist-logs` [`--new-issue`|`-n`] [`--private`|`-p`] : #: Upload logs for a failed build of to a new Gist. #: #: is usually the name of the formula to install, but it can be specified @@ -9,6 +9,9 @@ #: If `--new-issue` is passed, automatically create a new issue in the appropriate #: GitHub repository as well as creating the Gist. #: +#: If `--private` is passed, the Gist will be marked private and will not +#: appear in listings but will be accessible with the link. +#: #: If no logs are found, an error message is presented. require "formula" @@ -42,8 +45,8 @@ module Homebrew if GitHub.api_credentials_type == :none puts <<~EOS You can create a new personal access token: - #{GitHub::ALL_SCOPES_URL} - and then set the new HOMEBREW_GITHUB_API_TOKEN as the authentication method. + #{GitHub::ALL_SCOPES_URL} + #{Utils::Shell.set_variable_in_profile("HOMEBREW_GITHUB_API_TOKEN", "your_token_here")} EOS login! @@ -77,7 +80,7 @@ module Homebrew s end - # Hack for ruby < 1.9.3 + # Causes some terminals to display secure password entry indicators def noecho_gets system "stty -echo" result = $stdin.gets @@ -110,9 +113,13 @@ module Homebrew logs end + def create_private? + ARGV.include?("--private") || ARGV.switch?("p") + end + def create_gist(files, description) url = "https://api.github.com/gists" - data = { "public" => true, "files" => files, "description" => description } + data = { "public" => !create_private?, "files" => files, "description" => description } scopes = GitHub::CREATE_GIST_SCOPES GitHub.open_api(url, data: data, scopes: scopes)["html_url"] end diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index be8398bdb5..6721f3a0b4 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -1,11 +1,23 @@ #: * `info`: #: Display brief statistics for your Homebrew installation. #: -#: * `info` [`--verbose`]: +#: * `info` `--analytics` [`--days=`] [`--category=`]: +#: Display Homebrew analytics data (provided neither `HOMEBREW_NO_ANALYTICS` +#: or `HOMEBREW_NO_GITHUB_API` are set) +#: +#: The value for `days` must be `30`, `90` or `365`. The default is `30`. +#: +#: The value for `category` must be `install`, `install-on-request`, +#: `build-error` or `os-version`. The default is `install`. +#: +#: * `info` [`--analytics`]: #: Display information about and analytics data (provided neither #: `HOMEBREW_NO_ANALYTICS` or `HOMEBREW_NO_GITHUB_API` are set) #: -#: Pass `--verbose` to see more detailed analytics data. +#: Pass `--verbose` to see more verbose analytics data. +#: +#: Pass `--analytics` to see only more verbose analytics data instead of +#: formula information. #: #: * `info` `--github` : #: Open a browser to the GitHub History page for . @@ -47,7 +59,9 @@ module Homebrew def print_info if ARGV.named.empty? - if HOMEBREW_CELLAR.exist? + if ARGV.include?("--analytics") + output_analytics + elsif HOMEBREW_CELLAR.exist? count = Formula.racks.length puts "#{count} #{"keg".pluralize(count)}, #{HOMEBREW_CELLAR.abv}" end @@ -55,12 +69,21 @@ module Homebrew ARGV.named.each_with_index do |f, i| puts unless i.zero? begin - if f.include?("/") || File.exist?(f) - info_formula Formulary.factory(f) + formula = if f.include?("/") || File.exist?(f) + Formulary.factory(f) else - info_formula Formulary.find_with_priority(f) + Formulary.find_with_priority(f) + end + if ARGV.include?("--analytics") + output_formula_analytics(formula) + else + info_formula(formula) end rescue FormulaUnavailableError => e + if ARGV.include?("--analytics") + output_analytics(filter: f) + next + end ofail e.message # No formula with this name, try a missing formula lookup if (reason = MissingFormula.reason(f)) @@ -184,42 +207,165 @@ module Homebrew caveats = Caveats.new(f) ohai "Caveats", caveats.to_s unless caveats.empty? - output_analytics(f) + output_formula_analytics(f) end - def output_analytics(f) - return if ENV["HOMEBREW_NO_ANALYTICS"] - return if ENV["HOMEBREW_NO_GITHUB_API"] + def formulae_api_json(endpoint) + return if ENV["HOMEBREW_NO_ANALYTICS"] || ENV["HOMEBREW_NO_GITHUB_API"] - formulae_json_url = "https://formulae.brew.sh/api/formula/#{f}.json" - output, = curl_output("--max-time", "3", formulae_json_url) - return if output.empty? + output, = curl_output("--max-time", "3", + "https://formulae.brew.sh/api/#{endpoint}") + return if output.blank? - json = begin - JSON.parse(output) - rescue JSON::ParserError - nil + JSON.parse(output) + rescue JSON::ParserError + nil + end + + def analytics_table(category, days, results, os_version: false) + oh1 "#{category} (#{days} days)" + total_count = results.values.inject("+") + formatted_total_count = format_count(total_count) + formatted_total_percent = format_percent(100) + + index_header = "Index" + count_header = "Count" + percent_header = "Percent" + name_with_options_header = if os_version + "macOS Version" + else + "Name (with options)" end - return if json.nil? || json.empty? || json["analytics"].empty? - ohai "Analytics" - if ARGV.verbose? - json["analytics"].each do |category, value| - value.each do |range, results| - oh1 "#{category} (#{range})" - results.each do |name_with_options, count| - puts "#{name_with_options}: #{number_readable(count)}" - end - end + total_index_footer = "Total" + max_index_width = results.length.to_s.length + index_width = [ + index_header.length, + total_index_footer.length, + max_index_width, + ].max + count_width = [ + count_header.length, + formatted_total_count.length, + ].max + percent_width = [ + percent_header.length, + formatted_total_percent.length, + ].max + name_with_options_width = Tty.width - + index_width - + count_width - + percent_width - + 10 # spacing and lines + + formatted_index_header = + format "%#{index_width}s", index_header + formatted_name_with_options_header = + format "%-#{name_with_options_width}s", + name_with_options_header[0..name_with_options_width-1] + formatted_count_header = + format "%#{count_width}s", count_header + formatted_percent_header = + format "%#{percent_width}s", percent_header + puts "#{formatted_index_header} | #{formatted_name_with_options_header} | "\ + "#{formatted_count_header} | #{formatted_percent_header}" + + columns_line = "#{"-"*index_width}:|-#{"-"*name_with_options_width}-|-"\ + "#{"-"*count_width}:|-#{"-"*percent_width}:" + puts columns_line + + index = 0 + results.each do |name_with_options, count| + index += 1 + formatted_index = format "%0#{max_index_width}d", index + formatted_index = format "%-#{index_width}s", formatted_index + formatted_name_with_options = + format "%-#{name_with_options_width}s", + name_with_options[0..name_with_options_width-1] + formatted_count = format "%#{count_width}s", format_count(count) + formatted_percent = if total_count.zero? + format "%#{percent_width}s", format_percent(0) + else + format "%#{percent_width}s", + format_percent((count.to_i * 100) / total_count.to_f) end + puts "#{formatted_index} | #{formatted_name_with_options} | " \ + "#{formatted_count} | #{formatted_percent}%" + next if index > 10 + end + return unless results.length > 1 + + formatted_total_footer = + format "%-#{index_width}s", total_index_footer + formatted_blank_footer = + format "%-#{name_with_options_width}s", "" + formatted_total_count_footer = + format "%#{count_width}s", formatted_total_count + formatted_total_percent_footer = + format "%#{percent_width}s", formatted_total_percent + puts "#{formatted_total_footer} | #{formatted_blank_footer} | "\ + "#{formatted_total_count_footer} | #{formatted_total_percent_footer}%" + end + + def output_analytics(filter: nil) + days = ARGV.value("days") || "30" + valid_days = %w[30 90 365] + unless valid_days.include?(days) + raise ArgumentError("Days must be one of #{valid_days.join(", ")}!") + end + + category = ARGV.value("category") || "install" + valid_categories = %w[install install-on-request build-error os-version] + unless valid_categories.include?(category) + raise ArgumentError("Categories must be one of #{valid_categories.join(", ")}") + end + + json = formulae_api_json("analytics/#{category}/#{days}d.json") + return if json.blank? || json["items"].blank? + + os_version = category == "os-version" + results = {} + json["items"].each do |item| + key = if os_version + item["os_version"] + else + item["formula"] + end + if filter.present? + next if key != filter && !key.start_with?("#{filter} ") + end + results[key] = item["count"].tr(",", "").to_i + end + + if filter.present? && results.blank? + onoe "No results matching `#{filter}` found!" return end + analytics_table(category, days, results, os_version: os_version) + end + + def output_formula_analytics(f) + json = formulae_api_json("formula/#{f}.json") + return if json.blank? || json["analytics"].blank? + + full_analytics = ARGV.include?("--analytics") || ARGV.verbose? + + ohai "Analytics" json["analytics"].each do |category, value| - analytics = value.map do |range, results| - "#{number_readable(results.values.inject("+"))} (#{range})" + analytics = [] + + value.each do |days, results| + days = days.to_i + if full_analytics + analytics_table(category, days, results) + else + total_count = results.values.inject("+") + analytics << "#{number_readable(total_count)} (#{days} days)" + end end - puts "#{category}: #{analytics.join(", ")}" + + puts "#{category}: #{analytics.join(", ")}" unless full_analytics end end @@ -247,4 +393,12 @@ module Homebrew "#{dep.name} #{dep.option_tags.map { |o| "--#{o}" }.join(" ")}" end + + def format_count(count) + count.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse + end + + def format_percent(percent) + format "%.2f", percent + end end diff --git a/Library/Homebrew/cmd/tap.rb b/Library/Homebrew/cmd/tap.rb index 3b723a73ec..9539faee61 100644 --- a/Library/Homebrew/cmd/tap.rb +++ b/Library/Homebrew/cmd/tap.rb @@ -38,8 +38,6 @@ module Homebrew def tap if ARGV.include? "--repair" Tap.each(&:link_completions_and_manpages) - elsif ARGV.include? "--list-official" - odisabled("brew tap --list-official") elsif ARGV.include? "--list-pinned" puts Tap.select(&:pinned?).map(&:name) elsif ARGV.named.empty? diff --git a/Library/Homebrew/cmd/update.sh b/Library/Homebrew/cmd/update.sh index 0e31a2fcd1..370197e702 100644 --- a/Library/Homebrew/cmd/update.sh +++ b/Library/Homebrew/cmd/update.sh @@ -24,7 +24,7 @@ git() { git_init_if_necessary() { BREW_OFFICIAL_REMOTE="https://github.com/Homebrew/brew" - if [[ -n "$HOMEBREW_MACOS" ]] || [[ -n "$HOMEBREW_FORCE_HOMEBREW_ORG" ]] + if [[ -n "$HOMEBREW_MACOS" ]] || [[ -n "$HOMEBREW_FORCE_HOMEBREW_ON_LINUX" ]] then CORE_OFFICIAL_REMOTE="https://github.com/Homebrew/homebrew-core" else diff --git a/Library/Homebrew/compat.rb b/Library/Homebrew/compat.rb index 7c444615b2..35e634dd89 100644 --- a/Library/Homebrew/compat.rb +++ b/Library/Homebrew/compat.rb @@ -1,8 +1,7 @@ -require "compat/os/mac" -require "compat/dependable" -require "compat/dependency_collector" +require "compat/extend/os/mac/utils/bottles" +require "compat/requirements/x11_requirement" +require "compat/requirements/xcode_requirement" +require "compat/cask" require "compat/download_strategy" require "compat/fileutils" -require "compat/formula_support" -require "compat/cask" require "compat/tap" diff --git a/Library/Homebrew/compat/cask/cask_loader.rb b/Library/Homebrew/compat/cask/cask_loader.rb index 2ef242c150..d0119b4ef1 100644 --- a/Library/Homebrew/compat/cask/cask_loader.rb +++ b/Library/Homebrew/compat/cask/cask_loader.rb @@ -6,6 +6,8 @@ module Cask module Compat private + # TODO: can't delete this code until the merge of + # https://github.com/Homebrew/brew/pull/4730 or an equivalent. def cask(header_token, **options, &block) if header_token.is_a?(Hash) && header_token.key?(:v1) odisabled %q("cask :v1 => 'token'"), %q("cask 'token'") diff --git a/Library/Homebrew/compat/cask/cmd/--version.rb b/Library/Homebrew/compat/cask/cmd/--version.rb index 700d9ac11a..a42c941956 100644 --- a/Library/Homebrew/compat/cask/cmd/--version.rb +++ b/Library/Homebrew/compat/cask/cmd/--version.rb @@ -16,9 +16,7 @@ module Cask end def run - odeprecated "`brew cask --version`", "`brew --version`", disable_on: Time.new(2018, 10, 31) - ARGV.clear - Homebrew.__version + odisabled "`brew cask --version`", "`brew --version`" end def self.help diff --git a/Library/Homebrew/compat/cask/cmd/cleanup.rb b/Library/Homebrew/compat/cask/cmd/cleanup.rb index f7f6d9082d..39cb2db10d 100644 --- a/Library/Homebrew/compat/cask/cmd/cleanup.rb +++ b/Library/Homebrew/compat/cask/cmd/cleanup.rb @@ -22,18 +22,7 @@ module Cask end def run - odeprecated "`brew cask cleanup`", "`brew cleanup`", disable_on: Time.new(2018, 9, 30) - - cleanup = Homebrew::Cleanup.new - - casks(alternative: -> { Cask.to_a }).each do |cask| - cleanup.cleanup_cask(cask) - end - - return if cleanup.disk_cleanup_size.zero? - - disk_space = disk_usage_readable(cleanup.disk_cleanup_size) - ohai "This operation has freed approximately #{disk_space} of disk space." + odisabled "`brew cask cleanup`", "`brew cleanup`" end end end diff --git a/Library/Homebrew/compat/cask/cmd/search.rb b/Library/Homebrew/compat/cask/cmd/search.rb index 8e0ae4f43e..f333255867 100644 --- a/Library/Homebrew/compat/cask/cmd/search.rb +++ b/Library/Homebrew/compat/cask/cmd/search.rb @@ -6,8 +6,7 @@ module Cask module Compat class Search < AbstractCommand def run - odeprecated "`brew cask search`", "`brew search`", disable_on: Time.new(2018, 9, 30) - Homebrew.search(args.empty? ? "--casks" : args) + odisabled "`brew cask search`", "`brew search`" end def self.visible diff --git a/Library/Homebrew/compat/cask/dsl.rb b/Library/Homebrew/compat/cask/dsl.rb index 114b6d83bc..646af08364 100644 --- a/Library/Homebrew/compat/cask/dsl.rb +++ b/Library/Homebrew/compat/cask/dsl.rb @@ -1,8 +1,11 @@ module Cask class DSL module Compat + # TODO: can't delete this code until the merge of + # https://github.com/Homebrew/brew/pull/4730 or an equivalent. + def gpg(*) - odeprecated "the `gpg` stanza", disable_on: Time.new(2018, 12, 31) + odisabled "the `gpg` stanza" end def license(*) @@ -10,7 +13,7 @@ module Cask end def accessibility_access(*) - odeprecated "the `accessibility_access` stanza" + odisabled "the `accessibility_access` stanza" end end diff --git a/Library/Homebrew/compat/dependable.rb b/Library/Homebrew/compat/dependable.rb deleted file mode 100644 index 63195686a5..0000000000 --- a/Library/Homebrew/compat/dependable.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Dependable - module Compat - def run? - odisabled "Dependable#run?" - tags.include? :run - end - end - - prepend Compat -end diff --git a/Library/Homebrew/compat/dependency_collector.rb b/Library/Homebrew/compat/dependency_collector.rb deleted file mode 100644 index 5acfc8f5f5..0000000000 --- a/Library/Homebrew/compat/dependency_collector.rb +++ /dev/null @@ -1,12 +0,0 @@ -require "dependency_collector" - -class DependencyCollector - module Compat - def parse_string_spec(spec, tags) - odisabled "'depends_on ... => :run'" if tags.include?(:run) - super - end - end - - prepend Compat -end diff --git a/Library/Homebrew/compat/download_strategy.rb b/Library/Homebrew/compat/download_strategy.rb index d4b476a260..519fe34af8 100644 --- a/Library/Homebrew/compat/download_strategy.rb +++ b/Library/Homebrew/compat/download_strategy.rb @@ -10,7 +10,7 @@ require "download_strategy" class S3DownloadStrategy < CurlDownloadStrategy def initialize(url, name, version, **meta) odeprecated("S3DownloadStrategy", - "maintaining S3DownloadStrategy in your own formula or tap") + "a vendored S3DownloadStrategy in your own formula or tap (using require_relative)") super end @@ -26,6 +26,13 @@ class S3DownloadStrategy < CurlDownloadStrategy ENV["AWS_ACCESS_KEY_ID"] = ENV["HOMEBREW_AWS_ACCESS_KEY_ID"] ENV["AWS_SECRET_ACCESS_KEY"] = ENV["HOMEBREW_AWS_SECRET_ACCESS_KEY"] + begin + require "aws-sdk-s3" + rescue LoadError + Homebrew.install_gem! "aws-sdk-s3", "~> 1.8" + require "aws-sdk-s3" + end + begin signer = Aws::S3::Presigner.new s3url = signer.presigned_url :get_object, bucket: bucket, key: key @@ -52,7 +59,7 @@ class GitHubPrivateRepositoryDownloadStrategy < CurlDownloadStrategy def initialize(url, name, version, **meta) odeprecated("GitHubPrivateRepositoryDownloadStrategy", - "maintaining GitHubPrivateRepositoryDownloadStrategy in your own formula or tap") + "a vendored GitHubPrivateRepositoryDownloadStrategy in your own formula or tap (using require_relative)") super parse_url_pattern set_github_token @@ -106,7 +113,7 @@ end class GitHubPrivateRepositoryReleaseDownloadStrategy < GitHubPrivateRepositoryDownloadStrategy def initialize(url, name, version, **meta) odeprecated("GitHubPrivateRepositoryReleaseDownloadStrategy", - "maintaining GitHubPrivateRepositoryReleaseDownloadStrategy in your own formula or tap") + "a vendored GitHubPrivateRepositoryReleaseDownloadStrategy in your own formula or tap (using require_relative)") super end @@ -162,7 +169,7 @@ end class ScpDownloadStrategy < AbstractFileDownloadStrategy def initialize(url, name, version, **meta) odeprecated("ScpDownloadStrategy", - "maintaining ScpDownloadStrategy in your own formula or tap") + "a vendored ScpDownloadStrategy in your own formula or tap (using require_relative)") super parse_url_pattern end @@ -204,21 +211,15 @@ end class DownloadStrategyDetector class << self module Compat - def detect(url, using = nil) - strategy = super - require_aws_sdk if strategy == S3DownloadStrategy - strategy - end - def detect_from_url(url) case url when %r{^s3://} odeprecated("s3://", - "maintaining S3DownloadStrategy in your own formula or tap") + "a vendored S3DownloadStrategy in your own formula or tap (using require_relative)") S3DownloadStrategy when %r{^scp://} odeprecated("scp://", - "maintaining ScpDownloadStrategy in your own formula or tap") + "a vendored ScpDownloadStrategy in your own formula or tap (using require_relative)") ScpDownloadStrategy else super(url) @@ -229,19 +230,20 @@ class DownloadStrategyDetector case symbol when :github_private_repo odeprecated(":github_private_repo", - "maintaining GitHubPrivateRepositoryDownloadStrategy in your own formula or tap") + "a vendored GitHubPrivateRepositoryDownloadStrategy in your own formula or tap (using require_relative)") GitHubPrivateRepositoryDownloadStrategy when :github_private_release odeprecated(":github_private_repo", - "maintaining GitHubPrivateRepositoryReleaseDownloadStrategy in your own formula or tap") + "a vendored GitHubPrivateRepositoryReleaseDownloadStrategy in your own formula or tap "\ + "(using require_relative)") GitHubPrivateRepositoryReleaseDownloadStrategy when :s3 odeprecated(":s3", - "maintaining S3DownloadStrategy in your own formula or tap") + "a vendored S3DownloadStrategy in your own formula or tap (using require_relative)") S3DownloadStrategy when :scp odeprecated(":scp", - "maintaining ScpDownloadStrategy in your own formula or tap") + "a vendored ScpDownloadStrategy in your own formula or tap (using require_relative)") ScpDownloadStrategy else super(symbol) diff --git a/Library/Homebrew/compat/extend/os/mac/utils/bottles.rb b/Library/Homebrew/compat/extend/os/mac/utils/bottles.rb new file mode 100644 index 0000000000..5675539a10 --- /dev/null +++ b/Library/Homebrew/compat/extend/os/mac/utils/bottles.rb @@ -0,0 +1,19 @@ +module Utils + class Bottles + class Collector + module Compat + private + + def tag_without_or_later(tag) + return super unless tag.to_s.end_with?("_or_later") + + odeprecated "`or_later` bottles", + "bottles without `or_later` (or_later is implied now)" + tag.to_s[/(\w+)_or_later$/, 1].to_sym + end + end + + prepend Compat + end + end +end diff --git a/Library/Homebrew/compat/fileutils.rb b/Library/Homebrew/compat/fileutils.rb index 0304956aef..72b3c783f9 100644 --- a/Library/Homebrew/compat/fileutils.rb +++ b/Library/Homebrew/compat/fileutils.rb @@ -2,16 +2,12 @@ require "fileutils" module FileUtils module Compat - def ruby(*args) - odeprecated "ruby", 'system "ruby"' - system RUBY_PATH, *args + def ruby(*) + odisabled "ruby", 'system "ruby"' end - def mktemp(prefix = name, opts = {}) - odeprecated("FileUtils.mktemp", "mktemp") - Mktemp.new(prefix, opts).run do |staging| - yield staging - end + def mktemp(*) + odisabled("FileUtils.mktemp", "mktemp") end module_function :mktemp end diff --git a/Library/Homebrew/compat/formula_support.rb b/Library/Homebrew/compat/formula_support.rb deleted file mode 100644 index 7cce3a80b2..0000000000 --- a/Library/Homebrew/compat/formula_support.rb +++ /dev/null @@ -1,75 +0,0 @@ -require "formula_support" - -class KegOnlyReason - module Compat - def valid? - case @reason - when :provided_pre_mountain_lion - odisabled "keg_only :provided_pre_mountain_lion" - MacOS.version < :mountain_lion - when :provided_pre_mavericks - odisabled "keg_only :provided_pre_mavericks" - MacOS.version < :mavericks - when :provided_pre_el_capitan - odisabled "keg_only :provided_pre_el_capitan" - MacOS.version < :el_capitan - when :provided_pre_high_sierra - odisabled "keg_only :provided_pre_high_sierra" - MacOS.version < :high_sierra - when :provided_until_xcode43 - odisabled "keg_only :provided_until_xcode43" - MacOS::Xcode.version < "4.3" - when :provided_until_xcode5 - odisabled "keg_only :provided_until_xcode5" - MacOS::Xcode.version < "5.0" - else - super - end - end - - def to_s - case @reason - when :provided_pre_mountain_lion - odisabled "keg_only :provided_pre_mountain_lion" - - <<~EOS - macOS already provides this software in versions before Mountain Lion - EOS - when :provided_pre_mavericks - odisabled "keg_only :provided_pre_mavericks" - - <<~EOS - macOS already provides this software in versions before Mavericks - EOS - when :provided_pre_el_capitan - odisabled "keg_only :provided_pre_el_capitan" - - <<~EOS - macOS already provides this software in versions before El Capitan - EOS - when :provided_pre_high_sierra - odisabled "keg_only :provided_pre_high_sierra" - - <<~EOS - macOS already provides this software in versions before High Sierra - EOS - when :provided_until_xcode43 - odisabled "keg_only :provided_until_xcode43" - - <<~EOS - Xcode provides this software prior to version 4.3 - EOS - when :provided_until_xcode5 - odisabled "keg_only :provided_until_xcode5" - - <<~EOS - Xcode provides this software prior to version 5 - EOS - else - super - end.to_s.strip - end - end - - prepend Compat -end diff --git a/Library/Homebrew/compat/os/mac.rb b/Library/Homebrew/compat/os/mac.rb deleted file mode 100644 index a9389acaff..0000000000 --- a/Library/Homebrew/compat/os/mac.rb +++ /dev/null @@ -1,14 +0,0 @@ -module OS - module Mac - class << self - module Compat - def release - odisabled "MacOS.release", "MacOS.version" - version - end - end - - prepend Compat - end - end -end diff --git a/Library/Homebrew/compat/requirements/x11_requirement.rb b/Library/Homebrew/compat/requirements/x11_requirement.rb new file mode 100644 index 0000000000..4474784548 --- /dev/null +++ b/Library/Homebrew/compat/requirements/x11_requirement.rb @@ -0,0 +1,16 @@ +require "requirement" + +class X11Requirement < Requirement + module Compat + def initialize(tags = []) + if tags.first.to_s.match?(/(\d\.)+\d/) + odeprecated('depends_on :x11 => "X.Y.Z"') + tags.shift + end + + super(tags) + end + end + + prepend Compat +end diff --git a/Library/Homebrew/compat/requirements/xcode_requirement.rb b/Library/Homebrew/compat/requirements/xcode_requirement.rb new file mode 100644 index 0000000000..490d157091 --- /dev/null +++ b/Library/Homebrew/compat/requirements/xcode_requirement.rb @@ -0,0 +1,21 @@ +require "requirement" + +class XcodeRequirement < Requirement + module Compat + def initialize(tags = []) + @version = if tags.first.to_s.match?(/(\d\.)+\d/) + tags.shift + else + tags.find do |tag| + next unless tag.to_s.match?(/(\d\.)+\d/) + odeprecated('depends_on :xcode => [..., "X.Y.Z"]') + tags.delete(tag) + end + end + + super(tags) + end + end + + prepend Compat +end diff --git a/Library/Homebrew/dependency_collector.rb b/Library/Homebrew/dependency_collector.rb index 9f22429ca5..b1fb6e4f92 100644 --- a/Library/Homebrew/dependency_collector.rb +++ b/Library/Homebrew/dependency_collector.rb @@ -116,15 +116,17 @@ class DependencyCollector def parse_symbol_spec(spec, tags) case spec - when :x11 then X11Requirement.new(spec.to_s, tags) - when :xcode then XcodeRequirement.new(tags) - when :linux then LinuxRequirement.new(tags) - when :macos then MacOSRequirement.new(tags) - when :arch then ArchRequirement.new(tags) - when :java then JavaRequirement.new(tags) - when :osxfuse then OsxfuseRequirement.new(tags) - when :tuntap then TuntapRequirement.new(tags) - when :ld64 then ld64_dep_if_needed(tags) + when :arch then ArchRequirement.new(tags) + when :codesign then CodesignRequirement.new(tags) + when :java then JavaRequirement.new(tags) + when :linux then LinuxRequirement.new(tags) + when :macos then MacOSRequirement.new(tags) + when :maximum_macos then MaximumMacOSRequirement.new(tags) + when :osxfuse then OsxfuseRequirement.new(tags) + when :tuntap then TuntapRequirement.new(tags) + when :x11 then X11Requirement.new(tags) + when :xcode then XcodeRequirement.new(tags) + when :ld64 then ld64_dep_if_needed(tags) else raise ArgumentError, "Unsupported special dependency #{spec.inspect}" end diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index a33b4c05fb..636cfdf6f7 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -1,6 +1,7 @@ #: * `audit` [`--strict`] [`--fix`] [`--online`] [`--new-formula`] [`--display-cop-names`] [`--display-filename`] [`--only=`|`--except=`] [`--only-cops=`|`--except-cops=`] []: -#: Check for Homebrew coding style violations. This should be -#: run before submitting a new formula. +#: Check for Homebrew coding style violations. This should be run +#: before submitting a new formula. Will exit with a non-zero status if any errors +#: are found, which can be useful for implementing pre-commit hooks. #: #: If no are provided, all of them are checked. #: @@ -23,16 +24,13 @@ #: If `--display-filename` is passed, every line of output is prefixed with the #: name of the file or formula being audited, to make the output easy to grep. #: -#: Passing `--only=` will run only the methods named `audit_`, -#: while `--except=` will skip the methods named `audit_`. +#: Specifying `--only=` will run only the methods named `audit_`, +#: while `--except=` will skip the methods named `audit_`. #: For either option should be a comma-separated list. #: -#: Passing `--only-cops=` will check for violations of only the listed +#: Specifying `--only-cops=` will check for violations of only the listed #: RuboCop , while `--except-cops=` will skip checking the listed #: . For either option should be a comma-separated list of cop names. -#: -#: `audit` exits with a non-zero status if any errors are found. This is useful, -#: for instance, for implementing pre-commit hooks. # Undocumented options: # `-D` activates debugging and profiling of the audit methods (not the same as `--debug`) @@ -55,14 +53,15 @@ module Homebrew def audit_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `audit` [] : + `audit` [] - Check for Homebrew coding style violations. This should be - run before submitting a new formula. + Check for Homebrew coding style violations. This should be run before + submitting a new formula. Will exit with a non-zero status if any errors are + found, which can be useful for implementing pre-commit hooks. If no are provided, all of them are checked. EOS switch "--strict", - description: "Run additional style checks, including Rubocop style checks." + description: "Run additional style checks, including RuboCop style checks." switch "--online", description: "Run additional slower style checks that require a network connection." switch "--new-formula", @@ -74,24 +73,26 @@ module Homebrew switch "--display-cop-names", description: "Include the RuboCop cop name for each violation in the output." switch "--display-filename", - description: "Prefix everyline of output with name of the file or formula being audited, to "\ + description: "Prefix every line of output with name of the file or formula being audited, to "\ "make output easy to grep." switch "-D", "--audit-debug", - description: "Activates debugging and profiling" + description: "Enable debugging and profiling of audit methods." comma_array "--only", - description: "Passing `--only=` will run only the methods named audit_. "\ - " should be a comma-separated list." + description: "Specify a comma-separated list to only run the methods named "\ + "`audit_`." comma_array "--except", - description: "Passing `--except=` will run only the methods named audit_, "\ - " should be a comma-separated list." + description: "Specify a comma-separated list to skip running the methods named "\ + "`audit_`." comma_array "--only-cops", - description: "Passing `--only-cops=` will check for violations of only the listed "\ - "RuboCop cops. should be a comma-separated list of cop names." + description: "Specify a comma-separated list to check for violations of only the listed "\ + "RuboCop cops." comma_array "--except-cops", - description: "Passing `--except-cops=` will skip checking the listed RuboCop cops "\ - "violations. should be a comma-separated list of cop names." + description: "Specify a comma-separated list to skip checking for violations of the listed "\ + "RuboCop cops." switch :verbose switch :debug + conflicts "--only", "--except" + conflicts "--only-cops", "--except-cops" end end @@ -126,7 +127,7 @@ module Homebrew if only_cops && except_cops odie "--only-cops and --except-cops cannot be used simultaneously!" elsif (only_cops || except_cops) && (strict || args.only) - odie "--only-cops/--except-cops and --strict/--only cannot be used simultaneously" + odie "--only-cops/--except-cops and --strict/--only cannot be used simultaneously!" end options = { fix: args.fix?, realpath: true } @@ -252,7 +253,9 @@ module Homebrew def initialize(formula, options = {}) @formula = formula - @new_formula = options[:new_formula] && !formula.versioned_formula? + @versioned_formula = formula.versioned_formula? + @new_formula_inclusive = options[:new_formula] + @new_formula = options[:new_formula] && !@versioned_formula @strict = options[:strict] @online = options[:online] @display_cop_names = options[:display_cop_names] @@ -273,7 +276,7 @@ module Homebrew @style_offenses.each do |offense| if offense.cop_name.start_with?("NewFormulaAudit") - next if formula.versioned_formula? + next if @versioned_formula new_formula_problem offense.to_s(display_cop_name: @display_cop_names) next @@ -307,7 +310,7 @@ module Homebrew problem "File should end with a newline" unless text.trailing_newline? - if formula.versioned_formula? + if @versioned_formula unversioned_formula = begin # build this ourselves as we want e.g. homebrew/core to be present full_name = if formula.tap @@ -493,7 +496,6 @@ module Homebrew end def audit_keg_only_style - return unless @strict return unless formula.keg_only? whitelist = %w[ @@ -526,7 +528,7 @@ module Homebrew end def audit_versioned_keg_only - return unless formula.versioned_formula? + return unless @versioned_formula return unless @core_tap return if formula.keg_only? && formula.keg_only_reason.reason == :versioned_formula @@ -561,6 +563,18 @@ module Homebrew end end + def audit_bottle_spec + # special case: new versioned formulae should be audited + return unless @new_formula_inclusive + return unless @core_tap + + return if formula.bottle_disabled? + + return unless formula.bottle_defined? + + new_formula_problem "New formulae should not have a `bottle do` block" + end + def audit_bottle_disabled return unless formula.bottle_disabled? return if formula.bottle_unneeded? @@ -661,24 +675,27 @@ module Homebrew end end - if @core_tap && (formula.head || formula.devel) - unstable_spec_message = "Formulae should not have a `HEAD` or `devel` spec" + if @core_tap && formula.devel + problem "Formulae should not have a `devel` spec" + end + + if @core_tap && formula.head + head_spec_message = "Formulae should not have a `HEAD` spec" if @new_formula - new_formula_problem unstable_spec_message - elsif formula.versioned_formula? - versioned_unstable_spec = %w[ + new_formula_problem head_spec_message + elsif @versioned_formula + versioned_head_spec = %w[ bash-completion@2 imagemagick@6 python@2 ] - problem unstable_spec_message unless versioned_unstable_spec.include?(formula.name) + problem head_spec_message unless versioned_head_spec.include?(formula.name) end end throttled = %w[ aws-sdk-cpp 10 awscli 10 - heroku 10 quicktype 10 vim 50 ] @@ -687,14 +704,13 @@ module Homebrew next if formula.stable.nil? version = formula.stable.version.to_s.split(".").last.to_i - if @strict && a == formula.name && version.modulo(b.to_i).nonzero? + if a == formula.name && version.modulo(b.to_i).nonzero? problem "should only be updated every #{b} releases on multiples of #{b}" end end unstable_whitelist = %w[ aalib 1.4rc5 - angolmois 2.0.0alpha2 automysqlbackup 3.0-rc6 aview 1.3.0rc1 distcc 3.2rc1 @@ -703,10 +719,8 @@ module Homebrew hidapi 0.8.0-rc1 libcaca 0.99b19 nethack4 4.3.0-beta2 - opensyobon 1.0rc2 premake 4.4-beta5 pwnat 0.3-beta - pxz 4.999.9 recode 3.7-beta2 speexdsp 1.2rc3 sqoop 1.4.6 diff --git a/Library/Homebrew/dev-cmd/bottle.rb b/Library/Homebrew/dev-cmd/bottle.rb index 3f43214f02..6f4c372a31 100644 --- a/Library/Homebrew/dev-cmd/bottle.rb +++ b/Library/Homebrew/dev-cmd/bottle.rb @@ -1,10 +1,10 @@ #: * `bottle` [`--verbose`] [`--no-rebuild`|`--keep-old`] [`--skip-relocation`] [`--or-later`] [`--root-url=`] [`--force-core-tap`] [`--json`] : -#: Generate a bottle (binary package) from a formula installed with +#: Generate a bottle (binary package) from a formula that was installed with #: `--build-bottle`. #: #: If the formula specifies a rebuild version, it will be incremented in the -#: generated DSL. Passing `--keep-old` will attempt to keep it at its -#: original value, while `--no-rebuild` will remove it. +#: generated DSL. Passing `--keep-old` will attempt to keep it at its original +#: value, while `--no-rebuild` will remove it. #: #: If `--verbose` (or `-v`) is passed, print the bottling commands and any warnings #: encountered. @@ -15,7 +15,7 @@ #: If `--root-url` is passed, use the specified as the root of the #: bottle's URL instead of Homebrew's default. #: -#: If `--or-later` is passed, append _or_later to the bottle tag. +#: If `--or-later` is passed, append `_or_later` to the bottle tag. #: #: If `--force-core-tap` is passed, build a bottle even if is not #: in homebrew/core or any installed taps. @@ -72,13 +72,13 @@ module Homebrew def bottle_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `bottle` [] : + `bottle` [] - Generate a bottle (binary package) from a formula installed with + Generate a bottle (binary package) from a formula that was installed with `--build-bottle`. If the formula specifies a rebuild version, it will be incremented in the - generated DSL. Passing `--keep-old` will attempt to keep it at its - original value, while `--no-rebuild` will remove it. + generated DSL. Passing `--keep-old` will attempt to keep it at its original + value, while `--no-rebuild` will remove it. EOS switch "--skip-relocation", description: "Do not check if the bottle can be marked as relocatable." @@ -87,28 +87,30 @@ module Homebrew switch "--force-core-tap", description: "Build a bottle even if is not in homebrew/core or any installed taps." switch "--no-rebuild", - description: "If the formula specifies a rebuild version, it will be removed in the generated DSL." + description: "If the formula specifies a rebuild version, remove it from the generated DSL." switch "--keep-old", - description: "If the formula specifies a rebuild version, it will attempted to be kept in the "\ - " generated DSL." - switch "--merge", - description: "Generate a bottle from a formula and print the new DSL merged into the "\ - "existing formula." - switch "--write", - description: "Changes will be written to the formula file. A new commit will be generated unless "\ - "`--no-commit` is passed." - switch "--no-commit", - description: "When passed with `--write`, a new commit will not generated while writing changes "\ - "to the formula file.", - depends_on: "--write" + description: "If the formula specifies a rebuild version, attempt to preserve its value in the "\ + "generated DSL." switch "--json", description: "Write bottle information to a JSON file, which can be used as the argument for "\ "`--merge`." + switch "--merge", + description: "Generate an updated bottle block for a formula and optionally merge it into the "\ + "formula file. Instead of a formula name, requires a JSON file generated with "\ + "`brew bottle --json` ." + switch "--write", + depends_on: "--merge", + description: "Write the changes to the formula file. A new commit will be generated unless "\ + "`--no-commit` is passed." + switch "--no-commit", + depends_on: "--write", + description: "When passed with `--write`, a new commit will not generated after writing changes "\ + "to the formula file." flag "--root-url", - description: "Use the specified as the root of the bottle's URL instead of Homebrew's "\ - "default." + description: "Use the specified as the root of the bottle's URL instead of Homebrew's default." switch :verbose switch :debug + conflicts "--no-rebuild", "--keep-old" end end @@ -228,7 +230,7 @@ module Homebrew unless tap = f.tap unless args.force_core_tap? - return ofail "Formula not from core or any taps: #{f.full_name}" + return ofail "Formula not from core or any installed taps: #{f.full_name}" end tap = CoreTap.instance diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb index 16f3d24af6..67c5ab484e 100644 --- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb +++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb @@ -1,11 +1,11 @@ -#: * `bump-formula-pr` [`--devel`] [`--dry-run` [`--write`]] [`--audit`|`--strict`] [`--mirror=`] [`--version=`] [`--message=`] (`--url=` `--sha256=`|`--tag=` `--revision=`) : -#: Creates a pull request to update the formula with a new URL or a new tag. +#: * `bump-formula-pr` [`--devel`] [`--dry-run` [`--write`]] [`--audit`|`--strict`] [`--no-browse] [`--mirror=`] [`--version=`] [`--message=`] (`--url=` `--sha256=`|`--tag=` `--revision=`) []: +#: Create a pull request to update a formula with a new URL or a new tag. #: -#: If a is specified, the checksum of the new download must -#: also be specified. A best effort to determine the and +#: If a is specified, the checksum of the new download should +#: also be specified. A best effort to determine the and #: name will be made if either or both values are not supplied by the user. #: -#: If a is specified, the git commit corresponding to that +#: If a is specified, the Git commit corresponding to that #: tag must also be specified. #: #: If `--devel` is passed, bump the development rather than stable version. @@ -13,8 +13,8 @@ #: #: If `--dry-run` is passed, print what would be done rather than doing it. #: -#: If `--write` is passed along with `--dry-run`, perform a not-so-dry run -#: making the expected file modifications but not taking any git actions. +#: If `--write` is passed along with `--dry-run`, perform a not-so-dry run by +#: making the expected file modifications but not taking any Git actions. #: #: If `--audit` is passed, run `brew audit` before opening the PR. #: @@ -24,7 +24,7 @@ #: #: If `--version=` is passed, use the value to override the value #: parsed from the URL or tag. Note that `--version=0` can be used to delete -#: an existing `version` override from a formula if it has become redundant. +#: an existing version override from a formula if it has become redundant. #: #: If `--message=` is passed, append to the default PR #: message. @@ -36,8 +36,8 @@ #: If `--quiet` is passed, don't output replacement messages or warn about #: duplicate pull requests. #: -#: Note that this command cannot be used to transition a formula from a -#: URL-and-sha256 style specification into a tag-and-revision style +#: *Note:* this command cannot be used to transition a formula from a +#: URL-and-SHA-256 style specification into a tag-and-revision style #: specification, nor vice versa. It must use whichever style specification #: the preexisting formula already uses. @@ -50,57 +50,58 @@ module Homebrew def bump_formula_pr_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `bump-formula-pr` [] : + `bump-formula-pr` [] [] - Creates a pull request to update the formula with a new URL or a new tag. + Create a pull request to update a formula with a new URL or a new tag. - If a is specified, the checksum of the new download must - also be specified. A best effort to determine the and - name will be made if either or both values are not supplied by the user. + If a is specified, the checksum of the new download should also + be specified. A best effort to determine the and name will + be made if either or both values are not supplied by the user. - If a is specified, the git commit corresponding to that - tag must also be specified. + If a is specified, the Git commit corresponding to that tag + must also be specified. - Note that this command cannot be used to transition a formula from a - URL-and-sha256 style specification into a tag-and-revision style - specification, nor vice versa. It must use whichever style specification - the preexisting formula already uses. + *Note:* this command cannot be used to transition a formula from a + URL-and-SHA-256 style specification into a tag-and-revision style specification, + nor vice versa. It must use whichever style specification the preexisting + formula already uses. EOS switch "--devel", description: "Bump the development rather than stable version. The development spec must already exist." switch "-n", "--dry-run", description: "Print what would be done rather than doing it." switch "--write", - description: "When passed along with `--dry-run`, perform a not-so-dry run making the expected "\ - "file modifications but not taking any git actions." + depends_on: "--dry-run", + description: "When passed along with `--dry-run`, perform a not-so-dry run by making the expected "\ + "file modifications but not taking any Git actions." switch "--audit", description: "Run `brew audit` before opening the PR." switch "--strict", description: "Run `brew audit --strict` before opening the PR." switch "--no-browse", - description: "Output the pull request URL instead of opening in a browser" - flag "--url=", - description: "Provide new for the formula. If a is specified, the "\ - "checksum of the new download must also be specified." - flag "--revision=", - description: "Specify the new git commit corresponding to a specified ." - flag "--tag=", - required_for: "--revision=", - description: "Specify the new git commit for the formula." - flag "--sha256=", - depends_on: "--url=", - description: "Specify the checksum of new download." - flag "--mirror=", + description: "Print the pull request URL instead of opening in a browser." + flag "--mirror=", description: "Use the provided as a mirror URL." - flag "--version=", + flag "--version=", description: "Use the provided to override the value parsed from the URL or tag. Note "\ - "that `--version=0` can be used to delete an existing `version` override from a "\ + "that `--version=0` can be used to delete an existing version override from a "\ "formula if it has become redundant." - flag "--message=", - description: "Append provided to the default PR message." + flag "--message=", + description: "Append the provided to the default PR message." + flag "--url=", + description: "Specify the for the new download. If a is specified, the "\ + "checksum of the new download should also be specified." + flag "--sha256=", + depends_on: "--url=", + description: "Specify the checksum of the new download." + flag "--tag=", + description: "Specify the new git commit for the formula." + flag "--revision=", + required_for: "--tag=", + description: "Specify the new git commit corresponding to a specified ." - switch :quiet switch :force + switch :quiet switch :verbose switch :debug conflicts "--url", "--tag" @@ -352,7 +353,7 @@ module Homebrew "#{new_formula_version}#{devel_message}' -- #{formula.path}" ohai "git push --set-upstream $HUB_REMOTE #{branch}:#{branch}" ohai "create pull request with GitHub API" - ohai "git checkout -" + ohai "git checkout --quiet -" else begin diff --git a/Library/Homebrew/dev-cmd/create.rb b/Library/Homebrew/dev-cmd/create.rb index 4d65c8f416..69b3a7e12e 100644 --- a/Library/Homebrew/dev-cmd/create.rb +++ b/Library/Homebrew/dev-cmd/create.rb @@ -1,17 +1,17 @@ -#: * `create` [`--autotools`|`--cmake`|`--meson`] [`--no-fetch`] [`--set-name` ] [`--set-version` ] [`--tap` `/`]: +#: * `create` [`--autotools`|`--cmake`|`--meson`] [`--no-fetch`] [`--set-name` ] [`--set-version` ] [`--tap` `/`] : #: Generate a formula for the downloadable file at and open it in the editor. #: Homebrew will attempt to automatically derive the formula name #: and version, but if it fails, you'll have to make your own template. The `wget` -#: formula serves as a simple example. For the complete API have a look at -#: . +#: formula serves as a simple example. For the complete API, see: +#: #: #: If `--autotools` is passed, create a basic template for an Autotools-style build. #: If `--cmake` is passed, create a basic template for a CMake-style build. #: If `--meson` is passed, create a basic template for a Meson-style build. #: #: If `--no-fetch` is passed, Homebrew will not download to the cache and -#: will thus not add the SHA256 to the formula for you. It will also not check -#: the GitHub API for GitHub projects (to fill out the description and homepage). +#: will thus not add the SHA-256 to the formula for you, nor will it check +#: the GitHub API for GitHub projects (to fill out its description and homepage). #: #: The options `--set-name` and `--set-version` each take an argument and allow #: you to explicitly set the name and version of the package you are creating. @@ -30,13 +30,13 @@ module Homebrew def create_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `create` []: + `create` [] Generate a formula for the downloadable file at and open it in the editor. - Homebrew will attempt to automatically derive the formula name - and version, but if it fails, you'll have to make your own template. The `wget` - formula serves as a simple example. For the complete API have a look at - . + Homebrew will attempt to automatically derive the formula name and version, but + if it fails, you'll have to make your own template. The `wget` formula serves as + a simple example. For the complete API, see: + EOS switch "--autotools", description: "Create a basic template for an Autotools-style build." @@ -45,17 +45,17 @@ module Homebrew switch "--meson", description: "Create a basic template for a Meson-style build." switch "--no-fetch", - description: "Homebrew will not download to the cache and will thus not add the SHA256 to "\ - "the formula for you. It will also not check the GitHub API for GitHub projects "\ - "(to fill out the description and homepage)." - switch "--HEAD" + description: "Homebrew will not download to the cache and will thus not add the SHA-256 "\ + "to the formula for you, nor will it check the GitHub API for GitHub projects "\ + "(to fill out its description and homepage)." + switch "--HEAD", + description: "Indicate that points to the package's repository rather than a file." flag "--set-name=", - description: "Set the provided name of the package you are creating." + description: "Set the name of the new formula to the provided ." flag "--set-version=", - description: "Set the provided version of the package you are creating." + description: "Set the version of the new formula to the provided ." flag "--tap=", - description: "Takes a tap [`/`] as argument and generates the formula in the "\ - "specified tap." + description: "Generate the new formula in the provided tap, specified as `/`." switch :force switch :verbose switch :debug diff --git a/Library/Homebrew/dev-cmd/edit.rb b/Library/Homebrew/dev-cmd/edit.rb index 42d7ecf941..14f0780bfb 100644 --- a/Library/Homebrew/dev-cmd/edit.rb +++ b/Library/Homebrew/dev-cmd/edit.rb @@ -1,8 +1,8 @@ #: * `edit`: -#: Open all of Homebrew for editing. +#: Open the Homebrew repository for editing. #: #: * `edit` : -#: Open in the editor. +#: Open in the editor set by `EDITOR` or `HOMEBREW_EDITOR`. require "formula" require "cli_parser" @@ -13,9 +13,10 @@ module Homebrew def edit_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `edit` : - Open in the editor. Open all of Homebrew for editing if - no is provided. + `edit` [] + + Open a formula in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, or open the + Homebrew repository for editing if no is provided. EOS switch :force switch :verbose @@ -29,7 +30,7 @@ module Homebrew unless (HOMEBREW_REPOSITORY/".git").directory? raise <<~EOS Changes will be lost! - The first time you `brew update', all local changes will be lost, you should + The first time you `brew update', all local changes will be lost; you should thus `brew update' before you `brew edit'! EOS end diff --git a/Library/Homebrew/dev-cmd/extract.rb b/Library/Homebrew/dev-cmd/extract.rb index 3e4813fdd8..0a0ac2787d 100644 --- a/Library/Homebrew/dev-cmd/extract.rb +++ b/Library/Homebrew/dev-cmd/extract.rb @@ -1,7 +1,7 @@ #: * `extract` [`--force`] [`--version=`]: -#: Looks through repository history to find the of and -#: creates a copy in /Formula/@.rb. If the tap is -#: not installed yet, attempts to install/clone the tap before continuing. +#: Look through repository history to find the most recent version of and +#: create a copy in `/Formula/``@``.rb`. If the tap is +#: not installed yet, attempt to install/clone the tap before continuing. #: #: If `--force` is passed, the file at the destination will be overwritten #: if it already exists. Otherwise, existing files will be preserved. @@ -99,18 +99,17 @@ module Homebrew def extract_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `extract` [] : + `extract` [] - Looks through repository history to find the of and - creates a copy in /Formula/@.rb. If the tap is - not installed yet, attempts to install/clone the tap before continuing. + Look through repository history to find the most recent version of and + create a copy in `/Formula/``@``.rb`. If the tap is not + installed yet, attempt to install/clone the tap before continuing. EOS flag "--version=", - description: "Provided of will be extracted and placed in the destination "\ - "tap. Otherwise, the most recent version that can be found will be used." - switch :debug + description: "Extract the provided of instead of the most recent." switch :force + switch :debug end end @@ -128,7 +127,7 @@ module Homebrew repo = CoreTap.instance.path # Formulae can technically live in "/.rb" or # "/Formula/.rb", but explicitly use the latter for now - # since that is now core tap is structured. + # since that is how the core tap is structured. file = repo/"Formula/#{name}.rb" if args.version @@ -175,7 +174,7 @@ module Homebrew odie <<~EOS Destination formula already exists: #{path} To overwrite it and continue anyways, run: - `brew extract #{name} --version=#{version} --tap=#{destination_tap.name} --force` + brew extract --force --version=#{version} #{name} #{destination_tap.name} EOS end ohai "Overwriting existing formula at #{path}" if ARGV.debug? diff --git a/Library/Homebrew/dev-cmd/formula.rb b/Library/Homebrew/dev-cmd/formula.rb index 904f8e2aa6..43f355f20c 100644 --- a/Library/Homebrew/dev-cmd/formula.rb +++ b/Library/Homebrew/dev-cmd/formula.rb @@ -1,5 +1,5 @@ -#: * `formula` : -#: Display the path where is located. +#: * `formula` : +#: Display the path where a formula is located. require "formula" require "cli_parser" @@ -10,12 +10,12 @@ module Homebrew def formula_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `formula` : + `formula` - Display the path where is located. + Display the path where a formula is located. EOS - switch :debug switch :verbose + switch :debug end end diff --git a/Library/Homebrew/dev-cmd/irb.rb b/Library/Homebrew/dev-cmd/irb.rb index 816ab6047c..b001a89182 100644 --- a/Library/Homebrew/dev-cmd/irb.rb +++ b/Library/Homebrew/dev-cmd/irb.rb @@ -2,8 +2,9 @@ #: Enter the interactive Homebrew Ruby shell. #: #: If `--examples` is passed, several examples will be shown. -#: If `--pry` is passed or HOMEBREW_PRY is set, pry will be -#: used instead of irb. +#: +#: If `--pry` is passed or `HOMEBREW_PRY` is set, Pry will be +#: used instead of IRB. require "cli_parser" @@ -25,7 +26,7 @@ module Homebrew def irb_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `irb` []: + `irb` [] Enter the interactive Homebrew Ruby shell. EOS @@ -33,7 +34,7 @@ module Homebrew description: "Show several examples." switch "--pry", env: :pry, - description: "Pry will be used instead of irb if `--pry` is passed or HOMEBREW_PRY is set." + description: "Use Pry instead of IRB. Implied if `HOMEBREW_PRY` is set." end end diff --git a/Library/Homebrew/dev-cmd/linkage.rb b/Library/Homebrew/dev-cmd/linkage.rb index 2feb98f899..3cd56bf629 100644 --- a/Library/Homebrew/dev-cmd/linkage.rb +++ b/Library/Homebrew/dev-cmd/linkage.rb @@ -1,14 +1,12 @@ #: * `linkage` [`--test`] [`--reverse`] []: -#: Checks the library links of installed formulae. -#: -#: Only works on installed formulae. An error is raised if it is run on -#: uninstalled formulae. +#: Check the library links for kegs of installed formulae. +#: Raises an error if run on uninstalled formulae. #: #: If `--test` is passed, only display missing libraries and exit with a -#: non-zero exit code if any missing libraries were found. +#: non-zero status if any missing libraries are found. #: -#: If `--reverse` is passed, print the dylib followed by the binaries -#: which link to it for each library the keg references. +#: If `--reverse` is passed, for every library that a keg references, +#: print its dylib path followed by the binaries that link to it. #: #: If are given, check linkage for only the specified brews. @@ -22,21 +20,19 @@ module Homebrew def linkage_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `linkage` [] : + `linkage` [] [] - Checks the library links of an installed formula. - - Only works on installed formulae. An error is raised if it is run on - uninstalled formulae. + Check the library links for kegs of installed formulae. + Raises an error if run on uninstalled formulae. EOS switch "--test", - description: "Display only missing libraries and exit with a non-zero exit code if any missing "\ - "libraries were found." + description: "Display only missing libraries and exit with a non-zero status if any missing "\ + "libraries are found." switch "--reverse", - description: "Print the dylib followed by the binaries which link to it for each library the keg "\ - "references." + description: "For every library that a keg references, print its dylib path followed by the "\ + "binaries that link to it." switch "--cached", - description: "Print the cached linkage values stored in HOMEBREW_CACHE, set from a previous "\ + description: "Print the cached linkage values stored in `HOMEBREW_CACHE`, set by a previous "\ "`brew linkage` run." switch :verbose switch :debug diff --git a/Library/Homebrew/dev-cmd/man.rb b/Library/Homebrew/dev-cmd/man.rb index d11780923f..73f8a713b1 100644 --- a/Library/Homebrew/dev-cmd/man.rb +++ b/Library/Homebrew/dev-cmd/man.rb @@ -16,14 +16,17 @@ require "dev-cmd/bottle" require "dev-cmd/bump-formula-pr" require "dev-cmd/create" require "dev-cmd/edit" +require "dev-cmd/extract" require "dev-cmd/formula" require "dev-cmd/irb" require "dev-cmd/linkage" require "dev-cmd/mirror" +require "dev-cmd/prof" require "dev-cmd/pull" -require "dev-cmd/extract" require "dev-cmd/release-notes" +require "dev-cmd/ruby" require "dev-cmd/tap-new" +require "dev-cmd/test" require "dev-cmd/tests" require "dev-cmd/update-test" @@ -37,7 +40,7 @@ module Homebrew def man_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `man` []: + `man` [] Generate Homebrew's manpages. EOS @@ -47,7 +50,7 @@ module Homebrew "the date used in new manpages will match those in the existing manpages (to allow "\ "comparison without factoring in the date)." switch "--link", - description: "It is now done automatically by `brew update`." + description: "This is now done automatically by `brew update`." end end @@ -186,6 +189,7 @@ module Homebrew def generate_cmd_manpages(glob) cmd_paths = Pathname.glob(glob).sort man_page_lines = [] + man_args = Homebrew.args cmd_paths.each do |cmd_path| begin cmd_parser = Homebrew.send(cmd_arg_parser(cmd_path)) @@ -194,6 +198,7 @@ module Homebrew man_page_lines << path_glob_commands(cmd_path.to_s).first end end + Homebrew.args = man_args man_page_lines end @@ -220,15 +225,16 @@ module Homebrew end def generate_option_doc(short, long, desc) - "* #{format_short_opt(short)} #{format_long_opt(long)}:" + "\n" + desc + "\n" + comma = (short && long) ? ", " : "" + "* #{format_short_opt(short)}" + comma + "#{format_long_opt(long)}:" + "\n " + desc + "\n" end def format_short_opt(opt) - "`#{opt}`, " unless opt.nil? + "`#{opt}`" unless opt.nil? end def format_long_opt(opt) - "`#{opt}`" + "`#{opt}`" unless opt.nil? end def format_usage_banner(usage_banner) diff --git a/Library/Homebrew/dev-cmd/mirror.rb b/Library/Homebrew/dev-cmd/mirror.rb index a707e1dc7e..fc408cabc7 100644 --- a/Library/Homebrew/dev-cmd/mirror.rb +++ b/Library/Homebrew/dev-cmd/mirror.rb @@ -10,19 +10,19 @@ module Homebrew def mirror_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `mirror` : + `mirror` Reuploads the stable URL for a formula to Bintray to use it as a mirror. EOS - switch :debug switch :verbose + switch :debug end end def mirror mirror_args.parse - odie "This command requires at least formula argument!" if ARGV.named.empty? + odie "This command requires at least one formula argument!" if ARGV.named.empty? bintray_user = ENV["HOMEBREW_BINTRAY_USER"] bintray_key = ENV["HOMEBREW_BINTRAY_KEY"] diff --git a/Library/Homebrew/dev-cmd/prof.rb b/Library/Homebrew/dev-cmd/prof.rb index f2750e83c2..9a573bb68b 100644 --- a/Library/Homebrew/dev-cmd/prof.rb +++ b/Library/Homebrew/dev-cmd/prof.rb @@ -1,11 +1,23 @@ #: * `prof` []: #: Run Homebrew with the Ruby profiler. -#: For example: -#: brew prof readall +#: +#: *Example:* `brew prof readall` module Homebrew module_function + def prof_args + Homebrew::CLI::Parser.new do + usage_banner <<~EOS + `prof` [] + + Run Homebrew with the Ruby profiler. + + *Example:* `brew prof readall` + EOS + end + end + def prof Homebrew.install_gem_setup_path! "ruby-prof" FileUtils.mkdir_p "prof" diff --git a/Library/Homebrew/dev-cmd/pull.rb b/Library/Homebrew/dev-cmd/pull.rb index 1779be9478..b496f3aa19 100644 --- a/Library/Homebrew/dev-cmd/pull.rb +++ b/Library/Homebrew/dev-cmd/pull.rb @@ -1,6 +1,6 @@ #: * `pull` [`--bottle`] [`--bump`] [`--clean`] [`--ignore-whitespace`] [`--resolve`] [`--branch-okay`] [`--no-pbcopy`] [`--no-publish`] [`--warn-on-publish-failure`] [`--bintray-org=`] [`--test-bot-user=`] []: -#: Gets a patch from a GitHub commit or pull request and applies it to Homebrew. -#: Optionally, installs the formulae changed by the patch. +#: Get a patch from a GitHub commit or pull request and apply it to Homebrew. +#: Optionally, publish updated bottles for the formulae changed by the patch. #: #: Each may be one of: #: @@ -41,11 +41,11 @@ #: If `--warn-on-publish-failure` was passed, do not exit if there's a #: failure publishing bottles on Bintray. #: -#: If `--bintray-org=` is passed, publish at the given Bintray +#: If `--bintray-org=` is passed, publish at the provided Bintray #: organisation. #: #: If `--test-bot-user=` is passed, pull the bottle block -#: commit from the specified user on GitHub. +#: commit from the provided user on GitHub. require "net/http" require "net/https" @@ -74,12 +74,12 @@ module Homebrew def pull_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `pull` [] : + `pull` [] - Gets a patch from a GitHub commit or pull request and applies it to Homebrew. - Optionally, installs the formulae changed by the patch. + Get a patch from a GitHub commit or pull request and apply it to Homebrew. + Optionally, publish updated bottles for the formulae changed by the patch. - Each may be one of: + Each may be one of: ~ The ID number of a PR (pull request) in the homebrew/core GitHub repository @@ -112,9 +112,9 @@ module Homebrew switch "--warn-on-publish-failure", description: "Do not exit if there's a failure publishing bottles on Bintray." flag "--bintray-org=", - description: "Publish at the given Bintray organisation." + description: "Publish bottles at the provided Bintray ." flag "--test-bot-user=", - description: "Pull the bottle block commit from the specified user on GitHub." + description: "Pull the bottle block commit from the provided on GitHub." switch :verbose switch :debug end diff --git a/Library/Homebrew/dev-cmd/release-notes.rb b/Library/Homebrew/dev-cmd/release-notes.rb index 2a990a8617..2c3711c1c3 100644 --- a/Library/Homebrew/dev-cmd/release-notes.rb +++ b/Library/Homebrew/dev-cmd/release-notes.rb @@ -1,9 +1,9 @@ #: * `release-notes` [`--markdown`] [] []: -#: Output the merged pull requests on Homebrew/brew between two Git refs. +#: Print the merged pull requests on Homebrew/brew between two Git refs. #: If no is provided it defaults to the latest tag. #: If no is provided it defaults to `origin/master`. #: -#: If `--markdown` is passed, output as a Markdown list. +#: If `--markdown` is passed, print as a Markdown list. require "cli_parser" @@ -13,14 +13,14 @@ module Homebrew def release_notes_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `release-notes` [] [] []: + `release-notes` [] [] [] - Output the merged pull requests on Homebrew/brew between two Git refs. + Print the merged pull requests on Homebrew/brew between two Git refs. If no is provided it defaults to the latest tag. If no is provided it defaults to `origin/master`. EOS switch "--markdown", - description: "Output as a Markdown list." + description: "Print as a Markdown list." end end diff --git a/Library/Homebrew/dev-cmd/ruby.rb b/Library/Homebrew/dev-cmd/ruby.rb index f658529e07..35a4eb1c5c 100644 --- a/Library/Homebrew/dev-cmd/ruby.rb +++ b/Library/Homebrew/dev-cmd/ruby.rb @@ -1,13 +1,32 @@ #: * `ruby` []: #: Run a Ruby instance with Homebrew's libraries loaded. -#: For example: -# brew ruby -e "puts :gcc.f.deps" -# brew ruby script.rb +#: +#: *Example:* `brew ruby -e "puts :gcc.f.deps"` or `brew ruby script.rb` + +require "cli_parser" module Homebrew module_function + def ruby_args + Homebrew::CLI::Parser.new do + usage_banner <<~EOS + `ruby` [] + + Run a Ruby instance with Homebrew's libraries loaded. + + *Example:* `brew ruby -e "puts :gcc.f.deps"` or `brew ruby script.rb` + EOS + switch "-e", + description: "Execute the provided string argument as a script." + switch :verbose + switch :debug + end + end + def ruby + ruby_args.parse + exec ENV["HOMEBREW_RUBY_PATH"], "-I", $LOAD_PATH.join(File::PATH_SEPARATOR), "-rglobal", "-rdev-cmd/irb", *ARGV end end diff --git a/Library/Homebrew/dev-cmd/tap-new.rb b/Library/Homebrew/dev-cmd/tap-new.rb index 92ff6a40b9..e227fee242 100644 --- a/Library/Homebrew/dev-cmd/tap-new.rb +++ b/Library/Homebrew/dev-cmd/tap-new.rb @@ -7,23 +7,15 @@ require "cli_parser" module Homebrew module_function - def write_path(tap, filename, content) - path = tap.path/filename - tap.path.mkpath - raise "#{path} already exists" if path.exist? - - path.write content - end - def tap_new_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `tap-new` /: + `tap-new` `/` Generate the template files for a new tap. EOS - switch :debug switch :verbose + switch :debug end end @@ -84,4 +76,12 @@ module Homebrew YAML write_path(tap, ".travis.yml", travis) end + + def write_path(tap, filename, content) + path = tap.path/filename + tap.path.mkpath + raise "#{path} already exists" if path.exist? + + path.write content + end end diff --git a/Library/Homebrew/dev-cmd/test.rb b/Library/Homebrew/dev-cmd/test.rb index 7eadd67598..1198bd73d3 100644 --- a/Library/Homebrew/dev-cmd/test.rb +++ b/Library/Homebrew/dev-cmd/test.rb @@ -1,8 +1,7 @@ -#: * `test` [`--devel`|`--HEAD`] [`--debug`] [`--keep-tmp`] : -#: Most formulae provide a test method. `brew test` runs this -#: test method. There is no standard output or return code, but it should -#: generally indicate to the user if something is wrong with the installed -#: formula. +#: * `test` [`--devel`|`--HEAD`] [`--debug`] [`--keep-tmp`] : +#: Run the test method provided by a formula. +#: There is no standard output or return code, but generally it should notify the +#: user if something is wrong with the installed formula. #: #: To test the development or head version of a formula, use `--devel` or #: `--HEAD`. @@ -13,7 +12,7 @@ #: If `--keep-tmp` is passed, the temporary files created for the test are #: not deleted. #: -#: Example: `brew install jruby && brew test jruby` +#: *Example:* `brew install jruby && brew test jruby` require "extend/ENV" require "formula_assertions" @@ -23,6 +22,28 @@ require "timeout" module Homebrew module_function + def test_args + Homebrew::CLI::Parser.new do + usage_banner <<~EOS + `test` [] + + Run the test method provided by an installed formula. + There is no standard output or return code, but generally it should notify the + user if something is wrong with the installed formula. + + *Example:* `brew install jruby && brew test jruby` + EOS + switch "--devel", + description: "Test the development version of a formula." + switch "--HEAD", + description: "Test the head version of a formula." + switch "--keep-tmp", + description: "Keep the temporary files created for the test." + switch :verbose + switch :debug + end + end + def test raise FormulaUnspecifiedError if ARGV.named.empty? diff --git a/Library/Homebrew/dev-cmd/tests.rb b/Library/Homebrew/dev-cmd/tests.rb index add193d968..2d0e5b3ffa 100644 --- a/Library/Homebrew/dev-cmd/tests.rb +++ b/Library/Homebrew/dev-cmd/tests.rb @@ -1,6 +1,6 @@ -#: * `tests` [`--verbose`] [`--coverage`] [`--generic`] [`--no-compat`] [`--only=`[`:`]] [`--seed=`] [`--online`] [`--official-cmd-taps`]: +#: * `tests` [`--verbose`] [`--coverage`] [`--generic`] [`--no-compat`] [`--only=`[`:`]] [`--seed=`] [`--online`]: #: Run Homebrew's unit and integration tests. If provided, -#: `--only=` runs only _spec.rb, and `--seed` +#: `--only=` runs only `_spec.rb`, and `--seed` #: randomizes tests with the provided value instead of a random seed. #: #: If `--verbose` (or `-v`) is passed, print the command that runs the tests. @@ -24,25 +24,24 @@ module Homebrew def tests_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `tests` []: + `tests` [] - Run Homebrew's unit and integration tests. If provided, - `--only=` runs only _spec.rb, and `--seed` - randomizes tests with the provided value instead of a random seed. + Run Homebrew's unit and integration tests. EOS switch "--coverage", description: "Generate code coverage reports." switch "--generic", - description: "Run only OS-agnostic tests." + description: "Run only OS-agnostic tests." switch "--no-compat", description: "Do not load the compatibility layer when running tests." switch "--online", description: "Include tests that use the GitHub API and tests that use any of the taps for "\ "official external commands." flag "--only=", - description: "Run only _spec.rb" + description: "Run only `_spec.rb`. Appending `:` will start at a "\ + "specific line." flag "--seed=", - description: "Randomizes tests with the provided value instead of a random seed." + description: "Randomize tests with the provided instead of a random seed." switch :verbose switch :debug end diff --git a/Library/Homebrew/dev-cmd/update-test.rb b/Library/Homebrew/dev-cmd/update-test.rb index c9aec5b31a..dadcdef1b7 100644 --- a/Library/Homebrew/dev-cmd/update-test.rb +++ b/Library/Homebrew/dev-cmd/update-test.rb @@ -1,5 +1,5 @@ #: * `update-test` [`--commit=`] [`--before=`] [`--to-tag`] [`--keep-tmp`]: -#: Runs a test of `brew update` with a new repository clone. +#: Run a test of `brew update` with a new repository clone. #: #: If no arguments are passed, use `origin/master` as the start commit. #: @@ -22,10 +22,9 @@ module Homebrew def update_test_args Homebrew::CLI::Parser.new do usage_banner <<~EOS - `update-test` []: - - Runs a test of `brew update` with a new repository clone. + `update-test` [] + Run a test of `brew update` with a new repository clone. If no arguments are passed, use `origin/master` as the start commit. EOS switch "--to-tag", diff --git a/Library/Homebrew/diagnostic.rb b/Library/Homebrew/diagnostic.rb index 7f84168060..55df9aca8c 100644 --- a/Library/Homebrew/diagnostic.rb +++ b/Library/Homebrew/diagnostic.rb @@ -489,8 +489,7 @@ module Homebrew end def check_git_version - # System Git version on macOS Sierra. - minimum_version = "2.14.3".freeze + minimum_version = ENV["HOMEBREW_MINIMUM_GIT_VERSION"].freeze return unless Utils.git_available? return if Version.create(Utils.git_version) >= Version.create(minimum_version) diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb index 4afcc16032..bddc679e36 100644 --- a/Library/Homebrew/download_strategy.rb +++ b/Library/Homebrew/download_strategy.rb @@ -352,8 +352,9 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy end end - filenames = lines.map { |line| line[/^Content\-Disposition:\s*attachment;\s*filename=(["']?)([^;]+)\1/i, 2] } - .compact + filenames = + lines.map { |line| line[/^Content\-Disposition:\s*(?:inline|attachment);\s*filename=(["']?)([^;]+)\1/i, 2] } + .compact basename = filenames.last || parse_basename(redirect_url) diff --git a/Library/Homebrew/extend/os/keg.rb b/Library/Homebrew/extend/os/keg.rb new file mode 100644 index 0000000000..4164a96263 --- /dev/null +++ b/Library/Homebrew/extend/os/keg.rb @@ -0,0 +1 @@ +require "extend/os/mac/keg" if OS.mac? diff --git a/Library/Homebrew/extend/os/linux/keg_relocate.rb b/Library/Homebrew/extend/os/linux/keg_relocate.rb index a06caea7a2..dd08361de6 100644 --- a/Library/Homebrew/extend/os/linux/keg_relocate.rb +++ b/Library/Homebrew/extend/os/linux/keg_relocate.rb @@ -1,5 +1,8 @@ class Keg def relocate_dynamic_linkage(relocation) + # Patching the dynamic linker of glibc breaks it. + return if name == "glibc" + # Patching patchelf using itself fails with "Text file busy" or SIGBUS. return if name == "patchelf" @@ -83,4 +86,17 @@ class Keg def self.relocation_formulae ["patchelf"] end + + def self.bottle_dependencies + @bottle_dependencies ||= begin + formulae = relocation_formulae + gcc = Formula["gcc"] + if !ENV["HOMEBREW_FORCE_HOMEBREW_ON_LINUX"] && + DevelopmentTools.non_apple_gcc_version("gcc") < gcc.version.to_i + formulae += gcc.recursive_dependencies.map(&:name) + formulae << gcc.name + end + formulae + end + end end diff --git a/Library/Homebrew/extend/os/linux/tap.rb b/Library/Homebrew/extend/os/linux/tap.rb index ba8ae3e4f0..fd692afd94 100644 --- a/Library/Homebrew/extend/os/linux/tap.rb +++ b/Library/Homebrew/extend/os/linux/tap.rb @@ -1,6 +1,6 @@ class CoreTap < Tap def default_remote - if ENV["HOMEBREW_FORCE_HOMEBREW_ORG"] + if ENV["HOMEBREW_FORCE_HOMEBREW_ON_LINUX"] "https://github.com/Homebrew/homebrew-core".freeze else "https://github.com/Linuxbrew/homebrew-core".freeze diff --git a/Library/Homebrew/extend/os/mac/keg.rb b/Library/Homebrew/extend/os/mac/keg.rb new file mode 100644 index 0000000000..d7d7a6fe41 --- /dev/null +++ b/Library/Homebrew/extend/os/mac/keg.rb @@ -0,0 +1,4 @@ +class Keg + GENERIC_KEG_LINK_DIRECTORIES = remove_const :KEG_LINK_DIRECTORIES + KEG_LINK_DIRECTORIES = (GENERIC_KEG_LINK_DIRECTORIES + ["Frameworks"]).freeze +end diff --git a/Library/Homebrew/extend/os/mac/requirements/non_binary_osxfuse_requirement.rb b/Library/Homebrew/extend/os/mac/requirements/non_binary_osxfuse_requirement.rb deleted file mode 100644 index 39d638cf88..0000000000 --- a/Library/Homebrew/extend/os/mac/requirements/non_binary_osxfuse_requirement.rb +++ /dev/null @@ -1,15 +0,0 @@ -require "requirement" - -class NonBinaryOsxfuseRequirement < Requirement - fatal true - satisfy(build_env: false) do - HOMEBREW_PREFIX.to_s != "/usr/local" || !OsxfuseRequirement.binary_osxfuse_installed? - end - - def message - <<~EOS - osxfuse is already installed from the binary distribution and - conflicts with this formula. - EOS - end -end diff --git a/Library/Homebrew/extend/os/mac/utils/bottles.rb b/Library/Homebrew/extend/os/mac/utils/bottles.rb index 1093f1309c..02b6822fc0 100644 --- a/Library/Homebrew/extend/os/mac/utils/bottles.rb +++ b/Library/Homebrew/extend/os/mac/utils/bottles.rb @@ -42,6 +42,10 @@ module Utils altivec_tag if key?(altivec_tag) end + def tag_without_or_later(tag) + tag + end + # Find a bottle built for a previous version of macOS. def find_older_compatible_tag(tag) begin @@ -51,13 +55,12 @@ module Utils end keys.find do |key| - # TODO: move to compat? - key_tag_version = if key.to_s.end_with?("_or_later") - key.to_s[/(\w+)_or_later$/, 1].to_sym - else - key + key_tag_version = tag_without_or_later(key) + begin + MacOS::Version.from_symbol(key_tag_version) <= tag_version + rescue ArgumentError + false end - MacOS::Version.from_symbol(key_tag_version) <= tag_version end end end diff --git a/Library/Homebrew/extend/os/requirements/non_binary_osxfuse_requirement.rb b/Library/Homebrew/extend/os/requirements/non_binary_osxfuse_requirement.rb deleted file mode 100644 index 099f29382c..0000000000 --- a/Library/Homebrew/extend/os/requirements/non_binary_osxfuse_requirement.rb +++ /dev/null @@ -1,3 +0,0 @@ -if OS.mac? - require "extend/os/mac/requirements/non_binary_osxfuse_requirement" -end diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb index 1f67eab52b..513e112908 100644 --- a/Library/Homebrew/extend/pathname.rb +++ b/Library/Homebrew/extend/pathname.rb @@ -165,13 +165,14 @@ class Pathname # The enclosing `mktmpdir` and the `chmod` are a workaround # for https://github.com/rails/rails/pull/34037. Dir.mktmpdir(".d", dirname) do |tmpdir| + should_fix_sticky_bit = dirname.world_writable? && !dirname.sticky? + FileUtils.chmod "+t", dirname if should_fix_sticky_bit begin - FileUtils.chmod "+t", dirname - rescue Errno::EPERM - :ignore - end - File.atomic_write(self, tmpdir) do |file| - file.write(content) + File.atomic_write(self, tmpdir) do |file| + file.write(content) + end + ensure + FileUtils.chmod "-t", dirname if should_fix_sticky_bit end end end diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 83d7c7e876..655eca1860 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -2532,7 +2532,6 @@ class Formula # version '4.8.1' # end def fails_with(compiler, &block) - odisabled "fails_with :llvm" if compiler == :llvm specs.each { |spec| spec.fails_with(compiler, &block) } end diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index 9a86aa085c..c49bf2008a 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -489,14 +489,20 @@ class FormulaInstaller end end - if pour_bottle && !Keg.relocation_formulae.include?(formula.name) - bottle_deps = Keg.relocation_formulae - .map { |formula| Dependency.new(formula) } - .reject do |dep| + if pour_bottle && !Keg.bottle_dependencies.empty? + bottle_deps = if !Keg.bottle_dependencies.include?(formula.name) + Keg.bottle_dependencies + elsif !Keg.relocation_formulae.include?(formula.name) + Keg.relocation_formulae + else + [] + end + bottle_deps = bottle_deps.map { |formula| Dependency.new(formula) } + .reject do |dep| inherited_options[dep.name] |= inherited_options_for(dep) dep.satisfied? inherited_options[dep.name] end - expanded_deps = Dependency.merge_repeats(bottle_deps + expanded_deps) unless bottle_deps.empty? + expanded_deps = Dependency.merge_repeats(bottle_deps + expanded_deps) end expanded_deps.map { |dep| [dep, inherited_options[dep.name]] } diff --git a/Library/Homebrew/global.rb b/Library/Homebrew/global.rb index 9d09992835..da3c600332 100644 --- a/Library/Homebrew/global.rb +++ b/Library/Homebrew/global.rb @@ -54,7 +54,7 @@ HOMEBREW_USER_AGENT_FAKE_SAFARI = # `HOMEBREW_BOTTLE_DEFAULT_DOMAIN` isn't set. HOMEBREW_BOTTLE_DEFAULT_DOMAIN = if ENV["HOMEBREW_BOTTLE_DEFAULT_DOMAIN"] ENV["HOMEBREW_BOTTLE_DEFAULT_DOMAIN"] -elsif OS.mac? +elsif OS.mac? || ENV["HOMEBREW_FORCE_HOMEBREW_ON_LINUX"] "https://homebrew.bintray.com".freeze else "https://linuxbrew.bintray.com".freeze diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index 032f3e2e1e..d36faf5a0a 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -66,7 +66,7 @@ class Keg LOCALEDIR_RX = %r{(locale|man)/([a-z]{2}|C|POSIX)(_[A-Z]{2})?(\.[a-zA-Z\-0-9]+(@.+)?)?} INFOFILE_RX = %r{info/([^.].*?\.info|dir)$} KEG_LINK_DIRECTORIES = %w[ - bin etc include lib sbin share var Frameworks + bin etc include lib sbin share var ].freeze MUST_EXIST_SUBDIRECTORIES = ( KEG_LINK_DIRECTORIES - %w[var] + %w[ @@ -672,3 +672,5 @@ class Keg end end end + +require "extend/os/keg" diff --git a/Library/Homebrew/keg_relocate.rb b/Library/Homebrew/keg_relocate.rb index 6320a61bda..89bad8c3fb 100644 --- a/Library/Homebrew/keg_relocate.rb +++ b/Library/Homebrew/keg_relocate.rb @@ -187,6 +187,10 @@ class Keg def self.relocation_formulae [] end + + def self.bottle_dependencies + relocation_formulae + end end require "extend/os/keg_relocate" diff --git a/Library/Homebrew/manpages/brew.1.md.erb b/Library/Homebrew/manpages/brew.1.md.erb index b17b10a47a..3488c08878 100644 --- a/Library/Homebrew/manpages/brew.1.md.erb +++ b/Library/Homebrew/manpages/brew.1.md.erb @@ -10,7 +10,7 @@ # When done, regenerate the man page and its HTML version by running `brew man`. %> brew(1) -- The missing package manager for macOS -=============================================== +================================================ ## SYNOPSIS @@ -105,6 +105,7 @@ can take several different forms: The formula file will be cached for later use. ## ENVIRONMENT + Note that environment variables must have a value set to be detected. For example, `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just `export HOMEBREW_NO_INSECURE_REDIRECT`. * `HOMEBREW_ARTIFACT_DOMAIN`: @@ -180,22 +181,16 @@ Note that environment variables must have a value set to be detected. For exampl editors will do strange things in this case. * `HOMEBREW_FORCE_BREWED_CURL`: - If set, Homebrew will use a Homebrew-installed `curl` rather than the - system version. + If set, Homebrew will always use a Homebrew-installed `curl` rather than the + system version. Automatically set if the system version of `curl` is too old. * `HOMEBREW_FORCE_VENDOR_RUBY`: If set, Homebrew will always use its vendored, relocatable Ruby version even if the system version of Ruby is new enough. - * `HOMEBREW_GIT`: - When using Git, Homebrew will use `GIT` if set, - a Homebrew-built Git if installed, or the system-provided binary. - - Set this to force Homebrew to use a particular git binary. - * `HOMEBREW_FORCE_BREWED_GIT`: - If set, Homebrew will use a Homebrew-installed `git` rather than the - system version. + If set, Homebrew will always use a Homebrew-installed `git` rather than the + system version. Automatically set if the system version of `git` is too old. * `HOMEBREW_GITHUB_API_TOKEN`: A personal access token for the GitHub API, which you can create at diff --git a/Library/Homebrew/os/linux/global.rb b/Library/Homebrew/os/linux/global.rb index d29e194116..67d80e4560 100644 --- a/Library/Homebrew/os/linux/global.rb +++ b/Library/Homebrew/os/linux/global.rb @@ -1,3 +1,7 @@ module Homebrew - DEFAULT_PREFIX = "/home/linuxbrew/.linuxbrew".freeze + DEFAULT_PREFIX = if ENV["HOMEBREW_FORCE_HOMEBREW_ON_LINUX"] + "/usr/local".freeze + else + "/home/linuxbrew/.linuxbrew".freeze + end end diff --git a/Library/Homebrew/requirement.rb b/Library/Homebrew/requirement.rb index f9e8bf9581..97c6fe6cb5 100644 --- a/Library/Homebrew/requirement.rb +++ b/Library/Homebrew/requirement.rb @@ -150,10 +150,6 @@ class Requirement attr_reader :env_proc, :build attr_rw :fatal, :cask, :download - def default_formula(_val = nil) - odisabled "Requirement.default_formula" - end - def satisfy(options = nil, &block) return @satisfied if options.nil? && !block_given? diff --git a/Library/Homebrew/requirements.rb b/Library/Homebrew/requirements.rb index 6128db5163..0173017e87 100644 --- a/Library/Homebrew/requirements.rb +++ b/Library/Homebrew/requirements.rb @@ -1,11 +1,11 @@ require "requirement" +require "requirements/arch_requirement" +require "requirements/codesign_requirement" +require "requirements/java_requirement" require "requirements/linux_requirement" require "requirements/macos_requirement" require "requirements/maximum_macos_requirement" require "requirements/osxfuse_requirement" -require "requirements/java_requirement" require "requirements/tuntap_requirement" -require "requirements/unsigned_kext_requirement" require "requirements/x11_requirement" -require "requirements/arch_requirement" require "requirements/xcode_requirement" diff --git a/Library/Homebrew/requirements/arch_requirement.rb b/Library/Homebrew/requirements/arch_requirement.rb index 0ff52dfa82..0fff93a9ef 100644 --- a/Library/Homebrew/requirements/arch_requirement.rb +++ b/Library/Homebrew/requirements/arch_requirement.rb @@ -3,9 +3,9 @@ require "requirement" class ArchRequirement < Requirement fatal true - def initialize(arch) - @arch = arch.pop - super + def initialize(tags) + @arch = tags.shift + super(tags) end satisfy(build_env: false) do diff --git a/Library/Homebrew/requirements/codesign_requirement.rb b/Library/Homebrew/requirements/codesign_requirement.rb new file mode 100644 index 0000000000..ed6c6988e8 --- /dev/null +++ b/Library/Homebrew/requirements/codesign_requirement.rb @@ -0,0 +1,32 @@ +class CodesignRequirement < Requirement + fatal true + + def initialize(tags) + options = tags.shift + unless options.is_a?(Hash) + raise ArgumentError("CodesignRequirement requires an options Hash!") + end + unless options.key?(:identity) + raise ArgumentError("CodesignRequirement requires an identity key!") + end + + @identity = options.fetch(:identity) + @with = options.fetch(:with, "code signing") + @url = options.fetch(:url, nil) + super(tags) + end + + satisfy(build_env: false) do + mktemp do + FileUtils.cp "/usr/bin/false", "codesign_check" + quiet_system "/usr/bin/codesign", "-f", "-s", @identity, + "--dryrun", "codesign_check" + end + end + + def message + message = "#{@identity} identity must be available to build with #{@with}" + message += ":\n#{@url}" if @url.present? + message + end +end diff --git a/Library/Homebrew/requirements/java_requirement.rb b/Library/Homebrew/requirements/java_requirement.rb index fce7f57dbd..9c6062f0a3 100644 --- a/Library/Homebrew/requirements/java_requirement.rb +++ b/Library/Homebrew/requirements/java_requirement.rb @@ -27,7 +27,7 @@ class JavaRequirement < Requirement def initialize(tags = []) @version = tags.shift if /(\d+\.)+\d/ =~ tags.first - super + super(tags) end def message @@ -39,7 +39,7 @@ class JavaRequirement < Requirement end def inspect - "#<#{self.class.name}: #{name.inspect} #{tags.inspect} version=#{@version.inspect}>" + "#<#{self.class.name}: #{tags.inspect} version=#{@version.inspect}>" end def display_s diff --git a/Library/Homebrew/requirements/macos_requirement.rb b/Library/Homebrew/requirements/macos_requirement.rb index 37c53cf108..7f40d37fed 100644 --- a/Library/Homebrew/requirements/macos_requirement.rb +++ b/Library/Homebrew/requirements/macos_requirement.rb @@ -4,8 +4,8 @@ class MacOSRequirement < Requirement fatal true def initialize(tags = []) - @version = MacOS::Version.from_symbol(tags.first) unless tags.empty? - super + @version = MacOS::Version.from_symbol(tags.shift) unless tags.empty? + super(tags) end def minimum_version_specified? diff --git a/Library/Homebrew/requirements/maximum_macos_requirement.rb b/Library/Homebrew/requirements/maximum_macos_requirement.rb index 9a8851390f..4dd7fd73d5 100644 --- a/Library/Homebrew/requirements/maximum_macos_requirement.rb +++ b/Library/Homebrew/requirements/maximum_macos_requirement.rb @@ -4,8 +4,8 @@ class MaximumMacOSRequirement < Requirement fatal true def initialize(tags) - @version = MacOS::Version.from_symbol(tags.first) - super + @version = MacOS::Version.from_symbol(tags.shift) + super(tags) end satisfy(build_env: false) { MacOS.version <= @version } diff --git a/Library/Homebrew/requirements/non_binary_osxfuse_requirement.rb b/Library/Homebrew/requirements/non_binary_osxfuse_requirement.rb deleted file mode 100644 index bb7788f487..0000000000 --- a/Library/Homebrew/requirements/non_binary_osxfuse_requirement.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "requirement" - -class NonBinaryOsxfuseRequirement < Requirement - fatal false -end - -require "extend/os/requirements/non_binary_osxfuse_requirement" diff --git a/Library/Homebrew/requirements/unsigned_kext_requirement.rb b/Library/Homebrew/requirements/unsigned_kext_requirement.rb deleted file mode 100644 index b58a20ea6c..0000000000 --- a/Library/Homebrew/requirements/unsigned_kext_requirement.rb +++ /dev/null @@ -1,16 +0,0 @@ -require "requirement" - -class UnsignedKextRequirement < Requirement - fatal true - - satisfy(build_env: false) { MacOS.version < :yosemite } - - def message - s = <<~EOS - Building this formula from source isn't possible due to OS X - Yosemite (10.10) and above's strict unsigned kext ban. - EOS - s += super - s - end -end diff --git a/Library/Homebrew/requirements/x11_requirement.rb b/Library/Homebrew/requirements/x11_requirement.rb index b7de5a2848..539d374804 100644 --- a/Library/Homebrew/requirements/x11_requirement.rb +++ b/Library/Homebrew/requirements/x11_requirement.rb @@ -10,13 +10,6 @@ class X11Requirement < Requirement env { ENV.x11 } - def initialize(name = "x11", tags = []) - @name = name - # no-op on version specified as a tag argument - tags.shift if /(\d\.)+\d/ =~ tags.first - super(tags) - end - def min_version "1.12.2" end @@ -51,7 +44,7 @@ class X11Requirement < Requirement end def inspect - "#<#{self.class.name}: #{name.inspect} #{tags.inspect}>" + "#<#{self.class.name}: #{tags.inspect}>" end end diff --git a/Library/Homebrew/requirements/xcode_requirement.rb b/Library/Homebrew/requirements/xcode_requirement.rb index ac6744e2a5..2cafe29d50 100644 --- a/Library/Homebrew/requirements/xcode_requirement.rb +++ b/Library/Homebrew/requirements/xcode_requirement.rb @@ -6,8 +6,8 @@ class XcodeRequirement < Requirement satisfy(build_env: false) { xcode_installed_version } def initialize(tags = []) - @version = tags.find { |tag| tags.delete(tag) if tag =~ /(\d\.)+\d/ } - super + @version = tags.shift if tags.first.to_s.match?(/(\d\.)+\d/) + super(tags) end def xcode_installed_version @@ -40,6 +40,6 @@ class XcodeRequirement < Requirement end def inspect - "#<#{self.class.name}: #{name.inspect} #{tags.inspect} version=#{@version.inspect}>" + "#<#{self.class.name}: #{tags.inspect} version=#{@version.inspect}>" end end diff --git a/Library/Homebrew/rubocops.rb b/Library/Homebrew/rubocops.rb index b5dd08187b..aed555d72a 100644 --- a/Library/Homebrew/rubocops.rb +++ b/Library/Homebrew/rubocops.rb @@ -1,5 +1,6 @@ require_relative "load_path" +require "rubocop-rspec" require "rubocops/formula_desc_cop" require "rubocops/components_order_cop" require "rubocops/components_redundancy_cop" diff --git a/Library/Homebrew/rubocops/options_cop.rb b/Library/Homebrew/rubocops/options_cop.rb index ddd08e6866..98b6002f52 100644 --- a/Library/Homebrew/rubocops/options_cop.rb +++ b/Library/Homebrew/rubocops/options_cop.rb @@ -6,6 +6,7 @@ module RuboCop # This cop audits `options` in Formulae. class Options < FormulaCop DEPRECATION_MSG = "macOS has been 64-bit only since 10.6 so 32-bit options are deprecated.".freeze + UNI_DEPRECATION_MSG = "macOS has been 64-bit only since 10.6 so universal options are deprecated.".freeze def audit_formula(_node, _class_node, _parent_class_node, body_node) option_call_nodes = find_every_method_call_by_name(body_node, :option) @@ -13,20 +14,11 @@ module RuboCop option = parameters(option_call).first problem DEPRECATION_MSG if regex_match_group(option, /32-bit/) end - end - end - end - module FormulaAuditStrict - class Options < FormulaCop - DEPRECATION_MSG = "macOS has been 64-bit only since 10.6 so universal options are deprecated.".freeze - - def audit_formula(_node, _class_node, _parent_class_node, body_node) - option_call_nodes = find_every_method_call_by_name(body_node, :option) option_call_nodes.each do |option_call| offending_node(option_call) option = string_content(parameters(option_call).first) - problem DEPRECATION_MSG if option == "universal" + problem UNI_DEPRECATION_MSG if option == "universal" if option !~ /with(out)?-/ && option != "cxx11" && diff --git a/Library/Homebrew/rubocops/urls_cop.rb b/Library/Homebrew/rubocops/urls_cop.rb index 8ef40e9144..76713d5a3b 100644 --- a/Library/Homebrew/rubocops/urls_cop.rb +++ b/Library/Homebrew/rubocops/urls_cop.rb @@ -43,6 +43,7 @@ module RuboCop %r{^http://code\.google\.com/}, %r{^http://fossies\.org/}, %r{^http://mirrors\.kernel\.org/}, + %r{^http://mirrors\.ocf\.berkeley\.edu/}, %r{^http://(?:[^/]*\.)?bintray\.com/}, %r{^http://tools\.ietf\.org/}, %r{^http://launchpad\.net/}, @@ -125,10 +126,19 @@ module RuboCop problem <<~EOS Please use a secure mirror for Debian URLs. We recommend: - https://mirrors.ocf.berkeley.edu/debian/#{match[1]} + https://deb.debian.org/debian/#{match[1]} EOS end + # Check to use canonical urls for Debian packages + noncanon_deb_pattern = + Regexp.union([%r{^https://mirrors\.kernel\.org/debian/}, + %r{^https://mirrors\.ocf\.berkeley\.edu/debian/}, + %r{^https://(?:[^/]*\.)?mirrorservice\.org/sites/ftp\.debian\.org/debian/}]) + audit_urls(urls, noncanon_deb_pattern) do |_, url| + problem "Please use https://deb.debian.org/debian/ for #{url}" + end + # Check for new-url Google Code download urls, https:// is preferred google_code_pattern = Regexp.union([%r{^http://.*\.googlecode\.com/files.*}, %r{^http://code\.google\.com/}]) diff --git a/Library/Homebrew/shims/scm/git b/Library/Homebrew/shims/scm/git index 0930c0adc3..c4e7ec5134 100755 --- a/Library/Homebrew/shims/scm/git +++ b/Library/Homebrew/shims/scm/git @@ -1,6 +1,6 @@ #!/bin/bash -# This script because we support $GIT, $HOMEBREW_SVN, etc., Xcode-only and +# This script because we support $HOMEBREW_GIT, $HOMEBREW_SVN, etc., Xcode-only and # no Xcode/CLT configurations. Order is careful to be what the user would want. set +o posix diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb index 59a351a1b5..49b9e49f8c 100644 --- a/Library/Homebrew/software_spec.rb +++ b/Library/Homebrew/software_spec.rb @@ -212,7 +212,6 @@ class SoftwareSpec end def fails_with(compiler, &block) - odisabled "fails_with :llvm" if compiler == :llvm compiler_failures << CompilerFailure.create(compiler, &block) end diff --git a/Library/Homebrew/system_config.rb b/Library/Homebrew/system_config.rb index 23cdbffcef..f5ed7bd37c 100644 --- a/Library/Homebrew/system_config.rb +++ b/Library/Homebrew/system_config.rb @@ -123,7 +123,6 @@ class SystemConfig HOMEBREW_CACHE: "#{ENV["HOME"]}/Library/Caches/Homebrew", HOMEBREW_TEMP: ENV["HOMEBREW_SYSTEM_TEMP"], HOMEBREW_RUBY_WARNINGS: "-W0", - HOMEBREW_GIT: "git", }.freeze boring_keys = %w[ HOMEBREW_BROWSER @@ -137,10 +136,12 @@ class SystemConfig HOMEBREW_BREW_FILE HOMEBREW_COMMAND_DEPTH HOMEBREW_CURL + HOMEBREW_GIT HOMEBREW_GIT_CONFIG_FILE HOMEBREW_LIBRARY HOMEBREW_MACOS_VERSION HOMEBREW_MACOS_VERSION_NUMERIC + HOMEBREW_MINIMUM_GIT_VERSION HOMEBREW_RUBY_PATH HOMEBREW_SYSTEM HOMEBREW_SYSTEM_TEMP @@ -168,9 +169,6 @@ class SystemConfig if defaults_hash[:HOMEBREW_RUBY_WARNINGS] != ENV["HOMEBREW_RUBY_WARNINGS"].to_s f.puts "HOMEBREW_RUBY_WARNINGS: #{ENV["HOMEBREW_RUBY_WARNINGS"]}" end - if defaults_hash[:HOMEBREW_GIT] != ENV["HOMEBREW_GIT"].to_s - f.puts "HOMEBREW_GIT: #{ENV["HOMEBREW_GIT"]}" - end unless ENV["HOMEBREW_ENV"] ENV.sort.each do |key, value| next unless key.start_with?("HOMEBREW_") diff --git a/Library/Homebrew/test/.rubocop_todo.yml b/Library/Homebrew/test/.rubocop_todo.yml index c3bbe7dc26..6666df7549 100644 --- a/Library/Homebrew/test/.rubocop_todo.yml +++ b/Library/Homebrew/test/.rubocop_todo.yml @@ -121,17 +121,6 @@ RSpec/RepeatedDescription: - 'rubocops/lines_cop_spec.rb' - 'tab_spec.rb' -# Offense count: 10 -RSpec/RepeatedExample: - Exclude: - - 'compiler_selector_spec.rb' - - 'utils/shell_spec.rb' - -# Offense count: 2 -RSpec/ScatteredLet: - Exclude: - - 'cask/artifact/uninstall_zap_shared_examples.rb' - # Offense count: 31 RSpec/SubjectStub: Exclude: diff --git a/Library/Homebrew/test/Gemfile b/Library/Homebrew/test/Gemfile index 6ff11dc88d..74f7fe4225 100644 --- a/Library/Homebrew/test/Gemfile +++ b/Library/Homebrew/test/Gemfile @@ -8,7 +8,6 @@ gem "rspec-its", require: false gem "rspec-retry", require: false gem "rspec-wait", require: false gem "rubocop", HOMEBREW_RUBOCOP_VERSION -gem "rubocop-rspec", require: false group :development do gem "ronn", require: false diff --git a/Library/Homebrew/test/Gemfile.lock b/Library/Homebrew/test/Gemfile.lock index ed4e215f91..044db4dd5c 100644 --- a/Library/Homebrew/test/Gemfile.lock +++ b/Library/Homebrew/test/Gemfile.lock @@ -13,9 +13,9 @@ GEM json (2.1.0) mustache (1.1.0) parallel (1.12.1) - parallel_tests (2.23.0) + parallel_tests (2.26.0) parallel - parser (2.5.1.2) + parser (2.5.3.0) ast (~> 2.4.0) powerpack (0.1.2) rainbow (3.0.0) @@ -52,8 +52,6 @@ GEM rainbow (>= 2.2.2, < 4.0) ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) - rubocop-rspec (1.30.0) - rubocop (>= 0.58.0) ruby-progressbar (1.10.0) simplecov (0.16.1) docile (~> 1.1) @@ -77,7 +75,6 @@ DEPENDENCIES rspec-retry rspec-wait rubocop (= 0.59.1) - rubocop-rspec simplecov simplecov-cobertura diff --git a/Library/Homebrew/test/cask/artifact/uninstall_zap_shared_examples.rb b/Library/Homebrew/test/cask/artifact/uninstall_zap_shared_examples.rb index 56a8408360..650b275e13 100644 --- a/Library/Homebrew/test/cask/artifact/uninstall_zap_shared_examples.rb +++ b/Library/Homebrew/test/cask/artifact/uninstall_zap_shared_examples.rb @@ -158,6 +158,8 @@ shared_examples "#uninstall_phase or #zap_phase" do let(:glob_path1) { Pathname.new("#{dir}/glob_path1") } let(:glob_path2) { Pathname.new("#{dir}/glob_path2") } let(:paths) { [absolute_path, path_with_tilde, glob_path1, glob_path2] } + let(:fake_system_command) { NeverSudoSystemCommand } + let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-#{directive}")) } around(:each) do |example| begin @@ -171,9 +173,6 @@ shared_examples "#uninstall_phase or #zap_phase" do end end - let(:fake_system_command) { NeverSudoSystemCommand } - let(:cask) { Cask::CaskLoader.load(cask_path("with-#{artifact_dsl_key}-#{directive}")) } - before(:each) do allow_any_instance_of(Cask::Artifact::AbstractUninstall).to receive(:trash_paths) .and_wrap_original do |method, *args| diff --git a/Library/Homebrew/test/cli_parser_spec.rb b/Library/Homebrew/test/cli_parser_spec.rb index a2f294e78e..891de621eb 100644 --- a/Library/Homebrew/test/cli_parser_spec.rb +++ b/Library/Homebrew/test/cli_parser_spec.rb @@ -46,6 +46,11 @@ describe Homebrew::CLI::Parser do parser.parse([]) expect(Homebrew.args.pry?).to be true end + + it ":verbose with custom description" do + _, _, _, desc = parser.processed_options.find { |short, _| short == "-v" } + expect(desc).to eq "Flag for verbosity" + end end describe "test long flag options" do @@ -71,6 +76,20 @@ describe Homebrew::CLI::Parser do end end + describe "test short flag options" do + subject(:parser) { + described_class.new do + flag "-f", "--filename=", description: "Name of the file" + end + } + + it "parses a short flag option with its argument" do + parser.parse(["--filename=random.txt"]) + expect(Homebrew.args.filename).to eq "random.txt" + expect(Homebrew.args.f).to eq "random.txt" + end + end + describe "test constraints for flag options" do subject(:parser) { described_class.new do @@ -158,4 +177,18 @@ describe Homebrew::CLI::Parser do expect(Homebrew.args.switch_b?).to be true end end + + describe "test immutability of args" do + subject(:parser) { + described_class.new do + switch "-a", "--switch-a" + switch "-b", "--switch-b" + end + } + + it "raises exception upon Homebrew.args mutation" do + parser.parse(["--switch-a"]) + expect { parser.parse(["--switch-b"]) }.to raise_error(RuntimeError, /can't modify frozen OpenStruct/) + end + end end diff --git a/Library/Homebrew/test/cmd/info_spec.rb b/Library/Homebrew/test/cmd/info_spec.rb index 2d091de2ed..b318576e63 100644 --- a/Library/Homebrew/test/cmd/info_spec.rb +++ b/Library/Homebrew/test/cmd/info_spec.rb @@ -23,6 +23,13 @@ end describe Homebrew do let(:remote) { "https://github.com/Homebrew/homebrew-core" } + specify "::analytics_table" do + results = { ack: 10, wget: 100 } + expect { subject.analytics_table("install", "30", results) } + .to output(/110 | 100.00%/).to_stdout + .and not_to_output.to_stderr + end + specify "::github_remote_path" do expect(subject.github_remote_path(remote, "Formula/git.rb")) .to eq("https://github.com/Homebrew/homebrew-core/blob/master/Formula/git.rb") diff --git a/Library/Homebrew/test/compiler_selector_spec.rb b/Library/Homebrew/test/compiler_selector_spec.rb index 784fdbc5bf..1a0be87545 100644 --- a/Library/Homebrew/test/compiler_selector_spec.rb +++ b/Library/Homebrew/test/compiler_selector_spec.rb @@ -27,29 +27,10 @@ describe CompilerSelector do end describe "#compiler" do - it "raises an error if no matching compiler can be found" do - software_spec.fails_with(:clang) - software_spec.fails_with(:gcc_4_2) - software_spec.fails_with(gcc: "4.8") - software_spec.fails_with(gcc: "4.7") - - expect { subject.compiler }.to raise_error(CompilerSelectionError) - end - it "defaults to cc" do expect(subject.compiler).to eq(cc) end - it "returns gcc if it fails with clang" do - software_spec.fails_with(:clang) - expect(subject.compiler).to eq(:gcc_4_2) - end - - it "returns clang if it fails with gcc" do - software_spec.fails_with(:gcc_4_2) - expect(subject.compiler).to eq(:clang) - end - it "returns clang if it fails with non-Apple gcc" do software_spec.fails_with(gcc: "4.8") expect(subject.compiler).to eq(:clang) @@ -84,23 +65,7 @@ describe CompilerSelector do expect(subject.compiler).to eq("gcc-4.7") end - it "prefers gcc" do - software_spec.fails_with(:clang) - software_spec.fails_with(:gcc_4_2) - expect(subject.compiler).to eq("gcc-4.8") - end - - it "raises an error when gcc is missing" do - allow(versions).to receive(:gcc_4_2_build_version).and_return(Version::NULL) - - software_spec.fails_with(:clang) - software_spec.fails_with(gcc: "4.8") - software_spec.fails_with(gcc: "4.7") - - expect { subject.compiler }.to raise_error(CompilerSelectionError) - end - - it "raises an error when llvm and gcc are missing" do + it "raises an error when gcc or llvm is missing" do allow(versions).to receive(:gcc_4_2_build_version).and_return(Version::NULL) software_spec.fails_with(:clang) diff --git a/Library/Homebrew/test/dependency_collector_spec.rb b/Library/Homebrew/test/dependency_collector_spec.rb index a09d51eacc..37ee477b75 100644 --- a/Library/Homebrew/test/dependency_collector_spec.rb +++ b/Library/Homebrew/test/dependency_collector_spec.rb @@ -38,7 +38,7 @@ describe DependencyCollector do end specify "requirement tags" do - subject.add x11: "2.5.1" + subject.add :x11 subject.add xcode: :build expect(find_requirement(X11Requirement).tags).to be_empty expect(find_requirement(XcodeRequirement)).to be_a_build_requirement diff --git a/Library/Homebrew/test/dev-cmd/bottle_spec.rb b/Library/Homebrew/test/dev-cmd/bottle_spec.rb index b31f557bf2..fceb87b5b0 100644 --- a/Library/Homebrew/test/dev-cmd/bottle_spec.rb +++ b/Library/Homebrew/test/dev-cmd/bottle_spec.rb @@ -8,7 +8,7 @@ describe "brew bottle", :integration_test do (HOMEBREW_CELLAR/"patchelf/1.0/bin").mkpath expect { brew "bottle", "--no-rebuild", testball } - .to output(/Formula not from core or any taps/).to_stderr + .to output(/Formula not from core or any installed taps/).to_stderr .and not_to_output.to_stdout .and be_a_failure diff --git a/Library/Homebrew/test/formula_installer_bottle_spec.rb b/Library/Homebrew/test/formula_installer_bottle_spec.rb index 28568b57ba..30d19ca3fa 100644 --- a/Library/Homebrew/test/formula_installer_bottle_spec.rb +++ b/Library/Homebrew/test/formula_installer_bottle_spec.rb @@ -18,6 +18,7 @@ describe FormulaInstaller do expect(formula).to pour_bottle stub_formula_loader formula + stub_formula_loader formula("gcc") { url "gcc-1.0" } stub_formula_loader formula("patchelf") { url "patchelf-1.0" } allow(Formula["patchelf"]).to receive(:installed?).and_return(true) described_class.new(formula).install diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index 060315fb03..3d4cb84cdf 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -798,7 +798,7 @@ describe Formula do stub_formula_loader(f1) java = JavaRequirement.new - x11 = X11Requirement.new("x11", [:recommended]) + x11 = X11Requirement.new([:recommended]) xcode = XcodeRequirement.new(["1.0", :optional]) expect(Set.new(f1.recursive_requirements)).to eq(Set[java, x11]) diff --git a/Library/Homebrew/test/formulary_spec.rb b/Library/Homebrew/test/formulary_spec.rb index 62c126d444..14df97fd41 100644 --- a/Library/Homebrew/test/formulary_spec.rb +++ b/Library/Homebrew/test/formulary_spec.rb @@ -138,6 +138,7 @@ describe Formulary do context "with installed Formula" do before do allow(described_class).to receive(:loader_for).and_call_original + stub_formula_loader formula("gcc") { url "gcc-1.0" } stub_formula_loader formula("patchelf") { url "patchelf-1.0" } allow(Formula["patchelf"]).to receive(:installed?).and_return(true) end diff --git a/Library/Homebrew/test/java_requirement_spec.rb b/Library/Homebrew/test/java_requirement_spec.rb index b47593ab12..859c2d9fbb 100644 --- a/Library/Homebrew/test/java_requirement_spec.rb +++ b/Library/Homebrew/test/java_requirement_spec.rb @@ -14,7 +14,7 @@ describe JavaRequirement do describe "#inspect" do subject { described_class.new(%w[1.7+]) } - its(:inspect) { is_expected.to eq('#') } + its(:inspect) { is_expected.to eq('#') } end describe "#display_s" do diff --git a/Library/Homebrew/test/requirements/codesign_requirement_spec.rb b/Library/Homebrew/test/requirements/codesign_requirement_spec.rb new file mode 100644 index 0000000000..5940c6d6f5 --- /dev/null +++ b/Library/Homebrew/test/requirements/codesign_requirement_spec.rb @@ -0,0 +1,21 @@ +require "requirements/codesign_requirement" + +describe CodesignRequirement do + subject(:requirement) { + described_class.new([{ identity: identity, with: with, url: url }]) + } + + let(:identity) { "lldb_codesign" } + let(:with) { "LLDB" } + let(:url) { + "https://llvm.org/svn/llvm-project/lldb/trunk/docs/code-signing.txt" + } + + describe "#message" do + it "includes all parameters" do + expect(requirement.message).to include(identity) + expect(requirement.message).to include(with) + expect(requirement.message).to include(url) + end + end +end diff --git a/Library/Homebrew/test/requirements/non_binary_osxfuse_requirement_spec.rb b/Library/Homebrew/test/requirements/non_binary_osxfuse_requirement_spec.rb deleted file mode 100644 index 84fb448740..0000000000 --- a/Library/Homebrew/test/requirements/non_binary_osxfuse_requirement_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -require "requirements/non_binary_osxfuse_requirement" - -describe NonBinaryOsxfuseRequirement, :needs_macos do - subject { described_class.new([]) } - - describe "#message" do - its(:message) { is_expected.to match("osxfuse is already installed from the binary distribution") } - end -end diff --git a/Library/Homebrew/test/requirements_spec.rb b/Library/Homebrew/test/requirements_spec.rb index 3111a7c9c9..a4c9af3ad9 100644 --- a/Library/Homebrew/test/requirements_spec.rb +++ b/Library/Homebrew/test/requirements_spec.rb @@ -14,13 +14,13 @@ describe Requirements do end it "prefers the larger requirement when merging duplicates" do - subject << X11Requirement.new << X11Requirement.new("x11", %w[2.6]) - expect(subject.to_a).to eq([X11Requirement.new("x11", %w[2.6])]) + subject << X11Requirement.new << X11Requirement.new(%w[2.6]) + expect(subject.to_a).to eq([X11Requirement.new(%w[2.6])]) end it "does not use the smaller requirement when merging duplicates" do - subject << X11Requirement.new("x11", %w[2.6]) << X11Requirement.new - expect(subject.to_a).to eq([X11Requirement.new("x11", %w[2.6])]) + subject << X11Requirement.new(%w[2.6]) << X11Requirement.new + expect(subject.to_a).to eq([X11Requirement.new(%w[2.6])]) end end end diff --git a/Library/Homebrew/test/rubocops/options_cop_spec.rb b/Library/Homebrew/test/rubocops/options_cop_spec.rb index ef0e824bb5..a6942745d0 100644 --- a/Library/Homebrew/test/rubocops/options_cop_spec.rb +++ b/Library/Homebrew/test/rubocops/options_cop_spec.rb @@ -3,21 +3,17 @@ require "rubocops/options_cop" describe RuboCop::Cop::FormulaAudit::Options do subject(:cop) { described_class.new } - it "reports an offense when using the 32-bit option" do - expect_offense(<<~RUBY) - class Foo < Formula - url 'https://example.com/foo-1.0.tgz' - option "32-bit", "with 32-bit" - ^^^^^^ macOS has been 64-bit only since 10.6 so 32-bit options are deprecated. - end - RUBY - end -end + context "When auditing options" do + it "reports an offense when using the 32-bit option" do + expect_offense(<<~RUBY) + class Foo < Formula + url 'https://example.com/foo-1.0.tgz' + option "with-32-bit" + ^^^^^^ macOS has been 64-bit only since 10.6 so 32-bit options are deprecated. + end + RUBY + end -describe RuboCop::Cop::FormulaAuditStrict::Options do - subject(:cop) { described_class.new } - - context "When auditing options strictly" do it "with universal" do expect_offense(<<~RUBY) class Foo < Formula diff --git a/Library/Homebrew/test/rubocops/urls_cop_spec.rb b/Library/Homebrew/test/rubocops/urls_cop_spec.rb index 5664b93ccb..34500a4d22 100644 --- a/Library/Homebrew/test/rubocops/urls_cop_spec.rb +++ b/Library/Homebrew/test/rubocops/urls_cop_spec.rb @@ -76,9 +76,33 @@ describe RuboCop::Cop::FormulaAudit::Urls do "msg" => <<~EOS, Please use a secure mirror for Debian URLs. We recommend: - https://mirrors.ocf.berkeley.edu/debian/dists/foo/ + https://deb.debian.org/debian/dists/foo/ EOS "col" => 2, + }, { + "url" => "https://mirrors.kernel.org/debian/pool/main/n/nc6/foo.tar.gz", + "msg" => "Please use " \ + "https://deb.debian.org/debian/ for " \ + "https://mirrors.kernel.org/debian/pool/main/n/nc6/foo.tar.gz", + "col" => 2, + }, { + "url" => "https://mirrors.ocf.berkeley.edu/debian/pool/main/m/mkcue/foo.tar.gz", + "msg" => "Please use " \ + "https://deb.debian.org/debian/ for " \ + "https://mirrors.ocf.berkeley.edu/debian/pool/main/m/mkcue/foo.tar.gz", + "col" => 2, + }, { + "url" => "https://mirrorservice.org/sites/ftp.debian.org/debian/pool/main/n/netris/foo.tar.gz", + "msg" => "Please use " \ + "https://deb.debian.org/debian/ for " \ + "https://mirrorservice.org/sites/ftp.debian.org/debian/pool/main/n/netris/foo.tar.gz", + "col" => 2, + }, { + "url" => "https://www.mirrorservice.org/sites/ftp.debian.org/debian/pool/main/n/netris/foo.tar.gz", + "msg" => "Please use " \ + "https://deb.debian.org/debian/ for " \ + "https://www.mirrorservice.org/sites/ftp.debian.org/debian/pool/main/n/netris/foo.tar.gz", + "col" => 2, }, { "url" => "http://foo.googlecode.com/files/foo-1.0.zip", "msg" => "Please use https:// for http://foo.googlecode.com/files/foo-1.0.zip", diff --git a/Library/Homebrew/test/spec_helper.rb b/Library/Homebrew/test/spec_helper.rb index 9d30c1e7db..9b49b15b7c 100644 --- a/Library/Homebrew/test/spec_helper.rb +++ b/Library/Homebrew/test/spec_helper.rb @@ -98,7 +98,10 @@ RSpec.configure do |config| end config.before(:each, :needs_svn) do - skip "subversion not installed." unless which "svn" + homebrew_bin = File.dirname HOMEBREW_BREW_FILE + unless %W[/usr/bin/svn #{homebrew_bin}/svn].map { |x| File.executable?(x) }.any? + skip "subversion not installed." + end end config.before(:each, :needs_unzip) do @@ -187,7 +190,7 @@ RSpec::Matchers.define :a_json_string do begin JSON.parse(actual) true - rescue JSON::ParseError + rescue JSON::ParserError false end end diff --git a/Library/Homebrew/test/utils/shell_spec.rb b/Library/Homebrew/test/utils/shell_spec.rb index a9456ae117..f92afd4f26 100644 --- a/Library/Homebrew/test/utils/shell_spec.rb +++ b/Library/Homebrew/test/utils/shell_spec.rb @@ -7,8 +7,8 @@ describe Utils::Shell do expect(subject.profile).to eq("~/.bash_profile") end - it "returns ~/.bash_profile for Sh" do - ENV["SHELL"] = "/bin/another_shell" + it "returns ~/.bash_profile for sh" do + ENV["SHELL"] = "/bin/sh" expect(subject.profile).to eq("~/.bash_profile") end diff --git a/Library/Homebrew/test/x11_requirement_spec.rb b/Library/Homebrew/test/x11_requirement_spec.rb index ef50fdc761..342394bb34 100644 --- a/Library/Homebrew/test/x11_requirement_spec.rb +++ b/Library/Homebrew/test/x11_requirement_spec.rb @@ -10,15 +10,10 @@ describe X11Requirement do end describe "#eql?" do - it "returns true if the names are equal" do - other = described_class.new(default_name) + it "returns true if the requirements are equal" do + other = described_class.new expect(subject).to eql(other) end - - it "and returns false if the names differ" do - other = described_class.new("foo") - expect(subject).not_to eql(other) - end end describe "#modify_build_environment" do diff --git a/Library/Homebrew/unpack_strategy/compress.rb b/Library/Homebrew/unpack_strategy/compress.rb index 952e17c980..d435b9a599 100644 --- a/Library/Homebrew/unpack_strategy/compress.rb +++ b/Library/Homebrew/unpack_strategy/compress.rb @@ -5,7 +5,7 @@ module UnpackStrategy using Magic def self.extensions - [".compress"] + [".Z"] end def self.can_extract?(path) diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb index ba2abe7543..fe10623b40 100644 --- a/Library/Homebrew/utils/github.rb +++ b/Library/Homebrew/utils/github.rb @@ -33,7 +33,7 @@ module GitHub GitHub API Error: #{github_message} Try again in #{pretty_ratelimit_reset(reset)}, or create a personal access token: #{ALL_SCOPES_URL} - and then set the token as: export HOMEBREW_GITHUB_API_TOKEN="your_new_token" + #{Utils::Shell.set_variable_in_profile("HOMEBREW_GITHUB_API_TOKEN", "your_token_here")} EOS end @@ -58,7 +58,7 @@ module GitHub printf "protocol=https\\nhost=github.com\\n" | git credential-osxkeychain erase Or create a personal access token: #{ALL_SCOPES_URL} - and then set the token as: export HOMEBREW_GITHUB_API_TOKEN="your_new_token" + #{Utils::Shell.set_variable_in_profile("HOMEBREW_GITHUB_API_TOKEN", "your_token_here")} EOS end super message @@ -135,16 +135,18 @@ module GitHub Your macOS keychain GitHub credentials do not have sufficient scope! Scopes they need: #{needed_human_scopes} Scopes they have: #{credentials_scopes} - Create a personal access token: #{ALL_SCOPES_URL} - and then set HOMEBREW_GITHUB_API_TOKEN as the authentication method instead. + Create a personal access token: + #{ALL_SCOPES_URL} + #{Utils::Shell.set_variable_in_profile("HOMEBREW_GITHUB_API_TOKEN", "your_token_here")} EOS when :environment onoe <<~EOS Your HOMEBREW_GITHUB_API_TOKEN does not have sufficient scope! Scopes they need: #{needed_human_scopes} Scopes it has: #{credentials_scopes} - Create a new personal access token: #{ALL_SCOPES_URL} - and then set the new HOMEBREW_GITHUB_API_TOKEN as the authentication method instead. + Create a new personal access token: + #{ALL_SCOPES_URL} + #{Utils::Shell.set_variable_in_profile("HOMEBREW_GITHUB_API_TOKEN", "your_token_here")} EOS end end diff --git a/Library/Homebrew/vendor/Gemfile b/Library/Homebrew/vendor/Gemfile index 0ea1675a5a..93cfca2cd7 100644 --- a/Library/Homebrew/vendor/Gemfile +++ b/Library/Homebrew/vendor/Gemfile @@ -5,3 +5,8 @@ gem "concurrent-ruby" gem "backports" gem "plist" gem "ruby-macho" +gem "rubocop-rspec" + +# not actually vendored but used to ensure the version matches here. +require_relative "../constants" +gem "rubocop", HOMEBREW_RUBOCOP_VERSION diff --git a/Library/Homebrew/vendor/Gemfile.lock b/Library/Homebrew/vendor/Gemfile.lock index 7839681024..910bf2da62 100644 --- a/Library/Homebrew/vendor/Gemfile.lock +++ b/Library/Homebrew/vendor/Gemfile.lock @@ -6,16 +6,35 @@ GEM i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) + ast (2.4.0) backports (3.11.4) concurrent-ruby (1.0.5) i18n (1.1.0) concurrent-ruby (~> 1.0) + jaro_winkler (1.5.1) minitest (5.11.3) + parallel (1.12.1) + parser (2.5.1.2) + ast (~> 2.4.0) plist (3.4.0) + powerpack (0.1.2) + rainbow (3.0.0) + rubocop (0.59.1) + jaro_winkler (~> 1.5.1) + parallel (~> 1.10) + parser (>= 2.5, != 2.5.1.1) + powerpack (~> 0.1) + rainbow (>= 2.2.2, < 4.0) + ruby-progressbar (~> 1.7) + unicode-display_width (~> 1.0, >= 1.0.1) + rubocop-rspec (1.30.0) + rubocop (>= 0.58.0) ruby-macho (2.1.0) + ruby-progressbar (1.10.0) thread_safe (0.3.6) tzinfo (1.2.5) thread_safe (~> 0.1) + unicode-display_width (1.4.0) PLATFORMS ruby @@ -25,7 +44,9 @@ DEPENDENCIES backports concurrent-ruby plist + rubocop (= 0.59.1) + rubocop-rspec ruby-macho BUNDLED WITH - 1.16.4 + 1.16.6 diff --git a/Library/Homebrew/vendor/bundle-standalone/bundler/setup.rb b/Library/Homebrew/vendor/bundle-standalone/bundler/setup.rb index 76c3cfbf1f..e5b194b9c4 100644 --- a/Library/Homebrew/vendor/bundle-standalone/bundler/setup.rb +++ b/Library/Homebrew/vendor/bundle-standalone/bundler/setup.rb @@ -9,7 +9,18 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/minitest-5.11.3/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thread_safe-0.3.6/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tzinfo-1.2.5/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/activesupport-5.2.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ast-2.4.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/backports-3.11.4/lib" $:.unshift "#{path}/" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/extensions/universal-darwin-18/2.3.0/jaro_winkler-1.5.1" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/jaro_winkler-1.5.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.12.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-2.5.1.2/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.4.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/powerpack-0.1.2/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.0.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.10.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-1.4.0/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-0.59.1/lib" +$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-1.30.0/lib" $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.1.0/lib" diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/config/default.yml b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/config/default.yml new file mode 100644 index 0000000000..7fc26d8589 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/config/default.yml @@ -0,0 +1,451 @@ +--- +AllCops: + RSpec: + Patterns: + - _spec.rb + - "(?:^|/)spec/" + RSpec/FactoryBot: + Patterns: + - spec/factories.rb + - spec/factories/**/*.rb + - features/support/factories/**/*.rb + +RSpec/AlignLeftLetBrace: + Description: Checks that left braces for adjacent single line lets are aligned. + Enabled: false + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignLeftLetBrace + +RSpec/AlignRightLetBrace: + Description: Checks that right braces for adjacent single line lets are aligned. + Enabled: false + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AlignRightLetBrace + +RSpec/AnyInstance: + Description: Check that instances are not being stubbed globally. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AnyInstance + +RSpec/AroundBlock: + Description: Checks that around blocks actually run the test. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/AroundBlock + +RSpec/Be: + Description: Check for expectations where `be` is used without argument. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Be + +RSpec/BeEql: + Description: Check for expectations where `be(...)` can replace `eql(...)`. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeEql + +RSpec/BeforeAfterAll: + Description: Check that before/after(:all) isn't being used. + Enabled: true + Exclude: + - spec/spec_helper.rb + - spec/rails_helper.rb + - spec/support/**/*.rb + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/BeforeAfterAll + +RSpec/ContextWording: + Description: "`context` block descriptions should start with 'when', or 'with'." + Enabled: true + Prefixes: + - when + - with + - without + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording + +RSpec/DescribeClass: + Description: Check that the first argument to the top level describe is a constant. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeClass + +RSpec/DescribeMethod: + Description: Checks that the second argument to `describe` specifies a method. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeMethod + +RSpec/DescribeSymbol: + Description: Avoid describing symbols. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeSymbol + +RSpec/DescribedClass: + Description: Checks that tests use `described_class`. + SkipBlocks: false + Enabled: true + EnforcedStyle: described_class + SupportedStyles: + - described_class + - explicit + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribedClass + +RSpec/EmptyExampleGroup: + Description: Checks if an example group does not include any tests. + Enabled: true + CustomIncludeMethods: [] + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyExampleGroup + +RSpec/EmptyLineAfterExampleGroup: + Description: Checks if there is an empty line after example group blocks. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExampleGroup + +RSpec/EmptyLineAfterFinalLet: + Description: Checks if there is an empty line after the last let block. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterFinalLet + +RSpec/EmptyLineAfterHook: + Description: Checks if there is an empty line after hook blocks. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterHook + +RSpec/EmptyLineAfterSubject: + Description: Checks if there is an empty line after subject block. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterSubject + +RSpec/ExampleLength: + Description: Checks for long examples. + Enabled: true + Max: 5 + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleLength + +RSpec/ExampleWithoutDescription: + Description: Checks for examples without a description. + Enabled: true + EnforcedStyle: always_allow + SupportedStyles: + - always_allow + - single_line_only + - disallow + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWithoutDescription + +RSpec/ExampleWording: + Description: Checks for common mistakes in example descriptions. + Enabled: true + CustomTransform: + be: is + BE: IS + have: has + HAVE: HAS + IgnoredWords: [] + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExampleWording + +RSpec/ExpectActual: + Description: Checks for `expect(...)` calls containing literal values. + Enabled: true + Exclude: + - spec/routing/**/* + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectActual + +RSpec/ExpectChange: + Description: Checks for consistent style of change matcher. + Enabled: true + EnforcedStyle: method_call + SupportedStyles: + - method_call + - block + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectChange + +RSpec/ExpectInHook: + Enabled: true + Description: Do not use `expect` in hooks such as `before`. + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInHook + +RSpec/ExpectOutput: + Description: Checks for opportunities to use `expect { ... }.to output`. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectOutput + +RSpec/FilePath: + Description: Checks that spec file paths are consistent with the test subject. + Enabled: true + CustomTransform: + RuboCop: rubocop + RSpec: rspec + IgnoreMethods: false + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FilePath + +RSpec/Focus: + Description: Checks if examples are focused. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Focus + +RSpec/HookArgument: + Description: Checks the arguments passed to `before`, `around`, and `after`. + Enabled: true + EnforcedStyle: implicit + SupportedStyles: + - implicit + - each + - example + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HookArgument + +RSpec/HooksBeforeExamples: + Enabled: true + Description: Checks for before/around/after hooks that come after an example. + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HooksBeforeExamples + +RSpec/ImplicitExpect: + Description: Check that a consistent implicit expectation style is used. + Enabled: true + EnforcedStyle: is_expected + SupportedStyles: + - is_expected + - should + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitExpect + +RSpec/ImplicitSubject: + Enabled: true + Description: Checks for usage of implicit subject (`is_expected` / `should`). + EnforcedStyle: single_line_only + SupportedStyles: + - single_line_only + - single_statement_only + - disallow + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitSubject + +RSpec/InstanceSpy: + Description: Checks for `instance_double` used with `have_received`. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceSpy + +RSpec/InstanceVariable: + Description: Checks for instance variable usage in specs. + AssignmentOnly: false + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InstanceVariable + +RSpec/InvalidPredicateMatcher: + Description: Checks invalid usage for predicate matcher. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/InvalidPredicateMatcher + +RSpec/ItBehavesLike: + Description: Checks that only one `it_behaves_like` style is used. + Enabled: true + EnforcedStyle: it_behaves_like + SupportedStyles: + - it_behaves_like + - it_should_behave_like + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ItBehavesLike + +RSpec/IteratedExpectation: + Description: Check that `all` matcher is used instead of iterating over an array. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IteratedExpectation + +RSpec/LeadingSubject: + Description: Enforce that subject is the first definition in the test. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeadingSubject + +RSpec/LetBeforeExamples: + Description: Checks for `let` definitions that come after an example. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetBeforeExamples + +RSpec/LetSetup: + Description: Checks unreferenced `let!` calls being used for test setup. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LetSetup + +RSpec/MessageChain: + Description: Check that chains of messages are not being stubbed. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageChain + +RSpec/MessageExpectation: + Description: Checks for consistent message expectation style. + Enabled: false + EnforcedStyle: allow + SupportedStyles: + - allow + - expect + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageExpectation + +RSpec/MessageSpies: + Description: Checks that message expectations are set using spies. + Enabled: true + EnforcedStyle: have_received + SupportedStyles: + - have_received + - receive + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MessageSpies + +RSpec/MissingExampleGroupArgument: + Description: Checks that the first argument to an example group is not empty. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExampleGroupArgument + +RSpec/MultipleDescribes: + Description: Checks for multiple top level describes. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleDescribes + +RSpec/MultipleExpectations: + Description: Checks if examples contain too many `expect` calls. + Enabled: true + Max: 1 + AggregateFailuresByDefault: false + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleExpectations + +RSpec/MultipleSubjects: + Description: Checks if an example group defines `subject` multiple times. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleSubjects + +RSpec/NamedSubject: + Description: Checks for explicitly referenced test subjects. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NamedSubject + +RSpec/NestedGroups: + Description: Checks for nested example groups. + Enabled: true + Max: 3 + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NestedGroups + +RSpec/NotToNot: + Description: Checks for consistent method usage for negating expectations. + EnforcedStyle: not_to + SupportedStyles: + - not_to + - to_not + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NotToNot + +RSpec/OverwritingSetup: + Enabled: true + Description: Checks if there is a let/subject that overwrites an existing one. + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/OverwritingSetup + +RSpec/Pending: + Enabled: false + Description: Checks for any pending or skipped examples. + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Pending + +RSpec/PredicateMatcher: + Description: Prefer using predicate matcher over using predicate method directly. + Enabled: true + Strict: true + EnforcedStyle: inflected + SupportedStyles: + - inflected + - explicit + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/PredicateMatcher + +RSpec/ReceiveCounts: + Enabled: true + Description: Check for `once` and `twice` receive counts matchers usage. + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveCounts + +RSpec/ReceiveNever: + Enabled: true + Description: Prefer `not_to receive(...)` over `receive(...).never`. + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReceiveNever + +RSpec/RepeatedDescription: + Enabled: true + Description: Check for repeated description strings in example groups. + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedDescription + +RSpec/RepeatedExample: + Enabled: true + Description: Check for repeated examples within example groups. + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/RepeatedExample + +RSpec/ReturnFromStub: + Enabled: true + Description: Checks for consistent style of stub's return setting. + EnforcedStyle: and_return + SupportedStyles: + - and_return + - block + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ReturnFromStub + +RSpec/ScatteredLet: + Description: Checks for let scattered across the example group. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredLet + +RSpec/ScatteredSetup: + Description: Checks for setup scattered across multiple hooks in an example group. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ScatteredSetup + +RSpec/SharedContext: + Description: Checks for proper shared_context and shared_examples usage. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedContext + +RSpec/SharedExamples: + Description: Enforces use of string to titleize shared examples. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SharedExamples + +RSpec/SingleArgumentMessageChain: + Description: Checks that chains of messages contain more than one element. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SingleArgumentMessageChain + +RSpec/SubjectStub: + Description: Checks for stubbed test subjects. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SubjectStub + +RSpec/UnspecifiedException: + Description: Checks for a specified error in checking raised errors. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/UnspecifiedException + +RSpec/VerifiedDoubles: + Description: Prefer using verifying doubles over normal doubles. + Enabled: true + IgnoreNameless: true + IgnoreSymbolicNames: false + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VerifiedDoubles + +RSpec/VoidExpect: + Description: This cop checks void `expect()`. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VoidExpect + +Capybara/CurrentPathExpectation: + Description: Checks that no expectations are set on Capybara's `current_path`. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/CurrentPathExpectation + +Capybara/FeatureMethods: + Description: Checks for consistent method usage in feature specs. + Enabled: true + EnabledMethods: [] + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Capybara/FeatureMethods + +FactoryBot/AttributeDefinedStatically: + Description: Always declare attribute values as blocks. + Enabled: true + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/AttributeDefinedStatically + +FactoryBot/CreateList: + Description: Checks for create_list usage. + Enabled: true + EnforcedStyle: create_list + SupportedStyles: + - create_list + - n_times + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/FactoryBot/CreateList + +Rails/HttpStatus: + Description: Enforces use of symbolic or numeric value to describe HTTP status. + Enabled: true + EnforcedStyle: symbolic + SupportedStyles: + - numeric + - symbolic + StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/Rails/HttpStatus diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop-rspec.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop-rspec.rb new file mode 100644 index 0000000000..0c1719cea9 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop-rspec.rb @@ -0,0 +1,43 @@ +require 'pathname' +require 'yaml' + +require 'rubocop' + +require_relative 'rubocop/rspec' +require_relative 'rubocop/rspec/version' +require_relative 'rubocop/rspec/inject' +require_relative 'rubocop/rspec/node' +require_relative 'rubocop/rspec/top_level_describe' +require_relative 'rubocop/rspec/wording' +require_relative 'rubocop/rspec/util' +require_relative 'rubocop/rspec/language' +require_relative 'rubocop/rspec/language/node_pattern' +require_relative 'rubocop/rspec/concept' +require_relative 'rubocop/rspec/example_group' +require_relative 'rubocop/rspec/example' +require_relative 'rubocop/rspec/hook' +require_relative 'rubocop/cop/rspec/cop' +require_relative 'rubocop/rspec/align_let_brace' +require_relative 'rubocop/rspec/final_end_location' +require_relative 'rubocop/rspec/blank_line_separation' + +RuboCop::RSpec::Inject.defaults! + +require_relative 'rubocop/cop/rspec_cops' + +# We have to register our autocorrect incompatibilies in RuboCop's cops as well +# so we do not hit infinite loops + +module RuboCop + module Cop + module Layout + class ExtraSpacing # rubocop:disable Style/Documentation + def self.autocorrect_incompatible_with + [RSpec::AlignLeftLetBrace, RSpec::AlignRightLetBrace] + end + end + end + end +end + +RuboCop::AST::Node.include(RuboCop::RSpec::Node) diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/align_left_let_brace.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/align_left_let_brace.rb new file mode 100644 index 0000000000..8bbc9658ed --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/align_left_let_brace.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks that left braces for adjacent single line lets are aligned. + # + # @example + # + # # bad + # let(:foobar) { blahblah } + # let(:baz) { bar } + # let(:a) { b } + # + # # good + # let(:foobar) { blahblah } + # let(:baz) { bar } + # let(:a) { b } + # + class AlignLeftLetBrace < Cop + MSG = 'Align left let brace'.freeze + + def self.autocorrect_incompatible_with + [Layout::ExtraSpacing] + end + + def investigate(_processed_source) + return if processed_source.blank? + + token_aligner.offending_tokens.each do |let| + add_offense(let, location: :begin) + end + end + + def autocorrect(let) + lambda do |corrector| + corrector.insert_before( + let.loc.begin, + token_aligner.indent_for(let) + ) + end + end + + private + + def token_aligner + @token_aligner ||= + RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/align_right_let_brace.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/align_right_let_brace.rb new file mode 100644 index 0000000000..7eea9b9bdd --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/align_right_let_brace.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks that right braces for adjacent single line lets are aligned. + # + # @example + # + # # bad + # let(:foobar) { blahblah } + # let(:baz) { bar } + # let(:a) { b } + # + # # good + # let(:foobar) { blahblah } + # let(:baz) { bar } + # let(:a) { b } + # + class AlignRightLetBrace < Cop + MSG = 'Align right let brace'.freeze + + def self.autocorrect_incompatible_with + [Layout::ExtraSpacing] + end + + def investigate(_processed_source) + return if processed_source.blank? + + token_aligner.offending_tokens.each do |let| + add_offense(let, location: :end) + end + end + + def autocorrect(let) + lambda do |corrector| + corrector.insert_before( + let.loc.end, + token_aligner.indent_for(let) + ) + end + end + + private + + def token_aligner + @token_aligner ||= + RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/any_instance.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/any_instance.rb new file mode 100644 index 0000000000..a3890a0914 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/any_instance.rb @@ -0,0 +1,42 @@ +module RuboCop + module Cop + module RSpec + # Check that instances are not being stubbed globally. + # + # Prefer instance doubles over stubbing any instance of a class + # + # @example + # # bad + # describe MyClass do + # before { allow_any_instance_of(MyClass).to receive(:foo) } + # end + # + # # good + # describe MyClass do + # let(:my_instance) { instance_double(MyClass) } + # + # before do + # allow(MyClass).to receive(:new).and_return(my_instance) + # allow(my_instance).to receive(:foo) + # end + # end + class AnyInstance < Cop + MSG = 'Avoid stubbing using `%s`.'.freeze + + def_node_matcher :disallowed_stub, <<-PATTERN + (send _ ${:any_instance :allow_any_instance_of :expect_any_instance_of} ...) + PATTERN + + def on_send(node) + disallowed_stub(node) do |method| + add_offense( + node, + location: :expression, + message: format(MSG, method: method) + ) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/around_block.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/around_block.rb new file mode 100644 index 0000000000..42761e79ea --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/around_block.rb @@ -0,0 +1,71 @@ +module RuboCop + module Cop + module RSpec + # Checks that around blocks actually run the test. + # + # @example + # # bad + # around do + # some_method + # end + # + # around do |test| + # some_method + # end + # + # # good + # around do |test| + # some_method + # test.call + # end + # + # around do |test| + # some_method + # test.run + # end + class AroundBlock < Cop + MSG_NO_ARG = 'Test object should be passed to around block.'.freeze + MSG_UNUSED_ARG = 'You should call `%s.call` '\ + 'or `%s.run`.'.freeze + + def_node_matcher :hook, <<-PATTERN + (block {(send nil? :around) (send nil? :around sym)} (args $...) ...) + PATTERN + + def_node_search :find_arg_usage, <<-PATTERN + {(send $... {:call :run}) (send _ _ $...) (yield $...) (block-pass $...)} + PATTERN + + def on_block(node) + hook(node) do |(example_proxy)| + if example_proxy.nil? + add_no_arg_offense(node) + else + check_for_unused_proxy(node, example_proxy) + end + end + end + + private + + def add_no_arg_offense(node) + add_offense(node, location: :expression, message: MSG_NO_ARG) + end + + def check_for_unused_proxy(block, proxy) + name, = *proxy + + find_arg_usage(block) do |usage| + return if usage.include?(s(:lvar, name)) + end + + add_offense( + proxy, + location: :expression, + message: format(MSG_UNUSED_ARG, arg: name) + ) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/be.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/be.rb new file mode 100644 index 0000000000..1347811b10 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/be.rb @@ -0,0 +1,35 @@ +module RuboCop + module Cop + module RSpec + # Check for expectations where `be` is used without argument. + # + # The `be` matcher is too generic, as it pass on everything that is not + # nil or false. If that is the exact intend, use `be_truthy`. In all other + # cases it's better to specify what exactly is the expected value. + # + # @example + # + # # bad + # expect(foo).to be + # + # # good + # expect(foo).to be_truthy + # expect(foo).to be 1.0 + # expect(foo).to be(true) + # + class Be < Cop + MSG = 'Don\'t use `be` without an argument.'.freeze + + def_node_matcher :be_without_args, <<-PATTERN + (send _ {:to :not_to :to_not} $(send nil? :be)) + PATTERN + + def on_send(node) + be_without_args(node) do |matcher| + add_offense(matcher, location: :selector) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/be_eql.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/be_eql.rb new file mode 100644 index 0000000000..be0ca2858d --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/be_eql.rb @@ -0,0 +1,55 @@ +module RuboCop + module Cop + module RSpec + # Check for expectations where `be(...)` can replace `eql(...)`. + # + # The `be` matcher compares by identity while the `eql` matcher + # compares using `eql?`. Integers, floats, booleans, symbols, and nil + # can be compared by identity and therefore the `be` matcher is + # preferable as it is a more strict test. + # + # @example + # + # # bad + # expect(foo).to eql(1) + # expect(foo).to eql(1.0) + # expect(foo).to eql(true) + # expect(foo).to eql(false) + # expect(foo).to eql(:bar) + # expect(foo).to eql(nil) + # + # # good + # expect(foo).to be(1) + # expect(foo).to be(1.0) + # expect(foo).to be(true) + # expect(foo).to be(false) + # expect(foo).to be(:bar) + # expect(foo).to be(nil) + # + # This cop only looks for instances of `expect(...).to eql(...)`. We + # do not check `to_not` or `not_to` since `!eql?` is more strict + # than `!equal?`. We also do not try to flag `eq` because if + # `a == b`, and `b` is comparable by identity, `a` is still not + # necessarily the same type as `b` since the `#==` operator can + # coerce objects for comparison. + # + class BeEql < Cop + MSG = 'Prefer `be` over `eql`.'.freeze + + def_node_matcher :eql_type_with_identity, <<-PATTERN + (send _ :to $(send nil? :eql {true false int float sym nil_type?})) + PATTERN + + def on_send(node) + eql_type_with_identity(node) do |eql| + add_offense(eql, location: :selector) + end + end + + def autocorrect(node) + ->(corrector) { corrector.replace(node.loc.selector, 'be') } + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/before_after_all.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/before_after_all.rb new file mode 100644 index 0000000000..bf9f93df8d --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/before_after_all.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Check that before/after(:all) isn't being used. + # + # @example + # # bad + # # + # # Faster but risk of state leaking between examples + # # + # describe MyClass do + # before(:all) { Widget.create } + # after(:all) { Widget.delete_all } + # end + # + # # good + # # + # # Slower but examples are properly isolated + # # + # describe MyClass do + # before(:each) { Widget.create } + # after(:each) { Widget.delete_all } + # end + class BeforeAfterAll < Cop + MSG = 'Beware of using `%s` as it may cause state to leak '\ + 'between tests. If you are using `rspec-rails`, and '\ + '`use_transactional_fixtures` is enabled, then records created '\ + 'in `%s` are not automatically rolled back.'.freeze + + def_node_matcher :before_or_after_all, <<-PATTERN + $(send _ {:before :after} (sym {:all :context})) + PATTERN + + def on_send(node) + before_or_after_all(node) do |hook| + add_offense( + node, + location: :expression, + message: format(MSG, hook: hook.source) + ) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb new file mode 100644 index 0000000000..53d2cd638b --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb @@ -0,0 +1,42 @@ +module RuboCop + module Cop + module RSpec + module Capybara + # Checks that no expectations are set on Capybara's `current_path`. + # + # The `have_current_path` matcher (http://www.rubydoc.info/github/ + # teamcapybara/capybara/master/Capybara/RSpecMatchers#have_current_path- + # instance_method) should be used on `page` to set expectations on + # Capybara's current path, since it uses Capybara's waiting + # functionality (https://github.com/teamcapybara/capybara/blob/master/ + # README.md#asynchronous-javascript-ajax-and-friends) which ensures that + # preceding actions (like `click_link`) have completed. + # + # @example + # # bad + # expect(current_path).to eq('/callback') + # expect(page.current_path).to match(/widgets/) + # + # # good + # expect(page).to have_current_path("/callback") + # expect(page).to have_current_path(/widgets/) + # + class CurrentPathExpectation < Cop + MSG = 'Do not set an RSpec expectation on `current_path` in ' \ + 'Capybara feature specs - instead, use the ' \ + '`have_current_path` matcher on `page`'.freeze + + def_node_matcher :expectation_set_on_current_path, <<-PATTERN + (send nil? :expect (send {(send nil? :page) nil?} :current_path)) + PATTERN + + def on_send(node) + expectation_set_on_current_path(node) do + add_offense(node, location: :selector) + end + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/capybara/feature_methods.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/capybara/feature_methods.rb new file mode 100644 index 0000000000..8d60d3a771 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/capybara/feature_methods.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + module Capybara + # Checks for consistent method usage in feature specs. + # + # By default, the cop disables all Capybara-specific methods that have + # the same native RSpec method (e.g. are just aliases). Some teams + # however may prefer using some of the Capybara methods (like `feature`) + # to make it obvious that the test uses Capybara, while still disable + # the rest of the methods, like `given` (alias for `let`), `background` + # (alias for `before`), etc. You can configure which of the methods to + # be enabled by using the EnabledMethods configuration option. + # + # @example + # # bad + # feature 'User logs in' do + # given(:user) { User.new } + # + # background do + # visit new_session_path + # end + # + # scenario 'with OAuth' do + # # ... + # end + # end + # + # # good + # describe 'User logs in' do + # let(:user) { User.new } + # + # before do + # visit new_session_path + # end + # + # it 'with OAuth' do + # # ... + # end + # end + class FeatureMethods < Cop + MSG = 'Use `%s` instead of `%s`.'.freeze + + # https://git.io/v7Kwr + MAP = { + background: :before, + scenario: :it, + xscenario: :xit, + given: :let, + given!: :let!, + feature: :describe + }.freeze + + def_node_matcher :spec?, <<-PATTERN + (block + (send {(const nil? :RSpec) nil?} {:describe :feature} ...) + ...) + PATTERN + + def_node_matcher :feature_method, <<-PATTERN + (block + $(send {(const nil? :RSpec) nil?} ${#{MAP.keys.map(&:inspect).join(' ')}} ...) + ...) + PATTERN + + def on_block(node) + return unless inside_spec?(node) + + feature_method(node) do |send_node, match| + next if enabled?(match) + + add_offense( + send_node, + location: :selector, + message: format(MSG, method: match, replacement: MAP[match]) + ) + end + end + + def autocorrect(node) + lambda do |corrector| + corrector.replace(node.loc.selector, MAP[node.method_name].to_s) + end + end + + private + + def inside_spec?(node) + return spec?(node) if root_node?(node) + + root = node.ancestors.find { |parent| root_node?(parent) } + spec?(root) + end + + def root_node?(node) + node.parent.nil? || root_with_siblings?(node.parent) + end + + def root_with_siblings?(node) + node.begin_type? && node.parent.nil? + end + + def enabled?(method_name) + enabled_methods.include?(method_name) + end + + def enabled_methods + cop_config + .fetch('EnabledMethods', []) + .map(&:to_sym) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/context_wording.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/context_wording.rb new file mode 100644 index 0000000000..1cfed8767c --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/context_wording.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # `context` block descriptions should start with 'when', or 'with'. + # + # @see https://github.com/reachlocal/rspec-style-guide#context-descriptions + # @see http://www.betterspecs.org/#contexts + # + # @example `Prefixes` configuration option, defaults: 'when', 'with', and + # 'without' + # Prefixes: + # - when + # - with + # - without + # - if + # + # @example + # # bad + # context 'the display name not present' do + # # ... + # end + # + # # good + # context 'when the display name is not present' do + # # ... + # end + class ContextWording < Cop + MSG = 'Start context description with %s.'.freeze + + def_node_matcher :context_wording, <<-PATTERN + (block (send _ { :context :shared_context } $(str #bad_prefix?)) ...) + PATTERN + + def on_block(node) + context_wording(node) do |context| + add_offense(context, message: message) + end + end + + private + + def bad_prefix?(description) + !prefixes.include?(description.split.first) + end + + def prefixes + cop_config['Prefixes'] || [] + end + + def message + format(MSG, prefixes: joined_prefixes) + end + + def joined_prefixes + quoted = prefixes.map { |prefix| "'#{prefix}'" } + return quoted.first if quoted.size == 1 + + quoted << "or #{quoted.pop}" + quoted.join(', ') + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/cop.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/cop.rb new file mode 100644 index 0000000000..636333212b --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/cop.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +module RuboCop + module Cop # rubocop:disable Style/Documentation + WorkaroundCop = Cop.dup + + # Clone of the the normal RuboCop::Cop::Cop class so we can rewrite + # the inherited method without breaking functionality + class WorkaroundCop + # Remove the Cop.inherited method to be a noop. Our RSpec::Cop + # class will invoke the inherited hook instead + class << self + undef inherited + def inherited(*) end + end + + # Special case `Module#<` so that the rspec support rubocop exports + # is compatible with our subclass + def self.<(other) + other.equal?(RuboCop::Cop::Cop) || super + end + end + private_constant(:WorkaroundCop) + + module RSpec + # @abstract parent class to rspec cops + # + # The criteria for whether rubocop-rspec analyzes a certain ruby file + # is configured via `AllCops/RSpec`. For example, if you want to + # customize your project to scan all files within a `test/` directory + # then you could add this to your configuration: + # + # @example configuring analyzed paths + # + # AllCops: + # RSpec: + # Patterns: + # - '_test.rb$' + # - '(?:^|/)test/' + class Cop < WorkaroundCop + include RuboCop::RSpec::Language + include RuboCop::RSpec::Language::NodePattern + + DEFAULT_CONFIGURATION = + RuboCop::RSpec::CONFIG.fetch('AllCops').fetch('RSpec') + + DEFAULT_PATTERN_RE = Regexp.union( + DEFAULT_CONFIGURATION.fetch('Patterns') + .map(&Regexp.public_method(:new)) + ) + + # Invoke the original inherited hook so our cops are recognized + def self.inherited(subclass) + RuboCop::Cop::Cop.inherited(subclass) + end + + def relevant_file?(file) + relevant_rubocop_rspec_file?(file) && super + end + + private + + def relevant_rubocop_rspec_file?(file) + rspec_pattern =~ file + end + + def rspec_pattern + if rspec_pattern_config? + Regexp.union(rspec_pattern_config.map(&Regexp.public_method(:new))) + else + DEFAULT_PATTERN_RE + end + end + + def all_cops_config + config + .for_all_cops + end + + def rspec_pattern_config? + return unless all_cops_config.key?('RSpec') + + all_cops_config.fetch('RSpec').key?('Patterns') + end + + def rspec_pattern_config + all_cops_config + .fetch('RSpec', DEFAULT_CONFIGURATION) + .fetch('Patterns') + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/describe_class.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/describe_class.rb new file mode 100644 index 0000000000..ff2211dcf8 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/describe_class.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Check that the first argument to the top level describe is a constant. + # + # @example + # # bad + # describe 'Do something' do + # end + # + # # good + # describe TestedClass do + # end + # + # describe "A feature example", type: :feature do + # end + class DescribeClass < Cop + include RuboCop::RSpec::TopLevelDescribe + + MSG = 'The first argument to describe should be '\ + 'the class or module being tested.'.freeze + + def_node_matcher :valid_describe?, <<-PATTERN + { + (send {(const nil? :RSpec) nil?} :describe const ...) + (send {(const nil? :RSpec) nil?} :describe) + } + PATTERN + + def_node_matcher :describe_with_metadata, <<-PATTERN + (send {(const nil? :RSpec) nil?} :describe + !const + ... + (hash $...)) + PATTERN + + def_node_matcher :rails_metadata?, <<-PATTERN + (pair + (sym :type) + (sym {:request :feature :system :routing :view})) + PATTERN + + def_node_matcher :shared_group?, SharedGroups::ALL.block_pattern + + def on_top_level_describe(node, args) + return if shared_group?(root_node) + return if valid_describe?(node) + + describe_with_metadata(node) do |pairs| + return if pairs.any?(&method(:rails_metadata?)) + end + + add_offense(args.first, location: :expression) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/describe_method.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/describe_method.rb new file mode 100644 index 0000000000..109c556529 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/describe_method.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks that the second argument to `describe` specifies a method. + # + # @example + # # bad + # describe MyClass, 'do something' do + # end + # + # # good + # describe MyClass, '#my_instance_method' do + # end + # + # describe MyClass, '.my_class_method' do + # end + class DescribeMethod < Cop + include RuboCop::RSpec::TopLevelDescribe + include RuboCop::RSpec::Util + + MSG = 'The second argument to describe should be the method '\ + "being tested. '#instance' or '.class'.".freeze + + def on_top_level_describe(_node, (_, second_arg)) + return unless second_arg && second_arg.str_type? + return if second_arg.str_content.start_with?('#', '.') + + add_offense(second_arg, location: :expression) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/describe_symbol.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/describe_symbol.rb new file mode 100644 index 0000000000..95bb0b4c77 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/describe_symbol.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Avoid describing symbols. + # + # @example + # # bad + # describe :my_method do + # # ... + # end + # + # # good + # describe '#my_method' do + # # ... + # end + # + # @see https://github.com/rspec/rspec-core/issues/1610 + class DescribeSymbol < Cop + MSG = 'Avoid describing symbols.'.freeze + + def_node_matcher :describe_symbol?, <<-PATTERN + (send {(const nil? :RSpec) nil?} :describe $sym ...) + PATTERN + + def on_send(node) + describe_symbol?(node) do |match| + add_offense(match, location: :expression) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/described_class.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/described_class.rb new file mode 100644 index 0000000000..cabc766653 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/described_class.rb @@ -0,0 +1,124 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks that tests use `described_class`. + # + # If the first argument of describe is a class, the class is exposed to + # each example via described_class. + # + # This cop can be configured using the `EnforcedStyle` option + # + # @example `EnforcedStyle: described_class` + # # bad + # describe MyClass do + # subject { MyClass.do_something } + # end + # + # # good + # describe MyClass do + # subject { described_class.do_something } + # end + # + # @example `EnforcedStyle: explicit` + # # bad + # describe MyClass do + # subject { described_class.do_something } + # end + # + # # good + # describe MyClass do + # subject { MyClass.do_something } + # end + # + class DescribedClass < Cop + include RuboCop::RSpec::TopLevelDescribe + include ConfigurableEnforcedStyle + + DESCRIBED_CLASS = 'described_class'.freeze + MSG = 'Use `%s` instead of `%s`.'.freeze + + def_node_matcher :common_instance_exec_closure?, <<-PATTERN + (block (send (const nil? {:Class :Module}) :new ...) ...) + PATTERN + + def_node_matcher :rspec_block?, + RuboCop::RSpec::Language::ALL.block_pattern + + def_node_matcher :scope_changing_syntax?, '{def class module}' + + def on_block(node) + # In case the explicit style is used, we needs to remember what's + # being described. Thus, we use an ivar for @described_class. + describe, @described_class, body = described_constant(node) + + return if body.nil? + return unless top_level_describe?(describe) + + find_usage(body) do |match| + add_offense( + match, + location: :expression, + message: message(match.const_name) + ) + end + end + + def autocorrect(node) + replacement = if style == :described_class + DESCRIBED_CLASS + else + @described_class.const_name + end + lambda do |corrector| + corrector.replace(node.loc.expression, replacement) + end + end + + private + + def find_usage(node, &block) + yield(node) if offensive?(node) + + return if scope_change?(node) || node.const_type? + + node.each_child_node do |child| + find_usage(child, &block) + end + end + + def message(offense) + if style == :described_class + format(MSG, replacement: DESCRIBED_CLASS, src: offense) + else + format(MSG, replacement: @described_class.const_name, + src: DESCRIBED_CLASS) + end + end + + def scope_change?(node) + scope_changing_syntax?(node) || + common_instance_exec_closure?(node) || + skippable_block?(node) + end + + def skippable_block?(node) + node.block_type? && !rspec_block?(node) && skip_blocks? + end + + def skip_blocks? + cop_config['SkipBlocks'].equal?(true) + end + + def offensive?(node) + if style == :described_class + node.eql?(@described_class) + else + node.send_type? && node.method_name == :described_class + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_example_group.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_example_group.rb new file mode 100644 index 0000000000..3ee001dd64 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_example_group.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks if an example group does not include any tests. + # + # This cop is configurable using the `CustomIncludeMethods` option + # + # @example usage + # + # # bad + # describe Bacon do + # let(:bacon) { Bacon.new(chunkiness) } + # let(:chunkiness) { false } + # + # context 'extra chunky' do # flagged by rubocop + # let(:chunkiness) { true } + # end + # + # it 'is chunky' do + # expect(bacon.chunky?).to be_truthy + # end + # end + # + # # good + # describe Bacon do + # let(:bacon) { Bacon.new(chunkiness) } + # let(:chunkiness) { false } + # + # it 'is chunky' do + # expect(bacon.chunky?).to be_truthy + # end + # end + # + # @example configuration + # + # # .rubocop.yml + # # RSpec/EmptyExampleGroup: + # # CustomIncludeMethods: + # # - include_tests + # + # # spec_helper.rb + # RSpec.configure do |config| + # config.alias_it_behaves_like_to(:include_tests) + # end + # + # # bacon_spec.rb + # describe Bacon do + # let(:bacon) { Bacon.new(chunkiness) } + # let(:chunkiness) { false } + # + # context 'extra chunky' do # not flagged by rubocop + # let(:chunkiness) { true } + # + # include_tests 'shared tests' + # end + # end + # + class EmptyExampleGroup < Cop + MSG = 'Empty example group detected.'.freeze + + def_node_search :contains_example?, <<-PATTERN + { + #{(Examples::ALL + Includes::ALL).send_pattern} + (send _ #custom_include? ...) + } + PATTERN + + def on_block(node) + return unless example_group?(node) && !contains_example?(node) + + add_offense(node.send_node, location: :expression) + end + + private + + def custom_include?(method_name) + custom_include_methods.include?(method_name) + end + + def custom_include_methods + cop_config + .fetch('CustomIncludeMethods', []) + .map(&:to_sym) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_example_group.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_example_group.rb new file mode 100644 index 0000000000..4279e68eb0 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_example_group.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks if there is an empty line after example group blocks. + # + # @example + # # bad + # RSpec.describe Foo do + # describe '#bar' do + # end + # describe '#baz' do + # end + # end + # + # # good + # RSpec.describe Foo do + # describe '#bar' do + # end + # + # describe '#baz' do + # end + # end + # + class EmptyLineAfterExampleGroup < Cop + include RuboCop::RSpec::BlankLineSeparation + + MSG = 'Add an empty line after `%s`.'.freeze + + def on_block(node) + return unless example_group?(node) + return if last_child?(node) + + missing_separating_line(node) do |location| + add_offense( + node, + location: location, + message: format(MSG, example_group: node.method_name) + ) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_final_let.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_final_let.rb new file mode 100644 index 0000000000..f5f1ba77fa --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_final_let.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks if there is an empty line after the last let block. + # + # @example + # # bad + # let(:foo) { bar } + # let(:something) { other } + # it { does_something } + # + # # good + # let(:foo) { bar } + # let(:something) { other } + # + # it { does_something } + class EmptyLineAfterFinalLet < Cop + include RuboCop::RSpec::BlankLineSeparation + + MSG = 'Add an empty line after the last `let` block.'.freeze + + def on_block(node) + return unless example_group_with_body?(node) + + latest_let = node.body.child_nodes.select { |child| let?(child) }.last + + return if latest_let.nil? + return if last_child?(latest_let) + + missing_separating_line(latest_let) do |location| + add_offense(latest_let, location: location) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_hook.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_hook.rb new file mode 100644 index 0000000000..8ce719f5d1 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_hook.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks if there is an empty line after hook blocks. + # + # @example + # # bad + # before { do_something } + # it { does_something } + # + # # bad + # after { do_something } + # it { does_something } + # + # # bad + # around { |test| test.run } + # it { does_something } + # + # # good + # before { do_something } + # + # it { does_something } + # + # # good + # after { do_something } + # + # it { does_something } + # + # # good + # around { |test| test.run } + # + # it { does_something } + # + class EmptyLineAfterHook < Cop + include RuboCop::RSpec::BlankLineSeparation + + MSG = 'Add an empty line after `%s`.'.freeze + + def on_block(node) + return unless hook?(node) + return if last_child?(node) + + missing_separating_line(node) do |location| + add_offense( + node, + location: location, + message: format(MSG, hook: node.method_name) + ) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_subject.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_subject.rb new file mode 100644 index 0000000000..e41824b2b5 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/empty_line_after_subject.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks if there is an empty line after subject block. + # + # @example + # # bad + # subject(:obj) { described_class } + # let(:foo) { bar } + # + # # good + # subject(:obj) { described_class } + # + # let(:foo) { bar } + class EmptyLineAfterSubject < Cop + include RuboCop::RSpec::BlankLineSeparation + + MSG = 'Add empty line after `subject`.'.freeze + + def on_block(node) + return unless subject?(node) && !in_spec_block?(node) + return if last_child?(node) + + missing_separating_line(node) do |location| + add_offense(node, location: location, message: MSG) + end + end + + private + + def in_spec_block?(node) + node.each_ancestor(:block).any? do |ancestor| + Examples::ALL.include?(ancestor.method_name) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/example_length.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/example_length.rb new file mode 100644 index 0000000000..a867bf530d --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/example_length.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for long examples. + # + # A long example is usually more difficult to understand. Consider + # extracting out some behaviour, e.g. with a `let` block, or a helper + # method. + # + # @example + # # bad + # it do + # service = described_class.new + # more_setup + # more_setup + # result = service.call + # expect(result).to be(true) + # end + # + # # good + # it do + # service = described_class.new + # result = service.call + # expect(result).to be(true) + # end + class ExampleLength < Cop + include CodeLength + + MSG = 'Example has too many lines [%d/%d].'.freeze + + def on_block(node) + return unless example?(node) + + length = code_length(node) + + return unless length > max_length + + add_offense(node, location: :expression, message: message(length)) + end + + private + + def code_length(node) + node.source.lines[1..-2].count { |line| !irrelevant_line(line) } + end + + def message(length) + format(MSG, total: length, max: max_length) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/example_without_description.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/example_without_description.rb new file mode 100644 index 0000000000..fdb7316c08 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/example_without_description.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for examples without a description. + # + # RSpec allows for auto-generated example descriptions when there is no + # description provided or the description is an empty one. + # + # This cop removes empty descriptions. + # It also defines whether auto-generated description is allowed, based + # on the configured style. + # + # This cop can be configured using the `EnforcedStyle` option + # + # @example `EnforcedStyle: always_allow` + # # bad + # it('') { is_expected.to be_good } + # it '' do + # result = service.call + # expect(result).to be(true) + # end + # + # # good + # it { is_expected.to be_good } + # it do + # result = service.call + # expect(result).to be(true) + # end + # + # @example `EnforcedStyle: single_line_only` + # # bad + # it('') { is_expected.to be_good } + # it do + # result = service.call + # expect(result).to be(true) + # end + # + # # good + # it { is_expected.to be_good } + # + # @example `EnforcedStyle: disallow` + # # bad + # it { is_expected.to be_good } + # it do + # result = service.call + # expect(result).to be(true) + # end + class ExampleWithoutDescription < Cop + include ConfigurableEnforcedStyle + + MSG_DEFAULT_ARGUMENT = 'Omit the argument when you want to ' \ + 'have auto-generated description.'.freeze + MSG_ADD_DESCRIPTION = 'Add a description.'.freeze + + def_node_matcher :example_description, '(send nil? _ $(str $_))' + + def on_block(node) + return unless example?(node) + + check_example_without_description(node.send_node) + + example_description(node.send_node) do |message_node, message| + return unless message.to_s.empty? + + add_offense(message_node, message: MSG_DEFAULT_ARGUMENT) + end + end + + private + + def check_example_without_description(node) + return if node.arguments? + return unless disallow_empty_description?(node) + + add_offense(node, message: MSG_ADD_DESCRIPTION) + end + + def disallow_empty_description?(node) + style == :disallow || + (style == :single_line_only && node.parent.multiline?) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/example_wording.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/example_wording.rb new file mode 100644 index 0000000000..ba8ae11758 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/example_wording.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for common mistakes in example descriptions. + # + # This cop will correct docstrings that begin with 'should' and 'it'. + # + # @see http://betterspecs.org/#should + # + # The autocorrect is experimental - use with care! It can be configured + # with CustomTransform (e.g. have => has) and IgnoredWords (e.g. only). + # + # @example + # # bad + # it 'should find nothing' do + # end + # + # # good + # it 'finds nothing' do + # end + # + # @example + # # bad + # it 'it does things' do + # end + # + # # good + # it 'does things' do + # end + class ExampleWording < Cop + MSG_SHOULD = 'Do not use should when describing your tests.'.freeze + MSG_IT = "Do not repeat 'it' when describing your tests.".freeze + + SHOULD_PREFIX = /\Ashould(?:n't)?\b/i + IT_PREFIX = /\Ait /i + + def_node_matcher( + :it_description, + '(block (send _ :it $(str $_) ...) ...)' + ) + + def on_block(node) + it_description(node) do |description_node, message| + if message =~ SHOULD_PREFIX + add_wording_offense(description_node, MSG_SHOULD) + elsif message =~ IT_PREFIX + add_wording_offense(description_node, MSG_IT) + end + end + end + + def autocorrect(range) + ->(corrector) { corrector.replace(range, replacement_text(range)) } + end + + private + + def add_wording_offense(node, message) + expr = node.loc.expression + + docstring = + Parser::Source::Range.new( + expr.source_buffer, + expr.begin_pos + 1, + expr.end_pos - 1 + ) + + add_offense(docstring, location: docstring, message: message) + end + + def replacement_text(range) + text = range.source + + if text =~ SHOULD_PREFIX + RuboCop::RSpec::Wording.new( + text, + ignore: ignored_words, + replace: custom_transform + ).rewrite + else + text.sub(IT_PREFIX, '') + end + end + + def custom_transform + cop_config.fetch('CustomTransform', {}) + end + + def ignored_words + cop_config.fetch('IgnoredWords', []) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_actual.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_actual.rb new file mode 100644 index 0000000000..9da8b7cc83 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_actual.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for `expect(...)` calls containing literal values. + # + # @example + # # bad + # expect(5).to eq(price) + # expect(/foo/).to eq(pattern) + # expect("John").to eq(name) + # + # # good + # expect(price).to eq(5) + # expect(pattern).to eq(/foo/) + # expect(name).to eq("John") + # + class ExpectActual < Cop + MSG = 'Provide the actual you are testing to `expect(...)`.'.freeze + + SIMPLE_LITERALS = %i[ + true + false + nil + int + float + str + sym + complex + rational + regopt + ].freeze + + COMPLEX_LITERALS = %i[ + array + hash + pair + irange + erange + regexp + ].freeze + + def_node_matcher :expect_literal, '(send _ :expect $#literal?)' + + def on_send(node) + expect_literal(node) do |argument| + add_offense(argument, location: :expression) + end + end + + private + + # This is not implement using a NodePattern because it seems + # to not be able to match against an explicit (nil) sexp + def literal?(node) + node && (simple_literal?(node) || complex_literal?(node)) + end + + def simple_literal?(node) + SIMPLE_LITERALS.include?(node.type) + end + + def complex_literal?(node) + COMPLEX_LITERALS.include?(node.type) && + node.each_child_node.all?(&method(:literal?)) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_change.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_change.rb new file mode 100644 index 0000000000..552b2d763a --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_change.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for consistent style of change matcher. + # + # Enforces either passing object and attribute as arguments to the matcher + # or passing a block that reads the attribute value. + # + # This cop can be configured using the `EnforcedStyle` option. + # + # @example `EnforcedStyle: block` + # # bad + # expect(run).to change(Foo, :bar) + # + # # good + # expect(run).to change { Foo.bar } + # + # @example `EnforcedStyle: method_call` + # # bad + # expect(run).to change { Foo.bar } + # expect(run).to change { foo.baz } + # + # # good + # expect(run).to change(Foo, :bar) + # expect(run).to change(foo, :baz) + # # also good when there are arguments or chained method calls + # expect(run).to change { Foo.bar(:count) } + # expect(run).to change { user.reload.name } + # + class ExpectChange < Cop + include ConfigurableEnforcedStyle + + MSG_BLOCK = 'Prefer `change(%s, :%s)`.'.freeze + MSG_CALL = 'Prefer `change { %s.%s }`.'.freeze + + def_node_matcher :expect_change_with_arguments, <<-PATTERN + (send nil? :change ({const send} nil? $_) (sym $_)) + PATTERN + + def_node_matcher :expect_change_with_block, <<-PATTERN + (block + (send nil? :change) + (args) + (send ({const send} nil? $_) $_) + ) + PATTERN + + def on_send(node) + return unless style == :block + + expect_change_with_arguments(node) do |receiver, message| + add_offense( + node, + message: format(MSG_CALL, obj: receiver, attr: message) + ) + end + end + + def on_block(node) + return unless style == :method_call + + expect_change_with_block(node) do |receiver, message| + add_offense( + node, + message: format(MSG_BLOCK, obj: receiver, attr: message) + ) + end + end + + def autocorrect(node) + if style == :block + autocorrect_method_call_to_block(node) + else + autocorrect_block_to_method_call(node) + end + end + + private + + def autocorrect_method_call_to_block(node) + lambda do |corrector| + expect_change_with_arguments(node) do |receiver, message| + replacement = "change { #{receiver}.#{message} }" + corrector.replace(node.loc.expression, replacement) + end + end + end + + def autocorrect_block_to_method_call(node) + lambda do |corrector| + expect_change_with_block(node) do |receiver, message| + replacement = "change(#{receiver}, :#{message})" + corrector.replace(node.loc.expression, replacement) + end + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_in_hook.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_in_hook.rb new file mode 100644 index 0000000000..22232f60f8 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_in_hook.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Do not use `expect` in hooks such as `before`. + # + # @example + # # bad + # before do + # expect(something).to eq 'foo' + # end + # + # # bad + # after do + # expect_any_instance_of(Something).to receive(:foo) + # end + # + # # good + # it do + # expect(something).to eq 'foo' + # end + class ExpectInHook < Cop + MSG = 'Do not use `%s` in `%s` hook'.freeze + + def_node_search :expectation, Expectations::ALL.send_pattern + + def on_block(node) + return unless hook?(node) + return if node.body.nil? + + expectation(node.body) do |expect| + add_offense(expect, location: :selector, + message: message(expect, node)) + end + end + + private + + def message(expect, hook) + format(MSG, expect: expect.method_name, hook: hook.method_name) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_output.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_output.rb new file mode 100644 index 0000000000..d23e7159da --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/expect_output.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for opportunities to use `expect { ... }.to output`. + # + # @example + # # bad + # $stdout = StringIO.new + # my_app.print_report + # $stdout = STDOUT + # expect($stdout.string).to eq('Hello World') + # + # # good + # expect { my_app.print_report }.to output('Hello World').to_stdout + class ExpectOutput < Cop + MSG = 'Use `expect { ... }.to output(...).to_%s` '\ + 'instead of mutating $%s.'.freeze + + def on_gvasgn(node) + return unless inside_example_scope?(node) + + variable_name, _rhs = *node + name = variable_name[1..-1] + return unless name.eql?('stdout') || name.eql?('stderr') + + add_offense(node, location: :name, message: format(MSG, name: name)) + end + + private + + # Detect if we are inside the scope of a single example + # + # We want to encourage using `expect { ... }.to output` so + # we only care about situations where you would replace with + # an expectation. Therefore, assignments to stderr or stdout + # within a `before(:all)` or otherwise outside of an example + # don't matter. + def inside_example_scope?(node) + return false if node.nil? || example_group?(node) + return true if example?(node) + return RuboCop::RSpec::Hook.new(node).example? if hook?(node) + + inside_example_scope?(node.parent) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb new file mode 100644 index 0000000000..21b522b79f --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb @@ -0,0 +1,147 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + module FactoryBot + # Always declare attribute values as blocks. + # + # @example + # # bad + # kind [:active, :rejected].sample + # + # # good + # kind { [:active, :rejected].sample } + # + # # bad + # closed_at 1.day.from_now + # + # # good + # closed_at { 1.day.from_now } + # + # # bad + # count 1 + # + # # good + # count { 1 } + class AttributeDefinedStatically < Cop + MSG = 'Use a block to declare attribute values.'.freeze + + ATTRIBUTE_DEFINING_METHODS = %i[factory trait transient ignore].freeze + + UNPROXIED_METHODS = %i[ + __send__ + __id__ + nil? + send + object_id + extend + instance_eval + initialize + block_given? + raise + caller + method + ].freeze + + DEFINITION_PROXY_METHODS = %i[ + add_attribute + after + association + before + callback + ignore + initialize_with + sequence + skip_create + to_create + ].freeze + + RESERVED_METHODS = + DEFINITION_PROXY_METHODS + + UNPROXIED_METHODS + + ATTRIBUTE_DEFINING_METHODS + + def_node_matcher :value_matcher, <<-PATTERN + (send {self nil?} !#reserved_method? $...) + PATTERN + + def_node_search :factory_attributes, <<-PATTERN + (block (send nil? #attribute_defining_method? ...) _ { (begin $...) $(send ...) } ) + PATTERN + + def on_block(node) + factory_attributes(node).to_a.flatten.each do |attribute| + next if proc?(attribute) || association?(attribute) + + add_offense(attribute, location: :expression) + end + end + + def autocorrect(node) + if node.parenthesized? + autocorrect_replacing_parens(node) + else + autocorrect_without_parens(node) + end + end + + private + + def proc?(attribute) + value_matcher(attribute).to_a.all?(&:block_pass_type?) + end + + def association?(attribute) + argument = attribute.first_argument + argument.hash_type? && factory_key?(argument) + end + + def factory_key?(hash_node) + hash_node.keys.any? { |key| key.sym_type? && key.value == :factory } + end + + def autocorrect_replacing_parens(node) + left_braces, right_braces = braces(node) + + lambda do |corrector| + corrector.replace(node.location.begin, ' ' + left_braces) + corrector.replace(node.location.end, right_braces) + end + end + + def autocorrect_without_parens(node) + left_braces, right_braces = braces(node) + + lambda do |corrector| + argument = node.first_argument + expression = argument.location.expression + corrector.insert_before(expression, left_braces) + corrector.insert_after(expression, right_braces) + end + end + + def braces(node) + if value_hash_without_braces?(node.first_argument) + ['{ { ', ' } }'] + else + ['{ ', ' }'] + end + end + + def value_hash_without_braces?(node) + node.hash_type? && !node.braces? + end + + def reserved_method?(method_name) + RESERVED_METHODS.include?(method_name) + end + + def attribute_defining_method?(method_name) + ATTRIBUTE_DEFINING_METHODS.include?(method_name) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/factory_bot/create_list.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/factory_bot/create_list.rb new file mode 100644 index 0000000000..8eb690609a --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/factory_bot/create_list.rb @@ -0,0 +1,149 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + module FactoryBot + # Checks for create_list usage. + # + # This cop can be configured using the `EnforcedStyle` option + # + # @example `EnforcedStyle: create_list` + # # bad + # 3.times { create :user } + # + # # good + # create_list :user, 3 + # + # # good + # 3.times { |n| create :user, created_at: n.months.ago } + # + # @example `EnforcedStyle: n_times` + # # bad + # create_list :user, 3 + # + # # good + # 3.times { create :user } + class CreateList < Cop + include ConfigurableEnforcedStyle + + MSG_CREATE_LIST = 'Prefer create_list.'.freeze + MSG_N_TIMES = 'Prefer %s.times.'.freeze + + def_node_matcher :n_times_block?, <<-PATTERN + (block + (send (int _) :times) + ... + ) + PATTERN + + def_node_matcher :factory_call, <<-PATTERN + (send ${(const nil? {:FactoryGirl :FactoryBot}) nil?} :create (sym $_) $...) + PATTERN + + def_node_matcher :factory_list_call, <<-PATTERN + (send ${(const nil? {:FactoryGirl :FactoryBot}) nil?} :create_list (sym $_) (int $_) $...) + PATTERN + + def on_block(node) + return unless style == :create_list + return unless n_times_block?(node) + return unless contains_only_factory?(node.body) + + add_offense(node.send_node, + location: :expression, message: MSG_CREATE_LIST) + end + + def on_send(node) + return unless style == :n_times + + factory_list_call(node) do |_receiver, _factory, count, _| + add_offense( + node, + location: :selector, + message: format(MSG_N_TIMES, number: count) + ) + end + end + + def autocorrect(node) + if style == :create_list + autocorrect_n_times_to_create_list(node) + else + autocorrect_create_list_to_n_times(node) + end + end + + private + + def contains_only_factory?(node) + if node.block_type? + factory_call(node.send_node) + else + factory_call(node) + end + end + + def autocorrect_n_times_to_create_list(node) + block = node.parent + count = block.receiver.source + replacement = factory_call_replacement(block.body, count) + + lambda do |corrector| + corrector.replace(block.loc.expression, replacement) + end + end + + def autocorrect_create_list_to_n_times(node) + replacement = generate_n_times_block(node) + lambda do |corrector| + corrector.replace(node.loc.expression, replacement) + end + end + + def generate_n_times_block(node) + receiver, factory, count, options = *factory_list_call(node) + + arguments = ":#{factory}" + options = build_options_string(options) + arguments += ", #{options}" unless options.empty? + + replacement = format_receiver(receiver) + replacement += format_method_call(node, 'create', arguments) + "#{count}.times { #{replacement} }" + end + + def factory_call_replacement(body, count) + receiver, factory, options = *factory_call(body) + + arguments = ":#{factory}, #{count}" + options = build_options_string(options) + arguments += ", #{options}" unless options.empty? + + replacement = format_receiver(receiver) + replacement += format_method_call(body, 'create_list', arguments) + replacement + end + + def build_options_string(options) + options.map(&:source).join(', ') + end + + def format_method_call(node, method, arguments) + if node.parenthesized? + "#{method}(#{arguments})" + else + "#{method} #{arguments}" + end + end + + def format_receiver(receiver) + return '' unless receiver + + "#{receiver.source}." + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/file_path.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/file_path.rb new file mode 100644 index 0000000000..44df621366 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/file_path.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks that spec file paths are consistent with the test subject. + # + # Checks the path of the spec file and enforces that it reflects the + # described class/module and its optionally called out method. + # + # With the configuration option `IgnoreMethods` the called out method will + # be ignored when determining the enforced path. + # + # With the configuration option `CustomTransform` modules or classes can + # be specified that should not as usual be transformed from CamelCase to + # snake_case (e.g. 'RuboCop' => 'rubocop' ). + # + # @example + # # bad + # whatever_spec.rb # describe MyClass + # + # # bad + # my_class_spec.rb # describe MyClass, '#method' + # + # # good + # my_class_spec.rb # describe MyClass + # + # # good + # my_class_method_spec.rb # describe MyClass, '#method' + # + # # good + # my_class/method_spec.rb # describe MyClass, '#method' + # + # @example when configuration is `IgnoreMethods: true` + # # bad + # whatever_spec.rb # describe MyClass + # + # # good + # my_class_spec.rb # describe MyClass + # + # # good + # my_class_spec.rb # describe MyClass, '#method' + # + class FilePath < Cop + include RuboCop::RSpec::TopLevelDescribe + + MSG = 'Spec path should end with `%s`.'.freeze + + def_node_search :const_described?, '(send _ :describe (const ...) ...)' + def_node_search :routing_metadata?, '(pair (sym :type) (sym :routing))' + + def on_top_level_describe(node, args) + return unless const_described?(node) && single_top_level_describe? + return if routing_spec?(args) + + glob = glob_for(args) + + return if filename_ends_with?(glob) + + add_offense( + node, + location: :expression, + message: format(MSG, suffix: glob) + ) + end + + private + + def routing_spec?(args) + args.any?(&method(:routing_metadata?)) + end + + def glob_for((described_class, method_name)) + "#{expected_path(described_class)}#{name_glob(method_name)}*_spec.rb" + end + + def name_glob(name) + return unless name && name.str_type? + + "*#{name.str_content.gsub(/\W/, '')}" unless ignore_methods? + end + + def expected_path(constant) + File.join( + constant.const_name.split('::').map do |name| + custom_transform.fetch(name) { camel_to_snake_case(name) } + end + ) + end + + def camel_to_snake_case(string) + string + .gsub(/([^A-Z])([A-Z]+)/, '\1_\2') + .gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2') + .downcase + end + + def custom_transform + cop_config.fetch('CustomTransform', {}) + end + + def ignore_methods? + cop_config['IgnoreMethods'] + end + + def filename_ends_with?(glob) + File.fnmatch?("*#{glob}", processed_source.buffer.name) + end + + def relevant_rubocop_rspec_file?(_file) + true + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/focus.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/focus.rb new file mode 100644 index 0000000000..0322aae8d2 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/focus.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks if examples are focused. + # + # @example + # # bad + # describe MyClass, focus: true do + # end + # + # describe MyClass, :focus do + # end + # + # fdescribe MyClass do + # end + # + # # good + # describe MyClass do + # end + class Focus < Cop + MSG = 'Focused spec found.'.freeze + + focusable = + ExampleGroups::GROUPS + + ExampleGroups::SKIPPED + + Examples::EXAMPLES + + Examples::SKIPPED + + focused = ExampleGroups::FOCUSED + Examples::FOCUSED + + FOCUSABLE_SELECTORS = focusable.node_pattern_union + + FOCUS_SYMBOL = s(:sym, :focus) + FOCUS_TRUE = s(:pair, FOCUS_SYMBOL, s(:true)) + + def_node_matcher :metadata, <<-PATTERN + {(send nil? #{FOCUSABLE_SELECTORS} ... (hash $...)) + (send nil? #{FOCUSABLE_SELECTORS} $...)} + PATTERN + + def_node_matcher :focused_block?, focused.send_pattern + + def on_send(node) + focus_metadata(node) do |focus| + add_offense(focus, location: :expression) + end + end + + private + + def focus_metadata(node, &block) + yield(node) if focused_block?(node) + + metadata(node) do |matches| + matches.grep(FOCUS_SYMBOL, &block) + matches.grep(FOCUS_TRUE, &block) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/hook_argument.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/hook_argument.rb new file mode 100644 index 0000000000..2f83353c15 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/hook_argument.rb @@ -0,0 +1,136 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks the arguments passed to `before`, `around`, and `after`. + # + # This cop checks for consistent style when specifying RSpec + # hooks which run for each example. There are three supported + # styles: "implicit", "each", and "example." All styles have + # the same behavior. + # + # @example when configuration is `EnforcedStyle: implicit` + # # bad + # before(:each) do + # # ... + # end + # + # # bad + # before(:example) do + # # ... + # end + # + # # good + # before do + # # ... + # end + # + # @example when configuration is `EnforcedStyle: each` + # # bad + # before(:example) do + # # ... + # end + # + # # good + # before do + # # ... + # end + # + # # good + # before(:each) do + # # ... + # end + # + # @example when configuration is `EnforcedStyle: example` + # # bad + # before(:each) do + # # ... + # end + # + # # bad + # before do + # # ... + # end + # + # # good + # before(:example) do + # # ... + # end + class HookArgument < Cop + include ConfigurableEnforcedStyle + include RangeHelp + + IMPLICIT_MSG = 'Omit the default `%p` ' \ + 'argument for RSpec hooks.'.freeze + EXPLICIT_MSG = 'Use `%p` for RSpec hooks.'.freeze + + HOOKS = Hooks::ALL.node_pattern_union.freeze + + def_node_matcher :scoped_hook, <<-PATTERN + (block $(send _ #{HOOKS} (sym ${:each :example})) ...) + PATTERN + + def_node_matcher :unscoped_hook, "(block $(send _ #{HOOKS}) ...)" + + def on_block(node) + hook(node) do |method_send, scope_name| + return correct_style_detected if scope_name.equal?(style) + return check_implicit(method_send) unless scope_name + + style_detected(scope_name) + add_offense( + method_send, + location: :expression, + message: explicit_message(scope_name) + ) + end + end + + def autocorrect(node) + scope = implicit_style? ? '' : "(#{style.inspect})" + + lambda do |corrector| + corrector.replace(argument_range(node), scope) + end + end + + private + + def check_implicit(method_send) + style_detected(:implicit) + return if implicit_style? + + add_offense( + method_send, + location: :selector, + message: format(EXPLICIT_MSG, scope: style) + ) + end + + def explicit_message(scope) + if implicit_style? + format(IMPLICIT_MSG, scope: scope) + else + format(EXPLICIT_MSG, scope: style) + end + end + + def implicit_style? + style.equal?(:implicit) + end + + def hook(node, &block) + scoped_hook(node, &block) || unscoped_hook(node, &block) + end + + def argument_range(send_node) + range_between( + send_node.loc.selector.end_pos, + send_node.loc.expression.end_pos + ) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/hooks_before_examples.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/hooks_before_examples.rb new file mode 100644 index 0000000000..d81f6860a3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/hooks_before_examples.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for before/around/after hooks that come after an example. + # + # @example + # # Bad + # + # it 'checks what foo does' do + # expect(foo).to be + # end + # + # before { prepare } + # after { clean_up } + # + # # Good + # before { prepare } + # after { clean_up } + # + # it 'checks what foo does' do + # expect(foo).to be + # end + # + class HooksBeforeExamples < Cop + include RangeHelp + include RuboCop::RSpec::FinalEndLocation + + MSG = 'Move `%s` above the examples in the group.'.freeze + + def_node_matcher :example_or_group?, <<-PATTERN + { + #{(Examples::ALL + ExampleGroups::ALL).block_pattern} + #{Includes::EXAMPLES.send_pattern} + } + PATTERN + + def on_block(node) + return unless example_group_with_body?(node) + + check_hooks(node.body) if multiline_block?(node.body) + end + + def autocorrect(node) + lambda do |corrector| + first_example = find_first_example(node.parent) + first_example_pos = first_example.loc.expression + indent = "\n" + ' ' * first_example.loc.column + + corrector.insert_before(first_example_pos, source(node) + indent) + corrector.remove(node_range_with_surrounding_space(node)) + end + end + + private + + def multiline_block?(block) + block.begin_type? + end + + def check_hooks(node) + first_example = find_first_example(node) + return unless first_example + + node.each_child_node do |child| + next if child.sibling_index < first_example.sibling_index + next unless hook?(child) + + add_offense( + child, + message: format(MSG, hook: child.method_name) + ) + end + end + + def find_first_example(node) + node.children.find { |sibling| example_or_group?(sibling) } + end + + def node_range_with_surrounding_space(node) + range = node_range(node) + range_by_whole_lines(range, include_final_newline: true) + end + + def source(node) + node_range(node).source + end + + def node_range(node) + range_between( + node.loc.expression.begin_pos, + final_end_location(node).end_pos + ) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/implicit_expect.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/implicit_expect.rb new file mode 100644 index 0000000000..eb3272588b --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/implicit_expect.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Check that a consistent implicit expectation style is used. + # + # This cop can be configured using the `EnforcedStyle` option + # and supports the `--auto-gen-config` flag. + # + # @example `EnforcedStyle: is_expected` + # + # # bad + # it { should be_truthy } + # + # # good + # it { is_expected.to be_truthy } + # + # @example `EnforcedStyle: should` + # + # # bad + # it { is_expected.to be_truthy } + # + # # good + # it { should be_truthy } + # + class ImplicitExpect < Cop + include ConfigurableEnforcedStyle + + MSG = 'Prefer `%s` over `%s`.'.freeze + + def_node_matcher :implicit_expect, <<-PATTERN + { + (send nil? ${:should :should_not} ...) + (send (send nil? $:is_expected) {:to :to_not :not_to} ...) + } + PATTERN + + alternatives = { + 'is_expected.to' => 'should', + 'is_expected.not_to' => 'should_not', + 'is_expected.to_not' => 'should_not' + } + + ENFORCED_REPLACEMENTS = alternatives.merge(alternatives.invert).freeze + + def on_send(node) # rubocop:disable Metrics/MethodLength + return unless (source_range = offending_expect(node)) + + expectation_source = source_range.source + + if expectation_source.start_with?(style.to_s) + correct_style_detected + else + opposite_style_detected + + add_offense( + node, + location: source_range, + message: offense_message(expectation_source) + ) + end + end + + def autocorrect(node) + lambda do |corrector| + offense = offending_expect(node) + replacement = replacement_source(offense.source) + + corrector.replace(offense, replacement) + end + end + + private + + def offending_expect(node) + case implicit_expect(node) + when :is_expected + is_expected_range(node.loc) + when :should, :should_not + node.loc.selector + end + end + + def is_expected_range(source_map) # rubocop:disable PredicateName + Parser::Source::Range.new( + source_map.expression.source_buffer, + source_map.expression.begin_pos, + source_map.selector.end_pos + ) + end + + def offense_message(offending_source) + format( + MSG, + good: replacement_source(offending_source), + bad: offending_source + ) + end + + def replacement_source(offending_source) + ENFORCED_REPLACEMENTS.fetch(offending_source) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/implicit_subject.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/implicit_subject.rb new file mode 100644 index 0000000000..85877475f4 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/implicit_subject.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for usage of implicit subject (`is_expected` / `should`). + # + # This cop can be configured using the `EnforcedStyle` option + # + # @example `EnforcedStyle: single_line_only` + # # bad + # it do + # is_expected.to be_truthy + # end + # + # # good + # it { is_expected.to be_truthy } + # it do + # expect(subject).to be_truthy + # end + # + # @example `EnforcedStyle: disallow` + # # bad + # it { is_expected.to be_truthy } + # + # # good + # it { expect(subject).to be_truthy } + # + class ImplicitSubject < Cop + include ConfigurableEnforcedStyle + + MSG = "Don't use implicit subject.".freeze + + def_node_matcher :implicit_subject?, <<-PATTERN + (send nil? {:should :should_not :is_expected} ...) + PATTERN + + def on_send(node) + return unless implicit_subject?(node) + return if valid_usage?(node) + + add_offense(node) + end + + def autocorrect(node) + replacement = 'expect(subject)' + if node.method_name == :should + replacement += '.to' + elsif node.method_name == :should_not + replacement += '.not_to' + end + + ->(corrector) { corrector.replace(node.loc.selector, replacement) } + end + + private + + def valid_usage?(node) + example = node.ancestors.find { |parent| example?(parent) } + return false if example.nil? + + example.method_name == :its || allowed_by_style?(example) + end + + def allowed_by_style?(example) + if style == :single_line_only + example.single_line? + elsif style == :single_statement_only + !example.body.begin_type? + else + false + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/instance_spy.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/instance_spy.rb new file mode 100644 index 0000000000..9f40ac7173 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/instance_spy.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for `instance_double` used with `have_received`. + # + # @example + # # bad + # it do + # foo = instance_double(Foo).as_null_object + # expect(foo).to have_received(:bar) + # end + # + # # good + # it do + # foo = instance_spy(Foo) + # expect(foo).to have_received(:bar) + # end + # + class InstanceSpy < Cop + MSG = 'Use `instance_spy` when you check your double '\ + 'with `have_received`.'.freeze + + def_node_search :null_double, <<-PATTERN + (lvasgn $_ + (send + $(send nil? :instance_double + ...) :as_null_object)) + PATTERN + + def_node_search :have_received_usage, <<-PATTERN + (send + (send nil? :expect + (lvar $_)) :to + (send nil? :have_received + ...) + ...) + PATTERN + + def on_block(node) + return unless example?(node) + + null_double(node) do |var, receiver| + have_received_usage(node) do |expected| + add_offense(receiver, location: :expression) if expected == var + end + end + end + + def autocorrect(node) + lambda do |corrector| + replacement = 'instance_spy' + corrector.replace(node.loc.selector, replacement) + + double_source_map = node.parent.loc + as_null_object_range = double_source_map + .dot + .join(double_source_map.selector) + corrector.remove(as_null_object_range) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/instance_variable.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/instance_variable.rb new file mode 100644 index 0000000000..fab437d9d7 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/instance_variable.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for instance variable usage in specs. + # + # This cop can be configured with the option `AssignmentOnly` which + # will configure the cop to only register offenses on instance + # variable usage if the instance variable is also assigned within + # the spec + # + # @example + # # bad + # describe MyClass do + # before { @foo = [] } + # it { expect(@foo).to be_empty } + # end + # + # # good + # describe MyClass do + # let(:foo) { [] } + # it { expect(foo).to be_empty } + # end + # + # @example with AssignmentOnly configuration + # + # # rubocop.yml + # # RSpec/InstanceVariable: + # # AssignmentOnly: false + # + # # bad + # describe MyClass do + # before { @foo = [] } + # it { expect(@foo).to be_empty } + # end + # + # # allowed + # describe MyClass do + # it { expect(@foo).to be_empty } + # end + # + # # good + # describe MyClass do + # let(:foo) { [] } + # it { expect(foo).to be_empty } + # end + # + class InstanceVariable < Cop + MSG = 'Replace instance variable with local variable or `let`.'.freeze + + EXAMPLE_GROUP_METHODS = ExampleGroups::ALL + SharedGroups::ALL + + def_node_matcher :spec_group?, EXAMPLE_GROUP_METHODS.block_pattern + + def_node_matcher :dynamic_class?, <<-PATTERN + (block (send (const nil? :Class) :new ...) ...) + PATTERN + + def_node_search :ivar_usage, '$(ivar $_)' + + def_node_search :ivar_assigned?, '(ivasgn % ...)' + + def on_block(node) + return unless spec_group?(node) + + ivar_usage(node) do |ivar, name| + return if inside_dynamic_class?(ivar) + return if assignment_only? && !ivar_assigned?(node, name) + + add_offense(ivar, location: :expression) + end + end + + private + + def inside_dynamic_class?(node) + node.each_ancestor(:block).any? { |block| dynamic_class?(block) } + end + + def assignment_only? + cop_config['AssignmentOnly'] + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb new file mode 100644 index 0000000000..828588171f --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb @@ -0,0 +1,42 @@ +module RuboCop + module Cop + module RSpec + # Checks invalid usage for predicate matcher. + # + # Predicate matcher does not need a question. + # This cop checks an unnecessary question in predicate matcher. + # + # @example + # + # # bad + # expect(foo).to be_something? + # + # # good + # expect(foo).to be_something + class InvalidPredicateMatcher < Cop + MSG = 'Omit `?` from `%s`.'.freeze + + def_node_matcher :invalid_predicate_matcher?, <<-PATTERN + (send (send nil? :expect ...) {:to :not_to :to_not} $(send nil? #predicate?)) + PATTERN + + def on_send(node) + invalid_predicate_matcher?(node) do |predicate| + add_offense(predicate, location: :expression) + end + end + + private + + def predicate?(name) + name = name.to_s + name.start_with?('be_', 'have_') && name.end_with?('?') + end + + def message(predicate) + format(MSG, matcher: predicate.method_name) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/it_behaves_like.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/it_behaves_like.rb new file mode 100644 index 0000000000..b7ede3c09c --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/it_behaves_like.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks that only one `it_behaves_like` style is used. + # + # @example when configuration is `EnforcedStyle: it_behaves_like` + # # bad + # it_should_behave_like 'a foo' + # + # # good + # it_behaves_like 'a foo' + # + # @example when configuration is `EnforcedStyle: it_should_behave_like` + # # bad + # it_behaves_like 'a foo' + # + # # good + # it_should_behave_like 'a foo' + class ItBehavesLike < Cop + include ConfigurableEnforcedStyle + + MSG = 'Prefer `%s` over `%s` when including '\ + 'examples in a nested context.'.freeze + + def_node_matcher :example_inclusion_offense, '(send _ % ...)' + + def on_send(node) + example_inclusion_offense(node, alternative_style) do + add_offense(node, location: :expression) + end + end + + def autocorrect(node) + ->(corrector) { corrector.replace(node.loc.selector, style.to_s) } + end + + private + + def message(_node) + format(MSG, replacement: style, original: alternative_style) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/iterated_expectation.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/iterated_expectation.rb new file mode 100644 index 0000000000..3fa5f6b4c6 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/iterated_expectation.rb @@ -0,0 +1,52 @@ +module RuboCop + module Cop + module RSpec + # Check that `all` matcher is used instead of iterating over an array. + # + # @example + # # bad + # it 'validates users' do + # [user1, user2, user3].each { |user| expect(user).to be_valid } + # end + # + # # good + # it 'validates users' do + # expect([user1, user2, user3]).to all(be_valid) + # end + class IteratedExpectation < Cop + MSG = 'Prefer using the `all` matcher instead ' \ + 'of iterating over an array.'.freeze + + def_node_matcher :each?, <<-PATTERN + (block + (send ... :each) + (args (arg $_)) + $(...) + ) + PATTERN + + def_node_matcher :expectation?, <<-PATTERN + (send (send nil? :expect (lvar %)) :to ...) + PATTERN + + def on_block(node) + each?(node) do |arg, body| + if single_expectation?(body, arg) || only_expectations?(body, arg) + add_offense(node.send_node, location: :expression) + end + end + end + + private + + def single_expectation?(body, arg) + expectation?(body, arg) + end + + def only_expectations?(body, arg) + body.each_child_node.all? { |child| expectation?(child, arg) } + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/leading_subject.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/leading_subject.rb new file mode 100644 index 0000000000..bc21c2929d --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/leading_subject.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Enforce that subject is the first definition in the test. + # + # @example + # # bad + # let(:params) { blah } + # subject { described_class.new(params) } + # + # before { do_something } + # subject { described_class.new(params) } + # + # it { expect_something } + # subject { described_class.new(params) } + # it { expect_something_else } + # + # + # # good + # subject { described_class.new(params) } + # let(:params) { blah } + # + # # good + # subject { described_class.new(params) } + # before { do_something } + # + # # good + # subject { described_class.new(params) } + # it { expect_something } + # it { expect_something_else } + # + class LeadingSubject < Cop + include RangeHelp + + MSG = 'Declare `subject` above any other `%s` ' \ + 'declarations.'.freeze + + def on_block(node) + return unless subject?(node) && !in_spec_block?(node) + + check_previous_nodes(node) + end + + def check_previous_nodes(node) + node.parent.each_child_node do |sibling| + if offending?(sibling) + add_offense( + node, + location: :expression, + message: format(MSG, offending: sibling.method_name) + ) + end + + break if offending?(sibling) || sibling.equal?(node) + end + end + + def autocorrect(node) + lambda do |corrector| + first_node = find_first_offending_node(node) + first_node_position = first_node.loc.expression + indent = "\n" + ' ' * first_node.loc.column + corrector.insert_before(first_node_position, node.source + indent) + corrector.remove(node_range(node)) + end + end + + private + + def offending?(node) + let?(node) || hook?(node) || example?(node) + end + + def find_first_offending_node(node) + node.parent.children.find { |sibling| offending?(sibling) } + end + + def node_range(node) + range_by_whole_lines(node.source_range, include_final_newline: true) + end + + def in_spec_block?(node) + node.each_ancestor(:block).any? do |ancestor| + example?(ancestor) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/let_before_examples.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/let_before_examples.rb new file mode 100644 index 0000000000..f8d9f533e3 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/let_before_examples.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for `let` definitions that come after an example. + # + # @example + # # Bad + # let(:foo) { bar } + # + # it 'checks what foo does' do + # expect(foo).to be + # end + # + # let(:some) { other } + # + # it 'checks what some does' do + # expect(some).to be + # end + # + # # Good + # let(:foo) { bar } + # let(:some) { other } + # + # it 'checks what foo does' do + # expect(foo).to be + # end + # + # it 'checks what some does' do + # expect(some).to be + # end + class LetBeforeExamples < Cop + include RangeHelp + include RuboCop::RSpec::FinalEndLocation + + MSG = 'Move `let` before the examples in the group.'.freeze + + def_node_matcher :example_or_group?, <<-PATTERN + { + #{(Examples::ALL + ExampleGroups::ALL).block_pattern} + #{Includes::EXAMPLES.send_pattern} + } + PATTERN + + def on_block(node) + return unless example_group_with_body?(node) + + check_let_declarations(node.body) if multiline_block?(node.body) + end + + def autocorrect(node) + lambda do |corrector| + first_example = find_first_example(node.parent) + first_example_pos = first_example.loc.expression + indent = "\n" + ' ' * first_example.loc.column + + corrector.insert_before(first_example_pos, source(node) + indent) + corrector.remove(node_range_with_surrounding_space(node)) + end + end + + private + + def multiline_block?(block) + block.begin_type? + end + + def check_let_declarations(node) + first_example = find_first_example(node) + return unless first_example + + node.each_child_node do |child| + next if child.sibling_index < first_example.sibling_index + + add_offense(child, location: :expression) if let?(child) + end + end + + def find_first_example(node) + node.children.find { |sibling| example_or_group?(sibling) } + end + + def node_range_with_surrounding_space(node) + range = node_range(node) + range_by_whole_lines(range, include_final_newline: true) + end + + def source(node) + node_range(node).source + end + + def node_range(node) + range_between( + node.loc.expression.begin_pos, + final_end_location(node).end_pos + ) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/let_setup.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/let_setup.rb new file mode 100644 index 0000000000..f271f3d0d6 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/let_setup.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks unreferenced `let!` calls being used for test setup. + # + # @example + # # Bad + # let!(:my_widget) { create(:widget) } + # + # it 'counts widgets' do + # expect(Widget.count).to eq(1) + # end + # + # # Good + # it 'counts widgets' do + # create(:widget) + # expect(Widget.count).to eq(1) + # end + # + # # Good + # before { create(:widget) } + # + # it 'counts widgets' do + # expect(Widget.count).to eq(1) + # end + class LetSetup < Cop + include RuboCop::RSpec::TopLevelDescribe + + MSG = 'Do not use `let!` for test setup.'.freeze + + def_node_search :let_bang, <<-PATTERN + (block $(send nil? :let! (sym $_)) args ...) + PATTERN + + def_node_search :method_called?, '(send nil? %)' + + def on_block(node) + return unless example_group?(node) + + unused_let_bang(node) do |let| + add_offense(let, location: :expression) + end + end + + private + + def unused_let_bang(node) + let_bang(node) do |method_send, method_name| + yield(method_send) unless method_called?(node, method_name) + end + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/message_chain.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/message_chain.rb new file mode 100644 index 0000000000..88b4b221b5 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/message_chain.rb @@ -0,0 +1,31 @@ +module RuboCop + module Cop + module RSpec + # Check that chains of messages are not being stubbed. + # + # @example + # # bad + # allow(foo).to receive_message_chain(:bar, :baz).and_return(42) + # + # # better + # thing = Thing.new(baz: 42) + # allow(foo).to receive(bar: thing) + # + class MessageChain < Cop + MSG = 'Avoid stubbing using `%s`.'.freeze + + def_node_matcher :message_chain, <<-PATTERN + (send _ {:receive_message_chain :stub_chain} ...) + PATTERN + + def on_send(node) + message_chain(node) { add_offense(node, location: :selector) } + end + + def message(node) + format(MSG, method: node.method_name) + end + end + end + end +end diff --git a/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/message_expectation.rb b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/message_expectation.rb new file mode 100644 index 0000000000..cd1972dcd5 --- /dev/null +++ b/Library/Homebrew/vendor/bundle-standalone/ruby/2.3.0/gems/rubocop-rspec-1.30.0/lib/rubocop/cop/rspec/message_expectation.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module RSpec + # Checks for consistent message expectation style. + # + # This cop can be configured in your configuration using the + # `EnforcedStyle` option and supports `--auto-gen-config`. + # + # @example `EnforcedStyle: allow` + # + # # bad + # expect(foo).to receive(:bar) + # + # # good + # allow(foo).to receive(:bar) + # + # @example `EnforcedStyle: expect` + # + # # bad + # allow(foo).to receive(:bar) + # + # # good + # expect(foo).to receive(:bar) + # + class MessageExpectation < Cop + include ConfigurableEnforcedStyle + + MSG = 'Prefer `%