Dot Versions

Posted by Jason King 11 months ago

Ok, so there are chunks of code I write again and again, and this is one of them:

class Version 
  include Comparable
  def initialize(_v); @v = _v.split('.').map(&:to_i); end
  def <=>(_v); @v <=> _v.split('.').map(&:to_i); end
  def to_s; @v.join('.'); end
end

I was going to reformat it, so that the methods are all newlined properly, but actually - you should have to put up with looking at it like I look at it.

So, what does this do? Well, check this irb out:

irb(main):001:0> '3.6.8' > '3.6.4'
=> true
irb(main):002:0> '3.6.8' > '3.6.10'
=> true
irb(main):003:0> # Ack!  Should be false

We get a true because they’re strings, so they’re being compared alphabetically. Rescue us wonderful Version class:

irb(main):004:0*   class Version 
irb(main):005:1>     include Comparable
irb(main):006:1>     def initialize(_v); @v = _v.split('.').map(&:to_i); end
irb(main):007:1>     def <=>(_v); @v <=> _v.split('.').map(&:to_i); end
irb(main):008:1>     def to_s; @v.join('.'); end
irb(main):009:1>   end
=> nil
irb(main):010:0> v = Version.new('3.6.8')
=> #<Version:0x547e0 @v=[3, 6, 8]>
irb(main):011:0> v > '3.6.4'
=> true
irb(main):012:0> v > '3.6.10'
=> false

Yay. That’s it, you can get it here.

Comments

There are 2 comments on this post. Post yours →

Hongli Lai about 9 hours later

You could also use Gem::Version (part of RubyGems). It’s pretty much the same thing.

Jason King about 20 hours later

Yeah, good point. I still miss the simplicity of comparing a plain string version against the object, ie.:

irb(main):001:0> x = Gem::Version.new('3.6.8')
=> #
irb(main):002:0> x > '3.6.10'
ArgumentError: comparison of Gem::Version with String failed
    from (irb):2:in `>'
    from (irb):2

…but maybe with a little extension we can do what we want with Gem::Version.

irb(main):003:0> class Gem::Version
irb(main):004:1>   alias_method 'orig_cmp', ''
irb(main):005:1>   def (v)
irb(main):006:2>     unless( _r = orig_cmp(v))
irb(main):007:3>       _r = orig_cmp(Gem::Version.new(v))
irb(main):008:3>     end
irb(main):009:2>     return _r
irb(main):010:2>   end
irb(main):011:1> end
=> nil

…and now:

irb(main):012:0> x > '3.6.10'
=> false

So, that’s not bad either, code here.

Post a comment

Required fields look like this.

Markdown enabled. See the syntax rules for help.