gaddag 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +38 -0
- data/Rakefile +1 -0
- data/gaddag.gemspec +31 -0
- data/lib/gaddag.rb +47 -0
- data/lib/gaddag/arc.rb +41 -0
- data/lib/gaddag/node.rb +115 -0
- data/lib/gaddag/path.rb +72 -0
- data/lib/gaddag/word.rb +39 -0
- data/spec/shared/unit/gaddag/arc_context.rb +6 -0
- data/spec/shared/unit/gaddag/node/create_arc_behaviour.rb +41 -0
- data/spec/shared/unit/gaddag/node/create_final_path_behaviour.rb +33 -0
- data/spec/shared/unit/gaddag/node/create_path_behaviour.rb +15 -0
- data/spec/shared/unit/gaddag/node/create_path_context.rb +6 -0
- data/spec/unit/gaddag/add_spec.rb +46 -0
- data/spec/unit/gaddag/arc/add_final_letter_spec.rb +24 -0
- data/spec/unit/gaddag/arc/final_paths_spec.rb +49 -0
- data/spec/unit/gaddag/arc/initialize_spec.rb +16 -0
- data/spec/unit/gaddag/find_spec.rb +66 -0
- data/spec/unit/gaddag/initialize_spec.rb +11 -0
- data/spec/unit/gaddag/node/arc_spec.rb +23 -0
- data/spec/unit/gaddag/node/create_arc_spec.rb +8 -0
- data/spec/unit/gaddag/node/create_final_arc_spec.rb +18 -0
- data/spec/unit/gaddag/node/create_final_path_spec.rb +43 -0
- data/spec/unit/gaddag/node/create_path_spec.rb +44 -0
- data/spec/unit/gaddag/node/final_path_spec.rb +30 -0
- data/spec/unit/gaddag/node/final_paths_spec.rb +48 -0
- data/spec/unit/gaddag/node/follow_arc_spec.rb +24 -0
- data/spec/unit/gaddag/node/follow_path_spec.rb +41 -0
- data/spec/unit/gaddag/node/path_spec.rb +30 -0
- data/spec/unit/gaddag/path/equal_value_spec.rb +17 -0
- data/spec/unit/gaddag/path/include_delimiter_spec.rb +15 -0
- data/spec/unit/gaddag/path/initialize_spec.rb +12 -0
- data/spec/unit/gaddag/path/reversed_prefix_letters_spec.rb +34 -0
- data/spec/unit/gaddag/path/start_with_spec.rb +39 -0
- data/spec/unit/gaddag/path/suffix_letters_spec.rb +34 -0
- data/spec/unit/gaddag/path/to_ary_spec.rb +15 -0
- data/spec/unit/gaddag/path/to_s_spec.rb +18 -0
- data/spec/unit/gaddag/path/to_word_spec.rb +37 -0
- data/spec/unit/gaddag/word/equal_value_spec.rb +17 -0
- data/spec/unit/gaddag/word/initialize_spec.rb +12 -0
- data/spec/unit/gaddag/word/to_delimited_paths_spec.rb +29 -0
- data/spec/unit/gaddag/word/to_s_spec.rb +18 -0
- 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,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,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,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
|