class Dependabot::Uv::Requirement

def self.parse(obj)

def self.parse(obj)
  return ["=", Uv::Version.new(obj.to_s)] if obj.is_a?(Gem::Version)
  line = obj.to_s
  if (matches = PARENS_PATTERN.match(line))
    line = matches[1]
  end
  unless (matches = PATTERN.match(line))
    msg = "Illformed requirement [#{obj.inspect}]"
    raise BadRequirementError, msg
  end
  return DefaultRequirement if matches[:op] == ">=" && matches[:version] == "0"
  [matches[:op] || "=", Uv::Version.new(T.must(matches[:version]))]
end

def self.requirements_array(requirement_string)

def self.requirements_array(requirement_string)
  return [new(nil)] if requirement_string.nil?
  if (matches = PARENS_PATTERN.match(requirement_string))
    requirement_string = matches[1]
  end
  T.must(requirement_string).strip.split(OR_SEPARATOR).map do |req_string|
    new(req_string.strip)
  end
end

def convert_caret_req(req_string)

https://github.com/sdispater/poetry#caret-requirement
Poetry uses ^ requirements
def convert_caret_req(req_string)
  version = req_string.gsub(/^\^/, "")
  parts = version.split(".")
  parts.fill(0, parts.length...3)
  first_non_zero = parts.find { |d| d != "0" }
  first_non_zero_index =
    first_non_zero ? parts.index(first_non_zero) : parts.count - 1
  upper_bound = parts.map.with_index do |part, i|
    if i < first_non_zero_index then part
    elsif i == first_non_zero_index then (part.to_i + 1).to_s
    # .dev has lowest precedence: https://packaging.python.org/en/latest/specifications/version-specifiers/#summary-of-permitted-suffixes-and-relative-ordering
    elsif i > first_non_zero_index && i == 2 then "0.dev"
    else
      0
    end
  end.join(".")
  [">= #{version}", "< #{upper_bound}"]
end

def convert_exact(req_string)

def convert_exact(req_string)
  arbitrary_equality = req_string.start_with?("===")
  cleaned_version = req_string.gsub(/^=+/, "").strip
  return ["=== #{cleaned_version}"] if arbitrary_equality
  # Handle versions wildcarded with .*, e.g. 1.0.*
  if cleaned_version.include?(".*")
    # Remove all characters after the first .*, and the .*
    cleaned_version = cleaned_version.split(".*").first
    version = Version.new(cleaned_version)
    # Get the release segment parts [major, minor, patch]
    version_parts = version.release_segment
    if version_parts.length == 1
      major = T.must(version_parts[0])
      [">= #{major}.0.0.dev", "< #{major + 1}.0.0"]
    elsif version_parts.length == 2
      major, minor = version_parts
      "~> #{major}.#{minor}.0.dev"
    elsif version_parts.length == 3
      major, minor, patch = version_parts
      "~> #{major}.#{minor}.#{patch}.dev"
    else
      "= #{cleaned_version}"
    end
  else
    "= #{cleaned_version}"
  end
end

def convert_python_constraint_to_ruby_constraint(req_string)

def convert_python_constraint_to_ruby_constraint(req_string)
  return nil if req_string.nil? || req_string.strip.empty?
  return nil if req_string == "*"
  req_string = req_string.gsub("~=", "~>")
  req_string = req_string.gsub(/(?<=\d)[<=>].*\Z/, "")
  if req_string.match?(/~[^>]/) then convert_tilde_req(req_string)
  elsif req_string.start_with?("^") then convert_caret_req(req_string)
  elsif req_string.match?(/^=?={0,2}\s*\d+\.\d+(\.\d+)?(-[a-z0-9.-]+)?(\.\*)?$/i)
    convert_exact(req_string)
  elsif req_string.include?(".*") then convert_wildcard(req_string)
  else
    req_string
  end
end

def convert_tilde_req(req_string)

https://github.com/sdispater/poetry#tilde-requirements
Poetry uses ~ requirements.
def convert_tilde_req(req_string)
  version = req_string.gsub(/^~\>?/, "")
  parts = version.split(".")
  parts << "0" if parts.count < 3
  "~> #{parts.join('.')}"
end

def convert_wildcard(req_string)

def convert_wildcard(req_string)
  # NOTE: This isn't perfect. It replaces the "!= 1.0.*" case with
  # "!= 1.0.0". There's no way to model this correctly in Ruby :'(
  quoted_ops = OPS.keys.sort_by(&:length).reverse
                  .map { |k| Regexp.quote(k) }.join("|")
  op = req_string.match(/\A\s*(#{quoted_ops})?/)
                 .captures.first.to_s&.strip
  exact_op = ["", "=", "==", "==="].include?(op)
  req_string.strip
            .split(".")
            .first(req_string.split(".").index { |s| s.include?("*") } + 1)
            .join(".")
            .gsub(/\*(?!$)/, "0")
            .gsub(/\*$/, "0.dev")
            .tap { |s| exact_op ? s.gsub!(/^(?<!!)=*/, "~>") : s }
end

def exact?

def exact?
  return false unless @requirements.size == 1
  %w(= == ===).include?(@requirements[0][0])
end

def initialize(*requirements)

def initialize(*requirements)
  requirements = requirements.flatten.flat_map do |req_string|
    next if req_string.nil?
    # Standard python doesn't support whitespace in requirements, but Poetry does.
    req_string = req_string.gsub(/(\d +)([<=>])/, '\1,\2')
    req_string.split(",").map(&:strip).map do |r|
      convert_python_constraint_to_ruby_constraint(r)
    end
  end
  super(requirements)
end

def satisfied_by?(version)

def satisfied_by?(version)
  version = Uv::Version.new(version.to_s)
  requirements.all? { |op, rv| (OPS[op] || OPS["="]).call(version, rv) }
end