Merge branch 'master' into mlh-outdated-packages
This commit is contained in:
commit
d6f2a1c6fa
@ -43,3 +43,5 @@ RSpec/MultipleExpectations:
|
|||||||
Max: 26
|
Max: 26
|
||||||
RSpec/NestedGroups:
|
RSpec/NestedGroups:
|
||||||
Max: 5
|
Max: 5
|
||||||
|
RSpec/MultipleMemoizedHelpers:
|
||||||
|
Max: 12
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
require "English"
|
require "English"
|
||||||
|
|
||||||
|
SimpleCov.enable_for_subprocesses true
|
||||||
|
|
||||||
SimpleCov.start do
|
SimpleCov.start do
|
||||||
coverage_dir File.expand_path("../test/coverage", File.realpath(__FILE__))
|
coverage_dir File.expand_path("../test/coverage", File.realpath(__FILE__))
|
||||||
root File.expand_path("..", File.realpath(__FILE__))
|
root File.expand_path("..", File.realpath(__FILE__))
|
||||||
@ -12,9 +14,21 @@ SimpleCov.start do
|
|||||||
# tests to be dropped. This causes random fluctuations in test coverage.
|
# tests to be dropped. This causes random fluctuations in test coverage.
|
||||||
merge_timeout 86400
|
merge_timeout 86400
|
||||||
|
|
||||||
|
at_fork do |pid|
|
||||||
|
# This needs a unique name so it won't be ovewritten
|
||||||
|
command_name "#{SimpleCov.command_name} (#{pid})"
|
||||||
|
|
||||||
|
# be quiet, the parent process will be in charge of output and checking coverage totals
|
||||||
|
print_error_status = false
|
||||||
|
end
|
||||||
|
|
||||||
if ENV["HOMEBREW_INTEGRATION_TEST"]
|
if ENV["HOMEBREW_INTEGRATION_TEST"]
|
||||||
|
# This needs a unique name so it won't be ovewritten
|
||||||
command_name "#{ENV["HOMEBREW_INTEGRATION_TEST"]} (#{$PROCESS_ID})"
|
command_name "#{ENV["HOMEBREW_INTEGRATION_TEST"]} (#{$PROCESS_ID})"
|
||||||
|
|
||||||
|
# be quiet, the parent process will be in charge of output and checking coverage totals
|
||||||
|
print_error_status = false
|
||||||
|
|
||||||
at_exit do
|
at_exit do
|
||||||
exit_code = $ERROR_INFO.nil? ? 0 : $ERROR_INFO.status
|
exit_code = $ERROR_INFO.nil? ? 0 : $ERROR_INFO.status
|
||||||
$stdout.reopen("/dev/null")
|
$stdout.reopen("/dev/null")
|
||||||
|
|||||||
@ -10,7 +10,7 @@ GEM
|
|||||||
ast (2.4.1)
|
ast (2.4.1)
|
||||||
bindata (2.4.8)
|
bindata (2.4.8)
|
||||||
byebug (11.1.3)
|
byebug (11.1.3)
|
||||||
codecov (0.2.5)
|
codecov (0.2.6)
|
||||||
colorize
|
colorize
|
||||||
json
|
json
|
||||||
simplecov
|
simplecov
|
||||||
@ -112,11 +112,11 @@ GEM
|
|||||||
parser (>= 2.7.1.4)
|
parser (>= 2.7.1.4)
|
||||||
rubocop-performance (1.7.1)
|
rubocop-performance (1.7.1)
|
||||||
rubocop (>= 0.82.0)
|
rubocop (>= 0.82.0)
|
||||||
rubocop-rspec (1.42.0)
|
rubocop-rspec (1.43.1)
|
||||||
rubocop (>= 0.87.0)
|
rubocop (~> 0.87)
|
||||||
ruby-macho (2.2.0)
|
ruby-macho (2.2.0)
|
||||||
ruby-progressbar (1.10.1)
|
ruby-progressbar (1.10.1)
|
||||||
simplecov (0.18.5)
|
simplecov (0.19.0)
|
||||||
docile (~> 1.1)
|
docile (~> 1.1)
|
||||||
simplecov-html (~> 0.11)
|
simplecov-html (~> 0.11)
|
||||||
simplecov-html (0.12.2)
|
simplecov-html (0.12.2)
|
||||||
|
|||||||
@ -6,12 +6,18 @@ case "$HOMEBREW_SYSTEM" in
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
# Force UTF-8 to avoid encoding issues for users with broken locale settings.
|
# Force UTF-8 to avoid encoding issues for users with broken locale settings.
|
||||||
if [[ "$(locale charmap 2>/dev/null)" != "UTF-8" ]]
|
if [[ -n "$HOMEBREW_MACOS" ]]
|
||||||
then
|
then
|
||||||
if [[ -n "$HOMEBREW_MACOS" ]]
|
if [[ "$(locale charmap)" != "UTF-8" ]]
|
||||||
then
|
then
|
||||||
export LC_ALL="en_US.UTF-8"
|
export LC_ALL="en_US.UTF-8"
|
||||||
else
|
fi
|
||||||
|
else
|
||||||
|
if ! command -v locale >/dev/null
|
||||||
|
then
|
||||||
|
export LC_ALL=C
|
||||||
|
elif [[ "$(locale charmap)" != "UTF-8" ]]
|
||||||
|
then
|
||||||
locales=$(locale -a)
|
locales=$(locale -a)
|
||||||
c_utf_regex='\bC\.(utf8|UTF-8)\b'
|
c_utf_regex='\bC\.(utf8|UTF-8)\b'
|
||||||
en_us_regex='\ben_US\.(utf8|UTF-8)\b'
|
en_us_regex='\ben_US\.(utf8|UTF-8)\b'
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Settings for the build environment.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
class BuildEnvironment
|
class BuildEnvironment
|
||||||
def initialize(*settings)
|
def initialize(*settings)
|
||||||
@settings = Set.new(*settings)
|
@settings = Set.new(*settings)
|
||||||
@ -23,19 +26,15 @@ class BuildEnvironment
|
|||||||
@settings.include? :userpaths
|
@settings.include? :userpaths
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# DSL for specifying build environment settings.
|
||||||
module DSL
|
module DSL
|
||||||
def env(*settings)
|
def env(*settings)
|
||||||
@env ||= BuildEnvironment.new
|
@env ||= BuildEnvironment.new
|
||||||
@env.merge(settings)
|
@env.merge(settings)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
module Homebrew
|
KEYS = %w[
|
||||||
module_function
|
|
||||||
|
|
||||||
def build_env_keys(env)
|
|
||||||
%w[
|
|
||||||
CC CXX LD OBJC OBJCXX
|
CC CXX LD OBJC OBJCXX
|
||||||
HOMEBREW_CC HOMEBREW_CXX
|
HOMEBREW_CC HOMEBREW_CXX
|
||||||
CFLAGS CXXFLAGS CPPFLAGS LDFLAGS SDKROOT MAKEFLAGS
|
CFLAGS CXXFLAGS CPPFLAGS LDFLAGS SDKROOT MAKEFLAGS
|
||||||
@ -47,11 +46,15 @@ module Homebrew
|
|||||||
MAKE GIT CPP
|
MAKE GIT CPP
|
||||||
ACLOCAL_PATH PATH CPATH
|
ACLOCAL_PATH PATH CPATH
|
||||||
LD_LIBRARY_PATH LD_RUN_PATH LD_PRELOAD LIBRARY_PATH
|
LD_LIBRARY_PATH LD_RUN_PATH LD_PRELOAD LIBRARY_PATH
|
||||||
].select { |key| env.key?(key) }
|
].freeze
|
||||||
|
private_constant :KEYS
|
||||||
|
|
||||||
|
def self.keys(env)
|
||||||
|
KEYS & env.keys
|
||||||
end
|
end
|
||||||
|
|
||||||
def dump_build_env(env, f = $stdout)
|
def self.dump(env, f = $stdout)
|
||||||
keys = build_env_keys(env)
|
keys = self.keys(env)
|
||||||
keys -= %w[CC CXX OBJC OBJCXX] if env["CC"] == env["HOMEBREW_CC"]
|
keys -= %w[CC CXX OBJC OBJCXX] if env["CC"] == env["HOMEBREW_CC"]
|
||||||
|
|
||||||
keys.each do |key|
|
keys.each do |key|
|
||||||
|
|||||||
@ -18,6 +18,10 @@ module Cask
|
|||||||
def to_a
|
def to_a
|
||||||
[true]
|
[true]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def summarize
|
||||||
|
"true"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -47,6 +47,16 @@ module Cask
|
|||||||
"dr" => "doctor",
|
"dr" => "doctor",
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
DEPRECATED_COMMANDS = {
|
||||||
|
Cmd::Cache => "brew --cache --cask",
|
||||||
|
Cmd::Doctor => "brew doctor --verbose",
|
||||||
|
Cmd::Home => "brew home",
|
||||||
|
Cmd::List => "brew list --cask",
|
||||||
|
Cmd::Outdated => "brew outdated --cask",
|
||||||
|
Cmd::Reinstall => "brew reinstall",
|
||||||
|
Cmd::Upgrade => "brew upgrade --cask",
|
||||||
|
}.freeze
|
||||||
|
|
||||||
def self.description
|
def self.description
|
||||||
max_command_len = Cmd.commands.map(&:length).max
|
max_command_len = Cmd.commands.map(&:length).max
|
||||||
|
|
||||||
@ -212,6 +222,11 @@ module Cask
|
|||||||
detect_external_command(*argv) ||
|
detect_external_command(*argv) ||
|
||||||
[args.remaining.empty? ? NullCommand : UnknownSubcommand.new(args.remaining.first), argv]
|
[args.remaining.empty? ? NullCommand : UnknownSubcommand.new(args.remaining.first), argv]
|
||||||
|
|
||||||
|
# TODO: enable for next major/minor release
|
||||||
|
# if (replacement = DEPRECATED_COMMANDS[command])
|
||||||
|
# odeprecated "brew cask #{command.command_name}", replacement
|
||||||
|
# end
|
||||||
|
|
||||||
if args.help?
|
if args.help?
|
||||||
puts command.help
|
puts command.help
|
||||||
else
|
else
|
||||||
|
|||||||
@ -28,9 +28,9 @@ module Cask
|
|||||||
switch "--online",
|
switch "--online",
|
||||||
description: "Run additional, slower style checks that require a network connection"
|
description: "Run additional, slower style checks that require a network connection"
|
||||||
switch "--new-cask",
|
switch "--new-cask",
|
||||||
description: "Run various additional style checks to determine if a new cask is eligible
|
description: "Run various additional style checks to determine if a new cask is eligible " \
|
||||||
for Homebrew. This should be used when creating new casks and implies
|
"for Homebrew. This should be used when creating new casks and implies " \
|
||||||
`--strict` and `--online`"
|
"`--strict` and `--online`"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -8,8 +8,6 @@ module Cask
|
|||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
# odeprecated "brew cask home", "brew home"
|
|
||||||
|
|
||||||
if casks.none?
|
if casks.none?
|
||||||
odebug "Opening project homepage"
|
odebug "Opening project homepage"
|
||||||
self.class.open_url "https://brew.sh/"
|
self.class.open_url "https://brew.sh/"
|
||||||
|
|||||||
@ -6,9 +6,16 @@ require "formula"
|
|||||||
require "cask/cask_loader"
|
require "cask/cask_loader"
|
||||||
require "set"
|
require "set"
|
||||||
|
|
||||||
CLEANUP_DEFAULT_DAYS = 30
|
module Homebrew
|
||||||
|
# Helper class for cleaning up the Homebrew cache.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
class Cleanup
|
||||||
|
CLEANUP_DEFAULT_DAYS = 30
|
||||||
|
private_constant :CLEANUP_DEFAULT_DAYS
|
||||||
|
|
||||||
module CleanupRefinement
|
# `Pathname` refinement with helper functions for cleaning up files.
|
||||||
|
module CleanupRefinement
|
||||||
refine Pathname do
|
refine Pathname do
|
||||||
def incomplete?
|
def incomplete?
|
||||||
extname.end_with?(".incomplete")
|
extname.end_with?(".incomplete")
|
||||||
@ -120,12 +127,10 @@ module CleanupRefinement
|
|||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
using CleanupRefinement
|
using CleanupRefinement
|
||||||
|
|
||||||
module Homebrew
|
|
||||||
class Cleanup
|
|
||||||
extend Predicable
|
extend Predicable
|
||||||
|
|
||||||
PERIODIC_CLEAN_FILE = (HOMEBREW_CACHE/".cleaned").freeze
|
PERIODIC_CLEAN_FILE = (HOMEBREW_CACHE/".cleaned").freeze
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "cli/named_args"
|
||||||
require "ostruct"
|
require "ostruct"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
@ -19,7 +20,7 @@ module Homebrew
|
|||||||
|
|
||||||
# Can set these because they will be overwritten by freeze_named_args!
|
# Can set these because they will be overwritten by freeze_named_args!
|
||||||
# (whereas other values below will only be overwritten if passed).
|
# (whereas other values below will only be overwritten if passed).
|
||||||
self[:named_args] = []
|
self[:named_args] = NamedArgs.new
|
||||||
self[:remaining] = []
|
self[:remaining] = []
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -28,18 +29,12 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
def freeze_named_args!(named_args)
|
def freeze_named_args!(named_args)
|
||||||
# Reset cache values reliant on named_args
|
self[:named_args] = NamedArgs.new(
|
||||||
@formulae = nil
|
*named_args.freeze,
|
||||||
@formulae_and_casks = nil
|
override_spec: spec(nil),
|
||||||
@resolved_formulae = nil
|
force_bottle: force_bottle?,
|
||||||
@resolved_formulae_casks = nil
|
flags: flags_only,
|
||||||
@formulae_paths = nil
|
)
|
||||||
@casks = nil
|
|
||||||
@loaded_casks = nil
|
|
||||||
@kegs = nil
|
|
||||||
@kegs_casks = nil
|
|
||||||
|
|
||||||
self[:named_args] = named_args.freeze
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def freeze_processed_options!(processed_options)
|
def freeze_processed_options!(processed_options)
|
||||||
@ -54,7 +49,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
def named
|
def named
|
||||||
named_args || []
|
named_args || NamedArgs.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def no_named?
|
def no_named?
|
||||||
@ -62,102 +57,39 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
def formulae
|
def formulae
|
||||||
require "formula"
|
named.to_formulae
|
||||||
|
|
||||||
@formulae ||= (downcased_unique_named - casks).map do |name|
|
|
||||||
Formulary.factory(name, spec, force_bottle: force_bottle?, flags: flags_only)
|
|
||||||
end.uniq(&:name).freeze
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def formulae_and_casks
|
def formulae_and_casks
|
||||||
@formulae_and_casks ||= begin
|
named.to_formulae_and_casks
|
||||||
formulae_and_casks = []
|
|
||||||
|
|
||||||
downcased_unique_named.each do |name|
|
|
||||||
formulae_and_casks << Formulary.factory(name, spec)
|
|
||||||
rescue FormulaUnavailableError
|
|
||||||
begin
|
|
||||||
formulae_and_casks << Cask::CaskLoader.load(name)
|
|
||||||
rescue Cask::CaskUnavailableError
|
|
||||||
raise "No available formula or cask with the name \"#{name}\""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
formulae_and_casks.freeze
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def resolved_formulae
|
def resolved_formulae
|
||||||
require "formula"
|
named.to_resolved_formulae
|
||||||
|
|
||||||
@resolved_formulae ||= (downcased_unique_named - casks).map do |name|
|
|
||||||
Formulary.resolve(name, spec: spec(nil), force_bottle: force_bottle?, flags: flags_only)
|
|
||||||
end.uniq(&:name).freeze
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def resolved_formulae_casks
|
def resolved_formulae_casks
|
||||||
@resolved_formulae_casks ||= begin
|
named.to_resolved_formulae_to_casks
|
||||||
resolved_formulae = []
|
|
||||||
casks = []
|
|
||||||
|
|
||||||
downcased_unique_named.each do |name|
|
|
||||||
resolved_formulae << Formulary.resolve(name, spec: spec(nil),
|
|
||||||
force_bottle: force_bottle?, flags: flags_only)
|
|
||||||
rescue FormulaUnavailableError
|
|
||||||
begin
|
|
||||||
casks << Cask::CaskLoader.load(name)
|
|
||||||
rescue Cask::CaskUnavailableError
|
|
||||||
raise "No available formula or cask with the name \"#{name}\""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
[resolved_formulae.freeze, casks.freeze].freeze
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def formulae_paths
|
def formulae_paths
|
||||||
@formulae_paths ||= (downcased_unique_named - casks).map do |name|
|
named.to_formulae_paths
|
||||||
Formulary.path(name)
|
|
||||||
end.uniq.freeze
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def casks
|
def casks
|
||||||
@casks ||= downcased_unique_named.grep(HOMEBREW_CASK_TAP_CASK_REGEX)
|
named.homebrew_tap_cask_names
|
||||||
.freeze
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def loaded_casks
|
def loaded_casks
|
||||||
@loaded_casks ||= downcased_unique_named.map(&Cask::CaskLoader.method(:load)).freeze
|
named.to_casks
|
||||||
end
|
end
|
||||||
|
|
||||||
def kegs
|
def kegs
|
||||||
@kegs ||= downcased_unique_named.map do |name|
|
named.to_kegs
|
||||||
resolve_keg name
|
|
||||||
rescue NoSuchKegError => e
|
|
||||||
if (reason = Homebrew::MissingFormula.suggest_command(name, "uninstall"))
|
|
||||||
$stderr.puts reason
|
|
||||||
end
|
|
||||||
raise e
|
|
||||||
end.freeze
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def kegs_casks
|
def kegs_casks
|
||||||
@kegs_casks ||= begin
|
named.to_kegs_to_casks
|
||||||
kegs = []
|
|
||||||
casks = []
|
|
||||||
|
|
||||||
downcased_unique_named.each do |name|
|
|
||||||
kegs << resolve_keg(name)
|
|
||||||
rescue NoSuchKegError
|
|
||||||
begin
|
|
||||||
casks << Cask::CaskLoader.load(name)
|
|
||||||
rescue Cask::CaskUnavailableError
|
|
||||||
raise "No installed keg or cask with the name \"#{name}\""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
[kegs.freeze, casks.freeze].freeze
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_stable?
|
def build_stable?
|
||||||
@ -218,17 +150,6 @@ module Homebrew
|
|||||||
@cli_args.freeze
|
@cli_args.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
def downcased_unique_named
|
|
||||||
# Only lowercase names, not paths, bottle filenames or URLs
|
|
||||||
named.map do |arg|
|
|
||||||
if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg)
|
|
||||||
arg
|
|
||||||
else
|
|
||||||
arg.downcase
|
|
||||||
end
|
|
||||||
end.uniq
|
|
||||||
end
|
|
||||||
|
|
||||||
def spec(default = :stable)
|
def spec(default = :stable)
|
||||||
if HEAD?
|
if HEAD?
|
||||||
:head
|
:head
|
||||||
@ -238,50 +159,6 @@ module Homebrew
|
|||||||
default
|
default
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def resolve_keg(name)
|
|
||||||
require "keg"
|
|
||||||
require "formula"
|
|
||||||
require "missing_formula"
|
|
||||||
|
|
||||||
raise UsageError if name.blank?
|
|
||||||
|
|
||||||
rack = Formulary.to_rack(name.downcase)
|
|
||||||
|
|
||||||
dirs = rack.directory? ? rack.subdirs : []
|
|
||||||
raise NoSuchKegError, rack.basename if dirs.empty?
|
|
||||||
|
|
||||||
linked_keg_ref = HOMEBREW_LINKED_KEGS/rack.basename
|
|
||||||
opt_prefix = HOMEBREW_PREFIX/"opt/#{rack.basename}"
|
|
||||||
|
|
||||||
begin
|
|
||||||
if opt_prefix.symlink? && opt_prefix.directory?
|
|
||||||
Keg.new(opt_prefix.resolved_path)
|
|
||||||
elsif linked_keg_ref.symlink? && linked_keg_ref.directory?
|
|
||||||
Keg.new(linked_keg_ref.resolved_path)
|
|
||||||
elsif dirs.length == 1
|
|
||||||
Keg.new(dirs.first)
|
|
||||||
else
|
|
||||||
f = if name.include?("/") || File.exist?(name)
|
|
||||||
Formulary.factory(name)
|
|
||||||
else
|
|
||||||
Formulary.from_rack(rack)
|
|
||||||
end
|
|
||||||
|
|
||||||
unless (prefix = f.installed_prefix).directory?
|
|
||||||
raise MultipleVersionsInstalledError, "#{rack.basename} has multiple installed versions"
|
|
||||||
end
|
|
||||||
|
|
||||||
Keg.new(prefix)
|
|
||||||
end
|
|
||||||
rescue FormulaUnavailableError
|
|
||||||
raise MultipleVersionsInstalledError, <<~EOS
|
|
||||||
Multiple kegs installed to #{rack}
|
|
||||||
However we don't know which one you refer to.
|
|
||||||
Please delete (with rm -rf!) all but one and then try again.
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
180
Library/Homebrew/cli/named_args.rb
Normal file
180
Library/Homebrew/cli/named_args.rb
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "delegate"
|
||||||
|
|
||||||
|
module Homebrew
|
||||||
|
module CLI
|
||||||
|
class NamedArgs < SimpleDelegator
|
||||||
|
def initialize(*args, override_spec: nil, force_bottle: false, flags: [])
|
||||||
|
@args = args
|
||||||
|
@override_spec = override_spec
|
||||||
|
@force_bottle = force_bottle
|
||||||
|
@flags = flags
|
||||||
|
|
||||||
|
__setobj__(@args)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_formulae
|
||||||
|
@to_formulae ||= (downcased_unique_named - homebrew_tap_cask_names).map do |name|
|
||||||
|
Formulary.factory(name, spec, force_bottle: @force_bottle, flags: @flags)
|
||||||
|
end.uniq(&:name).freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_formulae_and_casks
|
||||||
|
@to_formulae_and_casks ||= begin
|
||||||
|
formulae_and_casks = []
|
||||||
|
|
||||||
|
downcased_unique_named.each do |name|
|
||||||
|
formulae_and_casks << Formulary.factory(name, spec)
|
||||||
|
|
||||||
|
puts "Treating #{name} as a formula. For the cask, use homebrew/cask/#{name}" if cask_exists_with_ref name
|
||||||
|
rescue FormulaUnavailableError
|
||||||
|
begin
|
||||||
|
formulae_and_casks << Cask::CaskLoader.load(name)
|
||||||
|
rescue Cask::CaskUnavailableError
|
||||||
|
raise "No available formula or cask with the name \"#{name}\""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
formulae_and_casks.freeze
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_resolved_formulae
|
||||||
|
@to_resolved_formulae ||= (downcased_unique_named - homebrew_tap_cask_names).map do |name|
|
||||||
|
Formulary.resolve(name, spec: spec(nil), force_bottle: @force_bottle, flags: @flags)
|
||||||
|
end.uniq(&:name).freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_resolved_formulae_to_casks
|
||||||
|
@to_resolved_formulae_to_casks ||= begin
|
||||||
|
resolved_formulae = []
|
||||||
|
casks = []
|
||||||
|
|
||||||
|
downcased_unique_named.each do |name|
|
||||||
|
resolved_formulae << Formulary.resolve(name, spec: spec(nil), force_bottle: @force_bottle, flags: @flags)
|
||||||
|
|
||||||
|
puts "Treating #{name} as a formula. For the cask, use homebrew/cask/#{name}" if cask_exists_with_ref name
|
||||||
|
rescue FormulaUnavailableError
|
||||||
|
begin
|
||||||
|
casks << Cask::CaskLoader.load(name)
|
||||||
|
rescue Cask::CaskUnavailableError
|
||||||
|
raise "No available formula or cask with the name \"#{name}\""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
[resolved_formulae.freeze, casks.freeze].freeze
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_formulae_paths
|
||||||
|
@to_formulae_paths ||= (downcased_unique_named - homebrew_tap_cask_names).map do |name|
|
||||||
|
Formulary.path(name)
|
||||||
|
end.uniq.freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_casks
|
||||||
|
@to_casks ||= downcased_unique_named.map(&Cask::CaskLoader.method(:load)).freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_kegs
|
||||||
|
@to_kegs ||= downcased_unique_named.map do |name|
|
||||||
|
resolve_keg name
|
||||||
|
rescue NoSuchKegError => e
|
||||||
|
if (reason = Homebrew::MissingFormula.suggest_command(name, "uninstall"))
|
||||||
|
$stderr.puts reason
|
||||||
|
end
|
||||||
|
raise e
|
||||||
|
end.freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_kegs_to_casks
|
||||||
|
@to_kegs_to_casks ||= begin
|
||||||
|
kegs = []
|
||||||
|
casks = []
|
||||||
|
|
||||||
|
downcased_unique_named.each do |name|
|
||||||
|
kegs << resolve_keg(name)
|
||||||
|
|
||||||
|
puts "Treating #{name} as a keg. For the cask, use homebrew/cask/#{name}" if cask_exists_with_ref name
|
||||||
|
rescue NoSuchKegError, FormulaUnavailableError
|
||||||
|
begin
|
||||||
|
casks << Cask::CaskLoader.load(name)
|
||||||
|
rescue Cask::CaskUnavailableError
|
||||||
|
raise "No installed keg or cask with the name \"#{name}\""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
[kegs.freeze, casks.freeze].freeze
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def homebrew_tap_cask_names
|
||||||
|
downcased_unique_named.grep(HOMEBREW_CASK_TAP_CASK_REGEX)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def downcased_unique_named
|
||||||
|
# Only lowercase names, not paths, bottle filenames or URLs
|
||||||
|
map do |arg|
|
||||||
|
if arg.include?("/") || arg.end_with?(".tar.gz") || File.exist?(arg)
|
||||||
|
arg
|
||||||
|
else
|
||||||
|
arg.downcase
|
||||||
|
end
|
||||||
|
end.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def spec(default = :stable)
|
||||||
|
@override_spec || default
|
||||||
|
end
|
||||||
|
|
||||||
|
def resolve_keg(name)
|
||||||
|
raise UsageError if name.blank?
|
||||||
|
|
||||||
|
rack = Formulary.to_rack(name.downcase)
|
||||||
|
|
||||||
|
dirs = rack.directory? ? rack.subdirs : []
|
||||||
|
raise NoSuchKegError, rack.basename if dirs.empty?
|
||||||
|
|
||||||
|
linked_keg_ref = HOMEBREW_LINKED_KEGS/rack.basename
|
||||||
|
opt_prefix = HOMEBREW_PREFIX/"opt/#{rack.basename}"
|
||||||
|
|
||||||
|
begin
|
||||||
|
if opt_prefix.symlink? && opt_prefix.directory?
|
||||||
|
Keg.new(opt_prefix.resolved_path)
|
||||||
|
elsif linked_keg_ref.symlink? && linked_keg_ref.directory?
|
||||||
|
Keg.new(linked_keg_ref.resolved_path)
|
||||||
|
elsif dirs.length == 1
|
||||||
|
Keg.new(dirs.first)
|
||||||
|
else
|
||||||
|
f = if name.include?("/") || File.exist?(name)
|
||||||
|
Formulary.factory(name)
|
||||||
|
else
|
||||||
|
Formulary.from_rack(rack)
|
||||||
|
end
|
||||||
|
|
||||||
|
unless (prefix = f.installed_prefix).directory?
|
||||||
|
raise MultipleVersionsInstalledError, "#{rack.basename} has multiple installed versions"
|
||||||
|
end
|
||||||
|
|
||||||
|
Keg.new(prefix)
|
||||||
|
end
|
||||||
|
rescue FormulaUnavailableError
|
||||||
|
raise MultipleVersionsInstalledError, <<~EOS
|
||||||
|
Multiple kegs installed to #{rack}
|
||||||
|
However we don't know which one you refer to.
|
||||||
|
Please delete (with rm -rf!) all but one and then try again.
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def cask_exists_with_ref(ref)
|
||||||
|
Cask::CaskLoader.load ref
|
||||||
|
rescue Cask::CaskUnavailableError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -43,9 +43,9 @@ module Homebrew
|
|||||||
Utils::Shell.from_path(args.shell)
|
Utils::Shell.from_path(args.shell)
|
||||||
end
|
end
|
||||||
|
|
||||||
env_keys = build_env_keys(ENV)
|
env_keys = BuildEnvironment.keys(ENV)
|
||||||
if shell.nil?
|
if shell.nil?
|
||||||
dump_build_env ENV
|
BuildEnvironment.dump ENV
|
||||||
else
|
else
|
||||||
env_keys.each do |key|
|
env_keys.each do |key|
|
||||||
puts Utils::Shell.export_value(key, ENV[key], shell)
|
puts Utils::Shell.export_value(key, ENV[key], shell)
|
||||||
|
|||||||
@ -25,10 +25,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
homepages = args.formulae_and_casks.map do |formula_or_cask|
|
homepages = args.formulae_and_casks.map do |formula_or_cask|
|
||||||
disclaimer = disclaimers(formula_or_cask)
|
puts "Opening homepage for #{name_of(formula_or_cask)}"
|
||||||
disclaimer = " (#{disclaimer})" if disclaimer.present?
|
|
||||||
|
|
||||||
puts "Opening homepage for #{name_of(formula_or_cask)}#{disclaimer}"
|
|
||||||
formula_or_cask.homepage
|
formula_or_cask.homepage
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -42,15 +39,4 @@ module Homebrew
|
|||||||
"Cask #{formula_or_cask.token}"
|
"Cask #{formula_or_cask.token}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def disclaimers(formula_or_cask)
|
|
||||||
return unless formula_or_cask.is_a? Formula
|
|
||||||
|
|
||||||
begin
|
|
||||||
cask = Cask::CaskLoader.load formula_or_cask.name
|
|
||||||
"for the cask, use #{cask.tap.name}/#{cask.token}"
|
|
||||||
rescue Cask::CaskUnavailableError
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
require "compilers"
|
require "compilers"
|
||||||
|
|
||||||
|
# Combination of C++ standard library and compiler.
|
||||||
class CxxStdlib
|
class CxxStdlib
|
||||||
include CompilerConstants
|
include CompilerConstants
|
||||||
|
|
||||||
|
# Error for when a formula's dependency was built with a different C++ standard library.
|
||||||
class CompatibilityError < StandardError
|
class CompatibilityError < StandardError
|
||||||
def initialize(formula, dep, stdlib)
|
def initialize(formula, dep, stdlib)
|
||||||
super <<~EOS
|
super <<~EOS
|
||||||
@ -17,8 +19,8 @@ class CxxStdlib
|
|||||||
def self.create(type, compiler)
|
def self.create(type, compiler)
|
||||||
raise ArgumentError, "Invalid C++ stdlib type: #{type}" if type && ![:libstdcxx, :libcxx].include?(type)
|
raise ArgumentError, "Invalid C++ stdlib type: #{type}" if type && ![:libstdcxx, :libcxx].include?(type)
|
||||||
|
|
||||||
klass = (compiler.to_s =~ GNU_GCC_REGEXP) ? GnuStdlib : AppleStdlib
|
apple_compiler = compiler.to_s.match?(GNU_GCC_REGEXP) ? false : true
|
||||||
klass.new(type, compiler)
|
CxxStdlib.new(type, compiler, apple_compiler)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.check_compatibility(formula, deps, keg, compiler)
|
def self.check_compatibility(formula, deps, keg, compiler)
|
||||||
@ -35,9 +37,10 @@ class CxxStdlib
|
|||||||
|
|
||||||
attr_reader :type, :compiler
|
attr_reader :type, :compiler
|
||||||
|
|
||||||
def initialize(type, compiler)
|
def initialize(type, compiler, apple_compiler)
|
||||||
@type = type
|
@type = type
|
||||||
@compiler = compiler.to_sym
|
@compiler = compiler.to_sym
|
||||||
|
@apple_compiler = apple_compiler
|
||||||
end
|
end
|
||||||
|
|
||||||
# If either package doesn't use C++, all is well.
|
# If either package doesn't use C++, all is well.
|
||||||
@ -72,15 +75,7 @@ class CxxStdlib
|
|||||||
"#<#{self.class.name}: #{compiler} #{type}>"
|
"#<#{self.class.name}: #{compiler} #{type}>"
|
||||||
end
|
end
|
||||||
|
|
||||||
class AppleStdlib < CxxStdlib
|
|
||||||
def apple_compiler?
|
def apple_compiler?
|
||||||
true
|
@apple_compiler
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class GnuStdlib < CxxStdlib
|
|
||||||
def apple_compiler?
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -11,7 +11,7 @@ module IRB
|
|||||||
|
|
||||||
def start_within(binding)
|
def start_within(binding)
|
||||||
unless @setup_done
|
unless @setup_done
|
||||||
setup(nil)
|
setup(nil, argv: [])
|
||||||
@setup_done = true
|
@setup_done = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -350,6 +350,11 @@ module Homebrew
|
|||||||
"LGPL-3.0" => ["LGPL-3.0-only", "LGPL-3.0-or-later"],
|
"LGPL-3.0" => ["LGPL-3.0-only", "LGPL-3.0-or-later"],
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
PERMITTED_FORMULA_LICENSE_MISMATCHES = {
|
||||||
|
"cmockery" => "0.1.2",
|
||||||
|
"scw@1" => "1.20",
|
||||||
|
}.freeze
|
||||||
|
|
||||||
def audit_license
|
def audit_license
|
||||||
if formula.license.present?
|
if formula.license.present?
|
||||||
non_standard_licenses = formula.license.map do |license|
|
non_standard_licenses = formula.license.map do |license|
|
||||||
@ -380,12 +385,13 @@ module Homebrew
|
|||||||
|
|
||||||
return unless @online
|
return unless @online
|
||||||
|
|
||||||
user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if @new_formula
|
user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*})
|
||||||
return if user.blank?
|
return if user.blank?
|
||||||
|
|
||||||
github_license = GitHub.get_repo_license(user, repo)
|
github_license = GitHub.get_repo_license(user, repo)
|
||||||
return if github_license && (formula.license + ["NOASSERTION"]).include?(github_license)
|
return if github_license && (formula.license + ["NOASSERTION"]).include?(github_license)
|
||||||
return if PERMITTED_LICENSE_MISMATCHES[github_license]&.any? { |license| formula.license.include? license }
|
return if PERMITTED_LICENSE_MISMATCHES[github_license]&.any? { |license| formula.license.include? license }
|
||||||
|
return if PERMITTED_FORMULA_LICENSE_MISMATCHES[formula.name] == formula.version
|
||||||
|
|
||||||
problem "Formula license #{formula.license} does not match GitHub license #{Array(github_license)}."
|
problem "Formula license #{formula.license} does not match GitHub license #{Array(github_license)}."
|
||||||
|
|
||||||
|
|||||||
@ -294,7 +294,10 @@ module Homebrew
|
|||||||
"",
|
"",
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
new_contents = inreplace_pairs(formula.path, replacement_pairs.uniq.compact, args: args)
|
new_contents = Utils::Inreplace.inreplace_pairs(formula.path,
|
||||||
|
replacement_pairs.uniq.compact,
|
||||||
|
read_only_run: read_only_run,
|
||||||
|
silent: args.quiet?)
|
||||||
|
|
||||||
new_formula_version = formula_version(formula, requested_spec, new_contents)
|
new_formula_version = formula_version(formula, requested_spec, new_contents)
|
||||||
|
|
||||||
@ -462,34 +465,6 @@ module Homebrew
|
|||||||
[remote_url, username]
|
[remote_url, username]
|
||||||
end
|
end
|
||||||
|
|
||||||
def inreplace_pairs(path, replacement_pairs, args:)
|
|
||||||
read_only_run = args.dry_run? && !args.write?
|
|
||||||
if read_only_run
|
|
||||||
str = path.open("r") { |f| Formulary.ensure_utf8_encoding(f).read }
|
|
||||||
contents = StringInreplaceExtension.new(str)
|
|
||||||
replacement_pairs.each do |old, new|
|
|
||||||
ohai "replace #{old.inspect} with #{new.inspect}" unless args.quiet?
|
|
||||||
raise "No old value for new value #{new}! Did you pass the wrong arguments?" unless old
|
|
||||||
|
|
||||||
contents.gsub!(old, new)
|
|
||||||
end
|
|
||||||
raise Utils::InreplaceError, path => contents.errors unless contents.errors.empty?
|
|
||||||
|
|
||||||
path.atomic_write(contents.inreplace_string) if args.write?
|
|
||||||
contents.inreplace_string
|
|
||||||
else
|
|
||||||
Utils::Inreplace.inreplace(path) do |s|
|
|
||||||
replacement_pairs.each do |old, new|
|
|
||||||
ohai "replace #{old.inspect} with #{new.inspect}" unless args.quiet?
|
|
||||||
raise "No old value for new value #{new}! Did you pass the wrong arguments?" unless old
|
|
||||||
|
|
||||||
s.gsub!(old, new)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
path.open("r") { |f| Formulary.ensure_utf8_encoding(f).read }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def formula_version(formula, spec, contents = nil)
|
def formula_version(formula, spec, contents = nil)
|
||||||
name = formula.name
|
name = formula.name
|
||||||
path = formula.path
|
path = formula.path
|
||||||
|
|||||||
@ -49,7 +49,7 @@ module Homebrew
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
ohai "#{prs.size} matching pull requests:"
|
ohai "#{prs.count} matching pull #{"request".pluralize(prs.count)}:"
|
||||||
pr_urls = []
|
pr_urls = []
|
||||||
prs.each do |pr|
|
prs.each do |pr|
|
||||||
puts "#{tap.full_name unless tap.core_tap?}##{pr["number"]}: #{pr["title"]}"
|
puts "#{tap.full_name unless tap.core_tap?}##{pr["number"]}: #{pr["title"]}"
|
||||||
|
|||||||
@ -99,6 +99,15 @@ class DevelopmentTools
|
|||||||
def subversion_handles_most_https_certificates?
|
def subversion_handles_most_https_certificates?
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def build_system_info
|
||||||
|
{
|
||||||
|
"os" => ENV["HOMEBREW_SYSTEM"],
|
||||||
|
"os_version" => OS_VERSION,
|
||||||
|
"cpu_family" => Hardware::CPU.family,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
alias generic_build_system_info build_system_info
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,9 @@ require "cask/caskroom"
|
|||||||
require "cask/quarantine"
|
require "cask/quarantine"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
|
# Module containing diagnostic checks.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
module Diagnostic
|
module Diagnostic
|
||||||
def self.missing_deps(ff, hide = nil)
|
def self.missing_deps(ff, hide = nil)
|
||||||
missing = {}
|
missing = {}
|
||||||
@ -25,44 +28,7 @@ module Homebrew
|
|||||||
missing
|
missing
|
||||||
end
|
end
|
||||||
|
|
||||||
class Volumes
|
# Diagnostic checks.
|
||||||
def initialize
|
|
||||||
@volumes = get_mounts
|
|
||||||
end
|
|
||||||
|
|
||||||
def which(path)
|
|
||||||
vols = get_mounts path
|
|
||||||
|
|
||||||
# no volume found
|
|
||||||
return -1 if vols.empty?
|
|
||||||
|
|
||||||
vol_index = @volumes.index(vols[0])
|
|
||||||
# volume not found in volume list
|
|
||||||
return -1 if vol_index.nil?
|
|
||||||
|
|
||||||
vol_index
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_mounts(path = nil)
|
|
||||||
vols = []
|
|
||||||
# get the volume of path, if path is nil returns all volumes
|
|
||||||
|
|
||||||
args = %w[/bin/df -P]
|
|
||||||
args << path if path
|
|
||||||
|
|
||||||
Utils.popen_read(*args) do |io|
|
|
||||||
io.each_line do |line|
|
|
||||||
case line.chomp
|
|
||||||
# regex matches: /dev/disk0s2 489562928 440803616 48247312 91% /
|
|
||||||
when /^.+\s+[0-9]+\s+[0-9]+\s+[0-9]+\s+[0-9]{1,3}%\s+(.+)/
|
|
||||||
vols << Regexp.last_match(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
vols
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Checks
|
class Checks
|
||||||
def initialize(verbose = true)
|
def initialize(verbose = true)
|
||||||
@verbose = verbose
|
@verbose = verbose
|
||||||
|
|||||||
@ -369,7 +369,7 @@ class BuildError < RuntimeError
|
|||||||
ohai "Configuration"
|
ohai "Configuration"
|
||||||
SystemConfig.dump_verbose_config
|
SystemConfig.dump_verbose_config
|
||||||
ohai "ENV"
|
ohai "ENV"
|
||||||
Homebrew.dump_build_env(env)
|
BuildEnvironment.dump env
|
||||||
puts
|
puts
|
||||||
onoe "#{formula.full_name} #{formula.version} did not build"
|
onoe "#{formula.full_name} #{formula.version} did not build"
|
||||||
unless (logs = Dir["#{formula.logs}/*"]).empty?
|
unless (logs = Dir["#{formula.logs}/*"]).empty?
|
||||||
|
|||||||
@ -38,7 +38,7 @@ module Homebrew
|
|||||||
f.close
|
f.close
|
||||||
return if system f.path
|
return if system f.path
|
||||||
|
|
||||||
<<~EOS.undent
|
<<~EOS
|
||||||
The directory #{HOMEBREW_TEMP} does not permit executing
|
The directory #{HOMEBREW_TEMP} does not permit executing
|
||||||
programs. It is likely mounted as "noexec". Please set HOMEBREW_TEMP
|
programs. It is likely mounted as "noexec". Please set HOMEBREW_TEMP
|
||||||
in your #{shell_profile} to a different directory, for example:
|
in your #{shell_profile} to a different directory, for example:
|
||||||
|
|||||||
@ -14,6 +14,12 @@ module Homebrew
|
|||||||
"/system/bin/linker64",
|
"/system/bin/linker64",
|
||||||
"/system/bin/linker",
|
"/system/bin/linker",
|
||||||
].freeze
|
].freeze
|
||||||
|
private_constant :DYNAMIC_LINKERS
|
||||||
|
|
||||||
|
def perform_preinstall_checks(all_fatal: false, cc: nil)
|
||||||
|
generic_perform_preinstall_checks(all_fatal: all_fatal, cc: cc)
|
||||||
|
symlink_ld_so
|
||||||
|
end
|
||||||
|
|
||||||
def check_cpu
|
def check_cpu
|
||||||
return if Hardware::CPU.intel? && Hardware::CPU.is_64_bit?
|
return if Hardware::CPU.intel? && Hardware::CPU.is_64_bit?
|
||||||
@ -28,6 +34,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
abort message
|
abort message
|
||||||
end
|
end
|
||||||
|
private_class_method :check_cpu
|
||||||
|
|
||||||
def symlink_ld_so
|
def symlink_ld_so
|
||||||
brew_ld_so = HOMEBREW_PREFIX/"lib/ld.so"
|
brew_ld_so = HOMEBREW_PREFIX/"lib/ld.so"
|
||||||
@ -42,10 +49,6 @@ module Homebrew
|
|||||||
FileUtils.mkdir_p HOMEBREW_PREFIX/"lib"
|
FileUtils.mkdir_p HOMEBREW_PREFIX/"lib"
|
||||||
FileUtils.ln_sf ld_so, brew_ld_so
|
FileUtils.ln_sf ld_so, brew_ld_so
|
||||||
end
|
end
|
||||||
|
private_class_method :symlink_ld_so
|
||||||
def perform_preinstall_checks(all_fatal: false, cc: nil)
|
|
||||||
generic_perform_preinstall_checks(all_fatal: all_fatal, cc: cc)
|
|
||||||
symlink_ld_so
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -56,5 +56,13 @@ class DevelopmentTools
|
|||||||
brew install gcc
|
brew install gcc
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def build_system_info
|
||||||
|
build_info = {
|
||||||
|
"xcode" => MacOS::Xcode.version.to_s.presence,
|
||||||
|
"clt" => MacOS::CLT.version.to_s.presence,
|
||||||
|
}
|
||||||
|
generic_build_system_info.merge build_info
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -2,6 +2,44 @@
|
|||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
module Diagnostic
|
module Diagnostic
|
||||||
|
class Volumes
|
||||||
|
def initialize
|
||||||
|
@volumes = get_mounts
|
||||||
|
end
|
||||||
|
|
||||||
|
def which(path)
|
||||||
|
vols = get_mounts path
|
||||||
|
|
||||||
|
# no volume found
|
||||||
|
return -1 if vols.empty?
|
||||||
|
|
||||||
|
vol_index = @volumes.index(vols[0])
|
||||||
|
# volume not found in volume list
|
||||||
|
return -1 if vol_index.nil?
|
||||||
|
|
||||||
|
vol_index
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_mounts(path = nil)
|
||||||
|
vols = []
|
||||||
|
# get the volume of path, if path is nil returns all volumes
|
||||||
|
|
||||||
|
args = %w[/bin/df -P]
|
||||||
|
args << path if path
|
||||||
|
|
||||||
|
Utils.popen_read(*args) do |io|
|
||||||
|
io.each_line do |line|
|
||||||
|
case line.chomp
|
||||||
|
# regex matches: /dev/disk0s2 489562928 440803616 48247312 91% /
|
||||||
|
when /^.+\s+[0-9]+\s+[0-9]+\s+[0-9]+\s+[0-9]{1,3}%\s+(.+)/
|
||||||
|
vols << Regexp.last_match(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vols
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class Checks
|
class Checks
|
||||||
undef fatal_build_from_source_checks, supported_configuration_checks,
|
undef fatal_build_from_source_checks, supported_configuration_checks,
|
||||||
build_from_source_checks
|
build_from_source_checks
|
||||||
|
|||||||
@ -2020,7 +2020,7 @@ class Formula
|
|||||||
|
|
||||||
SystemConfig.dump_verbose_config(log)
|
SystemConfig.dump_verbose_config(log)
|
||||||
log.puts
|
log.puts
|
||||||
Homebrew.dump_build_env(env, log)
|
BuildEnvironment.dump env, log
|
||||||
|
|
||||||
raise BuildError.new(self, cmd, args, env)
|
raise BuildError.new(self, cmd, args, env)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -21,7 +21,6 @@ require "cmd/install"
|
|||||||
require "find"
|
require "find"
|
||||||
|
|
||||||
class FormulaInstaller
|
class FormulaInstaller
|
||||||
include Homebrew::Install
|
|
||||||
include FormulaCellarChecks
|
include FormulaCellarChecks
|
||||||
extend Predicable
|
extend Predicable
|
||||||
|
|
||||||
@ -261,7 +260,9 @@ class FormulaInstaller
|
|||||||
lock
|
lock
|
||||||
|
|
||||||
start_time = Time.now
|
start_time = Time.now
|
||||||
perform_build_from_source_checks if !formula.bottle_unneeded? && !pour_bottle? && DevelopmentTools.installed?
|
if !formula.bottle_unneeded? && !pour_bottle? && DevelopmentTools.installed?
|
||||||
|
Homebrew::Install.perform_build_from_source_checks
|
||||||
|
end
|
||||||
|
|
||||||
# not in initialize so upgrade can unlink the active keg before calling this
|
# not in initialize so upgrade can unlink the active keg before calling this
|
||||||
# function but after instantiating this class so that it can avoid having to
|
# function but after instantiating this class so that it can avoid having to
|
||||||
|
|||||||
@ -64,6 +64,9 @@ class FormulaVersions
|
|||||||
versions_seen = (map.keys + [f.pkg_version]).uniq.length
|
versions_seen = (map.keys + [f.pkg_version]).uniq.length
|
||||||
end
|
end
|
||||||
return map if versions_seen > MAX_VERSIONS_DEPTH
|
return map if versions_seen > MAX_VERSIONS_DEPTH
|
||||||
|
rescue MacOSVersionError => e
|
||||||
|
odebug "#{e} in #{name} at revision #{rev}" if debug?
|
||||||
|
break
|
||||||
end
|
end
|
||||||
map
|
map
|
||||||
end
|
end
|
||||||
|
|||||||
@ -6,9 +6,27 @@ require "hardware"
|
|||||||
require "development_tools"
|
require "development_tools"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
|
# Helper module for performing (pre-)install checks.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
module Install
|
module Install
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
|
def perform_preinstall_checks(all_fatal: false, cc: nil)
|
||||||
|
check_cpu
|
||||||
|
attempt_directory_creation
|
||||||
|
check_cc_argv(cc)
|
||||||
|
diagnostic_checks(:supported_configuration_checks, fatal: all_fatal)
|
||||||
|
diagnostic_checks(:fatal_preinstall_checks)
|
||||||
|
end
|
||||||
|
alias generic_perform_preinstall_checks perform_preinstall_checks
|
||||||
|
module_function :generic_perform_preinstall_checks
|
||||||
|
|
||||||
|
def perform_build_from_source_checks(all_fatal: false)
|
||||||
|
diagnostic_checks(:fatal_build_from_source_checks)
|
||||||
|
diagnostic_checks(:build_from_source_checks, fatal: all_fatal)
|
||||||
|
end
|
||||||
|
|
||||||
def check_cpu
|
def check_cpu
|
||||||
return if Hardware::CPU.intel? && Hardware::CPU.is_64_bit?
|
return if Hardware::CPU.intel? && Hardware::CPU.is_64_bit?
|
||||||
|
|
||||||
@ -24,6 +42,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
abort message
|
abort message
|
||||||
end
|
end
|
||||||
|
private_class_method :check_cpu
|
||||||
|
|
||||||
def attempt_directory_creation
|
def attempt_directory_creation
|
||||||
Keg::MUST_EXIST_DIRECTORIES.each do |dir|
|
Keg::MUST_EXIST_DIRECTORIES.each do |dir|
|
||||||
@ -38,6 +57,7 @@ module Homebrew
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
private_class_method :attempt_directory_creation
|
||||||
|
|
||||||
def check_cc_argv(cc)
|
def check_cc_argv(cc)
|
||||||
return unless cc
|
return unless cc
|
||||||
@ -48,21 +68,7 @@ module Homebrew
|
|||||||
#{@checks.please_create_pull_requests}
|
#{@checks.please_create_pull_requests}
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
private_class_method :check_cc_argv
|
||||||
def perform_preinstall_checks(all_fatal: false, cc: nil)
|
|
||||||
check_cpu
|
|
||||||
attempt_directory_creation
|
|
||||||
check_cc_argv(cc)
|
|
||||||
diagnostic_checks(:supported_configuration_checks, fatal: all_fatal)
|
|
||||||
diagnostic_checks(:fatal_preinstall_checks)
|
|
||||||
end
|
|
||||||
alias generic_perform_preinstall_checks perform_preinstall_checks
|
|
||||||
module_function :generic_perform_preinstall_checks
|
|
||||||
|
|
||||||
def perform_build_from_source_checks(all_fatal: false)
|
|
||||||
diagnostic_checks(:fatal_build_from_source_checks)
|
|
||||||
diagnostic_checks(:build_from_source_checks, fatal: all_fatal)
|
|
||||||
end
|
|
||||||
|
|
||||||
def diagnostic_checks(type, fatal: true)
|
def diagnostic_checks(type, fatal: true)
|
||||||
@checks ||= Diagnostic::Checks.new
|
@checks ||= Diagnostic::Checks.new
|
||||||
@ -80,6 +86,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
exit 1 if failed && fatal
|
exit 1 if failed && fatal
|
||||||
end
|
end
|
||||||
|
private_class_method :diagnostic_checks
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -57,6 +57,10 @@ module OS
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sdk_path
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
module Xcode
|
module Xcode
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
|
|||||||
@ -36,6 +36,7 @@ class Tab < OpenStruct
|
|||||||
"stdlib" => stdlib,
|
"stdlib" => stdlib,
|
||||||
"aliases" => formula.aliases,
|
"aliases" => formula.aliases,
|
||||||
"runtime_dependencies" => Tab.runtime_deps_hash(runtime_deps),
|
"runtime_dependencies" => Tab.runtime_deps_hash(runtime_deps),
|
||||||
|
"arch" => Hardware::CPU.arch,
|
||||||
"source" => {
|
"source" => {
|
||||||
"path" => formula.specified_path.to_s,
|
"path" => formula.specified_path.to_s,
|
||||||
"tap" => formula.tap&.name,
|
"tap" => formula.tap&.name,
|
||||||
@ -47,6 +48,7 @@ class Tab < OpenStruct
|
|||||||
"version_scheme" => formula.version_scheme,
|
"version_scheme" => formula.version_scheme,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"built_on" => DevelopmentTools.build_system_info,
|
||||||
}
|
}
|
||||||
|
|
||||||
new(attributes)
|
new(attributes)
|
||||||
@ -198,6 +200,7 @@ class Tab < OpenStruct
|
|||||||
"version_scheme" => 0,
|
"version_scheme" => 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"built_on" => DevelopmentTools.generic_build_system_info,
|
||||||
}
|
}
|
||||||
|
|
||||||
new(attributes)
|
new(attributes)
|
||||||
@ -344,6 +347,7 @@ class Tab < OpenStruct
|
|||||||
"aliases" => aliases,
|
"aliases" => aliases,
|
||||||
"runtime_dependencies" => runtime_dependencies,
|
"runtime_dependencies" => runtime_dependencies,
|
||||||
"source" => source,
|
"source" => source,
|
||||||
|
"built_on" => built_on,
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON.generate(attributes, options)
|
JSON.generate(attributes, options)
|
||||||
|
|||||||
@ -25,14 +25,9 @@ describe Cask::Cmd::Cache, :cask do
|
|||||||
cache: Cask::Cache.path, **local_caffeine.url.specs
|
cache: Cask::Cache.path, **local_caffeine.url.specs
|
||||||
).cached_location
|
).cached_location
|
||||||
|
|
||||||
expect do
|
expect(described_class.cached_location(local_transmission))
|
||||||
described_class.run("local-transmission", "local-caffeine")
|
.to eql transmission_location
|
||||||
end.to output("#{transmission_location}\n#{caffeine_location}\n").to_stdout
|
expect(described_class.cached_location(local_caffeine))
|
||||||
end
|
.to eql caffeine_location
|
||||||
|
|
||||||
it "properly handles Casks that are not present" do
|
|
||||||
expect {
|
|
||||||
described_class.run("notacask")
|
|
||||||
}.to raise_error(Cask::CaskUnavailableError)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -120,7 +120,7 @@ describe Caveats do
|
|||||||
"plist_test.plist"
|
"plist_test.plist"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
allow(ENV).to receive(:[]).with("TMUX").and_return(true)
|
ENV["TMUX"] = "1"
|
||||||
allow(Homebrew).to receive(:_system).with("/usr/bin/pbpaste").and_return(false)
|
allow(Homebrew).to receive(:_system).with("/usr/bin/pbpaste").and_return(false)
|
||||||
caveats = described_class.new(f).caveats
|
caveats = described_class.new(f).caveats
|
||||||
|
|
||||||
|
|||||||
@ -5,9 +5,9 @@ require "cleanup"
|
|||||||
require "cask/cache"
|
require "cask/cache"
|
||||||
require "fileutils"
|
require "fileutils"
|
||||||
|
|
||||||
using CleanupRefinement
|
using Homebrew::Cleanup::CleanupRefinement
|
||||||
|
|
||||||
describe CleanupRefinement do
|
describe Homebrew::Cleanup::CleanupRefinement do
|
||||||
describe "::prune?" do
|
describe "::prune?" do
|
||||||
alias_matcher :be_pruned, :be_prune
|
alias_matcher :be_pruned, :be_prune
|
||||||
|
|
||||||
|
|||||||
110
Library/Homebrew/test/cli/named_args_spec.rb
Normal file
110
Library/Homebrew/test/cli/named_args_spec.rb
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "cli/named_args"
|
||||||
|
|
||||||
|
describe Homebrew::CLI::NamedArgs do
|
||||||
|
let(:foo) do
|
||||||
|
formula "foo" do
|
||||||
|
url "https://brew.sh"
|
||||||
|
version "1.0"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:foo_keg) do
|
||||||
|
path = (HOMEBREW_CELLAR/"foo/1.0").resolved_path
|
||||||
|
mkdir_p path
|
||||||
|
Keg.new(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:bar) do
|
||||||
|
formula "bar" do
|
||||||
|
url "https://brew.sh"
|
||||||
|
version "1.0"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:bar_keg) do
|
||||||
|
path = (HOMEBREW_CELLAR/"bar/1.0").resolved_path
|
||||||
|
mkdir_p path
|
||||||
|
Keg.new(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:baz) do
|
||||||
|
Cask::CaskLoader.load(+<<~RUBY)
|
||||||
|
cask "baz" do
|
||||||
|
version "1.0"
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_formulae" do
|
||||||
|
it "returns formulae" do
|
||||||
|
stub_formula_loader foo, call_original: true
|
||||||
|
stub_formula_loader bar
|
||||||
|
|
||||||
|
expect(described_class.new("foo", "bar").to_formulae).to eq [foo, bar]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_formulae_and_casks" do
|
||||||
|
it "returns formulae and casks" do
|
||||||
|
stub_formula_loader foo, call_original: true
|
||||||
|
stub_cask_loader baz, call_original: true
|
||||||
|
|
||||||
|
expect(described_class.new("foo", "baz").to_formulae_and_casks).to eq [foo, baz]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_resolved_formulae" do
|
||||||
|
it "returns resolved formulae" do
|
||||||
|
allow(Formulary).to receive(:resolve).and_return(foo, bar)
|
||||||
|
|
||||||
|
expect(described_class.new("foo", "bar").to_resolved_formulae).to eq [foo, bar]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_resolved_formulae_to_casks" do
|
||||||
|
it "returns resolved formulae, as well as casks" do
|
||||||
|
allow(Formulary).to receive(:resolve).and_call_original
|
||||||
|
allow(Formulary).to receive(:resolve).with("foo", any_args).and_return foo
|
||||||
|
stub_cask_loader baz, call_original: true
|
||||||
|
|
||||||
|
resolved_formulae, casks = described_class.new("foo", "baz").to_resolved_formulae_to_casks
|
||||||
|
|
||||||
|
expect(resolved_formulae).to eq [foo]
|
||||||
|
expect(casks).to eq [baz]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_casks" do
|
||||||
|
it "returns casks" do
|
||||||
|
stub_cask_loader baz
|
||||||
|
|
||||||
|
expect(described_class.new("baz").to_casks).to eq [baz]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_kegs" do
|
||||||
|
it "returns kegs" do
|
||||||
|
named_args = described_class.new("foo", "bar")
|
||||||
|
allow(named_args).to receive(:resolve_keg).with("foo").and_return foo_keg
|
||||||
|
allow(named_args).to receive(:resolve_keg).with("bar").and_return bar_keg
|
||||||
|
|
||||||
|
expect(named_args.to_kegs).to eq [foo_keg, bar_keg]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_kegs_to_casks" do
|
||||||
|
it "returns kegs, as well as casks" do
|
||||||
|
named_args = described_class.new("foo", "baz")
|
||||||
|
allow(named_args).to receive(:resolve_keg).and_call_original
|
||||||
|
allow(named_args).to receive(:resolve_keg).with("foo").and_return foo_keg
|
||||||
|
stub_cask_loader baz, call_original: true
|
||||||
|
|
||||||
|
kegs, casks = named_args.to_kegs_to_casks
|
||||||
|
|
||||||
|
expect(kegs).to eq [foo_keg]
|
||||||
|
expect(casks).to eq [baz]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -305,4 +305,12 @@ describe Utils::Inreplace do
|
|||||||
end
|
end
|
||||||
}.to raise_error(Utils::InreplaceError)
|
}.to raise_error(Utils::InreplaceError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#inreplace_pairs" do
|
||||||
|
it "raises error if there is no old value" do
|
||||||
|
expect {
|
||||||
|
described_class.inreplace_pairs(file.path, [[nil, "f"]])
|
||||||
|
}.to raise_error(Utils::InreplaceError)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -36,6 +36,7 @@ $LOAD_PATH.push(File.expand_path("#{ENV["HOMEBREW_LIBRARY"]}/Homebrew/test/suppo
|
|||||||
require_relative "../global"
|
require_relative "../global"
|
||||||
|
|
||||||
require "test/support/no_seed_progress_formatter"
|
require "test/support/no_seed_progress_formatter"
|
||||||
|
require "test/support/helper/cask"
|
||||||
require "test/support/helper/fixtures"
|
require "test/support/helper/fixtures"
|
||||||
require "test/support/helper/formula"
|
require "test/support/helper/formula"
|
||||||
require "test/support/helper/mktmpdir"
|
require "test/support/helper/mktmpdir"
|
||||||
@ -86,6 +87,7 @@ RSpec.configure do |config|
|
|||||||
|
|
||||||
config.include(RuboCop::RSpec::ExpectOffense)
|
config.include(RuboCop::RSpec::ExpectOffense)
|
||||||
|
|
||||||
|
config.include(Test::Helper::Cask)
|
||||||
config.include(Test::Helper::Fixtures)
|
config.include(Test::Helper::Fixtures)
|
||||||
config.include(Test::Helper::Formula)
|
config.include(Test::Helper::Formula)
|
||||||
config.include(Test::Helper::MkTmpDir)
|
config.include(Test::Helper::MkTmpDir)
|
||||||
|
|||||||
16
Library/Homebrew/test/support/helper/cask.rb
Normal file
16
Library/Homebrew/test/support/helper/cask.rb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "cask/cask_loader"
|
||||||
|
|
||||||
|
module Test
|
||||||
|
module Helper
|
||||||
|
module Cask
|
||||||
|
def stub_cask_loader(cask, ref = cask.token, call_original: false)
|
||||||
|
allow(::Cask::CaskLoader).to receive(:for).and_call_original if call_original
|
||||||
|
|
||||||
|
loader = ::Cask::CaskLoader::FromInstanceLoader.new cask
|
||||||
|
allow(::Cask::CaskLoader).to receive(:for).with(ref).and_return(loader)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -11,7 +11,9 @@ module Test
|
|||||||
|
|
||||||
# Use a stubbed {Formulary::FormulaLoader} to make a given formula be found
|
# Use a stubbed {Formulary::FormulaLoader} to make a given formula be found
|
||||||
# when loading from {Formulary} with `ref`.
|
# when loading from {Formulary} with `ref`.
|
||||||
def stub_formula_loader(formula, ref = formula.full_name)
|
def stub_formula_loader(formula, ref = formula.full_name, call_original: false)
|
||||||
|
allow(Formulary).to receive(:loader_for).and_call_original if call_original
|
||||||
|
|
||||||
loader = double(get_formula: formula)
|
loader = double(get_formula: formula)
|
||||||
allow(Formulary).to receive(:loader_for).with(ref, from: :keg).and_return(loader)
|
allow(Formulary).to receive(:loader_for).with(ref, from: :keg).and_return(loader)
|
||||||
allow(Formulary).to receive(:loader_for).with(ref, from: nil).and_return(loader)
|
allow(Formulary).to receive(:loader_for).with(ref, from: nil).and_return(loader)
|
||||||
|
|||||||
@ -11,6 +11,8 @@ module Utils
|
|||||||
end
|
end
|
||||||
|
|
||||||
module Inreplace
|
module Inreplace
|
||||||
|
module_function
|
||||||
|
|
||||||
# Sometimes we have to change a bit before we install. Mostly we
|
# Sometimes we have to change a bit before we install. Mostly we
|
||||||
# prefer a patch but if you need the `prefix` of this formula in the
|
# prefer a patch but if you need the `prefix` of this formula in the
|
||||||
# patch you have to resort to `inreplace`, because in the patch
|
# patch you have to resort to `inreplace`, because in the patch
|
||||||
@ -42,6 +44,23 @@ module Utils
|
|||||||
|
|
||||||
raise InreplaceError, errors unless errors.empty?
|
raise InreplaceError, errors unless errors.empty?
|
||||||
end
|
end
|
||||||
module_function :inreplace
|
|
||||||
|
def inreplace_pairs(path, replacement_pairs, read_only_run: false, silent: false)
|
||||||
|
str = File.open(path, "rb", &:read)
|
||||||
|
contents = StringInreplaceExtension.new(str)
|
||||||
|
replacement_pairs.each do |old, new|
|
||||||
|
ohai "replace #{old.inspect} with #{new.inspect}" unless silent
|
||||||
|
unless old
|
||||||
|
contents.errors << "No old value for new value #{new}! Did you pass the wrong arguments?"
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
contents.gsub!(old, new)
|
||||||
|
end
|
||||||
|
raise InreplaceError, path => contents.errors unless contents.errors.empty?
|
||||||
|
|
||||||
|
Pathname(path).atomic_write(contents.inreplace_string) unless read_only_run
|
||||||
|
contents.inreplace_string
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -51,7 +51,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel-1.19.2/lib"
|
|||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.1.0/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parallel_tests-3.1.0/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-2.7.1.4/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parser-2.7.1.4/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.0.0/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rainbow-3.0.0/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.5866/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-runtime-0.5.5869/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parlour-4.0.1/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/parlour-4.0.1/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.2.0/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/patchelf-1.2.0/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.5.0/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/plist-3.5.0/lib"
|
||||||
@ -74,9 +74,9 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-progressbar-1.10
|
|||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-1.7.0/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/unicode-display_width-1.7.0/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-0.88.0/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-0.88.0/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.7.1/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1.7.1/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-1.42.0/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-1.43.1/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.2.0/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.2.0/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.5866-universal-darwin-19/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-static-0.5.5869-universal-darwin-19/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.5866/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/sorbet-0.5.5869/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thor-1.0.1/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/thor-1.0.1/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tapioca-0.4.1/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/tapioca-0.4.1/lib"
|
||||||
|
|||||||
@ -1,72 +0,0 @@
|
|||||||
# 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
|
|
||||||
# subject { described_class }
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# describe 'TestedClass::VERSION' do
|
|
||||||
# subject { Object.const_get(self.class.description) }
|
|
||||||
# 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.'
|
|
||||||
|
|
||||||
def_node_matcher :valid_describe?, <<-PATTERN
|
|
||||||
{
|
|
||||||
(send #{RSPEC} :describe const ...)
|
|
||||||
(send #{RSPEC} :describe)
|
|
||||||
}
|
|
||||||
PATTERN
|
|
||||||
|
|
||||||
def_node_matcher :describe_with_rails_metadata?, <<-PATTERN
|
|
||||||
(send #{RSPEC} :describe !const ...
|
|
||||||
(hash <#rails_metadata? ...>)
|
|
||||||
)
|
|
||||||
PATTERN
|
|
||||||
|
|
||||||
def_node_matcher :rails_metadata?, <<-PATTERN
|
|
||||||
(pair
|
|
||||||
(sym :type)
|
|
||||||
(sym {
|
|
||||||
:channel :controller :helper :job :mailer :model :request
|
|
||||||
:routing :view :feature :system :mailbox
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
PATTERN
|
|
||||||
|
|
||||||
def on_top_level_describe(node, (described_value, _))
|
|
||||||
return if shared_group?(root_node)
|
|
||||||
return if valid_describe?(node)
|
|
||||||
return if describe_with_rails_metadata?(node)
|
|
||||||
return if string_constant_describe?(described_value)
|
|
||||||
|
|
||||||
add_offense(described_value)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def string_constant_describe?(described_value)
|
|
||||||
described_value.str_type? &&
|
|
||||||
described_value.value =~ /^((::)?[A-Z]\w*)+$/
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
# 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.'
|
|
||||||
|
|
||||||
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)
|
|
||||||
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
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module RuboCop
|
|
||||||
module Cop
|
|
||||||
module RSpec
|
|
||||||
# Checks that memoized helper names use the configured style.
|
|
||||||
#
|
|
||||||
# @example EnforcedStyle: snake_case (default)
|
|
||||||
# # bad
|
|
||||||
# let(:userName) { 'Adam' }
|
|
||||||
# subject(:userName) { 'Adam' }
|
|
||||||
#
|
|
||||||
# # good
|
|
||||||
# let(:user_name) { 'Adam' }
|
|
||||||
# subject(:user_name) { 'Adam' }
|
|
||||||
#
|
|
||||||
# @example EnforcedStyle: camelCase
|
|
||||||
# # bad
|
|
||||||
# let(:user_name) { 'Adam' }
|
|
||||||
# subject(:user_name) { 'Adam' }
|
|
||||||
#
|
|
||||||
# # good
|
|
||||||
# let(:userName) { 'Adam' }
|
|
||||||
# subject(:userName) { 'Adam' }
|
|
||||||
class VariableName < Cop
|
|
||||||
include ConfigurableNaming
|
|
||||||
include RuboCop::RSpec::Variable
|
|
||||||
|
|
||||||
MSG = 'Use %<style>s for variable names.'
|
|
||||||
|
|
||||||
def on_send(node)
|
|
||||||
variable_definition?(node) do |variable|
|
|
||||||
return if variable.dstr_type? || variable.dsym_type?
|
|
||||||
|
|
||||||
check_name(node, variable.value, variable.loc.expression)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def message(style)
|
|
||||||
format(MSG, style: style)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module RuboCop
|
|
||||||
module RSpec
|
|
||||||
# Helper methods for top level example group cops
|
|
||||||
module TopLevelGroup
|
|
||||||
extend RuboCop::NodePattern::Macros
|
|
||||||
include RuboCop::RSpec::Language
|
|
||||||
|
|
||||||
def_node_matcher :example_or_shared_group?,
|
|
||||||
(ExampleGroups::ALL + SharedGroups::ALL).block_pattern
|
|
||||||
|
|
||||||
def on_block(node)
|
|
||||||
return unless respond_to?(:on_top_level_group)
|
|
||||||
return unless top_level_group?(node)
|
|
||||||
|
|
||||||
on_top_level_group(node)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def top_level_group?(node)
|
|
||||||
top_level_groups.include?(node)
|
|
||||||
end
|
|
||||||
|
|
||||||
def top_level_groups
|
|
||||||
@top_level_groups ||=
|
|
||||||
top_level_nodes.select { |n| example_or_shared_group?(n) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def top_level_nodes
|
|
||||||
if root_node.begin_type?
|
|
||||||
root_node.children
|
|
||||||
else
|
|
||||||
[root_node]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def root_node
|
|
||||||
processed_source.ast
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -74,7 +74,7 @@ RSpec/ContextWording:
|
|||||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording
|
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording
|
||||||
|
|
||||||
RSpec/DescribeClass:
|
RSpec/DescribeClass:
|
||||||
Description: Check that the first argument to the top level describe is a constant.
|
Description: Check that the first argument to the top-level describe is a constant.
|
||||||
Enabled: true
|
Enabled: true
|
||||||
VersionAdded: '1.0'
|
VersionAdded: '1.0'
|
||||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeClass
|
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/DescribeClass
|
||||||
@ -381,7 +381,7 @@ RSpec/MissingExampleGroupArgument:
|
|||||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExampleGroupArgument
|
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MissingExampleGroupArgument
|
||||||
|
|
||||||
RSpec/MultipleDescribes:
|
RSpec/MultipleDescribes:
|
||||||
Description: Checks for multiple top level describes.
|
Description: Checks for multiple top-level example groups.
|
||||||
Enabled: true
|
Enabled: true
|
||||||
VersionAdded: '1.0'
|
VersionAdded: '1.0'
|
||||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleDescribes
|
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleDescribes
|
||||||
@ -394,6 +394,14 @@ RSpec/MultipleExpectations:
|
|||||||
VersionChanged: '1.21'
|
VersionChanged: '1.21'
|
||||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleExpectations
|
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleExpectations
|
||||||
|
|
||||||
|
RSpec/MultipleMemoizedHelpers:
|
||||||
|
Description: Checks if example groups contain too many `let` and `subject` calls.
|
||||||
|
Enabled: true
|
||||||
|
AllowSubject: true
|
||||||
|
Max: 5
|
||||||
|
VersionAdded: '1.43'
|
||||||
|
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/MultipleMemoizedHelpers
|
||||||
|
|
||||||
RSpec/MultipleSubjects:
|
RSpec/MultipleSubjects:
|
||||||
Description: Checks if an example group defines `subject` multiple times.
|
Description: Checks if an example group defines `subject` multiple times.
|
||||||
Enabled: true
|
Enabled: true
|
||||||
@ -558,7 +566,9 @@ RSpec/VariableName:
|
|||||||
SupportedStyles:
|
SupportedStyles:
|
||||||
- snake_case
|
- snake_case
|
||||||
- camelCase
|
- camelCase
|
||||||
|
IgnoredPatterns: []
|
||||||
VersionAdded: '1.40'
|
VersionAdded: '1.40'
|
||||||
|
VersionChanged: '1.43'
|
||||||
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName
|
StyleGuide: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/VariableName
|
||||||
|
|
||||||
RSpec/VerifiedDoubles:
|
RSpec/VerifiedDoubles:
|
||||||
@ -19,11 +19,12 @@ require_relative 'rubocop/rspec/example_group'
|
|||||||
require_relative 'rubocop/rspec/example'
|
require_relative 'rubocop/rspec/example'
|
||||||
require_relative 'rubocop/rspec/hook'
|
require_relative 'rubocop/rspec/hook'
|
||||||
require_relative 'rubocop/rspec/variable'
|
require_relative 'rubocop/rspec/variable'
|
||||||
|
require_relative 'rubocop/cop/rspec/base'
|
||||||
require_relative 'rubocop/cop/rspec/cop'
|
require_relative 'rubocop/cop/rspec/cop'
|
||||||
require_relative 'rubocop/rspec/align_let_brace'
|
require_relative 'rubocop/rspec/align_let_brace'
|
||||||
require_relative 'rubocop/rspec/factory_bot'
|
require_relative 'rubocop/rspec/factory_bot'
|
||||||
require_relative 'rubocop/rspec/final_end_location'
|
require_relative 'rubocop/rspec/final_end_location'
|
||||||
require_relative 'rubocop/rspec/blank_line_separation'
|
require_relative 'rubocop/rspec/empty_line_separation'
|
||||||
require_relative 'rubocop/rspec/corrector/move_node'
|
require_relative 'rubocop/rspec/corrector/move_node'
|
||||||
|
|
||||||
RuboCop::RSpec::Inject.defaults!
|
RuboCop::RSpec::Inject.defaults!
|
||||||
@ -17,7 +17,7 @@ module RuboCop
|
|||||||
# let(:baz) { bar }
|
# let(:baz) { bar }
|
||||||
# let(:a) { b }
|
# let(:a) { b }
|
||||||
#
|
#
|
||||||
class AlignLeftLetBrace < Cop
|
class AlignLeftLetBrace < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Align left let brace'
|
MSG = 'Align left let brace'
|
||||||
@ -17,7 +17,7 @@ module RuboCop
|
|||||||
# let(:baz) { bar }
|
# let(:baz) { bar }
|
||||||
# let(:a) { b }
|
# let(:a) { b }
|
||||||
#
|
#
|
||||||
class AlignRightLetBrace < Cop
|
class AlignRightLetBrace < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Align right let brace'
|
MSG = 'Align right let brace'
|
||||||
@ -22,7 +22,7 @@ module RuboCop
|
|||||||
# allow(my_instance).to receive(:foo)
|
# allow(my_instance).to receive(:foo)
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
class AnyInstance < Cop
|
class AnyInstance < Base
|
||||||
MSG = 'Avoid stubbing using `%<method>s`.'
|
MSG = 'Avoid stubbing using `%<method>s`.'
|
||||||
|
|
||||||
def_node_matcher :disallowed_stub, <<-PATTERN
|
def_node_matcher :disallowed_stub, <<-PATTERN
|
||||||
@ -25,7 +25,7 @@ module RuboCop
|
|||||||
# some_method
|
# some_method
|
||||||
# test.run
|
# test.run
|
||||||
# end
|
# end
|
||||||
class AroundBlock < Cop
|
class AroundBlock < Base
|
||||||
MSG_NO_ARG = 'Test object should be passed to around block.'
|
MSG_NO_ARG = 'Test object should be passed to around block.'
|
||||||
MSG_UNUSED_ARG = 'You should call `%<arg>s.call` '\
|
MSG_UNUSED_ARG = 'You should call `%<arg>s.call` '\
|
||||||
'or `%<arg>s.run`.'
|
'or `%<arg>s.run`.'
|
||||||
@ -17,7 +17,7 @@ module RuboCop
|
|||||||
# # Patterns:
|
# # Patterns:
|
||||||
# # - '_test.rb$'
|
# # - '_test.rb$'
|
||||||
# # - '(?:^|/)test/'
|
# # - '(?:^|/)test/'
|
||||||
class Cop < ::RuboCop::Cop::Base
|
class Base < ::RuboCop::Cop::Base
|
||||||
include RuboCop::RSpec::Language
|
include RuboCop::RSpec::Language
|
||||||
include RuboCop::RSpec::Language::NodePattern
|
include RuboCop::RSpec::Language::NodePattern
|
||||||
|
|
||||||
@ -30,8 +30,8 @@ module RuboCop
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Invoke the original inherited hook so our cops are recognized
|
# Invoke the original inherited hook so our cops are recognized
|
||||||
def self.inherited(subclass)
|
def self.inherited(subclass) # rubocop:disable Lint/MissingSuper
|
||||||
RuboCop::Cop::Cop.inherited(subclass)
|
RuboCop::Cop::Base.inherited(subclass)
|
||||||
end
|
end
|
||||||
|
|
||||||
def relevant_file?(file)
|
def relevant_file?(file)
|
||||||
@ -41,7 +41,7 @@ module RuboCop
|
|||||||
private
|
private
|
||||||
|
|
||||||
def relevant_rubocop_rspec_file?(file)
|
def relevant_rubocop_rspec_file?(file)
|
||||||
rspec_pattern =~ file
|
rspec_pattern.match?(file)
|
||||||
end
|
end
|
||||||
|
|
||||||
def rspec_pattern
|
def rspec_pattern
|
||||||
@ -19,7 +19,7 @@ module RuboCop
|
|||||||
# expect(foo).to be 1.0
|
# expect(foo).to be 1.0
|
||||||
# expect(foo).to be(true)
|
# expect(foo).to be(true)
|
||||||
#
|
#
|
||||||
class Be < Cop
|
class Be < Base
|
||||||
MSG = 'Don\'t use `be` without an argument.'
|
MSG = 'Don\'t use `be` without an argument.'
|
||||||
|
|
||||||
def_node_matcher :be_without_args, <<-PATTERN
|
def_node_matcher :be_without_args, <<-PATTERN
|
||||||
@ -35,7 +35,7 @@ module RuboCop
|
|||||||
# necessarily the same type as `b` since the `#==` operator can
|
# necessarily the same type as `b` since the `#==` operator can
|
||||||
# coerce objects for comparison.
|
# coerce objects for comparison.
|
||||||
#
|
#
|
||||||
class BeEql < Cop
|
class BeEql < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Prefer `be` over `eql`.'
|
MSG = 'Prefer `be` over `eql`.'
|
||||||
@ -23,7 +23,7 @@ module RuboCop
|
|||||||
# before(:each) { Widget.create }
|
# before(:each) { Widget.create }
|
||||||
# after(:each) { Widget.delete_all }
|
# after(:each) { Widget.delete_all }
|
||||||
# end
|
# end
|
||||||
class BeforeAfterAll < Cop
|
class BeforeAfterAll < Base
|
||||||
MSG = 'Beware of using `%<hook>s` as it may cause state to leak '\
|
MSG = 'Beware of using `%<hook>s` as it may cause state to leak '\
|
||||||
'between tests. If you are using `rspec-rails`, and '\
|
'between tests. If you are using `rspec-rails`, and '\
|
||||||
'`use_transactional_fixtures` is enabled, then records created '\
|
'`use_transactional_fixtures` is enabled, then records created '\
|
||||||
@ -23,7 +23,7 @@ module RuboCop
|
|||||||
# expect(page).to have_current_path("/callback")
|
# expect(page).to have_current_path("/callback")
|
||||||
# expect(page).to have_current_path(/widgets/)
|
# expect(page).to have_current_path(/widgets/)
|
||||||
#
|
#
|
||||||
class CurrentPathExpectation < Cop
|
class CurrentPathExpectation < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Do not set an RSpec expectation on `current_path` in ' \
|
MSG = 'Do not set an RSpec expectation on `current_path` in ' \
|
||||||
@ -40,7 +40,7 @@ module RuboCop
|
|||||||
# # ...
|
# # ...
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
class FeatureMethods < Cop
|
class FeatureMethods < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Use `%<replacement>s` instead of `%<method>s`.'
|
MSG = 'Use `%<replacement>s` instead of `%<method>s`.'
|
||||||
@ -55,15 +55,18 @@ module RuboCop
|
|||||||
feature: :describe
|
feature: :describe
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
def_node_matcher :capybara_speak,
|
||||||
|
SelectorSet.new(MAP.keys).node_pattern_union
|
||||||
|
|
||||||
def_node_matcher :spec?, <<-PATTERN
|
def_node_matcher :spec?, <<-PATTERN
|
||||||
(block
|
(block
|
||||||
(send #{RSPEC} {:describe :feature} ...)
|
(send #rspec? {:describe :feature} ...)
|
||||||
...)
|
...)
|
||||||
PATTERN
|
PATTERN
|
||||||
|
|
||||||
def_node_matcher :feature_method, <<-PATTERN
|
def_node_matcher :feature_method, <<-PATTERN
|
||||||
(block
|
(block
|
||||||
$(send #{RSPEC} ${#{MAP.keys.map(&:inspect).join(' ')}} ...)
|
$(send #rspec? $#capybara_speak ...)
|
||||||
...)
|
...)
|
||||||
PATTERN
|
PATTERN
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ module RuboCop
|
|||||||
# expect(page).to have_css('.foo', visible: :all)
|
# expect(page).to have_css('.foo', visible: :all)
|
||||||
# expect(page).to have_link('my link', visible: :hidden)
|
# expect(page).to have_link('my link', visible: :hidden)
|
||||||
#
|
#
|
||||||
class VisibilityMatcher < Cop
|
class VisibilityMatcher < Base
|
||||||
MSG_FALSE = 'Use `:all` or `:hidden` instead of `false`.'
|
MSG_FALSE = 'Use `:all` or `:hidden` instead of `false`.'
|
||||||
MSG_TRUE = 'Use `:visible` instead of `true`.'
|
MSG_TRUE = 'Use `:visible` instead of `true`.'
|
||||||
CAPYBARA_MATCHER_METHODS = %i[
|
CAPYBARA_MATCHER_METHODS = %i[
|
||||||
@ -23,13 +23,13 @@ module RuboCop
|
|||||||
# describe '.foo_bar' do
|
# describe '.foo_bar' do
|
||||||
# # ...
|
# # ...
|
||||||
# end
|
# end
|
||||||
class ContextMethod < Cop
|
class ContextMethod < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Use `describe` for testing methods.'
|
MSG = 'Use `describe` for testing methods.'
|
||||||
|
|
||||||
def_node_matcher :context_method, <<-PATTERN
|
def_node_matcher :context_method, <<-PATTERN
|
||||||
(block (send #{RSPEC} :context $(str #method_name?) ...) ...)
|
(block (send #rspec? :context $(str #method_name?) ...) ...)
|
||||||
PATTERN
|
PATTERN
|
||||||
|
|
||||||
def on_block(node)
|
def on_block(node)
|
||||||
@ -34,11 +34,11 @@ module RuboCop
|
|||||||
# context 'when the display name is not present' do
|
# context 'when the display name is not present' do
|
||||||
# # ...
|
# # ...
|
||||||
# end
|
# end
|
||||||
class ContextWording < Cop
|
class ContextWording < Base
|
||||||
MSG = 'Start context description with %<prefixes>s.'
|
MSG = 'Start context description with %<prefixes>s.'
|
||||||
|
|
||||||
def_node_matcher :context_wording, <<-PATTERN
|
def_node_matcher :context_wording, <<-PATTERN
|
||||||
(block (send #{RSPEC} { :context :shared_context } $(str #bad_prefix?) ...) ...)
|
(block (send #rspec? { :context :shared_context } $(str #bad_prefix?) ...) ...)
|
||||||
PATTERN
|
PATTERN
|
||||||
|
|
||||||
def on_block(node)
|
def on_block(node)
|
||||||
@ -51,7 +51,7 @@ module RuboCop
|
|||||||
private
|
private
|
||||||
|
|
||||||
def bad_prefix?(description)
|
def bad_prefix?(description)
|
||||||
!prefixes.include?(description.split.first)
|
!prefixes.include?(description.split(/\b/).first)
|
||||||
end
|
end
|
||||||
|
|
||||||
def joined_prefixes
|
def joined_prefixes
|
||||||
10
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rspec-1.43.1/lib/rubocop/cop/rspec/cop.rb
vendored
Normal file
10
Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/rubocop-rspec-1.43.1/lib/rubocop/cop/rspec/cop.rb
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module RuboCop
|
||||||
|
module Cop
|
||||||
|
module RSpec
|
||||||
|
# @deprecated Use ::RuboCop::Cop::RSpec::Base instead
|
||||||
|
Cop = Base
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
# 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
|
||||||
|
# subject { described_class }
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# describe 'TestedClass::VERSION' do
|
||||||
|
# subject { Object.const_get(self.class.description) }
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# describe "A feature example", type: :feature do
|
||||||
|
# end
|
||||||
|
class DescribeClass < Base
|
||||||
|
include RuboCop::RSpec::TopLevelGroup
|
||||||
|
|
||||||
|
MSG = 'The first argument to describe should be '\
|
||||||
|
'the class or module being tested.'
|
||||||
|
|
||||||
|
def_node_matcher :rails_metadata?, <<-PATTERN
|
||||||
|
(pair
|
||||||
|
(sym :type)
|
||||||
|
(sym { :channel :controller :helper :job :mailer :model :request
|
||||||
|
:routing :view :feature :system :mailbox })
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_matcher :example_group_with_rails_metadata?, <<~PATTERN
|
||||||
|
(send #rspec? :describe ... (hash <#rails_metadata? ...>))
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def_node_matcher :not_a_const_described, <<~PATTERN
|
||||||
|
(send #rspec? :describe $[!const !#string_constant?] ...)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def on_top_level_group(top_level_node)
|
||||||
|
return if example_group_with_rails_metadata?(top_level_node.send_node)
|
||||||
|
|
||||||
|
not_a_const_described(top_level_node.send_node) do |described|
|
||||||
|
add_offense(described)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def string_constant?(described)
|
||||||
|
described.str_type? &&
|
||||||
|
described.value.match?(/^(?:(?:::)?[A-Z]\w*)+$/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -16,17 +16,25 @@ module RuboCop
|
|||||||
#
|
#
|
||||||
# describe MyClass, '.my_class_method' do
|
# describe MyClass, '.my_class_method' do
|
||||||
# end
|
# end
|
||||||
class DescribeMethod < Cop
|
class DescribeMethod < Base
|
||||||
include RuboCop::RSpec::TopLevelDescribe
|
include RuboCop::RSpec::TopLevelGroup
|
||||||
|
|
||||||
MSG = 'The second argument to describe should be the method '\
|
MSG = 'The second argument to describe should be the method '\
|
||||||
"being tested. '#instance' or '.class'."
|
"being tested. '#instance' or '.class'."
|
||||||
|
|
||||||
def on_top_level_describe(_node, (_, second_arg))
|
def_node_matcher :second_argument, <<~PATTERN
|
||||||
return unless second_arg&.str_type?
|
(block
|
||||||
return if second_arg.str_content.start_with?('#', '.')
|
(send #rspec? :describe _first_argument $(str _) ...) ...
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
add_offense(second_arg)
|
def on_top_level_group(node)
|
||||||
|
second_argument = second_argument(node)
|
||||||
|
|
||||||
|
return unless second_argument
|
||||||
|
return if second_argument.str_content.start_with?('#', '.')
|
||||||
|
|
||||||
|
add_offense(second_argument)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -17,11 +17,11 @@ module RuboCop
|
|||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# @see https://github.com/rspec/rspec-core/issues/1610
|
# @see https://github.com/rspec/rspec-core/issues/1610
|
||||||
class DescribeSymbol < Cop
|
class DescribeSymbol < Base
|
||||||
MSG = 'Avoid describing symbols.'
|
MSG = 'Avoid describing symbols.'
|
||||||
|
|
||||||
def_node_matcher :describe_symbol?, <<-PATTERN
|
def_node_matcher :describe_symbol?, <<-PATTERN
|
||||||
(send #{RSPEC} :describe $sym ...)
|
(send #rspec? :describe $sym ...)
|
||||||
PATTERN
|
PATTERN
|
||||||
|
|
||||||
def on_send(node)
|
def on_send(node)
|
||||||
@ -54,7 +54,7 @@ module RuboCop
|
|||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
class DescribedClass < Cop
|
class DescribedClass < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include ConfigurableEnforcedStyle
|
include ConfigurableEnforcedStyle
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ module RuboCop
|
|||||||
if style == :described_class
|
if style == :described_class
|
||||||
offensive_described_class?(node)
|
offensive_described_class?(node)
|
||||||
else
|
else
|
||||||
node.send_type? && node.method_name == :described_class
|
node.send_type? && node.method?(:described_class)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ module RuboCop
|
|||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# @see https://github.com/rubocop-hq/rubocop-rspec/issues/735
|
# @see https://github.com/rubocop-hq/rubocop-rspec/issues/735
|
||||||
class DescribedClassModuleWrapping < Cop
|
class DescribedClassModuleWrapping < Base
|
||||||
MSG = 'Avoid opening modules and defining specs within them.'
|
MSG = 'Avoid opening modules and defining specs within them.'
|
||||||
|
|
||||||
def_node_search :find_rspec_blocks,
|
def_node_search :find_rspec_blocks,
|
||||||
@ -41,7 +41,7 @@ module RuboCop
|
|||||||
# describe 'display name presence' do
|
# describe 'display name presence' do
|
||||||
# # ...
|
# # ...
|
||||||
# end
|
# end
|
||||||
class Dialect < Cop
|
class Dialect < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include MethodPreference
|
include MethodPreference
|
||||||
|
|
||||||
@ -0,0 +1,174 @@
|
|||||||
|
# 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 < Base
|
||||||
|
MSG = 'Empty example group detected.'
|
||||||
|
|
||||||
|
# @!method example_group_body(node)
|
||||||
|
# Match example group blocks and yield their body
|
||||||
|
#
|
||||||
|
# @example source that matches
|
||||||
|
# describe 'example group' do
|
||||||
|
# it { is_expected.to be }
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# @param node [RuboCop::AST::Node]
|
||||||
|
# @yield [RuboCop::AST::Node] example group body
|
||||||
|
def_node_matcher :example_group_body, <<~PATTERN
|
||||||
|
(block #{ExampleGroups::ALL.send_pattern} args $_)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
# @!method example_or_group_or_include?(node)
|
||||||
|
# Match examples, example groups and includes
|
||||||
|
#
|
||||||
|
# @example source that matches
|
||||||
|
# it { is_expected.to fly }
|
||||||
|
# describe('non-empty example groups too') { }
|
||||||
|
# it_behaves_like 'an animal'
|
||||||
|
# it_behaves_like('a cat') { let(:food) { 'milk' } }
|
||||||
|
# it_has_root_access
|
||||||
|
#
|
||||||
|
# @param node [RuboCop::AST::Node]
|
||||||
|
# @return [Array<RuboCop::AST::Node>] matching nodes
|
||||||
|
def_node_matcher :example_or_group_or_include?, <<~PATTERN
|
||||||
|
{
|
||||||
|
#{Examples::ALL.block_pattern}
|
||||||
|
#{ExampleGroups::ALL.block_pattern}
|
||||||
|
#{Includes::ALL.send_pattern}
|
||||||
|
#{Includes::ALL.block_pattern}
|
||||||
|
(send nil? #custom_include? ...)
|
||||||
|
}
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
# @!method examples_inside_block?(node)
|
||||||
|
# Match examples defined inside a block which is not a hook
|
||||||
|
#
|
||||||
|
# @example source that matches
|
||||||
|
# %w(r g b).each do |color|
|
||||||
|
# it { is_expected.to have_color(color) }
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# @example source that does not match
|
||||||
|
# before do
|
||||||
|
# it { is_expected.to fall_into_oblivion }
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# @param node [RuboCop::AST::Node]
|
||||||
|
# @return [Array<RuboCop::AST::Node>] matching nodes
|
||||||
|
def_node_matcher :examples_inside_block?, <<~PATTERN
|
||||||
|
(block !#{Hooks::ALL.send_pattern} _ #examples?)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
# @!method examples_directly_or_in_block?(node)
|
||||||
|
# Match examples or examples inside blocks
|
||||||
|
#
|
||||||
|
# @example source that matches
|
||||||
|
# it { expect(drink).to be_cold }
|
||||||
|
# context('when winter') { it { expect(drink).to be_hot } }
|
||||||
|
# (1..5).each { |divisor| it { is_expected.to divide_by(divisor) } }
|
||||||
|
#
|
||||||
|
# @param node [RuboCop::AST::Node]
|
||||||
|
# @return [Array<RuboCop::AST::Node>] matching nodes
|
||||||
|
def_node_matcher :examples_directly_or_in_block?, <<~PATTERN
|
||||||
|
{
|
||||||
|
#example_or_group_or_include?
|
||||||
|
#examples_inside_block?
|
||||||
|
}
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
# @!method examples?(node)
|
||||||
|
# Matches examples defined in scopes where they could run
|
||||||
|
#
|
||||||
|
# @example source that matches
|
||||||
|
# it { expect(myself).to be_run }
|
||||||
|
# describe { it { i_run_as_well } }
|
||||||
|
#
|
||||||
|
# @example source that does not match
|
||||||
|
# before { it { whatever here wont run anyway } }
|
||||||
|
#
|
||||||
|
# @param node [RuboCop::AST::Node]
|
||||||
|
# @return [Array<RuboCop::AST::Node>] matching nodes
|
||||||
|
def_node_matcher :examples?, <<~PATTERN
|
||||||
|
{
|
||||||
|
#examples_directly_or_in_block?
|
||||||
|
(begin <#examples_directly_or_in_block? ...>)
|
||||||
|
}
|
||||||
|
PATTERN
|
||||||
|
|
||||||
|
def on_block(node)
|
||||||
|
example_group_body(node) do |body|
|
||||||
|
add_offense(node.send_node) unless examples?(body)
|
||||||
|
end
|
||||||
|
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
|
||||||
@ -22,7 +22,7 @@ module RuboCop
|
|||||||
# create_feed
|
# create_feed
|
||||||
# end
|
# end
|
||||||
# after(:all) { cleanup_feed }
|
# after(:all) { cleanup_feed }
|
||||||
class EmptyHook < Cop
|
class EmptyHook < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include RuboCop::Cop::RangeHelp
|
include RuboCop::Cop::RangeHelp
|
||||||
|
|
||||||
@ -41,22 +41,18 @@ module RuboCop
|
|||||||
# it { two }
|
# it { two }
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
class EmptyLineAfterExample < Cop
|
class EmptyLineAfterExample < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include RuboCop::RSpec::BlankLineSeparation
|
include RuboCop::RSpec::EmptyLineSeparation
|
||||||
|
|
||||||
MSG = 'Add an empty line after `%<example>s`.'
|
MSG = 'Add an empty line after `%<example>s`.'
|
||||||
|
|
||||||
def on_block(node)
|
def on_block(node)
|
||||||
return unless example?(node)
|
return unless example?(node)
|
||||||
return if last_child?(node)
|
|
||||||
return if allowed_one_liner?(node)
|
return if allowed_one_liner?(node)
|
||||||
|
|
||||||
missing_separating_line(node) do |location|
|
missing_separating_line_offense(node) do |method|
|
||||||
msg = format(MSG, example: node.method_name)
|
format(MSG, example: method)
|
||||||
add_offense(location, message: msg) do |corrector|
|
|
||||||
corrector.insert_after(location.end, "\n")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -23,21 +23,17 @@ module RuboCop
|
|||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
class EmptyLineAfterExampleGroup < Cop
|
class EmptyLineAfterExampleGroup < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include RuboCop::RSpec::BlankLineSeparation
|
include RuboCop::RSpec::EmptyLineSeparation
|
||||||
|
|
||||||
MSG = 'Add an empty line after `%<example_group>s`.'
|
MSG = 'Add an empty line after `%<example_group>s`.'
|
||||||
|
|
||||||
def on_block(node)
|
def on_block(node)
|
||||||
return unless example_group?(node)
|
return unless example_group?(node)
|
||||||
return if last_child?(node)
|
|
||||||
|
|
||||||
missing_separating_line(node) do |location|
|
missing_separating_line_offense(node) do |method|
|
||||||
msg = format(MSG, example_group: node.method_name)
|
format(MSG, example_group: method)
|
||||||
add_offense(location, message: msg) do |corrector|
|
|
||||||
corrector.insert_after(location.end, "\n")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -16,24 +16,21 @@ module RuboCop
|
|||||||
# let(:something) { other }
|
# let(:something) { other }
|
||||||
#
|
#
|
||||||
# it { does_something }
|
# it { does_something }
|
||||||
class EmptyLineAfterFinalLet < Cop
|
class EmptyLineAfterFinalLet < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include RuboCop::RSpec::BlankLineSeparation
|
include RuboCop::RSpec::EmptyLineSeparation
|
||||||
|
|
||||||
MSG = 'Add an empty line after the last `let` block.'
|
MSG = 'Add an empty line after the last `%<let>s`.'
|
||||||
|
|
||||||
def on_block(node)
|
def on_block(node)
|
||||||
return unless example_group_with_body?(node)
|
return unless example_group_with_body?(node)
|
||||||
|
|
||||||
latest_let = node.body.child_nodes.select { |child| let?(child) }.last
|
final_let = node.body.child_nodes.reverse.find { |child| let?(child) }
|
||||||
|
|
||||||
return if latest_let.nil?
|
return if final_let.nil?
|
||||||
return if last_child?(latest_let)
|
|
||||||
|
|
||||||
missing_separating_line(latest_let) do |location|
|
missing_separating_line_offense(final_let) do |method|
|
||||||
add_offense(location) do |corrector|
|
format(MSG, let: method)
|
||||||
corrector.insert_after(location.end, "\n")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -33,21 +33,17 @@ module RuboCop
|
|||||||
#
|
#
|
||||||
# it { does_something }
|
# it { does_something }
|
||||||
#
|
#
|
||||||
class EmptyLineAfterHook < Cop
|
class EmptyLineAfterHook < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include RuboCop::RSpec::BlankLineSeparation
|
include RuboCop::RSpec::EmptyLineSeparation
|
||||||
|
|
||||||
MSG = 'Add an empty line after `%<hook>s`.'
|
MSG = 'Add an empty line after `%<hook>s`.'
|
||||||
|
|
||||||
def on_block(node)
|
def on_block(node)
|
||||||
return unless hook?(node)
|
return unless hook?(node)
|
||||||
return if last_child?(node)
|
|
||||||
|
|
||||||
missing_separating_line(node) do |location|
|
missing_separating_line_offense(node) do |method|
|
||||||
msg = format(MSG, hook: node.method_name)
|
format(MSG, hook: method)
|
||||||
add_offense(location, message: msg) do |corrector|
|
|
||||||
corrector.insert_after(location.end, "\n")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -14,20 +14,17 @@ module RuboCop
|
|||||||
# subject(:obj) { described_class }
|
# subject(:obj) { described_class }
|
||||||
#
|
#
|
||||||
# let(:foo) { bar }
|
# let(:foo) { bar }
|
||||||
class EmptyLineAfterSubject < Cop
|
class EmptyLineAfterSubject < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include RuboCop::RSpec::BlankLineSeparation
|
include RuboCop::RSpec::EmptyLineSeparation
|
||||||
|
|
||||||
MSG = 'Add empty line after `subject`.'
|
MSG = 'Add an empty line after `%<subject>s`.'
|
||||||
|
|
||||||
def on_block(node)
|
def on_block(node)
|
||||||
return unless subject?(node) && !in_spec_block?(node)
|
return unless subject?(node) && !in_spec_block?(node)
|
||||||
return if last_child?(node)
|
|
||||||
|
|
||||||
missing_separating_line(node) do |location|
|
missing_separating_line_offense(node) do |method|
|
||||||
add_offense(location) do |corrector|
|
format(MSG, subject: method)
|
||||||
corrector.insert_after(location.end, "\n")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ module RuboCop
|
|||||||
# result = service.call
|
# result = service.call
|
||||||
# expect(result).to be(true)
|
# expect(result).to be(true)
|
||||||
# end
|
# end
|
||||||
class ExampleLength < Cop
|
class ExampleLength < Base
|
||||||
include CodeLength
|
include CodeLength
|
||||||
|
|
||||||
MSG = 'Example has too many lines [%<total>d/%<max>d].'
|
MSG = 'Example has too many lines [%<total>d/%<max>d].'
|
||||||
@ -47,7 +47,7 @@ module RuboCop
|
|||||||
# result = service.call
|
# result = service.call
|
||||||
# expect(result).to be(true)
|
# expect(result).to be(true)
|
||||||
# end
|
# end
|
||||||
class ExampleWithoutDescription < Cop
|
class ExampleWithoutDescription < Base
|
||||||
include ConfigurableEnforcedStyle
|
include ConfigurableEnforcedStyle
|
||||||
|
|
||||||
MSG_DEFAULT_ARGUMENT = 'Omit the argument when you want to ' \
|
MSG_DEFAULT_ARGUMENT = 'Omit the argument when you want to ' \
|
||||||
@ -29,7 +29,7 @@ module RuboCop
|
|||||||
# # good
|
# # good
|
||||||
# it 'does things' do
|
# it 'does things' do
|
||||||
# end
|
# end
|
||||||
class ExampleWording < Cop
|
class ExampleWording < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG_SHOULD = 'Do not use should when describing your tests.'
|
MSG_SHOULD = 'Do not use should when describing your tests.'
|
||||||
@ -47,9 +47,9 @@ module RuboCop
|
|||||||
|
|
||||||
def on_block(node)
|
def on_block(node)
|
||||||
it_description(node) do |description_node, message|
|
it_description(node) do |description_node, message|
|
||||||
if message =~ SHOULD_PREFIX
|
if message.match?(SHOULD_PREFIX)
|
||||||
add_wording_offense(description_node, MSG_SHOULD)
|
add_wording_offense(description_node, MSG_SHOULD)
|
||||||
elsif message =~ IT_PREFIX
|
elsif message.match?(IT_PREFIX)
|
||||||
add_wording_offense(description_node, MSG_IT)
|
add_wording_offense(description_node, MSG_IT)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -77,7 +77,7 @@ module RuboCop
|
|||||||
def replacement_text(node)
|
def replacement_text(node)
|
||||||
text = text(node)
|
text = text(node)
|
||||||
|
|
||||||
if text =~ SHOULD_PREFIX
|
if text.match?(SHOULD_PREFIX)
|
||||||
RuboCop::RSpec::Wording.new(
|
RuboCop::RSpec::Wording.new(
|
||||||
text,
|
text,
|
||||||
ignore: ignored_words,
|
ignore: ignored_words,
|
||||||
@ -16,7 +16,7 @@ module RuboCop
|
|||||||
# expect(pattern).to eq(/foo/)
|
# expect(pattern).to eq(/foo/)
|
||||||
# expect(name).to eq("John")
|
# expect(name).to eq("John")
|
||||||
#
|
#
|
||||||
class ExpectActual < Cop
|
class ExpectActual < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Provide the actual you are testing to `expect(...)`.'
|
MSG = 'Provide the actual you are testing to `expect(...)`.'
|
||||||
@ -29,7 +29,7 @@ module RuboCop
|
|||||||
# expect { run }.to change { Foo.bar(:count) }
|
# expect { run }.to change { Foo.bar(:count) }
|
||||||
# expect { run }.to change { user.reload.name }
|
# expect { run }.to change { user.reload.name }
|
||||||
#
|
#
|
||||||
class ExpectChange < Cop
|
class ExpectChange < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include ConfigurableEnforcedStyle
|
include ConfigurableEnforcedStyle
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ module RuboCop
|
|||||||
# it do
|
# it do
|
||||||
# expect(something).to eq 'foo'
|
# expect(something).to eq 'foo'
|
||||||
# end
|
# end
|
||||||
class ExpectInHook < Cop
|
class ExpectInHook < Base
|
||||||
MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'
|
MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'
|
||||||
|
|
||||||
def_node_search :expectation, Expectations::ALL.send_pattern
|
def_node_search :expectation, Expectations::ALL.send_pattern
|
||||||
@ -14,7 +14,7 @@ module RuboCop
|
|||||||
#
|
#
|
||||||
# # good
|
# # good
|
||||||
# expect { my_app.print_report }.to output('Hello World').to_stdout
|
# expect { my_app.print_report }.to output('Hello World').to_stdout
|
||||||
class ExpectOutput < Cop
|
class ExpectOutput < Base
|
||||||
MSG = 'Use `expect { ... }.to output(...).to_%<name>s` '\
|
MSG = 'Use `expect { ... }.to output(...).to_%<name>s` '\
|
||||||
'instead of mutating $%<name>s.'
|
'instead of mutating $%<name>s.'
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ module RuboCop
|
|||||||
#
|
#
|
||||||
# # good
|
# # good
|
||||||
# count { 1 }
|
# count { 1 }
|
||||||
class AttributeDefinedStatically < Cop
|
class AttributeDefinedStatically < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Use a block to declare attribute values.'
|
MSG = 'Use a block to declare attribute values.'
|
||||||
@ -39,7 +39,7 @@ module RuboCop
|
|||||||
|
|
||||||
def on_block(node)
|
def on_block(node)
|
||||||
attributes = factory_attributes(node) || []
|
attributes = factory_attributes(node) || []
|
||||||
attributes = [attributes] unless attributes.is_a?(Array)
|
attributes = [attributes] unless attributes.is_a?(Array) # rubocop:disable Style/ArrayCoercion, Lint/RedundantCopDisableDirective
|
||||||
|
|
||||||
attributes.each do |attribute|
|
attributes.each do |attribute|
|
||||||
next unless offensive_receiver?(attribute.receiver, node)
|
next unless offensive_receiver?(attribute.receiver, node)
|
||||||
@ -84,7 +84,7 @@ module RuboCop
|
|||||||
def autocorrect_replacing_parens(corrector, node)
|
def autocorrect_replacing_parens(corrector, node)
|
||||||
left_braces, right_braces = braces(node)
|
left_braces, right_braces = braces(node)
|
||||||
|
|
||||||
corrector.replace(node.location.begin, ' ' + left_braces)
|
corrector.replace(node.location.begin, " #{left_braces}")
|
||||||
corrector.replace(node.location.end, right_braces)
|
corrector.replace(node.location.end, right_braces)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ module RuboCop
|
|||||||
#
|
#
|
||||||
# # good
|
# # good
|
||||||
# 3.times { create :user }
|
# 3.times { create :user }
|
||||||
class CreateList < Cop
|
class CreateList < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include ConfigurableEnforcedStyle
|
include ConfigurableEnforcedStyle
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ module RuboCop
|
|||||||
PATTERN
|
PATTERN
|
||||||
|
|
||||||
def_node_matcher :factory_list_call, <<-PATTERN
|
def_node_matcher :factory_list_call, <<-PATTERN
|
||||||
(send ${(const nil? {:FactoryGirl :FactoryBot}) nil?} :create_list (sym $_) (int $_) $...)
|
(send {(const nil? {:FactoryGirl :FactoryBot}) nil?} :create_list (sym _) (int $_) ...)
|
||||||
PATTERN
|
PATTERN
|
||||||
|
|
||||||
def on_block(node)
|
def on_block(node)
|
||||||
@ -60,7 +60,7 @@ module RuboCop
|
|||||||
def on_send(node)
|
def on_send(node)
|
||||||
return unless style == :n_times
|
return unless style == :n_times
|
||||||
|
|
||||||
factory_list_call(node) do |_receiver, _factory, count, _|
|
factory_list_call(node) do |count|
|
||||||
message = format(MSG_N_TIMES, number: count)
|
message = format(MSG_N_TIMES, number: count)
|
||||||
add_offense(node.loc.selector, message: message) do |corrector|
|
add_offense(node.loc.selector, message: message) do |corrector|
|
||||||
TimesCorrector.new(node).call(corrector)
|
TimesCorrector.new(node).call(corrector)
|
||||||
@ -79,7 +79,7 @@ module RuboCop
|
|||||||
end
|
end
|
||||||
|
|
||||||
# :nodoc
|
# :nodoc
|
||||||
class Corrector
|
module Corrector
|
||||||
private
|
private
|
||||||
|
|
||||||
def build_options_string(options)
|
def build_options_string(options)
|
||||||
@ -102,7 +102,9 @@ module RuboCop
|
|||||||
end
|
end
|
||||||
|
|
||||||
# :nodoc
|
# :nodoc
|
||||||
class TimesCorrector < Corrector
|
class TimesCorrector
|
||||||
|
include Corrector
|
||||||
|
|
||||||
def initialize(node)
|
def initialize(node)
|
||||||
@node = node
|
@node = node
|
||||||
end
|
end
|
||||||
@ -130,7 +132,9 @@ module RuboCop
|
|||||||
end
|
end
|
||||||
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
class CreateListCorrector < Corrector
|
class CreateListCorrector
|
||||||
|
include Corrector
|
||||||
|
|
||||||
def initialize(node)
|
def initialize(node)
|
||||||
@node = node.parent
|
@node = node.parent
|
||||||
end
|
end
|
||||||
@ -19,7 +19,7 @@ module RuboCop
|
|||||||
# # good
|
# # good
|
||||||
# factory :foo, class: 'Foo' do
|
# factory :foo, class: 'Foo' do
|
||||||
# end
|
# end
|
||||||
class FactoryClassName < Cop
|
class FactoryClassName < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = "Pass '%<class_name>s' string instead of `%<class_name>s` " \
|
MSG = "Pass '%<class_name>s' string instead of `%<class_name>s` " \
|
||||||
@ -56,35 +56,43 @@ module RuboCop
|
|||||||
# # good
|
# # good
|
||||||
# my_class_spec.rb # describe MyClass, '#method'
|
# my_class_spec.rb # describe MyClass, '#method'
|
||||||
#
|
#
|
||||||
class FilePath < Cop
|
class FilePath < Base
|
||||||
include RuboCop::RSpec::TopLevelDescribe
|
include RuboCop::RSpec::TopLevelGroup
|
||||||
|
|
||||||
MSG = 'Spec path should end with `%<suffix>s`.'
|
MSG = 'Spec path should end with `%<suffix>s`.'
|
||||||
|
|
||||||
def_node_search :const_described?, '(send _ :describe (const ...) ...)'
|
def_node_matcher :const_described, <<~PATTERN
|
||||||
|
(block
|
||||||
|
$(send #rspec? _example_group $(const ...) $...) ...
|
||||||
|
)
|
||||||
|
PATTERN
|
||||||
|
|
||||||
def_node_search :routing_metadata?, '(pair (sym :type) (sym :routing))'
|
def_node_search :routing_metadata?, '(pair (sym :type) (sym :routing))'
|
||||||
|
|
||||||
def on_top_level_describe(node, args)
|
def on_top_level_group(node)
|
||||||
return unless const_described?(node) && single_top_level_describe?
|
return unless top_level_groups.one?
|
||||||
return if routing_spec?(args)
|
|
||||||
|
|
||||||
glob = glob_for(args)
|
const_described(node) do |send_node, described_class, arguments|
|
||||||
|
next if routing_spec?(arguments)
|
||||||
|
|
||||||
return if filename_ends_with?(glob)
|
ensure_correct_file_path(send_node, described_class, arguments)
|
||||||
|
end
|
||||||
add_offense(
|
|
||||||
node,
|
|
||||||
message: format(MSG, suffix: glob)
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def ensure_correct_file_path(send_node, described_class, arguments)
|
||||||
|
glob = glob_for(described_class, arguments.first)
|
||||||
|
return if filename_ends_with?(glob)
|
||||||
|
|
||||||
|
add_offense(send_node, message: format(MSG, suffix: glob))
|
||||||
|
end
|
||||||
|
|
||||||
def routing_spec?(args)
|
def routing_spec?(args)
|
||||||
args.any?(&method(:routing_metadata?))
|
args.any?(&method(:routing_metadata?))
|
||||||
end
|
end
|
||||||
|
|
||||||
def glob_for((described_class, method_name))
|
def glob_for(described_class, method_name)
|
||||||
return glob_for_spec_suffix_only? if spec_suffix_only?
|
return glob_for_spec_suffix_only? if spec_suffix_only?
|
||||||
|
|
||||||
"#{expected_path(described_class)}#{name_glob(method_name)}*_spec.rb"
|
"#{expected_path(described_class)}#{name_glob(method_name)}*_spec.rb"
|
||||||
@ -94,10 +102,10 @@ module RuboCop
|
|||||||
'*_spec.rb'
|
'*_spec.rb'
|
||||||
end
|
end
|
||||||
|
|
||||||
def name_glob(name)
|
def name_glob(method_name)
|
||||||
return unless name&.str_type?
|
return unless method_name&.str_type?
|
||||||
|
|
||||||
"*#{name.str_content.gsub(/\W/, '')}" unless ignore_methods?
|
"*#{method_name.str_content.gsub(/\W/, '')}" unless ignore_methods?
|
||||||
end
|
end
|
||||||
|
|
||||||
def expected_path(constant)
|
def expected_path(constant)
|
||||||
@ -19,23 +19,19 @@ module RuboCop
|
|||||||
# # good
|
# # good
|
||||||
# describe MyClass do
|
# describe MyClass do
|
||||||
# end
|
# end
|
||||||
class Focus < Cop
|
class Focus < Base
|
||||||
MSG = 'Focused spec found.'
|
MSG = 'Focused spec found.'
|
||||||
|
|
||||||
focusable =
|
|
||||||
ExampleGroups::GROUPS +
|
|
||||||
ExampleGroups::SKIPPED +
|
|
||||||
Examples::EXAMPLES +
|
|
||||||
Examples::SKIPPED +
|
|
||||||
Examples::PENDING
|
|
||||||
|
|
||||||
focused = ExampleGroups::FOCUSED + Examples::FOCUSED
|
focused = ExampleGroups::FOCUSED + Examples::FOCUSED
|
||||||
|
|
||||||
FOCUSABLE_SELECTORS = focusable.node_pattern_union
|
def_node_matcher :focusable_selector?,
|
||||||
|
(ExampleGroups::GROUPS + ExampleGroups::SKIPPED +
|
||||||
|
Examples::EXAMPLES + Examples::SKIPPED +
|
||||||
|
Examples::PENDING).node_pattern_union
|
||||||
|
|
||||||
def_node_matcher :metadata, <<-PATTERN
|
def_node_matcher :metadata, <<-PATTERN
|
||||||
{(send #{RSPEC} #{FOCUSABLE_SELECTORS} <$(sym :focus) ...>)
|
{(send #rspec? #focusable_selector? <$(sym :focus) ...>)
|
||||||
(send #{RSPEC} #{FOCUSABLE_SELECTORS} ... (hash <$(pair (sym :focus) true) ...>))}
|
(send #rspec? #focusable_selector? ... (hash <$(pair (sym :focus) true) ...>))}
|
||||||
PATTERN
|
PATTERN
|
||||||
|
|
||||||
def_node_matcher :focused_block?, focused.send_pattern
|
def_node_matcher :focused_block?, focused.send_pattern
|
||||||
@ -57,21 +57,20 @@ module RuboCop
|
|||||||
# before(:example) do
|
# before(:example) do
|
||||||
# # ...
|
# # ...
|
||||||
# end
|
# end
|
||||||
class HookArgument < Cop
|
class HookArgument < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include ConfigurableEnforcedStyle
|
include ConfigurableEnforcedStyle
|
||||||
|
|
||||||
IMPLICIT_MSG = 'Omit the default `%<scope>p` ' \
|
IMPLICIT_MSG = 'Omit the default `%<scope>p` argument for RSpec hooks.'
|
||||||
'argument for RSpec hooks.'
|
|
||||||
EXPLICIT_MSG = 'Use `%<scope>p` for RSpec hooks.'
|
EXPLICIT_MSG = 'Use `%<scope>p` for RSpec hooks.'
|
||||||
|
|
||||||
HOOKS = Hooks::ALL.node_pattern_union.freeze
|
def_node_matcher :hook?, Hooks::ALL.node_pattern_union
|
||||||
|
|
||||||
def_node_matcher :scoped_hook, <<-PATTERN
|
def_node_matcher :scoped_hook, <<-PATTERN
|
||||||
(block $(send _ #{HOOKS} (sym ${:each :example})) ...)
|
(block $(send _ #hook? (sym ${:each :example})) ...)
|
||||||
PATTERN
|
PATTERN
|
||||||
|
|
||||||
def_node_matcher :unscoped_hook, "(block $(send _ #{HOOKS}) ...)"
|
def_node_matcher :unscoped_hook, '(block $(send _ #hook?) ...)'
|
||||||
|
|
||||||
def on_block(node)
|
def on_block(node)
|
||||||
hook(node) do |method_send, scope_name|
|
hook(node) do |method_send, scope_name|
|
||||||
@ -23,7 +23,7 @@ module RuboCop
|
|||||||
# expect(foo).to be
|
# expect(foo).to be
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
class HooksBeforeExamples < Cop
|
class HooksBeforeExamples < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Move `%<hook>s` above the examples in the group.'
|
MSG = 'Move `%<hook>s` above the examples in the group.'
|
||||||
@ -16,7 +16,7 @@ module RuboCop
|
|||||||
# it 'changes something to a new value' do
|
# it 'changes something to a new value' do
|
||||||
# expect { do_something }.to change(something).to(new_value)
|
# expect { do_something }.to change(something).to(new_value)
|
||||||
# end
|
# end
|
||||||
class ImplicitBlockExpectation < Cop
|
class ImplicitBlockExpectation < Base
|
||||||
MSG = 'Avoid implicit block expectations.'
|
MSG = 'Avoid implicit block expectations.'
|
||||||
|
|
||||||
def_node_matcher :lambda?, <<-PATTERN
|
def_node_matcher :lambda?, <<-PATTERN
|
||||||
@ -24,7 +24,7 @@ module RuboCop
|
|||||||
# # good
|
# # good
|
||||||
# it { should be_truthy }
|
# it { should be_truthy }
|
||||||
#
|
#
|
||||||
class ImplicitExpect < Cop
|
class ImplicitExpect < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include ConfigurableEnforcedStyle
|
include ConfigurableEnforcedStyle
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ module RuboCop
|
|||||||
# # good
|
# # good
|
||||||
# it { expect(subject).to be_truthy }
|
# it { expect(subject).to be_truthy }
|
||||||
#
|
#
|
||||||
class ImplicitSubject < Cop
|
class ImplicitSubject < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include ConfigurableEnforcedStyle
|
include ConfigurableEnforcedStyle
|
||||||
|
|
||||||
@ -49,9 +49,10 @@ module RuboCop
|
|||||||
|
|
||||||
def autocorrect(corrector, node)
|
def autocorrect(corrector, node)
|
||||||
replacement = 'expect(subject)'
|
replacement = 'expect(subject)'
|
||||||
if node.method_name == :should
|
case node.method_name
|
||||||
|
when :should
|
||||||
replacement += '.to'
|
replacement += '.to'
|
||||||
elsif node.method_name == :should_not
|
when :should_not
|
||||||
replacement += '.not_to'
|
replacement += '.not_to'
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -62,13 +63,14 @@ module RuboCop
|
|||||||
example = node.ancestors.find { |parent| example?(parent) }
|
example = node.ancestors.find { |parent| example?(parent) }
|
||||||
return false if example.nil?
|
return false if example.nil?
|
||||||
|
|
||||||
example.method_name == :its || allowed_by_style?(example)
|
example.method?(:its) || allowed_by_style?(example)
|
||||||
end
|
end
|
||||||
|
|
||||||
def allowed_by_style?(example)
|
def allowed_by_style?(example)
|
||||||
if style == :single_line_only
|
case style
|
||||||
|
when :single_line_only
|
||||||
example.single_line?
|
example.single_line?
|
||||||
elsif style == :single_statement_only
|
when :single_statement_only
|
||||||
!example.body.begin_type?
|
!example.body.begin_type?
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
@ -18,7 +18,7 @@ module RuboCop
|
|||||||
# expect(foo).to have_received(:bar)
|
# expect(foo).to have_received(:bar)
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
class InstanceSpy < Cop
|
class InstanceSpy < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Use `instance_spy` when you check your double '\
|
MSG = 'Use `instance_spy` when you check your double '\
|
||||||
@ -46,7 +46,7 @@ module RuboCop
|
|||||||
# it { expect(foo).to be_empty }
|
# it { expect(foo).to be_empty }
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
class InstanceVariable < Cop
|
class InstanceVariable < Base
|
||||||
include RuboCop::RSpec::TopLevelGroup
|
include RuboCop::RSpec::TopLevelGroup
|
||||||
|
|
||||||
MSG = 'Avoid instance variables – use let, ' \
|
MSG = 'Avoid instance variables – use let, ' \
|
||||||
@ -15,7 +15,7 @@ module RuboCop
|
|||||||
#
|
#
|
||||||
# # good
|
# # good
|
||||||
# expect(foo).to be_something
|
# expect(foo).to be_something
|
||||||
class InvalidPredicateMatcher < Cop
|
class InvalidPredicateMatcher < Base
|
||||||
MSG = 'Omit `?` from `%<matcher>s`.'
|
MSG = 'Omit `?` from `%<matcher>s`.'
|
||||||
|
|
||||||
def_node_matcher :invalid_predicate_matcher?, <<-PATTERN
|
def_node_matcher :invalid_predicate_matcher?, <<-PATTERN
|
||||||
@ -18,7 +18,7 @@ module RuboCop
|
|||||||
#
|
#
|
||||||
# # good
|
# # good
|
||||||
# it_should_behave_like 'a foo'
|
# it_should_behave_like 'a foo'
|
||||||
class ItBehavesLike < Cop
|
class ItBehavesLike < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
include ConfigurableEnforcedStyle
|
include ConfigurableEnforcedStyle
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ module RuboCop
|
|||||||
# it 'validates users' do
|
# it 'validates users' do
|
||||||
# expect([user1, user2, user3]).to all(be_valid)
|
# expect([user1, user2, user3]).to all(be_valid)
|
||||||
# end
|
# end
|
||||||
class IteratedExpectation < Cop
|
class IteratedExpectation < Base
|
||||||
MSG = 'Prefer using the `all` matcher instead ' \
|
MSG = 'Prefer using the `all` matcher instead ' \
|
||||||
'of iterating over an array.'
|
'of iterating over an array.'
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ module RuboCop
|
|||||||
# it { expect_something }
|
# it { expect_something }
|
||||||
# it { expect_something_else }
|
# it { expect_something_else }
|
||||||
#
|
#
|
||||||
class LeadingSubject < Cop
|
class LeadingSubject < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Declare `subject` above any other `%<offending>s` declarations.'
|
MSG = 'Declare `subject` above any other `%<offending>s` declarations.'
|
||||||
@ -43,33 +43,36 @@ module RuboCop
|
|||||||
end
|
end
|
||||||
|
|
||||||
def check_previous_nodes(node)
|
def check_previous_nodes(node)
|
||||||
node.parent.each_child_node do |sibling|
|
offending_node(node) do |offender|
|
||||||
if offending?(sibling)
|
msg = format(MSG, offending: offender.method_name)
|
||||||
msg = format(MSG, offending: sibling.method_name)
|
|
||||||
add_offense(node, message: msg) do |corrector|
|
add_offense(node, message: msg) do |corrector|
|
||||||
autocorrect(corrector, node)
|
autocorrect(corrector, node, offender)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
break if offending?(sibling) || sibling.equal?(node)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def autocorrect(corrector, node)
|
def offending_node(node)
|
||||||
first_node = find_first_offending_node(node)
|
node.parent.each_child_node.find do |sibling|
|
||||||
|
break if sibling.equal?(node)
|
||||||
|
|
||||||
|
yield sibling if offending?(sibling)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def autocorrect(corrector, node, sibling)
|
||||||
RuboCop::RSpec::Corrector::MoveNode.new(
|
RuboCop::RSpec::Corrector::MoveNode.new(
|
||||||
node, corrector, processed_source
|
node, corrector, processed_source
|
||||||
).move_before(first_node)
|
).move_before(sibling)
|
||||||
end
|
end
|
||||||
|
|
||||||
def offending?(node)
|
def offending?(node)
|
||||||
let?(node) || hook?(node) || example?(node)
|
let?(node) ||
|
||||||
end
|
hook?(node) ||
|
||||||
|
example?(node) ||
|
||||||
def find_first_offending_node(node)
|
spec_group?(node) ||
|
||||||
node.parent.children.find { |sibling| offending?(sibling) }
|
include?(node)
|
||||||
end
|
end
|
||||||
|
|
||||||
def in_spec_block?(node)
|
def in_spec_block?(node)
|
||||||
@ -93,7 +93,7 @@ module RuboCop
|
|||||||
# stub_const('SomeModule::SomeClass', foo_class)
|
# stub_const('SomeModule::SomeClass', foo_class)
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
class LeakyConstantDeclaration < Cop
|
class LeakyConstantDeclaration < Base
|
||||||
MSG_CONST = 'Stub constant instead of declaring explicitly.'
|
MSG_CONST = 'Stub constant instead of declaring explicitly.'
|
||||||
MSG_CLASS = 'Stub class constant instead of declaring explicitly.'
|
MSG_CLASS = 'Stub class constant instead of declaring explicitly.'
|
||||||
MSG_MODULE = 'Stub module constant instead of declaring explicitly.'
|
MSG_MODULE = 'Stub module constant instead of declaring explicitly.'
|
||||||
@ -30,7 +30,7 @@ module RuboCop
|
|||||||
# it 'checks what some does' do
|
# it 'checks what some does' do
|
||||||
# expect(some).to be
|
# expect(some).to be
|
||||||
# end
|
# end
|
||||||
class LetBeforeExamples < Cop
|
class LetBeforeExamples < Base
|
||||||
extend AutoCorrector
|
extend AutoCorrector
|
||||||
|
|
||||||
MSG = 'Move `let` before the examples in the group.'
|
MSG = 'Move `let` before the examples in the group.'
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user