Skip to content

Instantly share code, notes, and snippets.

@jpignata
Created June 16, 2020 01:12
Show Gist options
  • Save jpignata/55b5d85e3ea25d7ed566edafc02e14c7 to your computer and use it in GitHub Desktop.
Save jpignata/55b5d85e3ea25d7ed566edafc02e14c7 to your computer and use it in GitHub Desktop.
class Version
module Symbol
POSITIVE_INTEGER = 0
ZERO = 1
LETTER = 2
DOT = 3
DASH = 4
PLUS = 5
UNKNOWN = 99
def self.for(character)
case character
when ('1'..'9')
Symbol::POSITIVE_INTEGER
when '0'
Symbol::ZERO
when ('A'..'Z'), ('a'..'z')
Symbol::LETTER
when '.'
Symbol::DOT
when '-'
Symbol::DASH
when '+'
Symbol::PLUS
else
Symbol::UNKNOWN
end
end
end
class Acceptor
STATES = {
start: {
Symbol::POSITIVE_INTEGER => :major,
Symbol::ZERO => :major_end
},
major: {
Symbol::POSITIVE_INTEGER => :major,
Symbol::ZERO => :major,
Symbol::DOT => :minor_start
},
major_end: {
Symbol::DOT => :minor_start
},
minor_start: {
Symbol::POSITIVE_INTEGER => :minor,
Symbol::ZERO => :minor_end
},
minor: {
Symbol::POSITIVE_INTEGER => :minor,
Symbol::ZERO => :minor,
Symbol::DOT => :patch_start
},
minor_end: {
Symbol::DOT => :patch_start
},
patch_start: {
Symbol::POSITIVE_INTEGER => :patch,
Symbol::ZERO => :patch_end
},
patch: {
Symbol::POSITIVE_INTEGER => :patch,
Symbol::ZERO => :patch,
Symbol::DASH => :prerelease,
Symbol::PLUS => :build
},
patch_end: {
Symbol::DASH => :prerelease,
Symbol::PLUS => :build
},
prerelease: {
Symbol::POSITIVE_INTEGER => :prerelease,
Symbol::ZERO => :prerelease,
Symbol::LETTER => :prerelease,
Symbol::DOT => :prerelease_new_identifier,
Symbol::PLUS => :build
},
prerelease_new_identifier: {
Symbol::POSITIVE_INTEGER => :prerelease,
Symbol::ZERO => :prerelease,
Symbol::LETTER => :prerelease
},
build: {
Symbol::POSITIVE_INTEGER => :build,
Symbol::ZERO => :build,
Symbol::LETTER => :build,
Symbol::DOT => :build_new_identifier
},
build_new_identifier: {
Symbol::POSITIVE_INTEGER => :build,
Symbol::ZERO => :build,
Symbol::LETTER => :build
}
}
ACCEPTING = [:patch, :patch_end, :prerelease, :build]
def initialize(candidate)
unless candidate.respond_to?(:chars)
raise ArgumentError, "Invalid argument: #{candidate}"
end
@candidate = candidate
end
def valid?
state = :start
symbols = candidate.chars.map { |character| Symbol.for(character) }
return false if symbols.include?(Symbol::UNKNOWN)
symbols.each do |symbol|
if STATES[state].key?(symbol)
state = STATES[state][symbol]
else
return false
end
end
ACCEPTING.include?(state)
end
private
attr_reader :candidate
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment