sortifiable 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -0
- data/README +13 -0
- data/lib/sortifiable/version.rb +1 -1
- data/lib/sortifiable.rb +79 -30
- data/test/sortifiable_test.rb +248 -69
- metadata +4 -4
data/CHANGELOG
CHANGED
data/README
CHANGED
@@ -24,4 +24,17 @@ the scope methods and query interface introduced with Ruby on Rails 3.0
|
|
24
24
|
todo_list.last.move_higher
|
25
25
|
|
26
26
|
|
27
|
+
=== Contributions
|
28
|
+
|
29
|
+
Bug fixes and new feature patches are welcome. Please provide tests and
|
30
|
+
documentation wherever possible - without them it is unlikely your patch
|
31
|
+
will be accepted. If you're fixing a bug then a failing test for the bug
|
32
|
+
is essential. Once you have completed your patch please open a GitHub
|
33
|
+
pull request and I will review it and respond as quickly as possible.
|
34
|
+
|
35
|
+
Thanks to the following people for their contributions:
|
36
|
+
|
37
|
+
* Manuel Meurer
|
38
|
+
|
39
|
+
|
27
40
|
Copyright (c) 2011 Andrew White, released under the MIT license
|
data/lib/sortifiable/version.rb
CHANGED
data/lib/sortifiable.rb
CHANGED
@@ -48,30 +48,35 @@ module Sortifiable
|
|
48
48
|
def acts_as_list(options = {})
|
49
49
|
options.reverse_merge!(:scope => [], :column => :position)
|
50
50
|
|
51
|
-
if options[:scope].is_a?(Symbol)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
if reflection.
|
56
|
-
options[:
|
57
|
-
|
58
|
-
|
59
|
-
|
51
|
+
if options[:scope].is_a?(Symbol)
|
52
|
+
if reflections.key?(options[:scope])
|
53
|
+
reflection = reflections[options.delete(:scope)]
|
54
|
+
|
55
|
+
if reflection.belongs_to?
|
56
|
+
if reflection.options[:polymorphic]
|
57
|
+
options[:scope] = [
|
58
|
+
reflection.association_foreign_key.to_sym,
|
59
|
+
reflection.options[:foreign_type].to_sym
|
60
|
+
]
|
61
|
+
else
|
62
|
+
options[:scope] = reflection.association_foreign_key.to_sym
|
63
|
+
end
|
60
64
|
else
|
61
|
-
|
65
|
+
raise ArgumentError, "Only belongs_to associations can be used as a scope"
|
62
66
|
end
|
63
|
-
|
64
|
-
|
67
|
+
elsif options[:scope].to_s !~ /_id$/
|
68
|
+
options[:scope] = "#{options[:scope]}_id".to_sym
|
65
69
|
end
|
66
|
-
elsif options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/
|
67
|
-
options[:scope] = "#{options[:scope]}_id".to_sym
|
68
70
|
end
|
69
71
|
|
70
72
|
options[:class] = self
|
71
73
|
|
72
74
|
include InstanceMethods
|
73
|
-
|
74
|
-
|
75
|
+
|
76
|
+
before_create :add_to_list
|
77
|
+
before_destroy :decrement_position_on_lower_items, :if => :in_list?
|
78
|
+
before_save :decrement_position_on_lower_items_in_old_list, :if => :will_leave_list?
|
79
|
+
before_save :add_to_bottom_of_new_list, :if => :will_leave_list?
|
75
80
|
|
76
81
|
self.acts_as_list_options = options
|
77
82
|
end
|
@@ -92,9 +97,9 @@ module Sortifiable
|
|
92
97
|
ids = lock_list!
|
93
98
|
last_position = ids.size
|
94
99
|
if persisted?
|
95
|
-
update_position
|
100
|
+
update_position last_position + 1
|
96
101
|
else
|
97
|
-
|
102
|
+
set_position last_position + 1
|
98
103
|
end
|
99
104
|
end
|
100
105
|
end
|
@@ -138,6 +143,11 @@ module Sortifiable
|
|
138
143
|
!new_record? && !send(position_column).nil?
|
139
144
|
end
|
140
145
|
|
146
|
+
# Test if this record is in a scoped list but will leave the scoped list when saved
|
147
|
+
def will_leave_list?
|
148
|
+
in_list? && scope_parts.any? { |scope_part| send("#{scope_part}_changed?") }
|
149
|
+
end
|
150
|
+
|
141
151
|
# Increase the position of this item without adjusting the rest of the list.
|
142
152
|
def increment_position
|
143
153
|
in_list? && update_position(current_position + 1)
|
@@ -200,8 +210,7 @@ module Sortifiable
|
|
200
210
|
|
201
211
|
# Returns the bottom position in the list.
|
202
212
|
def last_position
|
203
|
-
|
204
|
-
item ? item.current_position : 0
|
213
|
+
last_item.try(:current_position) || 0
|
205
214
|
end
|
206
215
|
alias_method :bottom_position, :last_position
|
207
216
|
|
@@ -232,7 +241,7 @@ module Sortifiable
|
|
232
241
|
END
|
233
242
|
SQL
|
234
243
|
|
235
|
-
|
244
|
+
set_position current_position - 1
|
236
245
|
list_scope.update_all(sql) > 0
|
237
246
|
end
|
238
247
|
end
|
@@ -258,7 +267,7 @@ module Sortifiable
|
|
258
267
|
END
|
259
268
|
SQL
|
260
269
|
|
261
|
-
|
270
|
+
set_position current_position + 1
|
262
271
|
list_scope.update_all(sql) > 0
|
263
272
|
end
|
264
273
|
end
|
@@ -285,7 +294,7 @@ module Sortifiable
|
|
285
294
|
END
|
286
295
|
SQL
|
287
296
|
|
288
|
-
|
297
|
+
set_position last_position
|
289
298
|
list_scope.update_all(sql) > 0
|
290
299
|
end
|
291
300
|
end
|
@@ -311,7 +320,7 @@ module Sortifiable
|
|
311
320
|
END
|
312
321
|
SQL
|
313
322
|
|
314
|
-
|
323
|
+
set_position 1
|
315
324
|
list_scope.update_all(sql) > 0
|
316
325
|
end
|
317
326
|
end
|
@@ -335,7 +344,7 @@ module Sortifiable
|
|
335
344
|
END
|
336
345
|
SQL
|
337
346
|
|
338
|
-
|
347
|
+
set_position nil
|
339
348
|
list_scope.update_all(sql) > 0
|
340
349
|
end
|
341
350
|
else
|
@@ -354,6 +363,46 @@ module Sortifiable
|
|
354
363
|
list_scope.update_all(update, conditions) > 0
|
355
364
|
end
|
356
365
|
|
366
|
+
def decrement_position_on_lower_items_in_old_list #:nodoc:
|
367
|
+
with_old_scope do
|
368
|
+
decrement_position_on_lower_items
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def with_old_scope #:nodoc:
|
373
|
+
# Save new scope in variable
|
374
|
+
new_scope = scope_parts.map { |scope_part| send(scope_part) }
|
375
|
+
|
376
|
+
# Set old scope
|
377
|
+
scope_parts.each { |scope_part| send "#{scope_part}=", send("#{scope_part}_was") }
|
378
|
+
|
379
|
+
yield
|
380
|
+
|
381
|
+
# Set new scope
|
382
|
+
scope_parts.each_with_index { |scope_part, i| send "#{scope_part}=", new_scope[i] }
|
383
|
+
end
|
384
|
+
|
385
|
+
def scope_parts_from_string(string) #:nodoc:
|
386
|
+
string.split('AND').map(&:strip).map { |condition| condition.split.first }
|
387
|
+
end
|
388
|
+
|
389
|
+
def scope_parts #:nodoc:
|
390
|
+
if acts_as_list_options[:scope].is_a?(String)
|
391
|
+
scope_parts_from_string(acts_as_list_options[:scope])
|
392
|
+
else
|
393
|
+
Array(acts_as_list_options[:scope])
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
def add_to_bottom_of_new_list #:nodoc:
|
398
|
+
set_position nil
|
399
|
+
add_to_list
|
400
|
+
end
|
401
|
+
|
402
|
+
def set_position(position) #:nodoc:
|
403
|
+
send "#{position_column}=", position
|
404
|
+
end
|
405
|
+
|
357
406
|
def list_class #:nodoc:
|
358
407
|
acts_as_list_options[:class]
|
359
408
|
end
|
@@ -384,15 +433,15 @@ module Sortifiable
|
|
384
433
|
|
385
434
|
def scope_condition #:nodoc:
|
386
435
|
if acts_as_list_options[:scope].is_a?(String)
|
387
|
-
instance_eval("
|
436
|
+
instance_eval %("#{acts_as_list_options[:scope]}")
|
388
437
|
else
|
389
|
-
Array
|
438
|
+
Array(acts_as_list_options[:scope]).each_with_object({}) { |k, m| m[k] = send(k) }
|
390
439
|
end
|
391
440
|
end
|
392
441
|
|
393
|
-
def update_position(new_position)
|
394
|
-
list_class.update_all(
|
395
|
-
|
442
|
+
def update_position(new_position) #:nodoc:
|
443
|
+
list_class.update_all({ position_column => new_position }, { list_class.primary_key => id })
|
444
|
+
set_position new_position
|
396
445
|
end
|
397
446
|
end
|
398
447
|
end
|
data/test/sortifiable_test.rb
CHANGED
@@ -47,6 +47,7 @@ end
|
|
47
47
|
class ListWithStringScopeMixin < ActiveRecord::Base
|
48
48
|
acts_as_list :column => "pos", :scope => 'parent_id = #{parent_id}'
|
49
49
|
set_table_name "mixins"
|
50
|
+
default_scope order(:pos)
|
50
51
|
end
|
51
52
|
|
52
53
|
class ArrayScopeListMixin < ActiveRecord::Base
|
@@ -100,7 +101,11 @@ class ListTest < Test::Unit::TestCase
|
|
100
101
|
|
101
102
|
def setup
|
102
103
|
setup_db
|
103
|
-
|
104
|
+
[5, 6].each do |parent_id|
|
105
|
+
(1..4).each do |i|
|
106
|
+
ListMixin.create! :pos => i, :parent_id => parent_id
|
107
|
+
end
|
108
|
+
end
|
104
109
|
end
|
105
110
|
|
106
111
|
def teardown
|
@@ -108,41 +113,42 @@ class ListTest < Test::Unit::TestCase
|
|
108
113
|
end
|
109
114
|
|
110
115
|
def test_reordering
|
111
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
116
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
112
117
|
|
113
118
|
ListMixin.find(2).move_lower
|
114
|
-
assert_equal [1, 3, 2, 4], ListMixin.where(
|
119
|
+
assert_equal [1, 3, 2, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
115
120
|
|
116
121
|
ListMixin.find(2).move_higher
|
117
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
122
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
118
123
|
|
119
124
|
ListMixin.find(1).move_to_bottom
|
120
|
-
assert_equal [2, 3, 4, 1], ListMixin.where(
|
125
|
+
assert_equal [2, 3, 4, 1], ListMixin.where(:parent_id => 5).map(&:id)
|
121
126
|
|
122
127
|
ListMixin.find(1).move_to_top
|
123
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
128
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
124
129
|
|
125
130
|
ListMixin.find(2).move_to_bottom
|
126
|
-
assert_equal [1, 3, 4, 2], ListMixin.where(
|
131
|
+
assert_equal [1, 3, 4, 2], ListMixin.where(:parent_id => 5).map(&:id)
|
127
132
|
|
128
133
|
ListMixin.find(4).move_to_top
|
129
|
-
assert_equal [4, 1, 3, 2], ListMixin.where(
|
134
|
+
assert_equal [4, 1, 3, 2], ListMixin.where(:parent_id => 5).map(&:id)
|
130
135
|
end
|
131
136
|
|
132
137
|
def test_bounds_checking
|
133
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
138
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:pos)
|
134
139
|
|
135
140
|
ListMixin.find(1).move_higher
|
136
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
141
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:pos)
|
137
142
|
|
138
143
|
ListMixin.find(4).move_lower
|
139
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
144
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:pos)
|
140
145
|
end
|
141
146
|
|
142
147
|
def test_move_to_bottom_with_next_to_last_item
|
143
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
148
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
149
|
+
|
144
150
|
ListMixin.find(3).move_to_bottom
|
145
|
-
assert_equal [1, 2, 4, 3], ListMixin.where(
|
151
|
+
assert_equal [1, 2, 4, 3], ListMixin.where(:parent_id => 5).map(&:id)
|
146
152
|
end
|
147
153
|
|
148
154
|
def test_next_prev
|
@@ -216,11 +222,11 @@ class ListTest < Test::Unit::TestCase
|
|
216
222
|
end
|
217
223
|
|
218
224
|
def test_delete_middle
|
219
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
225
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
220
226
|
|
221
227
|
ListMixin.find(2).destroy
|
222
228
|
|
223
|
-
assert_equal [1, 3, 4], ListMixin.where(
|
229
|
+
assert_equal [1, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
224
230
|
|
225
231
|
assert_equal 1, ListMixin.find(1).pos
|
226
232
|
assert_equal 2, ListMixin.find(3).pos
|
@@ -228,23 +234,16 @@ class ListTest < Test::Unit::TestCase
|
|
228
234
|
|
229
235
|
ListMixin.find(1).destroy
|
230
236
|
|
231
|
-
assert_equal [3, 4], ListMixin.where(
|
237
|
+
assert_equal [3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
232
238
|
|
233
239
|
assert_equal 1, ListMixin.find(3).pos
|
234
240
|
assert_equal 2, ListMixin.find(4).pos
|
235
241
|
end
|
236
242
|
|
237
|
-
def test_with_string_based_scope
|
238
|
-
new = ListWithStringScopeMixin.create(:parent_id => 500)
|
239
|
-
assert_equal 1, new.pos
|
240
|
-
assert new.first?
|
241
|
-
assert new.last?
|
242
|
-
end
|
243
|
-
|
244
243
|
def test_nil_scope
|
245
244
|
new1, new2, new3 = ListMixin.create, ListMixin.create, ListMixin.create
|
246
245
|
new2.move_higher
|
247
|
-
assert_equal [new2, new1, new3], ListMixin.where(
|
246
|
+
assert_equal [new2, new1, new3], ListMixin.where(:parent_id => nil)
|
248
247
|
end
|
249
248
|
|
250
249
|
def test_remove_from_list_should_then_fail_in_list?
|
@@ -254,11 +253,11 @@ class ListTest < Test::Unit::TestCase
|
|
254
253
|
end
|
255
254
|
|
256
255
|
def test_remove_from_list_should_set_position_to_nil
|
257
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
256
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
258
257
|
|
259
258
|
ListMixin.find(2).remove_from_list
|
260
259
|
|
261
|
-
assert_equal [2, 1, 3, 4], ListMixin.where(
|
260
|
+
assert_equal [2, 1, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
262
261
|
|
263
262
|
assert_equal 1, ListMixin.find(1).pos
|
264
263
|
assert_equal nil, ListMixin.find(2).pos
|
@@ -267,20 +266,47 @@ class ListTest < Test::Unit::TestCase
|
|
267
266
|
end
|
268
267
|
|
269
268
|
def test_remove_before_destroy_does_not_shift_lower_items_twice
|
270
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
269
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
271
270
|
|
272
271
|
ListMixin.find(2).remove_from_list
|
273
272
|
ListMixin.find(2).destroy
|
274
273
|
|
275
|
-
assert_equal [1, 3, 4], ListMixin.where(
|
274
|
+
assert_equal [1, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
275
|
+
|
276
|
+
assert_equal 1, ListMixin.find(1).pos
|
277
|
+
assert_equal 2, ListMixin.find(3).pos
|
278
|
+
assert_equal 3, ListMixin.find(4).pos
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_remove_from_list_by_updating_should_shift_lower_items
|
282
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
283
|
+
|
284
|
+
ListMixin.find(2).update_attributes! :parent_id => 6
|
285
|
+
|
286
|
+
assert_equal [1, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
276
287
|
|
277
288
|
assert_equal 1, ListMixin.find(1).pos
|
278
289
|
assert_equal 2, ListMixin.find(3).pos
|
279
290
|
assert_equal 3, ListMixin.find(4).pos
|
280
291
|
end
|
281
292
|
|
293
|
+
def test_move_to_new_list_by_updating_should_append
|
294
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
295
|
+
assert_equal [5, 6, 7, 8], ListMixin.where(:parent_id => 6).map(&:id)
|
296
|
+
|
297
|
+
ListMixin.find(2).update_attributes! :parent_id => 6
|
298
|
+
|
299
|
+
assert_equal [5, 6, 7, 8, 2], ListMixin.where(:parent_id => 6).map(&:id)
|
300
|
+
|
301
|
+
assert_equal 1, ListMixin.find(5).pos
|
302
|
+
assert_equal 2, ListMixin.find(6).pos
|
303
|
+
assert_equal 3, ListMixin.find(7).pos
|
304
|
+
assert_equal 4, ListMixin.find(8).pos
|
305
|
+
assert_equal 5, ListMixin.find(2).pos
|
306
|
+
end
|
307
|
+
|
282
308
|
def test_before_destroy_callbacks_do_not_update_position_to_nil_before_deleting_the_record
|
283
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
309
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
284
310
|
|
285
311
|
# We need to trigger all the before_destroy callbacks without actually
|
286
312
|
# destroying the record so we can see the affect the callbacks have on
|
@@ -292,7 +318,7 @@ class ListTest < Test::Unit::TestCase
|
|
292
318
|
list.send(:callback, :before_destroy)
|
293
319
|
end
|
294
320
|
|
295
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
321
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5).map(&:id)
|
296
322
|
|
297
323
|
assert_equal 1, ListMixin.find(1).pos
|
298
324
|
assert_equal 2, ListMixin.find(2).pos
|
@@ -302,12 +328,78 @@ class ListTest < Test::Unit::TestCase
|
|
302
328
|
|
303
329
|
def test_higher_items
|
304
330
|
assert_equal [1, 2], ListMixin.find(3).higher_items.map(&:id)
|
305
|
-
assert_equal
|
331
|
+
assert_equal [], ListMixin.find(1).higher_items.map(&:id)
|
306
332
|
end
|
307
333
|
|
308
334
|
def test_lower_items
|
309
335
|
assert_equal [3, 4], ListMixin.find(2).lower_items.map(&:id)
|
310
|
-
assert_equal
|
336
|
+
assert_equal [], ListMixin.find(4).lower_items.map(&:id)
|
337
|
+
end
|
338
|
+
|
339
|
+
end
|
340
|
+
|
341
|
+
class ListWithStringScopeTest < Test::Unit::TestCase
|
342
|
+
|
343
|
+
def setup
|
344
|
+
setup_db
|
345
|
+
[5, 6].each do |parent_id|
|
346
|
+
(1..4).each do |i|
|
347
|
+
ListWithStringScopeMixin.create! :parent_id => parent_id
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
def teardown
|
353
|
+
teardown_db
|
354
|
+
end
|
355
|
+
|
356
|
+
def test_insert
|
357
|
+
new = ListWithStringScopeMixin.create(:parent_id => 500)
|
358
|
+
assert_equal 1, new.pos
|
359
|
+
assert new.first?
|
360
|
+
assert new.last?
|
361
|
+
|
362
|
+
new = ListWithStringScopeMixin.create(:parent_id => 500)
|
363
|
+
assert_equal 2, new.pos
|
364
|
+
assert !new.first?
|
365
|
+
assert new.last?
|
366
|
+
|
367
|
+
new = ListWithStringScopeMixin.create(:parent_id => 500)
|
368
|
+
assert_equal 3, new.pos
|
369
|
+
assert !new.first?
|
370
|
+
assert new.last?
|
371
|
+
|
372
|
+
new = ListWithStringScopeMixin.create(:parent_id => 0)
|
373
|
+
assert_equal 1, new.pos
|
374
|
+
assert new.first?
|
375
|
+
assert new.last?
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_remove_from_list_by_updating_should_shift_lower_items
|
379
|
+
assert_equal [1, 2, 3, 4], ListWithStringScopeMixin.where(:parent_id => 5).map(&:id)
|
380
|
+
|
381
|
+
ListWithStringScopeMixin.find(2).update_attributes! :parent_id => 6
|
382
|
+
|
383
|
+
assert_equal [1, 3, 4], ListWithStringScopeMixin.where(:parent_id => 5).map(&:id)
|
384
|
+
|
385
|
+
assert_equal 1, ListWithStringScopeMixin.find(1).pos
|
386
|
+
assert_equal 2, ListWithStringScopeMixin.find(3).pos
|
387
|
+
assert_equal 3, ListWithStringScopeMixin.find(4).pos
|
388
|
+
end
|
389
|
+
|
390
|
+
def test_move_to_new_list_by_updating_should_append
|
391
|
+
assert_equal [1, 2, 3, 4], ListWithStringScopeMixin.where(:parent_id => 5).map(&:id)
|
392
|
+
assert_equal [5, 6, 7, 8], ListWithStringScopeMixin.where(:parent_id => 6).map(&:id)
|
393
|
+
|
394
|
+
ListWithStringScopeMixin.find(2).update_attributes! :parent_id => 6
|
395
|
+
|
396
|
+
assert_equal [5, 6, 7, 8, 2], ListWithStringScopeMixin.where(:parent_id => 6).map(&:id)
|
397
|
+
|
398
|
+
assert_equal 1, ListWithStringScopeMixin.find(5).pos
|
399
|
+
assert_equal 2, ListWithStringScopeMixin.find(6).pos
|
400
|
+
assert_equal 3, ListWithStringScopeMixin.find(7).pos
|
401
|
+
assert_equal 4, ListWithStringScopeMixin.find(8).pos
|
402
|
+
assert_equal 5, ListWithStringScopeMixin.find(2).pos
|
311
403
|
end
|
312
404
|
|
313
405
|
end
|
@@ -334,41 +426,41 @@ class ListSubTest < Test::Unit::TestCase
|
|
334
426
|
end
|
335
427
|
|
336
428
|
def test_reordering
|
337
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
429
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5000).map(&:id)
|
338
430
|
|
339
431
|
ListMixin.find(2).move_lower
|
340
|
-
assert_equal [1, 3, 2, 4], ListMixin.where(
|
432
|
+
assert_equal [1, 3, 2, 4], ListMixin.where(:parent_id => 5000).map(&:id)
|
341
433
|
|
342
434
|
ListMixin.find(2).move_higher
|
343
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
435
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5000).map(&:id)
|
344
436
|
|
345
437
|
ListMixin.find(1).move_to_bottom
|
346
|
-
assert_equal [2, 3, 4, 1], ListMixin.where(
|
438
|
+
assert_equal [2, 3, 4, 1], ListMixin.where(:parent_id => 5000).map(&:id)
|
347
439
|
|
348
440
|
ListMixin.find(1).move_to_top
|
349
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
441
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5000).map(&:id)
|
350
442
|
|
351
443
|
ListMixin.find(2).move_to_bottom
|
352
|
-
assert_equal [1, 3, 4, 2], ListMixin.where(
|
444
|
+
assert_equal [1, 3, 4, 2], ListMixin.where(:parent_id => 5000).map(&:id)
|
353
445
|
|
354
446
|
ListMixin.find(4).move_to_top
|
355
|
-
assert_equal [4, 1, 3, 2], ListMixin.where(
|
447
|
+
assert_equal [4, 1, 3, 2], ListMixin.where(:parent_id => 5000).map(&:id)
|
356
448
|
end
|
357
449
|
|
358
450
|
def test_bounds_checking
|
359
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
451
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5000).map(&:pos)
|
360
452
|
|
361
453
|
ListMixin.find(1).move_higher
|
362
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
454
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5000).map(&:pos)
|
363
455
|
|
364
456
|
ListMixin.find(4).move_lower
|
365
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
457
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5000).map(&:pos)
|
366
458
|
end
|
367
459
|
|
368
460
|
def test_move_to_bottom_with_next_to_last_item
|
369
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
461
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5000).map(&:id)
|
370
462
|
ListMixin.find(3).move_to_bottom
|
371
|
-
assert_equal [1, 2, 4, 3], ListMixin.where(
|
463
|
+
assert_equal [1, 2, 4, 3], ListMixin.where(:parent_id => 5000).map(&:id)
|
372
464
|
end
|
373
465
|
|
374
466
|
def test_next_prev
|
@@ -379,22 +471,22 @@ class ListSubTest < Test::Unit::TestCase
|
|
379
471
|
end
|
380
472
|
|
381
473
|
def test_injection
|
382
|
-
item = ListMixin.new(
|
474
|
+
item = ListMixin.new(:parent_id => 1)
|
383
475
|
assert_equal({ :parent_id => 1 }, item.send(:scope_condition))
|
384
476
|
assert_equal("pos", item.send(:position_column))
|
385
477
|
end
|
386
478
|
|
387
479
|
def test_insert_at
|
388
|
-
new = ListMixin.create(
|
480
|
+
new = ListMixin.create(:parent_id => 20)
|
389
481
|
assert_equal 1, new.pos
|
390
482
|
|
391
|
-
new = ListMixinSub1.create(
|
483
|
+
new = ListMixinSub1.create(:parent_id => 20)
|
392
484
|
assert_equal 2, new.pos
|
393
485
|
|
394
|
-
new = ListMixinSub2.create(
|
486
|
+
new = ListMixinSub2.create(:parent_id => 20)
|
395
487
|
assert_equal 3, new.pos
|
396
488
|
|
397
|
-
new4 = ListMixin.create(
|
489
|
+
new4 = ListMixin.create(:parent_id => 20)
|
398
490
|
assert_equal 4, new4.pos
|
399
491
|
|
400
492
|
new4.insert_at(3)
|
@@ -409,7 +501,7 @@ class ListSubTest < Test::Unit::TestCase
|
|
409
501
|
new4.reload
|
410
502
|
assert_equal 4, new4.pos
|
411
503
|
|
412
|
-
new5 = ListMixinSub1.create(
|
504
|
+
new5 = ListMixinSub1.create(:parent_id => 20)
|
413
505
|
assert_equal 5, new5.pos
|
414
506
|
|
415
507
|
new5.insert_at(1)
|
@@ -420,11 +512,11 @@ class ListSubTest < Test::Unit::TestCase
|
|
420
512
|
end
|
421
513
|
|
422
514
|
def test_delete_middle
|
423
|
-
assert_equal [1, 2, 3, 4], ListMixin.where(
|
515
|
+
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 5000).map(&:id)
|
424
516
|
|
425
517
|
ListMixin.find(2).destroy
|
426
518
|
|
427
|
-
assert_equal [1, 3, 4], ListMixin.where(
|
519
|
+
assert_equal [1, 3, 4], ListMixin.where(:parent_id => 5000).map(&:id)
|
428
520
|
|
429
521
|
assert_equal 1, ListMixin.find(1).pos
|
430
522
|
assert_equal 2, ListMixin.find(3).pos
|
@@ -432,7 +524,7 @@ class ListSubTest < Test::Unit::TestCase
|
|
432
524
|
|
433
525
|
ListMixin.find(1).destroy
|
434
526
|
|
435
|
-
assert_equal [3, 4], ListMixin.where(
|
527
|
+
assert_equal [3, 4], ListMixin.where(:parent_id => 5000).map(&:id)
|
436
528
|
|
437
529
|
assert_equal 1, ListMixin.find(3).pos
|
438
530
|
assert_equal 2, ListMixin.find(4).pos
|
@@ -441,13 +533,13 @@ class ListSubTest < Test::Unit::TestCase
|
|
441
533
|
def test_higher_items
|
442
534
|
ListMixin.find(2).remove_from_list
|
443
535
|
assert_equal [1], ListMixin.find(3).higher_items.map(&:id)
|
444
|
-
assert_equal
|
536
|
+
assert_equal [], ListMixin.find(1).higher_items.map(&:id)
|
445
537
|
end
|
446
538
|
|
447
539
|
def test_lower_items
|
448
540
|
ListMixin.find(3).remove_from_list
|
449
541
|
assert_equal [4], ListMixin.find(2).lower_items.map(&:id)
|
450
|
-
assert_equal
|
542
|
+
assert_equal [], ListMixin.find(4).lower_items.map(&:id)
|
451
543
|
end
|
452
544
|
|
453
545
|
def test_list_class
|
@@ -460,12 +552,16 @@ class ArrayScopeListTest < Test::Unit::TestCase
|
|
460
552
|
|
461
553
|
def setup
|
462
554
|
setup_db
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
555
|
+
['ParentClass', 'bananas'].each do |parent_type|
|
556
|
+
[5, 6].each do |parent_id|
|
557
|
+
(1..4).each do |i|
|
558
|
+
ArrayScopeListMixin.create!(
|
559
|
+
:pos => i,
|
560
|
+
:parent_id => parent_id,
|
561
|
+
:parent_type => parent_type
|
562
|
+
)
|
563
|
+
end
|
564
|
+
end
|
469
565
|
end
|
470
566
|
end
|
471
567
|
|
@@ -524,8 +620,8 @@ class ArrayScopeListTest < Test::Unit::TestCase
|
|
524
620
|
|
525
621
|
def test_injection
|
526
622
|
item = ArrayScopeListMixin.new(conditions)
|
527
|
-
assert_equal
|
528
|
-
assert_equal
|
623
|
+
assert_equal conditions, item.send(:scope_condition)
|
624
|
+
assert_equal "pos", item.send(:position_column)
|
529
625
|
end
|
530
626
|
|
531
627
|
def test_insert
|
@@ -604,9 +700,92 @@ class ArrayScopeListTest < Test::Unit::TestCase
|
|
604
700
|
assert_equal 2, ArrayScopeListMixin.find(4).pos
|
605
701
|
end
|
606
702
|
|
703
|
+
def test_remove_from_list_by_updating_scope_part_1_should_shift_lower_items
|
704
|
+
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(conditions).map(&:id)
|
705
|
+
|
706
|
+
ArrayScopeListMixin.find(2).update_attributes! :parent_id => 6
|
707
|
+
|
708
|
+
assert_equal [1, 3, 4], ArrayScopeListMixin.where(conditions).map(&:id)
|
709
|
+
|
710
|
+
assert_equal 1, ArrayScopeListMixin.find(1).pos
|
711
|
+
assert_equal 2, ArrayScopeListMixin.find(3).pos
|
712
|
+
assert_equal 3, ArrayScopeListMixin.find(4).pos
|
713
|
+
end
|
714
|
+
|
715
|
+
def test_remove_from_list_by_updating_scope_part_2_should_shift_lower_items
|
716
|
+
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(conditions).map(&:id)
|
717
|
+
|
718
|
+
ArrayScopeListMixin.find(2).update_attributes! :parent_type => 'bananas'
|
719
|
+
|
720
|
+
assert_equal [1, 3, 4], ArrayScopeListMixin.where(conditions).map(&:id)
|
721
|
+
|
722
|
+
assert_equal 1, ArrayScopeListMixin.find(1).pos
|
723
|
+
assert_equal 2, ArrayScopeListMixin.find(3).pos
|
724
|
+
assert_equal 3, ArrayScopeListMixin.find(4).pos
|
725
|
+
end
|
726
|
+
|
727
|
+
def test_remove_from_list_by_updating_complete_scope_should_shift_lower_items
|
728
|
+
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(conditions).map(&:id)
|
729
|
+
|
730
|
+
ArrayScopeListMixin.find(2).update_attributes! :parent_id => 6, :parent_type => 'bananas'
|
731
|
+
|
732
|
+
assert_equal [1, 3, 4], ArrayScopeListMixin.where(conditions).map(&:id)
|
733
|
+
|
734
|
+
assert_equal 1, ArrayScopeListMixin.find(1).pos
|
735
|
+
assert_equal 2, ArrayScopeListMixin.find(3).pos
|
736
|
+
assert_equal 3, ArrayScopeListMixin.find(4).pos
|
737
|
+
end
|
738
|
+
|
739
|
+
def test_move_to_new_list_by_updating_scope_part_1_should_append
|
740
|
+
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(conditions).map(&:id)
|
741
|
+
assert_equal [5, 6, 7, 8], ArrayScopeListMixin.where(conditions(:parent_id => 6)).map(&:id)
|
742
|
+
|
743
|
+
ArrayScopeListMixin.find(2).update_attributes! :parent_id => 6
|
744
|
+
|
745
|
+
assert_equal [5, 6, 7, 8, 2], ArrayScopeListMixin.where(conditions(:parent_id => 6)).map(&:id)
|
746
|
+
|
747
|
+
assert_equal 1, ArrayScopeListMixin.find(5).pos
|
748
|
+
assert_equal 2, ArrayScopeListMixin.find(6).pos
|
749
|
+
assert_equal 3, ArrayScopeListMixin.find(7).pos
|
750
|
+
assert_equal 4, ArrayScopeListMixin.find(8).pos
|
751
|
+
assert_equal 5, ArrayScopeListMixin.find(2).pos
|
752
|
+
end
|
753
|
+
|
754
|
+
def test_move_to_new_list_by_updating_scope_part_2_should_append
|
755
|
+
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(conditions).map(&:id)
|
756
|
+
assert_equal [9, 10, 11, 12], ArrayScopeListMixin.where(conditions(:parent_type => 'bananas')).map(&:id)
|
757
|
+
|
758
|
+
ArrayScopeListMixin.find(2).update_attributes! :parent_type => 'bananas'
|
759
|
+
|
760
|
+
assert_equal [9, 10, 11, 12, 2], ArrayScopeListMixin.where(conditions(:parent_type => 'bananas')).map(&:id)
|
761
|
+
|
762
|
+
assert_equal 1, ArrayScopeListMixin.find(9).pos
|
763
|
+
assert_equal 2, ArrayScopeListMixin.find(10).pos
|
764
|
+
assert_equal 3, ArrayScopeListMixin.find(11).pos
|
765
|
+
assert_equal 4, ArrayScopeListMixin.find(12).pos
|
766
|
+
assert_equal 5, ArrayScopeListMixin.find(2).pos
|
767
|
+
end
|
768
|
+
|
769
|
+
def test_move_to_new_list_by_updating_complete_scope_should_append
|
770
|
+
assert_equal [ 1, 2, 3, 4], ArrayScopeListMixin.where(conditions).map(&:id)
|
771
|
+
assert_equal [13, 14, 15, 16], ArrayScopeListMixin.where(:parent_id => 6, :parent_type => 'bananas').map(&:id)
|
772
|
+
|
773
|
+
ArrayScopeListMixin.find(2).update_attributes! :parent_id => 6, :parent_type => 'bananas'
|
774
|
+
|
775
|
+
assert_equal [13, 14, 15, 16, 2], ArrayScopeListMixin.where(:parent_id => 6, :parent_type => 'bananas').map(&:id)
|
776
|
+
|
777
|
+
assert_equal 1, ArrayScopeListMixin.find(13).pos
|
778
|
+
assert_equal 2, ArrayScopeListMixin.find(14).pos
|
779
|
+
assert_equal 3, ArrayScopeListMixin.find(15).pos
|
780
|
+
assert_equal 4, ArrayScopeListMixin.find(16).pos
|
781
|
+
assert_equal 5, ArrayScopeListMixin.find(2).pos
|
782
|
+
end
|
783
|
+
|
607
784
|
def test_remove_from_list_should_then_fail_in_list?
|
608
785
|
assert_equal true, ArrayScopeListMixin.find(1).in_list?
|
786
|
+
|
609
787
|
ArrayScopeListMixin.find(1).remove_from_list
|
788
|
+
|
610
789
|
assert_equal false, ArrayScopeListMixin.find(1).in_list?
|
611
790
|
end
|
612
791
|
|
@@ -638,12 +817,12 @@ class ArrayScopeListTest < Test::Unit::TestCase
|
|
638
817
|
|
639
818
|
def test_higher_items
|
640
819
|
assert_equal [1, 2], ArrayScopeListMixin.find(3).higher_items.map(&:id)
|
641
|
-
assert_equal
|
820
|
+
assert_equal [], ArrayScopeListMixin.find(1).higher_items.map(&:id)
|
642
821
|
end
|
643
822
|
|
644
823
|
def test_lower_items
|
645
824
|
assert_equal [3, 4], ArrayScopeListMixin.find(2).lower_items.map(&:id)
|
646
|
-
assert_equal
|
825
|
+
assert_equal [], ArrayScopeListMixin.find(4).lower_items.map(&:id)
|
647
826
|
end
|
648
827
|
|
649
828
|
end
|
@@ -652,16 +831,16 @@ class AssociationScopeListTest < Test::Unit::TestCase
|
|
652
831
|
|
653
832
|
def setup
|
654
833
|
setup_db
|
655
|
-
(1..4).each do |
|
834
|
+
(1..4).each do |i|
|
656
835
|
AssociationScopeListMixin.create!(
|
657
|
-
:pos =>
|
836
|
+
:pos => i,
|
658
837
|
:parent_id => 5
|
659
838
|
)
|
660
839
|
end
|
661
840
|
|
662
|
-
(1..4).each do |
|
841
|
+
(1..4).each do |i|
|
663
842
|
PolymorphicAssociationScopeListMixin.create!(
|
664
|
-
:pos =>
|
843
|
+
:pos => i,
|
665
844
|
:parent_id => 5,
|
666
845
|
:parent_type => 'ParentClass'
|
667
846
|
)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sortifiable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andrew White
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-04-
|
18
|
+
date: 2011-04-20 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|