acts_as_ordered_tree 1.3.1 → 2.0.0.beta3

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.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/lib/acts_as_ordered_tree.rb +22 -100
  3. data/lib/acts_as_ordered_tree/adapters.rb +17 -0
  4. data/lib/acts_as_ordered_tree/adapters/abstract.rb +23 -0
  5. data/lib/acts_as_ordered_tree/adapters/postgresql.rb +150 -0
  6. data/lib/acts_as_ordered_tree/adapters/recursive.rb +157 -0
  7. data/lib/acts_as_ordered_tree/compatibility.rb +22 -0
  8. data/lib/acts_as_ordered_tree/compatibility/active_record/association_scope.rb +9 -0
  9. data/lib/acts_as_ordered_tree/compatibility/active_record/default_scoped.rb +19 -0
  10. data/lib/acts_as_ordered_tree/compatibility/active_record/null_relation.rb +71 -0
  11. data/lib/acts_as_ordered_tree/compatibility/features.rb +153 -0
  12. data/lib/acts_as_ordered_tree/deprecate.rb +24 -0
  13. data/lib/acts_as_ordered_tree/hooks.rb +38 -0
  14. data/lib/acts_as_ordered_tree/hooks/update.rb +86 -0
  15. data/lib/acts_as_ordered_tree/instance_methods.rb +92 -453
  16. data/lib/acts_as_ordered_tree/iterators/arranger.rb +35 -0
  17. data/lib/acts_as_ordered_tree/iterators/level_calculator.rb +52 -0
  18. data/lib/acts_as_ordered_tree/iterators/orphans_pruner.rb +58 -0
  19. data/lib/acts_as_ordered_tree/node.rb +78 -0
  20. data/lib/acts_as_ordered_tree/node/attributes.rb +48 -0
  21. data/lib/acts_as_ordered_tree/node/movement.rb +62 -0
  22. data/lib/acts_as_ordered_tree/node/movements.rb +111 -0
  23. data/lib/acts_as_ordered_tree/node/predicates.rb +98 -0
  24. data/lib/acts_as_ordered_tree/node/reloading.rb +49 -0
  25. data/lib/acts_as_ordered_tree/node/siblings.rb +139 -0
  26. data/lib/acts_as_ordered_tree/node/traversals.rb +53 -0
  27. data/lib/acts_as_ordered_tree/persevering_transaction.rb +93 -0
  28. data/lib/acts_as_ordered_tree/position.rb +143 -0
  29. data/lib/acts_as_ordered_tree/relation/arrangeable.rb +33 -0
  30. data/lib/acts_as_ordered_tree/relation/iterable.rb +41 -0
  31. data/lib/acts_as_ordered_tree/relation/preloaded.rb +46 -11
  32. data/lib/acts_as_ordered_tree/transaction/base.rb +57 -0
  33. data/lib/acts_as_ordered_tree/transaction/callbacks.rb +67 -0
  34. data/lib/acts_as_ordered_tree/transaction/create.rb +68 -0
  35. data/lib/acts_as_ordered_tree/transaction/destroy.rb +34 -0
  36. data/lib/acts_as_ordered_tree/transaction/dsl.rb +214 -0
  37. data/lib/acts_as_ordered_tree/transaction/factory.rb +67 -0
  38. data/lib/acts_as_ordered_tree/transaction/move.rb +70 -0
  39. data/lib/acts_as_ordered_tree/transaction/passthrough.rb +12 -0
  40. data/lib/acts_as_ordered_tree/transaction/reorder.rb +42 -0
  41. data/lib/acts_as_ordered_tree/transaction/save.rb +64 -0
  42. data/lib/acts_as_ordered_tree/transaction/update.rb +78 -0
  43. data/lib/acts_as_ordered_tree/tree.rb +148 -0
  44. data/lib/acts_as_ordered_tree/tree/association.rb +20 -0
  45. data/lib/acts_as_ordered_tree/tree/callbacks.rb +57 -0
  46. data/lib/acts_as_ordered_tree/tree/children_association.rb +120 -0
  47. data/lib/acts_as_ordered_tree/tree/columns.rb +102 -0
  48. data/lib/acts_as_ordered_tree/tree/deprecated_columns_accessors.rb +24 -0
  49. data/lib/acts_as_ordered_tree/tree/parent_association.rb +31 -0
  50. data/lib/acts_as_ordered_tree/tree/perseverance.rb +19 -0
  51. data/lib/acts_as_ordered_tree/tree/scopes.rb +56 -0
  52. data/lib/acts_as_ordered_tree/validators.rb +1 -1
  53. data/lib/acts_as_ordered_tree/version.rb +1 -1
  54. data/spec/acts_as_ordered_tree_spec.rb +80 -909
  55. data/spec/adapters/postgresql_spec.rb +14 -0
  56. data/spec/adapters/recursive_spec.rb +12 -0
  57. data/spec/adapters/shared.rb +272 -0
  58. data/spec/callbacks_spec.rb +177 -0
  59. data/spec/counter_cache_spec.rb +31 -0
  60. data/spec/create_spec.rb +110 -0
  61. data/spec/destroy_spec.rb +57 -0
  62. data/spec/inheritance_spec.rb +176 -0
  63. data/spec/move_spec.rb +94 -0
  64. data/spec/node/movements/concurrent_movements_spec.rb +354 -0
  65. data/spec/node/movements/move_higher_spec.rb +46 -0
  66. data/spec/node/movements/move_lower_spec.rb +46 -0
  67. data/spec/node/movements/move_to_child_of_spec.rb +147 -0
  68. data/spec/node/movements/move_to_child_with_index_spec.rb +124 -0
  69. data/spec/node/movements/move_to_child_with_position_spec.rb +85 -0
  70. data/spec/node/movements/move_to_left_of_spec.rb +120 -0
  71. data/spec/node/movements/move_to_right_of_spec.rb +120 -0
  72. data/spec/node/movements/move_to_root_spec.rb +67 -0
  73. data/spec/node/predicates_spec.rb +211 -0
  74. data/spec/node/reloading_spec.rb +42 -0
  75. data/spec/node/siblings_spec.rb +193 -0
  76. data/spec/node/traversals_spec.rb +71 -0
  77. data/spec/persevering_transaction_spec.rb +98 -0
  78. data/spec/relation/arrangeable_spec.rb +88 -0
  79. data/spec/relation/iterable_spec.rb +104 -0
  80. data/spec/relation/preloaded_spec.rb +57 -0
  81. data/spec/reorder_spec.rb +83 -0
  82. data/spec/spec_helper.rb +30 -38
  83. data/spec/support/db/boot.rb +22 -0
  84. data/spec/{db → support/db}/config.travis.yml +2 -0
  85. data/spec/{db → support/db}/config.yml +1 -0
  86. data/spec/{db → support/db}/schema.rb +9 -0
  87. data/spec/support/factories.rb +2 -2
  88. data/spec/support/matchers.rb +67 -58
  89. data/spec/support/models.rb +6 -14
  90. data/spec/support/tree_factory.rb +315 -0
  91. data/spec/tree/children_association_spec.rb +72 -0
  92. data/spec/tree/columns_spec.rb +65 -0
  93. data/spec/tree/scopes_spec.rb +39 -0
  94. metadata +161 -43
  95. data/lib/acts_as_ordered_tree/adapters/postgresql_adapter.rb +0 -104
  96. data/lib/acts_as_ordered_tree/arrangeable.rb +0 -80
  97. data/lib/acts_as_ordered_tree/class_methods.rb +0 -72
  98. data/lib/acts_as_ordered_tree/relation/base.rb +0 -26
  99. data/lib/acts_as_ordered_tree/tenacious_transaction.rb +0 -30
  100. data/spec/concurrency_support_spec.rb +0 -156
@@ -0,0 +1,71 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActsAsOrderedTree::Node::Traversals, :transactional do
6
+ shared_examples 'ActsAsOrderedTree::Node traversals' do |model, attrs = {}|
7
+ let(:root_1) { create model, attrs }
8
+ let(:child_1) { create model, attrs.merge(:parent => root_1) }
9
+ let(:grandchild_1) { create model, attrs.merge(:parent => child_1) }
10
+ let(:root_2) { create model, attrs }
11
+ let(:child_2) { create model, attrs.merge(:parent => root_2) }
12
+ let(:grandchild_2) { create model, attrs.merge(:parent => child_2) }
13
+
14
+ before { [root_1, child_1, grandchild_1].each(&:reload) }
15
+ before { [root_2, child_2, grandchild_2].each(&:reload) }
16
+
17
+ describe '#root' do
18
+ it { expect(root_1.root).to eq root_1 }
19
+ it { expect{root_1.root}.not_to query_database }
20
+ it { expect(child_1.root).to eq root_1 }
21
+ it { expect(grandchild_1.root).to eq root_1 }
22
+
23
+ it { expect(root_2.root).to eq root_2 }
24
+ it { expect{root_2.root}.not_to query_database }
25
+ it { expect(child_2.root).to eq root_2 }
26
+ it { expect(grandchild_2.root).to eq root_2 }
27
+ end
28
+
29
+ describe '#self_and_ancestors' do
30
+ it { expect(root_1.self_and_ancestors).to eq [root_1] }
31
+ it { expect{root_1.self_and_ancestors}.not_to query_database }
32
+ it { expect(child_1.self_and_ancestors).to eq [root_1, child_1] }
33
+ it { expect(grandchild_1.self_and_ancestors).to eq [root_1, child_1, grandchild_1] }
34
+
35
+ it { expect(child_1.self_and_ancestors).to respond_to :each_with_level }
36
+ it { expect(child_1.self_and_ancestors).to respond_to :each_without_orphans }
37
+ end
38
+
39
+ describe '#ancestors' do
40
+ it { expect(root_1.ancestors).to eq [] }
41
+ it { expect{root_1.ancestors}.not_to query_database }
42
+ it { expect(child_1.ancestors).to eq [root_1] }
43
+ it { expect(grandchild_1.ancestors).to eq [root_1, child_1] }
44
+
45
+ it { expect(child_1.ancestors).to respond_to :each_with_level }
46
+ it { expect(child_1.ancestors).to respond_to :each_without_orphans }
47
+ end
48
+
49
+ describe '#self_and_descendants' do
50
+ it { expect(root_1.self_and_descendants).to eq [root_1, child_1, grandchild_1] }
51
+ it { expect(child_1.self_and_descendants).to eq [child_1, grandchild_1] }
52
+ it { expect(grandchild_1.self_and_descendants).to eq [grandchild_1] }
53
+
54
+ it { expect(root_1.self_and_descendants).to respond_to :each_with_level }
55
+ it { expect(root_1.self_and_descendants).to respond_to :each_without_orphans }
56
+ end
57
+
58
+ describe '#descendants' do
59
+ it { expect(root_1.descendants).to eq [child_1, grandchild_1] }
60
+ it { expect(child_1.descendants).to eq [grandchild_1] }
61
+ it { expect(grandchild_1.descendants).to eq [] }
62
+
63
+ it { expect(root_1.descendants).to respond_to :each_with_level }
64
+ it { expect(root_1.descendants).to respond_to :each_without_orphans }
65
+ end
66
+ end
67
+
68
+ include_examples 'ActsAsOrderedTree::Node traversals', :default
69
+ include_examples 'ActsAsOrderedTree::Node traversals', :default_with_counter_cache
70
+ include_examples 'ActsAsOrderedTree::Node traversals', :scoped, :scope_type => 'a'
71
+ end
@@ -0,0 +1,98 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'acts_as_ordered_tree/persevering_transaction'
6
+
7
+ describe ActsAsOrderedTree::PerseveringTransaction, :non_transactional do
8
+ def create_transaction(connection = ActiveRecord::Base.connection)
9
+ described_class.new(connection)
10
+ end
11
+
12
+ describe 'Transaction state' do
13
+ def transaction
14
+ @transaction ||= create_transaction
15
+ end
16
+
17
+ it 'becomes committed only when real transaction ends' do
18
+ transaction.start do
19
+ nested_transaction = create_transaction
20
+
21
+ nested_transaction.start { }
22
+
23
+ expect(nested_transaction).not_to be_committed
24
+ expect(transaction).not_to be_committed
25
+ end
26
+
27
+ expect(transaction).to be_committed
28
+ end
29
+
30
+ it 'becomes rolledback when real transaction is rolledback' do
31
+ transaction.start do
32
+ raise ActiveRecord::Rollback
33
+ end
34
+
35
+ expect(transaction).to be_rolledback
36
+ end
37
+ end
38
+
39
+ describe 'After commit callbacks' do
40
+ it 'executes callbacks only when real transaction commits' do
41
+ executed = []
42
+
43
+ outer = create_transaction
44
+ outer.after_commit { executed << 1 }
45
+
46
+ outer.start do
47
+ inner = create_transaction
48
+ inner.after_commit { executed << 2 }
49
+
50
+ inner.start { }
51
+
52
+ expect(executed).to be_empty
53
+ end
54
+
55
+ expect(executed).to eq [1, 2]
56
+ end
57
+ end
58
+
59
+ describe 'Deadlock handling' do
60
+ def start_in_thread(&block)
61
+ Thread.start do
62
+ ActiveRecord::Base.connection_pool.with_connection do |connection|
63
+ trans = create_transaction(connection)
64
+ trans.start(&block)
65
+ trans
66
+ end
67
+ end
68
+ end
69
+
70
+ let!(:resource1) { Default.create!(:name => 'resource 1') }
71
+ let!(:resource2) { Default.create!(:name => 'resource 2') }
72
+
73
+ # this test randomly fails on Rails 3.1
74
+ it 'Restarts transaction when deadlock occurred' do
75
+ threads = []
76
+
77
+ threads << start_in_thread do
78
+ resource1.lock!
79
+ sleep 0.1
80
+ resource2.lock!
81
+ sleep 0.1
82
+ end
83
+
84
+ threads << start_in_thread do
85
+ resource2.lock!
86
+ sleep 0.1
87
+ resource1.lock!
88
+ sleep 0.1
89
+ end
90
+
91
+ transactions = threads.map(&:value)
92
+
93
+ expect(transactions[0]).to be_committed
94
+ expect(transactions[1]).to be_committed
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,88 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActsAsOrderedTree::Relation::Arrangeable, :transactional do
6
+ tree :factory => :default do
7
+ root {
8
+ child_1 {
9
+ grandchild_11
10
+ grandchild_12
11
+ }
12
+ child_2 {
13
+ grandchild_21
14
+ grandchild_22
15
+ }
16
+ }
17
+ end
18
+
19
+ specify '#descendants scope should be arrangeable' do
20
+ expect(root.descendants.arrange).to eq Hash[
21
+ child_1 => {
22
+ grandchild_11 => {},
23
+ grandchild_12 => {}
24
+ },
25
+ child_2 => {
26
+ grandchild_21 => {},
27
+ grandchild_22 => {}
28
+ }
29
+ ]
30
+ end
31
+
32
+ specify '#self_and_descendants should be arrangeable' do
33
+ expect(root.self_and_descendants.arrange).to eq Hash[
34
+ root => {
35
+ child_1 => {
36
+ grandchild_11 => {},
37
+ grandchild_12 => {}
38
+ },
39
+ child_2 => {
40
+ grandchild_21 => {},
41
+ grandchild_22 => {}
42
+ }
43
+ }
44
+ ]
45
+ end
46
+
47
+ specify '#ancestors should be arrangeable' do
48
+ expect(grandchild_11.ancestors.arrange).to eq Hash[
49
+ root => {
50
+ child_1 => {}
51
+ }
52
+ ]
53
+ end
54
+
55
+ specify '#self_and_ancestors should be arrangeable' do
56
+ expect(grandchild_11.self_and_ancestors.arrange).to eq Hash[
57
+ root => {
58
+ child_1 => {
59
+ grandchild_11 => {}
60
+ }
61
+ }
62
+ ]
63
+ end
64
+
65
+ it 'should not discard orphaned nodes by default' do
66
+ relation = root.descendants.where(root.class.arel_table[:id].not_eq(child_1.id))
67
+
68
+ expect(relation.arrange).to eq Hash[
69
+ grandchild_11 => {},
70
+ grandchild_12 => {},
71
+ child_2 => {
72
+ grandchild_21 => {},
73
+ grandchild_22 => {}
74
+ }
75
+ ]
76
+ end
77
+
78
+ it 'should discard orphans if option :discard passed' do
79
+ relation = root.descendants.where(root.class.arel_table[:id].not_eq(child_1.id))
80
+
81
+ expect(relation.arrange(:orphans => :discard)).to eq Hash[
82
+ child_2 => {
83
+ grandchild_21 => {},
84
+ grandchild_22 => {}
85
+ }
86
+ ]
87
+ end
88
+ end
@@ -0,0 +1,104 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'acts_as_ordered_tree/relation/iterable'
6
+
7
+ describe ActsAsOrderedTree::Relation::Iterable, :transactional do
8
+ shared_examples 'iterable' do |model|
9
+ tree :factory => model do
10
+ root_1 {
11
+ child_1 {
12
+ child_2
13
+ }
14
+ child_3 {
15
+ child_4
16
+ child_5
17
+ }
18
+ }
19
+ root_2 {
20
+ child_6
21
+ }
22
+ end
23
+
24
+ describe '#each_with_level' do
25
+ it 'iterates over collection and yields level' do
26
+ relation = current_tree.order(:id).extending(described_class)
27
+
28
+ expect { |b|
29
+ relation.each_with_level(&b)
30
+ }.to yield_successive_args [root_1, 0],
31
+ [child_1, 1],
32
+ [child_2, 2],
33
+ [child_3, 1],
34
+ [child_4, 2],
35
+ [child_5, 2],
36
+ [root_2, 0],
37
+ [child_6, 1]
38
+ end
39
+
40
+ it 'computes level relative to first selected node' do
41
+ expect { |b|
42
+ root_1.descendants.extending(described_class).each_with_level(&b)
43
+ }.to yield_successive_args [child_1, 1],
44
+ [child_2, 2],
45
+ [child_3, 1],
46
+ [child_4, 2],
47
+ [child_5, 2]
48
+ end
49
+ end
50
+
51
+ describe '#each_without_orphans' do
52
+ let(:relation) { current_tree.order(:id).extending(described_class) }
53
+
54
+ it 'iterates over collection' do
55
+ expect { |b|
56
+ relation.each_without_orphans(&b)
57
+ }.to yield_successive_args root_1,
58
+ child_1,
59
+ child_2,
60
+ child_3,
61
+ child_4,
62
+ child_5,
63
+ root_2,
64
+ child_6
65
+ end
66
+
67
+ it 'iterates over collection and discards orphans' do
68
+ expect { |b|
69
+ relation.where('id != ?', child_3.id).each_without_orphans(&b)
70
+ }.to yield_successive_args root_1,
71
+ child_1,
72
+ child_2,
73
+ root_2,
74
+ child_6
75
+ end
76
+
77
+ it 'iterates over collection and discards orphans' do
78
+ expect { |b|
79
+ relation.where('id != ?', root_2.id).each_without_orphans(&b)
80
+ }.to yield_successive_args root_1,
81
+ child_1,
82
+ child_2,
83
+ child_3,
84
+ child_4,
85
+ child_5
86
+ end
87
+
88
+ it 'iterates over collection and discards orphans' do
89
+ expect { |b|
90
+ relation.where('id != ?', root_1.id).each_without_orphans(&b)
91
+ }.to yield_successive_args root_2,
92
+ child_6
93
+ end
94
+ end
95
+ end
96
+
97
+ describe 'Model with cached level' do
98
+ it_behaves_like 'iterable', :default
99
+ end
100
+
101
+ describe 'Model without cached level' do
102
+ it_behaves_like 'iterable', :default_without_depth
103
+ end
104
+ end
@@ -0,0 +1,57 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'acts_as_ordered_tree/relation/preloaded'
6
+
7
+ describe ActsAsOrderedTree::Relation::Preloaded, :transactional do
8
+ let!(:records) { create_list :default, 2 }
9
+
10
+ def relation
11
+ Default.where(nil).extending(described_class)
12
+ end
13
+
14
+ context 'when preloaded records were not set' do
15
+ it { expect(relation).to match_array records }
16
+ it { expect(relation.to_a).not_to be records }
17
+ it { expect{relation.to_a}.to query_database.once }
18
+ end
19
+
20
+ context 'when preloaded records were set directly' do
21
+ let(:preloaded) { relation.records(records) }
22
+
23
+ it { expect(preloaded).to eq records }
24
+
25
+ it { expect(preloaded.to_a).to be records }
26
+ it { expect{preloaded.to_a}.not_to query_database }
27
+
28
+ it { expect(preloaded.size).to eq 2 }
29
+ it { expect{preloaded.size}.not_to query_database }
30
+
31
+ context 'when preloaded relation was extended' do
32
+ let(:extended) { preloaded.extending(Module.new) }
33
+
34
+ it { expect(extended).to eq records }
35
+
36
+ it { expect(extended.to_a).to be records }
37
+ it { expect{extended.to_a}.not_to query_database }
38
+
39
+ it { expect(extended.size).to eq 2 }
40
+ it { expect{extended.size}.not_to query_database }
41
+ end
42
+
43
+ describe '#reverse_order' do
44
+ it { expect(preloaded.reverse_order).not_to be preloaded }
45
+ it { expect(preloaded.reverse_order.size).to eq 2 }
46
+ it { expect(preloaded.reverse_order).to eq records.reverse }
47
+ it { expect{preloaded.reverse_order.to_a}.not_to query_database }
48
+ end
49
+
50
+ describe '#reverse_order!' do
51
+ it { expect(preloaded.reverse_order!).to be preloaded }
52
+ it { expect(preloaded.reverse_order!.size).to eq 2 }
53
+ it { expect(preloaded.reverse_order!.to_a).to eq records.reverse }
54
+ it { expect{preloaded.reverse_order!.to_a}.not_to query_database }
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,83 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActsAsOrderedTree, 'Reorder via save', :transactional do
6
+ tree :factory => :default do
7
+ root {
8
+ child_1
9
+ child_2
10
+ child_3
11
+ }
12
+ end
13
+
14
+ def reorder(node, position)
15
+ name = "category #{rand(100..1000)}"
16
+ node.position = position
17
+ node.name = name
18
+ expect { node.save! }.not_to raise_error
19
+ expect(node.name).to eq name
20
+ end
21
+
22
+ def assert_order(*nodes)
23
+ nodes.each_with_index do |node, index|
24
+ expect(node.reload.position).to eq index + 1
25
+ end
26
+ end
27
+
28
+ context 'when I change position to lower' do
29
+ before { reorder child_2, 1 }
30
+
31
+ it 'moves node up' do
32
+ assert_order child_2, child_1, child_3
33
+ end
34
+ end
35
+
36
+ context 'when I change position to lower' do
37
+ before { reorder child_2, 3 }
38
+
39
+ it 'moves node down' do
40
+ assert_order child_1, child_3, child_2
41
+ end
42
+ end
43
+
44
+ context 'when I move highest node lower' do
45
+ before { reorder child_1, 3 }
46
+
47
+ it 'moves node down' do
48
+ assert_order child_2, child_3, child_1
49
+ end
50
+ end
51
+
52
+ context 'when I move lowest node upper' do
53
+ before { reorder child_3, 1 }
54
+
55
+ it 'moves node down' do
56
+ assert_order child_3, child_1, child_2
57
+ end
58
+ end
59
+
60
+ context 'when I move to very high position' do
61
+ before { reorder child_1, 5 }
62
+
63
+ it 'moves node to bottom' do
64
+ assert_order child_2, child_3, child_1
65
+ end
66
+ end
67
+
68
+ context 'when I move to zero position' do
69
+ before { reorder child_2, 0 }
70
+
71
+ it 'moves it to top' do
72
+ assert_order child_2, child_1, child_3
73
+ end
74
+ end
75
+
76
+ context 'when I move to same position' do
77
+ before { reorder child_2, 2 }
78
+
79
+ specify 'order remains the same' do
80
+ assert_order child_1, child_2, child_3
81
+ end
82
+ end
83
+ end