How does Ruby compare semantic version strings?
It checks the ordinal of each individual character in the string. It stops the first time there is a mismatch on the same index. The higher the ordinal, the "bigger" the character is. Basically, it something like:
first_string.chars.map(&:ord) >= second_string.chars.map(&:ord)
As pointed in the comments, this doesn't lead to natural ordering, hence why people use Gem::Version
:
'11' > '9' # => false
Determine order of version numbers in ruby
The natural first step is to split the version "numbers" into numeric components:
v1 = '2.1.10'.split('.').map(&:to_i) # [ 2, 1, 10 ]
v2 = '2.1.3'.split('.').map(&:to_i) # [ 2, 1, 3 ]
Then note that Array#<=>
compares arrays element by element so you can use it to whip up a quick'n'dirty <
implementation for arrays. You can use <=>
to monkey patch #<
and #>
methods into Array or just do it inline:
if (v1 <=> v2) < 0
# v1 < v2
elsif (v1 <=> v2) > 0
# v1 > v2
else
# v1 == v2
end
<=>
is specified to return -1
, 0
, or +1
so you could use
if (v1 <=> v2) == -1
# v1 < v2
elsif (v1 <=> v2) == 1
# v1 > v2
else
# v1 == v2
end
too; I prefer the first version as the < 0
and > 0
are more suggestive as to the intent.
You'd probably want to hide all that behind a method somewhere or maybe even monkey patch String
to have a version comparing method.
The above also means that 2.1
is a lower version number than, say, 2.1.11
so you don't have to worry about having the same number of components.
I am assuming that you're working with versions whose components are decimal numbers.
What is the best approach to compare two files dates in Ruby?
mtime
gives you a Time, not a string.
You can "subtract" Time objects, resulting in seconds. If a and b are both files, you can do something like
(b.mtime - a.mtime).between?(0, 120)
which would return false if b is more then 2 minutes older than a.
Version sort (with alphas, betas, etc.) in ruby
Ruby ships with the Gem class, which knows about versions:
ar = ['10.0.0b12', '10.0.0b3', '10.0.0a2', '9.0.10', '9.0.3']
p ar.sort_by { |v| Gem::Version.new(v) }
# => ["9.0.3", "9.0.10", "10.0.0a2", "10.0.0b3", "10.0.0b12"]
How to check if the RUBY_VERSION is greater than a certain version?
Ruby's Gem library can do version number comparisons:
require 'rubygems' # not needed with Ruby 1.9+
ver1 = Gem::Version.new('1.8.7') # => #<Gem::Version "1.8.7">
ver2 = Gem::Version.new('1.9.2') # => #<Gem::Version "1.9.2">
ver1 <=> ver2 # => -1
See http://rubydoc.info/stdlib/rubygems/1.9.2/Gem/Version for more info.
How to find a bigger version number?
An idea: create a Object#compare_by
method that behaves like compare
(aka the spaceship operator Object#<=>) but takes a custom block:
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
You can also take a more specific approach still based on the compare
method:
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
Related Topics
Welcome/Home Page in Ruby on Rails - Best Practice
Ubuntu Rails Install Fails on Zlib
Using Memcache Client with Ruby
Select Arrays Between Date Ranges with Ruby
Capturing Groups Don't Work as Expected with Ruby Scan Method
Can You Eval Code in the Context of a Caller in Ruby
Uninstall Old Versions of Ruby Gems
Nokogiri Was Built Against Libxml Version 2.7.7, But Has Dynamically Loaded 2.7.3
Equivalent of "Continue" in Ruby
Portable Ruby on Rails Environment
How to "Soft Delete" User with Devise
Rails, Postgresql, and History Triggers
Best Solution for Authentication in Ruby on Rails
Circular Dependency Detected While Autoloading Constant User
What Does 'Def Self.Function' Name Mean
Differencebetween 'After_Create' and 'After_Save' and When to Use Which