ranked-model 0.4.4 → 0.4.8
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 +5 -5
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.travis.yml +32 -25
- data/Appraisals +40 -35
- data/Gemfile +12 -0
- data/Readme.mkd +61 -12
- data/gemfiles/rails_4_2.gemfile +8 -7
- data/gemfiles/rails_5_0.gemfile +8 -8
- data/gemfiles/rails_5_1.gemfile +8 -8
- data/gemfiles/rails_5_2.gemfile +7 -4
- data/gemfiles/rails_6_0.gemfile +22 -0
- data/gemfiles/rails_6_1.gemfile +22 -0
- data/lib/ranked-model/ranker.rb +356 -351
- data/lib/ranked-model/version.rb +1 -1
- data/lib/ranked-model.rb +1 -1
- data/ranked-model.gemspec +4 -4
- data/spec/duck-model/column_default_ducks_spec.rb +1 -1
- data/spec/duck-model/duck_spec.rb +84 -46
- data/spec/duck-model/lots_of_ducks_spec.rb +29 -33
- data/spec/ego-model/ego_spec.rb +3 -3
- data/spec/number-model/number_spec.rb +10 -2
- data/spec/player-model/records_already_exist_spec.rb +1 -1
- data/spec/ranked-model/ranker_spec.rb +18 -0
- data/spec/sti-model/element_spec.rb +24 -24
- data/spec/sti-model/vehicle_spec.rb +4 -4
- data/spec/support/active_record.rb +7 -5
- metadata +16 -16
- data/gemfiles/rails_4_1.gemfile +0 -22
data/lib/ranked-model/ranker.rb
CHANGED
@@ -1,351 +1,356 @@
|
|
1
|
-
module RankedModel
|
2
|
-
|
3
|
-
class InvalidScope < StandardError; end
|
4
|
-
class InvalidField < StandardError; end
|
5
|
-
|
6
|
-
class Ranker
|
7
|
-
attr_accessor :name, :column, :scope, :with_same, :class_name, :unless
|
8
|
-
|
9
|
-
def initialize name, options={}
|
10
|
-
self.name = name.to_sym
|
11
|
-
self.column = options[:column] || name
|
12
|
-
self.class_name = options[:class_name]
|
13
|
-
|
14
|
-
[ :scope, :with_same, :unless ].each do |key|
|
15
|
-
self.send "#{key}=", options[key]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def with instance
|
20
|
-
Mapper.new self, instance
|
21
|
-
end
|
22
|
-
|
23
|
-
class Mapper
|
24
|
-
attr_accessor :ranker, :instance
|
25
|
-
|
26
|
-
def initialize ranker, instance
|
27
|
-
self.ranker = ranker
|
28
|
-
self.instance = instance
|
29
|
-
|
30
|
-
validate_ranker_for_instance!
|
31
|
-
end
|
32
|
-
|
33
|
-
def validate_ranker_for_instance!
|
34
|
-
if ranker.scope && !instance_class.respond_to?(ranker.scope)
|
35
|
-
raise RankedModel::InvalidScope, %Q{No scope called "#{ranker.scope}" found in model}
|
36
|
-
end
|
37
|
-
|
38
|
-
if ranker.with_same
|
39
|
-
if (case ranker.with_same
|
40
|
-
when Symbol
|
41
|
-
!instance.respond_to?(ranker.with_same)
|
42
|
-
when Array
|
43
|
-
array_element = ranker.with_same.detect {|attr| !instance.respond_to?(attr) }
|
44
|
-
else
|
45
|
-
false
|
46
|
-
end)
|
47
|
-
raise RankedModel::InvalidField, %Q{No field called "#{array_element || ranker.with_same}" found in model}
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def handle_ranking
|
53
|
-
case ranker.unless
|
54
|
-
when Proc
|
55
|
-
return if ranker.unless.call(instance)
|
56
|
-
when Symbol
|
57
|
-
return if instance.send(ranker.unless)
|
58
|
-
end
|
59
|
-
|
60
|
-
update_index_from_position
|
61
|
-
assure_unique_position
|
62
|
-
end
|
63
|
-
|
64
|
-
def update_rank! value
|
65
|
-
# Bypass callbacks
|
66
|
-
#
|
67
|
-
instance_class.
|
68
|
-
where(instance_class.primary_key => instance.id).
|
69
|
-
update_all(ranker.column => value)
|
70
|
-
end
|
71
|
-
|
72
|
-
def
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
def
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
def
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
def
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
def
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
when :
|
130
|
-
if
|
131
|
-
rank_at_average
|
132
|
-
else
|
133
|
-
position_at :middle
|
134
|
-
end
|
135
|
-
when :
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
neighbors
|
146
|
-
|
147
|
-
max = neighbors[:upper].rank
|
148
|
-
min
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
# If there is room at the
|
194
|
-
|
195
|
-
# ...then move everyone else
|
196
|
-
_scope.
|
197
|
-
where( instance_class.arel_table[ranker.column].
|
198
|
-
update_all( "#{escaped_column} = #{escaped_column}
|
199
|
-
# If there is room at the
|
200
|
-
elsif
|
201
|
-
# ...then move everyone else
|
202
|
-
_scope.
|
203
|
-
where( instance_class.arel_table[ranker.column].
|
204
|
-
update_all( "#{escaped_column} = #{escaped_column}
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
end
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
{ :lower =>
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
{
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
{
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
1
|
+
module RankedModel
|
2
|
+
|
3
|
+
class InvalidScope < StandardError; end
|
4
|
+
class InvalidField < StandardError; end
|
5
|
+
|
6
|
+
class Ranker
|
7
|
+
attr_accessor :name, :column, :scope, :with_same, :class_name, :unless
|
8
|
+
|
9
|
+
def initialize name, options={}
|
10
|
+
self.name = name.to_sym
|
11
|
+
self.column = options[:column] || name
|
12
|
+
self.class_name = options[:class_name]
|
13
|
+
|
14
|
+
[ :scope, :with_same, :unless ].each do |key|
|
15
|
+
self.send "#{key}=", options[key]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def with instance
|
20
|
+
Mapper.new self, instance
|
21
|
+
end
|
22
|
+
|
23
|
+
class Mapper
|
24
|
+
attr_accessor :ranker, :instance
|
25
|
+
|
26
|
+
def initialize ranker, instance
|
27
|
+
self.ranker = ranker
|
28
|
+
self.instance = instance
|
29
|
+
|
30
|
+
validate_ranker_for_instance!
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_ranker_for_instance!
|
34
|
+
if ranker.scope && !instance_class.respond_to?(ranker.scope)
|
35
|
+
raise RankedModel::InvalidScope, %Q{No scope called "#{ranker.scope}" found in model}
|
36
|
+
end
|
37
|
+
|
38
|
+
if ranker.with_same
|
39
|
+
if (case ranker.with_same
|
40
|
+
when Symbol
|
41
|
+
!instance.respond_to?(ranker.with_same)
|
42
|
+
when Array
|
43
|
+
array_element = ranker.with_same.detect {|attr| !instance.respond_to?(attr) }
|
44
|
+
else
|
45
|
+
false
|
46
|
+
end)
|
47
|
+
raise RankedModel::InvalidField, %Q{No field called "#{array_element || ranker.with_same}" found in model}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def handle_ranking
|
53
|
+
case ranker.unless
|
54
|
+
when Proc
|
55
|
+
return if ranker.unless.call(instance)
|
56
|
+
when Symbol
|
57
|
+
return if instance.send(ranker.unless)
|
58
|
+
end
|
59
|
+
|
60
|
+
update_index_from_position
|
61
|
+
assure_unique_position
|
62
|
+
end
|
63
|
+
|
64
|
+
def update_rank! value
|
65
|
+
# Bypass callbacks
|
66
|
+
#
|
67
|
+
instance_class.
|
68
|
+
where(instance_class.primary_key => instance.id).
|
69
|
+
update_all(ranker.column => value)
|
70
|
+
end
|
71
|
+
|
72
|
+
def reset_ranks!
|
73
|
+
finder.update_all(ranker.column => nil)
|
74
|
+
end
|
75
|
+
|
76
|
+
def position
|
77
|
+
instance.send "#{ranker.name}_position"
|
78
|
+
end
|
79
|
+
|
80
|
+
def relative_rank
|
81
|
+
escaped_column = instance_class.connection.quote_column_name ranker.column
|
82
|
+
|
83
|
+
finder.where("#{escaped_column} < #{rank}").count(:all)
|
84
|
+
end
|
85
|
+
|
86
|
+
def rank
|
87
|
+
instance.send "#{ranker.column}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def current_at_position _pos
|
91
|
+
if (ordered_instance = finder.offset(_pos).first)
|
92
|
+
RankedModel::Ranker::Mapper.new ranker, ordered_instance
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def has_rank?
|
97
|
+
!rank.nil?
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def reset_cache
|
103
|
+
@finder, @current_order, @current_first, @current_last = nil
|
104
|
+
end
|
105
|
+
|
106
|
+
def instance_class
|
107
|
+
ranker.class_name.nil? ? instance.class : ranker.class_name.constantize
|
108
|
+
end
|
109
|
+
|
110
|
+
def position_at value
|
111
|
+
instance.send "#{ranker.name}_position=", value
|
112
|
+
update_index_from_position
|
113
|
+
end
|
114
|
+
|
115
|
+
def rank_at value
|
116
|
+
instance.send "#{ranker.column}=", value
|
117
|
+
end
|
118
|
+
|
119
|
+
def rank_changed?
|
120
|
+
instance.send "#{ranker.column}_changed?"
|
121
|
+
end
|
122
|
+
|
123
|
+
def new_record?
|
124
|
+
instance.new_record?
|
125
|
+
end
|
126
|
+
|
127
|
+
def update_index_from_position
|
128
|
+
case position
|
129
|
+
when :first, 'first'
|
130
|
+
if current_first && current_first.rank
|
131
|
+
rank_at_average current_first.rank, RankedModel::MIN_RANK_VALUE
|
132
|
+
else
|
133
|
+
position_at :middle
|
134
|
+
end
|
135
|
+
when :last, 'last'
|
136
|
+
if current_last && current_last.rank
|
137
|
+
rank_at_average current_last.rank, RankedModel::MAX_RANK_VALUE
|
138
|
+
else
|
139
|
+
position_at :middle
|
140
|
+
end
|
141
|
+
when :middle, 'middle'
|
142
|
+
rank_at_average RankedModel::MIN_RANK_VALUE, RankedModel::MAX_RANK_VALUE
|
143
|
+
when :down, 'down'
|
144
|
+
neighbors = find_next_two(rank)
|
145
|
+
if neighbors[:lower]
|
146
|
+
min = neighbors[:lower].rank
|
147
|
+
max = neighbors[:upper] ? neighbors[:upper].rank : RankedModel::MAX_RANK_VALUE
|
148
|
+
rank_at_average min, max
|
149
|
+
end
|
150
|
+
when :up, 'up'
|
151
|
+
neighbors = find_previous_two(rank)
|
152
|
+
if neighbors[:upper]
|
153
|
+
max = neighbors[:upper].rank
|
154
|
+
min = neighbors[:lower] ? neighbors[:lower].rank : RankedModel::MIN_RANK_VALUE
|
155
|
+
rank_at_average min, max
|
156
|
+
end
|
157
|
+
when String
|
158
|
+
position_at position.to_i
|
159
|
+
when 0
|
160
|
+
position_at :first
|
161
|
+
when Integer
|
162
|
+
neighbors = neighbors_at_position(position)
|
163
|
+
min = ((neighbors[:lower] && neighbors[:lower].has_rank?) ? neighbors[:lower].rank : RankedModel::MIN_RANK_VALUE)
|
164
|
+
max = ((neighbors[:upper] && neighbors[:upper].has_rank?) ? neighbors[:upper].rank : RankedModel::MAX_RANK_VALUE)
|
165
|
+
rank_at_average min, max
|
166
|
+
when NilClass
|
167
|
+
if !rank
|
168
|
+
position_at :last
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def rank_at_average(min, max)
|
174
|
+
if (max - min).between?(-1, 1) # No room at the inn...
|
175
|
+
rebalance_ranks
|
176
|
+
position_at position
|
177
|
+
else
|
178
|
+
rank_at( ( ( max - min ).to_f / 2 ).ceil + min )
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def assure_unique_position
|
183
|
+
if ( new_record? || rank_changed? )
|
184
|
+
if (rank > RankedModel::MAX_RANK_VALUE) || rank_taken?
|
185
|
+
rearrange_ranks
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def rearrange_ranks
|
191
|
+
_scope = finder
|
192
|
+
escaped_column = instance_class.connection.quote_column_name ranker.column
|
193
|
+
# If there is room at the bottom of the list and we're added to the very top of the list...
|
194
|
+
if current_first.rank && current_first.rank > RankedModel::MIN_RANK_VALUE && rank == RankedModel::MAX_RANK_VALUE
|
195
|
+
# ...then move everyone else down 1 to make room for us at the end
|
196
|
+
_scope.
|
197
|
+
where( instance_class.arel_table[ranker.column].lteq(rank) ).
|
198
|
+
update_all( "#{escaped_column} = #{escaped_column} - 1" )
|
199
|
+
# If there is room at the top of the list and we're added below the last value in the list...
|
200
|
+
elsif current_last.rank && current_last.rank < (RankedModel::MAX_RANK_VALUE - 1) && rank < current_last.rank
|
201
|
+
# ...then move everyone else at or above our desired rank up 1 to make room for us
|
202
|
+
_scope.
|
203
|
+
where( instance_class.arel_table[ranker.column].gteq(rank) ).
|
204
|
+
update_all( "#{escaped_column} = #{escaped_column} + 1" )
|
205
|
+
# If there is room at the bottom of the list and we're added above the lowest value in the list...
|
206
|
+
elsif current_first.rank && current_first.rank > RankedModel::MIN_RANK_VALUE && rank > current_first.rank
|
207
|
+
# ...then move everyone else below us down 1 and change our rank down 1 to avoid the collission
|
208
|
+
_scope.
|
209
|
+
where( instance_class.arel_table[ranker.column].lt(rank) ).
|
210
|
+
update_all( "#{escaped_column} = #{escaped_column} - 1" )
|
211
|
+
rank_at( rank - 1 )
|
212
|
+
else
|
213
|
+
rebalance_ranks
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def rebalance_ranks
|
218
|
+
ActiveRecord::Base.transaction do
|
219
|
+
if rank && instance.persisted?
|
220
|
+
origin = current_order.index { |item| item.instance.id == instance.id }
|
221
|
+
if origin
|
222
|
+
destination = current_order.index { |item| rank <= item.rank }
|
223
|
+
destination -= 1 if origin < destination
|
224
|
+
|
225
|
+
current_order.insert destination, current_order.delete_at(origin)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
gaps = current_order.size + 1
|
230
|
+
range = (RankedModel::MAX_RANK_VALUE - RankedModel::MIN_RANK_VALUE).to_f
|
231
|
+
gap_size = (range / gaps).ceil
|
232
|
+
|
233
|
+
reset_ranks!
|
234
|
+
|
235
|
+
current_order.each.with_index(1) do |item, position|
|
236
|
+
new_rank = (gap_size * position) + RankedModel::MIN_RANK_VALUE
|
237
|
+
|
238
|
+
if item.instance.id == instance.id
|
239
|
+
rank_at new_rank
|
240
|
+
else
|
241
|
+
item.update_rank! new_rank
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
reset_cache
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def finder(order = :asc)
|
250
|
+
@finder ||= {}
|
251
|
+
@finder[order] ||= begin
|
252
|
+
_finder = instance_class
|
253
|
+
columns = [instance_class.primary_key.to_sym, ranker.column]
|
254
|
+
|
255
|
+
if ranker.scope
|
256
|
+
_finder = _finder.send ranker.scope
|
257
|
+
end
|
258
|
+
|
259
|
+
case ranker.with_same
|
260
|
+
when Symbol
|
261
|
+
columns << ranker.with_same
|
262
|
+
_finder = _finder.where \
|
263
|
+
ranker.with_same => instance.attributes[ranker.with_same.to_s]
|
264
|
+
when Array
|
265
|
+
ranker.with_same.each do |column|
|
266
|
+
columns << column
|
267
|
+
_finder = _finder.where column => instance.attributes[column.to_s]
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
unless new_record?
|
272
|
+
_finder = _finder.where.not instance_class.primary_key.to_sym => instance.id
|
273
|
+
end
|
274
|
+
|
275
|
+
_finder.reorder(ranker.column.to_sym => order).select(columns)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def current_order
|
280
|
+
@current_order ||= begin
|
281
|
+
finder.unscope(where: instance_class.primary_key.to_sym).collect { |ordered_instance|
|
282
|
+
RankedModel::Ranker::Mapper.new ranker, ordered_instance
|
283
|
+
}
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def current_first
|
288
|
+
@current_first ||= begin
|
289
|
+
if (ordered_instance = finder.first)
|
290
|
+
RankedModel::Ranker::Mapper.new ranker, ordered_instance
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def current_last
|
296
|
+
@current_last ||= begin
|
297
|
+
if (ordered_instance = finder.last)
|
298
|
+
RankedModel::Ranker::Mapper.new ranker, ordered_instance
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def rank_taken?
|
304
|
+
finder.except(:order).where(ranker.column => rank).exists?
|
305
|
+
end
|
306
|
+
|
307
|
+
def neighbors_at_position _pos
|
308
|
+
if _pos > 0
|
309
|
+
if (ordered_instances = finder.offset(_pos-1).limit(2).to_a)
|
310
|
+
if ordered_instances[1]
|
311
|
+
{ :lower => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[0] ),
|
312
|
+
:upper => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[1] ) }
|
313
|
+
elsif ordered_instances[0]
|
314
|
+
{ :lower => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[0] ) }
|
315
|
+
else
|
316
|
+
{ :lower => current_last }
|
317
|
+
end
|
318
|
+
end
|
319
|
+
else
|
320
|
+
if (ordered_instance = finder.first)
|
321
|
+
{ :upper => RankedModel::Ranker::Mapper.new( ranker, ordered_instance ) }
|
322
|
+
else
|
323
|
+
{}
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def find_next_two _rank
|
329
|
+
ordered_instances = finder.where(instance_class.arel_table[ranker.column].gt _rank).limit(2)
|
330
|
+
if ordered_instances[1]
|
331
|
+
{ :lower => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[0] ),
|
332
|
+
:upper => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[1] ) }
|
333
|
+
elsif ordered_instances[0]
|
334
|
+
{ :lower => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[0] ) }
|
335
|
+
else
|
336
|
+
{}
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def find_previous_two _rank
|
341
|
+
ordered_instances = finder(:desc).where(instance_class.arel_table[ranker.column].lt _rank).limit(2)
|
342
|
+
if ordered_instances[1]
|
343
|
+
{ :upper => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[0] ),
|
344
|
+
:lower => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[1] ) }
|
345
|
+
elsif ordered_instances[0]
|
346
|
+
{ :upper => RankedModel::Ranker::Mapper.new( ranker, ordered_instances[0] ) }
|
347
|
+
else
|
348
|
+
{}
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
end
|
353
|
+
|
354
|
+
end
|
355
|
+
|
356
|
+
end
|