acts_as_list 0.8.2 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +13 -8
- data/CHANGELOG.md +14 -0
- data/Gemfile +16 -3
- data/README.md +37 -0
- data/gemfiles/rails_3_2.gemfile +16 -2
- data/gemfiles/rails_4_1.gemfile +16 -2
- data/gemfiles/rails_4_2.gemfile +16 -2
- data/gemfiles/rails_5_0.gemfile +16 -2
- data/lib/acts_as_list.rb +8 -14
- data/lib/acts_as_list/active_record/acts/add_new_at_method_definer.rb +9 -0
- data/lib/acts_as_list/active_record/acts/aux_method_definer.rb +9 -0
- data/lib/acts_as_list/active_record/acts/callback_definer.rb +19 -0
- data/lib/acts_as_list/active_record/acts/column_method_definer.rb +50 -0
- data/lib/acts_as_list/active_record/acts/list.rb +224 -302
- data/lib/acts_as_list/active_record/acts/no_update.rb +50 -0
- data/lib/acts_as_list/active_record/acts/scope_method_definer.rb +49 -0
- data/lib/acts_as_list/active_record/acts/sequential_updates_method_definer.rb +21 -0
- data/lib/acts_as_list/active_record/acts/top_of_list_method_definer.rb +13 -0
- data/lib/acts_as_list/version.rb +1 -1
- data/test/database.yml +16 -0
- data/test/helper.rb +12 -0
- data/test/shared_array_scope_list.rb +19 -4
- data/test/shared_list.rb +34 -10
- data/test/shared_list_sub.rb +17 -1
- data/test/shared_no_addition.rb +2 -2
- data/test/shared_top_addition.rb +16 -1
- data/test/shared_zero_based.rb +11 -0
- data/test/test_joined_list.rb +8 -2
- data/test/test_list.rb +148 -44
- metadata +12 -2
data/test/shared_zero_based.rb
CHANGED
@@ -15,6 +15,11 @@ module Shared
|
|
15
15
|
assert !new.first?
|
16
16
|
assert new.last?
|
17
17
|
|
18
|
+
new = ZeroBasedMixin.acts_as_list_no_update { ZeroBasedMixin.create(parent_id: 20) }
|
19
|
+
assert_equal_or_nil $default_position, new.pos
|
20
|
+
assert !new.first?
|
21
|
+
assert !new.last?
|
22
|
+
|
18
23
|
new = ZeroBasedMixin.create(parent_id: 20)
|
19
24
|
assert_equal 2, new.pos
|
20
25
|
assert !new.first?
|
@@ -63,6 +68,9 @@ module Shared
|
|
63
68
|
new = ZeroBasedMixin.create(parent_id: 20)
|
64
69
|
assert_equal 2, new.pos
|
65
70
|
|
71
|
+
new_noup = ZeroBasedMixin.acts_as_list_no_update { ZeroBasedMixin.create(parent_id: 20) }
|
72
|
+
assert_equal_or_nil $default_position, new_noup.pos
|
73
|
+
|
66
74
|
new4 = ZeroBasedMixin.create(parent_id: 20)
|
67
75
|
assert_equal 3, new4.pos
|
68
76
|
|
@@ -86,6 +94,9 @@ module Shared
|
|
86
94
|
|
87
95
|
new4.reload
|
88
96
|
assert_equal 4, new4.pos
|
97
|
+
|
98
|
+
new_noup.reload
|
99
|
+
assert_equal_or_nil $default_position, new_noup.pos
|
89
100
|
end
|
90
101
|
end
|
91
102
|
end
|
data/test/test_joined_list.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
|
3
|
+
db_config = YAML.load_file(File.expand_path("../database.yml", __FILE__)).fetch(ENV["DB"] || "sqlite")
|
4
|
+
ActiveRecord::Base.establish_connection(db_config)
|
4
5
|
ActiveRecord::Schema.verbose = false
|
5
6
|
|
6
7
|
class Section < ActiveRecord::Base
|
@@ -36,7 +37,12 @@ class JoinedTestCase < Minitest::Test
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def teardown
|
39
|
-
ActiveRecord::
|
40
|
+
if ActiveRecord::VERSION::MAJOR >= 5
|
41
|
+
tables = ActiveRecord::Base.connection.data_sources
|
42
|
+
else
|
43
|
+
tables = ActiveRecord::Base.connection.tables
|
44
|
+
end
|
45
|
+
tables.each do |table|
|
40
46
|
ActiveRecord::Base.connection.drop_table(table)
|
41
47
|
end
|
42
48
|
super
|
data/test/test_list.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
# NOTE: following now done in helper.rb (better Readability)
|
2
2
|
require 'helper'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
database: 'file:memdb1?mode=memory&cache=shared'
|
7
|
-
)
|
4
|
+
db_config = YAML.load_file(File.expand_path("../database.yml", __FILE__)).fetch(ENV["DB"] || "sqlite")
|
5
|
+
ActiveRecord::Base.establish_connection(db_config)
|
8
6
|
ActiveRecord::Schema.verbose = false
|
9
7
|
|
10
8
|
def setup_db(position_options = {})
|
9
|
+
$default_position = position_options[:default]
|
10
|
+
|
11
|
+
# sqlite cannot drop/rename/alter columns and add constraints after table creation
|
12
|
+
sqlite = ENV.fetch("DB", "sqlite") == "sqlite"
|
13
|
+
|
11
14
|
# AR caches columns options like defaults etc. Clear them!
|
12
15
|
ActiveRecord::Base.connection.create_table :mixins do |t|
|
13
|
-
t.column :pos, :integer, position_options
|
16
|
+
t.column :pos, :integer, position_options unless position_options[:positive] && sqlite
|
14
17
|
t.column :active, :boolean, default: true
|
15
18
|
t.column :parent_id, :integer
|
16
19
|
t.column :parent_type, :string
|
@@ -19,6 +22,20 @@ def setup_db(position_options = {})
|
|
19
22
|
t.column :state, :integer
|
20
23
|
end
|
21
24
|
|
25
|
+
if position_options[:unique] && !(sqlite && position_options[:positive])
|
26
|
+
ActiveRecord::Base.connection.add_index :mixins, :pos, unique: true
|
27
|
+
end
|
28
|
+
|
29
|
+
if position_options[:positive]
|
30
|
+
if sqlite
|
31
|
+
# SQLite cannot add constraint after table creation, also cannot add unique inside ADD COLUMN
|
32
|
+
ActiveRecord::Base.connection.execute('ALTER TABLE mixins ADD COLUMN pos integer8 NOT NULL CHECK (pos > 0) DEFAULT 1')
|
33
|
+
ActiveRecord::Base.connection.execute('CREATE UNIQUE INDEX index_mixins_on_pos ON mixins(pos)')
|
34
|
+
else
|
35
|
+
ActiveRecord::Base.connection.execute('ALTER TABLE mixins ADD CONSTRAINT pos_check CHECK (pos > 0)')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
22
39
|
# This table is used to test table names and column names quoting
|
23
40
|
ActiveRecord::Base.connection.create_table 'table-name' do |t|
|
24
41
|
t.column :order, :integer
|
@@ -115,6 +132,14 @@ class DefaultScopedWhereMixin < Mixin
|
|
115
132
|
end
|
116
133
|
end
|
117
134
|
|
135
|
+
class SequentialUpdatesDefault < Mixin
|
136
|
+
acts_as_list column: "pos"
|
137
|
+
end
|
138
|
+
|
139
|
+
class SequentialUpdatesFalseMixin < Mixin
|
140
|
+
acts_as_list column: "pos", sequential_updates: false
|
141
|
+
end
|
142
|
+
|
118
143
|
class TopAdditionMixin < Mixin
|
119
144
|
acts_as_list column: "pos", add_new_at: :top, scope: :parent_id
|
120
145
|
end
|
@@ -163,13 +188,6 @@ end
|
|
163
188
|
class TheBaseSubclass < TheBaseClass
|
164
189
|
end
|
165
190
|
|
166
|
-
class DBConfigTest < Minitest::Test
|
167
|
-
def test_db_config
|
168
|
-
# make sure sqlite3 accepts multi threaded access
|
169
|
-
assert_equal "file:memdb1?mode=memory&cache=shared", ActiveRecord::Base.connection.pool.spec.config[:database]
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
191
|
class QuotedList < ActiveRecord::Base
|
174
192
|
self.table_name = 'table-name'
|
175
193
|
acts_as_list column: :order
|
@@ -239,7 +257,7 @@ class ListTest < ActsAsListTestCase
|
|
239
257
|
wait_for_it = false
|
240
258
|
threads.each(&:join)
|
241
259
|
|
242
|
-
assert_equal
|
260
|
+
assert_equal((1..n).to_a, ListMixin.where(parent_id: 1).order('pos').map(&:pos))
|
243
261
|
end
|
244
262
|
end
|
245
263
|
|
@@ -326,6 +344,11 @@ class DefaultScopedTest < ActsAsListTestCase
|
|
326
344
|
assert !new.first?
|
327
345
|
assert new.last?
|
328
346
|
|
347
|
+
new = DefaultScopedMixin.acts_as_list_no_update { DefaultScopedMixin.create }
|
348
|
+
assert_equal_or_nil $default_position, new.pos
|
349
|
+
assert_equal $default_position.is_a?(Fixnum), new.first?
|
350
|
+
assert !new.last?
|
351
|
+
|
329
352
|
new = DefaultScopedMixin.create
|
330
353
|
assert_equal 7, new.pos
|
331
354
|
assert !new.first?
|
@@ -361,6 +384,9 @@ class DefaultScopedTest < ActsAsListTestCase
|
|
361
384
|
new = DefaultScopedMixin.create
|
362
385
|
assert_equal 6, new.pos
|
363
386
|
|
387
|
+
new_noup = DefaultScopedMixin.acts_as_list_no_update { DefaultScopedMixin.create }
|
388
|
+
assert_equal_or_nil $default_position, new_noup.pos
|
389
|
+
|
364
390
|
new = DefaultScopedMixin.create
|
365
391
|
assert_equal 7, new.pos
|
366
392
|
|
@@ -387,6 +413,9 @@ class DefaultScopedTest < ActsAsListTestCase
|
|
387
413
|
|
388
414
|
new4.reload
|
389
415
|
assert_equal 4, new4.pos
|
416
|
+
|
417
|
+
new_noup.reload
|
418
|
+
assert_equal_or_nil $default_position, new_noup.pos
|
390
419
|
end
|
391
420
|
|
392
421
|
def test_update_position
|
@@ -419,6 +448,11 @@ class DefaultScopedWhereTest < ActsAsListTestCase
|
|
419
448
|
assert !new.first?
|
420
449
|
assert new.last?
|
421
450
|
|
451
|
+
new = DefaultScopedWhereMixin.acts_as_list_no_update { DefaultScopedWhereMixin.create }
|
452
|
+
assert_equal_or_nil $default_position, new.pos
|
453
|
+
assert_equal $default_position.is_a?(Fixnum), new.first?
|
454
|
+
assert !new.last?
|
455
|
+
|
422
456
|
new = DefaultScopedWhereMixin.create
|
423
457
|
assert_equal 7, new.pos
|
424
458
|
assert !new.first?
|
@@ -457,6 +491,9 @@ class DefaultScopedWhereTest < ActsAsListTestCase
|
|
457
491
|
new = DefaultScopedWhereMixin.create
|
458
492
|
assert_equal 7, new.pos
|
459
493
|
|
494
|
+
new_noup = DefaultScopedWhereMixin.acts_as_list_no_update { DefaultScopedWhereMixin.create }
|
495
|
+
assert_equal_or_nil $default_position, new_noup.pos
|
496
|
+
|
460
497
|
new4 = DefaultScopedWhereMixin.create
|
461
498
|
assert_equal 8, new4.pos
|
462
499
|
|
@@ -480,6 +517,9 @@ class DefaultScopedWhereTest < ActsAsListTestCase
|
|
480
517
|
|
481
518
|
new4.reload
|
482
519
|
assert_equal 4, new4.pos
|
520
|
+
|
521
|
+
new_noup.reload
|
522
|
+
assert_equal_or_nil $default_position, new_noup.pos
|
483
523
|
end
|
484
524
|
|
485
525
|
def test_update_position
|
@@ -534,10 +574,20 @@ class MultiDestroyTest < ActsAsListTestCase
|
|
534
574
|
new3 = DefaultScopedMixin.create
|
535
575
|
assert_equal 3, new3.pos
|
536
576
|
|
577
|
+
new4 = DefaultScopedMixin.create
|
578
|
+
assert_equal 4, new4.pos
|
579
|
+
|
537
580
|
new1.destroy
|
538
581
|
new2.destroy
|
539
582
|
new3.reload
|
583
|
+
new4.reload
|
540
584
|
assert_equal 1, new3.pos
|
585
|
+
assert_equal 2, new4.pos
|
586
|
+
|
587
|
+
DefaultScopedMixin.acts_as_list_no_update { new3.destroy }
|
588
|
+
|
589
|
+
new4.reload
|
590
|
+
assert_equal 2, new4.pos
|
541
591
|
end
|
542
592
|
end
|
543
593
|
|
@@ -670,65 +720,79 @@ class MultipleListsArrayScopeTest < ActsAsListTestCase
|
|
670
720
|
end
|
671
721
|
end
|
672
722
|
|
723
|
+
require 'timecop'
|
724
|
+
|
673
725
|
class TouchTest < ActsAsListTestCase
|
674
726
|
def setup
|
675
727
|
setup_db
|
676
|
-
|
728
|
+
Timecop.freeze(yesterday) do
|
729
|
+
4.times { ListMixin.create! }
|
730
|
+
end
|
677
731
|
end
|
678
732
|
|
679
733
|
def now
|
680
|
-
Time.
|
734
|
+
@now ||= Time.current
|
681
735
|
end
|
682
736
|
|
683
737
|
def yesterday
|
684
|
-
1.day.ago
|
738
|
+
@yesterday ||= 1.day.ago
|
685
739
|
end
|
686
740
|
|
687
741
|
def updated_ats
|
688
|
-
ListMixin.pluck(:updated_at)
|
742
|
+
ListMixin.order(:id).pluck(:updated_at)
|
689
743
|
end
|
690
744
|
|
691
745
|
def test_moving_item_lower_touches_self_and_lower_item
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
746
|
+
Timecop.freeze(now) do
|
747
|
+
ListMixin.first.move_lower
|
748
|
+
updated_ats[0..1].each do |updated_at|
|
749
|
+
assert_equal updated_at.to_i, now.to_i
|
750
|
+
end
|
751
|
+
updated_ats[2..3].each do |updated_at|
|
752
|
+
assert_equal updated_at.to_i, yesterday.to_i
|
753
|
+
end
|
698
754
|
end
|
699
755
|
end
|
700
756
|
|
701
757
|
def test_moving_item_higher_touches_self_and_higher_item
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
758
|
+
Timecop.freeze(now) do
|
759
|
+
ListMixin.all.second.move_higher
|
760
|
+
updated_ats[0..1].each do |updated_at|
|
761
|
+
assert_equal updated_at.to_i, now.to_i
|
762
|
+
end
|
763
|
+
updated_ats[2..3].each do |updated_at|
|
764
|
+
assert_equal updated_at.to_i, yesterday.to_i
|
765
|
+
end
|
708
766
|
end
|
709
767
|
end
|
710
768
|
|
711
769
|
def test_moving_item_to_bottom_touches_all_other_items
|
712
|
-
|
713
|
-
|
714
|
-
|
770
|
+
Timecop.freeze(now) do
|
771
|
+
ListMixin.first.move_to_bottom
|
772
|
+
updated_ats.each do |updated_at|
|
773
|
+
assert_equal updated_at.to_i, now.to_i
|
774
|
+
end
|
715
775
|
end
|
716
776
|
end
|
717
777
|
|
718
778
|
def test_moving_item_to_top_touches_all_other_items
|
719
|
-
|
720
|
-
|
721
|
-
|
779
|
+
Timecop.freeze(now) do
|
780
|
+
ListMixin.last.move_to_top
|
781
|
+
updated_ats.each do |updated_at|
|
782
|
+
assert_equal updated_at.to_i, now.to_i
|
783
|
+
end
|
722
784
|
end
|
723
785
|
end
|
724
786
|
|
725
787
|
def test_removing_item_touches_all_lower_items
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
788
|
+
Timecop.freeze(now) do
|
789
|
+
ListMixin.all.third.remove_from_list
|
790
|
+
updated_ats[0..1].each do |updated_at|
|
791
|
+
assert_equal updated_at.to_i, yesterday.to_i
|
792
|
+
end
|
793
|
+
updated_ats[2..2].each do |updated_at|
|
794
|
+
assert_equal updated_at.to_i, now.to_i
|
795
|
+
end
|
732
796
|
end
|
733
797
|
end
|
734
798
|
end
|
@@ -768,8 +832,9 @@ class NilPositionTest < ActsAsListTestCase
|
|
768
832
|
new3.reload.pos = 1
|
769
833
|
new3.save
|
770
834
|
|
771
|
-
assert_equal [
|
772
|
-
assert_equal [
|
835
|
+
assert_equal [1, 2], DefaultScopedMixin.where("pos IS NOT NULL").map(&:pos)
|
836
|
+
assert_equal [3, 1], DefaultScopedMixin.where("pos IS NOT NULL").map(&:id)
|
837
|
+
assert_nil new2.reload.pos
|
773
838
|
|
774
839
|
new2.reload.pos = 1
|
775
840
|
new2.save
|
@@ -777,4 +842,43 @@ class NilPositionTest < ActsAsListTestCase
|
|
777
842
|
assert_equal [1, 2, 3], DefaultScopedMixin.all.map(&:pos)
|
778
843
|
assert_equal [2, 3, 1], DefaultScopedMixin.all.map(&:id)
|
779
844
|
end
|
780
|
-
end
|
845
|
+
end
|
846
|
+
|
847
|
+
class SequentialUpdatesOptionDefaultTest < ActsAsListTestCase
|
848
|
+
def setup
|
849
|
+
setup_db
|
850
|
+
end
|
851
|
+
|
852
|
+
def test_sequential_updates_default_to_false_without_unique_index
|
853
|
+
assert_equal false, SequentialUpdatesDefault.new.send(:sequential_updates?)
|
854
|
+
end
|
855
|
+
end
|
856
|
+
|
857
|
+
class SequentialUpdatesMixinNotNullUniquePositiveConstraintsTest < ActsAsListTestCase
|
858
|
+
def setup
|
859
|
+
setup_db null: false, unique: true, positive: true
|
860
|
+
(1..4).each { |counter| SequentialUpdatesDefault.create!({pos: counter}) }
|
861
|
+
end
|
862
|
+
|
863
|
+
def test_sequential_updates_default_to_true_with_unique_index
|
864
|
+
assert_equal true, SequentialUpdatesDefault.new.send(:sequential_updates?)
|
865
|
+
end
|
866
|
+
|
867
|
+
def test_sequential_updates_option_override_with_false
|
868
|
+
assert_equal false, SequentialUpdatesFalseMixin.new.send(:sequential_updates?)
|
869
|
+
end
|
870
|
+
|
871
|
+
def test_insert_at
|
872
|
+
new = SequentialUpdatesDefault.create
|
873
|
+
assert_equal 5, new.pos
|
874
|
+
|
875
|
+
new.insert_at(1)
|
876
|
+
assert_equal 1, new.pos
|
877
|
+
|
878
|
+
new.insert_at(5)
|
879
|
+
assert_equal 5, new.pos
|
880
|
+
|
881
|
+
new.insert_at(3)
|
882
|
+
assert_equal 3, new.pos
|
883
|
+
end
|
884
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_list
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2017-01-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -65,8 +65,17 @@ files:
|
|
65
65
|
- gemfiles/rails_5_0.gemfile
|
66
66
|
- init.rb
|
67
67
|
- lib/acts_as_list.rb
|
68
|
+
- lib/acts_as_list/active_record/acts/add_new_at_method_definer.rb
|
69
|
+
- lib/acts_as_list/active_record/acts/aux_method_definer.rb
|
70
|
+
- lib/acts_as_list/active_record/acts/callback_definer.rb
|
71
|
+
- lib/acts_as_list/active_record/acts/column_method_definer.rb
|
68
72
|
- lib/acts_as_list/active_record/acts/list.rb
|
73
|
+
- lib/acts_as_list/active_record/acts/no_update.rb
|
74
|
+
- lib/acts_as_list/active_record/acts/scope_method_definer.rb
|
75
|
+
- lib/acts_as_list/active_record/acts/sequential_updates_method_definer.rb
|
76
|
+
- lib/acts_as_list/active_record/acts/top_of_list_method_definer.rb
|
69
77
|
- lib/acts_as_list/version.rb
|
78
|
+
- test/database.yml
|
70
79
|
- test/helper.rb
|
71
80
|
- test/shared.rb
|
72
81
|
- test/shared_array_scope_list.rb
|
@@ -104,6 +113,7 @@ specification_version: 4
|
|
104
113
|
summary: A gem adding sorting, reordering capabilities to an active_record model,
|
105
114
|
allowing it to act as a list
|
106
115
|
test_files:
|
116
|
+
- test/database.yml
|
107
117
|
- test/helper.rb
|
108
118
|
- test/shared.rb
|
109
119
|
- test/shared_array_scope_list.rb
|