Class: Vers::Constraint
- Inherits:
-
Object
- Object
- Vers::Constraint
- 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 =
1000
Instance Attribute Summary collapse
-
#operator ⇒ Object
readonly
Returns the value of attribute operator.
-
#version ⇒ Object
readonly
Returns the value of attribute version.
Class Method Summary collapse
-
.parse(constraint_string) ⇒ Constraint
Parses a constraint string into operator and version components.
-
.parse_uncached(constraint_string) ⇒ Object
Internal uncached parsing method.
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#exclusion? ⇒ Boolean
Returns true if this is an exclusion constraint (!=).
- #hash ⇒ Object
-
#initialize(operator, version) ⇒ Constraint
constructor
Creates a new constraint with the given operator and version.
-
#satisfies?(version_string) ⇒ Boolean
Checks if a version satisfies this constraint.
-
#to_interval(scheme: nil) ⇒ Interval
Converts this constraint to an interval representation.
-
#to_s ⇒ String
String representation of this constraint.
Constructor Details
#initialize(operator, version) ⇒ Constraint
Creates a new constraint with the given operator and version
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
#operator ⇒ Object (readonly)
Returns the value of attribute operator.
28 29 30 |
# File 'lib/vers/constraint.rb', line 28 def operator @operator end |
#version ⇒ Object (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">
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/vers/constraint.rb', line 56 def self.parse(constraint_string) # Bound input length before cache lookup so oversized strings never # become cache keys and never trigger eviction. if constraint_string.length > Version::MAX_LENGTH raise ArgumentError, "Constraint string too long (#{constraint_string.length} > #{Version::MAX_LENGTH})" end return @@constraint_cache[constraint_string] if @@constraint_cache.key?(constraint_string) if @@constraint_cache.size >= @@cache_size_limit keys = @@constraint_cache.keys keys.first(keys.size / 2).each { |k| @@constraint_cache.delete(k) } end constraint = parse_uncached(constraint_string) @@constraint_cache[constraint_string] = constraint constraint end |
.parse_uncached(constraint_string) ⇒ Object
Internal uncached parsing method
78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/vers/constraint.rb', line 78 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
162 163 164 |
# File 'lib/vers/constraint.rb', line 162 def ==(other) other.is_a?(Constraint) && operator == other.operator && version == other.version end |
#exclusion? ⇒ Boolean
Returns true if this is an exclusion constraint (!=)
124 125 126 |
# File 'lib/vers/constraint.rb', line 124 def exclusion? operator == "!=" end |
#hash ⇒ Object
166 167 168 |
# File 'lib/vers/constraint.rb', line 166 def hash [operator, version].hash end |
#satisfies?(version_string) ⇒ Boolean
Checks if a version satisfies this constraint
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/vers/constraint.rb', line 134 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_interval(scheme: nil) ⇒ Interval
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]
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/vers/constraint.rb', line 101 def to_interval(scheme: nil) case operator when "=" Interval.exact(version, scheme: scheme) when "!=" # != constraints need special handling in ranges - they create exclusions nil when ">" Interval.greater_than(version, inclusive: false, scheme: scheme) when ">=" Interval.greater_than(version, inclusive: true, scheme: scheme) when "<" Interval.less_than(version, inclusive: false, scheme: scheme) when "<=" Interval.less_than(version, inclusive: true, scheme: scheme) end end |
#to_s ⇒ String
String representation of this constraint
158 159 160 |
# File 'lib/vers/constraint.rb', line 158 def to_s "#{operator}#{version}" end |