From 293ade450aef7a050362cda997d4272d92b1c79a Mon Sep 17 00:00:00 2001 From: devnote-dev Date: Tue, 1 Oct 2024 17:36:56 +0100 Subject: [PATCH] feat(semantic_version): add valid? & parse? with version pattern --- src/semantic_version.cr | 46 +++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/semantic_version.cr b/src/semantic_version.cr index 476360b32a0e..59a87ef036ee 100644 --- a/src/semantic_version.cr +++ b/src/semantic_version.cr @@ -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 @@ -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" @@ -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 # => # + # ``` + # + # 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