Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SemanticVersion.valid? & SemanticVersion.parse? #15051

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions spec/std/semantic_version_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ describe SemanticVersion do
end
end

it "accepts valid versions" do
%w[
1.2.3
1.2.3-2
1.2.3-10
1.2.3-alpha
1.2.3-alpha.2
1.2.3-alpha.10
].each do |version|
SemanticVersion.valid?(version).should be_true
SemanticVersion.parse?(version).should_not be_nil
end
end

it "does not accept bad versions" do
sversions = %w(
1
Expand Down Expand Up @@ -84,6 +98,8 @@ describe SemanticVersion do
99999999999999999999999.999999999999999999.99999999999999999----RC-SNAPSHOT.12.09.1--------------------------------..12
)
sversions.each do |s|
SemanticVersion.valid?(s).should be_false
SemanticVersion.parse?(s).should be_nil
expect_raises(ArgumentError) { SemanticVersion.parse(s) }
end
end
Expand Down
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
devnote-dev marked this conversation as resolved.
Show resolved Hide resolved
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
Loading