Class: Semverse::Constraint

Inherits:
Object
  • Object
show all
Defined in:
lib/semverse/constraint.rb

Constant Summary collapse

OPERATOR_TYPES =
{
  "~>" => :approx,
  "~"  => :approx,
  ">=" => :greater_than_equal,
  "<=" => :less_than_equal,
  "="  => :equal,
  ">"  => :greater_than,
  "<"  => :less_than,
}.freeze
COMPARE_FUNS =
{
  approx: method(:compare_approx),
  greater_than_equal: method(:compare_gte),
  greater_than: method(:compare_gt),
  less_than_equal: method(:compare_lte),
  less_than: method(:compare_lt),
  equal: method(:compare_equal)
}.freeze
REGEXP =
/^(#{OPERATOR_TYPES.keys.join('|')})\s?(.+)$/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(constraint = nil) ⇒ Constraint

Returns a new instance of Constraint.

Parameters:

  • constraint (#to_s) (defaults to: nil)


202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/semverse/constraint.rb', line 202

def initialize(constraint = nil)
  constraint = constraint.to_s
  if constraint.nil? || constraint.empty?
    constraint = '>= 0.0.0'
  end

  @operator, @major, @minor, @patch, @pre_release, @build = self.class.split(constraint)

  unless operator_type == :approx
    @minor ||= 0
    @patch ||= 0
  end

  @version = Version.new([
    self.major,
    self.minor,
    self.patch,
    self.pre_release,
    self.build,
  ])
end

Instance Attribute Details

#buildObject (readonly)

Returns the value of attribute build.



193
194
195
# File 'lib/semverse/constraint.rb', line 193

def build
  @build
end

#majorObject (readonly)

Returns the value of attribute major.



189
190
191
# File 'lib/semverse/constraint.rb', line 189

def major
  @major
end

#minorObject (readonly)

Returns the value of attribute minor.



190
191
192
# File 'lib/semverse/constraint.rb', line 190

def minor
  @minor
end

#operatorObject (readonly)

Returns the value of attribute operator.



188
189
190
# File 'lib/semverse/constraint.rb', line 188

def operator
  @operator
end

#patchObject (readonly)

Returns the value of attribute patch.



191
192
193
# File 'lib/semverse/constraint.rb', line 191

def patch
  @patch
end

#pre_releaseObject (readonly)

Returns the value of attribute pre_release.



192
193
194
# File 'lib/semverse/constraint.rb', line 192

def pre_release
  @pre_release
end

#versionSemverse::Version (readonly)

Return the Semverse::Version representation of the major, minor, and patch attributes of this instance

Returns:



199
200
201
# File 'lib/semverse/constraint.rb', line 199

def version
  @version
end

Class Method Details

.coerce(object) ⇒ Constraint

Coerce the object into a constraint.

Parameters:

Returns:



9
10
11
12
13
14
15
# File 'lib/semverse/constraint.rb', line 9

def coerce(object)
  if object.nil?
    DEFAULT_CONSTRAINT
  else
    object.is_a?(self) ? object : new(object)
  end
end

.compare_approx(constraint, target_version) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/semverse/constraint.rb', line 148

def compare_approx(constraint, target_version)
  min = constraint.version
  max = if constraint.patch.nil?
    Version.new([min.major + 1, 0, 0, 0])
  elsif constraint.build
    identifiers = constraint.version.identifiers(:build)
    replace     = identifiers.last.to_i.to_s == identifiers.last.to_s ? "-" : nil
    Version.new([min.major, min.minor, min.patch, min.pre_release, identifiers.fill(replace, -1).join('.')])
  elsif constraint.pre_release
    identifiers = constraint.version.identifiers(:pre_release)
    replace     = identifiers.last.to_i.to_s == identifiers.last.to_s ? "-" : nil
    Version.new([min.major, min.minor, min.patch, identifiers.fill(replace, -1).join('.')])
  else
    Version.new([min.major, min.minor + 1, 0, 0])
  end
  min <= target_version && target_version < max
end

.compare_equal(constraint, target_version) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


108
109
110
# File 'lib/semverse/constraint.rb', line 108

def compare_equal(constraint, target_version)
  target_version == constraint.version
end

.compare_gt(constraint, target_version) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


116
117
118
# File 'lib/semverse/constraint.rb', line 116

def compare_gt(constraint, target_version)
  target_version > constraint.version
end

.compare_gte(constraint, target_version) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


132
133
134
# File 'lib/semverse/constraint.rb', line 132

def compare_gte(constraint, target_version)
  target_version >= constraint.version
end

.compare_lt(constraint, target_version) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


124
125
126
# File 'lib/semverse/constraint.rb', line 124

def compare_lt(constraint, target_version)
  target_version < constraint.version
end

.compare_lte(constraint, target_version) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


140
141
142
# File 'lib/semverse/constraint.rb', line 140

def compare_lte(constraint, target_version)
  target_version <= constraint.version
end

.satisfy_all(constraints, versions) ⇒ Array<Semverse::Version>

Returns all of the versions which satisfy all of the given constraints

Parameters:

Returns:



23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/semverse/constraint.rb', line 23

def satisfy_all(constraints, versions)
  constraints = Array(constraints).collect do |con|
    con.is_a?(Constraint) ? con : Constraint.new(con)
  end.uniq

  versions = Array(versions).collect do |ver|
    ver.is_a?(Version) ? ver : Version.new(ver)
  end.uniq

  versions.select do |ver|
    constraints.all? { |constraint| constraint.satisfies?(ver) }
  end
end

.satisfy_best(constraints, versions) ⇒ Semverse::Version

Return the best version from the given list of versions for the given list of constraints

Parameters:

Returns:

Raises:



45
46
47
48
49
50
51
52
53
# File 'lib/semverse/constraint.rb', line 45

def satisfy_best(constraints, versions)
  solution = satisfy_all(constraints, versions)

  if solution.empty?
    raise NoSolutionError
  end

  solution.sort.last
end

.split(constraint) ⇒ Array?

Split a constraint string into an Array of two elements. The first element being the operator and second being the version string.

If the given string does not contain a constraint operator then (=) will be used.

If the given string does not contain a valid version string then nil will be returned.

Examples:

splitting a string with a constraint operator and valid version string

Constraint.split(">= 1.0.0") => [ ">=", "1.0.0" ]

splitting a string without a constraint operator

Constraint.split("0.0.0") => [ "=", "1.0.0" ]

splitting a string without a valid version string

Constraint.split("hello") => nil

Parameters:

  • constraint (#to_s)

Returns:

  • (Array, nil)


76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/semverse/constraint.rb', line 76

def split(constraint)
  if constraint =~ /^[0-9]/
    operator = "="
    version  = constraint
  else
    _, operator, version = REGEXP.match(constraint).to_a
  end

  if operator.nil?
    raise InvalidConstraintFormat.new(constraint)
  end

  split_version = case version.to_s
  when /^(\d+)\.(\d+)\.(\d+)(-([0-9a-z\-\.]+))?(\+([0-9a-z\-\.]+))?$/i
    [ $1.to_i, $2.to_i, $3.to_i, $5, $7 ]
  when /^(\d+)\.(\d+)\.(\d+)?$/
    [ $1.to_i, $2.to_i, $3.to_i, nil, nil ]
  when /^(\d+)\.(\d+)?$/
    [ $1.to_i, $2.to_i, nil, nil, nil ]
  when /^(\d+)$/
    [ $1.to_i, nil, nil, nil, nil ]
  else
    raise InvalidConstraintFormat.new(constraint)
  end

  [ operator, split_version ].flatten
end

Instance Method Details

#==(other) ⇒ Boolean Also known as: eql?

Parameters:

  • other (Object)

Returns:

  • (Boolean)


254
255
256
257
258
# File 'lib/semverse/constraint.rb', line 254

def ==(other)
  other.is_a?(self.class) &&
    self.operator == other.operator &&
    self.version == other.version
end

#inspectObject



261
262
263
# File 'lib/semverse/constraint.rb', line 261

def inspect
  "#<#{self.class.to_s} #{to_s}>"
end

#operator_typeSymbol

Returns:

  • (Symbol)


225
226
227
228
229
230
231
# File 'lib/semverse/constraint.rb', line 225

def operator_type
  unless type = OPERATOR_TYPES.fetch(operator)
    raise RuntimeError, "unknown operator type: #{operator}"
  end

  type
end

#satisfies?(target) ⇒ Boolean Also known as: include?

Returns true or false if the given version would be satisfied by the version constraint.

Parameters:

Returns:

  • (Boolean)


239
240
241
242
243
244
245
# File 'lib/semverse/constraint.rb', line 239

def satisfies?(target)
  target = Version.coerce(target)

  return false if !version.zero? && greedy_match?(target)

  compare(target)
end

#to_sObject



265
266
267
268
269
270
271
272
# File 'lib/semverse/constraint.rb', line 265

def to_s
  out =  "#{operator} #{major}"
  out << ".#{minor}" if minor
  out << ".#{patch}" if patch
  out << "-#{pre_release}" if pre_release
  out << "+#{build}" if build
  out
end