Skip to content

Instantly share code, notes, and snippets.

@jpignata
Created June 16, 2020 01:12
Show Gist options
  • Select an option

  • Save jpignata/55b5d85e3ea25d7ed566edafc02e14c7 to your computer and use it in GitHub Desktop.

Select an option

Save jpignata/55b5d85e3ea25d7ed566edafc02e14c7 to your computer and use it in GitHub Desktop.

Revisions

  1. jpignata renamed this gist Jun 16, 2020. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. jpignata created this gist Jun 16, 2020.
    139 changes: 139 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,139 @@
    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