diff options
author | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-16 18:49:26 +0900 |
---|---|---|
committer | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-30 00:39:06 +0900 |
commit | fcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch) | |
tree | 64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/lib/rubygems/requirement.rb |
Fresh start
Diffstat (limited to 'jni/ruby/lib/rubygems/requirement.rb')
-rw-r--r-- | jni/ruby/lib/rubygems/requirement.rb | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/jni/ruby/lib/rubygems/requirement.rb b/jni/ruby/lib/rubygems/requirement.rb new file mode 100644 index 0000000..8b6a816 --- /dev/null +++ b/jni/ruby/lib/rubygems/requirement.rb @@ -0,0 +1,273 @@ +require "rubygems/version" +require "rubygems/deprecate" + +# If we're being loaded after yaml was already required, then +# load our yaml + workarounds now. +Gem.load_yaml if defined? ::YAML + +## +# A Requirement is a set of one or more version restrictions. It supports a +# few (<tt>=, !=, >, <, >=, <=, ~></tt>) different restriction operators. +# +# See Gem::Version for a description on how versions and requirements work +# together in RubyGems. + +class Gem::Requirement + OPS = { #:nodoc: + "=" => lambda { |v, r| v == r }, + "!=" => lambda { |v, r| v != r }, + ">" => lambda { |v, r| v > r }, + "<" => lambda { |v, r| v < r }, + ">=" => lambda { |v, r| v >= r }, + "<=" => lambda { |v, r| v <= r }, + "~>" => lambda { |v, r| v >= r && v.release < r.bump } + } + + quoted = OPS.keys.map { |k| Regexp.quote k }.join "|" + PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*" # :nodoc: + + ## + # A regular expression that matches a requirement + + PATTERN = /\A#{PATTERN_RAW}\z/ + + ## + # The default requirement matches any version + + DefaultRequirement = [">=", Gem::Version.new(0)] + + ## + # Raised when a bad requirement is encountered + + class BadRequirementError < ArgumentError; end + + ## + # Factory method to create a Gem::Requirement object. Input may be + # a Version, a String, or nil. Intended to simplify client code. + # + # If the input is "weird", the default version requirement is + # returned. + + def self.create input + case input + when Gem::Requirement then + input + when Gem::Version, Array then + new input + else + if input.respond_to? :to_str then + new [input.to_str] + else + default + end + end + end + + ## + # A default "version requirement" can surely _only_ be '>= 0'. + + def self.default + new '>= 0' + end + + ## + # Parse +obj+, returning an <tt>[op, version]</tt> pair. +obj+ can + # be a String or a Gem::Version. + # + # If +obj+ is a String, it can be either a full requirement + # specification, like <tt>">= 1.2"</tt>, or a simple version number, + # like <tt>"1.2"</tt>. + # + # parse("> 1.0") # => [">", "1.0"] + # parse("1.0") # => ["=", "1.0"] + # parse(Gem::Version.new("1.0")) # => ["=, "1.0"] + + def self.parse obj + return ["=", obj] if Gem::Version === obj + + unless PATTERN =~ obj.to_s + raise BadRequirementError, "Illformed requirement [#{obj.inspect}]" + end + + if $1 == ">=" && $2 == "0" + DefaultRequirement + else + [$1 || "=", Gem::Version.new($2)] + end + end + + ## + # An array of requirement pairs. The first element of the pair is + # the op, and the second is the Gem::Version. + + attr_reader :requirements #:nodoc: + + ## + # Constructs a requirement from +requirements+. Requirements can be + # Strings, Gem::Versions, or Arrays of those. +nil+ and duplicate + # requirements are ignored. An empty set of +requirements+ is the + # same as <tt>">= 0"</tt>. + + def initialize *requirements + requirements = requirements.flatten + requirements.compact! + requirements.uniq! + + if requirements.empty? + @requirements = [DefaultRequirement] + else + @requirements = requirements.map! { |r| self.class.parse r } + end + end + + ## + # Concatenates the +new+ requirements onto this requirement. + + def concat new + new = new.flatten + new.compact! + new.uniq! + new = new.map { |r| self.class.parse r } + + @requirements.concat new + end + + ## + # Formats this requirement for use in a Gem::RequestSet::Lockfile. + + def for_lockfile # :nodoc: + return if [DefaultRequirement] == @requirements + + list = requirements.sort_by { |_, version| + version + }.map { |op, version| + "#{op} #{version}" + }.uniq + + " (#{list.join ', '})" + end + + ## + # true if this gem has no requirements. + + def none? + if @requirements.size == 1 + @requirements[0] == DefaultRequirement + else + false + end + end + + ## + # true if the requirement is for only an exact version + + def exact? + return false unless @requirements.size == 1 + @requirements[0][0] == "=" + end + + def as_list # :nodoc: + requirements.map { |op, version| "#{op} #{version}" }.sort + end + + def hash # :nodoc: + requirements.hash + end + + def marshal_dump # :nodoc: + fix_syck_default_key_in_requirements + + [@requirements] + end + + def marshal_load array # :nodoc: + @requirements = array[0] + + fix_syck_default_key_in_requirements + end + + def yaml_initialize(tag, vals) # :nodoc: + vals.each do |ivar, val| + instance_variable_set "@#{ivar}", val + end + + Gem.load_yaml + fix_syck_default_key_in_requirements + end + + def init_with coder # :nodoc: + yaml_initialize coder.tag, coder.map + end + + def to_yaml_properties # :nodoc: + ["@requirements"] + end + + def encode_with coder # :nodoc: + coder.add 'requirements', @requirements + end + + ## + # A requirement is a prerelease if any of the versions inside of it + # are prereleases + + def prerelease? + requirements.any? { |r| r.last.prerelease? } + end + + def pretty_print q # :nodoc: + q.group 1, 'Gem::Requirement.new(', ')' do + q.pp as_list + end + end + + ## + # True if +version+ satisfies this Requirement. + + def satisfied_by? version + raise ArgumentError, "Need a Gem::Version: #{version.inspect}" unless + Gem::Version === version + # #28965: syck has a bug with unquoted '=' YAML.loading as YAML::DefaultKey + requirements.all? { |op, rv| (OPS[op] || OPS["="]).call version, rv } + end + + alias :=== :satisfied_by? + alias :=~ :satisfied_by? + + ## + # True if the requirement will not always match the latest version. + + def specific? + return true if @requirements.length > 1 # GIGO, > 1, > 2 is silly + + not %w[> >=].include? @requirements.first.first # grab the operator + end + + def to_s # :nodoc: + as_list.join ", " + end + + def == other # :nodoc: + Gem::Requirement === other and to_s == other.to_s + end + + private + + def fix_syck_default_key_in_requirements # :nodoc: + Gem.load_yaml + + # Fixup the Syck DefaultKey bug + @requirements.each do |r| + if r[0].kind_of? Gem::SyckDefaultKey + r[0] = "=" + end + end + end +end + +class Gem::Version + # This is needed for compatibility with older yaml + # gemspecs. + + Requirement = Gem::Requirement # :nodoc: +end |