mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
Warn about undocumented non-private APIs.
This commit is contained in:
parent
7c0b989740
commit
caf87c0336
@ -70,6 +70,11 @@ Style/Documentation:
|
||||
- version.rb
|
||||
- tap.rb
|
||||
|
||||
Homebrew/NegateInclude:
|
||||
Exclude:
|
||||
# YARD runs stand-alone.
|
||||
- yard/docstring_parser.rb
|
||||
|
||||
Style/DocumentationMethod:
|
||||
Include:
|
||||
- "formula.rb"
|
||||
|
@ -18,6 +18,7 @@ end
|
||||
group :doc, optional: true do
|
||||
gem "yard", require: false
|
||||
gem "yard-sorbet", require: false
|
||||
gem "redcarpet", require: false
|
||||
end
|
||||
group :ast, optional: true do
|
||||
gem "rubocop-ast", require: false
|
||||
|
@ -60,7 +60,6 @@ class PATH
|
||||
@paths.join(File::PATH_SEPARATOR)
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s = to_str
|
||||
|
||||
|
@ -265,7 +265,7 @@ EOS
|
||||
fi
|
||||
}
|
||||
|
||||
# NOTE: the members of the array in the second arg must not have spaces!
|
||||
# NOTE: The members of the array in the second arg must not have spaces!
|
||||
check-array-membership() {
|
||||
local item=$1
|
||||
shift
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Note: that we use a non-standard config file name to reduce
|
||||
# name clashes with other IRB config files like `.irbrc`.
|
||||
# Note #2: This doesn't work with system Ruby for some reason.
|
||||
# NOTE: We use a non-standard config file name to reduce name clashes with
|
||||
# other IRB config files like `.irbrc`.
|
||||
# NOTE: This doesn't work with system Ruby for some reason.
|
||||
|
||||
require 'irb/completion'
|
||||
|
||||
|
@ -9,16 +9,26 @@ class BuildOptions
|
||||
end
|
||||
|
||||
# True if a {Formula} is being built with a specific option.
|
||||
# <pre>args << "--i-want-spam" if build.with? "spam"
|
||||
#
|
||||
# ### Examples
|
||||
#
|
||||
# ```ruby
|
||||
# args << "--i-want-spam" if build.with? "spam"
|
||||
# ```
|
||||
#
|
||||
# ```ruby
|
||||
# args << "--qt-gui" if build.with? "qt" # "--with-qt" ==> build.with? "qt"
|
||||
# ```
|
||||
#
|
||||
# # If a formula presents a user with a choice, but the choice must be fulfilled:
|
||||
# If a formula presents a user with a choice, but the choice must be fulfilled:
|
||||
#
|
||||
# ```ruby
|
||||
# if build.with? "example2"
|
||||
# args << "--with-example2"
|
||||
# else
|
||||
# args << "--with-example1"
|
||||
# end</pre>
|
||||
# end
|
||||
# ```
|
||||
def with?(val)
|
||||
option_names = val.respond_to?(:option_names) ? val.option_names : [val]
|
||||
|
||||
@ -34,7 +44,12 @@ class BuildOptions
|
||||
end
|
||||
|
||||
# True if a {Formula} is being built without a specific option.
|
||||
# <pre>args << "--no-spam-plz" if build.without? "spam"</pre>
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# args << "--no-spam-plz" if build.without? "spam"
|
||||
# ```
|
||||
def without?(val)
|
||||
!with?(val)
|
||||
end
|
||||
@ -45,19 +60,33 @@ class BuildOptions
|
||||
end
|
||||
|
||||
# True if a {Formula} is being built with {Formula.head} instead of {Formula.stable}.
|
||||
# <pre>args << "--some-new-stuff" if build.head?</pre>
|
||||
# <pre># If there are multiple conditional arguments use a block instead of lines.
|
||||
#
|
||||
# ### Examples
|
||||
#
|
||||
# ```ruby
|
||||
# args << "--some-new-stuff" if build.head?
|
||||
# ```
|
||||
#
|
||||
# If there are multiple conditional arguments use a block instead of lines.
|
||||
#
|
||||
# ```ruby
|
||||
# if build.head?
|
||||
# args << "--i-want-pizza"
|
||||
# args << "--and-a-cold-beer" if build.with? "cold-beer"
|
||||
# end</pre>
|
||||
# end
|
||||
# ```
|
||||
def head?
|
||||
include? "HEAD"
|
||||
end
|
||||
|
||||
# True if a {Formula} is being built with {Formula.stable} instead of {Formula.head}.
|
||||
# This is the default.
|
||||
# <pre>args << "--some-beta" if build.head?</pre>
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# args << "--some-beta" if build.head?
|
||||
# ```
|
||||
def stable?
|
||||
!head?
|
||||
end
|
||||
|
@ -147,7 +147,6 @@ module Cask
|
||||
cask.config
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"#{summarize} (#{self.class.english_name})"
|
||||
|
@ -78,7 +78,8 @@ module Cask
|
||||
@allow_reassignment = allow_reassignment
|
||||
@loaded_from_api = loaded_from_api
|
||||
@loader = loader
|
||||
# Sorbet has trouble with bound procs assigned to ivars: https://github.com/sorbet/sorbet/issues/6843
|
||||
# Sorbet has trouble with bound procs assigned to instance variables:
|
||||
# https://github.com/sorbet/sorbet/issues/6843
|
||||
instance_variable_set(:@block, block)
|
||||
|
||||
@default_config = config || Config.new
|
||||
@ -323,11 +324,9 @@ module Cask
|
||||
end
|
||||
|
||||
# @api public
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s = token
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<Cask #{token}#{sourcefile_path&.to_s&.prepend(" ")}>"
|
||||
|
@ -112,6 +112,16 @@ module Cask
|
||||
@token = cask.token
|
||||
end
|
||||
|
||||
# Specifies the cask's name.
|
||||
#
|
||||
# NOTE: Multiple names can be specified.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# name "Visual Studio Code"
|
||||
# ```
|
||||
#
|
||||
# @api public
|
||||
def name(*args)
|
||||
@name ||= []
|
||||
@ -120,6 +130,14 @@ module Cask
|
||||
@name.concat(args.flatten)
|
||||
end
|
||||
|
||||
# Describes the cask.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# desc "Open-source code editor"
|
||||
# ```
|
||||
#
|
||||
# @api public
|
||||
def desc(description = nil)
|
||||
set_unique_stanza(:desc, description.nil?) { description }
|
||||
@ -146,6 +164,14 @@ module Cask
|
||||
raise CaskInvalidError.new(cask, "'#{stanza}' stanza failed with: #{e}")
|
||||
end
|
||||
|
||||
# Sets the cask's homepage.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# homepage "https://code.visualstudio.com/"
|
||||
# ```
|
||||
#
|
||||
# @api public
|
||||
def homepage(homepage = nil)
|
||||
set_unique_stanza(:homepage, homepage.nil?) { homepage }
|
||||
@ -201,6 +227,14 @@ module Cask
|
||||
@language_blocks.keys.flatten
|
||||
end
|
||||
|
||||
# Sets the cask's download URL.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# url "https://update.code.visualstudio.com/#{version}/#{arch}/stable"
|
||||
# ```
|
||||
#
|
||||
# @api public
|
||||
def url(*args, **options, &block)
|
||||
caller_location = T.must(caller_locations).fetch(0)
|
||||
@ -214,6 +248,8 @@ module Cask
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the cask's appcast URL.
|
||||
#
|
||||
# @api public
|
||||
def appcast(*args, **kwargs)
|
||||
set_unique_stanza(:appcast, args.empty? && kwargs.empty?) do
|
||||
@ -222,6 +258,22 @@ module Cask
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the cask's container type or nested container path.
|
||||
#
|
||||
# ### Examples
|
||||
#
|
||||
# The container is a nested disk image:
|
||||
#
|
||||
# ```ruby
|
||||
# container nested: "orca-#{version}.dmg"
|
||||
# ```
|
||||
#
|
||||
# The container should not be unarchived:
|
||||
#
|
||||
# ```ruby
|
||||
# container type: :naked
|
||||
# ```
|
||||
#
|
||||
# @api public
|
||||
def container(**kwargs)
|
||||
set_unique_stanza(:container, kwargs.empty?) do
|
||||
@ -229,6 +281,15 @@ module Cask
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the cask's version.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# version "1.88.1"
|
||||
# ```
|
||||
#
|
||||
# @see DSL::Version
|
||||
# @api public
|
||||
def version(arg = nil)
|
||||
set_unique_stanza(:version, arg.nil?) do
|
||||
@ -240,6 +301,23 @@ module Cask
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the cask's download checksum.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# For universal or single-architecture downloads:
|
||||
#
|
||||
# ```ruby
|
||||
# sha256 "7bdb497080ffafdfd8cc94d8c62b004af1be9599e865e5555e456e2681e150ca"
|
||||
# ```
|
||||
#
|
||||
# For architecture-dependent downloads:
|
||||
#
|
||||
# ```ruby
|
||||
# sha256 arm: "7bdb497080ffafdfd8cc94d8c62b004af1be9599e865e5555e456e2681e150ca",
|
||||
# intel: "b3c1c2442480a0219b9e05cf91d03385858c20f04b764ec08a3fa83d1b27e7b2"
|
||||
# ```
|
||||
#
|
||||
# @api public
|
||||
def sha256(arg = nil, arm: nil, intel: nil)
|
||||
should_return = arg.nil? && arm.nil? && intel.nil?
|
||||
@ -259,6 +337,14 @@ module Cask
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the cask's architecture strings.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# arch arm: "darwin-arm64", intel: "darwin"
|
||||
# ```
|
||||
#
|
||||
# @api public
|
||||
def arch(arm: nil, intel: nil)
|
||||
should_return = arm.nil? && intel.nil?
|
||||
@ -270,7 +356,10 @@ module Cask
|
||||
end
|
||||
end
|
||||
|
||||
# `depends_on` uses a load method so that multiple stanzas can be merged.
|
||||
# Declare dependencies and requirements for a cask.
|
||||
#
|
||||
# NOTE: Multiple dependencies can be specified.
|
||||
#
|
||||
# @api public
|
||||
def depends_on(**kwargs)
|
||||
@depends_on ||= DSL::DependsOn.new
|
||||
@ -284,9 +373,11 @@ module Cask
|
||||
@depends_on
|
||||
end
|
||||
|
||||
# Declare conflicts that keep a cask from installing or working correctly.
|
||||
#
|
||||
# @api public
|
||||
def conflicts_with(**kwargs)
|
||||
# TODO: remove this constraint, and instead merge multiple conflicts_with stanzas
|
||||
# TODO: Remove this constraint and instead merge multiple `conflicts_with` stanzas
|
||||
set_unique_stanza(:conflicts_with, kwargs.empty?) { DSL::ConflictsWith.new(**kwargs) }
|
||||
end
|
||||
|
||||
@ -298,6 +389,8 @@ module Cask
|
||||
cask.caskroom_path
|
||||
end
|
||||
|
||||
# The staged location for this cask, including version number.
|
||||
#
|
||||
# @api public
|
||||
def staged_path
|
||||
return @staged_path if @staged_path
|
||||
@ -306,6 +399,8 @@ module Cask
|
||||
@staged_path = caskroom_path.join(cask_version.to_s)
|
||||
end
|
||||
|
||||
# Provide the user with cask-specific information at install time.
|
||||
#
|
||||
# @api public
|
||||
def caveats(*strings, &block)
|
||||
@caveats ||= DSL::Caveats.new(cask)
|
||||
@ -326,11 +421,15 @@ module Cask
|
||||
@caveats&.discontinued? == true
|
||||
end
|
||||
|
||||
# Asserts that the cask artifacts auto-update.
|
||||
#
|
||||
# @api public
|
||||
def auto_updates(auto_updates = nil)
|
||||
set_unique_stanza(:auto_updates, auto_updates.nil?) { auto_updates }
|
||||
end
|
||||
|
||||
# Automatically fetch the latest version of a cask from changelogs.
|
||||
#
|
||||
# @api public
|
||||
def livecheck(&block)
|
||||
@livecheck ||= Livecheck.new(cask)
|
||||
@ -344,6 +443,10 @@ module Cask
|
||||
@livecheck.instance_eval(&block)
|
||||
end
|
||||
|
||||
# Declare that a cask is no longer functional or supported.
|
||||
#
|
||||
# NOTE: A warning will be shown when trying to install this cask.
|
||||
#
|
||||
# @api public
|
||||
def deprecate!(date:, because:)
|
||||
@deprecation_date = Date.parse(date)
|
||||
@ -353,6 +456,10 @@ module Cask
|
||||
@deprecated = true
|
||||
end
|
||||
|
||||
# Declare that a cask is no longer functional or supported.
|
||||
#
|
||||
# NOTE: An error will be thrown when trying to install this cask.
|
||||
#
|
||||
# @api public
|
||||
def disable!(date:, because:)
|
||||
@disable_date = Date.parse(date)
|
||||
@ -405,6 +512,8 @@ module Cask
|
||||
true
|
||||
end
|
||||
|
||||
# The directory `app`s are installed into.
|
||||
#
|
||||
# @api public
|
||||
def appdir
|
||||
return HOMEBREW_CASK_APPDIR_PLACEHOLDER if Cask.generating_hash?
|
||||
|
@ -37,7 +37,6 @@ module Cask
|
||||
|
||||
private_class_method :caveat
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
(@custom_caveats + @built_in_caveats.values).join("\n")
|
||||
|
@ -27,7 +27,6 @@ module Cask
|
||||
pairs.to_yaml
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s = pairs.inspect
|
||||
end
|
||||
|
@ -9,8 +9,8 @@ module Cask
|
||||
class Postflight < Base
|
||||
include Staged
|
||||
|
||||
def suppress_move_to_applications(_options = {})
|
||||
odisabled "Cask::DSL#suppress_move_to_applications"
|
||||
def suppress_move_to_applications(**_options)
|
||||
odisabled "`Cask::DSL::Postflight#suppress_move_to_applications`"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -94,70 +94,94 @@ module Cask
|
||||
to_s == "latest"
|
||||
end
|
||||
|
||||
# The major version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def major
|
||||
version { slice(MAJOR_MINOR_PATCH_REGEX, 1) }
|
||||
end
|
||||
|
||||
# The minor version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def minor
|
||||
version { slice(MAJOR_MINOR_PATCH_REGEX, 2) }
|
||||
end
|
||||
|
||||
# The patch version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def patch
|
||||
version { slice(MAJOR_MINOR_PATCH_REGEX, 3) }
|
||||
end
|
||||
|
||||
# The major and minor version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def major_minor
|
||||
version { [major, minor].reject(&:empty?).join(".") }
|
||||
end
|
||||
|
||||
# The major, minor and patch version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def major_minor_patch
|
||||
version { [major, minor, patch].reject(&:empty?).join(".") }
|
||||
end
|
||||
|
||||
# The minor and patch version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def minor_patch
|
||||
version { [minor, patch].reject(&:empty?).join(".") }
|
||||
end
|
||||
|
||||
# The comma separated values of the version as array.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T::Array[Version]) } # Only top-level T.self_type is supported https://sorbet.org/docs/self-type
|
||||
def csv
|
||||
split(",").map { self.class.new(_1) }
|
||||
end
|
||||
|
||||
# The version part before the first comma.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def before_comma
|
||||
version { split(",", 2).first }
|
||||
end
|
||||
|
||||
# The version part after the first comma.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def after_comma
|
||||
version { split(",", 2).second }
|
||||
end
|
||||
|
||||
# The version without any dividers.
|
||||
#
|
||||
# @see DIVIDER_REGEX
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def no_dividers
|
||||
version { gsub(DIVIDER_REGEX, "") }
|
||||
end
|
||||
|
||||
# The version with the given record separator removed from the end.
|
||||
#
|
||||
# @see String#chomp
|
||||
# @api public
|
||||
sig { params(separator: T.nilable(String)).returns(T.self_type) }
|
||||
def chomp(separator = nil)
|
||||
version { to_s.chomp(T.unsafe(separator)) }
|
||||
sig { params(separator: String).returns(T.self_type) }
|
||||
def chomp(separator = T.unsafe(nil))
|
||||
version { to_s.chomp(separator) }
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -13,7 +13,6 @@ module Cask
|
||||
@errors = errors
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
<<~EOS
|
||||
@ -41,7 +40,6 @@ module Cask
|
||||
|
||||
# Error when a cask is not installed.
|
||||
class CaskNotInstalledError < AbstractCaskErrorWithToken
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"Cask '#{token}' is not installed."
|
||||
@ -57,7 +55,6 @@ module Cask
|
||||
@message = message
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"Cask '#{token}' has been #{message}"
|
||||
@ -73,7 +70,6 @@ module Cask
|
||||
@conflicting_cask = conflicting_cask
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"Cask '#{token}' conflicts with '#{conflicting_cask}'."
|
||||
@ -82,7 +78,6 @@ module Cask
|
||||
|
||||
# Error when a cask is not available.
|
||||
class CaskUnavailableError < AbstractCaskErrorWithToken
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"Cask '#{token}' is unavailable#{reason.empty? ? "." : ": #{reason}"}"
|
||||
@ -91,7 +86,6 @@ module Cask
|
||||
|
||||
# Error when a cask is unreadable.
|
||||
class CaskUnreadableError < CaskUnavailableError
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"Cask '#{token}' is unreadable#{reason.empty? ? "." : ": #{reason}"}"
|
||||
@ -107,7 +101,6 @@ module Cask
|
||||
@tap = tap
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
s = super
|
||||
@ -142,7 +135,6 @@ module Cask
|
||||
|
||||
# Error when a cask already exists.
|
||||
class CaskAlreadyCreatedError < AbstractCaskErrorWithToken
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
%Q(Cask '#{token}' already exists. Run #{Formatter.identifier("brew edit --cask #{token}")} to edit it.)
|
||||
@ -151,7 +143,6 @@ module Cask
|
||||
|
||||
# Error when there is a cyclic cask dependency.
|
||||
class CaskCyclicDependencyError < AbstractCaskErrorWithToken
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"Cask '#{token}' includes cyclic dependencies on other Casks#{reason.empty? ? "." : ": #{reason}"}"
|
||||
@ -160,7 +151,6 @@ module Cask
|
||||
|
||||
# Error when a cask depends on itself.
|
||||
class CaskSelfReferencingDependencyError < CaskCyclicDependencyError
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"Cask '#{token}' depends on itself."
|
||||
@ -169,7 +159,6 @@ module Cask
|
||||
|
||||
# Error when no cask is specified.
|
||||
class CaskUnspecifiedError < CaskError
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"This command requires a Cask token."
|
||||
@ -178,7 +167,6 @@ module Cask
|
||||
|
||||
# Error when a cask is invalid.
|
||||
class CaskInvalidError < AbstractCaskErrorWithToken
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"Cask '#{token}' definition is invalid#{reason.empty? ? "." : ": #{reason}"}"
|
||||
@ -203,7 +191,6 @@ module Cask
|
||||
@reason = reason
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
s = +"Failed to quarantine #{path}."
|
||||
@ -220,7 +207,6 @@ module Cask
|
||||
|
||||
# Error while propagating quarantine information to subdirectories.
|
||||
class CaskQuarantinePropagationError < CaskQuarantineError
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
s = +"Failed to quarantine one or more files within #{path}."
|
||||
@ -237,7 +223,6 @@ module Cask
|
||||
|
||||
# Error while removing quarantine information.
|
||||
class CaskQuarantineReleaseError < CaskQuarantineError
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
s = +"Failed to release #{path} from quarantine."
|
||||
|
@ -17,22 +17,32 @@ module Cask
|
||||
extend Forwardable
|
||||
def_delegators :uri, :path, :scheme, :to_s
|
||||
|
||||
# @api public
|
||||
sig {
|
||||
params(
|
||||
uri: T.any(URI::Generic, String),
|
||||
# @api public
|
||||
verified: T.nilable(String),
|
||||
# @api public
|
||||
using: T.any(Class, Symbol, NilClass),
|
||||
# @api public
|
||||
tag: T.nilable(String),
|
||||
# @api public
|
||||
branch: T.nilable(String),
|
||||
# @api public
|
||||
revisions: T.nilable(T::Array[String]),
|
||||
# @api public
|
||||
revision: T.nilable(String),
|
||||
# @api public
|
||||
trust_cert: T.nilable(T::Boolean),
|
||||
# @api public
|
||||
cookies: T.nilable(T::Hash[String, String]),
|
||||
referer: T.nilable(T.any(URI::Generic, String)),
|
||||
# @api public
|
||||
header: T.nilable(T.any(String, T::Array[String])),
|
||||
user_agent: T.nilable(T.any(Symbol, String)),
|
||||
# @api public
|
||||
data: T.nilable(T::Hash[String, String]),
|
||||
# @api public
|
||||
only_path: T.nilable(String),
|
||||
).void
|
||||
}
|
||||
@ -77,8 +87,19 @@ module Cask
|
||||
end
|
||||
|
||||
class BlockDSL
|
||||
# To access URL associated with page contents.
|
||||
# Allow accessing the URL associated with page contents.
|
||||
module PageWithURL
|
||||
# Get the URL of the fetched page.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# url "https://example.org/download" do |page|
|
||||
# file = page[/href="([^"]+.dmg)"/, 1]
|
||||
# URL.join(page.url, file)
|
||||
# end
|
||||
# ```
|
||||
#
|
||||
# @api public
|
||||
sig { returns(URI::Generic) }
|
||||
attr_accessor :url
|
||||
@ -87,12 +108,12 @@ module Cask
|
||||
sig {
|
||||
params(
|
||||
uri: T.nilable(T.any(URI::Generic, String)),
|
||||
dsl: T.nilable(::Cask::DSL),
|
||||
dsl: ::Cask::DSL,
|
||||
block: T.proc.params(arg0: T.all(String, PageWithURL))
|
||||
.returns(T.any(T.any(URI::Generic, String), [T.any(URI::Generic, String), Hash])),
|
||||
).void
|
||||
}
|
||||
def initialize(uri, dsl: nil, &block)
|
||||
def initialize(uri, dsl:, &block)
|
||||
@uri = uri
|
||||
@dsl = dsl
|
||||
@block = block
|
||||
@ -114,6 +135,8 @@ module Cask
|
||||
end
|
||||
end
|
||||
|
||||
# Allows calling a nested `url` stanza in a `url do` block.
|
||||
#
|
||||
# @api public
|
||||
sig {
|
||||
params(
|
||||
@ -123,10 +146,12 @@ module Cask
|
||||
).returns(T.any(T.any(URI::Generic, String), [T.any(URI::Generic, String), Hash]))
|
||||
}
|
||||
def url(uri, &block)
|
||||
self.class.new(uri, &block).call
|
||||
self.class.new(uri, dsl: @dsl, &block).call
|
||||
end
|
||||
private :url
|
||||
|
||||
# This allows calling DSL methods from inside a `url` block.
|
||||
#
|
||||
# @api public
|
||||
def method_missing(method, *args, &block)
|
||||
if @dsl.respond_to?(method)
|
||||
@ -135,10 +160,12 @@ module Cask
|
||||
super
|
||||
end
|
||||
end
|
||||
private :method_missing
|
||||
|
||||
def respond_to_missing?(method, include_all)
|
||||
@dsl.respond_to?(method, include_all) || super
|
||||
end
|
||||
private :respond_to_missing?
|
||||
end
|
||||
|
||||
sig {
|
||||
@ -187,7 +214,7 @@ module Cask
|
||||
super(
|
||||
if block
|
||||
LazyObject.new do
|
||||
uri2, options = *BlockDSL.new(uri, dsl:, &block).call
|
||||
uri2, options = *BlockDSL.new(uri, dsl: T.must(dsl), &block).call
|
||||
options ||= {}
|
||||
DSL.new(uri2, **options)
|
||||
end
|
||||
|
@ -68,7 +68,7 @@ module Cask
|
||||
unless tried_permissions
|
||||
print_stderr = Context.current.debug? || Context.current.verbose?
|
||||
# TODO: Better handling for the case where path is a symlink.
|
||||
# The -h and -R flags cannot be combined, and behavior is
|
||||
# The `-h` and `-R` flags cannot be combined and behavior is
|
||||
# dependent on whether the file argument has a trailing
|
||||
# slash. This should do the right thing, but is fragile.
|
||||
command.run("/usr/bin/chflags",
|
||||
@ -87,7 +87,7 @@ module Cask
|
||||
unless tried_ownership
|
||||
# in case of ownership problems
|
||||
# TODO: Further examine files to see if ownership is the problem
|
||||
# before using sudo+chown
|
||||
# before using `sudo` and `chown`.
|
||||
ohai "Using sudo to gain ownership of path '#{path}'"
|
||||
command.run("/usr/sbin/chown",
|
||||
args: command_args + ["--", User.current, path],
|
||||
|
@ -756,7 +756,7 @@ class ReporterHub
|
||||
def dump(auto_update: false)
|
||||
report_all = ENV["HOMEBREW_UPDATE_REPORT_ALL_FORMULAE"].present?
|
||||
if report_all && !Homebrew::EnvConfig.no_install_from_api?
|
||||
odisabled "HOMEBREW_UPDATE_REPORT_ALL_FORMULAE"
|
||||
odisabled "`HOMEBREW_UPDATE_REPORT_ALL_FORMULAE`"
|
||||
opoo "This will not report all formulae because Homebrew cannot get this data from the API."
|
||||
report_all = false
|
||||
end
|
||||
|
@ -65,7 +65,6 @@ class CompilerFailure
|
||||
type == compiler.type && version_matched
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{type} #{version}>"
|
||||
|
@ -22,7 +22,6 @@ class CxxStdlib
|
||||
type.to_s.gsub(/cxx$/, "c++")
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{compiler} #{type}>"
|
||||
|
@ -35,7 +35,6 @@ class Dependencies < SimpleDelegator
|
||||
self.class.new(*__getobj__.reject { |dep| dep.uses_from_macos? && dep.use_macos_install? })
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{__getobj__}>"
|
||||
@ -62,7 +61,6 @@ class Requirements < SimpleDelegator
|
||||
self
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: {#{__getobj__.to_a.join(", ")}}>"
|
||||
|
@ -4,6 +4,8 @@
|
||||
require "dependable"
|
||||
|
||||
# A dependency on another Homebrew formula.
|
||||
#
|
||||
# @api internal
|
||||
class Dependency
|
||||
extend Forwardable
|
||||
include Dependable
|
||||
@ -94,11 +96,9 @@ class Dependency
|
||||
false
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s = name
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{name.inspect} #{tags.inspect}>"
|
||||
@ -115,6 +115,8 @@ class Dependency
|
||||
# the list.
|
||||
# The default filter, which is applied when a block is not given, omits
|
||||
# optionals and recommends based on what the dependent has asked for
|
||||
#
|
||||
# @api internal
|
||||
def expand(dependent, deps = dependent.deps, cache_key: nil, &block)
|
||||
# Keep track dependencies to avoid infinite cyclic dependency recursion.
|
||||
@expand_stack ||= []
|
||||
@ -181,6 +183,8 @@ class Dependency
|
||||
end
|
||||
|
||||
# Keep a dependency, but prune its dependencies.
|
||||
#
|
||||
# @api internal
|
||||
sig { void }
|
||||
def keep_but_prune_recursive_deps
|
||||
throw(:action, :keep_but_prune_recursive_deps)
|
||||
@ -282,7 +286,6 @@ class UsesFromMacOSDependency < Dependency
|
||||
self.class.new(formula.full_name.to_s, tags, bounds:)
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{name.inspect} #{tags.inspect} #{bounds.inspect}>"
|
||||
|
@ -98,7 +98,7 @@ module Homebrew
|
||||
end
|
||||
odie "Could not find #{name}! The formula or version may not have existed." if test_formula.nil?
|
||||
else
|
||||
# Search in the root directory of <repo> as well as recursively in all of its subdirectories
|
||||
# Search in the root directory of `repo` as well as recursively in all of its subdirectories.
|
||||
files = Dir[repo/"{,**/}"].filter_map do |dir|
|
||||
Pathname.glob("#{dir}/#{name}.rb").find(&:file?)
|
||||
end
|
||||
|
@ -20,16 +20,18 @@ module Homebrew
|
||||
def run
|
||||
Homebrew.install_bundler_gems!(groups: ["doc"])
|
||||
|
||||
HOMEBREW_LIBRARY_PATH.cd do
|
||||
HOMEBREW_LIBRARY_PATH.cd do |dir|
|
||||
no_api_args = if args.only_public?
|
||||
["--hide-api", "private", "--hide-api", "internal"]
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
system "bundle", "exec", "yard", "doc", "--output", "doc", *no_api_args
|
||||
output_dir = dir/"doc"
|
||||
|
||||
exec_browser "file://#{HOMEBREW_LIBRARY_PATH}/doc/index.html" if args.open?
|
||||
safe_system "bundle", "exec", "yard", "doc", "--fail-on-warning", *no_api_args, "--output", output_dir
|
||||
|
||||
exec_browser "file://#{output_dir}/index.html" if args.open?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -77,11 +77,9 @@ class AbstractDownloadStrategy
|
||||
end
|
||||
|
||||
# Disable any output during downloading.
|
||||
#
|
||||
# @deprecated
|
||||
sig { void }
|
||||
def shutup!
|
||||
odeprecated "AbstractDownloadStrategy#shutup!", "AbstractDownloadStrategy#quiet!"
|
||||
odeprecated "`AbstractDownloadStrategy#shutup!`", "`AbstractDownloadStrategy#quiet!`"
|
||||
quiet!
|
||||
end
|
||||
|
||||
@ -125,7 +123,6 @@ class AbstractDownloadStrategy
|
||||
end
|
||||
private :chdir
|
||||
|
||||
# @!attribute [r] source_modified_time
|
||||
# Returns the most recent modified time for all files in the current working directory after stage.
|
||||
#
|
||||
# @api public
|
||||
@ -236,9 +233,7 @@ class VCSDownloadStrategy < AbstractDownloadStrategy
|
||||
version.respond_to?(:head?) && version.head?
|
||||
end
|
||||
|
||||
# @!attribute [r] last_commit
|
||||
# Return last commit's unique identifier for the repository.
|
||||
# Return most recent modified timestamp unless overridden.
|
||||
# Return the most recent modified timestamp.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(String) }
|
||||
@ -733,7 +728,8 @@ class SubversionDownloadStrategy < VCSDownloadStrategy
|
||||
super
|
||||
end
|
||||
|
||||
# @see AbstractDownloadStrategy#source_modified_time
|
||||
# Returns the most recent modified time for all files in the current working directory after stage.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(Time) }
|
||||
def source_modified_time
|
||||
@ -747,7 +743,8 @@ class SubversionDownloadStrategy < VCSDownloadStrategy
|
||||
Time.parse time
|
||||
end
|
||||
|
||||
# @see VCSDownloadStrategy#last_commit
|
||||
# Return last commit's unique identifier for the repository.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(String) }
|
||||
def last_commit
|
||||
@ -847,7 +844,8 @@ class GitDownloadStrategy < VCSDownloadStrategy
|
||||
@ref ||= "master"
|
||||
end
|
||||
|
||||
# @see AbstractDownloadStrategy#source_modified_time
|
||||
# Returns the most recent modified time for all files in the current working directory after stage.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(Time) }
|
||||
def source_modified_time
|
||||
@ -855,7 +853,8 @@ class GitDownloadStrategy < VCSDownloadStrategy
|
||||
Time.parse(out)
|
||||
end
|
||||
|
||||
# @see VCSDownloadStrategy#last_commit
|
||||
# Return last commit's unique identifier for the repository.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(String) }
|
||||
def last_commit
|
||||
@ -1165,7 +1164,8 @@ class CVSDownloadStrategy < VCSDownloadStrategy
|
||||
end
|
||||
end
|
||||
|
||||
# @see AbstractDownloadStrategy#source_modified_time
|
||||
# Returns the most recent modified time for all files in the current working directory after stage.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(Time) }
|
||||
def source_modified_time
|
||||
@ -1240,7 +1240,8 @@ class MercurialDownloadStrategy < VCSDownloadStrategy
|
||||
@url = @url.sub(%r{^hg://}, "")
|
||||
end
|
||||
|
||||
# @see AbstractDownloadStrategy#source_modified_time
|
||||
# Returns the most recent modified time for all files in the current working directory after stage.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(Time) }
|
||||
def source_modified_time
|
||||
@ -1250,7 +1251,8 @@ class MercurialDownloadStrategy < VCSDownloadStrategy
|
||||
Time.parse(out)
|
||||
end
|
||||
|
||||
# @see VCSDownloadStrategy#last_commit
|
||||
# Return last commit's unique identifier for the repository.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(String) }
|
||||
def last_commit
|
||||
@ -1327,7 +1329,8 @@ class BazaarDownloadStrategy < VCSDownloadStrategy
|
||||
@url = @url.sub(%r{^bzr://}, "")
|
||||
end
|
||||
|
||||
# @see AbstractDownloadStrategy#source_modified_time
|
||||
# Returns the most recent modified time for all files in the current working directory after stage.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(Time) }
|
||||
def source_modified_time
|
||||
@ -1338,7 +1341,8 @@ class BazaarDownloadStrategy < VCSDownloadStrategy
|
||||
Time.parse(timestamp)
|
||||
end
|
||||
|
||||
# @see VCSDownloadStrategy#last_commit
|
||||
# Return last commit's unique identifier for the repository.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(String) }
|
||||
def last_commit
|
||||
@ -1390,7 +1394,8 @@ class FossilDownloadStrategy < VCSDownloadStrategy
|
||||
@url = @url.sub(%r{^fossil://}, "")
|
||||
end
|
||||
|
||||
# @see AbstractDownloadStrategy#source_modified_time
|
||||
# Returns the most recent modified time for all files in the current working directory after stage.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(Time) }
|
||||
def source_modified_time
|
||||
@ -1398,7 +1403,8 @@ class FossilDownloadStrategy < VCSDownloadStrategy
|
||||
Time.parse(out[/^uuid: +\h+ (.+)$/, 1])
|
||||
end
|
||||
|
||||
# @see VCSDownloadStrategy#last_commit
|
||||
# Return last commit's unique identifier for the repository.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(String) }
|
||||
def last_commit
|
||||
|
@ -16,7 +16,6 @@ class UsageError < RuntimeError
|
||||
@reason = reason
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
s = "Invalid usage"
|
||||
@ -109,7 +108,6 @@ class FormulaOrCaskUnavailableError < RuntimeError
|
||||
"Did you mean #{similar_formula_names.to_sentence two_words_connector: " or ", last_word_connector: " or "}?"
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
s = "No available formula or cask with the name \"#{name}\". #{did_you_mean}".strip
|
||||
@ -129,7 +127,6 @@ class TapFormulaOrCaskUnavailableError < FormulaOrCaskUnavailableError
|
||||
@tap = tap
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
s = super
|
||||
@ -149,7 +146,6 @@ class FormulaUnavailableError < FormulaOrCaskUnavailableError
|
||||
" (dependency of #{dependent})" if dependent && dependent != name
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"No available formula with the name \"#{name}\"#{dependent_s}. #{did_you_mean}".strip
|
||||
@ -160,7 +156,6 @@ end
|
||||
module FormulaClassUnavailableErrorModule
|
||||
attr_reader :path, :class_name, :class_list
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
s = super
|
||||
@ -204,7 +199,6 @@ end
|
||||
module FormulaUnreadableErrorModule
|
||||
attr_reader :formula_error
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"#{name}: " + formula_error.to_s
|
||||
@ -233,7 +227,6 @@ class TapFormulaUnavailableError < FormulaUnavailableError
|
||||
super "#{tap}/#{name}"
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
s = super
|
||||
@ -572,7 +565,7 @@ class UnbottledError < RuntimeError
|
||||
end
|
||||
end
|
||||
|
||||
# Raised by Homebrew.install, Homebrew.reinstall, and Homebrew.upgrade
|
||||
# Raised by `Homebrew.install`, `Homebrew.reinstall` and `Homebrew.upgrade`
|
||||
# if the user passes any flags/environment that would case a bottle-only
|
||||
# installation on a system without build tools to fail.
|
||||
class BuildFlagsError < RuntimeError
|
||||
|
@ -1,5 +1,6 @@
|
||||
# typed: strict
|
||||
|
||||
# @!visibility private
|
||||
module EnvMethods
|
||||
include Kernel
|
||||
|
||||
@ -39,6 +40,7 @@ module EnvActivation
|
||||
include Superenv
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
class Sorbet
|
||||
module Private
|
||||
module Static
|
||||
|
@ -4,6 +4,7 @@ module SharedEnvExtension
|
||||
include EnvMethods
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
class Sorbet
|
||||
module Private
|
||||
module Static
|
||||
|
@ -2,59 +2,72 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Array
|
||||
# Equal to <tt>self[1]</tt>.
|
||||
# Equal to `self[1]`.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# %w( a b c d e ).second # => "b"
|
||||
# ```
|
||||
def second = self[1]
|
||||
|
||||
# Equal to <tt>self[2]</tt>.
|
||||
# Equal to `self[2]`.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# %w( a b c d e ).third # => "c"
|
||||
# ```
|
||||
def third = self[2]
|
||||
|
||||
# Equal to <tt>self[3]</tt>.
|
||||
# Equal to `self[3]`.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# %w( a b c d e ).fourth # => "d"
|
||||
# ```
|
||||
def fourth = self[3]
|
||||
|
||||
# Equal to <tt>self[4]</tt>.
|
||||
# Equal to `self[4]`.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# %w( a b c d e ).fifth # => "e"
|
||||
# ```
|
||||
def fifth = self[4]
|
||||
|
||||
# Converts the array to a comma-separated sentence where the last element is
|
||||
# joined by the connector word.
|
||||
#
|
||||
# You can pass the following kwargs to change the default behavior:
|
||||
#
|
||||
# * <tt>:words_connector</tt> - The sign or word used to join all but the last
|
||||
# element in arrays with three or more elements (default: ", ").
|
||||
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element
|
||||
# in arrays with three or more elements (default: ", and ").
|
||||
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements
|
||||
# in arrays with two elements (default: " and ").
|
||||
#
|
||||
# ==== Examples
|
||||
# ### Examples
|
||||
#
|
||||
# ```ruby
|
||||
# [].to_sentence # => ""
|
||||
# ['one'].to_sentence # => "one"
|
||||
# ['one', 'two'].to_sentence # => "one and two"
|
||||
# ['one', 'two', 'three'].to_sentence # => "one, two, and three"
|
||||
# ['one', 'two', 'three'].to_sentence # => "one, two and three"
|
||||
# ['one', 'two'].to_sentence(two_words_connector: '-')
|
||||
# # => "one-two"
|
||||
# ```
|
||||
#
|
||||
# ```
|
||||
# ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ')
|
||||
# # => "one or two or at least three"
|
||||
# ```
|
||||
#
|
||||
# @see https://github.com/rails/rails/blob/v7.0.4.2/activesupport/lib/active_support/core_ext/array/conversions.rb#L8-L84
|
||||
# ActiveSupport Array#to_sentence monkey-patch
|
||||
#
|
||||
#
|
||||
# Copyright (c) David Heinemeier Hansson
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# distribute, sublicense and/or sell copies of the Software and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
@ -68,6 +81,14 @@ class Array
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
#
|
||||
# @param [String] words_connector The sign or word used to join all but the last
|
||||
# element in arrays with three or more elements (default: `", "`).
|
||||
# @param [String] last_word_connector The sign or word used to join the last element
|
||||
# in arrays with three or more elements (default: `" and "`).
|
||||
# @param [String] two_words_connector The sign or word used to join the elements
|
||||
# in arrays with two elements (default: `" and "`).
|
||||
sig { params(words_connector: String, two_words_connector: String, last_word_connector: String).returns(String) }
|
||||
def to_sentence(words_connector: ", ", two_words_connector: " and ", last_word_connector: " and ")
|
||||
case length
|
||||
|
@ -3,15 +3,20 @@
|
||||
|
||||
class Object
|
||||
# An object is blank if it's false, empty, or a whitespace string.
|
||||
# For example, +nil+, '', ' ', [], {}, and +false+ are all blank.
|
||||
#
|
||||
# This simplifies
|
||||
# For example, `nil`, `''`, `' '`, `[]`, `{}` and `false` are all blank.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# !address || address.empty?
|
||||
# ```
|
||||
#
|
||||
# to
|
||||
# can be simplified to
|
||||
#
|
||||
# ```ruby
|
||||
# address.blank?
|
||||
# ```
|
||||
sig { returns(T::Boolean) }
|
||||
def blank?
|
||||
respond_to?(:empty?) ? !!T.unsafe(self).empty? : false
|
||||
@ -21,20 +26,23 @@ class Object
|
||||
sig { returns(T::Boolean) }
|
||||
def present? = !blank?
|
||||
|
||||
# Returns the receiver if it's present otherwise returns +nil+.
|
||||
# <tt>object.presence</tt> is equivalent to
|
||||
# Returns the receiver if it's present, otherwise returns `nil`.
|
||||
#
|
||||
# object.present? ? object : nil
|
||||
# `object.presence` is equivalent to `object.present? ? object : nil`.
|
||||
#
|
||||
# For example, something like
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# state = params[:state] if params[:state].present?
|
||||
# country = params[:country] if params[:country].present?
|
||||
# region = state || country || 'US'
|
||||
# ```
|
||||
#
|
||||
# becomes
|
||||
# can be simplified to
|
||||
#
|
||||
# ```ruby
|
||||
# region = params[:state].presence || params[:country].presence || 'US'
|
||||
# ```
|
||||
sig { returns(T.nilable(T.self_type)) }
|
||||
def presence
|
||||
self if present?
|
||||
@ -42,9 +50,11 @@ class Object
|
||||
end
|
||||
|
||||
class NilClass
|
||||
# +nil+ is blank:
|
||||
# `nil` is blank:
|
||||
#
|
||||
# ```ruby
|
||||
# nil.blank? # => true
|
||||
# ```
|
||||
sig { returns(TrueClass) }
|
||||
def blank? = true
|
||||
|
||||
@ -53,9 +63,11 @@ class NilClass
|
||||
end
|
||||
|
||||
class FalseClass
|
||||
# +false+ is blank:
|
||||
# `false` is blank:
|
||||
#
|
||||
# ```ruby
|
||||
# false.blank? # => true
|
||||
# ```
|
||||
sig { returns(TrueClass) }
|
||||
def blank? = true
|
||||
|
||||
@ -64,9 +76,11 @@ class FalseClass
|
||||
end
|
||||
|
||||
class TrueClass
|
||||
# +true+ is not blank:
|
||||
# `true` is not blank:
|
||||
#
|
||||
# ```ruby
|
||||
# true.blank? # => false
|
||||
# ```
|
||||
sig { returns(FalseClass) }
|
||||
def blank? = false
|
||||
|
||||
@ -77,11 +91,12 @@ end
|
||||
class Array
|
||||
# An array is blank if it's empty:
|
||||
#
|
||||
# ```ruby
|
||||
# [].blank? # => true
|
||||
# [1,2,3].blank? # => false
|
||||
#
|
||||
# @return [true, false]
|
||||
alias blank? empty?
|
||||
# ```
|
||||
sig { returns(T::Boolean) }
|
||||
def blank? = empty?
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def present? = !empty? # :nodoc:
|
||||
@ -90,11 +105,13 @@ end
|
||||
class Hash
|
||||
# A hash is blank if it's empty:
|
||||
#
|
||||
#
|
||||
# ```ruby
|
||||
# {}.blank? # => true
|
||||
# { key: 'value' }.blank? # => false
|
||||
#
|
||||
# @return [true, false]
|
||||
alias blank? empty?
|
||||
# ```
|
||||
sig { returns(T::Boolean) }
|
||||
def blank? = empty?
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def present? = !empty? # :nodoc:
|
||||
@ -103,9 +120,12 @@ end
|
||||
class Symbol
|
||||
# A Symbol is blank if it's empty:
|
||||
#
|
||||
# ```ruby
|
||||
# :''.blank? # => true
|
||||
# :symbol.blank? # => false
|
||||
alias blank? empty?
|
||||
# ```
|
||||
sig { returns(T::Boolean) }
|
||||
def blank? = empty?
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def present? = !empty? # :nodoc:
|
||||
@ -122,14 +142,18 @@ class String
|
||||
|
||||
# A string is blank if it's empty or contains whitespaces only:
|
||||
#
|
||||
# ```ruby
|
||||
# ''.blank? # => true
|
||||
# ' '.blank? # => true
|
||||
# "\t\n\r".blank? # => true
|
||||
# ' blah '.blank? # => false
|
||||
# ```
|
||||
#
|
||||
# Unicode whitespace is supported:
|
||||
#
|
||||
# ```ruby
|
||||
# "\u00a0".blank? # => true
|
||||
# ```
|
||||
sig { returns(T::Boolean) }
|
||||
def blank?
|
||||
# The regexp that matches blank strings is expensive. For the case of empty
|
||||
@ -150,8 +174,10 @@ end
|
||||
class Numeric # :nodoc:
|
||||
# No number is blank:
|
||||
#
|
||||
# ```ruby
|
||||
# 1.blank? # => false
|
||||
# 0.blank? # => false
|
||||
# ```
|
||||
sig { returns(FalseClass) }
|
||||
def blank? = false
|
||||
|
||||
@ -162,7 +188,9 @@ end
|
||||
class Time # :nodoc:
|
||||
# No Time is blank:
|
||||
#
|
||||
# ```ruby
|
||||
# Time.now.blank? # => false
|
||||
# ```
|
||||
sig { returns(FalseClass) }
|
||||
def blank? = false
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Enumerable
|
||||
# The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
|
||||
# The negative of the {Enumerable#include?}. Returns `true` if the
|
||||
# collection does not include the object.
|
||||
sig { params(object: T.untyped).returns(T::Boolean) }
|
||||
def exclude?(object) = !include?(object)
|
||||
@ -10,21 +10,29 @@ module Enumerable
|
||||
# Returns a new +Array+ without the blank items.
|
||||
# Uses Object#blank? for determining if an item is blank.
|
||||
#
|
||||
# ### Examples
|
||||
#
|
||||
# ```
|
||||
# [1, "", nil, 2, " ", [], {}, false, true].compact_blank
|
||||
# # => [1, 2, true]
|
||||
# ```
|
||||
#
|
||||
# ```ruby
|
||||
# Set.new([nil, "", 1, false]).compact_blank
|
||||
# # => [1]
|
||||
# ```
|
||||
#
|
||||
# When called on a +Hash+, returns a new +Hash+ without the blank values.
|
||||
# When called on a {Hash}, returns a new {Hash} without the blank values.
|
||||
#
|
||||
# ```ruby
|
||||
# { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
|
||||
# # => { b: 1, f: true }
|
||||
# ```
|
||||
sig { returns(T.self_type) }
|
||||
def compact_blank = T.unsafe(self).reject(&:blank?)
|
||||
end
|
||||
|
||||
class Hash
|
||||
# Hash#reject has its own definition, so this needs one too.
|
||||
# {Hash#reject} has its own definition, so this needs one too.
|
||||
def compact_blank = reject { |_k, v| T.unsafe(v).blank? }
|
||||
end
|
||||
|
@ -2,25 +2,31 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Hash
|
||||
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
||||
# Returns a new hash with `self` and `other_hash` merged recursively.
|
||||
#
|
||||
# ### Examples
|
||||
#
|
||||
# ```ruby
|
||||
# h1 = { a: true, b: { c: [1, 2, 3] } }
|
||||
# h2 = { a: false, b: { x: [3, 4, 5] } }
|
||||
#
|
||||
# h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
|
||||
# ```
|
||||
#
|
||||
# Like with Hash#merge in the standard library, a block can be provided
|
||||
# to merge values:
|
||||
#
|
||||
# ```ruby
|
||||
# h1 = { a: 100, b: 200, c: { c1: 100 } }
|
||||
# h2 = { b: 250, c: { c1: 200 } }
|
||||
# h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
|
||||
# # => { a: 100, b: 450, c: { c1: 300 } }
|
||||
# ```
|
||||
def deep_merge(other_hash, &block)
|
||||
dup.deep_merge!(other_hash, &block)
|
||||
end
|
||||
|
||||
# Same as +deep_merge+, but modifies +self+.
|
||||
# Same as {#deep_merge}, but modifies `self`.
|
||||
def deep_merge!(other_hash, &block)
|
||||
merge!(other_hash) do |key, this_val, other_val|
|
||||
if T.unsafe(this_val).is_a?(Hash) && other_val.is_a?(Hash)
|
||||
|
@ -6,11 +6,14 @@ class Hash
|
||||
# This includes the values from the root hash and from all
|
||||
# nested hashes and arrays.
|
||||
#
|
||||
# @example
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# hash = { person: { name: 'Rob', age: '28' } }
|
||||
#
|
||||
# hash.deep_transform_values{ |value| value.to_s.upcase }
|
||||
# # => {person: {name: "ROB", age: "28"}}
|
||||
# ```
|
||||
def deep_transform_values(&block) = _deep_transform_values_in_object(self, &block)
|
||||
|
||||
# Destructively converts all values by using the block operation.
|
||||
|
@ -5,14 +5,18 @@ class Hash
|
||||
# Validates all keys in a hash match `*valid_keys`, raising
|
||||
# `ArgumentError` on a mismatch.
|
||||
#
|
||||
# Note that keys are treated differently than HashWithIndifferentAccess,
|
||||
# Note that keys are treated differently than `HashWithIndifferentAccess`,
|
||||
# meaning that string and symbol keys will not match.
|
||||
#
|
||||
# ### Example#
|
||||
#
|
||||
# ```ruby
|
||||
# { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age)
|
||||
# # => raises "ArgumentError: Unknown key: :years. Valid keys are: :name, :age"
|
||||
# { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age')
|
||||
# # => raises "ArgumentError: Unknown key: :name. Valid keys are: 'name', 'age'"
|
||||
# { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
|
||||
# ```
|
||||
sig { params(valid_keys: T.untyped).void }
|
||||
def assert_valid_keys(*valid_keys)
|
||||
valid_keys.flatten!
|
||||
@ -28,10 +32,14 @@ class Hash
|
||||
# This includes the keys from the root hash and from all
|
||||
# nested hashes and arrays.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# hash = { person: { name: 'Rob', age: '28' } }
|
||||
#
|
||||
# hash.deep_transform_keys{ |key| key.to_s.upcase }
|
||||
# # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
|
||||
# ```
|
||||
def deep_transform_keys(&block) = _deep_transform_keys_in_object(self, &block)
|
||||
|
||||
# Destructively converts all keys by using the block operation.
|
||||
@ -43,10 +51,14 @@ class Hash
|
||||
# This includes the keys from the root hash and from all
|
||||
# nested hashes and arrays.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# hash = { person: { name: 'Rob', age: '28' } }
|
||||
#
|
||||
# hash.deep_stringify_keys
|
||||
# # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
|
||||
# ```
|
||||
def deep_stringify_keys = T.unsafe(self).deep_transform_keys(&:to_s)
|
||||
|
||||
# Destructively converts all keys to strings.
|
||||
@ -55,13 +67,17 @@ class Hash
|
||||
def deep_stringify_keys! = T.unsafe(self).deep_transform_keys!(&:to_s)
|
||||
|
||||
# Returns a new hash with all keys converted to symbols, as long as
|
||||
# they respond to +to_sym+. This includes the keys from the root hash
|
||||
# they respond to `to_sym`. This includes the keys from the root hash
|
||||
# and from all nested hashes and arrays.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
|
||||
#
|
||||
# hash.deep_symbolize_keys
|
||||
# # => {:person=>{:name=>"Rob", :age=>"28"}}
|
||||
# ```
|
||||
def deep_symbolize_keys
|
||||
deep_transform_keys do |key|
|
||||
T.unsafe(key).to_sym
|
||||
@ -71,7 +87,7 @@ class Hash
|
||||
end
|
||||
|
||||
# Destructively converts all keys to symbols, as long as they respond
|
||||
# to +to_sym+. This includes the keys from the root hash and from all
|
||||
# to `to_sym`. This includes the keys from the root hash and from all
|
||||
# nested hashes and arrays.
|
||||
def deep_symbolize_keys!
|
||||
deep_transform_keys! do |key|
|
||||
@ -102,7 +118,7 @@ class Hash
|
||||
def _deep_transform_keys_in_object!(object, &block)
|
||||
case object
|
||||
when Hash
|
||||
# We can't use `each_key` here because we're updating the hash in-place
|
||||
# We can't use `each_key` here because we're updating the hash in-place.
|
||||
object.keys.each do |key| # rubocop:disable Style/HashEachMethods
|
||||
value = object.delete(key)
|
||||
object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
|
||||
|
@ -493,14 +493,20 @@ module Kernel
|
||||
end
|
||||
|
||||
# Calls the given block with the passed environment variables
|
||||
# added to ENV, then restores ENV afterwards.
|
||||
# <pre>with_env(PATH: "/bin") do
|
||||
# system "echo $PATH"
|
||||
# end</pre>
|
||||
# added to `ENV`, then restores `ENV` afterwards.
|
||||
#
|
||||
# @note This method is *not* thread-safe - other threads
|
||||
# NOTE: This method is **not** thread-safe – other threads
|
||||
# which happen to be scheduled during the block will also
|
||||
# see these environment variables.
|
||||
#
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# with_env(PATH: "/bin") do
|
||||
# system "echo $PATH"
|
||||
# end
|
||||
# ```
|
||||
#
|
||||
# @api public
|
||||
def with_env(hash)
|
||||
old_values = {}
|
||||
|
@ -1,24 +1,30 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
#--
|
||||
# Most objects are cloneable, but not all. For example you can't dup methods:
|
||||
#
|
||||
# ```ruby
|
||||
# method(:puts).dup # => TypeError: allocator undefined for Method
|
||||
# ```
|
||||
#
|
||||
# Classes may signal their instances are not duplicable removing +dup+/+clone+
|
||||
# or raising exceptions from them. So, to dup an arbitrary object you normally
|
||||
# use an optimistic approach and are ready to catch an exception, say:
|
||||
#
|
||||
# ```ruby
|
||||
# arbitrary_object.dup rescue object
|
||||
# ```
|
||||
#
|
||||
# Rails dups objects in a few critical spots where they are not that arbitrary.
|
||||
# That rescue is very expensive (like 40 times slower than a predicate), and it
|
||||
# That `rescue` is very expensive (like 40 times slower than a predicate) and it
|
||||
# is often triggered.
|
||||
#
|
||||
# That's why we hardcode the following cases and check duplicable? instead of
|
||||
# using that rescue idiom.
|
||||
#++
|
||||
# rubocop:disable Layout/EmptyLines
|
||||
|
||||
|
||||
# rubocop:enable Layout/EmptyLines
|
||||
class Object
|
||||
# Can you safely dup this object?
|
||||
#
|
||||
@ -31,8 +37,10 @@ end
|
||||
class Method
|
||||
# Methods are not duplicable:
|
||||
#
|
||||
# ```ruby
|
||||
# method(:puts).duplicable? # => false
|
||||
# method(:puts).dup # => TypeError: allocator undefined for Method
|
||||
# ```
|
||||
sig { returns(FalseClass) }
|
||||
def duplicable? = false
|
||||
end
|
||||
@ -40,8 +48,10 @@ end
|
||||
class UnboundMethod
|
||||
# Unbound methods are not duplicable:
|
||||
#
|
||||
# ```ruby
|
||||
# method(:puts).unbind.duplicable? # => false
|
||||
# method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
|
||||
# ```
|
||||
sig { returns(FalseClass) }
|
||||
def duplicable? = false
|
||||
end
|
||||
@ -51,7 +61,9 @@ require "singleton"
|
||||
module Singleton
|
||||
# Singleton instances are not duplicable:
|
||||
#
|
||||
# ```ruby
|
||||
# Class.new.include(Singleton).instance.dup # TypeError (can't dup instance of singleton
|
||||
# ```
|
||||
sig { returns(FalseClass) }
|
||||
def duplicable? = false
|
||||
end
|
||||
|
@ -27,12 +27,11 @@ module Stdenv
|
||||
|
||||
append "LDFLAGS", "-Wl,-headerpad_max_install_names"
|
||||
|
||||
# sed is strict, and errors out when it encounters files with
|
||||
# mixed character sets
|
||||
# `sed` is strict and errors out when it encounters files with mixed character sets.
|
||||
delete("LC_ALL")
|
||||
self["LC_CTYPE"] = "C"
|
||||
|
||||
# Add lib and include etc. from the current macosxsdk to compiler flags:
|
||||
# Add `lib` and `include` etc. from the current `macosxsdk` to compiler flags:
|
||||
macosxsdk(formula: @formula, testing_formula:)
|
||||
|
||||
return unless MacOS::Xcode.without_clt?
|
||||
@ -42,8 +41,8 @@ module Stdenv
|
||||
end
|
||||
|
||||
def remove_macosxsdk(version = nil)
|
||||
# Clear all lib and include dirs from CFLAGS, CPPFLAGS, LDFLAGS that were
|
||||
# previously added by macosxsdk
|
||||
# Clear all `lib` and `include` dirs from `CFLAGS`, `CPPFLAGS`, `LDFLAGS` that were
|
||||
# previously added by `macosxsdk`.
|
||||
remove_from_cflags(/ ?-mmacosx-version-min=\d+\.\d+/)
|
||||
delete("CPATH")
|
||||
remove "LDFLAGS", "-L#{HOMEBREW_PREFIX}/lib"
|
||||
@ -58,14 +57,14 @@ module Stdenv
|
||||
if HOMEBREW_PREFIX.to_s == "/usr/local"
|
||||
delete("CMAKE_PREFIX_PATH")
|
||||
else
|
||||
# It was set in setup_build_environment, so we have to restore it here.
|
||||
# It was set in `setup_build_environment`, so we have to restore it here.
|
||||
self["CMAKE_PREFIX_PATH"] = HOMEBREW_PREFIX.to_s
|
||||
end
|
||||
remove "CMAKE_FRAMEWORK_PATH", "#{sdk}/System/Library/Frameworks"
|
||||
end
|
||||
|
||||
def macosxsdk(version = nil, formula: nil, testing_formula: false)
|
||||
# Sets all needed lib and include dirs to CFLAGS, CPPFLAGS, LDFLAGS.
|
||||
# Sets all needed `lib` and `include` dirs to `CFLAGS`, `CPPFLAGS`, `LDFLAGS`.
|
||||
remove_macosxsdk
|
||||
min_version = version || MacOS.version
|
||||
append_to_cflags("-mmacosx-version-min=#{min_version}")
|
||||
|
@ -83,8 +83,8 @@ module Hardware
|
||||
sysctl_bool("hw.optional.sse4_2")
|
||||
end
|
||||
|
||||
# NOTE: this is more reliable than checking uname.
|
||||
# `sysctl` returns the right answer even when running in Rosetta 2.
|
||||
# NOTE: This is more reliable than checking `uname`. `sysctl` returns
|
||||
# the right answer even when running in Rosetta 2.
|
||||
def physical_cpu_arm64?
|
||||
sysctl_bool("hw.optional.arm64")
|
||||
end
|
||||
|
@ -126,10 +126,11 @@ class Pathname
|
||||
|
||||
mkpath
|
||||
|
||||
# Use FileUtils.mv over File.rename to handle filesystem boundaries. If src
|
||||
# is a symlink, and its target is moved first, FileUtils.mv will fail:
|
||||
# https://bugs.ruby-lang.org/issues/7707
|
||||
# In that case, use the system "mv" command.
|
||||
# Use `FileUtils.mv` over `File.rename` to handle filesystem boundaries. If `src`
|
||||
# is a symlink and its target is moved first, `FileUtils.mv` will fail
|
||||
# (https://bugs.ruby-lang.org/issues/7707).
|
||||
#
|
||||
# In that case, use the system `mv` command.
|
||||
if src.symlink?
|
||||
raise unless Kernel.system "mv", src.to_s, dst
|
||||
else
|
||||
@ -178,7 +179,9 @@ class Pathname
|
||||
T.unsafe(self).open("a", **open_args) { |f| f.puts(content) }
|
||||
end
|
||||
|
||||
# @note This always overwrites.
|
||||
# Write to a file atomically.
|
||||
#
|
||||
# NOTE: This always overwrites.
|
||||
#
|
||||
# @api public
|
||||
sig { params(content: String).void }
|
||||
@ -201,6 +204,7 @@ class Pathname
|
||||
# Changing file ownership failed, moving on.
|
||||
nil
|
||||
end
|
||||
|
||||
begin
|
||||
# This operation will affect filesystem ACL's
|
||||
chmod(old_stat.mode)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,6 @@ class KegOnlyReason
|
||||
!by_macos?
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
return @explanation unless @explanation.empty?
|
||||
|
@ -25,7 +25,6 @@ module Homebrew
|
||||
@text.include? string
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
@text
|
||||
|
@ -106,7 +106,6 @@ class GitRepository
|
||||
popen_git("log", "-1", "--pretty=%B", commit, "--", safe:, err: :out)&.strip
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s = pathname.to_s
|
||||
|
||||
|
@ -48,7 +48,6 @@ class Keg
|
||||
EOS
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
s = []
|
||||
@ -67,7 +66,6 @@ class Keg
|
||||
|
||||
# Error for when a directory is not writable.
|
||||
class DirectoryNotWritableError < LinkError
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
<<~EOS
|
||||
@ -176,11 +174,9 @@ class Keg
|
||||
path.parent
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s = path.to_s
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}:#{path}>"
|
||||
|
@ -14,7 +14,7 @@ module Language
|
||||
# e.g. `resource "github.com/foo/bar"`.
|
||||
sig { params(resources: T::Array[Resource], target: T.any(String, Pathname)).void }
|
||||
def self.stage_deps(resources, target)
|
||||
# odeprecated "Language::Go::stage_deps", "Go modules"
|
||||
# odeprecated "`Language::Go.stage_deps`", "Go modules"
|
||||
if resources.empty?
|
||||
if Homebrew::EnvConfig.developer?
|
||||
odie "Tried to stage empty Language::Go resources array"
|
||||
|
@ -150,8 +150,8 @@ module Language
|
||||
#
|
||||
# @param venv_root [Pathname, String] the path to the root of the virtualenv
|
||||
# (often `libexec/"venv"`)
|
||||
# @param python [String, Pathname] which interpreter to use (e.g. "python3"
|
||||
# or "python3.x")
|
||||
# @param python [String, Pathname] which interpreter to use (e.g. `"python3"`
|
||||
# or `"python3.x"`)
|
||||
# @param formula [Formula] the active {Formula}
|
||||
# @return [Virtualenv] a {Virtualenv} instance
|
||||
sig {
|
||||
@ -166,7 +166,7 @@ module Language
|
||||
def virtualenv_create(venv_root, python = "python", formula = T.cast(self, Formula),
|
||||
system_site_packages: true, without_pip: true)
|
||||
# Limit deprecation to 3.12+ for now (or if we can't determine the version).
|
||||
# Some used this argument for setuptools, which we no longer bundle since 3.12.
|
||||
# Some used this argument for `setuptools`, which we no longer bundle since 3.12.
|
||||
unless without_pip
|
||||
python_version = Language::Python.major_minor_version(python)
|
||||
if python_version.nil? || python_version.null? || python_version >= "3.12"
|
||||
@ -198,8 +198,8 @@ module Language
|
||||
|
||||
# Returns true if a formula option for the specified python is currently
|
||||
# active or if the specified python is required by the formula. Valid
|
||||
# inputs are "python", "python2", and :python3. Note that
|
||||
# "with-python", "without-python", "with-python@2", and "without-python@2"
|
||||
# inputs are `"python"`, `"python2"` and `:python3`. Note that
|
||||
# `"with-python"`, `"without-python"`, `"with-python@2"` and `"without-python@2"`
|
||||
# formula options are handled correctly even if not associated with any
|
||||
# corresponding depends_on statement.
|
||||
sig { params(python: String).returns(T::Boolean) }
|
||||
|
@ -16,15 +16,20 @@ class LazyObject < Delegator
|
||||
@__delegate__ = @__callable__.call
|
||||
# rubocop:enable Naming/MemoizedInstanceVariableName
|
||||
end
|
||||
private :__getobj__
|
||||
|
||||
def __setobj__(callable)
|
||||
@__callable__ = callable
|
||||
end
|
||||
private :__setobj__
|
||||
|
||||
# Forward to the inner object to make lazy objects type-checkable.
|
||||
#
|
||||
# @!visibility private
|
||||
def is_a?(klass)
|
||||
# see https://sorbet.org/docs/faq#how-can-i-fix-type-errors-that-arise-from-super
|
||||
T.bind(self, T.untyped)
|
||||
|
||||
__getobj__.is_a?(klass) || super
|
||||
end
|
||||
end
|
||||
|
@ -39,9 +39,11 @@ module Homebrew
|
||||
) do
|
||||
extend Forwardable
|
||||
|
||||
# @!attribute [r] version
|
||||
# @api public
|
||||
delegate version: :bundle_version
|
||||
|
||||
# @!attribute [r] short_version
|
||||
# @api public
|
||||
delegate short_version: :bundle_version
|
||||
end
|
||||
|
@ -54,12 +54,15 @@ module Homebrew
|
||||
) do
|
||||
extend Forwardable
|
||||
|
||||
# @!attribute [r] version
|
||||
# @api public
|
||||
delegate version: :bundle_version
|
||||
|
||||
# @!attribute [r] short_version
|
||||
# @api public
|
||||
delegate short_version: :bundle_version
|
||||
|
||||
# @!attribute [r] nice_version
|
||||
# @api public
|
||||
delegate nice_version: :bundle_version
|
||||
end
|
||||
|
@ -106,7 +106,6 @@ class Locale
|
||||
locale_groups.find { |locales| locales.any? { |locale| include?(locale) } }
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
[@language, @script, @region].compact.join("-")
|
||||
|
@ -132,6 +132,7 @@ class MacOSVersion < Version
|
||||
alias requires_popcnt? requires_nehalem_cpu?
|
||||
|
||||
# Represents the absence of a version.
|
||||
#
|
||||
# NOTE: Constructor needs to called with an arbitrary macOS-like version which is then set to `nil`.
|
||||
NULL = MacOSVersion.new("10.0").tap { |v| v.instance_variable_set(:@version, nil) }.freeze
|
||||
end
|
||||
@ -141,7 +142,7 @@ require "lazy_object"
|
||||
module MacOSVersionErrorCompat
|
||||
def const_missing(name)
|
||||
if name == :MacOSVersionError
|
||||
odisabled "MacOSVersionError", "MacOSVersion::Error"
|
||||
odisabled "`MacOSVersionError`", "`MacOSVersion::Error`"
|
||||
return MacOSVersion::Error
|
||||
end
|
||||
|
||||
@ -158,7 +159,7 @@ end
|
||||
|
||||
module MacOSVersions
|
||||
SYMBOLS = LazyObject.new do # rubocop:disable Style/MutableConstant
|
||||
odisabled "MacOSVersions::SYMBOLS", "MacOSVersion::SYMBOLS"
|
||||
odisabled "`MacOSVersions::SYMBOLS`", "`MacOSVersion::SYMBOLS`"
|
||||
MacOSVersion::SYMBOLS
|
||||
end
|
||||
end
|
||||
@ -167,7 +168,7 @@ module OS
|
||||
module Mac
|
||||
# TODO: Replace `::Version` with `Version` when this is removed.
|
||||
Version = LazyObject.new do # rubocop:disable Style/MutableConstant
|
||||
odisabled "OS::Mac::Version", "MacOSVersion"
|
||||
odisabled "`OS::Mac::Version`", "`MacOSVersion`"
|
||||
MacOSVersion
|
||||
end
|
||||
end
|
||||
|
@ -287,17 +287,18 @@ class Migrator
|
||||
def repin
|
||||
return unless pinned?
|
||||
|
||||
# old_pin_record is a relative symlink and when we try to to read it
|
||||
# `old_pin_record` is a relative symlink and when we try to to read it
|
||||
# from <dir> we actually try to find file
|
||||
# <dir>/../<...>/../Cellar/name/version.
|
||||
# To repin formula we need to update the link thus that it points to
|
||||
# the right directory.
|
||||
# NOTE: old_pin_record.realpath.sub(oldname, newname) is unacceptable
|
||||
# here, because it resolves every symlink for old_pin_record and then
|
||||
#
|
||||
# NOTE: `old_pin_record.realpath.sub(oldname, newname)` is unacceptable
|
||||
# here, because it resolves every symlink for `old_pin_record` and then
|
||||
# substitutes oldname with newname. It breaks things like
|
||||
# Pathname#make_relative_symlink, where Pathname#relative_path_from
|
||||
# is used to find relative path from source to destination parent and
|
||||
# it assumes no symlinks.
|
||||
# `Pathname#make_relative_symlink`, where `Pathname#relative_path_from`
|
||||
# is used to find the relative path from source to destination parent
|
||||
# and it assumes no symlinks.
|
||||
src_oldname = (old_pin_record.dirname/old_pin_link_record).expand_path
|
||||
new_pin_record.make_relative_symlink(src_oldname.sub(oldname, newname))
|
||||
old_pin_record.delete
|
||||
|
@ -38,7 +38,6 @@ class Mktemp
|
||||
@quiet = true
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"[Mktemp: #{tmpdir} retain=#{@retain} quiet=#{@quiet}]"
|
||||
|
@ -11,7 +11,6 @@ class Option
|
||||
@description = description
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s = flag
|
||||
|
||||
@ -30,7 +29,6 @@ class Option
|
||||
name.hash
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{flag.inspect}>"
|
||||
@ -134,13 +132,11 @@ class Options
|
||||
|
||||
alias to_ary to_a
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
@options.map(&:to_s).join(" ")
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{to_a.inspect}>"
|
||||
|
@ -51,7 +51,6 @@ class EmbeddedPatch
|
||||
Utils.safe_popen_write("patch", *args) { |p| p.write(data) }
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{strip.inspect}>"
|
||||
@ -151,7 +150,6 @@ class ExternalPatch
|
||||
raise BuildError.new(f, cmd, args, ENV.to_hash)
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{strip.inspect} #{url.inspect}>"
|
||||
|
@ -39,7 +39,6 @@ class PkgVersion
|
||||
end
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s = to_str
|
||||
|
||||
|
@ -140,7 +140,6 @@ class Requirement
|
||||
[self.class, name, tags].hash
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{tags.inspect}>"
|
||||
|
@ -27,7 +27,6 @@ class ArchRequirement < Requirement
|
||||
"The #{@arch} architecture is required for this software."
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: arch=#{@arch.to_s.inspect} #{tags.inspect}>"
|
||||
|
@ -96,7 +96,6 @@ class MacOSRequirement < Requirement
|
||||
[super, comparator, version].hash
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: version#{@comparator}#{@version.to_s.inspect} #{tags.inspect}>"
|
||||
|
@ -48,7 +48,6 @@ class XcodeRequirement < Requirement
|
||||
end
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: version>=#{@version.inspect} #{tags.inspect}>"
|
||||
|
@ -146,17 +146,22 @@ class Resource < Downloadable
|
||||
super(verify_download_integrity:)
|
||||
end
|
||||
|
||||
# @!attribute [w] livecheck
|
||||
# {Livecheck} can be used to check for newer versions of the software.
|
||||
# This method evaluates the DSL specified in the livecheck block of the
|
||||
# {Resource} (if it exists) and sets the instance variables of a {Livecheck}
|
||||
# object accordingly. This is used by `brew livecheck` to check for newer
|
||||
# versions of the software.
|
||||
#
|
||||
# <pre>livecheck do
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# livecheck do
|
||||
# url "https://example.com/foo/releases"
|
||||
# regex /foo-(\d+(?:\.\d+)+)\.tar/
|
||||
# end</pre>
|
||||
# end
|
||||
# ```
|
||||
#
|
||||
# @!attribute [w] livecheck
|
||||
def livecheck(&block)
|
||||
return @livecheck unless block
|
||||
|
||||
@ -302,7 +307,6 @@ class ResourceStageContext
|
||||
@staging = staging
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"<#{self.class}: resource=#{resource} staging=#{staging}>"
|
||||
|
@ -4,27 +4,26 @@
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Homebrew
|
||||
# Checks for code that can be written with simpler conditionals
|
||||
# using `Object#blank?`.
|
||||
# Checks for code that can be simplified using `Object#blank?`.
|
||||
#
|
||||
# @note
|
||||
# This cop is unsafe autocorrection, because `' '.empty?` returns false,
|
||||
# but `' '.blank?` returns true. Therefore, autocorrection is not compatible
|
||||
# if the receiver is a non-empty blank string, tab, or newline meta characters.
|
||||
# NOTE: Auto-correction for this cop is unsafe because `' '.empty?` returns `false`,
|
||||
# but `' '.blank?` returns `true`. Therefore, auto-correction is not compatible
|
||||
# if the receiver is a non-empty blank string.
|
||||
#
|
||||
# @example
|
||||
# # Converts usages of `nil? || empty?` to `blank?`
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# # bad
|
||||
# foo.nil? || foo.empty?
|
||||
# foo == nil || foo.empty?
|
||||
#
|
||||
# # good
|
||||
# foo.blank?
|
||||
# ```
|
||||
class Blank < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG_NIL_OR_EMPTY = "Use `%<prefer>s` instead of `%<current>s`."
|
||||
MSG = "Use `%<prefer>s` instead of `%<current>s`."
|
||||
|
||||
# `(send nil $_)` is not actually a valid match for an offense. Nodes
|
||||
# that have a single method call on the left hand side
|
||||
@ -49,7 +48,7 @@ module RuboCop
|
||||
nil_or_empty?(node) do |var1, var2|
|
||||
return if var1 != var2
|
||||
|
||||
message = format(MSG_NIL_OR_EMPTY, prefer: replacement(var1), current: node.source)
|
||||
message = format(MSG, prefer: replacement(var1), current: node.source)
|
||||
add_offense(node, message:) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
|
@ -9,7 +9,9 @@ module RuboCop
|
||||
module Cask
|
||||
# This cop makes sure that OS conditionals are consistent.
|
||||
#
|
||||
# @example
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# # bad
|
||||
# cask 'foo' do
|
||||
# if MacOS.version == :high_sierra
|
||||
@ -23,6 +25,7 @@ module RuboCop
|
||||
# sha256 "..."
|
||||
# end
|
||||
# end
|
||||
# ```
|
||||
class OnSystemConditionals < Base
|
||||
extend Forwardable
|
||||
extend AutoCorrector
|
||||
|
@ -6,16 +6,17 @@ module RuboCop
|
||||
module Cask
|
||||
# This cop checks that a cask's `url` stanza is formatted correctly.
|
||||
#
|
||||
# @example
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# # bad
|
||||
# url "https://example.com/download/foo.dmg",
|
||||
# verified: "https://example.com/download"
|
||||
#
|
||||
#
|
||||
# # good
|
||||
# url "https://example.com/download/foo.dmg",
|
||||
# verified: "example.com/download/"
|
||||
#
|
||||
# ```
|
||||
class Url < Base
|
||||
extend AutoCorrector
|
||||
extend Forwardable
|
||||
|
@ -8,7 +8,9 @@ module RuboCop
|
||||
module Cask
|
||||
# This cop audits variables in casks.
|
||||
#
|
||||
# @example
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# # bad
|
||||
# cask do
|
||||
# arch = Hardware::CPU.intel? ? "darwin" : "darwin-arm64"
|
||||
@ -18,6 +20,7 @@ module RuboCop
|
||||
# cask 'foo' do
|
||||
# arch arm: "darwin-arm64", intel: "darwin"
|
||||
# end
|
||||
# ```
|
||||
class Variables < Base
|
||||
extend Forwardable
|
||||
extend AutoCorrector
|
||||
|
@ -6,9 +6,11 @@ require "rubocops/extend/formula_cop"
|
||||
module RuboCop
|
||||
module Cop
|
||||
module FormulaAudit
|
||||
# This cop makes sure that caveats don't recommend unsupported or unsafe operations.
|
||||
# This cop ensures that caveats don't recommend unsupported or unsafe operations.
|
||||
#
|
||||
# @example
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# # bad
|
||||
# def caveats
|
||||
# <<~EOS
|
||||
@ -22,11 +24,12 @@ module RuboCop
|
||||
# Use `sudo` to run the executable.
|
||||
# EOS
|
||||
# end
|
||||
# ```
|
||||
class Caveats < FormulaCop
|
||||
def audit_formula(_node, _class_node, _parent_class_node, _body_node)
|
||||
caveats_strings.each do |n|
|
||||
if regex_match_group(n, /\bsetuid\b/i)
|
||||
problem "Don't recommend setuid in the caveats, suggest sudo instead."
|
||||
problem "Don't recommend `setuid` in the caveats, suggest `sudo` instead."
|
||||
end
|
||||
|
||||
problem "Don't use ANSI escape codes in the caveats." if regex_match_group(n, /\e/)
|
||||
|
@ -6,8 +6,7 @@ module RuboCop
|
||||
module Homebrew
|
||||
# Checks if collection can be blank-compacted with `compact_blank`.
|
||||
#
|
||||
# @note
|
||||
# It is unsafe by default because false positives may occur in the
|
||||
# NOTE: It is unsafe by default because false positives may occur in the
|
||||
# blank check of block arguments to the receiver object.
|
||||
#
|
||||
# For example, `[[1, 2], [3, nil]].reject { |first, second| second.blank? }` and
|
||||
@ -20,15 +19,18 @@ module RuboCop
|
||||
# `ActionController::Parameters#compact_blank!` is equivalent to `reject!(&:blank?)`.
|
||||
# If the cop makes a mistake, autocorrected code may get unexpected behavior.
|
||||
#
|
||||
# @example
|
||||
# ### Examples
|
||||
#
|
||||
# ```ruby
|
||||
# # bad
|
||||
# collection.reject(&:blank?)
|
||||
# collection.reject { |_k, v| v.blank? }
|
||||
#
|
||||
# # good
|
||||
# collection.compact_blank
|
||||
# ```
|
||||
#
|
||||
# ```ruby
|
||||
# # bad
|
||||
# collection.delete_if(&:blank?) # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
|
||||
# collection.delete_if { |_, v| v.blank? } # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
|
||||
@ -37,12 +39,13 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# collection.compact_blank!
|
||||
#
|
||||
# ```
|
||||
class CompactBlank < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = "Use `%<preferred_method>s` instead."
|
||||
|
||||
RESTRICT_ON_SEND = [:reject, :delete_if, :reject!].freeze
|
||||
|
||||
def_node_matcher :reject_with_block?, <<~PATTERN
|
||||
|
@ -70,7 +70,7 @@ module RuboCop
|
||||
# Compact the above into this list as we're able to remove detailed notations, etc over time.
|
||||
when
|
||||
# Check for http:// GitHub homepage URLs, https:// is preferred.
|
||||
# Note: only check homepages that are repo pages, not *.github.com hosts
|
||||
# NOTE: Only check homepages that are repo pages, not *.github.com hosts.
|
||||
%r{^http://github\.com/},
|
||||
%r{^http://[^/]*\.github\.io/},
|
||||
|
||||
|
@ -4,9 +4,10 @@
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Homebrew
|
||||
# This cop restricts usage of IO.read functions for security reasons.
|
||||
# This cop restricts usage of `IO.read` functions for security reasons.
|
||||
class IORead < Base
|
||||
MSG = "The use of `IO.%<method>s` is a security risk."
|
||||
|
||||
RESTRICT_ON_SEND = [:read, :readlines].freeze
|
||||
|
||||
def on_send(node)
|
||||
|
@ -7,11 +7,12 @@ module RuboCop
|
||||
# Enforces the use of `collection.exclude?(obj)`
|
||||
# over `!collection.include?(obj)`.
|
||||
#
|
||||
# @note
|
||||
# This cop is unsafe because false positive will occur for
|
||||
# receiver objects that do not have an `exclude?` method. (e.g. `IPAddr`)
|
||||
# NOTE: This cop is unsafe because false positives will occur for
|
||||
# receiver objects that do not have an `#exclude?` method (e.g. `IPAddr`).
|
||||
#
|
||||
# @example
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# # bad
|
||||
# !array.include?(2)
|
||||
# !hash.include?(:key)
|
||||
@ -19,11 +20,12 @@ module RuboCop
|
||||
# # good
|
||||
# array.exclude?(2)
|
||||
# hash.exclude?(:key)
|
||||
#
|
||||
# ```
|
||||
class NegateInclude < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG = "Use `.exclude?` and remove the negation part."
|
||||
|
||||
RESTRICT_ON_SEND = [:!].freeze
|
||||
|
||||
def_node_matcher :negate_include_call?, <<~PATTERN
|
||||
|
@ -7,7 +7,9 @@ module RuboCop
|
||||
# Checks code that can be written more easily using
|
||||
# `Object#presence` defined by Active Support.
|
||||
#
|
||||
# @example
|
||||
# ### Examples
|
||||
#
|
||||
# ```ruby
|
||||
# # bad
|
||||
# a.present? ? a : nil
|
||||
#
|
||||
@ -22,8 +24,9 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# a.presence
|
||||
# ```
|
||||
#
|
||||
# @example
|
||||
# ```ruby
|
||||
# # bad
|
||||
# a.present? ? a : b
|
||||
#
|
||||
@ -38,6 +41,7 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# a.presence || b
|
||||
# ```
|
||||
class Presence < Base
|
||||
include RangeHelp
|
||||
extend AutoCorrector
|
||||
|
@ -4,12 +4,11 @@
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Homebrew
|
||||
# Checks for code that can be written with simpler conditionals
|
||||
# using `Object#present?`.
|
||||
# Checks for code that can be simplified using `Object#present?`.
|
||||
#
|
||||
# @example
|
||||
# # Converts usages of `!nil? && !empty?` to `present?`
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# # bad
|
||||
# !foo.nil? && !foo.empty?
|
||||
#
|
||||
@ -18,10 +17,11 @@ module RuboCop
|
||||
#
|
||||
# # good
|
||||
# foo.present?
|
||||
# ```
|
||||
class Present < Base
|
||||
extend AutoCorrector
|
||||
|
||||
MSG_EXISTS_AND_NOT_EMPTY = "Use `%<prefer>s` instead of `%<current>s`."
|
||||
MSG = "Use `%<prefer>s` instead of `%<current>s`."
|
||||
|
||||
def_node_matcher :exists_and_not_empty?, <<~PATTERN
|
||||
(and
|
||||
@ -41,7 +41,7 @@ module RuboCop
|
||||
exists_and_not_empty?(node) do |var1, var2|
|
||||
return if var1 != var2
|
||||
|
||||
message = format(MSG_EXISTS_AND_NOT_EMPTY, prefer: replacement(var1), current: node.source)
|
||||
message = format(MSG, prefer: replacement(var1), current: node.source)
|
||||
|
||||
add_offense(node, message:) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
@ -53,7 +53,7 @@ module RuboCop
|
||||
exists_and_not_empty?(node) do |var1, var2|
|
||||
return if var1 != var2
|
||||
|
||||
add_offense(node, message: MSG_EXISTS_AND_NOT_EMPTY) do |corrector|
|
||||
add_offense(node, message: MSG) do |corrector|
|
||||
autocorrect(corrector, node)
|
||||
end
|
||||
end
|
||||
|
@ -7,20 +7,18 @@ module RuboCop
|
||||
# Checks to make sure safe navigation isn't used with `blank?` in
|
||||
# a conditional.
|
||||
#
|
||||
# @note
|
||||
# While the safe navigation operator is generally a good idea, when
|
||||
# NOTE: While the safe navigation operator is generally a good idea, when
|
||||
# checking `foo&.blank?` in a conditional, `foo` being `nil` will actually
|
||||
# do the opposite of what the author intends.
|
||||
# do the opposite of what the author intends:
|
||||
#
|
||||
# For example:
|
||||
#
|
||||
# [source,ruby]
|
||||
# ----
|
||||
# ```ruby
|
||||
# foo&.blank? #=> nil
|
||||
# foo.blank? #=> true
|
||||
# ----
|
||||
# ```
|
||||
#
|
||||
# @example
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# # bad
|
||||
# do_something if foo&.blank?
|
||||
# do_something unless foo&.blank?
|
||||
@ -28,7 +26,7 @@ module RuboCop
|
||||
# # good
|
||||
# do_something if foo.blank?
|
||||
# do_something unless foo.blank?
|
||||
#
|
||||
# ```
|
||||
class SafeNavigationWithBlank < Base
|
||||
extend AutoCorrector
|
||||
|
||||
|
@ -174,10 +174,19 @@ module RuboCop
|
||||
|
||||
# Matches a method with a receiver. Yields to a block with matching method node.
|
||||
#
|
||||
# @example to match `Formula.factory(name)`
|
||||
# ### Examples
|
||||
#
|
||||
# Match `Formula.factory(name)`.
|
||||
#
|
||||
# ```ruby
|
||||
# find_instance_method_call(node, "Formula", :factory)
|
||||
# @example to match `build.head?`
|
||||
# ```
|
||||
#
|
||||
# Match `build.head?`.
|
||||
#
|
||||
# ```ruby
|
||||
# find_instance_method_call(node, :build, :head?)
|
||||
# ```
|
||||
def find_instance_method_call(node, instance, method_name)
|
||||
methods = find_every_method_call_by_name(node, method_name)
|
||||
methods.each do |method|
|
||||
@ -194,8 +203,13 @@ module RuboCop
|
||||
|
||||
# Matches receiver part of method. Yields to a block with parent node of receiver.
|
||||
#
|
||||
# @example to match `ARGV.<whatever>()`
|
||||
# ### Example
|
||||
#
|
||||
# Match `ARGV.<whatever>()`.
|
||||
#
|
||||
# ```ruby
|
||||
# find_instance_call(node, "ARGV")
|
||||
# ```
|
||||
def find_instance_call(node, name)
|
||||
node.each_descendant(:send) do |method_node|
|
||||
next if method_node.receiver.nil?
|
||||
|
@ -40,9 +40,11 @@ module RuboCop
|
||||
until
|
||||
while
|
||||
].freeze
|
||||
private_constant :SHELL_BUILTINS
|
||||
|
||||
# https://github.com/ruby/ruby/blob/v2_6_3/process.c#L2495
|
||||
SHELL_METACHARACTERS = %W[* ? { } [ ] < > ( ) ~ & | \\ $ ; ' ` " \n #].freeze
|
||||
private_constant :SHELL_METACHARACTERS
|
||||
|
||||
# This cop makes sure that shell command arguments are separated.
|
||||
class ShellCommands < Base
|
||||
@ -60,6 +62,8 @@ module RuboCop
|
||||
[:Utils, :popen_write],
|
||||
[:Utils, :safe_popen_write],
|
||||
].freeze
|
||||
private_constant :TARGET_METHODS
|
||||
|
||||
RESTRICT_ON_SEND = TARGET_METHODS.map(&:second).uniq.freeze
|
||||
|
||||
def on_send(node)
|
||||
|
@ -207,7 +207,7 @@ module RuboCop
|
||||
problem "Use versioned rather than branch tarballs for stable checksums."
|
||||
end
|
||||
|
||||
# Use new-style archive downloads
|
||||
# Use new-style archive downloads.
|
||||
archive_gh_pattern = %r{https://.*github.*/(?:tar|zip)ball/}
|
||||
audit_urls(urls, archive_gh_pattern) do |_, url|
|
||||
next if url.end_with?(".git")
|
||||
|
@ -138,7 +138,7 @@ class SoftwareSpec
|
||||
end
|
||||
|
||||
def go_resource(name, &block)
|
||||
# odeprecated "SoftwareSpec#go_resource", "Go modules"
|
||||
# odeprecated "`SoftwareSpec#go_resource`", "Go modules"
|
||||
resource name, Resource::Go, &block
|
||||
end
|
||||
|
||||
@ -207,18 +207,6 @@ class SoftwareSpec
|
||||
depends_on UsesFromMacOSDependency.new(dep, tags, bounds:)
|
||||
end
|
||||
|
||||
# @deprecated
|
||||
def uses_from_macos_elements
|
||||
# TODO: Remember to remove the delegate from `Formula`.
|
||||
odisabled "#uses_from_macos_elements", "#declared_deps"
|
||||
end
|
||||
|
||||
# @deprecated
|
||||
def uses_from_macos_names
|
||||
# TODO: Remember to remove the delegate from `Formula`.
|
||||
odisabled "#uses_from_macos_names", "#declared_deps"
|
||||
end
|
||||
|
||||
def deps
|
||||
dependency_collector.deps.dup_without_system_deps
|
||||
end
|
||||
@ -318,7 +306,6 @@ class Bottle
|
||||
"#{name}--#{version}#{extname}"
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s = to_str
|
||||
|
||||
|
@ -80,21 +80,12 @@ class Formula
|
||||
sig { params(args: T.untyped, options: T.untyped, block: T.untyped).returns(T::Boolean) }
|
||||
def loaded_from_api?(*args, **options, &block); end
|
||||
|
||||
sig { params(args: T.untyped, options: T.untyped, block: T.untyped).returns(T.untyped) }
|
||||
def resource(*args, **options, &block); end
|
||||
|
||||
sig { params(args: T.untyped, options: T.untyped, block: T.untyped).returns(T.untyped) }
|
||||
def deps(*args, **options, &block); end
|
||||
|
||||
sig { params(args: T.untyped, options: T.untyped, block: T.untyped).returns(T.untyped) }
|
||||
def declared_deps(*args, **options, &block); end
|
||||
|
||||
sig { params(args: T.untyped, options: T.untyped, block: T.untyped).returns(T.untyped) }
|
||||
def uses_from_macos_elements(*args, **options, &block); end
|
||||
|
||||
sig { params(args: T.untyped, options: T.untyped, block: T.untyped).returns(T.untyped) }
|
||||
def uses_from_macos_names(*args, **options, &block); end
|
||||
|
||||
sig { params(args: T.untyped, options: T.untyped, block: T.untyped).returns(T.untyped) }
|
||||
def requirements(*args, **options, &block); end
|
||||
|
||||
@ -161,9 +152,6 @@ class Formula
|
||||
sig { params(args: T.untyped, options: T.untyped, block: T.untyped).returns(T.untyped) }
|
||||
def env(*args, **options, &block); end
|
||||
|
||||
sig { params(args: T.untyped, options: T.untyped, block: T.untyped).returns(T.untyped) }
|
||||
def conflicts(*args, **options, &block); end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def self.loaded_from_api?; end
|
||||
|
||||
|
@ -16,7 +16,6 @@ module Homebrew
|
||||
@column = column
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"#{line}#{column&.to_s&.prepend(":")}"
|
||||
|
@ -179,7 +179,7 @@ module Homebrew
|
||||
# -f (--force) : we know what we are doing, force apply patches
|
||||
# -d / (--directory=/) : change to root directory, since we use absolute file paths
|
||||
# -p0 (--strip=0) : do not strip path prefixes, since we are at root directory
|
||||
# NOTE: we use short flags where for compatibility
|
||||
# NOTE: We use short flags for compatibility.
|
||||
patch_command = %w[patch -g 0 -f -d / -p0]
|
||||
patches = system_command(shellcheck, args: ["--format=diff", *args]).stdout
|
||||
Utils.safe_popen_write(*patch_command) { |p| p.write(patches) } if patches.present?
|
||||
|
@ -13,12 +13,18 @@ class Tab
|
||||
|
||||
FILENAME = "INSTALL_RECEIPT.json"
|
||||
|
||||
# Check whether the formula was installed as a dependency.
|
||||
#
|
||||
# @api internal
|
||||
attr_accessor :installed_as_dependency
|
||||
|
||||
# Check whether the formula was installed on request.
|
||||
#
|
||||
# @api internal
|
||||
attr_accessor :installed_on_request
|
||||
|
||||
# Check whether the formula was poured from a bottle.
|
||||
#
|
||||
# @api internal
|
||||
attr_accessor :poured_from_bottle
|
||||
|
||||
@ -27,6 +33,8 @@ class Tab
|
||||
:built_on
|
||||
attr_writer :used_options, :unused_options, :compiler, :source_modified_time
|
||||
|
||||
# Returns the formula's runtime dependencies.
|
||||
#
|
||||
# @api internal
|
||||
attr_writer :runtime_dependencies
|
||||
|
||||
@ -72,7 +80,8 @@ class Tab
|
||||
end
|
||||
|
||||
# Returns the {Tab} for an install receipt at `path`.
|
||||
# Results are cached.
|
||||
#
|
||||
# NOTE: Results are cached.
|
||||
def self.from_file(path)
|
||||
cache.fetch(path) do |p|
|
||||
content = File.read(p)
|
||||
@ -282,7 +291,10 @@ class Tab
|
||||
spec == :stable
|
||||
end
|
||||
|
||||
# The options used to install the formula.
|
||||
#
|
||||
# @api internal
|
||||
sig { returns(Options) }
|
||||
def used_options
|
||||
Options.create(@used_options)
|
||||
end
|
||||
@ -321,6 +333,7 @@ class Tab
|
||||
built_as_bottle
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(Tap)) }
|
||||
def tap
|
||||
tap_name = source["tap"]
|
||||
Tap.fetch(tap_name) if tap_name
|
||||
@ -407,7 +420,6 @@ class Tab
|
||||
tabfile.atomic_write(to_json)
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
s = []
|
||||
|
@ -154,7 +154,6 @@ class Tap
|
||||
attr_reader :name
|
||||
|
||||
# @api public
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s = name
|
||||
|
||||
|
@ -73,8 +73,8 @@ RSpec.describe "ENV" do
|
||||
expect(subject["foo"]).to eq("1")
|
||||
end
|
||||
|
||||
# NOTE: this may be a wrong behavior; we should probably reject objects that
|
||||
# do not respond to #to_str. For now this documents existing behavior.
|
||||
# NOTE: This may be a wrong behavior; we should probably reject objects that
|
||||
# do not respond to `#to_str`. For now this documents existing behavior.
|
||||
it "coerces a value to a string" do
|
||||
subject.append "foo", 42
|
||||
expect(subject["foo"]).to eq("42")
|
||||
|
@ -332,7 +332,7 @@ RSpec.describe Cask::Cask, :cask do
|
||||
expect(JSON.pretty_generate(h["variations"])).to eq expected_sha256_variations.strip
|
||||
end
|
||||
|
||||
# @note The calls to `Cask.generating_hash!` and `Cask.generated_hash!`
|
||||
# NOTE: The calls to `Cask.generating_hash!` and `Cask.generated_hash!`
|
||||
# are not idempotent so they can only be used in one test.
|
||||
it "returns the correct hash placeholders" do
|
||||
described_class.generating_hash!
|
||||
|
@ -87,7 +87,7 @@ RSpec.describe Caveats do
|
||||
expect(caveats).to include("tmux")
|
||||
end
|
||||
|
||||
# @todo This should get deprecated and the service block `plist_name` method should get used instead.
|
||||
# TODO: This should get deprecated and the service block `plist_name` method should get used instead.
|
||||
it "prints info when there are custom service files" do
|
||||
f = formula do
|
||||
url "foo-1.0"
|
||||
|
@ -75,7 +75,7 @@ RSpec.describe Homebrew::Livecheck::Strategy::HeaderMatch do
|
||||
end
|
||||
|
||||
it "returns an array of version strings when given headers and a block" do
|
||||
# Returning a string from block, no regex
|
||||
# Returning a string from block, no regex.
|
||||
expect(
|
||||
header_match.versions_from_headers(headers[:location]) do |headers|
|
||||
v = Version.parse(headers["location"], detected_from_url: true)
|
||||
@ -83,16 +83,17 @@ RSpec.describe Homebrew::Livecheck::Strategy::HeaderMatch do
|
||||
end,
|
||||
).to eq(versions[:location])
|
||||
|
||||
# Returning a string from block, explicit regex
|
||||
# Returning a string from block, explicit regex.
|
||||
expect(
|
||||
header_match.versions_from_headers(headers[:location], regexes[:latest]) do |headers, regex|
|
||||
headers["location"] ? headers["location"][regex, 1] : nil
|
||||
end,
|
||||
).to eq(versions[:location])
|
||||
|
||||
# Returning an array of strings from block
|
||||
# NOTE: Strategies runs `#compact` on an array from a block, so nil
|
||||
# values are filtered out without needing to use `#compact` in the block.
|
||||
# Returning an array of strings from block.
|
||||
#
|
||||
# NOTE: Strategies runs `#compact` on an array from a block, so nil values
|
||||
# are filtered out without needing to use `#compact` in the block.
|
||||
expect(
|
||||
header_match.versions_from_headers(
|
||||
headers[:content_disposition_and_location],
|
||||
|
@ -1058,7 +1058,7 @@ RSpec.describe Homebrew::Service do
|
||||
}
|
||||
end
|
||||
|
||||
# @note The calls to `Formula.generating_hash!` and `Formula.generated_hash!`
|
||||
# NOTE: The calls to `Formula.generating_hash!` and `Formula.generated_hash!`
|
||||
# are not idempotent so they can only be used in one test.
|
||||
it "replaces local paths with placeholders" do
|
||||
f = stub_formula do
|
||||
|
@ -10,7 +10,7 @@ RSpec.describe Tapioca::Compilers::Args do
|
||||
Homebrew::Cmd::List.parser
|
||||
end
|
||||
|
||||
# good testing candidate, bc it has multiple for each of switch, flag, and comma_array args:
|
||||
# Good testing candidate because it has multiple for each of `switch`, `flag` and `comma_array` args:
|
||||
let(:update_python_resources_parser) do
|
||||
require "dev-cmd/update-python-resources"
|
||||
Homebrew::DevCmd::UpdatePythonResources.parser
|
||||
|
@ -35,7 +35,7 @@ module Cachable
|
||||
# A list of all classes that have been loaded into memory that mixin or
|
||||
# inherit `Cachable` at the class or module level.
|
||||
#
|
||||
# Note: Classes that inherit from `Formula` are excluded since it's not
|
||||
# NOTE: Classes that inherit from `Formula` are excluded since it's not
|
||||
# necessary to track and clear individual formula caches.
|
||||
def self.class_list
|
||||
@class_list ||= []
|
||||
@ -44,7 +44,7 @@ module Cachable
|
||||
# Clear the cache of every class or module that mixes in or inherits
|
||||
# `Cachable` at the class or module level.
|
||||
#
|
||||
# Note: Classes that inherit from `Formula` are excluded since it's not
|
||||
# NOTE: Classes that inherit from `Formula` are excluded since it's not
|
||||
# necessary to track and clear individual formula caches.
|
||||
def self.clear_all_caches
|
||||
class_list.each(&:clear_cache)
|
||||
|
@ -6,11 +6,11 @@ RSpec.describe UnpackStrategy::Zstd do
|
||||
let(:path) { TEST_FIXTURE_DIR/"cask/container.tar.zst" }
|
||||
|
||||
it "is correctly detected" do
|
||||
# UnpackStrategy.detect(path) for a .tar.XXX file returns either UnpackStrategy::Tar if
|
||||
# the host's tar is able to extract that compressed file or UnpackStrategy::XXX otherwise,
|
||||
# such as UnpackStrategy::Zstd. On macOS UnpackStrategy.detect("container.tar.zst")
|
||||
# returns UnpackStrategy::Zstd, and on ubuntu-22.04 it returns UnpackStrategy::Tar,
|
||||
# because the host's version of tar is recent enough and zstd is installed.
|
||||
# `UnpackStrategy.detect(path)` for a `.tar.XXX` file returns either `UnpackStrategy::Tar` if
|
||||
# the host's `tar` is able to extract that compressed file or `UnpackStrategy::XXX` otherwise,
|
||||
# such as `UnpackStrategy::Zstd`. On macOS `UnpackStrategy.detect("container.tar.zst")`
|
||||
# returns `UnpackStrategy::Zstd` and on Ubuntu 22.04 it returns `UnpackStrategy::Tar`,
|
||||
# because the host's version of `tar` is recent enough and `zstd` is installed.
|
||||
expect(UnpackStrategy.detect(path)).to(be_a(described_class).or(be_a(UnpackStrategy::Tar)))
|
||||
end
|
||||
end
|
||||
|
@ -72,7 +72,7 @@ RSpec.describe Utils::Shell do
|
||||
specify "::csh_quote" do
|
||||
expect(described_class.send(:csh_quote, "")).to eq("''")
|
||||
expect(described_class.send(:csh_quote, "\\")).to eq("\\\\")
|
||||
# NOTE: this test is different than for sh
|
||||
# NOTE: This test is different than for `sh`.
|
||||
expect(described_class.send(:csh_quote, "\n")).to eq("'\\\n'")
|
||||
expect(described_class.send(:csh_quote, "$")).to eq("\\$")
|
||||
expect(described_class.send(:csh_quote, "word")).to eq("word")
|
||||
|
@ -15,7 +15,6 @@ class URL
|
||||
@specs.freeze
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
@url
|
||||
|
@ -202,7 +202,6 @@ module Utils
|
||||
end
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
to_sym.to_s
|
||||
|
@ -239,7 +239,7 @@ module Homebrew
|
||||
|
||||
install_bundler!
|
||||
|
||||
# Combine the passed groups with the ones stored in settings
|
||||
# Combine the passed groups with the ones stored in settings.
|
||||
groups |= (user_gem_groups & valid_gem_groups)
|
||||
groups.sort!
|
||||
|
||||
|
@ -73,7 +73,6 @@ module GitHub
|
||||
@end_column = Integer(end_column) if end_column
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
metadata = @type.to_s
|
||||
|
@ -23,13 +23,21 @@ module Utils
|
||||
# defined by the formula, as only `HOMEBREW_PREFIX` is available
|
||||
# in the {DATAPatch embedded patch}.
|
||||
#
|
||||
# @example `inreplace` supports regular expressions:
|
||||
# inreplace "somefile.cfg", /look[for]what?/, "replace by #{bin}/tool"
|
||||
# ### Examples
|
||||
#
|
||||
# @example `inreplace` supports blocks:
|
||||
# `inreplace` supports regular expressions:
|
||||
#
|
||||
# ```ruby
|
||||
# inreplace "somefile.cfg", /look[for]what?/, "replace by #{bin}/tool"
|
||||
# ```
|
||||
#
|
||||
# `inreplace` supports blocks:
|
||||
#
|
||||
# ```ruby
|
||||
# inreplace "Makefile" do |s|
|
||||
# s.gsub! "/usr/local", HOMEBREW_PREFIX.to_s
|
||||
# end
|
||||
# ```
|
||||
#
|
||||
# @see StringInreplaceExtension
|
||||
# @api public
|
||||
|
@ -82,7 +82,6 @@ module PyPI
|
||||
]
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
if valid_pypi_package?
|
||||
|
@ -20,8 +20,11 @@ module Utils
|
||||
|
||||
# Rewrite shebang for the given `paths` using the given `rewrite_info`.
|
||||
#
|
||||
# @example
|
||||
# ### Example
|
||||
#
|
||||
# ```ruby
|
||||
# rewrite_shebang detected_python_shebang, bin/"script.py"
|
||||
# ```
|
||||
#
|
||||
# @api public
|
||||
sig { params(rewrite_info: RewriteInfo, paths: T.any(String, Pathname)).void }
|
||||
|
@ -98,7 +98,6 @@ module Tty
|
||||
end
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
return "" unless color?
|
||||
|
@ -57,7 +57,6 @@ class Version
|
||||
sig { abstract.params(other: T.untyped).returns(T.nilable(Integer)) }
|
||||
def <=>(other); end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name} #{value.inspect}>"
|
||||
@ -83,7 +82,6 @@ class Version
|
||||
value.to_s
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def to_s = to_str
|
||||
|
||||
@ -135,7 +133,6 @@ class Version
|
||||
sig { returns(T::Boolean) }
|
||||
def blank? = true
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}>"
|
||||
@ -350,7 +347,7 @@ class Version
|
||||
|
||||
sig { params(val: String).returns(Version) }
|
||||
def self.create(val)
|
||||
odisabled "Version.create", "Version.new"
|
||||
odisabled "`Version.create`", "`Version.new`"
|
||||
new(val)
|
||||
end
|
||||
|
||||
@ -516,12 +513,16 @@ class Version
|
||||
private_constant :HEAD_VERSION_REGEX
|
||||
|
||||
# Check if this is a HEAD version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T::Boolean) }
|
||||
def head?
|
||||
version&.match?(HEAD_VERSION_REGEX) || false
|
||||
end
|
||||
|
||||
# Return the commit for a HEAD version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.nilable(String)) }
|
||||
def commit
|
||||
version&.match(HEAD_VERSION_REGEX)&.[](:commit)
|
||||
@ -646,6 +647,8 @@ class Version
|
||||
end
|
||||
alias eql? ==
|
||||
|
||||
# The major version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.nilable(Token)) }
|
||||
def major
|
||||
@ -654,6 +657,8 @@ class Version
|
||||
tokens.first
|
||||
end
|
||||
|
||||
# The minor version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.nilable(Token)) }
|
||||
def minor
|
||||
@ -662,6 +667,8 @@ class Version
|
||||
tokens.second
|
||||
end
|
||||
|
||||
# The patch version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.nilable(Token)) }
|
||||
def patch
|
||||
@ -670,6 +677,8 @@ class Version
|
||||
tokens.third
|
||||
end
|
||||
|
||||
# The major and minor version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def major_minor
|
||||
@ -679,6 +688,8 @@ class Version
|
||||
major_minor.empty? ? NULL : self.class.new(major_minor.join("."))
|
||||
end
|
||||
|
||||
# The major, minor and patch version.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(T.self_type) }
|
||||
def major_minor_patch
|
||||
@ -693,6 +704,9 @@ class Version
|
||||
version.hash
|
||||
end
|
||||
|
||||
# Convert the version to a floating-point number.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(Float) }
|
||||
def to_f
|
||||
return Float::NAN if null?
|
||||
@ -700,11 +714,15 @@ class Version
|
||||
version.to_f
|
||||
end
|
||||
|
||||
# Convert the version to an integer.
|
||||
#
|
||||
# @api public
|
||||
sig { returns(Integer) }
|
||||
def to_i
|
||||
version.to_i
|
||||
end
|
||||
|
||||
# @api public
|
||||
sig { returns(String) }
|
||||
def to_str
|
||||
raise NoMethodError, "undefined method `to_str' for #{self.class}:NULL" if null?
|
||||
@ -712,7 +730,7 @@ class Version
|
||||
T.must(version).to_str
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
# @api public
|
||||
sig { returns(String) }
|
||||
def to_s = version.to_s
|
||||
|
||||
@ -728,7 +746,6 @@ class Version
|
||||
super
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
return "#<Version::NULL>" if null?
|
||||
@ -760,6 +777,7 @@ class Version
|
||||
end
|
||||
|
||||
# Represents the absence of a version.
|
||||
#
|
||||
# NOTE: Constructor needs to called with an arbitrary non-empty version which is then set to `nil`.
|
||||
NULL = Version.new("NULL").tap { |v| v.instance_variable_set(:@version, nil) }.freeze
|
||||
end
|
||||
|
@ -5,15 +5,90 @@
|
||||
module Homebrew
|
||||
module YARD
|
||||
class DocstringParser < ::YARD::DocstringParser
|
||||
# Every `Object` has these methods.
|
||||
OVERRIDABLE_METHODS = [
|
||||
:hash, :inspect, :to_s,
|
||||
:<=>, :===, :!~, :eql?, :equal?, :!, :==, :!=
|
||||
].freeze
|
||||
private_constant :OVERRIDABLE_METHODS
|
||||
|
||||
SELF_EXPLANATORY_METHODS = [:to_yaml, :to_json, :to_str].freeze
|
||||
private_constant :SELF_EXPLANATORY_METHODS
|
||||
|
||||
def parse_content(content)
|
||||
# Convert plain text to tags.
|
||||
content = content&.gsub(/^\s*(TODO|FIXME):\s*/i, "@todo ")
|
||||
content = content&.gsub(/^\s*NOTE:\s*/i, "@note ")
|
||||
|
||||
# Ignore non-documentation comments.
|
||||
content = content&.sub(/(\A(typed|.*rubocop)|TODO|FIXME):.*/m, "")
|
||||
content = content&.sub(/\A(typed|.*rubocop):.*/m, "")
|
||||
|
||||
content = super(content)
|
||||
|
||||
source = handler&.statement&.source
|
||||
|
||||
if object&.type == :method &&
|
||||
(match = source&.match(/\so(deprecated|disabled)\s+"((?:\\"|[^"])*)"(?:\s*,\s*"((?:\\"|[^"])*))?"/m))
|
||||
type = match[1]
|
||||
method = match[2]
|
||||
method = method.sub(/\#{self(\.class)?}/, object.namespace.to_s)
|
||||
replacement = match[3]
|
||||
replacement = replacement.sub(/\#{self(\.class)?}/, object.namespace.to_s)
|
||||
|
||||
# Only match `odeprecated`/`odisabled` for this method.
|
||||
if method.match?(/(.|#|`)#{Regexp.escape(object.name.to_s)}`/)
|
||||
if (method_name = method[/\A`([^`]*)`\Z/, 1]) && (
|
||||
(method_name.count(".") + method_name.count("#")) <= 1
|
||||
)
|
||||
method_name = method_name.delete_prefix(object.namespace.to_s)
|
||||
method = (method_name.delete_prefix(".") == object.name(true).to_s) ? nil : "{#{method_name}}"
|
||||
end
|
||||
|
||||
if replacement &&
|
||||
(replacement_method_name = replacement[/\A`([^`]*)`\Z/, 1]) && (
|
||||
(replacement_method_name.count(".") + replacement_method_name.count("#")) <= 1
|
||||
)
|
||||
replacement_method_name = replacement_method_name.delete_prefix(object.namespace.to_s)
|
||||
replacement = "{#{replacement_method_name}}"
|
||||
end
|
||||
|
||||
if method && !method.include?('#{')
|
||||
description = "Calling #{method} is #{type}"
|
||||
description += ", use #{replacement} instead" if replacement && !replacement.include?('#{')
|
||||
description += "."
|
||||
elsif replacement && !replacement.include?('#{')
|
||||
description = "Use #{replacement} instead."
|
||||
else
|
||||
description = ""
|
||||
end
|
||||
|
||||
tags << create_tag("deprecated", description)
|
||||
end
|
||||
end
|
||||
|
||||
api = tags.find { |tag| tag.tag_name == "api" }&.text
|
||||
is_private = tags.any? { |tag| tag.tag_name == "private" }
|
||||
visibility = directives.find { |d| d.tag.tag_name == "visibility" }&.tag&.text
|
||||
|
||||
# Hide `#hash`, `#inspect` and `#to_s`.
|
||||
if visibility.nil? && OVERRIDABLE_METHODS.include?(object&.name)
|
||||
create_directive("visibility", "private")
|
||||
visibility = "private"
|
||||
end
|
||||
|
||||
# Mark everything as `@api private` by default.
|
||||
visibility_tags = ["visibility", "api", "private"]
|
||||
tags << create_tag("api", "private") if tags.none? { |tag| visibility_tags.include?(tag.tag_name) }
|
||||
if api.nil? && !is_private
|
||||
tags << create_tag("api", "private")
|
||||
api = "private"
|
||||
end
|
||||
|
||||
# Warn about undocumented non-private APIs.
|
||||
if handler && api && api != "private" && visibility != "private" &&
|
||||
content.chomp.empty? && !SELF_EXPLANATORY_METHODS.include?(object&.name)
|
||||
stmt = handler.statement
|
||||
log.warn "#{api.capitalize} API should be documented:\n " \
|
||||
"in `#{handler.parser.file}`:#{stmt.line}:\n\n#{stmt.show}\n"
|
||||
end
|
||||
|
||||
content
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user