acts_as_list 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|