Skip to content

Commit

Permalink
feat(semantic_version): add valid? & parse? with version pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
devnote-dev committed Oct 1, 2024
1 parent 46ca8fb commit 293ade4
Showing 1 changed file with 33 additions and 13 deletions.
46 changes: 33 additions & 13 deletions src/semantic_version.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
struct SemanticVersion
include Comparable(self)

VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)
(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?
(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/x

# The major version of this semantic version
getter major : Int32

Expand All @@ -19,7 +23,18 @@ struct SemanticVersion
# The pre-release version of this semantic version
getter prerelease : Prerelease

# Parses a `SemanticVersion` from the given semantic version string
# Checks if *str* is a valid semantic version.
#
# ```
# require "semantic_version"
#
# SemanticVersion.valid?("1.15.0") # => true
# SemanticVersion.valid?("1.2") # => false
def self.valid?(str : String) : Bool
VERSION_PATTERN.matches?(str)
end

# Parses a `SemanticVersion` from the given semantic version string.
#
# ```
# require "semantic_version"
Expand All @@ -30,18 +45,23 @@ struct SemanticVersion
#
# Raises `ArgumentError` if *str* is not a semantic version.
def self.parse(str : String) : self
if m = str.match /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)
(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?
(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/x
major = m[1].to_i
minor = m[2].to_i
patch = m[3].to_i
prerelease = m[4]?
build = m[5]?
new major, minor, patch, prerelease, build
else
raise ArgumentError.new("Not a semantic version: #{str.inspect}")
end
parse?(str) || raise ArgumentError.new("Not a semantic version: #{str.inspect}")
end

# Parses a `SemanticVersion` from the given semantic version string.
#
# ```
# require "semantic_version"
#
# semver = SemanticVersion.parse("2.61.4")
# semver # => #<SemanticVersion:0x55b3667c9e70 @major=2, @minor=61, @patch=4, ... >
# ```
#
# Returns `nil` if *str* is not a semantic version.
def self.parse?(str : String) : self?
return unless m = str.match VERSION_PATTERN

new m[1].to_i, m[2].to_i, m[3].to_i, m[4]?, m[5]?
end

# Creates a new `SemanticVersion` instance with the given major, minor, and patch versions
Expand Down

0 comments on commit 293ade4

Please sign in to comment.