ranked-model 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +18 -9
- data/Appraisals +39 -29
- data/Gemfile +0 -3
- data/Readme.mkd +18 -10
- data/gemfiles/rails_3_2.gemfile +1 -3
- data/gemfiles/rails_4_1.gemfile +0 -2
- data/gemfiles/rails_4_2.gemfile +0 -2
- data/gemfiles/rails_5_0.gemfile +22 -0
- data/gemfiles/rails_5_1.gemfile +22 -0
- data/gemfiles/rails_5_2.gemfile +19 -0
- data/lib/ranked-model.rb +1 -1
- data/lib/ranked-model/ranker.rb +68 -59
- data/lib/ranked-model/version.rb +1 -1
- data/ranked-model.gemspec +6 -6
- data/spec/duck-model/duck_spec.rb +66 -35
- data/spec/duck-model/lots_of_ducks_spec.rb +27 -11
- data/spec/number-model/number_spec.rb +31 -0
- data/spec/ranked-model/version_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -0
- data/spec/sti-model/vehicle_spec.rb +2 -2
- data/spec/support/active_record.rb +10 -0
- metadata +34 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5cfad22b2acf05bc3deda080d1bb11b96ade3c9d
|
|
4
|
+
data.tar.gz: cd2d02de24cf6465ee4211818beb6696ec41e616
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd1dbb2069c730aeda634d15cc4cd5a5fa0be8def4cca8db3b6bb320e40ef97f29f88bac16f2ba12720a1287cbb06ae3188e7862f5586599757fc2c56f6d3e6e
|
|
7
|
+
data.tar.gz: b5f0896c2a4979b3f8d157bc20f3ee1bc7846ea6ef2ffb3432b50d5696e0852f803026bea3d0177c8db22b949c3d8c89022582b4c79da84c8ff8fc4a2611d3a6
|
data/.travis.yml
CHANGED
|
@@ -14,25 +14,34 @@ rvm:
|
|
|
14
14
|
- 2.4.4
|
|
15
15
|
- 2.5.1
|
|
16
16
|
- jruby-9.1.17.0
|
|
17
|
-
- rbx-3.
|
|
17
|
+
- rbx-3.107
|
|
18
18
|
env:
|
|
19
19
|
- DB=sqlite
|
|
20
20
|
- DB=mysql
|
|
21
21
|
- DB=postgresql
|
|
22
22
|
gemfile:
|
|
23
|
-
- gemfiles/rails_3_2.gemfile
|
|
24
23
|
- gemfiles/rails_4_1.gemfile
|
|
25
24
|
- gemfiles/rails_4_2.gemfile
|
|
25
|
+
- gemfiles/rails_5_0.gemfile
|
|
26
|
+
- gemfiles/rails_5_1.gemfile
|
|
27
|
+
- gemfiles/rails_5_2.gemfile
|
|
26
28
|
matrix:
|
|
27
29
|
exclude:
|
|
28
|
-
- rvm:
|
|
29
|
-
gemfile: gemfiles/
|
|
30
|
+
- rvm: 1.9.3
|
|
31
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
|
32
|
+
- rvm: 1.9.3
|
|
33
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
|
34
|
+
- rvm: 1.9.3
|
|
35
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
|
36
|
+
- rvm: 2.1.10
|
|
37
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
|
38
|
+
- rvm: 2.1.10
|
|
39
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
|
40
|
+
- rvm: 2.1.10
|
|
41
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
|
42
|
+
- rvm: jruby-9.1.17.0
|
|
43
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
|
30
44
|
- rvm: 2.4.4
|
|
31
45
|
gemfile: gemfiles/rails_4_1.gemfile
|
|
32
|
-
- rvm: 2.5.1
|
|
33
|
-
gemfile: gemfiles/rails_3_2.gemfile
|
|
34
46
|
- rvm: 2.5.1
|
|
35
47
|
gemfile: gemfiles/rails_4_1.gemfile
|
|
36
|
-
- env: DB=postgresql
|
|
37
|
-
gemfile: gemfiles/rails_3_2.gemfile
|
|
38
|
-
|
data/Appraisals
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
appraise "rails-
|
|
1
|
+
appraise "rails-4-1" do
|
|
2
2
|
group :sqlite do
|
|
3
3
|
gem "sqlite3", platform: :ruby
|
|
4
4
|
gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.24", platform: :jruby
|
|
@@ -12,16 +12,16 @@ appraise "rails-3-2" do
|
|
|
12
12
|
gem "activerecord-jdbcpostgresql-adapter", "~> 1.3.24", platform: :jruby
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
gem "activerecord", "~>
|
|
15
|
+
gem "activerecord", "~> 4.1.16"
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
appraise "rails-4-
|
|
18
|
+
appraise "rails-4-2" do
|
|
19
19
|
group :sqlite do
|
|
20
20
|
gem "sqlite3", platform: :ruby
|
|
21
21
|
gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.24", platform: :jruby
|
|
22
22
|
end
|
|
23
23
|
group :mysql do
|
|
24
|
-
gem "mysql2", "~> 0.
|
|
24
|
+
gem "mysql2", "~> 0.4.10", platform: :ruby
|
|
25
25
|
gem "activerecord-jdbcmysql-adapter", "~> 1.3.24", platform: :jruby
|
|
26
26
|
end
|
|
27
27
|
group :postgresql do
|
|
@@ -29,43 +29,53 @@ appraise "rails-4-1" do
|
|
|
29
29
|
gem "activerecord-jdbcpostgresql-adapter", "~> 1.3.24", platform: :jruby
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
gem "activerecord", "~> 4.
|
|
32
|
+
gem "activerecord", "~> 4.2.10"
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
appraise "rails-
|
|
35
|
+
appraise "rails-5-0" do
|
|
36
36
|
group :sqlite do
|
|
37
37
|
gem "sqlite3", platform: :ruby
|
|
38
|
-
gem "activerecord-jdbcsqlite3-adapter", "~> 1
|
|
38
|
+
gem "activerecord-jdbcsqlite3-adapter", "~> 50.1", platform: :jruby
|
|
39
39
|
end
|
|
40
40
|
group :mysql do
|
|
41
41
|
gem "mysql2", "~> 0.4.10", platform: :ruby
|
|
42
|
-
gem "activerecord-jdbcmysql-adapter", "~> 1
|
|
42
|
+
gem "activerecord-jdbcmysql-adapter", "~> 50.1", platform: :jruby
|
|
43
43
|
end
|
|
44
44
|
group :postgresql do
|
|
45
|
-
gem "pg", "~> 0.
|
|
46
|
-
gem "activerecord-jdbcpostgresql-adapter", "~> 1
|
|
45
|
+
gem "pg", "~> 0.21.0", platform: :ruby
|
|
46
|
+
gem "activerecord-jdbcpostgresql-adapter", "~> 50.1", platform: :jruby
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
gem "activerecord", "~>
|
|
49
|
+
gem "activerecord", "~> 5.0.7"
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
appraise "rails-5-1" do
|
|
53
|
+
group :sqlite do
|
|
54
|
+
gem "sqlite3", platform: :ruby
|
|
55
|
+
gem "activerecord-jdbcsqlite3-adapter", "~> 51.1", platform: :jruby
|
|
56
|
+
end
|
|
57
|
+
group :mysql do
|
|
58
|
+
gem "mysql2", "~> 0.4.10", platform: :ruby
|
|
59
|
+
gem "activerecord-jdbcmysql-adapter", "~> 51.1", platform: :jruby
|
|
60
|
+
end
|
|
61
|
+
group :postgresql do
|
|
62
|
+
gem "pg", "~> 0.21.0", platform: :ruby
|
|
63
|
+
gem "activerecord-jdbcpostgresql-adapter", "~> 51.1", platform: :jruby
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
gem "activerecord", "~> 5.1.6"
|
|
67
|
+
end
|
|
58
68
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
appraise "rails-5-2" do
|
|
70
|
+
group :sqlite do
|
|
71
|
+
gem "sqlite3", platform: :ruby
|
|
72
|
+
end
|
|
73
|
+
group :mysql do
|
|
74
|
+
gem "mysql2", "~> 0.4.10", platform: :ruby
|
|
75
|
+
end
|
|
76
|
+
group :postgresql do
|
|
77
|
+
gem "pg", "~> 0.21.0", platform: :ruby
|
|
78
|
+
end
|
|
65
79
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
# gem "mysql2", "~> 0.4.10", platform: :ruby
|
|
69
|
-
# end
|
|
70
|
-
# gem "activerecord", "~> 5.2.0.rc1"
|
|
71
|
-
# end
|
|
80
|
+
gem "activerecord", "~> 5.2.0"
|
|
81
|
+
end
|
data/Gemfile
CHANGED
data/Readme.mkd
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
**ranked-model** is a modern row sorting library built for Rails 3
|
|
1
|
+
**ranked-model** is a modern row sorting library built for Rails 3, 4 and 5. It uses ARel aggressively and is better optimized than most other libraries.
|
|
2
2
|
|
|
3
3
|
[](https://travis-ci.org/mixonic/ranked-model)
|
|
4
4
|
|
|
5
5
|
Installation
|
|
6
6
|
------------
|
|
7
7
|
|
|
8
|
-
ranked-model passes specs with Rails
|
|
8
|
+
ranked-model passes specs with Rails 4.1, 4.2, 5.0, 5.1 and 5.2 for MySQL, Postgres, and SQLite on Ruby 1.9.3, 2.1 through 2.5, jruby-9.1.17.0, and rbx-3.107 where Rails supports the platform. This is with the exception of Postgres before Rails 4.0 on all platforms, which is unsupported by `ranked-model`. Note that the `pg` gem has pulled support for rbx (Rubinius) from version 1 onward.
|
|
9
9
|
|
|
10
10
|
TL;DR, if you are using Rails 4 and up you are 100% good to go. Before Rails 4, be wary of Postgres.
|
|
11
11
|
|
|
@@ -55,6 +55,8 @@ implement a sorting UI, just update the resource by appending the column name wi
|
|
|
55
55
|
@duck.update_attribute :row_order_position, 0 # or 1, 2, 37. :first, :last, :up and :down are also valid
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
**IMPORTANT: Note that you MUST append _position to the column name when setting a new position on an instance. This is a fake column that can take relative as well as absolute index-based values for position.**
|
|
59
|
+
|
|
58
60
|
Position numbers begin at zero. A position number greater than the number of records acts the
|
|
59
61
|
same as :last. :up and :down move the record up/down the ladder by one step.
|
|
60
62
|
|
|
@@ -80,16 +82,19 @@ class Duck < ActiveRecord::Base
|
|
|
80
82
|
|
|
81
83
|
include RankedModel
|
|
82
84
|
|
|
83
|
-
ranks :row_order,
|
|
84
|
-
:column => :sort_order
|
|
85
|
-
|
|
85
|
+
ranks :row_order, # Name this ranker, used with rank()
|
|
86
|
+
:column => :sort_order # Override the default column, which defaults to the name
|
|
87
|
+
|
|
86
88
|
belongs_to :pond
|
|
87
89
|
ranks :swimming_order,
|
|
88
|
-
:with_same => :pond_id
|
|
89
|
-
|
|
90
|
+
:with_same => :pond_id # Ducks belong_to Ponds, make the ranker scoped to one pond
|
|
91
|
+
|
|
92
|
+
ranks :row_order,
|
|
93
|
+
:with_same => [:pond_id, :breed] # Lets rank them by breed
|
|
94
|
+
|
|
90
95
|
scope :walking, where(:walking => true )
|
|
91
96
|
ranks :walking_order,
|
|
92
|
-
:scope => :walking
|
|
97
|
+
:scope => :walking # Narrow this ranker to a scope
|
|
93
98
|
|
|
94
99
|
end
|
|
95
100
|
```
|
|
@@ -178,10 +183,12 @@ Fork, clone, write a test, write some code, commit, push, send a pull request.
|
|
|
178
183
|
The specs can be run with sqlite, postgres, and mysql:
|
|
179
184
|
|
|
180
185
|
```
|
|
181
|
-
|
|
186
|
+
bundle
|
|
187
|
+
appraisal install
|
|
188
|
+
DB=postgresql bundle exec appraisal rake
|
|
182
189
|
```
|
|
183
190
|
|
|
184
|
-
|
|
191
|
+
If no DB is specified (`sqlite`, `mysql`, or `postgresql`), the tests run against sqlite.
|
|
185
192
|
|
|
186
193
|
RankedModel is mostly the handiwork of Matthew Beale:
|
|
187
194
|
|
|
@@ -203,3 +210,4 @@ A hearty thanks to these contributors:
|
|
|
203
210
|
* [jguyon](https://github.com/jguyon)
|
|
204
211
|
* [pehrlich](https://github.com/pehrlich)
|
|
205
212
|
* [petergoldstein](https://github.com/petergoldstein)
|
|
213
|
+
* [brendon](https://github.com/brendon)
|
data/gemfiles/rails_3_2.gemfile
CHANGED
data/gemfiles/rails_4_1.gemfile
CHANGED
data/gemfiles/rails_4_2.gemfile
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "activerecord", "~> 5.0.7"
|
|
6
|
+
|
|
7
|
+
group :sqlite do
|
|
8
|
+
gem "sqlite3", platform: :ruby
|
|
9
|
+
gem "activerecord-jdbcsqlite3-adapter", "~> 50.1", platform: :jruby
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
group :mysql do
|
|
13
|
+
gem "mysql2", "~> 0.4.10", platform: :ruby
|
|
14
|
+
gem "activerecord-jdbcmysql-adapter", "~> 50.1", platform: :jruby
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
group :postgresql do
|
|
18
|
+
gem "pg", "~> 0.21.0", platform: :ruby
|
|
19
|
+
gem "activerecord-jdbcpostgresql-adapter", "~> 50.1", platform: :jruby
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
gemspec path: "../"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "activerecord", "~> 5.1.6"
|
|
6
|
+
|
|
7
|
+
group :sqlite do
|
|
8
|
+
gem "sqlite3", platform: :ruby
|
|
9
|
+
gem "activerecord-jdbcsqlite3-adapter", "~> 51.1", platform: :jruby
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
group :mysql do
|
|
13
|
+
gem "mysql2", "~> 0.4.10", platform: :ruby
|
|
14
|
+
gem "activerecord-jdbcmysql-adapter", "~> 51.1", platform: :jruby
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
group :postgresql do
|
|
18
|
+
gem "pg", "~> 0.21.0", platform: :ruby
|
|
19
|
+
gem "activerecord-jdbcpostgresql-adapter", "~> 51.1", platform: :jruby
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
gemspec path: "../"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "activerecord", "~> 5.2.0"
|
|
6
|
+
|
|
7
|
+
group :sqlite do
|
|
8
|
+
gem "sqlite3", platform: :ruby
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
group :mysql do
|
|
12
|
+
gem "mysql2", "~> 0.4.10", platform: :ruby
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
group :postgresql do
|
|
16
|
+
gem "pg", "~> 0.21.0", platform: :ruby
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
gemspec path: "../"
|
data/lib/ranked-model.rb
CHANGED
data/lib/ranked-model/ranker.rb
CHANGED
|
@@ -66,7 +66,7 @@ module RankedModel
|
|
|
66
66
|
#
|
|
67
67
|
instance_class.
|
|
68
68
|
where(instance_class.primary_key => instance.id).
|
|
69
|
-
update_all(
|
|
69
|
+
update_all(ranker.column => value)
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def position
|
|
@@ -89,6 +89,10 @@ module RankedModel
|
|
|
89
89
|
|
|
90
90
|
private
|
|
91
91
|
|
|
92
|
+
def reset_cache
|
|
93
|
+
@finder, @current_order, @current_first, @current_last = nil
|
|
94
|
+
end
|
|
95
|
+
|
|
92
96
|
def instance_class
|
|
93
97
|
ranker.class_name.nil? ? instance.class : ranker.class_name.constantize
|
|
94
98
|
end
|
|
@@ -114,31 +118,31 @@ module RankedModel
|
|
|
114
118
|
case position
|
|
115
119
|
when :first, 'first'
|
|
116
120
|
if current_first && current_first.rank
|
|
117
|
-
|
|
121
|
+
rank_at_average current_first.rank, RankedModel::MIN_RANK_VALUE
|
|
118
122
|
else
|
|
119
123
|
position_at :middle
|
|
120
124
|
end
|
|
121
125
|
when :last, 'last'
|
|
122
126
|
if current_last && current_last.rank
|
|
123
|
-
|
|
127
|
+
rank_at_average current_last.rank, RankedModel::MAX_RANK_VALUE
|
|
124
128
|
else
|
|
125
129
|
position_at :middle
|
|
126
130
|
end
|
|
127
131
|
when :middle, 'middle'
|
|
128
|
-
|
|
132
|
+
rank_at_average RankedModel::MIN_RANK_VALUE, RankedModel::MAX_RANK_VALUE
|
|
129
133
|
when :down, 'down'
|
|
130
134
|
neighbors = find_next_two(rank)
|
|
131
135
|
if neighbors[:lower]
|
|
132
136
|
min = neighbors[:lower].rank
|
|
133
137
|
max = neighbors[:upper] ? neighbors[:upper].rank : RankedModel::MAX_RANK_VALUE
|
|
134
|
-
|
|
138
|
+
rank_at_average min, max
|
|
135
139
|
end
|
|
136
140
|
when :up, 'up'
|
|
137
141
|
neighbors = find_previous_two(rank)
|
|
138
142
|
if neighbors[:upper]
|
|
139
143
|
max = neighbors[:upper].rank
|
|
140
144
|
min = neighbors[:lower] ? neighbors[:lower].rank : RankedModel::MIN_RANK_VALUE
|
|
141
|
-
|
|
145
|
+
rank_at_average min, max
|
|
142
146
|
end
|
|
143
147
|
when String
|
|
144
148
|
position_at position.to_i
|
|
@@ -148,7 +152,7 @@ module RankedModel
|
|
|
148
152
|
neighbors = neighbors_at_position(position)
|
|
149
153
|
min = ((neighbors[:lower] && neighbors[:lower].has_rank?) ? neighbors[:lower].rank : RankedModel::MIN_RANK_VALUE)
|
|
150
154
|
max = ((neighbors[:upper] && neighbors[:upper].has_rank?) ? neighbors[:upper].rank : RankedModel::MAX_RANK_VALUE)
|
|
151
|
-
|
|
155
|
+
rank_at_average min, max
|
|
152
156
|
when NilClass
|
|
153
157
|
if !rank
|
|
154
158
|
position_at :last
|
|
@@ -156,12 +160,17 @@ module RankedModel
|
|
|
156
160
|
end
|
|
157
161
|
end
|
|
158
162
|
|
|
163
|
+
def rank_at_average(min, max)
|
|
164
|
+
if (max - min).between?(-1, 1) # No room at the inn...
|
|
165
|
+
rebalance_ranks
|
|
166
|
+
position_at position
|
|
167
|
+
else
|
|
168
|
+
rank_at( ( ( max - min ).to_f / 2 ).ceil + min )
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
159
172
|
def assure_unique_position
|
|
160
173
|
if ( new_record? || rank_changed? )
|
|
161
|
-
unless rank
|
|
162
|
-
rank_at( RankedModel::MAX_RANK_VALUE )
|
|
163
|
-
end
|
|
164
|
-
|
|
165
174
|
if (rank > RankedModel::MAX_RANK_VALUE) || current_at_rank(rank)
|
|
166
175
|
rearrange_ranks
|
|
167
176
|
end
|
|
@@ -170,22 +179,25 @@ module RankedModel
|
|
|
170
179
|
|
|
171
180
|
def rearrange_ranks
|
|
172
181
|
_scope = finder
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
_scope = _scope.where( instance_class.arel_table[instance_class.primary_key].not_eq(instance.id) )
|
|
176
|
-
end
|
|
182
|
+
escaped_column = ActiveRecord::Base.connection.quote_column_name ranker.column
|
|
183
|
+
# If there is room at the bottom of the list and we're added to the very top of the list...
|
|
177
184
|
if current_first.rank && current_first.rank > RankedModel::MIN_RANK_VALUE && rank == RankedModel::MAX_RANK_VALUE
|
|
185
|
+
# ...then move everyone else down 1 to make room for us at the end
|
|
178
186
|
_scope.
|
|
179
187
|
where( instance_class.arel_table[ranker.column].lteq(rank) ).
|
|
180
|
-
update_all(
|
|
188
|
+
update_all( "#{escaped_column} = #{escaped_column} - 1" )
|
|
189
|
+
# If there is room at the top of the list and we're added below the last value in the list...
|
|
181
190
|
elsif current_last.rank && current_last.rank < (RankedModel::MAX_RANK_VALUE - 1) && rank < current_last.rank
|
|
191
|
+
# ...then move everyone else at or above our desired rank up 1 to make room for us
|
|
182
192
|
_scope.
|
|
183
193
|
where( instance_class.arel_table[ranker.column].gteq(rank) ).
|
|
184
|
-
update_all(
|
|
194
|
+
update_all( "#{escaped_column} = #{escaped_column} + 1" )
|
|
195
|
+
# If there is room at the bottom of the list and we're added above the lowest value in the list...
|
|
185
196
|
elsif current_first.rank && current_first.rank > RankedModel::MIN_RANK_VALUE && rank > current_first.rank
|
|
197
|
+
# ...then move everyone else below us down 1 and change our rank down 1 to avoid the collission
|
|
186
198
|
_scope.
|
|
187
199
|
where( instance_class.arel_table[ranker.column].lt(rank) ).
|
|
188
|
-
update_all(
|
|
200
|
+
update_all( "#{escaped_column} = #{escaped_column} - 1" )
|
|
189
201
|
rank_at( rank - 1 )
|
|
190
202
|
else
|
|
191
203
|
rebalance_ranks
|
|
@@ -193,67 +205,64 @@ module RankedModel
|
|
|
193
205
|
end
|
|
194
206
|
|
|
195
207
|
def rebalance_ranks
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
208
|
+
if rank
|
|
209
|
+
origin = current_order.index { |item| item.instance.id == instance.id }
|
|
210
|
+
destination = current_order.index { |item| rank <= item.rank }
|
|
211
|
+
destination -= 1 if origin < destination
|
|
212
|
+
|
|
213
|
+
current_order.insert destination, current_order.delete_at(origin)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
gaps = current_order.size + 1
|
|
217
|
+
range = (RankedModel::MAX_RANK_VALUE - RankedModel::MIN_RANK_VALUE).to_f
|
|
218
|
+
gap_size = (range / gaps).ceil
|
|
219
|
+
|
|
220
|
+
current_order.each.with_index(1) do |item, position|
|
|
221
|
+
new_rank = (gap_size * position) + RankedModel::MIN_RANK_VALUE
|
|
222
|
+
|
|
223
|
+
if item.instance.id == instance.id
|
|
224
|
+
rank_at new_rank
|
|
204
225
|
else
|
|
205
|
-
|
|
206
|
-
( !current_order[index].rank.nil? &&
|
|
207
|
-
current_order[index].rank >= rank )
|
|
208
|
-
rank_at rank_value
|
|
209
|
-
has_set_self = true
|
|
210
|
-
next
|
|
211
|
-
end
|
|
226
|
+
item.update_rank! new_rank
|
|
212
227
|
end
|
|
213
|
-
current_order[index].update_rank! rank_value
|
|
214
228
|
end
|
|
229
|
+
|
|
230
|
+
reset_cache
|
|
215
231
|
end
|
|
216
232
|
|
|
217
233
|
def finder(order = :asc)
|
|
218
234
|
@finder ||= {}
|
|
219
235
|
@finder[order] ||= begin
|
|
220
236
|
_finder = instance_class
|
|
221
|
-
columns = [instance_class.
|
|
237
|
+
columns = [instance_class.primary_key.to_sym, ranker.column]
|
|
238
|
+
|
|
222
239
|
if ranker.scope
|
|
223
240
|
_finder = _finder.send ranker.scope
|
|
224
241
|
end
|
|
242
|
+
|
|
225
243
|
case ranker.with_same
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
_finder = _finder.where \
|
|
229
|
-
instance_class.arel_table[ranker.with_same].eq(instance.attributes["#{ranker.with_same}"])
|
|
230
|
-
when Array
|
|
231
|
-
ranker.with_same.each {|c| columns.push instance_class.arel_table[c] }
|
|
232
|
-
_finder = _finder.where(
|
|
233
|
-
ranker.with_same[1..-1].inject(
|
|
234
|
-
instance_class.arel_table[ranker.with_same.first].eq(
|
|
235
|
-
instance.attributes["#{ranker.with_same.first}"]
|
|
236
|
-
)
|
|
237
|
-
) {|scoper, attr|
|
|
238
|
-
scoper.and(
|
|
239
|
-
instance_class.arel_table[attr].eq(
|
|
240
|
-
instance.attributes["#{attr}"]
|
|
241
|
-
)
|
|
242
|
-
)
|
|
243
|
-
}
|
|
244
|
-
)
|
|
245
|
-
end
|
|
246
|
-
if !new_record?
|
|
244
|
+
when Symbol
|
|
245
|
+
columns << ranker.with_same
|
|
247
246
|
_finder = _finder.where \
|
|
248
|
-
|
|
247
|
+
ranker.with_same => instance.attributes[ranker.with_same.to_s]
|
|
248
|
+
when Array
|
|
249
|
+
ranker.with_same.each do |column|
|
|
250
|
+
columns << column
|
|
251
|
+
_finder = _finder.where column => instance.attributes[column.to_s]
|
|
252
|
+
end
|
|
249
253
|
end
|
|
250
|
-
|
|
254
|
+
|
|
255
|
+
unless new_record?
|
|
256
|
+
_finder = _finder.where.not instance_class.primary_key.to_sym => instance.id
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
_finder.order(ranker.column.to_sym => order).select(columns)
|
|
251
260
|
end
|
|
252
261
|
end
|
|
253
262
|
|
|
254
263
|
def current_order
|
|
255
264
|
@current_order ||= begin
|
|
256
|
-
finder.collect { |ordered_instance|
|
|
265
|
+
finder.unscope(where: instance_class.primary_key.to_sym).collect { |ordered_instance|
|
|
257
266
|
RankedModel::Ranker::Mapper.new ranker, ordered_instance
|
|
258
267
|
}
|
|
259
268
|
end
|
data/lib/ranked-model/version.rb
CHANGED
data/ranked-model.gemspec
CHANGED
|
@@ -13,14 +13,14 @@ Gem::Specification.new do |s|
|
|
|
13
13
|
s.description = %q{ranked-model is a modern row sorting library built for Rails 3 & 4. It uses ARel aggressively and is better optimized than most other libraries.}
|
|
14
14
|
s.license = 'MIT'
|
|
15
15
|
|
|
16
|
-
s.add_dependency "activerecord", ">=
|
|
17
|
-
s.add_development_dependency "rspec", "~>
|
|
18
|
-
s.add_development_dependency "
|
|
19
|
-
s.add_development_dependency "
|
|
20
|
-
s.add_development_dependency "
|
|
21
|
-
s.add_development_dependency "database_cleaner", "~> 1.2.0"
|
|
16
|
+
s.add_dependency "activerecord", ">= 4.1.16"
|
|
17
|
+
s.add_development_dependency "rspec", "~> 3"
|
|
18
|
+
s.add_development_dependency "rspec-its"
|
|
19
|
+
s.add_development_dependency "mocha"
|
|
20
|
+
s.add_development_dependency "database_cleaner", "~> 1.7.0"
|
|
22
21
|
s.add_development_dependency "rake", "~> 10.1.0"
|
|
23
22
|
s.add_development_dependency "appraisal"
|
|
23
|
+
s.add_development_dependency "pry"
|
|
24
24
|
|
|
25
25
|
s.files = `git ls-files`.split("\n")
|
|
26
26
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
@@ -8,14 +8,14 @@ describe Duck do
|
|
|
8
8
|
|
|
9
9
|
subject { @duck }
|
|
10
10
|
|
|
11
|
-
it { subject.respond_to
|
|
12
|
-
it { subject.respond_to
|
|
13
|
-
it { subject.respond_to
|
|
14
|
-
it { subject.respond_to
|
|
15
|
-
it { subject.respond_to
|
|
16
|
-
it { subject.respond_to
|
|
17
|
-
it { subject.respond_to
|
|
18
|
-
it { subject.respond_to
|
|
11
|
+
it { expect(subject).to respond_to(:row_position) }
|
|
12
|
+
it { expect(subject).to respond_to(:row_position=) }
|
|
13
|
+
it { expect(subject).to respond_to(:size_position) }
|
|
14
|
+
it { expect(subject).to respond_to(:size_position=) }
|
|
15
|
+
it { expect(subject).to respond_to(:age_position) }
|
|
16
|
+
it { expect(subject).to respond_to(:age_position=) }
|
|
17
|
+
it { expect(subject).to respond_to(:landing_order_position) }
|
|
18
|
+
it { expect(subject).to respond_to(:landing_order_position=) }
|
|
19
19
|
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -148,9 +148,9 @@ describe Duck do
|
|
|
148
148
|
it "doesn't change ranking" do
|
|
149
149
|
# puts Duck.rank(:age).collect {|duck| "#{duck.name} #{duck.age}" }
|
|
150
150
|
duck = Duck.rank(:age)[2]
|
|
151
|
-
->{
|
|
151
|
+
expect(->{
|
|
152
152
|
duck.update_attribute :name, 'New Name'
|
|
153
|
-
}.
|
|
153
|
+
}).to_not change(duck.reload, :age)
|
|
154
154
|
# puts Duck.rank(:age).collect {|duck| "#{duck.name} #{duck.age}" }
|
|
155
155
|
end
|
|
156
156
|
|
|
@@ -161,7 +161,7 @@ describe Duck do
|
|
|
161
161
|
it "marks record as changed" do
|
|
162
162
|
duck = Duck.rank(:age)[2]
|
|
163
163
|
duck.age_position = 1
|
|
164
|
-
duck.changed
|
|
164
|
+
expect(duck.changed?).to be true
|
|
165
165
|
end
|
|
166
166
|
|
|
167
167
|
end
|
|
@@ -172,7 +172,7 @@ describe Duck do
|
|
|
172
172
|
|
|
173
173
|
it "doesnt set empty string" do
|
|
174
174
|
subject.age_position = ''
|
|
175
|
-
subject.age_position.
|
|
175
|
+
expect(subject.age_position).to be_nil
|
|
176
176
|
end
|
|
177
177
|
|
|
178
178
|
end
|
|
@@ -198,9 +198,9 @@ describe Duck do
|
|
|
198
198
|
|
|
199
199
|
subject { Duck.rank(:row).collect {|duck| duck.id } }
|
|
200
200
|
|
|
201
|
-
it { subject[0..1].
|
|
201
|
+
it { expect(subject[0..1]).to eq(@ordered[0..1]) }
|
|
202
202
|
|
|
203
|
-
it { subject[3..subject.length].
|
|
203
|
+
it { expect(subject[3..subject.length]).to eq(@ordered[2..@ordered.length]) }
|
|
204
204
|
|
|
205
205
|
}
|
|
206
206
|
|
|
@@ -233,7 +233,38 @@ describe Duck do
|
|
|
233
233
|
|
|
234
234
|
subject { Duck.rank(:row).collect {|duck| duck.id } }
|
|
235
235
|
|
|
236
|
-
it { subject[1..subject.length].
|
|
236
|
+
it { expect(subject[1..subject.length]).to eq(@ordered) }
|
|
237
|
+
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
describe "second to last" do
|
|
243
|
+
|
|
244
|
+
before {
|
|
245
|
+
[:quacky, :feathers, :wingy, :webby, :waddly, :beaky].each_with_index do |name, i|
|
|
246
|
+
Duck.where(id: @ducks[name].id).update_all(row: RankedModel::MAX_RANK_VALUE - i)
|
|
247
|
+
@ducks[name].reload
|
|
248
|
+
end
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
context {
|
|
252
|
+
|
|
253
|
+
before { @ducks[:wingy].update_attribute :row_position, (@ducks.size - 2) }
|
|
254
|
+
|
|
255
|
+
subject { Duck.ranker(:row).with(Duck.new).current_at_position(@ducks.size - 2).instance }
|
|
256
|
+
|
|
257
|
+
its(:id) { should == @ducks[:wingy].id }
|
|
258
|
+
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
context {
|
|
262
|
+
|
|
263
|
+
before { @ducks[:wingy].update_attribute :row_position, :down }
|
|
264
|
+
|
|
265
|
+
subject { Duck.ranker(:row).with(Duck.new).current_at_position(@ducks.size - 2).instance }
|
|
266
|
+
|
|
267
|
+
its(:id) { should == @ducks[:wingy].id }
|
|
237
268
|
|
|
238
269
|
}
|
|
239
270
|
|
|
@@ -274,7 +305,7 @@ describe Duck do
|
|
|
274
305
|
|
|
275
306
|
subject { Duck.rank(:row).collect {|duck| duck.id } }
|
|
276
307
|
|
|
277
|
-
it { subject[0..-2].
|
|
308
|
+
it { expect(subject[0..-2]).to eq(@ordered) }
|
|
278
309
|
|
|
279
310
|
}
|
|
280
311
|
|
|
@@ -315,7 +346,7 @@ describe Duck do
|
|
|
315
346
|
|
|
316
347
|
subject { Duck.rank(:row).collect {|duck| duck.id } }
|
|
317
348
|
|
|
318
|
-
it { subject[0..-2].
|
|
349
|
+
it { expect(subject[0..-2]).to eq(@ordered) }
|
|
319
350
|
|
|
320
351
|
}
|
|
321
352
|
|
|
@@ -356,7 +387,7 @@ describe Duck do
|
|
|
356
387
|
|
|
357
388
|
subject { Duck.rank(:row).collect {|duck| duck.id } }
|
|
358
389
|
|
|
359
|
-
it { subject[0..-2].
|
|
390
|
+
it { expect(subject[0..-2]).to eq(@ordered) }
|
|
360
391
|
|
|
361
392
|
}
|
|
362
393
|
|
|
@@ -383,9 +414,9 @@ describe Duck do
|
|
|
383
414
|
|
|
384
415
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
385
416
|
|
|
386
|
-
it { subject[0..3].
|
|
417
|
+
it { expect(subject[0..3]).to eq(@ordered[0..3]) }
|
|
387
418
|
|
|
388
|
-
it { subject[5..subject.length].
|
|
419
|
+
it { expect(subject[5..subject.length]).to eq(@ordered[4..@ordered.length]) }
|
|
389
420
|
|
|
390
421
|
}
|
|
391
422
|
|
|
@@ -410,7 +441,7 @@ describe Duck do
|
|
|
410
441
|
|
|
411
442
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
412
443
|
|
|
413
|
-
it { subject[0..-2].
|
|
444
|
+
it { expect(subject[0..-2]).to eq(@ordered) }
|
|
414
445
|
|
|
415
446
|
}
|
|
416
447
|
|
|
@@ -435,7 +466,7 @@ describe Duck do
|
|
|
435
466
|
|
|
436
467
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
437
468
|
|
|
438
|
-
it { subject[0..-2].
|
|
469
|
+
it { expect(subject[0..-2]).to eq(@ordered) }
|
|
439
470
|
|
|
440
471
|
}
|
|
441
472
|
|
|
@@ -464,9 +495,9 @@ describe Duck do
|
|
|
464
495
|
|
|
465
496
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
466
497
|
|
|
467
|
-
it { subject[0..3].
|
|
498
|
+
it { expect(subject[0..3]).to eq(@ordered[0..3]) }
|
|
468
499
|
|
|
469
|
-
it { subject[5..subject.length].
|
|
500
|
+
it { expect(subject[5..subject.length]).to eq(@ordered[4..@ordered.length]) }
|
|
470
501
|
|
|
471
502
|
}
|
|
472
503
|
|
|
@@ -491,7 +522,7 @@ describe Duck do
|
|
|
491
522
|
|
|
492
523
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
493
524
|
|
|
494
|
-
it { subject[0..-2].
|
|
525
|
+
it { expect(subject[0..-2]).to eq(@ordered) }
|
|
495
526
|
|
|
496
527
|
}
|
|
497
528
|
|
|
@@ -516,7 +547,7 @@ describe Duck do
|
|
|
516
547
|
|
|
517
548
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
518
549
|
|
|
519
|
-
it { subject[0..-2].
|
|
550
|
+
it { expect(subject[0..-2]).to eq(@ordered) }
|
|
520
551
|
|
|
521
552
|
}
|
|
522
553
|
|
|
@@ -545,9 +576,9 @@ describe Duck do
|
|
|
545
576
|
|
|
546
577
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
547
578
|
|
|
548
|
-
it { subject[0..1].
|
|
579
|
+
it { expect(subject[0..1]).to eq(@ordered[0..1]) }
|
|
549
580
|
|
|
550
|
-
it { subject[3..subject.length].
|
|
581
|
+
it { expect(subject[3..subject.length]).to eq(@ordered[2..@ordered.length]) }
|
|
551
582
|
|
|
552
583
|
}
|
|
553
584
|
|
|
@@ -572,7 +603,7 @@ describe Duck do
|
|
|
572
603
|
|
|
573
604
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
574
605
|
|
|
575
|
-
it { subject[1..subject.length].
|
|
606
|
+
it { expect(subject[1..subject.length]).to eq(@ordered) }
|
|
576
607
|
|
|
577
608
|
}
|
|
578
609
|
|
|
@@ -597,7 +628,7 @@ describe Duck do
|
|
|
597
628
|
|
|
598
629
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
599
630
|
|
|
600
|
-
it { subject[1..subject.length].
|
|
631
|
+
it { expect(subject[1..subject.length]).to eq(@ordered) }
|
|
601
632
|
|
|
602
633
|
}
|
|
603
634
|
|
|
@@ -655,9 +686,9 @@ describe Duck do
|
|
|
655
686
|
|
|
656
687
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
657
688
|
|
|
658
|
-
it { subject[0..1].
|
|
689
|
+
it { expect(subject[0..1]).to eq(@ordered[0..1]) }
|
|
659
690
|
|
|
660
|
-
it { subject[3..subject.length].
|
|
691
|
+
it { expect(subject[3..subject.length]).to eq(@ordered[2..@ordered.length]) }
|
|
661
692
|
|
|
662
693
|
}
|
|
663
694
|
|
|
@@ -682,7 +713,7 @@ describe Duck do
|
|
|
682
713
|
|
|
683
714
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
684
715
|
|
|
685
|
-
it { subject[1..subject.length].
|
|
716
|
+
it { expect(subject[1..subject.length]).to eq(@ordered) }
|
|
686
717
|
|
|
687
718
|
}
|
|
688
719
|
|
|
@@ -707,7 +738,7 @@ describe Duck do
|
|
|
707
738
|
|
|
708
739
|
subject { Duck.rank(:row).collect { |duck| duck.id } }
|
|
709
740
|
|
|
710
|
-
it { subject[1..subject.length].
|
|
741
|
+
it { expect(subject[1..subject.length]).to eq(@ordered) }
|
|
711
742
|
|
|
712
743
|
}
|
|
713
744
|
|
|
@@ -792,7 +823,7 @@ describe Duck do
|
|
|
792
823
|
|
|
793
824
|
subject { @untouchable_ranks.call }
|
|
794
825
|
|
|
795
|
-
it {
|
|
826
|
+
it { is_expected.to eq(@previous_ranks) }
|
|
796
827
|
|
|
797
828
|
end
|
|
798
829
|
|
|
@@ -9,6 +9,20 @@ describe Duck do
|
|
|
9
9
|
end
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
describe "a large number of records" do
|
|
13
|
+
before { @ducks = Duck.all }
|
|
14
|
+
|
|
15
|
+
describe "the last two ducks' rows' difference" do
|
|
16
|
+
subject { @ducks[-1].row - @ducks[-2].row }
|
|
17
|
+
it { is_expected.not_to be_between(-1, 1) }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "the second to last two ducks' rows' difference" do
|
|
21
|
+
subject { @ducks[-2].row - @ducks[-3].row }
|
|
22
|
+
it { is_expected.not_to be_between(-1, 1) }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
12
26
|
describe "setting and fetching by position" do
|
|
13
27
|
|
|
14
28
|
describe '137' do
|
|
@@ -81,7 +95,7 @@ describe Duck do
|
|
|
81
95
|
|
|
82
96
|
subject { Duck.rank(:row).collect {|d| d.id } }
|
|
83
97
|
|
|
84
|
-
it {
|
|
98
|
+
it { is_expected.to eq(@ordered[0..-2] + [@ordered[-1], @first.id, @second.id]) }
|
|
85
99
|
|
|
86
100
|
}
|
|
87
101
|
|
|
@@ -103,12 +117,12 @@ describe Duck do
|
|
|
103
117
|
context {
|
|
104
118
|
subject { Duck.where(:pond => 'Pond 1').rank(:age).collect {|d| d.id } }
|
|
105
119
|
|
|
106
|
-
it {
|
|
120
|
+
it { is_expected.to eq(@ordered[0..-2] + [@ordered[-1], @duck_11.id, @duck_12.id]) }
|
|
107
121
|
}
|
|
108
122
|
|
|
109
123
|
context {
|
|
110
124
|
subject { Duck.first.age }
|
|
111
|
-
it {
|
|
125
|
+
it { is_expected.to eq(0)}
|
|
112
126
|
}
|
|
113
127
|
|
|
114
128
|
end
|
|
@@ -127,7 +141,7 @@ describe Duck do
|
|
|
127
141
|
|
|
128
142
|
subject { Duck.rank(:row).collect {|d| d.id } }
|
|
129
143
|
|
|
130
|
-
it {
|
|
144
|
+
it { is_expected.to eq([@second.id, @first.id] + @ordered) }
|
|
131
145
|
|
|
132
146
|
}
|
|
133
147
|
|
|
@@ -136,21 +150,23 @@ describe Duck do
|
|
|
136
150
|
describe "with no more gaps" do
|
|
137
151
|
|
|
138
152
|
before {
|
|
139
|
-
@first = Duck.first
|
|
140
|
-
@second = Duck.
|
|
141
|
-
@third = Duck.offset(2).first
|
|
142
|
-
@fourth = Duck.offset(4).first
|
|
153
|
+
@first = Duck.rank(:row).first
|
|
154
|
+
@second = Duck.rank(:row).offset(1).first
|
|
155
|
+
@third = Duck.rank(:row).offset(2).first
|
|
156
|
+
@fourth = Duck.rank(:row).offset(4).first
|
|
157
|
+
@fifth = Duck.rank(:row).offset(5).first
|
|
143
158
|
@lower = Duck.rank(:row).
|
|
144
|
-
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id])).
|
|
159
|
+
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id, @fifth.id])).
|
|
145
160
|
where(Duck.arel_table[:row].lt(RankedModel::MAX_RANK_VALUE / 2)).
|
|
146
161
|
collect {|d| d.id }
|
|
147
162
|
@upper = Duck.rank(:row).
|
|
148
|
-
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id])).
|
|
163
|
+
where(Duck.arel_table[:id].not_in([@first.id, @second.id, @third.id, @fourth.id, @fifth.id])).
|
|
149
164
|
where(Duck.arel_table[:row].gteq(RankedModel::MAX_RANK_VALUE / 2)).
|
|
150
165
|
collect {|d| d.id }
|
|
151
166
|
@first.update_attribute :row, RankedModel::MIN_RANK_VALUE
|
|
152
167
|
@second.update_attribute :row, RankedModel::MAX_RANK_VALUE
|
|
153
168
|
@third.update_attribute :row, (RankedModel::MAX_RANK_VALUE / 2)
|
|
169
|
+
Duck.where(id: @fifth.id).update_all row: @third.row
|
|
154
170
|
@fourth.update_attribute :row, @third.row
|
|
155
171
|
}
|
|
156
172
|
|
|
@@ -158,7 +174,7 @@ describe Duck do
|
|
|
158
174
|
|
|
159
175
|
subject { Duck.rank(:row).collect {|d| d.id } }
|
|
160
176
|
|
|
161
|
-
it {
|
|
177
|
+
it { is_expected.to eq([@first.id] + @lower + [@fourth.id, @third.id, @fifth.id] + @upper + [@second.id]) }
|
|
162
178
|
|
|
163
179
|
}
|
|
164
180
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Number do
|
|
4
|
+
|
|
5
|
+
before {
|
|
6
|
+
200.times do |i|
|
|
7
|
+
Number.create :value => i
|
|
8
|
+
end
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe "a rearrangement with keyword column name" do
|
|
12
|
+
|
|
13
|
+
before {
|
|
14
|
+
@first = Number.first
|
|
15
|
+
@second = Number.offset(1).first
|
|
16
|
+
@ordered = Number.rank(:order).where(Number.arel_table[:id].not_in([@first.id, @second.id])).collect {|d| d.id }
|
|
17
|
+
@first.update_attribute :order, RankedModel::MAX_RANK_VALUE
|
|
18
|
+
@second.update_attribute :order, RankedModel::MAX_RANK_VALUE
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
context {
|
|
22
|
+
|
|
23
|
+
subject { Number.rank(:order).collect {|d| d.id } }
|
|
24
|
+
|
|
25
|
+
it { should == (@ordered[0..-2] + [@ordered[-1], @first.id, @second.id]) }
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
require 'rubygems'
|
|
2
2
|
require 'bundler/setup'
|
|
3
|
+
require 'rspec/its'
|
|
3
4
|
|
|
4
5
|
require 'ranked-model'
|
|
6
|
+
require 'pry'
|
|
5
7
|
|
|
6
8
|
Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each {|f| require f}
|
|
7
9
|
|
|
8
10
|
# After the DB connection is setup
|
|
9
11
|
require 'database_cleaner'
|
|
10
12
|
|
|
13
|
+
# Uncomment this to see Active Record logging for tests
|
|
14
|
+
# ActiveRecord::Base.logger = Logger.new(STDOUT)
|
|
15
|
+
|
|
11
16
|
RSpec.configure do |config|
|
|
12
17
|
config.mock_with :mocha
|
|
13
18
|
|
|
@@ -43,7 +43,7 @@ describe Vehicle do
|
|
|
43
43
|
describe "Vehicle" do
|
|
44
44
|
|
|
45
45
|
it "should have one ranker object" do
|
|
46
|
-
Vehicle.rankers.count.
|
|
46
|
+
expect(Vehicle.rankers.count).to eq(1)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
subject { Vehicle.rankers.first }
|
|
@@ -57,7 +57,7 @@ describe Vehicle do
|
|
|
57
57
|
describe "MotorBike" do
|
|
58
58
|
|
|
59
59
|
it "should have one ranker object" do
|
|
60
|
-
MotorBike.rankers.count.
|
|
60
|
+
expect(MotorBike.rankers.count).to eq(1)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
subject { MotorBike.rankers.first }
|
|
@@ -56,6 +56,11 @@ ActiveRecord::Schema.define :version => 0 do
|
|
|
56
56
|
t.string :city
|
|
57
57
|
t.integer :score
|
|
58
58
|
end
|
|
59
|
+
|
|
60
|
+
create_table :numbers, :force => true do |t|
|
|
61
|
+
t.float :value
|
|
62
|
+
t.integer :order
|
|
63
|
+
end
|
|
59
64
|
end
|
|
60
65
|
|
|
61
66
|
class Duck < ActiveRecord::Base
|
|
@@ -145,3 +150,8 @@ end
|
|
|
145
150
|
class Player < ActiveRecord::Base
|
|
146
151
|
# don't add rank yet, do it in the specs
|
|
147
152
|
end
|
|
153
|
+
|
|
154
|
+
class Number < ActiveRecord::Base
|
|
155
|
+
include RankedModel
|
|
156
|
+
ranks :order
|
|
157
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ranked-model
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matthew Beale
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-
|
|
11
|
+
date: 2018-12-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -16,100 +16,100 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 4.1.16
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 4.1.16
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rspec
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: '3'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: '3'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: rspec-its
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - "
|
|
45
|
+
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
47
|
+
version: '0'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- - "
|
|
52
|
+
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
54
|
+
version: '0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
56
|
+
name: mocha
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- - "
|
|
59
|
+
- - ">="
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: 0
|
|
61
|
+
version: '0'
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
|
-
- - "
|
|
66
|
+
- - ">="
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: 0
|
|
68
|
+
version: '0'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
70
|
+
name: database_cleaner
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
75
|
+
version: 1.7.0
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
82
|
+
version: 1.7.0
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: rake
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
87
|
- - "~>"
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: 1.
|
|
89
|
+
version: 10.1.0
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
94
|
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: 1.
|
|
96
|
+
version: 10.1.0
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
98
|
+
name: appraisal
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
|
-
- - "
|
|
101
|
+
- - ">="
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
|
-
version:
|
|
103
|
+
version: '0'
|
|
104
104
|
type: :development
|
|
105
105
|
prerelease: false
|
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
|
108
|
-
- - "
|
|
108
|
+
- - ">="
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
|
-
version:
|
|
110
|
+
version: '0'
|
|
111
111
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name:
|
|
112
|
+
name: pry
|
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
|
114
114
|
requirements:
|
|
115
115
|
- - ">="
|
|
@@ -141,6 +141,9 @@ files:
|
|
|
141
141
|
- gemfiles/rails_3_2.gemfile
|
|
142
142
|
- gemfiles/rails_4_1.gemfile
|
|
143
143
|
- gemfiles/rails_4_2.gemfile
|
|
144
|
+
- gemfiles/rails_5_0.gemfile
|
|
145
|
+
- gemfiles/rails_5_1.gemfile
|
|
146
|
+
- gemfiles/rails_5_2.gemfile
|
|
144
147
|
- lib/ranked-model.rb
|
|
145
148
|
- lib/ranked-model/railtie.rb
|
|
146
149
|
- lib/ranked-model/ranker.rb
|
|
@@ -151,6 +154,7 @@ files:
|
|
|
151
154
|
- spec/duck-model/lots_of_ducks_spec.rb
|
|
152
155
|
- spec/duck-model/wrong_ducks_spec.rb
|
|
153
156
|
- spec/ego-model/ego_spec.rb
|
|
157
|
+
- spec/number-model/number_spec.rb
|
|
154
158
|
- spec/player-model/records_already_exist_spec.rb
|
|
155
159
|
- spec/ranked-model/ranker_spec.rb
|
|
156
160
|
- spec/ranked-model/version_spec.rb
|
|
@@ -180,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
180
184
|
version: '0'
|
|
181
185
|
requirements: []
|
|
182
186
|
rubyforge_project:
|
|
183
|
-
rubygems_version: 2.
|
|
187
|
+
rubygems_version: 2.5.2.2
|
|
184
188
|
signing_key:
|
|
185
189
|
specification_version: 4
|
|
186
190
|
summary: An acts_as_sortable replacement built for Rails 3 & 4
|
|
@@ -189,6 +193,7 @@ test_files:
|
|
|
189
193
|
- spec/duck-model/lots_of_ducks_spec.rb
|
|
190
194
|
- spec/duck-model/wrong_ducks_spec.rb
|
|
191
195
|
- spec/ego-model/ego_spec.rb
|
|
196
|
+
- spec/number-model/number_spec.rb
|
|
192
197
|
- spec/player-model/records_already_exist_spec.rb
|
|
193
198
|
- spec/ranked-model/ranker_spec.rb
|
|
194
199
|
- spec/ranked-model/version_spec.rb
|