Ruby'de sürümler nasıl karşılaştırılır?


120

Bazı sürüm dizelerini karşılaştırmak ve en yenisini almak için bir kod parçası nasıl yazılır?

Örneğin dizeleri gibi: '0.1', '0.2.1', '0.44'.


Bir süre önce kötümser sürüm kısıtlamalarını karşılaştırmam gerekiyordu, ancak bunu yapmak için RubyGems'e güvenmek istemedim, bu yüzden Versionihtiyacım olan her şeyi yapan basit bir sınıf yazdım : Shorts.jeffkreeftmeijer.com/2014/…
jkreeftmeijer

Yanıtlar:


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

14
Gem::Version...Sözdizimi beni bir mücevher yüklenmeleri gerektiğini düşündük yaptı. Ancak gerekli değildi.
Guillaume

Not: Bu, Ruby 1.x'te benim için tanımlanmamış 'Gem' değişkeni hakkında bir hata verir, ancak Ruby 2.x'te beklendiği gibi çalışır. Benim durumumda RUBY_VERSION'ı Ruby 1.x (2.x değil) olup olmadığını kontrol ediyordum, bu yüzden John Hyland ve DigitalRoss'un yaptığı gibi RUBY_VERSION.split ('.') [0] == "1" yaptım.
uliwitness

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

6
@uliwitness Ruby 1.x - 2.x değil; 1.8.x'e karşı 1.9+. Ruby through 1.8.x varsayılan olarak rubygems içermez; ad alanına require 'rubygems'erişmek için bir a ihtiyacınız var Gem. Ancak 1.9'dan itibaren otomatik olarak dahil edilir.
Mark Reed

Bu, joker NPM sürümlerini karşılaştırmak için de işe yaradı. +1
deepelement


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
Buradaki diğer cevapların bazıları gibi, sayısal yerine dizi karşılaştırmaları yapıyormuşsunuz gibi görünüyor, bu da '0.10' ve '0.4' gibi sürümleri karşılaştırırken sorunlara neden olacaktır.
John Hyland

7
Bir mücevher kurmayı gerektirmeyen özlü çözüm için oy verildi.
JD.

2
Değeri ne 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 olursa olsun: Code blob onu çirkinleştiriyor, ancak temelde bu vs Gem :: Version'u kullanmak yaklaşık iki kat daha hızlı.
Shai

Yine de sürüm bir dizi değildir .
Sergio Tulentsev

15

Sen kullanabilirsiniz Versionomymücevher (mevcut 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
Bunu gördüm, ancak gerçekten basit bir şey yapmak için 2 mücevher kullanmamı gerektiriyor. Bunu son seçenek olarak kullanmak istiyorum.
user239895

8
"Tekerleği yeniden icat etmeyin". Basit olması, programcının işe koyup düşünmediği anlamına gelmez. Cevheri kullanın, kodu okuyun ve ondan öğrenin - ve daha büyük ve daha iyi şeylere geçin!
Trevoke

Bağımlılık yönetimi ve sürüm bakımı zor bir sorundur ve muhtemelen 2 sürümü karşılaştırma görevinden çok daha zordur. Bu durumda 2 tane daha bağımlılık getirmenin son çare olması gerektiğine tamamen katılıyorum.
kkodev

10

yapardım

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

O zaman yapabilirsin

a1 <=> a2

(ve muhtemelen tüm diğer "olağan" karşılaştırmalar).

... ve bir <veya >test istiyorsanız, örneğin

(a1 <=> a2) < 0

veya bu kadar eğilimliysen biraz daha fazla işlev paketi yap.


1
Array.class_eval {include Comparable}, tüm dizilerin <,>, vb. Yanıt vermesini sağlar. Veya, bunu sadece belirli dizilere yapmak istiyorsanız: a = [1, 2]; a.extend (Karşılaştırılabilir)
Wayne Conrad

4
Bu çözümde bulduğum sorun, "1.2.0" değerinin "1.2" den daha büyük olduğunu döndürmesidir
Maria S

9

Gem::Version buraya gitmenin kolay yolu:

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

Bir c uzantısı gerektiren versiyonomiden çok daha iyi !?
W.Andrew Loe III

"max" ın işe yarayacağını sanmıyorum .. 0.5'in 0.44'ten büyük olduğunu bildirecek. Semver sürümlerini karşılaştırırken bu doğru değildir.
Flo Woo

2
bu en son Gem :: Sürümünde düzeltilmiş görünüyor. 0,44, şu anda 0,5'ten yüksek olarak doğru şekilde rapor edilmektedir.
Flo Woo

5

Herhangi bir mücevher kullanmadan elle yapmak istiyorsanız, aşağıdaki gibi bir şey işe yaramalıdır, ancak biraz kalıcı görünebilir.

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

Esasen, her sürüm dizesini bir tamsayı dizisine dönüştürür ve ardından dizi karşılaştırma işlecini kullanırsınız . Bu, birisinin sürdürmesi gerekecek kod içine giriyorsa, takip etmesi biraz daha kolay bir şey elde etmek için bileşen adımlarını ayırabilirsiniz.


-1

Aynı problemi yaşadım, Taşsız versiyon karşılaştırıcısı istedim, şununla geldi:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.