Module: Ruby::Rego::Builtins::Semver

Extended by:
RegistryHelpers
Defined in:
lib/ruby/rego/builtins/semver.rb

Overview

Built-in Semantic Versioning helpers (semver.is_valid, semver.compare), matching OPA (which vendors coreos/go-semver). A version is MAJOR.MINOR.PATCH[-PRERELEASE] [+BUILD]; OPA’s parser is lenient — it accepts a leading lowercase “v” and leading zeros in numeric components — but each numeric component must fit in a signed 64-bit integer. is_valid is total over runtime values (a non-string yields false); compare yields undefined for a non-string or invalid version. Build metadata is ignored when comparing; precedence follows SemVer §11.

Intentional divergence: OPA’s semver.compare infinite-loops while comparing two numeric prerelease identifiers in a few cases — most visibly when they are equal in value but differ textually via leading zeros (e.g. “1.0.0-01” vs “1.0.0-1”), and also when one straddles the 64-bit boundary — an upstream coreos/go-semver bug. This implementation compares prerelease identifiers numerically and terminates on every input, returning the correct SemVer result instead of hanging.

Defined Under Namespace

Classes: Version

Constant Summary collapse

SEMVER_FUNCTIONS =
{
  "semver.is_valid" => { arity: 1, handler: :is_valid },
  "semver.compare" => { arity: 2, handler: :compare }
}.freeze
MAX_COMPONENT =

Largest value a numeric component (or numeric prerelease identifier) may take; a larger value is invalid for a component, and is treated as a string identifier in a prerelease (matching coreos/go-semver’s int64 parse).

(2**63) - 1
IDENTIFIERS =

A dot-separated run of [0-9A-Za-z-] identifiers (prerelease or build metadata).

/\A[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*\z/
NUMERIC =

A numeric component / identifier: ASCII digits only (leading zeros allowed).

/\A\d+\z/

Class Method Summary collapse

Methods included from RegistryHelpers

register_configured_functions

Class Method Details

.compare(a_value, b_value) ⇒ Ruby::Rego::NumberValue

Parameters:

Returns:



69
70
71
72
73
# File 'lib/ruby/rego/builtins/semver.rb', line 69

def self.compare(a_value, b_value)
  first = version_arg(a_value, "semver.compare")
  second = version_arg(b_value, "semver.compare")
  NumberValue.new(compare_versions(first, second))
end

.is_valid(value) ⇒ Ruby::Rego::BooleanValue

:reek:NilCheck

Parameters:

Returns:



60
61
62
63
64
# File 'lib/ruby/rego/builtins/semver.rb', line 60

def self.is_valid(value)
  return BooleanValue.new(false) unless value.is_a?(StringValue)

  BooleanValue.new(!parse(value.value).nil?)
end

.register!Ruby::Rego::Builtins::BuiltinRegistry



49
50
51
52
53
# File 'lib/ruby/rego/builtins/semver.rb', line 49

def self.register!
  registry = BuiltinRegistry.instance
  register_configured_functions(registry, SEMVER_FUNCTIONS)
  registry
end