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 CHANGED
@@ -1,3 +1,8 @@
1
+ *0.2.1 (April 20th, 2011)
2
+
3
+ * Add checking for scope changes so items are moved between lists correctly [Manuel Meurer]
4
+
5
+
1
6
  *0.2.0 (April 7th, 2011)
2
7
 
3
8
  * Use pessimistic locking to reduce concurrency problems
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
@@ -1,3 +1,3 @@
1
1
  module Sortifiable
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
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) && reflections.key?(options[:scope])
52
- reflection = reflections[options.delete(:scope)]
53
-
54
- if reflection.belongs_to?
55
- if reflection.options[:polymorphic]
56
- options[:scope] = [
57
- reflection.association_foreign_key.to_sym,
58
- reflection.options[:foreign_type].to_sym
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
- options[:scope] = reflection.association_foreign_key.to_sym
65
+ raise ArgumentError, "Only belongs_to associations can be used as a scope"
62
66
  end
63
- else
64
- raise ArgumentError, "Only belongs_to associations can be used as a scope"
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
- before_create :add_to_list
74
- before_destroy :decrement_position_on_lower_items, :if => :in_list?
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(last_position + 1)
100
+ update_position last_position + 1
96
101
  else
97
- send("#{position_column}=".to_sym, last_position + 1)
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
- item = last_item
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
- send("#{position_column}=".to_sym, current_position - 1)
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
- send("#{position_column}=".to_sym, current_position + 1)
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
- send("#{position_column}=".to_sym, last_position)
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
- send("#{position_column}=".to_sym, 1)
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
- send("#{position_column}=".to_sym, nil)
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("\"#{acts_as_list_options[:scope]}\"")
436
+ instance_eval %("#{acts_as_list_options[:scope]}")
388
437
  else
389
- Array.wrap(acts_as_list_options[:scope]).inject({}){ |m,k| m[k] = send(k); m }
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(["#{quoted_position_column} = ?", new_position], list_class.primary_key => id)
395
- send("#{position_column}=".to_sym, new_position)
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
@@ -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
- (1..4).each { |counter| ListMixin.create! :pos => counter, :parent_id => 5 }
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:pos)
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('parent_id = 5').map(&:pos)
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('parent_id = 5').map(&:pos)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id IS NULL')
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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('parent_id = 5').map(&:id)
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 [], ListMixin.find(1).higher_items.map(&:id)
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 [], ListMixin.find(4).lower_items.map(&:id)
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('parent_id = 5000').map(&:id)
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('parent_id = 5000').map(&:id)
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('parent_id = 5000').map(&:id)
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('parent_id = 5000').map(&:id)
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('parent_id = 5000').map(&:id)
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('parent_id = 5000').map(&:id)
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('parent_id = 5000').map(&:id)
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('parent_id = 5000').map(&:pos)
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('parent_id = 5000').map(&:pos)
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('parent_id = 5000').map(&:pos)
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('parent_id = 5000').map(&:id)
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('parent_id = 5000').map(&:id)
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("parent_id"=>1)
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("parent_id" => 20)
480
+ new = ListMixin.create(:parent_id => 20)
389
481
  assert_equal 1, new.pos
390
482
 
391
- new = ListMixinSub1.create("parent_id" => 20)
483
+ new = ListMixinSub1.create(:parent_id => 20)
392
484
  assert_equal 2, new.pos
393
485
 
394
- new = ListMixinSub2.create("parent_id" => 20)
486
+ new = ListMixinSub2.create(:parent_id => 20)
395
487
  assert_equal 3, new.pos
396
488
 
397
- new4 = ListMixin.create("parent_id" => 20)
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("parent_id" => 20)
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('parent_id = 5000').map(&:id)
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('parent_id = 5000').map(&:id)
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('parent_id = 5000').map(&:id)
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 [], ListMixin.find(1).higher_items.map(&:id)
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 [], ListMixin.find(4).lower_items.map(&:id)
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
- (1..4).each do |counter|
464
- ArrayScopeListMixin.create!(
465
- :pos => counter,
466
- :parent_id => 5,
467
- :parent_type => 'ParentClass'
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(conditions, item.send(:scope_condition))
528
- assert_equal("pos", item.send(:position_column))
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 [], ArrayScopeListMixin.find(1).higher_items.map(&:id)
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 [], ArrayScopeListMixin.find(4).lower_items.map(&:id)
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 |counter|
834
+ (1..4).each do |i|
656
835
  AssociationScopeListMixin.create!(
657
- :pos => counter,
836
+ :pos => i,
658
837
  :parent_id => 5
659
838
  )
660
839
  end
661
840
 
662
- (1..4).each do |counter|
841
+ (1..4).each do |i|
663
842
  PolymorphicAssociationScopeListMixin.create!(
664
- :pos => counter,
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: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 0
10
- version: 0.2.0
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-07 00:00:00 +01:00
18
+ date: 2011-04-20 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency