gaddag 0.1.1

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 (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +38 -0
  8. data/Rakefile +1 -0
  9. data/gaddag.gemspec +31 -0
  10. data/lib/gaddag.rb +47 -0
  11. data/lib/gaddag/arc.rb +41 -0
  12. data/lib/gaddag/node.rb +115 -0
  13. data/lib/gaddag/path.rb +72 -0
  14. data/lib/gaddag/word.rb +39 -0
  15. data/spec/shared/unit/gaddag/arc_context.rb +6 -0
  16. data/spec/shared/unit/gaddag/node/create_arc_behaviour.rb +41 -0
  17. data/spec/shared/unit/gaddag/node/create_final_path_behaviour.rb +33 -0
  18. data/spec/shared/unit/gaddag/node/create_path_behaviour.rb +15 -0
  19. data/spec/shared/unit/gaddag/node/create_path_context.rb +6 -0
  20. data/spec/unit/gaddag/add_spec.rb +46 -0
  21. data/spec/unit/gaddag/arc/add_final_letter_spec.rb +24 -0
  22. data/spec/unit/gaddag/arc/final_paths_spec.rb +49 -0
  23. data/spec/unit/gaddag/arc/initialize_spec.rb +16 -0
  24. data/spec/unit/gaddag/find_spec.rb +66 -0
  25. data/spec/unit/gaddag/initialize_spec.rb +11 -0
  26. data/spec/unit/gaddag/node/arc_spec.rb +23 -0
  27. data/spec/unit/gaddag/node/create_arc_spec.rb +8 -0
  28. data/spec/unit/gaddag/node/create_final_arc_spec.rb +18 -0
  29. data/spec/unit/gaddag/node/create_final_path_spec.rb +43 -0
  30. data/spec/unit/gaddag/node/create_path_spec.rb +44 -0
  31. data/spec/unit/gaddag/node/final_path_spec.rb +30 -0
  32. data/spec/unit/gaddag/node/final_paths_spec.rb +48 -0
  33. data/spec/unit/gaddag/node/follow_arc_spec.rb +24 -0
  34. data/spec/unit/gaddag/node/follow_path_spec.rb +41 -0
  35. data/spec/unit/gaddag/node/path_spec.rb +30 -0
  36. data/spec/unit/gaddag/path/equal_value_spec.rb +17 -0
  37. data/spec/unit/gaddag/path/include_delimiter_spec.rb +15 -0
  38. data/spec/unit/gaddag/path/initialize_spec.rb +12 -0
  39. data/spec/unit/gaddag/path/reversed_prefix_letters_spec.rb +34 -0
  40. data/spec/unit/gaddag/path/start_with_spec.rb +39 -0
  41. data/spec/unit/gaddag/path/suffix_letters_spec.rb +34 -0
  42. data/spec/unit/gaddag/path/to_ary_spec.rb +15 -0
  43. data/spec/unit/gaddag/path/to_s_spec.rb +18 -0
  44. data/spec/unit/gaddag/path/to_word_spec.rb +37 -0
  45. data/spec/unit/gaddag/word/equal_value_spec.rb +17 -0
  46. data/spec/unit/gaddag/word/initialize_spec.rb +12 -0
  47. data/spec/unit/gaddag/word/to_delimited_paths_spec.rb +29 -0
  48. data/spec/unit/gaddag/word/to_s_spec.rb +18 -0
  49. metadata +252 -0
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples 'GADDAG::Node#create_arc/behaviour' do
4
+ subject { GADDAG::Node.new }
5
+
6
+ let(:letter) { 'L' }
7
+ let(:destination) { GADDAG::Node.new }
8
+
9
+ let(:create_arc) { ->(*args) { subject.create_arc(*args) } }
10
+
11
+ let(:arc) { create_arc.call(letter) }
12
+ let(:another_arc) { create_arc.call(letter) }
13
+
14
+ let(:arc_with_destination) { create_arc.call(letter, destination) }
15
+
16
+ it 'returns the newly created arc' do
17
+ expect(arc).to be_an_instance_of(GADDAG::Arc)
18
+ end
19
+
20
+ it 'adds the arc to the mapping of outgoing arcs' do
21
+ expect(subject.outgoing_arcs).to include(letter.to_sym => arc)
22
+ end
23
+
24
+ context 'when not provided with a destination node' do
25
+ it 'points the arc to a newly created destination node' do
26
+ expect(arc.destination).to eq(GADDAG::Node.new)
27
+ end
28
+ end
29
+
30
+ context 'when provided with a destination node' do
31
+ it 'points the arc to the given destination node' do
32
+ expect(arc_with_destination.destination).to equal(destination)
33
+ end
34
+ end
35
+
36
+ context 'when created again for the same letter' do
37
+ it 'returns the original arc' do
38
+ expect(another_arc).to equal(arc)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples 'GADDAG::Node#create_final_path/behaviour' do
4
+ include_context 'GADDAG::Node#create_path/context'
5
+
6
+ let!(:final_node) { subject.create_final_path(letters) }
7
+
8
+ let(:letters_without_last_one) { letters[0..-2] }
9
+ let(:letters_without_last_two) { letters[0..-3]}
10
+
11
+ let(:last_letter) { letters[-1] }
12
+ let(:second_last_letter) { letters[-2] }
13
+
14
+ it 'creates the path for the given letters up till the second last letter' do
15
+ expect { subject.follow_path(letters_without_last_one) }.to_not raise_error
16
+ end
17
+
18
+ it 'does not create an arc for the last letter' do
19
+ expect { subject.follow_path(letters) }.to raise_error(KeyError)
20
+ end
21
+
22
+ it 'adds the last letter to the last arc as final letter' do
23
+ expect(subject.follow_path(letters_without_last_two).outgoing_arcs).to eq({
24
+ second_last_letter.to_sym => GADDAG::Arc.new(GADDAG::Node.new).tap do |arc|
25
+ arc.add_final_letter(last_letter)
26
+ end
27
+ })
28
+ end
29
+
30
+ it 'returns the last created node' do
31
+ expect(final_node).to equal(subject.follow_path(letters_without_last_one))
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples 'GADDAG::Node#create_path/behaviour' do
4
+ include_context 'GADDAG::Node#create_path/context'
5
+
6
+ let!(:final_node) { subject.create_path(letters) }
7
+
8
+ it 'creates the path for the given letters' do
9
+ expect { subject.follow_path(letters) }.to_not raise_error
10
+ end
11
+
12
+ it 'returns the last created node' do
13
+ expect(final_node).to equal(subject.follow_path(letters))
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ shared_context 'GADDAG::Node#create_path/context' do
4
+ subject { GADDAG::Node.new }
5
+ let(:letters) { %w[B ♢ R E A K] }
6
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require 'gaddag'
4
+
5
+ describe GADDAG, '#add' do
6
+ subject { GADDAG.new }
7
+ let(:path_delimiter) { GADDAG::Path::DELIMITER }
8
+
9
+ it 'returns itself' do
10
+ expect(subject.add('ANYTHING')).to equal(subject)
11
+ end
12
+
13
+ context 'given that the word BREAK is added' do
14
+ before { subject.add('BREAK') }
15
+
16
+ it 'creates a final path for K-A-E-R-B-♢' do
17
+ final_node = subject.root.follow_path(%w[K A E R])
18
+ expect(final_node.outgoing_arcs).to have_key(:B)
19
+ expect(final_node.outgoing_arcs[:B].final_letters).to eq([path_delimiter].to_set)
20
+ end
21
+
22
+ it 'creates a final path for B-♢-R-E-A-K' do
23
+ final_node = subject.root.follow_path(%w[B] + [path_delimiter] + %w[R E])
24
+ expect(final_node.outgoing_arcs).to have_key(:A)
25
+ expect(final_node.outgoing_arcs[:A].final_letters).to eq(['K'].to_set)
26
+ end
27
+
28
+ it 'creates a final path for R-B-♢-E-A-K' do
29
+ final_node = subject.root.follow_path(%w[R B] + [path_delimiter] + %w[E])
30
+ expect(final_node.outgoing_arcs).to have_key(:A)
31
+ expect(final_node.outgoing_arcs[:A].final_letters).to eq(['K'].to_set)
32
+ end
33
+
34
+ it 'creates a final path for E-R-B-♢-A-K' do
35
+ final_node = subject.root.follow_path(%w[E R B] + [path_delimiter])
36
+ expect(final_node.outgoing_arcs).to have_key(:A)
37
+ expect(final_node.outgoing_arcs[:A].final_letters).to eq(['K'].to_set)
38
+ end
39
+
40
+ it 'creates a final path for A-E-R-B-♢-K' do
41
+ final_node = subject.root.follow_path(%w[A E R B])
42
+ expect(final_node.outgoing_arcs).to have_key(path_delimiter.to_sym)
43
+ expect(final_node.outgoing_arcs[path_delimiter.to_sym].final_letters).to eq(['K'].to_set)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ require 'gaddag'
4
+ require 'shared/unit/gaddag/arc_context'
5
+
6
+ describe GADDAG::Arc, '#add_final_letter' do
7
+ include_context 'GADDAG::Arc/context'
8
+
9
+ context 'when adding a final letter' do
10
+ before { subject.add_final_letter('K') }
11
+
12
+ it 'is added' do
13
+ expect(subject.final_letters).to eq(%w[K].to_set)
14
+ end
15
+ end
16
+
17
+ context 'when adding a final letter twice' do
18
+ before { 2.times { subject.add_final_letter('L') } }
19
+
20
+ it 'is only added once' do
21
+ expect(subject.final_letters).to eq(%w[L].to_set)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'gaddag'
4
+ require 'shared/unit/gaddag/arc_context'
5
+
6
+ describe GADDAG::Arc, '#final_paths' do
7
+ include_context 'GADDAG::Arc/context'
8
+
9
+ let(:first_final_path) { GADDAG::Path.new(%w[A B C]) }
10
+ let(:second_final_path) { GADDAG::Path.new(%w[D E F]) }
11
+
12
+ context 'when the arc includes no final letters' do
13
+ context 'when the destination node has no final paths' do
14
+ specify { expect(subject.final_paths).to be_empty }
15
+ end
16
+
17
+ context 'when the destination node has final paths' do
18
+ before { destination.create_final_path(first_final_path.letters) }
19
+ before { destination.create_final_path(second_final_path.letters) }
20
+
21
+ specify { expect(subject.final_paths).to include(first_final_path) }
22
+ specify { expect(subject.final_paths).to include(second_final_path) }
23
+ specify { expect(subject.final_paths.count).to eq(2) }
24
+ end
25
+ end
26
+
27
+ context 'when the arc does include final letters' do
28
+ before { %w(X Y).each { |l| subject.add_final_letter(l) } }
29
+
30
+ context 'when the destination node has no final paths' do
31
+ specify { expect(subject.final_paths).to include(GADDAG::Path.new(%w[X])) }
32
+ specify { expect(subject.final_paths).to include(GADDAG::Path.new(%w[Y])) }
33
+ specify { expect(subject.final_paths.count).to eq(2) }
34
+ end
35
+
36
+ context 'when the destination node has final paths' do
37
+ before { destination.create_final_path(first_final_path.letters) }
38
+ before { destination.create_final_path(second_final_path.letters) }
39
+
40
+ specify { expect(subject.final_paths).to include(GADDAG::Path.new(%w[X])) }
41
+ specify { expect(subject.final_paths).to include(GADDAG::Path.new(%w[Y])) }
42
+
43
+ specify { expect(subject.final_paths).to include(first_final_path) }
44
+ specify { expect(subject.final_paths).to include(second_final_path) }
45
+
46
+ specify { expect(subject.final_paths.count).to eq(4) }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ require 'gaddag'
4
+ require 'shared/unit/gaddag/arc_context'
5
+
6
+ describe GADDAG::Arc, '#initialize' do
7
+ include_context 'GADDAG::Arc/context'
8
+
9
+ it 'initializes an empty set of final letters' do
10
+ expect(subject.final_letters).to be_empty
11
+ end
12
+
13
+ it 'stores the destination node' do
14
+ expect(subject.destination).to equal(destination)
15
+ end
16
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ require 'gaddag'
4
+
5
+ describe GADDAG, '#find' do
6
+ subject { GADDAG.new }
7
+
8
+ context 'given that the words BREAK and AKIN are added' do
9
+ before { subject.add('BREAK') }
10
+ before { subject.add('AKIN') }
11
+
12
+ context 'when searching for any word or substring that has not been added' do
13
+ it 'yields no results' do
14
+ expect(subject.find('ZOMBIES')).to be_empty
15
+ end
16
+ end
17
+
18
+ context 'when searching for an empty substring' do
19
+ let(:results) { subject.find('') }
20
+
21
+ it 'yields all words that have been added' do
22
+ expect(results).to eq(['BREAK', 'AKIN'])
23
+ end
24
+ end
25
+
26
+ context 'when searching for the letter E' do
27
+ let(:results) { subject.find('E') }
28
+
29
+ it 'yields one result, namely BREAK' do
30
+ expect(results).to eq(['BREAK'])
31
+ end
32
+ end
33
+
34
+ context 'when searching for the word BREAK' do
35
+ let(:results) { subject.find('BREAK') }
36
+
37
+ it 'yields one result, namely BREAK' do
38
+ expect(results).to eq(['BREAK'])
39
+ end
40
+ end
41
+
42
+ context 'when searching for the substring BREA' do
43
+ let(:results) { subject.find('BREA') }
44
+
45
+ it 'yields one result, namely BREAK' do
46
+ expect(results).to eq(['BREAK'])
47
+ end
48
+ end
49
+
50
+ context 'when searching for the substring REAK' do
51
+ let(:results) { subject.find('REAK') }
52
+
53
+ it 'yields one result, namely BREAK' do
54
+ expect(results).to eq(['BREAK'])
55
+ end
56
+ end
57
+
58
+ context 'when searching for the substring AK' do
59
+ let(:results) { subject.find('AK') }
60
+
61
+ it 'yields two results, namely BREAK and AKIN' do
62
+ expect(results).to eq(['BREAK', 'AKIN'])
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ require 'gaddag'
4
+
5
+ describe GADDAG, '#initialize' do
6
+ subject { GADDAG.new }
7
+
8
+ it 'sets the root node the a new, empty node' do
9
+ expect(subject.root).to eq(GADDAG::Node.new)
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require 'gaddag'
4
+
5
+ describe GADDAG::Node, '#arc?' do
6
+ subject { GADDAG::Node.new }
7
+
8
+ let(:letter) { 'L' }
9
+
10
+ context 'when the arc for the given letter exists' do
11
+ before { subject.create_arc(letter) }
12
+
13
+ it 'returns true' do
14
+ expect(subject.arc?(letter)).to eq(true)
15
+ end
16
+ end
17
+
18
+ context 'when the arc for the given letter does not exist' do
19
+ it 'returns false' do
20
+ expect(subject.arc?(letter)).to eq(false)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ require 'gaddag'
4
+ require 'shared/unit/gaddag/node/create_arc_behaviour'
5
+
6
+ describe GADDAG::Node, '#create_arc' do
7
+ it_behaves_like 'GADDAG::Node#create_arc/behaviour'
8
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ require 'gaddag'
4
+ require 'shared/unit/gaddag/node/create_arc_behaviour'
5
+
6
+ describe GADDAG::Node, '#create_final_arc' do
7
+ it_behaves_like 'GADDAG::Node#create_arc/behaviour' do
8
+ let(:final_letter) { 'Z' }
9
+
10
+ let(:create_arc) do
11
+ ->(*args) { subject.create_final_arc(*args.insert(1, final_letter)) }
12
+ end
13
+
14
+ it 'adds the final letter to the arc' do
15
+ expect(arc.final_letters).to include(final_letter)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+
3
+ require 'gaddag'
4
+ require 'shared/unit/gaddag/node/create_path_context'
5
+ require 'shared/unit/gaddag/node/create_final_path_behaviour'
6
+
7
+ describe GADDAG::Node, '#create_final_path' do
8
+ context 'when not given a list of destination nodes' do
9
+ it_behaves_like 'GADDAG::Node#create_final_path/behaviour'
10
+ end
11
+
12
+ context 'when given a list of destination nodes' do
13
+ it_behaves_like 'GADDAG::Node#create_final_path/behaviour' do
14
+ let(:letters) { %w[B ♢ R E A K] }
15
+
16
+ let!(:destinations) { 6.times.map { GADDAG::Node.new } }
17
+ let!(:final_node) { subject.create_final_path(letters, destinations) }
18
+
19
+ it 'creates the path for the given letters through the given destination nodes' do
20
+ expect(subject.follow_path(%w[B])).to equal(destinations[0])
21
+ expect(subject.follow_path(%w[B ♢])).to equal(destinations[1])
22
+ expect(subject.follow_path(%w[B ♢ R])).to equal(destinations[2])
23
+ expect(subject.follow_path(%w[B ♢ R E])).to equal(destinations[3])
24
+ expect(subject.follow_path(%w[B ♢ R E A])).to equal(destinations[4])
25
+ end
26
+ end
27
+ end
28
+
29
+ context 'when given a shortened list of destination nodes' do
30
+ it_behaves_like 'GADDAG::Node#create_final_path/behaviour' do
31
+ let(:letters) { %w[B ♢ R E A K] }
32
+
33
+ let(:destinations) { 3.times.map { GADDAG::Node.new } }
34
+ let!(:final_node) { subject.create_final_path(letters, destinations) }
35
+
36
+ it 'creates a path through the shortened list of destination nodes' do
37
+ expect(subject.follow_path(%w[B])).to equal(destinations[0])
38
+ expect(subject.follow_path(%w[B ♢])).to equal(destinations[1])
39
+ expect(subject.follow_path(%w[B ♢ R])).to equal(destinations[2])
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require 'gaddag'
4
+ require 'shared/unit/gaddag/node/create_path_context'
5
+ require 'shared/unit/gaddag/node/create_path_behaviour'
6
+
7
+ describe GADDAG::Node, '#create_path' do
8
+ context 'when not given a list of destination nodes' do
9
+ it_behaves_like 'GADDAG::Node#create_path/behaviour'
10
+ end
11
+
12
+ context 'when given a list of destination nodes' do
13
+ it_behaves_like 'GADDAG::Node#create_path/behaviour' do
14
+ let(:letters) { %w[B ♢ R E A K] }
15
+
16
+ let(:destinations) { 6.times.map { GADDAG::Node.new } }
17
+ let!(:final_node) { subject.create_path(letters, destinations) }
18
+
19
+ it 'creates a path through the given destination nodes' do
20
+ expect(subject.follow_path(%w[B])).to equal(destinations[0])
21
+ expect(subject.follow_path(%w[B ♢])).to equal(destinations[1])
22
+ expect(subject.follow_path(%w[B ♢ R])).to equal(destinations[2])
23
+ expect(subject.follow_path(%w[B ♢ R E])).to equal(destinations[3])
24
+ expect(subject.follow_path(%w[B ♢ R E A])).to equal(destinations[4])
25
+ expect(subject.follow_path(%w[B ♢ R E A K])).to equal(destinations[5])
26
+ end
27
+ end
28
+ end
29
+
30
+ context 'when given a shortened list of destination nodes' do
31
+ it_behaves_like 'GADDAG::Node#create_path/behaviour' do
32
+ let(:letters) { %w[B ♢ R E A K] }
33
+
34
+ let(:destinations) { 3.times.map { GADDAG::Node.new } }
35
+ let!(:final_node) { subject.create_path(letters, destinations) }
36
+
37
+ it 'creates a path through the shortened list of destination nodes' do
38
+ expect(subject.follow_path(%w[B])).to equal(destinations[0])
39
+ expect(subject.follow_path(%w[B ♢])).to equal(destinations[1])
40
+ expect(subject.follow_path(%w[B ♢ R])).to equal(destinations[2])
41
+ end
42
+ end
43
+ end
44
+ end