Ruby에서 버전을 비교하는 방법은 무엇입니까?


119

일부 버전 문자열을 비교하고 최신 버전을 얻기 위해 코드를 작성하는 방법은 무엇입니까?

예를 들어 다음과 같은 문자열 : '0.1', '0.2.1', '0.44'.


예전에 비관적 인 버전 제약을 비교해야했지만 RubyGems에 의존하고 싶지 않았기 때문에 Version필요한 모든 작업을 수행하는 간단한 클래스를 작성했습니다 . shorts.jeffkreeftmeijer.com/2014/…
jkreeftmeijer

답변:


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

14
Gem::Version...구문은 제가 보석을 설치해야 할 것이라고 생각했다. 그러나 그것은 필요하지 않았습니다.
Guillaume

참고 : 이것은 Ruby 1.x에서 정의되지 않은 변수 'Gem'에 대한 오류를 제공하지만 Ruby 2.x에서는 예상대로 작동합니다. 제 경우에는 Ruby 1.x (2.x가 아님)에 대해 RUBY_VERSION을 확인했기 때문에 John Hyland 및 DigitalRoss처럼 RUBY_VERSION.split ( '.') [0] == "1"을 수행했습니다.
uliwitness

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

6
@uliwitness는 Ruby 1.x 대 2.x가 아닙니다. 1.8.x 대 1.9+입니다. Ruby부터 1.8.x까지는 기본적으로 rubygems가 포함되지 않습니다. 네임 스페이스에 require 'rubygems'액세스하려면 이 필요합니다 Gem. 그러나 1.9부터는 자동으로 포함됩니다.
Mark Reed

이것은 와일드 카드 NPM 버전을 비교하는 데에도 효과적이었습니다. +1
deepelement 2014-09-07

35

비관적 버전 제약 을 확인해야하는 경우 다음 과 같이 Gem :: Dependency를 사용할 수 있습니다 .

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

1
최신 버전은 이름에 문자열이 필요한 것으로 보입니다. 빈 문자열은 잘, 즉 작동Gem::Dependency.new('', '~> 1.4.5').match?('', '1.4.6beta4')
피터는 WageNet

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

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은 그것을 추악하게 만들지 만 기본적으로 this vs Gem :: Version 사용은 약 두 배 더 빠릅니다.
Shai

하지만 버전은 배열 이 아닙니다 .
Sergio Tulentsev

15

Versionomygem을 사용할 수 있습니다 ( 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
"바퀴를 재발 명하지 마십시오". 간단하기 때문에 프로그래머가 작업을하지 않고 생각하지 않았 음을 의미하지는 않습니다. gem을 사용하고, 코드를 읽고, 그것으로부터 배우고, 더 크고 더 나은 것으로 넘어 가세요!
Trevoke 2010 년

종속성 관리 및 버전 유지 관리는 어려운 문제이며 두 버전을 비교하는 작업보다 훨씬 더 어려울 수 있습니다. 이 경우에 2 개의 종속성을 더 도입하는 것이 최후의 수단이되어야한다는 데 전적으로 동의합니다.
kkodev

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 (비교 가능)
Wayne Conrad

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 확장이 필요한 versionomy보다 훨씬 낫습니다!?
W. Andrew Loe III

나는 'max'가 작동하지 않을 것이라고 생각한다. 그것은 0.5가 0.44보다 크다고보고 할 것이다. semver 버전을 비교할 때 사실이 아닙니다.
Flo Woo

2
이것은 최신 Gem :: Version에서 수정 된 것 같습니다. 0.44는 이제 0.5보다 높은 것으로 올바르게보고됩니다.
플로 우

5

보석을 사용하지 않고 손으로하고 싶다면 조금 엉망이기는하지만 다음과 같은 것이 작동 할 것입니다.

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

기본적으로 각 버전 문자열을 정수 배열로 변환 한 다음 배열 비교 연산자 를 사용합니다 . 누군가가 유지 관리해야 할 코드에 들어가면 좀 더 쉽게 따라 할 수 있도록 구성 요소 단계를 나눌 수 있습니다.


-1

나는 같은 문제가 있었고 Gem-less 버전 비교기를 원했고 다음과 같이 생각했습니다.

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.