Class: Udb::RequirementSpec

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/udb/version_spec.rb

Overview

Represents a version requirement

A requirement is either a logical comparison (>, >=, <, <=, =, !=) or a compatible operator (~>).

Examples:

Logical requirement

# When the requirement is a logical comparison, the extension parameter is not needed
RequirementSpec.new(">= 0.5").satisfied_by?(VersionSpec.new("1.0"), nil) #=> true
RequirementSpec.new(">= 0.5").satisfied_by?(VersionSpec.new("0.4"), nil) #=> false

Compatible requirement

s_ext = cfg_arch.extension(...) # S extension, which is breaking between 1.11 -> 1.12
RequirementSpec.new("~> 1.11").satisfied_by?(VersionSpec.new("1.10"), s_ext) #=> true
RequirementSpec.new("~> 1.11").satisfied_by?(VersionSpec.new("1.11"), s_ext) #=> true
RequirementSpec.new("~> 1.11").satisfied_by?(VersionSpec.new("1.12"), s_ext) #=> false

Constant Summary collapse

REQUIREMENT_OP_REGEX =
/((?:>=)|(?:>)|(?:~>)|(?:<)|(?:<=)|(?:!=)|(?:=))/
REQUIREMENT_REGEX =
/#{REQUIREMENT_OP_REGEX}\s*(#{VersionSpec::VERSION_REGEX})/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(requirement)

Parameters:

  • requirement (String)

    A requirement string



192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/udb/version_spec.rb', line 192

def initialize(requirement)
  if requirement =~ /^\s*#{REQUIREMENT_REGEX}\s*$/
    m = T.must(::Regexp.last_match)
    @op = T.must(m[1]).freeze
    @op_sym = @op.to_sym
    @op_sym.freeze
    @version_str = T.must(m[2]).freeze
    @version_spec = VersionSpec.new(@version_str).freeze
  else
    raise ArgumentError, "Bad requirement string '#{requirement}' #{REQUIREMENT_REGEX}"
  end
end

Instance Attribute Details

#opString (readonly)

Returns:

  • (String)


185
186
187
# File 'lib/udb/version_spec.rb', line 185

def op
  @op
end

#version_specVersionSpec (readonly)

Returns:



188
189
190
# File 'lib/udb/version_spec.rb', line 188

def version_spec
  @version_spec
end

Instance Method Details

#eql?(other) ⇒ Boolean

Parameters:

  • other (T.untyped)

Returns:

  • (Boolean)


206
207
208
209
210
211
212
# File 'lib/udb/version_spec.rb', line 206

def eql?(other)
  if other.is_a?(RequirementSpec)
    self.hash == other.hash
  else
    false
  end
end

#hashInteger

Returns:

  • (Integer)


215
216
217
# File 'lib/udb/version_spec.rb', line 215

def hash
  @hash ||= [@op_sym, @version_spec].hash.freeze
end

#satisfied_by?(version, ext) ⇒ Boolean

Returns if the version satisfies the requirement.

Parameters:

  • version (VersionSpec)

    A version spec

  • ext (Hash)

    Raw extension spec (from YAML)

  • version (String, VersionSpec)

    A version string

  • ext (Extension, Hash{String => T.untyped})

    An extension, needed to evaluate the compatible (~>) operator

Returns:

  • (Boolean)

    if the version satisfies the requirement



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/udb/version_spec.rb', line 252

def satisfied_by?(version, ext)
  v_spec =
    case version
    when String
      VersionSpec.new(version)
    when VersionSpec
      version
    else
      T.absurd(version)
    end

  result =
    case @op_sym
    when :>=
      v_spec >= @version_spec
    when :>
      v_spec > @version_spec
    when :<=
      v_spec <= @version_spec
    when :<
      v_spec < @version_spec
    when :"="
      v_spec == @version_spec
    when :"!="
      v_spec != @version_spec
    when :"~>"
      if ext.is_a?(Extension)
        matching_ver = ext.versions.find { |v| v.version_spec == v_spec }
        raise "Can't find version?" if matching_ver.nil?

        matching_ver.compatible?(ext.arch.extension_version(ext.name, v_spec.to_s))
      else
        versions = ext.fetch("versions")
        compatible_versions = []
        versions.each do |vinfo|
          vspec = VersionSpec.new(vinfo.fetch("version"))
          compatible_versions << vspec if vspec >= v_spec
          break if compatible_versions.size.positive? && vinfo.key?("breaking")
        end

        compatible_versions.include?(v_spec)
      end
    when :"!~>" # not a legal spec, but used for inversion
      if ext.is_a?(Extension)
        matching_ver = ext.versions.find { |v| v.version_spec == v_spec }
        raise "Can't find version?" if matching_ver.nil?

        !matching_ver.compatible?(ext.arch.extension_version(ext.name, v_spec.to_s))
      else
        versions = ext.fetch("versions")
        compatible_versions = []
        versions.each do |vinfo|
          vspec = VersionSpec.new(vinfo.fetch("version"))
          compatible_versions << vspec if vspec >= v_spec
          break if compatible_versions.size.positive? && vinfo.key?("breaking")
        end

        !compatible_versions.include?(v_spec)
      end
    end

  T.must(result)
end

#to_sString

Returns:

  • (String)


220
221
222
# File 'lib/udb/version_spec.rb', line 220

def to_s
  "#{@op} #{@version_str}"
end