2 つのバージョン文字列を比較すると、to_f
うまく機能しません。
> "1.5.8".to_f > "1.5.7".to_f
=> false
文字列比較の方が優れていますが、常に正しいとは限りません。
> "1.5.8" > "1.5.7"
=> true
> "1.5.8" > "1.5.9"
=> false
> "1.5.8" > "1.5.10" # oops!
=> true
バージョン文字列を正しく比較するには?
2 つのバージョン文字列を比較すると、to_f
うまく機能しません。
> "1.5.8".to_f > "1.5.7".to_f
=> false
文字列比較の方が優れていますが、常に正しいとは限りません。
> "1.5.8" > "1.5.7"
=> true
> "1.5.8" > "1.5.9"
=> false
> "1.5.8" > "1.5.10" # oops!
=> true
バージョン文字列を正しく比較するには?
アイデア: (宇宙船オペレーターObject#<=>としても知られる) のように動作するが、カスタム ブロックを取るObject#compare_by
メソッドを作成します。compare
class Object
def compare_by(other)
yield(self) <=> yield(other)
end
end
>> "1.5.2".compare_by("1.5.7") { |s| s.split(".").map(&:to_i) }
#=> -1
compare
メソッドに基づいて、より具体的なアプローチを取ることもできます。
class String
def compare_by_fields(other, fieldsep = ".")
cmp = proc { |s| s.split(fieldsep).map(&:to_i) }
cmp.call(self) <=> cmp.call(other)
end
end
>> "1.5.8".compare_by_fields("1.5.8")
#=> 0
個人的には、おそらくVersionomy gem を使用するだけで、この特定の車輪を再発明する必要はありません。
例:
require 'versionomy'
v1 = Versionomy.parse("1.5.8")
v2 = Versionomy.parse("1.5.10")
v2 > v1
#=> true
最初に、バージョンのさまざまな部分を分割することから始めます。
v1 = "1.5.8"
v2 = "1.5.7"
v1_arr = v1.split(".")
=> ["1", "5", "8"]
v2_arr = v2.split(".")
=> ["1", "5", "7"]
v1_arr.size.times do |index|
if v1_arr[index] != v2_arr[index]
# compare the values at the given index. Don't forget to use to_i!
break
end
end