closure_tree 4.6.3 → 5.0.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 +3 -0
- data/Appraisals +8 -8
- data/CHANGELOG.md +29 -14
- data/README.md +30 -20
- data/closure_tree.gemspec +8 -9
- data/lib/closure_tree/acts_as_tree.rb +3 -5
- data/lib/closure_tree/finders.rb +36 -48
- data/lib/closure_tree/model.rb +1 -0
- data/lib/closure_tree/support.rb +55 -2
- data/lib/closure_tree/support_attributes.rb +3 -8
- data/lib/closure_tree/support_flags.rb +2 -3
- data/lib/closure_tree/version.rb +1 -1
- data/spec/db/database.yml +2 -2
- data/spec/db/models.rb +7 -1
- data/spec/db/schema.rb +1 -0
- data/spec/hierarchy_maintenance_spec.rb +1 -0
- data/spec/label_spec.rb +48 -36
- data/spec/metal_spec.rb +50 -4
- data/spec/parallel_spec.rb +66 -49
- data/spec/spec_helper.rb +3 -0
- data/spec/support/database.rb +13 -11
- data/spec/tag_examples.rb +137 -102
- data/tests.sh +2 -4
- metadata +18 -20
- data/spec/support/helpers.rb +0 -8
data/spec/spec_helper.rb
CHANGED
data/spec/support/database.rb
CHANGED
@@ -1,24 +1,26 @@
|
|
1
1
|
database_folder = "#{File.dirname(__FILE__)}/../db"
|
2
2
|
database_adapter = ENV['DB'] ||= 'mysql'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
log.sev_threshold = Logger::DEBUG
|
7
|
-
ActiveRecord::Base.logger = log
|
4
|
+
def sqlite?
|
5
|
+
ENV['DB'] == 'sqlite'
|
8
6
|
end
|
9
7
|
|
8
|
+
log = Logger.new('db.log')
|
9
|
+
log.sev_threshold = Logger::DEBUG
|
10
|
+
ActiveRecord::Base.logger = log
|
11
|
+
|
10
12
|
ActiveRecord::Migration.verbose = false
|
11
13
|
ActiveRecord::Base.table_name_prefix = ENV['DB_PREFIX'].to_s
|
12
14
|
ActiveRecord::Base.table_name_suffix = ENV['DB_SUFFIX'].to_s
|
15
|
+
|
16
|
+
def db_name
|
17
|
+
@db_name ||= "closure_tree_test_#{rand(1..2**31)}"
|
18
|
+
end
|
19
|
+
|
13
20
|
ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read("#{database_folder}/database.yml")).result)
|
14
21
|
|
15
22
|
config = ActiveRecord::Base.configurations[database_adapter]
|
16
23
|
|
17
|
-
unless config['database'] == ':memory:'
|
18
|
-
# Postgresql or Mysql
|
19
|
-
config['database'].concat ENV['TRAVIS_JOB_NUMBER'].to_s.gsub(/\W/, '_')
|
20
|
-
end
|
21
|
-
|
22
24
|
begin
|
23
25
|
case database_adapter
|
24
26
|
when 'sqlite'
|
@@ -42,8 +44,8 @@ require "#{database_folder}/models"
|
|
42
44
|
def count_queries(&block)
|
43
45
|
count = 0
|
44
46
|
counter_fn = ->(name, started, finished, unique_id, payload) do
|
45
|
-
count += 1 unless payload[:name].in? %w[
|
47
|
+
count += 1 unless payload[:name].in? %w[CACHE SCHEMA]
|
46
48
|
end
|
47
|
-
ActiveSupport::Notifications.subscribed(counter_fn,
|
49
|
+
ActiveSupport::Notifications.subscribed(counter_fn, 'sql.active_record', &block)
|
48
50
|
count
|
49
51
|
end
|
data/spec/tag_examples.rb
CHANGED
@@ -33,15 +33,25 @@ shared_examples_for Tag do
|
|
33
33
|
expect(tag_class.leaves).to be_empty
|
34
34
|
end
|
35
35
|
|
36
|
-
it "#find_or_create_by_path" do
|
37
|
-
a = tag_class.create!(:
|
36
|
+
it "#find_or_create_by_path with strings" do
|
37
|
+
a = tag_class.create!(name: 'a')
|
38
38
|
expect(a.find_or_create_by_path(%w{b c}).ancestry_path).to eq(%w{a b c})
|
39
39
|
end
|
40
|
+
|
41
|
+
it "#find_or_create_by_path with hashes" do
|
42
|
+
a = tag_class.create!(name: 'a', title: 'A')
|
43
|
+
subject = a.find_or_create_by_path([
|
44
|
+
{name: 'b', title: 'B'},
|
45
|
+
{name: 'c', title: 'C'}
|
46
|
+
])
|
47
|
+
expect(subject.ancestry_path).to eq(%w{a b c})
|
48
|
+
expect(subject.self_and_ancestors.map(&:title)).to eq(%w{C B A})
|
49
|
+
end
|
40
50
|
end
|
41
51
|
|
42
52
|
context "with 1 tag" do
|
43
53
|
before do
|
44
|
-
@tag = tag_class.create!(:
|
54
|
+
@tag = tag_class.create!(name: "tag")
|
45
55
|
end
|
46
56
|
|
47
57
|
it "should be a leaf" do
|
@@ -64,7 +74,7 @@ shared_examples_for Tag do
|
|
64
74
|
|
65
75
|
context "with child" do
|
66
76
|
before do
|
67
|
-
@child = tag_class.create!(:
|
77
|
+
@child = tag_class.create!(name: 'tag 2')
|
68
78
|
end
|
69
79
|
|
70
80
|
def assert_roots_and_leaves
|
@@ -96,8 +106,8 @@ shared_examples_for Tag do
|
|
96
106
|
|
97
107
|
context "with 2 tags" do
|
98
108
|
before :each do
|
99
|
-
@root = tag_class.create!(:
|
100
|
-
@leaf = @root.add_child(tag_class.create!(:
|
109
|
+
@root = tag_class.create!(name: "root")
|
110
|
+
@leaf = @root.add_child(tag_class.create!(name: "leaf"))
|
101
111
|
end
|
102
112
|
it "should return a simple root and leaf" do
|
103
113
|
expect(tag_class.roots).to eq([@root])
|
@@ -114,9 +124,9 @@ shared_examples_for Tag do
|
|
114
124
|
|
115
125
|
context "3 tag collection.create db" do
|
116
126
|
before :each do
|
117
|
-
@root = tag_class.create! :
|
118
|
-
@mid = @root.children.create! :
|
119
|
-
@leaf = @mid.children.create! :
|
127
|
+
@root = tag_class.create! name: "root"
|
128
|
+
@mid = @root.children.create! name: "mid"
|
129
|
+
@leaf = @mid.children.create! name: "leaf"
|
120
130
|
DestroyedTag.delete_all
|
121
131
|
end
|
122
132
|
|
@@ -144,7 +154,7 @@ shared_examples_for Tag do
|
|
144
154
|
end
|
145
155
|
|
146
156
|
it 'fix self_and_ancestors properly on reparenting' do
|
147
|
-
t = tag_class.create! :
|
157
|
+
t = tag_class.create! name: 'moar leaf'
|
148
158
|
expect(t.self_and_ancestors.to_a).to eq([t])
|
149
159
|
@mid.children << t
|
150
160
|
expect(t.self_and_ancestors.to_a).to eq([t, @mid, @root])
|
@@ -157,7 +167,7 @@ shared_examples_for Tag do
|
|
157
167
|
end
|
158
168
|
|
159
169
|
it 'moves non-leaves' do
|
160
|
-
new_root = tag_class.create! :
|
170
|
+
new_root = tag_class.create! name: "new_root"
|
161
171
|
new_root.children << @mid
|
162
172
|
expect(@root.reload.descendants).to be_empty
|
163
173
|
expect(new_root.descendants).to eq([@mid, @leaf])
|
@@ -165,7 +175,7 @@ shared_examples_for Tag do
|
|
165
175
|
end
|
166
176
|
|
167
177
|
it 'moves leaves' do
|
168
|
-
new_root = tag_class.create! :
|
178
|
+
new_root = tag_class.create! name: "new_root"
|
169
179
|
new_root.children << @leaf
|
170
180
|
expect(new_root.descendants).to eq([@leaf])
|
171
181
|
expect(@root.reload.descendants).to eq([@mid])
|
@@ -175,9 +185,9 @@ shared_examples_for Tag do
|
|
175
185
|
|
176
186
|
context "3 tag explicit_create db" do
|
177
187
|
before :each do
|
178
|
-
@root = tag_class.create!(:
|
179
|
-
@mid = @root.add_child(tag_class.create!(:
|
180
|
-
@leaf = @mid.add_child(tag_class.create!(:
|
188
|
+
@root = tag_class.create!(name: "root")
|
189
|
+
@mid = @root.add_child(tag_class.create!(name: "mid"))
|
190
|
+
@leaf = @mid.add_child(tag_class.create!(name: "leaf"))
|
181
191
|
end
|
182
192
|
|
183
193
|
it "should create all tags" do
|
@@ -208,19 +218,19 @@ shared_examples_for Tag do
|
|
208
218
|
|
209
219
|
it "cleans up hierarchy references for leaves" do
|
210
220
|
@leaf.destroy
|
211
|
-
expect(tag_hierarchy_class.where(:
|
212
|
-
expect(tag_hierarchy_class.where(:
|
221
|
+
expect(tag_hierarchy_class.where(ancestor_id: @leaf.id)).to be_empty
|
222
|
+
expect(tag_hierarchy_class.where(descendant_id: @leaf.id)).to be_empty
|
213
223
|
end
|
214
224
|
|
215
225
|
it "cleans up hierarchy references" do
|
216
226
|
@mid.destroy
|
217
|
-
expect(tag_hierarchy_class.where(:
|
218
|
-
expect(tag_hierarchy_class.where(:
|
227
|
+
expect(tag_hierarchy_class.where(ancestor_id: @mid.id)).to be_empty
|
228
|
+
expect(tag_hierarchy_class.where(descendant_id: @mid.id)).to be_empty
|
219
229
|
expect(@root.reload).to be_root
|
220
230
|
root_hiers = @root.ancestor_hierarchies.to_a
|
221
231
|
expect(root_hiers.size).to eq(1)
|
222
|
-
expect(tag_hierarchy_class.where(:
|
223
|
-
expect(tag_hierarchy_class.where(:
|
232
|
+
expect(tag_hierarchy_class.where(ancestor_id: @root.id)).to eq(root_hiers)
|
233
|
+
expect(tag_hierarchy_class.where(descendant_id: @root.id)).to eq(root_hiers)
|
224
234
|
end
|
225
235
|
|
226
236
|
it "should have different hash codes for each hierarchy model" do
|
@@ -234,12 +244,12 @@ shared_examples_for Tag do
|
|
234
244
|
end
|
235
245
|
|
236
246
|
it "performs as the readme says it does" do
|
237
|
-
grandparent = tag_class.create(:
|
238
|
-
parent = grandparent.children.create(:
|
239
|
-
child1 = tag_class.create(:
|
240
|
-
child2 = tag_class.new(:
|
247
|
+
grandparent = tag_class.create(name: 'Grandparent')
|
248
|
+
parent = grandparent.children.create(name: 'Parent')
|
249
|
+
child1 = tag_class.create(name: 'First Child', parent: parent)
|
250
|
+
child2 = tag_class.new(name: 'Second Child')
|
241
251
|
parent.children << child2
|
242
|
-
child3 = tag_class.new(:
|
252
|
+
child3 = tag_class.new(name: 'Third Child')
|
243
253
|
parent.add_child child3
|
244
254
|
expect(grandparent.self_and_descendants.collect(&:name)).to eq(
|
245
255
|
["Grandparent", "Parent", "First Child", "Second Child", "Third Child"]
|
@@ -259,11 +269,11 @@ shared_examples_for Tag do
|
|
259
269
|
|
260
270
|
it "roots sort alphabetically" do
|
261
271
|
expected = ("a".."z").to_a
|
262
|
-
expected.shuffle.each { |ea| tag_class.create!(:
|
272
|
+
expected.shuffle.each { |ea| tag_class.create!(name: ea) }
|
263
273
|
expect(tag_class.roots.collect { |ea| ea.name }).to eq(expected)
|
264
274
|
end
|
265
275
|
|
266
|
-
context
|
276
|
+
context 'with simple tree' do
|
267
277
|
before :each do
|
268
278
|
tag_class.find_or_create_by_path %w(a1 b1 c1a)
|
269
279
|
tag_class.find_or_create_by_path %w(a1 b1 c1b)
|
@@ -272,9 +282,8 @@ shared_examples_for Tag do
|
|
272
282
|
tag_class.find_or_create_by_path %w(a2 b2)
|
273
283
|
tag_class.find_or_create_by_path %w(a3)
|
274
284
|
|
275
|
-
@a1, @a2, @a3, @b1, @b1b, @b2, @c1a, @c1b, @c1c =
|
276
|
-
|
277
|
-
reorder(:name).to_a
|
285
|
+
@a1, @a2, @a3, @b1, @b1b, @b2, @c1a, @c1b, @c1c =
|
286
|
+
tag_class.all.sort_by(&:name)
|
278
287
|
@expected_roots = [@a1, @a2, @a3]
|
279
288
|
@expected_leaves = [@c1a, @c1b, @c1c, @b1b, @b2, @a3]
|
280
289
|
@expected_siblings = [[@a1, @a2, @a3], [@b1, @b1b], [@c1a, @c1b, @c1c]]
|
@@ -365,40 +374,63 @@ shared_examples_for Tag do
|
|
365
374
|
it 'limits subsequent where clauses' do
|
366
375
|
a1c = tag_class.find_or_create_by_path %w(A1 B C)
|
367
376
|
a2c = tag_class.find_or_create_by_path %w(A2 B C)
|
368
|
-
|
369
|
-
expect(
|
377
|
+
# different paths!
|
378
|
+
expect(a1c).not_to eq(a2c)
|
379
|
+
expect(tag_class.where(:name => 'C').to_a).to match_array([a1c, a2c])
|
380
|
+
expect(tag_class.with_ancestor(a1c.parent.parent).where(:name => 'C').to_a).to eq([a1c])
|
370
381
|
end
|
371
382
|
end
|
372
383
|
|
373
|
-
context
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
384
|
+
context 'paths' do
|
385
|
+
context 'with grandchild' do
|
386
|
+
before do
|
387
|
+
@child = tag_class.find_or_create_by_path([
|
388
|
+
{name: 'grandparent', title: 'Nonnie'},
|
389
|
+
{name: 'parent', title: 'Mom'},
|
390
|
+
{name: 'child', title: 'Kid'}])
|
391
|
+
@parent = @child.parent
|
392
|
+
@grandparent = @parent.parent
|
393
|
+
end
|
383
394
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
395
|
+
it 'should build ancestry path' do
|
396
|
+
expect(@child.ancestry_path).to eq(%w{grandparent parent child})
|
397
|
+
expect(@child.ancestry_path(:name)).to eq(%w{grandparent parent child})
|
398
|
+
expect(@child.ancestry_path(:title)).to eq(%w{Nonnie Mom Kid})
|
399
|
+
end
|
389
400
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
401
|
+
it 'assembles ancestors' do
|
402
|
+
expect(@child.ancestors).to eq([@parent, @grandparent])
|
403
|
+
expect(@child.self_and_ancestors).to eq([@child, @parent, @grandparent])
|
404
|
+
end
|
405
|
+
|
406
|
+
it "should find by path" do
|
407
|
+
# class method:
|
408
|
+
expect(tag_class.find_by_path(%w{grandparent parent child})).to eq(@child)
|
409
|
+
# instance method:
|
410
|
+
expect(@parent.find_by_path(%w{child})).to eq(@child)
|
411
|
+
expect(@grandparent.find_by_path(%w{parent child})).to eq(@child)
|
412
|
+
expect(@parent.find_by_path(%w{child larvae})).to be_nil
|
413
|
+
end
|
394
414
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
415
|
+
it "should respect attribute hashes with both selection and creation" do
|
416
|
+
expected_title = 'something else'
|
417
|
+
attrs = {title: expected_title}
|
418
|
+
existing_title = @grandparent.title
|
419
|
+
new_grandparent = tag_class.find_or_create_by_path(%w{grandparent}, attrs)
|
420
|
+
expect(new_grandparent).not_to eq(@grandparent)
|
421
|
+
expect(new_grandparent.title).to eq(expected_title)
|
422
|
+
expect(@grandparent.reload.title).to eq(existing_title)
|
423
|
+
end
|
424
|
+
|
425
|
+
it "should create a hierarchy with a given attribute" do
|
426
|
+
expected_title = 'unicorn rainbows'
|
427
|
+
attrs = {title: expected_title}
|
428
|
+
child = tag_class.find_or_create_by_path(%w{grandparent parent child}, attrs)
|
429
|
+
expect(child).not_to eq(@child)
|
430
|
+
[child, child.parent, child.parent.parent].each do |ea|
|
431
|
+
expect(ea.title).to eq(expected_title)
|
432
|
+
end
|
433
|
+
end
|
402
434
|
end
|
403
435
|
|
404
436
|
it "finds correctly rooted paths" do
|
@@ -415,10 +447,14 @@ shared_examples_for Tag do
|
|
415
447
|
end
|
416
448
|
|
417
449
|
it "find_by_path for 2 nodes" do
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
450
|
+
path = %w(a b c)
|
451
|
+
c = tag_class.find_or_create_by_path path
|
452
|
+
permutations = path.permutation.to_a
|
453
|
+
correct = %w(b c)
|
454
|
+
expect(c.root.find_by_path(correct)).to eq(c)
|
455
|
+
(permutations - correct).each do |bad_path|
|
456
|
+
expect(c.root.find_by_path(bad_path)).to be_nil
|
457
|
+
end
|
422
458
|
end
|
423
459
|
|
424
460
|
it "find_by_path for 3 nodes" do
|
@@ -435,32 +471,29 @@ shared_examples_for Tag do
|
|
435
471
|
expect(tag_class.find_by_path(%w{grandparent parent missing child})).to be_nil
|
436
472
|
end
|
437
473
|
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
474
|
+
describe ".find_or_create_by_path" do
|
475
|
+
it "uses existing records" do
|
476
|
+
grandparent = tag_class.find_or_create_by_path(%w{grandparent})
|
477
|
+
expect(grandparent).to eq(grandparent)
|
478
|
+
child = tag_class.find_or_create_by_path(%w{grandparent parent child})
|
479
|
+
expect(child).to eq(child)
|
480
|
+
end
|
445
481
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
new_grandparent = tag_class.find_or_create_by_path(%w{grandparent}, attrs)
|
451
|
-
expect(new_grandparent).not_to eq(@grandparent)
|
452
|
-
expect(new_grandparent.title).to eq(expected_title)
|
453
|
-
expect(@grandparent.reload.title).to eq(existing_title)
|
454
|
-
end
|
482
|
+
it "creates 2-deep trees with strings" do
|
483
|
+
subject = tag_class.find_or_create_by_path(%w{events anniversary})
|
484
|
+
expect(subject.ancestry_path).to eq(%w{events anniversary})
|
485
|
+
end
|
455
486
|
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
487
|
+
it "creates 2-deep trees with hashes" do
|
488
|
+
subject = tag_class.find_or_create_by_path([
|
489
|
+
{name: 'test1', title: 'TEST1'},
|
490
|
+
{name: 'test2', title: 'TEST2'}
|
491
|
+
])
|
492
|
+
expect(subject.ancestry_path).to eq(%w{test1 test2})
|
493
|
+
# `self_and_ancestors` and `ancestors` is ordered parent-first. (!!)
|
494
|
+
expect(subject.self_and_ancestors.map(&:title)).to eq(%w{TEST2 TEST1})
|
463
495
|
end
|
496
|
+
|
464
497
|
end
|
465
498
|
end
|
466
499
|
|
@@ -480,19 +513,19 @@ shared_examples_for Tag do
|
|
480
513
|
|
481
514
|
context "#hash_tree" do
|
482
515
|
it "returns {} for depth 0" do
|
483
|
-
expect(tag_class.hash_tree(:
|
516
|
+
expect(tag_class.hash_tree(limit_depth: 0)).to eq({})
|
484
517
|
end
|
485
518
|
it "limit_depth 1" do
|
486
|
-
expect(tag_class.hash_tree(:
|
519
|
+
expect(tag_class.hash_tree(limit_depth: 1)).to eq({@a => {}})
|
487
520
|
end
|
488
521
|
it "limit_depth 2" do
|
489
|
-
expect(tag_class.hash_tree(:
|
522
|
+
expect(tag_class.hash_tree(limit_depth: 2)).to eq({@a => {@b => {}, @b2 => {}}})
|
490
523
|
end
|
491
524
|
it "limit_depth 3" do
|
492
|
-
expect(tag_class.hash_tree(:
|
525
|
+
expect(tag_class.hash_tree(limit_depth: 3)).to eq({@a => {@b => {@c1 => {}, @c2 => {}}, @b2 => {}}})
|
493
526
|
end
|
494
527
|
it "limit_depth 4" do
|
495
|
-
expect(tag_class.hash_tree(:
|
528
|
+
expect(tag_class.hash_tree(limit_depth: 4)).to eq(@full_tree)
|
496
529
|
end
|
497
530
|
it "no limit holdum" do
|
498
531
|
expect(tag_class.hash_tree).to eq(@full_tree)
|
@@ -532,16 +565,16 @@ shared_examples_for Tag do
|
|
532
565
|
before :each do
|
533
566
|
end
|
534
567
|
it "returns {} for depth 0" do
|
535
|
-
expect(@b.hash_tree(:
|
568
|
+
expect(@b.hash_tree(limit_depth: 0)).to eq({})
|
536
569
|
end
|
537
570
|
it "limit_depth 1" do
|
538
|
-
expect(@b.hash_tree(:
|
571
|
+
expect(@b.hash_tree(limit_depth: 1)).to eq({@b => {}})
|
539
572
|
end
|
540
573
|
it "limit_depth 2" do
|
541
|
-
expect(@b.hash_tree(:
|
574
|
+
expect(@b.hash_tree(limit_depth: 2)).to eq({@b => {@c1 => {}, @c2 => {}}})
|
542
575
|
end
|
543
576
|
it "limit_depth 3" do
|
544
|
-
expect(@b.hash_tree(:
|
577
|
+
expect(@b.hash_tree(limit_depth: 3)).to eq({@b => {@c1 => {@d1 => {}}, @c2 => {@d2 => {}}}})
|
545
578
|
end
|
546
579
|
it "no limit holdum from subsubroot" do
|
547
580
|
expect(@c1.hash_tree).to eq({@c1 => {@d1 => {}}})
|
@@ -555,12 +588,14 @@ shared_examples_for Tag do
|
|
555
588
|
end
|
556
589
|
end
|
557
590
|
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
591
|
+
it 'finds_by_path for very deep trees' do
|
592
|
+
expect(tag_class._ct).to receive(:max_join_tables).at_least(1).and_return(3)
|
593
|
+
path = (1..20).to_a.map { |ea| ea.to_s }
|
594
|
+
subject = tag_class.find_or_create_by_path(path)
|
595
|
+
expect(subject.ancestry_path).to eq(path)
|
596
|
+
expect(tag_class.find_by_path(path)).to eq(subject)
|
597
|
+
root = subject.root
|
598
|
+
expect(root.find_by_path(path[1..-1])).to eq(subject)
|
564
599
|
end
|
565
600
|
|
566
601
|
describe 'DOT rendering' do
|
@@ -571,7 +606,7 @@ shared_examples_for Tag do
|
|
571
606
|
tag_class.find_or_create_by_path(%w(a b1 c1))
|
572
607
|
tag_class.find_or_create_by_path(%w(a b2 c2))
|
573
608
|
tag_class.find_or_create_by_path(%w(a b2 c3))
|
574
|
-
a, b1, b2, c1, c2, c3 = %w(a b1 b2 c1 c2 c3).map { |ea| tag_class.where(:
|
609
|
+
a, b1, b2, c1, c2, c3 = %w(a b1 b2 c1 c2 c3).map { |ea| tag_class.where(name: ea).first.id }
|
575
610
|
dot = tag_class.roots.first.to_dot_digraph
|
576
611
|
expect(dot).to eq <<-DOT
|
577
612
|
digraph G {
|