課題
アプリケーションのバージョン番号について、以上(「以下」「より大きい」「より小さい」「同じ」)を判定したい。
例えば、 1.3.2
は 1.2.3
より大きい(一般的には新しい)、1.3.2
は 2.3.2
より小さい(一般的には古い)というな判定をしたい。
ふわっとした仕様
バージョニングルールはソフトウェアによって色んなパターンがあるようです。ここではバージョンにあれこれ考えを巡らせてみる - Qiita の「数字によるバージョン」を参考に次の内容で対応することにします。
- 同じアプリケーションの2つのバージョン番号同士について「以上」「以下」「より大きい」「より小さい」を判定できる
- バージョン番号は
.
で区切られた文字列- 数字以外の文字列は無視する
- メジャー・マイナーの2階層、加えてビルドとリビジョンの4階層だけでなく、複数階層パターンに対応する
- 比較対象のバージョニングルールは階層の数を除いて途中で変更されないこと
バージョン番号の例
1
0.3
0.0.1
My Software 0.0.1
シュッと実装
比較メソッドを実装する際に、Ruby の Comaprable
モジュールを使います。
Comparable
モジュールの比較演算子を定義する事で、通常の数値比較のように直感的なインターフェースになります(テストケースを参照)。
require 'test/unit'
class VersionComparator
include Comparable
attr_reader :splited_version
def initialize(version)
@splited_version = version.gsub(/[^\d.]+/, '').split('.').map(&:to_i)
end
def <=>(other)
@splited_version <=> other.splited_version
end
end
class TestVersionComparator < Test::Unit::TestCase
def test_ufo
# test <
assert_equal true, VersionComparator.new('0.0.1') < VersionComparator.new('0.0.2')
assert_equal false, VersionComparator.new('0.0.5') < VersionComparator.new('0.0.2')
assert_equal true, VersionComparator.new('0.0.5') < VersionComparator.new('0.1.2')
assert_equal false, VersionComparator.new('0.0.5') < VersionComparator.new('0.0.5')
assert_equal false, VersionComparator.new('0.5') < VersionComparator.new('0.0.5')
assert_equal true, VersionComparator.new('0.0.5') < VersionComparator.new('0.5')
assert_equal true, VersionComparator.new('My Software 0.0.1') < VersionComparator.new('My Software 0.0.2')
# test <=
assert_equal true, VersionComparator.new('0.0.1') <= VersionComparator.new('0.0.2')
assert_equal false, VersionComparator.new('0.0.5') <= VersionComparator.new('0.0.2')
assert_equal true, VersionComparator.new('0.0.5') <= VersionComparator.new('0.1.2')
assert_equal true, VersionComparator.new('0.0.5') <= VersionComparator.new('0.0.5')
assert_equal false, VersionComparator.new('0.5') <= VersionComparator.new('0.0.5')
assert_equal true, VersionComparator.new('0.0.5') <= VersionComparator.new('0.5')
assert_equal true, VersionComparator.new('My Software 0.0.1') <= VersionComparator.new('My Software 0.0.2')
# test >
assert_equal false, VersionComparator.new('0.0.1') > VersionComparator.new('0.0.2')
assert_equal true, VersionComparator.new('0.0.5') > VersionComparator.new('0.0.2')
assert_equal false, VersionComparator.new('0.0.5') > VersionComparator.new('0.1.2')
assert_equal false, VersionComparator.new('0.0.5') > VersionComparator.new('0.0.5')
assert_equal true, VersionComparator.new('0.5') > VersionComparator.new('0.0.5')
assert_equal false, VersionComparator.new('0.0.5') > VersionComparator.new('0.5')
assert_equal false, VersionComparator.new('My Software 0.0.1') > VersionComparator.new('My Software 0.0.2')
# test >=
assert_equal false, VersionComparator.new('0.0.1') >= VersionComparator.new('0.0.2')
assert_equal true, VersionComparator.new('0.0.5') >= VersionComparator.new('0.0.2')
assert_equal false, VersionComparator.new('0.0.5') >= VersionComparator.new('0.1.2')
assert_equal true, VersionComparator.new('0.0.5') >= VersionComparator.new('0.0.5')
assert_equal true, VersionComparator.new('0.5') >= VersionComparator.new('0.0.5')
assert_equal false, VersionComparator.new('0.0.5') >= VersionComparator.new('0.5')
assert_equal false, VersionComparator.new('My Software 0.0.1') >= VersionComparator.new('My Software 0.0.2')
# test ==
assert_equal true, VersionComparator.new('0.0.1') == VersionComparator.new('0.0.1')
assert_equal true, VersionComparator.new('My Software 0.0.2') == VersionComparator.new('My Software 0.0.2')
end
end