naturalsorter 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -16,19 +16,40 @@ Because the default sort method does not recognize the numbers in the string. Th
16
16
 
17
17
  ## API
18
18
 
19
- This GEM has just 2 methods
19
+ This GEM has 8 methods
20
20
 
21
21
  `Naturalsorter::Sorter.sort(array, caseinsesitive)`
22
22
 
23
- And this here for more advanced sorting
23
+ `Naturalsorter::Sorter.sort_desc(array, caseinsesitive)`
24
+
25
+ And this here for more advanced sorting. Where you can put in a array of objects and the method which should called on every object for comparison.
24
26
 
25
27
  `Naturalsorter::Sorter.sort_by_method(array, method, caseinsesitive)`
26
28
 
29
+ `Naturalsorter::Sorter.sort_by_method_desc(array, method, caseinsesitive)`
30
+
31
+ This methods are based on a different algo. spezially optimizied for sorting version strings.
32
+
33
+ `Naturalsorter::Sorter.sort_version(array)`
34
+
35
+ `Naturalsorter::Sorter.sort_version_desc(array)`
36
+
37
+ This here is again for an array with objects.
38
+
39
+ `Naturalsorter::Sorter.sort_version_by_method(array, method)`
40
+
41
+ `Naturalsorter::Sorter.sort_version_by_method_desc(array)`
42
+
43
+ Get newest.
44
+
45
+ `Naturalsorter::Sorter.get_newest_version(first, second)`
46
+
47
+
27
48
  ## Installation
28
49
 
29
50
  You should add this line to your Gemfile
30
51
 
31
- `gem 'naturalsorter', '0.1.0'`
52
+ `gem 'naturalsorter', '0.2.0'`
32
53
 
33
54
  and run this command in your app root directory
34
55
 
@@ -46,9 +67,16 @@ If you have more advanced objects you want to sort, you should use the second me
46
67
 
47
68
  `Naturalsorter::Sorter.sort_by_method(users, "firstname", true)`
48
69
 
49
- that's it!
70
+ Isn't that awesome?
71
+
72
+ The next methods are based on my own implementation, optimized for sorting version strings like "1.1, 1.4, 1.10"
73
+
74
+ `Naturalsorter::Sorter.sort_version(["1.10", "1.1", "1.2"])`
75
+
76
+ will return the array ["1.1", "1.2", "1.10"]
77
+
50
78
 
51
79
  ## Alan Davies
52
80
 
53
- This project uses internal the natcmp implementation from Alan Davies. All glorry to him for his awesome work.
81
+ The first 4 methods in this librarie are internal based on the natcmp implementation from Alan Davies. All glorry to him for his awesome work.
54
82
 
data/lib/naturalsorter.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "naturalsorter/version"
2
2
  require "natcmp"
3
+ require "versioncmp"
3
4
 
4
5
  # naturalsorter.rb
5
6
  #
@@ -35,6 +36,14 @@ module Naturalsorter
35
36
  array.sort { |a,b| Natcmp.natcmp(a,b,caseinsesitive) }
36
37
  end
37
38
 
39
+ def self.sort_desc(array, caseinsesitive)
40
+ if (array.nil? || array.empty?)
41
+ return nil
42
+ end
43
+ array.sort { |a, b| Natcmp.natcmp(b,a,caseinsesitive) }
44
+ end
45
+
46
+
38
47
  # 'Natural order' sort for an array of objects.
39
48
  def self.sort_by_method(array, method, caseinsesitive)
40
49
  if (array.nil? || array.empty?)
@@ -42,6 +51,73 @@ module Naturalsorter
42
51
  end
43
52
  array.sort { |a,b| Natcmp.natcmp(a.send(method),b.send(method),caseinsesitive) }
44
53
  end
54
+
55
+ def self.sort_by_method_desc(array, method, caseinsesitive)
56
+ if (array.nil? || array.empty?)
57
+ return nil
58
+ end
59
+ array.sort { |a, b| Natcmp.natcmp(b.send(method),a.send(method),caseinsesitive) }
60
+ end
61
+
62
+
63
+ def self.sort_version(array)
64
+ return nil if (array.nil? || array.empty?)
65
+ array.sort { |a,b| Versioncmp.compare( a, b ) }
66
+ end
67
+
68
+ def self.sort_version_desc(array)
69
+ return nil if (array.nil? || array.empty?)
70
+ array.sort { |a,b| Versioncmp.compare( b, a ) }
71
+ end
72
+
73
+
74
+
75
+ def self.sort_version_by_method(array, method)
76
+ return nil if (array.nil? || array.empty?)
77
+ array.sort { |a,b| Versioncmp.compare(a.send(method), b.send(method)) }
78
+ end
79
+
80
+ def self.sort_version_by_method_desc(array, method)
81
+ return nil if (array.nil? || array.empty?)
82
+ array.sort { |a,b| Versioncmp.compare(b.send(method), a.send(method)) }
83
+ end
84
+
85
+
86
+
87
+ def self.get_newest_version(first, second)
88
+ array = [first, second]
89
+ array = array.sort { |a,b| Versioncmp.compare( a, b ) }
90
+ array.last
91
+ end
92
+
93
+ def self.is_version_current?(version, current_version)
94
+ version = version.gsub("~>", "")
95
+ versions = version.split(".")
96
+ currents = current_version.split(".")
97
+ min_length = versions.size
98
+ if currents.size < min_length
99
+ min_length = currents.size
100
+ end
101
+ min_length = min_length - 2
102
+ if min_length < 0
103
+ min_length = 0
104
+ end
105
+ (0..min_length).each do |z|
106
+ ver = versions[z]
107
+ cur = currents[z]
108
+ if (cur > ver)
109
+ return false
110
+ end
111
+ end
112
+ if currents.size < versions.size
113
+ ver = versions[min_length + 1]
114
+ cur = currents[min_length + 1]
115
+ if cur > ver
116
+ return false
117
+ end
118
+ end
119
+ true
120
+ end
45
121
 
46
122
  end
47
123
 
@@ -1,3 +1,3 @@
1
1
  module Naturalsorter
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/versioncmp.rb ADDED
@@ -0,0 +1,145 @@
1
+ # versioncmp.rb
2
+ #
3
+ # Natural order comparison of two version strings
4
+ # e.g. "1.10.beta" < "1.10" > "1.9"
5
+ # which does not follow alphabetically
6
+ #
7
+ #
8
+ # This implementation is Copyright (C) 2012 by Robert Reiz
9
+ #
10
+ # This software is provided 'as-is', without any express or implied
11
+ # warranty. In no event will the authors be held liable for any damages
12
+ # arising from the use of this software.
13
+ #
14
+ # Permission is granted to anyone to use this software for any purpose,
15
+ # including commercial applications, and to alter it and redistribute it
16
+ # freely, subject to the following restrictions:
17
+ #
18
+ # 1. The origin of this software must not be misrepresented; you must not
19
+ # claim that you wrote the original software. If you use this software
20
+ # in a product, an acknowledgment in the product documentation would be
21
+ # appreciated but is not required.
22
+ # 2. Altered source versions must be plainly marked as such, and must not be
23
+ # misrepresented as being the original software.
24
+ # 3. This notice may not be removed or altered from any source distribution.
25
+
26
+ class Versioncmp
27
+
28
+ # 'Natural version order' comparison of two version strings
29
+ def self.compare(a, b)
30
+
31
+ offset1 = 0;
32
+ offset2 = 0;
33
+
34
+ for i in 0..100
35
+ if offset1 >= a.length() || offset2 >= b.length()
36
+ break
37
+ end
38
+
39
+ part1 = Versioncmp.getAPiece(offset1, a);
40
+ part2 = Versioncmp.getAPiece(offset2, b);
41
+ offset1 += part1.length() + 1;
42
+ offset2 += part2.length() + 1;
43
+
44
+ if ( part1.match(/^[0-9]+$/) != nil && part2.match(/^[0-9]+$/) != nil )
45
+ ai = part1;
46
+ bi = part2;
47
+ result = Versioncmp.compareInt(ai, bi);
48
+ if result != 0
49
+ return result;
50
+ else
51
+ next
52
+ end
53
+ elsif ( part1.match(/^[0-9]+$/) == nil && part2.match(/^[0-9]+$/) == nil )
54
+ result = Versioncmp.compareString(part1, part2)
55
+ if (result != 0)
56
+ return result
57
+ else
58
+ next
59
+ end
60
+ else
61
+ if (part1.match(/^[0-9]+$/) != nil && part2.match(/^[0-9]+$/) == nil)
62
+ return 1;
63
+ else
64
+ return -1;
65
+ end
66
+ end
67
+ end
68
+ result = Versioncmp.checkForRC(a, b)
69
+ return result
70
+ end
71
+
72
+ def self.compareInt(ai, bi)
73
+ return -1 if (ai < bi)
74
+ return 0 if (ai == bi)
75
+ return 1
76
+ end
77
+
78
+ def self.compareString(a, b)
79
+ return 0 if a.eql? b
80
+ return -1 if a < b
81
+ return 1
82
+ end
83
+
84
+ def self.checkForRC(a, b)
85
+ big = String.new(a)
86
+ small = String.new(b)
87
+ if (a.length() < b.length())
88
+ big = String.new(b)
89
+ small = String.new(a)
90
+ end
91
+ if (Versioncmp.isRc(big))
92
+ bigwithoutRc = big.gsub(/\.RC[1-9]*$/, "").gsub(/\.rc[1-9]*$/, "")
93
+ if (Versioncmp.compareString(bigwithoutRc, small) == 0)
94
+ return Versioncmp.getRcValue(a, b)
95
+ end
96
+ elsif (Versioncmp.isBeta(big))
97
+ bigwithoutBeta = big.gsub(/\.BETA[1-9]*$/, "").gsub(/\.beta[1-9]*$/, "")
98
+ if (Versioncmp.compareString(bigwithoutBeta, small) == 0)
99
+ return Versioncmp.getRcValue(a, b)
100
+ end
101
+ elsif (Versioncmp.isPre(big))
102
+ bigwithoutPre = big.gsub(/\.PRE[1-9]*$/, "").gsub(/\.pre[1-9]*$/, "")
103
+ if (Versioncmp.compareString(bigwithoutPre, small) == 0)
104
+ return Versioncmp.getRcValue(a, b)
105
+ end
106
+ end
107
+ return Versioncmp.compareString(big, small);
108
+ end
109
+
110
+ def self.isRc(a)
111
+ return a.match(/.*RC[1-9]*$/) != nil || a.match(/.*rc[1-9]*$/) != nil;
112
+ end
113
+
114
+ def self.isBeta(a)
115
+ return a.match(/.*BETA[1-9]*$/) != nil || a.match(/.*beta[1-9]*$/) != nil;
116
+ end
117
+
118
+ def self.isPre(a)
119
+ return a.match(/.*PRE[1-9]*$/) != nil || a.match(/.*pre[1-9]*$/) != nil;
120
+ end
121
+
122
+ def self.getAPiece(offset, cake)
123
+ for z in 0..100
124
+ offsetz = offset + z
125
+ if offsetz > cake.length()
126
+ break
127
+ end
128
+ p = cake[offset..offset + z]
129
+ if ( p.match(/^[0-9]+$/) == nil )
130
+ break
131
+ end
132
+ end
133
+ if z > 0
134
+ z = z - 1
135
+ end
136
+ piece = cake[offset..offset + z ]
137
+ return piece
138
+ end
139
+
140
+ def self.getRcValue(a, b)
141
+ return 1 if (a.length() < b.length())
142
+ return -1
143
+ end
144
+
145
+ end
@@ -2,16 +2,112 @@ require "naturalsorter"
2
2
 
3
3
  describe Naturalsorter::Sorter do
4
4
 
5
- it "cba is abc" do
6
- Naturalsorter::Sorter.sort(["c", "b", "a"], true).should eql(["a", "b", "c"])
5
+ describe "sort" do
6
+ it "cba is abc" do
7
+ Naturalsorter::Sorter.sort(["c", "b", "a"], true).should eql(["a", "b", "c"])
8
+ end
9
+ it "c400b5a1 is a1b5c400" do
10
+ Naturalsorter::Sorter.sort(["a400", "a5", "a1"], true).should eql(["a1", "a5", "a400"])
11
+ end
7
12
  end
8
-
9
- it "c400b5a1 is a1b5c400" do
10
- Naturalsorter::Sorter.sort(["a400", "a5", "a1"], true).should eql(["a1", "a5", "a400"])
13
+ describe "sort_desc" do
14
+ it "cba is abc" do
15
+ Naturalsorter::Sorter.sort_desc(["c", "b", "a"], true).should eql(["c", "b", "a"])
16
+ end
17
+ it "c400b5a1 is a1b5c400" do
18
+ Naturalsorter::Sorter.sort_desc(["a5", "a400", "a1"], true).should eql(["a400", "a5", "a1"])
19
+ end
11
20
  end
12
21
 
13
- it "c400b5a1 is a1b5c400" do
14
- Naturalsorter::Sorter.sort_by_method(["a400", "a5", "a1"], "to_s", true).should eql(["a1", "a5", "a400"])
22
+ describe "sort_by_method" do
23
+ it "c400b5a1 is a1b5c400" do
24
+ Naturalsorter::Sorter.sort_by_method(["a400", "a5", "a1"], "to_s", true).should eql(["a1", "a5", "a400"])
25
+ end
26
+ end
27
+ describe "sort_by_method_desc" do
28
+ it "a5 a400 a1 is a400 a5 a1" do
29
+ Naturalsorter::Sorter.sort_by_method_desc(["a5", "a400", "a1"], "to_s", true).should eql(["a400", "a5", "a1"])
30
+ end
15
31
  end
32
+
33
+
34
+ describe "sort_version" do
35
+
36
+ it "1.1, 1.0 is 1.0, 1.1" do
37
+ Naturalsorter::Sorter.sort_version(["1.1", "1.0"]).should eql(["1.0", "1.1"])
38
+ end
39
+
40
+ it "1.0, 1.1 is 1.0, 1.1" do
41
+ Naturalsorter::Sorter.sort_version(["1.0", "1.1"]).should eql(["1.0", "1.1"])
42
+ end
43
+
44
+ it "4.5, 1.0 is 1.0, 4.5" do
45
+ Naturalsorter::Sorter.sort_version(["4.5", "1.0"]).should eql(["1.0", "4.5"])
46
+ end
47
+
48
+ it "1.0, 4.5 is 1.0, 4.5" do
49
+ Naturalsorter::Sorter.sort_version(["1.0", "4.5"]).should eql(["1.0", "4.5"])
50
+ end
51
+
52
+ it "1.2, 1.1 is 1.1, 1.2" do
53
+ Naturalsorter::Sorter.sort_version(["0.4", "0.1", "1.1", "1.2", "1.0"]).should eql(["0.1", "0.4", "1.0", "1.1", "1.2"])
54
+ end
55
+
56
+ it "1.2, 1.1 is 1.1, 1.2" do
57
+ Naturalsorter::Sorter.sort_version( ["0.4", "0.1", "1.1", "1.2", "1.0", "1.0.RC1"]).should eql(["0.1", "0.4", "1.0.RC1", "1.0", "1.1", "1.2"])
58
+ end
59
+
60
+ it "1.2, 1.1 is 1.1, 1.2" do
61
+ Naturalsorter::Sorter.sort_version_desc(["0.4", "0.1", "1.1", "1.2", "1.0", "1.0.RC1"]).should eql(["1.2", "1.1", "1.0", "1.0.RC1", "0.4", "0.1"])
62
+ end
63
+
64
+ it "1.2, 1.1 is 1.1, 1.2" do
65
+ Naturalsorter::Sorter.sort_version(["1.1", "1.2", "1.0"]).should eql(["1.0", "1.1", "1.2"])
66
+ end
16
67
 
68
+ it "sort with RC" do
69
+ Naturalsorter::Sorter.sort_version(["1.1", "1.1.RC1"]).should eql(["1.1.RC1", "1.1"])
70
+ end
71
+
72
+ it "sort with RC" do
73
+ Naturalsorter::Sorter.sort_version(["1.1.RC1", "1.1", "1.0"]).should eql(["1.0", "1.1.RC1", "1.1"])
74
+ end
75
+
76
+ end
77
+
78
+ describe "is_version_current?" do
79
+ it "returns true" do
80
+ Naturalsorter::Sorter.is_version_current?("1.1.1", "1.1.9").should be_true
81
+ end
82
+ it "returns false" do
83
+ Naturalsorter::Sorter.is_version_current?("1.1.1", "1.2.0").should be_false
84
+ end
85
+ it "returns false" do
86
+ Naturalsorter::Sorter.is_version_current?("1.1.1", "1.2").should be_false
87
+ end
88
+ it "returns false" do
89
+ Naturalsorter::Sorter.is_version_current?("1.1.1", "2.0").should be_false
90
+ end
91
+ it "returns false" do
92
+ Naturalsorter::Sorter.is_version_current?("1.1.1", "2").should be_false
93
+ end
94
+ end
95
+
96
+ describe "get_newest_version" do
97
+
98
+ it "returns 2.0" do
99
+ Naturalsorter::Sorter.get_newest_version("1.1", "2.0").should eql("2.0")
100
+ end
101
+ it "returns 1.1" do
102
+ Naturalsorter::Sorter.get_newest_version("1.1", "1.0").should eql("1.1")
103
+ end
104
+ it "returns 4.5" do
105
+ Naturalsorter::Sorter.get_newest_version("4.5", "1.0").should eql("4.5")
106
+ end
107
+ it "returns 1.0" do
108
+ Naturalsorter::Sorter.get_newest_version("1.0", "1.0").should eql("1.0")
109
+ end
110
+
111
+ end
112
+
17
113
  end
@@ -0,0 +1,41 @@
1
+ require "naturalsorter"
2
+
3
+ describe Versioncmp do
4
+
5
+ it "smaler" do
6
+ Versioncmp.compare("1.1", "1.2").should eql(-1)
7
+ end
8
+
9
+ it "bigger" do
10
+ Versioncmp.compare("1.1", "1.0").should eql(1)
11
+ end
12
+
13
+ it "equal" do
14
+ Versioncmp.compare("1.1", "1.1").should eql(0)
15
+ end
16
+
17
+ it "equal RC" do
18
+ Versioncmp.compare("1.1.RC1", "1.1.RC1").should eql(0)
19
+ end
20
+
21
+ it "smaller RC" do
22
+ Versioncmp.compare("1.1.RC1", "1.1").should eql(-1)
23
+ end
24
+
25
+ it "smaller RC" do
26
+ Versioncmp.compare("1.1.rc1", "1.1").should eql(-1)
27
+ end
28
+
29
+ it "bigger RC" do
30
+ Versioncmp.compare("1.1.rc3", "1.1.rc2").should eql(1)
31
+ end
32
+
33
+ it "bigger RC than 1.0" do
34
+ Versioncmp.compare("1.1.RC1", "1.0").should eql(1)
35
+ end
36
+
37
+ it "bigger RC than 1.0" do
38
+ Versioncmp.compare("1.1.RC1", "1.1").should eql(-1)
39
+ end
40
+
41
+ end
metadata CHANGED
@@ -1,45 +1,34 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: naturalsorter
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 1
8
- - 0
9
- version: 0.1.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - reiz
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2012-01-08 00:00:00 +01:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2012-04-04 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: rspec
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- requirements:
16
+ requirement: &70285480167460 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
25
19
  - - ~>
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 2
29
- - 6
30
- version: "2.6"
20
+ - !ruby/object:Gem::Version
21
+ version: '2.6'
31
22
  type: :development
32
- version_requirements: *id001
23
+ prerelease: false
24
+ version_requirements: *70285480167460
33
25
  description: This GEM is sorting Arrays in a natural order. a2 < a10
34
- email:
26
+ email:
35
27
  - robert.reiz@gmx.com
36
28
  executables: []
37
-
38
29
  extensions: []
39
-
40
30
  extra_rdoc_files: []
41
-
42
- files:
31
+ files:
43
32
  - .gitignore
44
33
  - Gemfile
45
34
  - README.markdown
@@ -47,37 +36,34 @@ files:
47
36
  - lib/natcmp.rb
48
37
  - lib/naturalsorter.rb
49
38
  - lib/naturalsorter/version.rb
39
+ - lib/versioncmp.rb
50
40
  - naturalsorter.gemspec
51
41
  - spec/naturalsorter_spec.rb
52
- has_rdoc: true
42
+ - spec/versioncmp_spec.rb
53
43
  homepage: https://github.com/reiz/naturalsorter
54
44
  licenses: []
55
-
56
45
  post_install_message:
57
46
  rdoc_options: []
58
-
59
- require_paths:
47
+ require_paths:
60
48
  - lib
61
- required_ruby_version: !ruby/object:Gem::Requirement
62
- requirements:
63
- - - ">="
64
- - !ruby/object:Gem::Version
65
- segments:
66
- - 0
67
- version: "0"
68
- required_rubygems_version: !ruby/object:Gem::Requirement
69
- requirements:
70
- - - ">="
71
- - !ruby/object:Gem::Version
72
- segments:
73
- - 0
74
- version: "0"
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
75
61
  requirements: []
76
-
77
62
  rubyforge_project: naturalsorter
78
- rubygems_version: 1.3.6
63
+ rubygems_version: 1.8.17
79
64
  signing_key:
80
65
  specification_version: 3
81
66
  summary: Sorting arrays in natural order
82
- test_files:
67
+ test_files:
83
68
  - spec/naturalsorter_spec.rb
69
+ - spec/versioncmp_spec.rb