111 lines
3.4 KiB
Ruby
Raw Normal View History

livecheck: Add Options class This adds a `Livecheck::Options` class, which is intended to house various configuration options that are set in `livecheck` blocks, conditionally set by livecheck at runtime, etc. The general idea is that when we add features involving configurations options (e.g., for livecheck, strategies, curl, etc.), we can make changes to `Options` without needing to modify parameters for strategy `find_versions` methods, `Strategy` methods like `page_headers` and `page_content`, etc. This is something that I've been trying to improve over the years and `Options` should help to reduce maintenance overhead in this area while also strengthening type signatures. `Options` replaces the existing `homebrew_curl` option (which related strategies pass to `Strategy` methods and on to `curl_args`) and the new `url_options` (which contains `post_form` or `post_json` values that are used to make `POST` requests). I recently added `url_options` as a temporary way of enabling `POST` support without `Options` but this restores the original `Options`-based implementation. Along the way, I added a `homebrew_curl` parameter to the `url` DSL method, allowing us to set an explicit value in `livecheck` blocks. This is something that we've needed in some cases but I also intend to replace implicit/inferred `homebrew_curl` usage with explicit values in `livecheck` blocks once this is available for use. My intention is to eventually remove the implicit behavior and only rely on explicit values. That will align with how `homebrew_curl` options work for other URLs and makes the behavior clear just from looking at the `livecheck` block. Lastly, this removes the `unused` rest parameter from `find_versions` methods. I originally added `unused` as a way of handling parameters that some `find_versions` methods have but others don't (e.g., `cask` in `ExtractPlist`), as this allowed us to pass various arguments to `find_versions` methods without worrying about whether a particular parameter is available. This isn't an ideal solution and I originally wanted to handle this situation by only passing expected arguments to `find_versions` methods but there was a technical issue standing in the way. I recently found an answer to the issue, so this also replaces the existing `ExtractPlist` special case with generic logic that checks the parameters for a strategy's `find_versions` method and only passes expected arguments. Replacing the aforementioned `find_versions` parameters with `Options` ensures that the remaining parameters are fairly consistent across strategies and any differences are handled by the aforementioned logic. Outside of `ExtractPlist`, the only other difference is that some `find_versions` methods have a `provided_content` parameter but that's currently only used by tests (though it's intended for caching support in the future). I will be renaming that parameter to `content` in an upcoming PR and expanding it to the other strategies, which should make them all consistent outside of `ExtractPlist`.
2025-02-11 18:04:38 -05:00
# typed: strict
# frozen_string_literal: true
module Homebrew
module Livecheck
# Options to modify livecheck's behavior. These primarily come from
# `livecheck` blocks but they can also be set by livecheck at runtime.
#
# Option values use a `nil` default to indicate that the value has not been
# set.
class Options
# Whether to use brewed curl.
sig { returns(T.nilable(T::Boolean)) }
attr_reader :homebrew_curl
# Form data to use when making a `POST` request.
sig { returns(T.nilable(T::Hash[Symbol, String])) }
attr_reader :post_form
# JSON data to use when making a `POST` request.
sig { returns(T.nilable(T::Hash[Symbol, String])) }
attr_reader :post_json
# @param homebrew_curl whether to use brewed curl
# @param post_form form data to use when making a `POST` request
# @param post_json JSON data to use when making a `POST` request
sig {
params(
homebrew_curl: T.nilable(T::Boolean),
post_form: T.nilable(T::Hash[Symbol, String]),
post_json: T.nilable(T::Hash[Symbol, String]),
).void
}
def initialize(homebrew_curl: nil, post_form: nil, post_json: nil)
@homebrew_curl = homebrew_curl
@post_form = post_form
@post_json = post_json
end
# Returns a `Hash` of options that are provided as arguments to `url`.
sig { returns(T::Hash[Symbol, T.untyped]) }
def url_options
{
homebrew_curl:,
post_form:,
post_json:,
}
end
# Returns a `Hash` of all instance variables, using `Symbol` keys.
sig { returns(T::Hash[Symbol, T.untyped]) }
def to_h
{
homebrew_curl:,
post_form:,
post_json:,
}
end
# Returns a `Hash` of all instance variables, using `String` keys.
sig { returns(T::Hash[String, T.untyped]) }
def to_hash
{
"homebrew_curl" => @homebrew_curl,
"post_form" => @post_form,
"post_json" => @post_json,
}
end
# Returns a new object formed by merging `other` values with a copy of
# `self`.
#
# `nil` values are removed from `other` before merging if it is an
# `Options` object, as these are unitiailized values. This ensures that
# existing values in `self` aren't unexpectedly overwritten with defaults.
sig { params(other: T.any(Options, T::Hash[Symbol, T.untyped])).returns(Options) }
def merge(other)
return dup if other.empty?
this_hash = to_h
other_hash = other.is_a?(Options) ? other.to_h.compact : other
return dup if this_hash == other_hash
new_options = this_hash.merge(other_hash)
Options.new(**new_options)
end
sig { params(other: T.untyped).returns(T::Boolean) }
def ==(other)
instance_of?(other.class) &&
@homebrew_curl == other.homebrew_curl &&
@post_form == other.post_form &&
@post_json == other.post_json
end
alias eql? ==
# Whether the object has only default values.
sig { returns(T::Boolean) }
def empty?
@homebrew_curl.nil? && @post_form.nil? && @post_json.nil?
end
# Whether the object has any non-default values.
sig { returns(T::Boolean) }
def present?
!@homebrew_curl.nil? || !@post_form.nil? || !@post_json.nil?
end
end
end
end