Permalink
Browse files

adding compare method for versions

  • Loading branch information...
1 parent e85a036 commit 1ee15b0e218a32f85f42a51249ba9edfa5931e61 reiz committed Apr 4, 2012
Showing with 249 additions and 2 deletions.
  1. +33 −0 lib/naturalsorter.rb
  2. +1 −1 lib/naturalsorter/version.rb
  3. +149 −0 lib/versioncmp.rb
  4. +25 −1 spec/naturalsorter_spec.rb
  5. +41 −0 spec/versioncmp_spec.rb
View
@@ -1,5 +1,6 @@
require "naturalsorter/version"
require "natcmp"
+require "versioncmp"
# naturalsorter.rb
#
@@ -35,13 +36,45 @@ def self.sort(array, caseinsesitive)
array.sort { |a,b| Natcmp.natcmp(a,b,caseinsesitive) }
end
+ def self.sort_desc(array, caseinsesitive)
+ if (array.nil? || array.empty?)
+ return nil
+ end
+ array.sort { |a, b| Natcmp.natcmp(a,b,caseinsesitive) }
+ end
+
+ def self.sort_version(array, direction)
+ return nil if (array.nil? || array.empty?)
+ if direction.eql? "asc"
+ array.sort { |a,b| Versioncmp.compare( a, b ) }
+ else
+ array.sort { |a,b| Versioncmp.compare( b, a ) }
+ end
+ end
+
# 'Natural order' sort for an array of objects.
def self.sort_by_method(array, method, caseinsesitive)
if (array.nil? || array.empty?)
return nil
end
array.sort { |a,b| Natcmp.natcmp(a.send(method),b.send(method),caseinsesitive) }
end
+
+ def self.sort_version_by_method(array, method, direction)
+ return nil if (array.nil? || array.empty?)
+ if direction.eql? "asc"
+ array.sort { |a,b| Versioncmp.compare(a.send(method), b.send(method)) }
+ else
+ array.sort { |a,b| Versioncmp.compare(b.send(method), a.send(method)) }
+ end
+ end
+
+ def self.sort_desc_by_method(array, method, caseinsesitive)
+ if (array.nil? || array.empty?)
+ return nil
+ end
+ array.sort { |a, b| Natcmp.natcmp(a.send(method),b.send(method),caseinsesitive) }
+ end
end
@@ -1,3 +1,3 @@
module Naturalsorter
- VERSION = "0.1.0"
+ VERSION = "0.2.0"
end
View
@@ -0,0 +1,149 @@
+# versioncmp.rb
+#
+# Natural order comparison of two version strings
+# e.g. "1.10.beta" < "1.10" > "1.9"
+# which does not follow alphabetically
+#
+#
+# This implementation is Copyright (C) 2012 by Robert Reiz
+#
+# This software is provided 'as-is', without any express or implied
+# warranty. In no event will the authors be held liable for any damages
+# arising from the use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software
+# in a product, an acknowledgment in the product documentation would be
+# appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+
+class Versioncmp
+
+ # 'Natural version order' comparison of two version strings
+ def self.compare(a, b)
+
+ offset1 = 0;
+ offset2 = 0;
+
+ for i in 0..100
+ if offset1 >= a.length() || offset2 >= b.length()
+ break
+ end
+
+ part1 = Versioncmp.getAPiece(offset1, a);
+ part2 = Versioncmp.getAPiece(offset2, b);
+
+ offset1 += part1.length() + 1;
+ offset2 += part2.length() + 1;
+
+ if ( part1.match(/^[0-9]+$/) != nil && part2.match(/^[0-9]+$/) != nil )
+ ai = part1;
+ bi = part2;
+ result = Versioncmp.compareInt(ai, bi);
+ if result != 0
+ return result;
+ else
+ next
+ end
+ elsif ( part1.match(/^[0-9]+$/) == nil && part2.match(/^[0-9]+$/) == nil )
+ result = Versioncmp.compareString(part1, part2)
+ if (result != 0)
+ return result
+ else
+ next
+ end
+ else
+ if (part1.match(/^[0-9]+$/) != nil && part2.match(/^[0-9]+$/) == nil)
+ return 1;
+ else
+ return -1;
+ end
+ end
+ end
+ result = Versioncmp.checkForRC(a, b)
+ return result
+ end
+
+ def self.compareInt(ai, bi)
+ return -1 if (ai < bi)
+ return 0 if (ai == bi)
+ return 1
+ end
+
+ def self.compareString(a, b)
+ return 0 if a.eql? b
+ return -1 if a < b
+ return 1
+ end
+
+ def self.checkForRC(a, b)
+ # p "checkForRc #{a} #{b}"
+ big = String.new(a)
+ small = String.new(b)
+ if (a.length() < b.length())
+ big = String.new(b)
+ small = String.new(a)
+ end
+ if (Versioncmp.isRc(big))
+ # p " it is RC #{big}"
+ bigwithoutRc = big.gsub(/\.RC[1-9]*$/, "").gsub(/\.rc[1-9]*$/, "")
+ if (Versioncmp.compareString(bigwithoutRc, small) == 0)
+ # p " it is RC #{bigwithoutRc} -1"
+ return Versioncmp.getRcValue(a, b)
+ end
+ elsif (Versioncmp.isBeta(big))
+ bigwithoutBeta = big.gsub(/\.BETA[1-9]*$/, "").gsub(/\.beta[1-9]*$/, "")
+ if (Versioncmp.compareString(bigwithoutBeta, small) == 0)
+ return Versioncmp.getRcValue(a, b)
+ end
+ elsif (Versioncmp.isPre(big))
+ bigwithoutPre = big.gsub(/\.PRE[1-9]*$/, "").gsub(/\.pre[1-9]*$/, "")
+ if (Versioncmp.compareString(bigwithoutPre, small) == 0)
+ return Versioncmp.getRcValue(a, b)
+ end
+ end
+ return Versioncmp.compareString(big, small);
+ end
+
+ def self.isRc(a)
+ return a.match(/.*RC[1-9]*$/) != nil || a.match(/.*rc[1-9]*$/) != nil;
+ end
+
+ def self.isBeta(a)
+ return a.match(/.*BETA[1-9]*$/) != nil || a.match(/.*beta[1-9]*$/) != nil;
+ end
+
+ def self.isPre(a)
+ return a.match(/.*PRE[1-9]*$/) != nil || a.match(/.*pre[1-9]*$/) != nil;
+ end
+
+ def self.getAPiece(offset, cake)
+ for z in 0..100
+ offsetz = offset + z
+ if offsetz > cake.length()
+ break
+ end
+ p = cake[offset..offset + z]
+ if ( p.match(/^[0-9]+$/) == nil )
+ break
+ end
+ end
+ if z > 0
+ z = z - 1
+ end
+ piece = cake[offset..offset + z ]
+ return piece
+ end
+
+ def self.getRcValue(a, b)
+ return 1 if (a.length() < b.length())
+ return -1
+ end
+
+end
@@ -13,5 +13,29 @@
it "c400b5a1 is a1b5c400" do
Naturalsorter::Sorter.sort_by_method(["a400", "a5", "a1"], "to_s", true).should eql(["a1", "a5", "a400"])
end
-
+
+ it "1.2, 1.1 is 1.1, 1.2" do
+ Naturalsorter::Sorter.sort_version(["0.4", "0.1", "1.1", "1.2", "1.0"], "asc").should eql(["0.1", "0.4", "1.0", "1.1", "1.2"])
+ end
+
+ it "1.2, 1.1 is 1.1, 1.2" do
+ Naturalsorter::Sorter.sort_version(["0.4", "0.1", "1.1", "1.2", "1.0", "1.0.RC1"], "asc").should eql(["0.1", "0.4", "1.0.RC1", "1.0", "1.1", "1.2"])
+ end
+
+ it "1.2, 1.1 is 1.1, 1.2" do
+ Naturalsorter::Sorter.sort_version(["0.4", "0.1", "1.1", "1.2", "1.0", "1.0.RC1"], "desc").should eql(["1.2", "1.1", "1.0", "1.0.RC1", "0.4", "0.1"])
+ end
+
+ it "1.2, 1.1 is 1.1, 1.2" do
+ Naturalsorter::Sorter.sort_version(["1.1", "1.2", "1.0"], "asc").should eql(["1.0", "1.1", "1.2"])
+ end
+
+ it "sort with RC" do
+ Naturalsorter::Sorter.sort_version(["1.1", "1.1.RC1"], "asc").should eql(["1.1.RC1", "1.1"])
+ end
+
+ it "sort with RC" do
+ Naturalsorter::Sorter.sort_version(["1.1.RC1", "1.1", "1.0"], "asc").should eql(["1.0", "1.1.RC1", "1.1"])
+ end
+
end
@@ -0,0 +1,41 @@
+require "naturalsorter"
+
+describe Versioncmp do
+
+ it "smaler" do
+ Versioncmp.compare("1.1", "1.2").should eql(-1)
+ end
+
+ it "bigger" do
+ Versioncmp.compare("1.1", "1.0").should eql(1)
+ end
+
+ it "equal" do
+ Versioncmp.compare("1.1", "1.1").should eql(0)
+ end
+
+ it "equal RC" do
+ Versioncmp.compare("1.1.RC1", "1.1.RC1").should eql(0)
+ end
+
+ it "smaller RC" do
+ Versioncmp.compare("1.1.RC1", "1.1").should eql(-1)
+ end
+
+ it "smaller RC" do
+ Versioncmp.compare("1.1.rc1", "1.1").should eql(-1)
+ end
+
+ it "bigger RC" do
+ Versioncmp.compare("1.1.rc3", "1.1.rc2").should eql(1)
+ end
+
+ it "bigger RC than 1.0" do
+ Versioncmp.compare("1.1.RC1", "1.0").should eql(1)
+ end
+
+ it "bigger RC than 1.0" do
+ Versioncmp.compare("1.1.RC1", "1.1").should eql(-1)
+ end
+
+end

0 comments on commit 1ee15b0

Please sign in to comment.