sortifiable 0.2.0 → 0.2.1
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.
- 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
|