Class: SemanticPuppet::VersionRange
- Defined in:
- lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb
Overview
A Semantic Version Range.
Defined Under Namespace
Classes: AbstractRange, AllRange, ComparatorRange, EqRange, GtEqRange, GtRange, LtEqRange, LtRange, MinMaxRange
Constant Summary collapse
- UPPER_X =
'X'.freeze
- LOWER_X =
'x'.freeze
- STAR =
'*'.freeze
- NR =
'0|[1-9][0-9]*'.freeze
- XR =
'(x|X|\*|' + NR + ')'.freeze
- XR_NC =
'(?:x|X|\*|' + NR + ')'.freeze
- PART =
'(?:[0-9A-Za-z-]+)'.freeze
- PARTS =
PART + '(?:\.' + PART + ')*'.freeze
- QUALIFIER =
'(?:-(' + PARTS + '))?(?:\+(' + PARTS + '))?'.freeze
- QUALIFIER_NC =
'(?:-' + PARTS + ')?(?:\+' + PARTS + ')?'.freeze
- PARTIAL =
XR_NC + '(?:\.' + XR_NC + '(?:\.' + XR_NC + QUALIFIER_NC + ')?)?'.freeze
- SIMPLE =
The ~> isn’t in the spec but allowed
'([<>=~^]|<=|>=|~>|~=)?(' + PARTIAL + ')'.freeze
- SIMPLE_EXPR =
/\A#{SIMPLE}\z/.freeze
- SIMPLE_WITH_EXTRA_WS =
'([<>=~^]|<=|>=)?\s+(' + PARTIAL + ')'.freeze
- SIMPLE_WITH_EXTRA_WS_EXPR =
/\A#{SIMPLE_WITH_EXTRA_WS}\z/.freeze
- HYPHEN =
'(' + PARTIAL + ')\s+-\s+(' + PARTIAL + ')'.freeze
- HYPHEN_EXPR =
/\A#{HYPHEN}\z/.freeze
- PARTIAL_EXPR =
/\A#{XR}(?:\.#{XR}(?:\.#{XR}#{QUALIFIER})?)?\z/.freeze
- LOGICAL_OR =
/\s*\|\|\s*/.freeze
- RANGE_SPLIT =
/\s+/.freeze
- EMPTY_RANGE =
A range that matches no versions
VersionRange.new([], nil).freeze
- ALL_RANGE =
VersionRange.new([AllRange::SINGLETON], '*')
Instance Attribute Summary collapse
-
#ranges ⇒ Object
readonly
private
Provides read access to the ranges.
Class Method Summary collapse
-
.parse(range_string, strict_semver = true) ⇒ VersionRange
Parses a version range string into a comparable VersionRange instance.
Instance Method Summary collapse
-
#begin ⇒ Version
Returns the version that denotes the beginning of this range.
-
#end ⇒ Version
Returns the version that denotes the end of this range.
- #eql?(range) ⇒ Boolean (also: #==)
-
#exclude_begin? ⇒ Boolean
Returns ‘true` if the beginning is excluded from the range.
-
#exclude_end? ⇒ Boolean
Returns ‘true` if the end is excluded from the range.
- #hash ⇒ Object
-
#include?(version) ⇒ Boolean
(also: #member?, #cover?, #===)
‘true` if the given version is included in the range.
-
#initialize(ranges, string, exclude_end = nil) ⇒ VersionRange
constructor
private
Creates a new version range.
-
#inspect ⇒ String
Returns a canonical string representation of this range, assembled from the internal matchers.
-
#intersection(other) ⇒ VersionRange
(also: #&)
Computes the intersection of a pair of ranges.
-
#to_s ⇒ String
Returns a string representation of this range.
Constructor Details
#initialize(from, to, exclude_end = false) ⇒ VersionRange #initialize(ranges, string) ⇒ VersionRange
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Creates a new version range
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 226 def initialize(ranges, string, exclude_end = nil) if ranges.is_a?(Array) @strict_semver = exclude_end.nil? ? true : exclude_end else lb = GtEqRange.new(ranges) if exclude_end ub = LtRange.new(string) string = ">=#{string} <#{ranges}" else ub = LtEqRange.new(string) string = "#{string} - #{ranges}" end ranges = [MinMaxRange.create(lb, ub)] @strict_semver = true end ranges.compact! merge_happened = true while ranges.size > 1 && merge_happened # merge ranges if possible merge_happened = false result = [] until ranges.empty? unmerged = [] x = ranges.pop result << ranges.reduce(x) do |memo, y| merged = memo.merge(y) if merged.nil? unmerged << y else merge_happened = true memo = merged end memo end ranges = unmerged end ranges = result.reverse! end ranges = [LtRange::MATCH_NOTHING] if ranges.empty? @ranges = ranges @string = string.nil? ? ranges.join(' || ') : string end |
Instance Attribute Details
#ranges ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Provides read access to the ranges. For internal use only
211 212 213 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 211 def ranges @ranges end |
Class Method Details
.parse(range_string, strict_semver = true) ⇒ VersionRange
Parses a version range string into a comparable SemanticPuppet::VersionRange instance.
Currently parsed version range string may take any of the following: forms:
-
Regular Semantic Version strings
-
ex. ‘“1.0.0”`, `“1.2.3-pre”`
-
-
Partial Semantic Version strings
-
ex. ‘“1.0.x”`, `“1”`, `“2.X”`, `“3.*”`,
-
-
Inequalities
-
ex. ‘“> 1.0.0”`, `“<3.2.0”`, `“>=4.0.0”`
-
-
Approximate Caret Versions
-
ex. ‘“^1”`, `“^3.2”`, `“^4.1.0”`
-
-
Approximate Tilde Versions
-
ex. ‘“~1.0.0”`, `“~ 3.2.0”`, `“~4.0.0”`
-
-
Inclusive Ranges
-
ex. ‘“1.0.0 - 1.3.9”`
-
-
Range Intersections
-
ex. ‘“>1.0.0 <=2.3.0”`
-
-
Combined ranges
-
ex, ‘“>=1.0.0 <2.3.0 || >=2.5.0 <3.0.0”`
-
65 66 67 68 69 70 71 72 73 74 75 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 103 104 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 65 def self.parse(range_string, strict_semver = true) # Remove extra whitespace after operators. Such whitespace should not cause a split range_set = range_string.gsub(/([><=~^])(?:\s+|\s*v)/, '\1') ranges = range_set.split(LOGICAL_OR) return ALL_RANGE if ranges.empty? new(ranges.map do |range| if range =~ HYPHEN_EXPR MinMaxRange.create(GtEqRange.new(parse_version($1)), LtEqRange.new(parse_version($2))) else # Split on whitespace simples = range.split(RANGE_SPLIT).map do |simple| match_data = SIMPLE_EXPR.match(simple) raise ArgumentError, _("Unparsable version range: \"%{range}\"") % { range: range_string } unless match_data operand = match_data[2] # Case based on operator case match_data[1] when '~', '~>', '~=' parse_tilde(operand) when '^' parse_caret(operand) when '>' parse_gt_version(operand) when '>=' GtEqRange.new(parse_version(operand)) when '<' LtRange.new(parse_version(operand)) when '<=' parse_lteq_version(operand) when '=' parse_xrange(operand) else parse_xrange(operand) end end simples.size == 1 ? simples[0] : MinMaxRange.create(*simples) end end.uniq, range_string, strict_semver).freeze end |
Instance Method Details
#begin ⇒ Version
Returns the version that denotes the beginning of this range.
Since this really is an OR between disparate ranges, it may have multiple beginnings. This method returns ‘nil` if that is the case.
287 288 289 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 287 def begin @ranges.size == 1 ? @ranges[0].begin : nil end |
#end ⇒ Version
Returns the version that denotes the end of this range.
Since this really is an OR between disparate ranges, it may have multiple ends. This method returns ‘nil` if that is the case.
298 299 300 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 298 def end @ranges.size == 1 ? @ranges[0].end : nil end |
#eql?(range) ⇒ Boolean Also known as: ==
271 272 273 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 271 def eql?(range) range.is_a?(VersionRange) && @ranges.eql?(range.ranges) end |
#exclude_begin? ⇒ Boolean
Returns ‘true` if the beginning is excluded from the range.
Since this really is an OR between disparate ranges, it may have multiple beginnings. This method returns ‘nil` if that is the case.
309 310 311 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 309 def exclude_begin? @ranges.size == 1 ? @ranges[0].exclude_begin? : nil end |
#exclude_end? ⇒ Boolean
Returns ‘true` if the end is excluded from the range.
Since this really is an OR between disparate ranges, it may have multiple ends. This method returns ‘nil` if that is the case.
320 321 322 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 320 def exclude_end? @ranges.size == 1 ? @ranges[0].exclude_end? : nil end |
#hash ⇒ Object
276 277 278 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 276 def hash @ranges.hash end |
#include?(version) ⇒ Boolean Also known as: member?, cover?, ===
Returns ‘true` if the given version is included in the range.
326 327 328 329 330 331 332 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 326 def include?(version) if @strict_semver @ranges.any? { |range| range.include?(version) && (version.stable? || range.test_prerelease?(version)) } else @ranges.any? { |range| range.include?(version) || !version.stable? && range.stable? && range.include?(version.to_stable) } end end |
#inspect ⇒ String
Returns a canonical string representation of this range, assembled from the internal matchers.
366 367 368 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 366 def inspect @ranges.join(' || ') end |
#intersection(other) ⇒ VersionRange Also known as: &
Computes the intersection of a pair of ranges. If the ranges have no useful intersection, an empty range is returned.
343 344 345 346 347 348 349 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 343 def intersection(other) raise ArgumentError, _("value must be a %{type}") % { :type => self.class.name } unless other.is_a?(VersionRange) result = @ranges.map { |range| other.ranges.map { |o_range| range.intersection(o_range) } }.flatten result.compact! result.uniq! result.empty? ? EMPTY_RANGE : VersionRange.new(result, nil) end |
#to_s ⇒ String
Returns a string representation of this range. This will be the string that was used when the range was parsed.
357 358 359 |
# File 'lib/puppet/vendor/semantic_puppet/lib/semantic_puppet/version_range.rb', line 357 def to_s @string end |