forester 4.3.0 → 5.0.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.
@@ -1,34 +0,0 @@
1
- module Forester
2
- module Views
3
-
4
- def as_root_hash(options = {})
5
- default_options = {
6
- fields_to_include: :all,
7
- max_level: :last,
8
- children_key: :children,
9
- stringify_keys: false,
10
- symbolize_keys: false
11
- }
12
- options = default_options.merge(options)
13
-
14
- hash = content.to_hash(options)
15
-
16
- children_key = options[:children_key]
17
- children_key = children_key.to_s if options[:stringify_keys]
18
-
19
- max_level = options[:max_level]
20
- max_level = -1 if max_level == :last
21
-
22
- next_children =
23
- if max_level == 0
24
- []
25
- else
26
- next_options = options.merge(max_level: max_level - 1)
27
- children.map { |node| node.as_root_hash(next_options) }
28
- end
29
-
30
- hash.merge(children_key => next_children)
31
- end
32
-
33
- end
34
- end
@@ -1,41 +0,0 @@
1
- require 'simplecov'
2
- SimpleCov.start do
3
- add_filter 'test/'
4
- end
5
-
6
- require 'minitest/autorun'
7
-
8
- require 'pry-byebug'
9
-
10
- require 'forester'
11
-
12
- class Forester::Test < Minitest::Test
13
-
14
- private
15
-
16
- PATH_TO_TREES = "#{File.dirname(__FILE__)}/trees"
17
- PATH_TO_SIMPLE_TREE = "#{PATH_TO_TREES}/simple_tree.yml"
18
- TREE = Forester::TreeFactory.from_yaml_file(PATH_TO_SIMPLE_TREE)
19
-
20
- BINARY_TREE = Forester::TreeFactory.node_from_hash(name: :top) do |parent|
21
- parent.add_child_content!(name: :left) do |left|
22
- left.add_child_content!(name: :left_left) do |left_left|
23
- left_left.add_child_content!(name: :left_left_left)
24
- end
25
- left.add_child_content!(name: :left_right)
26
- end
27
- parent.add_child_content!(name: :right) do |right|
28
- right.add_child_content!(name: :right_left)
29
- right.add_child_content!(name: :right_right)
30
- end
31
- end
32
-
33
- def tree
34
- TREE
35
- end
36
-
37
- def binary_tree
38
- BINARY_TREE
39
- end
40
-
41
- end
@@ -1,48 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- class TestAdHocTree < Forester::Test
4
-
5
- def test_content
6
- assert_equal({ number: 1 }, Forester::TreeFactory.node_from_hash(number: 1).content)
7
- end
8
-
9
- def test_each_node_type
10
- assert_instance_of Enumerator, binary_tree.each_node
11
- end
12
-
13
- def test_each_content_type
14
- assert_instance_of Enumerator, binary_tree.each_content
15
- end
16
-
17
- def test_each_content_depth_first
18
- expected = %i(top left left_left left_left_left left_right right right_left right_right)
19
- assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :depth_first)
20
- assert_equal expected, binary_tree.each_node(traversal: :depth_first).map { |n| n.get(:name) }
21
- assert_equal expected, binary_tree.each_content(traversal: :depth_first).map { |c| c[:name] }
22
- end
23
-
24
- def test_each_content_breadth_first
25
- expected = %i(top left right left_left left_right right_left right_right left_left_left)
26
-
27
- assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :breadth_first)
28
- assert_equal expected, binary_tree.each_node(traversal: :breadth_first).map { |n| n.get(:name) }
29
- assert_equal expected, binary_tree.each_node.map { |n| n.get(:name) }
30
- assert_equal expected, binary_tree.each_content(traversal: :breadth_first).map { |c| c[:name] }
31
- assert_equal expected, binary_tree.each_content.map { |c| c[:name] }
32
- end
33
-
34
- def test_each_content_postorder
35
- expected = %i(left_left_left left_left left_right left right_left right_right right top)
36
- assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :postorder)
37
- assert_equal expected, binary_tree.each_node(traversal: :postorder).map { |n| n.get(:name) }
38
- assert_equal expected, binary_tree.each_content(traversal: :postorder).map { |c| c[:name] }
39
- end
40
-
41
- def test_each_content_preorder
42
- expected = %i(top left left_left left_left_left left_right right right_left right_right)
43
- assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :preorder)
44
- assert_equal expected, binary_tree.each_node(traversal: :preorder).map { |n| n.get(:name) }
45
- assert_equal expected, binary_tree.each_content(traversal: :preorder).map { |c| c[:name] }
46
- end
47
-
48
- end
@@ -1,105 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- class TestAggregators < Forester::Test
4
-
5
- def test_group_by_sibling_subtrees
6
- expected = {
7
- "First node of level 2" => [
8
- "Already in level 2",
9
- "I want to be the very best",
10
- "like no one ever was"
11
- ],
12
- "Second node of level 2" => [
13
- "I have a sibling to my left",
14
- "She wants to catch them all"
15
- ],
16
- "Third node of level 2" => [
17
- "Reached level 3",
18
- "It's dark",
19
- "A hidden secret lies in the deepest leaves...",
20
- "Just kidding.",
21
- "Could forester handle trees with hundreds of levels?",
22
- "Maybe."
23
- ]
24
- }
25
-
26
- actual = tree.group_by_sibling_subtrees(
27
- level: 2,
28
- aggregation_field: 'strings'
29
- )
30
-
31
- assert_equal expected, actual
32
- end
33
-
34
- def test_group_by_sibling_subtrees_with_ancestry
35
- expected = {
36
- ["First node of level 1", "First node of level 2"] => ["Already in level 2", "I want to be the very best", "like no one ever was"],
37
- ["First node of level 1", "Second node of level 2"] => ["I have a sibling to my left", "She wants to catch them all"],
38
- ["Second node of level 1", "Third node of level 2"] => ["Reached level 3", "It's dark", "A hidden secret lies in the deepest leaves...", "Just kidding.", "Could forester handle trees with hundreds of levels?", "Maybe."]
39
- }
40
-
41
- actual = tree.group_by_sibling_subtrees(
42
- level: 2,
43
- aggregation_field: 'strings',
44
- ancestry_in_keys: true
45
- )
46
-
47
- assert_equal expected, actual
48
- end
49
-
50
- def test_nodes_with
51
- expected_names = [
52
- "A hidden secret lies in the deepest leaves...",
53
- "Just kidding.",
54
- "Could forester handle trees with hundreds of levels?",
55
- "Maybe."
56
- ]
57
-
58
- found_nodes = tree.nodes_with('name', 'Second node of level 3')
59
- assert_equal 1, found_nodes.length
60
-
61
- actual_names = found_nodes.flat_map do |node|
62
- node.own_and_descendants('strings')
63
- end
64
-
65
- assert_equal expected_names, actual_names
66
- end
67
-
68
- def test_search
69
- expected = [7]
70
-
71
- actual_1 = tree.search({
72
- by_field: 'name',
73
- keywords: 'Second node of level 3',
74
- then_get: 'value',
75
- subtree: false
76
- })
77
-
78
- actual_2 = tree.search({
79
- by_field: 'name',
80
- keywords: ['Second node of level 3', 'Not present name'],
81
- then_get: 'value',
82
- subtree: false
83
- })
84
-
85
- actual_3 = tree.search({
86
- by_field: 'strings',
87
- keywords: 'A hidden secret lies in the deepest leaves...',
88
- then_get: 'value',
89
- subtree: false
90
- })
91
- assert_equal expected, actual_1
92
- assert_equal expected, actual_2
93
- assert_equal expected, actual_3
94
-
95
- expected_values = [7, 8, 9]
96
- actual_values = tree.search({
97
- by_field: 'name',
98
- keywords: 'Second node of level 3',
99
- then_get: 'value',
100
- subtree: true
101
- })
102
- assert_equal expected_values, actual_values
103
- end
104
-
105
- end
@@ -1,97 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- class TestMutators < Forester::Test
4
-
5
- def test_add_field
6
- tree.add_field!('number_four', 4)
7
-
8
- assert_equal 4, tree.get(:number_four)
9
- assert_equal 4, tree.get('number_four')
10
-
11
- tree.add_field!(:number_five, 5)
12
-
13
- assert_equal 5, tree.get(:number_five)
14
- assert_equal 5, tree.get('number_five')
15
-
16
- number_one = 1
17
-
18
- tree.add_field!(:number_six, -> (node) { node.get(:number_five) + number_one })
19
-
20
- assert_equal 6, tree.get(:number_six)
21
- end
22
-
23
- def test_delete_values
24
- node_1, node_2, node_3 = nodes_with_tags
25
-
26
- tree.delete_values!(:tags, [])
27
- assert_equal ['First tag', 'Second tag', 'Third tag'], node_1.get(:tags)
28
- assert_equal ['Second tag', 'Third tag'], node_2.get(:tags)
29
- assert_equal ['Third tag'], node_3.get(:tags)
30
-
31
- tree.delete_values!(:tags, ['First tag'])
32
- assert_equal ['Second tag', 'Third tag'], node_1.get(:tags)
33
- assert_equal ['Second tag', 'Third tag'], node_2.get(:tags)
34
- assert_equal ['Third tag'], node_3.get(:tags)
35
-
36
- tree.delete_values!(:tags, ['First tag', 'Second tag', 'Third tag'])
37
- assert_equal [], node_1.get(:tags)
38
- assert_equal [], node_2.get(:tags)
39
- assert_equal [], node_3.get(:tags)
40
- end
41
-
42
- def test_percolate_values
43
- node_1, node_2, node_3 = nodes_with_tags
44
-
45
- tree.percolate_values!(:tags, ['First tag', 'Second tag', 'Third tag'])
46
- assert_equal ['First tag', 'Second tag', 'Third tag'], node_1.get(:tags)
47
- assert_equal ['Second tag', 'Third tag'], node_2.get(:tags)
48
- assert_equal ['Third tag'], node_3.get(:tags)
49
-
50
- tree.percolate_values!(:tags, ['First tag'])
51
- assert_equal ['First tag'], node_1.get(:tags)
52
- assert_equal [], node_2.get(:tags)
53
- assert_equal [], node_3.get(:tags)
54
-
55
- tree.percolate_values!(:tags, [])
56
- assert_equal [], node_1.get(:tags)
57
- assert_equal [], node_2.get(:tags)
58
- assert_equal [], node_3.get(:tags)
59
- end
60
-
61
- def test_change_parent_to
62
- node_to_move = binary_tree.search(single_node: true, by_field: :name, keywords: [:left_left]).first
63
- old_parent = binary_tree.search(single_node: true, by_field: :name, keywords: [:left]).first
64
- new_parent = binary_tree.search(single_node: true, by_field: :name, keywords: [:right]).first
65
-
66
- node_to_move.change_parent_to!(new_parent)
67
-
68
- expected = %i(top left left_right right right_left right_right left_left left_left_left)
69
- assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :depth_first)
70
-
71
- node_to_move.change_parent_to!(old_parent, subtree: false)
72
-
73
- expected = %i(top left left_right left_left right right_left right_right left_left_left)
74
- assert_equal expected, binary_tree.get(:name, subtree: true, traversal: :depth_first)
75
- end
76
-
77
- private
78
-
79
- def tree
80
- @mutable_tree ||= super.detached_subtree_copy
81
- end
82
-
83
- def binary_tree
84
- @mutable_binary_tree ||= super.detached_subtree_copy
85
- end
86
-
87
- def nodes_with_tags
88
- [1, 6, 9].map do |n|
89
- tree.search({
90
- single_node: true,
91
- by_field: :value,
92
- keywords: n
93
- }).first
94
- end
95
- end
96
-
97
- end
@@ -1,30 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- class TestTreeFactory < Forester::Test
4
-
5
- def test_from_root_hash
6
- hash = YAML.load_file(PATH_TO_SIMPLE_TREE)
7
-
8
- whole_tree = from_root_hash(hash)
9
-
10
- whole_trees = [whole_tree] + [29, 4].map { |ml| from_root_hash(hash, max_level: ml) }
11
-
12
- assert(whole_trees.product(whole_trees).all? { |t1, t2| t1.same_as?(t2) })
13
-
14
- pruned_trees = (0..2).map { |ml| from_root_hash(hash, max_level: ml) }
15
-
16
- pruned_trees.each_with_index do |t, i|
17
- assert_equal(i, t.max_level)
18
-
19
- pruned = whole_trees[i].remove_levels_past!(i)
20
- assert(t.same_as?(pruned))
21
- end
22
- end
23
-
24
- private
25
-
26
- def from_root_hash(hash, options = {})
27
- Forester::TreeFactory.from_root_hash(hash['root'], options)
28
- end
29
-
30
- end
@@ -1,44 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- class TestTreeNode < Forester::Test
4
-
5
- def test_size
6
- assert_equal 10, tree.size
7
- end
8
-
9
- def test_values
10
- values = (0..9).to_a
11
-
12
- expected = values.reduce(:+)
13
- actual = tree.reduce(0) { |acum, node| acum + node.get('value') }
14
-
15
- assert_equal expected, actual
16
-
17
- assert_equal values, tree.get('value', subtree: true)
18
- end
19
-
20
- def test_missing_values
21
- assert_equal 0, tree.get('value')
22
- assert_equal 'no', tree.get('whatever', default: 'no')
23
- assert_equal 'no', tree.get('whatever', default: 'missing') { 'no' }
24
- assert_equal 'no', tree.get('whatever') { 'no' }
25
- assert_equal 'no', tree.get('whatever') { |n| 'no' }
26
- assert_equal 1, tree.get('whatever') { |n| n.get('value') + 1 }
27
-
28
- assert_raises(ArgumentError) { tree.get('whatever') }
29
- end
30
-
31
- def test_levels
32
- expected = [
33
- ["root"],
34
- ["First node of level 1", "Second node of level 1"],
35
- ["First node of level 2", "Second node of level 2", "Third node of level 2"],
36
- ["First node of level 3", "Second node of level 3"],
37
- ["First node of level 4", "Second node of level 4"]
38
- ]
39
- actual = tree.each_level.map { |l| l.map { |n| n.get('name') } }.to_a
40
-
41
- assert_equal expected, actual
42
- end
43
-
44
- end
@@ -1,240 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- class TestValidators < Forester::Test
4
-
5
- def test_validate_uniqueness_of_field_uniques
6
- expected = {
7
- is_valid: true,
8
- repeated: {},
9
- failures: {}
10
- }
11
-
12
- ['name', :name, 'special', 'ghost'].each do |field|
13
- actual = tree.validate_uniqueness_of_field(field)
14
- assert_equal expected, actual
15
- end
16
-
17
- end
18
-
19
- def test_validate_uniqueness_of_field_color
20
- expected = {
21
- is_valid: false,
22
- repeated: {
23
- :color => ['Green', 'Yellow']
24
- },
25
- failures: {
26
- :color => {
27
- 'Green' => ['First node of level 1', 'Second node of level 1'],
28
- 'Yellow' => ['First node of level 4', 'Second node of level 4']
29
- }
30
- }
31
- }
32
-
33
- actual = tree.validate_uniqueness_of_field(:color)
34
- assert_equal expected, actual
35
- end
36
-
37
- def test_validate_uniqueness_of_field_color_first_failure_only
38
- expected = {
39
- is_valid: false,
40
- repeated: {
41
- :color => ['Green']
42
- },
43
- failures: {
44
- :color => {
45
- 'Green' => ['First node of level 1', 'Second node of level 1']
46
- }
47
- }
48
- }
49
-
50
- actual = tree.validate_uniqueness_of_field(:color, {
51
- first_failure_only: true
52
- })
53
- assert_equal expected, actual
54
- end
55
-
56
- def test_validate_uniqueness_of_field_color_among_siblings_of_level_1
57
- expected = {
58
- is_valid: false,
59
- repeated: {
60
- :color => ['Green']
61
- },
62
- failures: {
63
- :color => {
64
- 'Green' => ['First node of level 1', 'Second node of level 1']
65
- }
66
- }
67
- }
68
-
69
- actual = tree.validate_uniqueness_of_field(:color, {
70
- among_siblings_of_level: 1
71
- })
72
-
73
- assert_equal expected, actual
74
- end
75
-
76
- def test_validate_uniqueness_of_field_color_among_siblings_of_level_2
77
- expected = {
78
- is_valid: true,
79
- repeated: {},
80
- failures: {}
81
- }
82
-
83
- actual = tree.validate_uniqueness_of_field(:color, {
84
- among_siblings_of_level: 2
85
- })
86
-
87
- assert_equal expected, actual
88
- end
89
-
90
- def test_validate_uniqueness_of_field_color_within_subtrees_of_level_1
91
- expected = {
92
- is_valid: false,
93
- repeated: {
94
- :color => ['Yellow']
95
- },
96
- failures: {
97
- :color => {
98
- 'Yellow' => ['First node of level 4', 'Second node of level 4']
99
- }
100
- }
101
- }
102
-
103
- actual = tree.validate_uniqueness_of_field(:color, {
104
- within_subtrees_of_level: 1,
105
- })
106
-
107
- assert_equal expected, actual
108
- end
109
-
110
- def test_validate_uniqueness_of_field_color_within_subtrees_of_level_3
111
- expected = {
112
- is_valid: false,
113
- repeated: {
114
- :color => ['Yellow']
115
- },
116
- failures: {
117
- :color => {
118
- 'Yellow' => ['First node of level 4', 'Second node of level 4']
119
- }
120
- }
121
- }
122
-
123
- actual = tree.validate_uniqueness_of_field(:color, {
124
- within_subtrees_of_level: 3,
125
- })
126
-
127
- assert_equal expected, actual
128
- end
129
-
130
- def test_validate_uniqueness_of_field_color_within_subtrees_of_level_4
131
- expected = {
132
- is_valid: true,
133
- repeated: {},
134
- failures: {}
135
- }
136
-
137
- actual = tree.validate_uniqueness_of_field(:color, {
138
- within_subtrees_of_level: 4,
139
- })
140
-
141
- assert_equal expected, actual
142
- end
143
-
144
- def test_validate_uniqueness_of_fields_name_color
145
- expected = {
146
- is_valid: false,
147
- repeated: {
148
- 'color' => ['Green', 'Yellow']
149
- },
150
- failures: {
151
- 'color' => {
152
- 'Green' => ['First node of level 1', 'Second node of level 1'],
153
- 'Yellow' => ['First node of level 4', 'Second node of level 4']
154
- }
155
- }
156
- }
157
-
158
- actual = tree.validate_uniqueness_of_fields(['name', 'color'])
159
-
160
- assert_equal expected, actual
161
- end
162
-
163
- def test_validate_uniqueness_of_combination_of_fields_name_color
164
- expected = {
165
- is_valid: true,
166
- repeated: {},
167
- failures: {}
168
- }
169
-
170
- actual = tree.validate_uniqueness_of_fields(['name', 'color'], {
171
- combination: true
172
- })
173
-
174
- assert_equal expected, actual
175
- end
176
-
177
- def test_validate_uniqueness_of_fields_color_tone_first_failure_only
178
- expected = {
179
- is_valid: false,
180
- repeated: {
181
- 'color' => ['Green']
182
- },
183
- failures: {
184
- 'color' => {
185
- 'Green' => ['First node of level 1', 'Second node of level 1']
186
- }
187
- }
188
- }
189
-
190
- actual = tree.validate_uniqueness_of_fields(['color', 'tone'], {
191
- first_failure_only: true
192
- })
193
-
194
- assert_equal expected, actual
195
- end
196
-
197
- def test_validate_uniqueness_of_fields_color_tone
198
- expected = {
199
- is_valid: false,
200
- repeated: {
201
- 'color' => ['Green', 'Yellow'],
202
- 'tone' => ['Dark']
203
- },
204
- failures: {
205
- 'color' => {
206
- 'Green' => ['First node of level 1', 'Second node of level 1'],
207
- 'Yellow' => ['First node of level 4', 'Second node of level 4']
208
- },
209
- 'tone' => {
210
- 'Dark' => ['First node of level 1', 'Second node of level 1']
211
- }
212
- }
213
- }
214
-
215
- actual = tree.validate_uniqueness_of_fields(['color', 'tone'])
216
-
217
- assert_equal expected, actual
218
- end
219
-
220
- def test_validate_uniqueness_of_combination_of_fields_color_tone
221
- expected = {
222
- is_valid: false,
223
- repeated: {
224
- ['color', 'tone'] => [['Green', 'Dark']]
225
- },
226
- failures: {
227
- ['color', 'tone'] => {
228
- ['Green', 'Dark'] => ['First node of level 1', 'Second node of level 1']
229
- }
230
- }
231
- }
232
-
233
- actual = tree.validate_uniqueness_of_fields(['color', 'tone'], {
234
- combination: true
235
- })
236
-
237
- assert_equal expected, actual
238
- end
239
-
240
- end