Rubyでバージョンを比較する方法は?


119

一部のバージョンの文字列を比較して最新のコードを取得するコードを作成する方法は?

たとえば、次のような文字列です'0.1', '0.2.1', '0.44'


私はシンプルに書いたので、私はしばらく前に悲観的なバージョンの制約を比較するために必要な、私はそれを行うにはRubyGemsのに依存したくなかったVersion:すべてのIの必要性を行うクラスshorts.jeffkreeftmeijer.com/2014/...
jkreeftmeijer

回答:


230
Gem::Version.new('0.4.1') > Gem::Version.new('0.10.1')

14
Gem::Version...構文は、私が宝石をインストールする必要があるだろうと思いました。しかし、それは必須ではありませんでした。
ギヨーム

注:これにより、Ruby 1.xでは未定義の変数「Gem」に関するエラーが発生しますが、Ruby 2.xでは期待どおりに機能します。私の場合、私はRUBY_VERSIONがRuby 1.x(2.xではない)であるかどうかをチェックしていたため、John HylandやDigitalRossのようにRUBY_VERSION.split( '。')[0] == "1"を実行しました。
公証人2013年

5
Gem::Dependency.new(nil, '~> 1.4.5').match?(nil, '1.4.6beta4')
levinalex 2013

6
@uliwitness Ruby 1.xと2.xではありません。1.8.x対1.9+です。1.8.xまでのRubyには、デフォルトでrubygemsは含まれていません。名前空間にrequire 'rubygems'アクセスするにはが必要ですGem。ただし、1.9以降は自動的に含まれます。
マークリード

これは、ワイルドカードNPMバージョンの比較にも役立ちました。+1
ディープエレメント2014


19
class Version < Array
  def initialize s
    super(s.split('.').map { |e| e.to_i })
  end
  def < x
    (self <=> x) < 0
  end
  def > x
    (self <=> x) > 0
  end
  def == x
    (self <=> x) == 0
  end
end
p [Version.new('1.2') < Version.new('1.2.1')]
p [Version.new('1.2') < Version.new('1.10.1')]

3
ここでの他のいくつかの回答と同様に、数値ではなく文字列比較を実行しているように見えます。これにより、「0.10」や「0.4」などのバージョンを比較するときに問題が発生します。
John Hyland、2010年

7
gemのインストールを必要としない簡潔なソリューションに賛成。
JD。

2
価値のあること: vers = (1..3000000).map{|x| "0.0.#{x}"}; 'ok' puts Time.now; vers.map{|v| ComparableVersion.new(v) }.sort.first; puts Time.now # 24 seconds 2013-10-29 13:36:09 -0700 2013-10-29 13:36:33 -0700 => nil puts Time.now; vers.map{|v| Gem::Version.new(v) }.sort.first; puts Time.now # 41 seconds 2013-10-29 13:36:53 -0700 2013-10-29 13:37:34 -0700 コードblobは見苦しくなりますが、基本的に、これとGem :: Versionを使用すると、約2倍速くなります。
Shai

ただし、バージョンは配列ではありません
セルジオトゥレンツェフ2017年

15

あなたは使用することができますVersionomy宝石(で利用可能githubのを):

require 'versionomy'

v1 = Versionomy.parse('0.1')
v2 = Versionomy.parse('0.2.1')
v3 = Versionomy.parse('0.44')

v1 < v2  # => true
v2 < v3  # => true

v1 > v2  # => false
v2 > v3  # => false

4
私はそれを見てきましたが、本当に簡単なことを行うには2つの宝石を使用する必要があります。それを最後の選択肢として使いたいです。
user239895 2010年

8
「車輪を再発明しないでください」。シンプルだからといって、プログラマーが仕事をしなかったり、考えたりしなかったわけではありません。宝石を使用し、コードを読み、それから学びます-そして、より大きくより良いものに移りましょう!
2010年

依存関係の管理とバージョンの保守は難しい問題であり、2つのバージョンを比較する作業よりもはるかに難しいでしょう。この場合、さらに2つの依存関係を導入することは最後の手段となることに同意します。
kkodev 2017

10

私はするだろう

a1 = v1.split('.').map{|s|s.to_i}
a2 = v2.split('.').map{|s|s.to_i}

その後、行うことができます

a1 <=> a2

(そしておそらく他のすべての「通常の」比較)。

... <または>テストが必要な場合は、たとえば

(a1 <=> a2) < 0

または、必要に応じて、関数のラッピングをさらに行います。


1
Array.class_eval {include Comparable}は、すべての配列を<、>などに応答させます。または、特定の配列に対してこれを実行したいだけの場合:a = [1、2]; a.extend(比較可能)
ウェインコンラッド

4
この解決策で私が見つけた問題は、「1.2.0」が「1.2」より大きいことを返すということです
Maria S

9

Gem::Version ここに行く簡単な方法です:

%w<0.1 0.2.1 0.44>.map {|v| Gem::Version.new v}.max.to_s
=> "0.44"

c-extensionを必要とするバージョン管理よりもはるかに優れています!?
W. Andrew Loe III 2013

「max」が機能するとは思いません。0.5は0.44よりも大きいと報告されます。これは、semverのバージョンを比較する場合には当てはまりません。
Flo Woo

2
これは最新のGem :: Versionで修正されたようです。現在、0.44は0.5より高いと正しく報告されています。
Flo Woo

5

宝石を使用せずに手作業で行いたい場合は、次のようなものがうまくいくはずですが、少し見栄えがします。

versions = [ '0.10', '0.2.1', '0.4' ]
versions.map{ |v| (v.split '.').collect(&:to_i) }.max.join '.'

基本的に、各バージョン文字列を整数の配列に変換してから、配列比較演算子を使用します。誰かが保守する必要があるコードでこれを行っている場合は、コンポーネントのステップを分割して、少し簡単に実行できるようにすることができます。


-1

私は同じ問題を抱えていました、ジェムレスバージョンのコンパレータが欲しかったので、これを思いつきました:

def compare_versions(versionString1,versionString2)
    v1 = versionString1.split('.').collect(&:to_i)
    v2 = versionString2.split('.').collect(&:to_i)
    #pad with zeroes so they're the same length
    while v1.length < v2.length
        v1.push(0)
    end
    while v2.length < v1.length
        v2.push(0)
    end
    for pair in v1.zip(v2)
        diff = pair[0] - pair[1]
        return diff if diff != 0
    end
    return 0
end
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.