Class: Vers::Constraint

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

Overview

Represents a single version constraint (e.g., “>=1.2.3”, “!=2.0.0”)

A constraint consists of an operator and a version. This class handles parsing constraint strings and converting them to intervals.

Examples

constraint = Vers::Constraint.new(">=", "1.2.3")
constraint.operator  # => ">="
constraint.version   # => "1.2.3"
constraint.to_interval # => [1.2.3,+∞)

Constant Summary collapse

OPERATORS =

Valid constraint operators as defined in the vers spec

%w[= != < <= > >=].freeze
OPERATOR_REGEX =

Pre-compiled regex patterns for performance

/\A(!=|>=|<=|[<>=])/
@@constraint_cache =

Cache for parsed constraints

{}
@@cache_size_limit =
500

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(operator, version) ⇒ Constraint

Creates a new constraint with the given operator and version

Parameters:

  • operator (String)

    The constraint operator (=, !=, <, <=, >, >=)

  • version (String)

    The version string

Raises:

  • (ArgumentError)

    if operator is invalid



37
38
39
40
41
42
# File 'lib/vers/constraint.rb', line 37

def initialize(operator, version)
  raise ArgumentError, "Invalid operator: #{operator}" unless OPERATORS.include?(operator)
  
  @operator = operator
  @version = version
end

Instance Attribute Details

#operatorObject (readonly)

Returns the value of attribute operator.



28
29
30
# File 'lib/vers/constraint.rb', line 28

def operator
  @operator
end

#versionObject (readonly)

Returns the value of attribute version.



28
29
30
# File 'lib/vers/constraint.rb', line 28

def version
  @version
end

Class Method Details

.parse(constraint_string) ⇒ Constraint

Parses a constraint string into operator and version components

Examples

Vers::Constraint.parse(">=1.2.3")  # => #<Vers::Constraint:0x... @operator=">=", @version="1.2.3">
Vers::Constraint.parse("!=2.0.0")  # => #<Vers::Constraint:0x... @operator="!=", @version="2.0.0">

Parameters:

  • constraint_string (String)

    The constraint string to parse

Returns:

Raises:

  • (ArgumentError)

    if the constraint string is invalid



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/vers/constraint.rb', line 56

def self.parse(constraint_string)
  # Limit cache size to prevent memory bloat
  if @@constraint_cache.size >= @@cache_size_limit
    @@constraint_cache.clear
  end
  
  # Return cached constraint if available
  return @@constraint_cache[constraint_string] if @@constraint_cache.key?(constraint_string)
  
  constraint = parse_uncached(constraint_string)
  @@constraint_cache[constraint_string] = constraint
  constraint
end

.parse_uncached(constraint_string) ⇒ Object

Internal uncached parsing method



73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/vers/constraint.rb', line 73

def self.parse_uncached(constraint_string)
  # Use regex for faster operator detection
  if match = constraint_string.match(OPERATOR_REGEX)
    operator = match[1]
    version = constraint_string[operator.length..-1].strip
    raise ArgumentError, "Invalid constraint format: #{constraint_string}" if version.empty?
    new(operator, version)
  else
    # No operator found, treat as exact match
    new("=", constraint_string.strip)
  end
end

Instance Method Details

#==(other) ⇒ Object



157
158
159
# File 'lib/vers/constraint.rb', line 157

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

#exclusion?Boolean

Returns true if this is an exclusion constraint (!=)

Returns:

  • (Boolean)


119
120
121
# File 'lib/vers/constraint.rb', line 119

def exclusion?
  operator == "!="
end

#hashObject



161
162
163
# File 'lib/vers/constraint.rb', line 161

def hash
  [operator, version].hash
end

#satisfies?(version_string) ⇒ Boolean

Checks if a version satisfies this constraint

Parameters:

  • version_string (String)

    The version to check

Returns:

  • (Boolean)

    true if the version satisfies the constraint



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/vers/constraint.rb', line 129

def satisfies?(version_string)
  comparison = Version.compare(version_string, version)
  
  case operator
  when "="
    comparison == 0
  when "!="
    comparison != 0
  when ">"
    comparison > 0
  when ">="
    comparison >= 0
  when "<"
    comparison < 0
  when "<="
    comparison <= 0
  end
end

#to_intervalInterval

Converts this constraint to an interval representation

Examples

Vers::Constraint.new(">=", "1.2.3").to_interval  # => [1.2.3,+∞)
Vers::Constraint.new("=", "1.0.0").to_interval   # => [1.0.0,1.0.0]

Returns:

  • (Interval)

    The interval representation of this constraint



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/vers/constraint.rb', line 96

def to_interval
  case operator
  when "="
    Interval.exact(version)
  when "!="
    # != constraints need special handling in ranges - they create exclusions
    nil
  when ">"
    Interval.greater_than(version, inclusive: false)
  when ">="
    Interval.greater_than(version, inclusive: true)
  when "<"
    Interval.less_than(version, inclusive: false)
  when "<="
    Interval.less_than(version, inclusive: true)
  end
end

#to_sString

String representation of this constraint

Returns:

  • (String)

    The constraint as a string



153
154
155
# File 'lib/vers/constraint.rb', line 153

def to_s
  "#{operator}#{version}"
end