rambling-trie 2.4.0 → 2.5.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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +28 -0
  3. data/Gemfile +20 -8
  4. data/Guardfile +16 -5
  5. data/README.md +38 -32
  6. data/Rakefile +6 -0
  7. data/Steepfile +35 -0
  8. data/lib/rambling/trie/comparable.rb +2 -2
  9. data/lib/rambling/trie/compressible.rb +1 -1
  10. data/lib/rambling/trie/compressor.rb +22 -19
  11. data/lib/rambling/trie/configuration/properties.rb +10 -6
  12. data/lib/rambling/trie/configuration/provider_collection.rb +14 -9
  13. data/lib/rambling/trie/configuration.rb +2 -3
  14. data/lib/rambling/trie/container.rb +32 -24
  15. data/lib/rambling/trie/enumerable.rb +5 -6
  16. data/lib/rambling/trie/nodes/compressed.rb +26 -16
  17. data/lib/rambling/trie/nodes/node.rb +35 -12
  18. data/lib/rambling/trie/nodes/raw.rb +18 -20
  19. data/lib/rambling/trie/nodes.rb +2 -3
  20. data/lib/rambling/trie/readers/plain_text.rb +3 -3
  21. data/lib/rambling/trie/readers.rb +2 -3
  22. data/lib/rambling/trie/serializers/file.rb +1 -3
  23. data/lib/rambling/trie/serializers/marshal.rb +4 -4
  24. data/lib/rambling/trie/serializers/yaml.rb +3 -3
  25. data/lib/rambling/trie/serializers/zip.rb +13 -5
  26. data/lib/rambling/trie/serializers.rb +2 -3
  27. data/lib/rambling/trie/stringifyable.rb +1 -1
  28. data/lib/rambling/trie/version.rb +1 -1
  29. data/lib/rambling/trie.rb +12 -15
  30. data/rambling-trie.gemspec +4 -10
  31. data/sig/lib/rambling/trie/comparable.rbs +17 -0
  32. data/sig/lib/rambling/trie/compressible.rbs +17 -0
  33. data/sig/lib/rambling/trie/compressor.rbs +17 -0
  34. data/sig/lib/rambling/trie/configuration/properties.rbs +28 -0
  35. data/sig/lib/rambling/trie/configuration/provider_collection.rbs +47 -0
  36. data/sig/lib/rambling/trie/container.rbs +69 -0
  37. data/sig/lib/rambling/trie/enumerable.rbs +23 -0
  38. data/sig/lib/rambling/trie/inspectable.rbs +27 -0
  39. data/sig/lib/rambling/trie/invalid_operation.rbs +7 -0
  40. data/sig/lib/rambling/trie/nodes/compressed.rbs +25 -0
  41. data/sig/lib/rambling/trie/nodes/missing.rbs +9 -0
  42. data/sig/lib/rambling/trie/nodes/node.rbs +69 -0
  43. data/sig/lib/rambling/trie/nodes/raw.rbs +27 -0
  44. data/sig/lib/rambling/trie/readers/plain_text.rbs +9 -0
  45. data/sig/lib/rambling/trie/readers/reader.rbs +9 -0
  46. data/sig/lib/rambling/trie/serializers/file.rbs +8 -0
  47. data/sig/lib/rambling/trie/serializers/marshal.rbs +13 -0
  48. data/sig/lib/rambling/trie/serializers/serializer.rbs +10 -0
  49. data/sig/lib/rambling/trie/serializers/yaml.rbs +13 -0
  50. data/sig/lib/rambling/trie/serializers/zip.rbs +21 -0
  51. data/sig/lib/rambling/trie/stringifyable.rbs +21 -0
  52. data/sig/lib/rambling/trie.rbs +27 -0
  53. data/sig/lib/zip/entry.rbs +11 -0
  54. data/sig/lib/zip/file.rbs +11 -0
  55. metadata +34 -123
  56. data/spec/assets/test_words.en_US.txt +0 -23
  57. data/spec/assets/test_words.es_DO.txt +0 -24
  58. data/spec/integration/rambling/trie_spec.rb +0 -116
  59. data/spec/lib/rambling/trie/comparable_spec.rb +0 -87
  60. data/spec/lib/rambling/trie/compressor_spec.rb +0 -111
  61. data/spec/lib/rambling/trie/configuration/properties_spec.rb +0 -75
  62. data/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +0 -177
  63. data/spec/lib/rambling/trie/container_spec.rb +0 -466
  64. data/spec/lib/rambling/trie/enumerable_spec.rb +0 -50
  65. data/spec/lib/rambling/trie/inspectable_spec.rb +0 -62
  66. data/spec/lib/rambling/trie/nodes/compressed_spec.rb +0 -43
  67. data/spec/lib/rambling/trie/nodes/node_spec.rb +0 -9
  68. data/spec/lib/rambling/trie/nodes/raw_spec.rb +0 -184
  69. data/spec/lib/rambling/trie/readers/plain_text_spec.rb +0 -26
  70. data/spec/lib/rambling/trie/readers/reader_spec.rb +0 -14
  71. data/spec/lib/rambling/trie/serializers/file_spec.rb +0 -11
  72. data/spec/lib/rambling/trie/serializers/marshal_spec.rb +0 -10
  73. data/spec/lib/rambling/trie/serializers/serializer_spec.rb +0 -21
  74. data/spec/lib/rambling/trie/serializers/yaml_spec.rb +0 -10
  75. data/spec/lib/rambling/trie/serializers/zip_spec.rb +0 -36
  76. data/spec/lib/rambling/trie/stringifyable_spec.rb +0 -89
  77. data/spec/lib/rambling/trie_spec.rb +0 -244
  78. data/spec/spec_helper.rb +0 -42
  79. data/spec/support/config.rb +0 -15
  80. data/spec/support/helpers/add_word.rb +0 -20
  81. data/spec/support/helpers/one_line_heredoc.rb +0 -11
  82. data/spec/support/shared_examples/a_compressible_trie.rb +0 -46
  83. data/spec/support/shared_examples/a_container_partial_word.rb +0 -17
  84. data/spec/support/shared_examples/a_container_scan.rb +0 -14
  85. data/spec/support/shared_examples/a_container_word.rb +0 -43
  86. data/spec/support/shared_examples/a_container_words_within.rb +0 -44
  87. data/spec/support/shared_examples/a_serializable_trie.rb +0 -26
  88. data/spec/support/shared_examples/a_serializer.rb +0 -60
  89. data/spec/support/shared_examples/a_trie_data_structure.rb +0 -45
  90. data/spec/support/shared_examples/a_trie_node.rb +0 -135
  91. data/spec/support/shared_examples/a_trie_node_implementation.rb +0 -149
  92. data/spec/tmp/.gitkeep +0 -0
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Inspectable do
6
- let(:node) { Rambling::Trie::Nodes::Raw.new }
7
-
8
- before do
9
- add_words node, %w(only three words)
10
- end
11
-
12
- describe '#inspect' do
13
- let(:child) { node[:o] }
14
- let(:terminal_node) { node[:o][:n][:l][:y] }
15
-
16
- it 'returns a pretty printed version of the parent node' do
17
- expect(node.inspect).to eq one_line <<~RAW
18
- #<Rambling::Trie::Nodes::Raw letter: nil,
19
- terminal: nil,
20
- children: [:o, :t, :w]>
21
- RAW
22
- end
23
-
24
- it 'returns a pretty printed version of the child node' do
25
- expect(child.inspect).to eq one_line <<~CHILD
26
- #<Rambling::Trie::Nodes::Raw letter: :o,
27
- terminal: nil,
28
- children: [:n]>
29
- CHILD
30
- end
31
-
32
- it 'returns a pretty printed version of the terminal node' do
33
- expect(terminal_node.inspect).to eq one_line <<~TERMINAL
34
- #<Rambling::Trie::Nodes::Raw letter: :y,
35
- terminal: true,
36
- children: []>
37
- TERMINAL
38
- end
39
-
40
- context 'with a compressed node' do
41
- let(:compressor) { Rambling::Trie::Compressor.new }
42
- let(:compressed) { compressor.compress node }
43
- let(:compressed_child) { compressed[:o] }
44
-
45
- it 'returns a pretty printed version of the compressed parent node' do
46
- expect(compressed.inspect).to eq one_line <<~COMPRESSED
47
- #<Rambling::Trie::Nodes::Compressed letter: nil,
48
- terminal: nil,
49
- children: [:o, :t, :w]>
50
- COMPRESSED
51
- end
52
-
53
- it 'returns a pretty printed version of the compressed child node' do
54
- expect(compressed_child.inspect).to eq one_line <<~CHILD
55
- #<Rambling::Trie::Nodes::Compressed letter: :only,
56
- terminal: true,
57
- children: []>
58
- CHILD
59
- end
60
- end
61
- end
62
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Nodes::Compressed do
6
- let(:raw_node) { Rambling::Trie::Nodes::Raw.new }
7
- let(:compressor) { Rambling::Trie::Compressor.new }
8
- let(:node) { compressor.compress raw_node }
9
-
10
- describe '#new' do
11
- it 'is not a word' do
12
- expect(node).not_to be_word
13
- end
14
- end
15
-
16
- it_behaves_like 'a trie node implementation' do
17
- def add_word_to_tree word
18
- add_word raw_node, word
19
- end
20
-
21
- def add_words_to_tree words
22
- add_words raw_node, words
23
- end
24
-
25
- def assign_letter letter
26
- raw_node.letter = letter
27
- end
28
- end
29
-
30
- describe '#compressed?' do
31
- it 'returns true' do
32
- expect(node).to be_compressed
33
- end
34
- end
35
-
36
- describe '#add' do
37
- it 'raises an error' do
38
- expect do
39
- add_word node, 'restaurant'
40
- end.to raise_error Rambling::Trie::InvalidOperation
41
- end
42
- end
43
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Nodes::Node do
6
- it_behaves_like 'a trie node' do
7
- let(:node) { described_class.new }
8
- end
9
- end
@@ -1,184 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Nodes::Raw do
6
- let(:node) { described_class.new }
7
-
8
- describe '#new' do
9
- it 'is not a word' do
10
- expect(node).not_to be_word
11
- end
12
- end
13
-
14
- it_behaves_like 'a trie node implementation' do
15
- def add_word_to_tree word
16
- add_word node, word
17
- end
18
-
19
- def add_words_to_tree words
20
- add_words node, words
21
- end
22
-
23
- def assign_letter letter
24
- node.letter = letter
25
- end
26
- end
27
-
28
- describe '#compressed?' do
29
- it 'returns false' do
30
- expect(node).not_to be_compressed
31
- end
32
- end
33
-
34
- describe '#add' do
35
- context 'when the node has no branches' do
36
- before { add_word node, 'abc' }
37
-
38
- it 'adds only one child' do
39
- expect(node.children.size).to eq 1
40
- end
41
-
42
- # rubocop:disable RSpec/MultipleExpectations
43
- it 'adds the full subtree' do
44
- expect(node[:a]).not_to be_nil
45
- expect(node[:a][:b]).not_to be_nil
46
- expect(node[:a][:b][:c]).not_to be_nil
47
- end
48
- # rubocop:enable RSpec/MultipleExpectations
49
-
50
- # rubocop:disable RSpec/MultipleExpectations
51
- it 'marks only the last child as terminal' do
52
- expect(node).not_to be_terminal
53
- expect(node[:a]).not_to be_terminal
54
- expect(node[:a][:b]).not_to be_terminal
55
- expect(node[:a][:b][:c]).to be_terminal
56
- end
57
- # rubocop:enable RSpec/MultipleExpectations
58
- end
59
-
60
- context 'when a word is added more than once' do
61
- before do
62
- add_word node, 'ack'
63
- add_word node, 'ack'
64
- end
65
-
66
- # rubocop:disable RSpec/MultipleExpectations
67
- it 'only counts it once' do
68
- expect(node.children.size).to eq 1
69
- expect(node[:a].children.size).to eq 1
70
- expect(node[:a][:c].children.size).to eq 1
71
- expect(node[:a][:c][:k].children.size).to eq 0
72
- end
73
- # rubocop:enable RSpec/MultipleExpectations
74
-
75
- # rubocop:disable RSpec/MultipleExpectations
76
- it 'does not change the terminal nodes in the tree' do
77
- expect(node).not_to be_terminal
78
- expect(node[:a]).not_to be_terminal
79
- expect(node[:a][:c]).not_to be_terminal
80
- expect(node[:a][:c][:k]).to be_terminal
81
- end
82
- # rubocop:enable RSpec/MultipleExpectations
83
-
84
- it 'still returns the "added" node' do
85
- child = add_word node, 'ack'
86
- expect(child.letter).to eq :a
87
- end
88
- end
89
-
90
- context 'when the word does not exist in the tree but the letters do' do
91
- before { add_words node, %w(ack a) }
92
-
93
- it 'does not add another branch' do
94
- expect(node.children.size).to eq 1
95
- end
96
-
97
- # rubocop:disable RSpec/MultipleExpectations
98
- it 'marks the corresponding node as terminal' do
99
- expect(node).not_to be_terminal
100
- expect(node[:a]).to be_terminal
101
- expect(node[:a][:c]).not_to be_terminal
102
- expect(node[:a][:c][:k]).to be_terminal
103
- end
104
- # rubocop:enable RSpec/MultipleExpectations
105
-
106
- it 'returns the added node' do
107
- child = add_word node, 'a'
108
- expect(child.letter).to eq :a
109
- end
110
- end
111
-
112
- context 'when the node has a letter and a parent' do
113
- let(:parent) { described_class.new }
114
- let(:node) { described_class.new :a, parent }
115
-
116
- context 'when adding an empty string' do
117
- before { add_word node, '' }
118
-
119
- it 'does not alter the node letter' do
120
- expect(node.letter).to eq :a
121
- end
122
-
123
- it 'does not change the node children' do
124
- expect(node.children.size).to eq 0
125
- end
126
-
127
- it 'changes the node to terminal' do
128
- expect(node).to be_terminal
129
- end
130
- end
131
-
132
- context 'when adding a one letter word' do
133
- before { add_word node, 'b' }
134
-
135
- it 'does not alter the node letter' do
136
- expect(node.letter).to eq :a
137
- end
138
-
139
- # rubocop:disable RSpec/MultipleExpectations
140
- it 'adds a child with the expected letter' do
141
- expect(node.children.size).to eq 1
142
- expect(node.children.first.letter).to eq :b
143
- end
144
- # rubocop:enable RSpec/MultipleExpectations
145
-
146
- it 'reports it has the expected letter a key' do
147
- expect(node).to have_key(:b)
148
- end
149
-
150
- it 'returns the child corresponding to the key' do
151
- expect(node[:b]).to eq node.children_tree[:b]
152
- end
153
-
154
- it 'does not mark itself as terminal' do
155
- expect(node).not_to be_terminal
156
- end
157
-
158
- it 'marks the first child as terminal' do
159
- expect(node[:b]).to be_terminal
160
- end
161
- end
162
-
163
- context 'when adding a large word' do
164
- before { add_word node, 'mplified' }
165
-
166
- it 'marks the last letter as terminal' do
167
- expect(node[:m][:p][:l][:i][:f][:i][:e][:d]).to be_terminal
168
- end
169
-
170
- # rubocop:disable RSpec/ExampleLength, RSpec/MultipleExpectations
171
- it 'does not mark any other letter as terminal' do
172
- expect(node[:m][:p][:l][:i][:f][:i][:e]).not_to be_terminal
173
- expect(node[:m][:p][:l][:i][:f][:i]).not_to be_terminal
174
- expect(node[:m][:p][:l][:i][:f]).not_to be_terminal
175
- expect(node[:m][:p][:l][:i]).not_to be_terminal
176
- expect(node[:m][:p][:l]).not_to be_terminal
177
- expect(node[:m][:p]).not_to be_terminal
178
- expect(node[:m]).not_to be_terminal
179
- end
180
- # rubocop:enable RSpec/ExampleLength, RSpec/MultipleExpectations
181
- end
182
- end
183
- end
184
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Readers::PlainText do
6
- subject(:reader) { described_class.new }
7
-
8
- describe '#each_word' do
9
- let(:filepath) { File.join(::SPEC_ROOT, 'assets', 'test_words.en_US.txt') }
10
- let(:words) { File.readlines(filepath).map(&:chomp) }
11
-
12
- it 'yields every word yielded by the file' do
13
- yielded = []
14
- reader.each_word(filepath) { |word| yielded << word }
15
- expect(yielded).to eq words
16
- end
17
-
18
- it 'returns an enumerator when no block is given' do
19
- expect(reader.each_word filepath).to be_an Enumerator
20
- end
21
-
22
- it 'returns the enumerable when a block is given' do
23
- expect(reader.each_word(filepath) { |_| }).to eq reader
24
- end
25
- end
26
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Readers::Reader do
6
- subject(:reader) { described_class.new }
7
-
8
- describe '#load' do
9
- it 'is an abstract method that raises NotImplementedError' do
10
- expect { reader.each_word('any-file.zip') }
11
- .to raise_exception NotImplementedError
12
- end
13
- end
14
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Serializers::File do
6
- it_behaves_like 'a serializer' do
7
- let(:file_format) { :file }
8
- let(:content) { trie.to_a.join ' ' }
9
- let(:format_content) { ->(content) { content } }
10
- end
11
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Serializers::Marshal do
6
- it_behaves_like 'a serializer' do
7
- let(:file_format) { :marshal }
8
- let(:format_content) { Marshal.method(:dump) }
9
- end
10
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Serializers::Serializer do
6
- subject(:serializer) { described_class.new }
7
-
8
- describe '#load' do
9
- it 'is an abstract method that raises NotImplementedError' do
10
- expect { serializer.load('any-file.zip') }
11
- .to raise_exception NotImplementedError
12
- end
13
- end
14
-
15
- describe '#dump' do
16
- it 'is an abstract method that raises NotImplementedError' do
17
- expect { serializer.dump('any contents', 'any-file.zip') }
18
- .to raise_exception NotImplementedError
19
- end
20
- end
21
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Serializers::Yaml do
6
- it_behaves_like 'a serializer' do
7
- let(:file_format) { :yml }
8
- let(:format_content) { YAML.method(:dump) }
9
- end
10
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Serializers::Zip do
6
- {
7
- yaml: YAML.method(:dump),
8
- yml: YAML.method(:dump),
9
- marshal: Marshal.method(:dump),
10
- file: Marshal.method(:dump),
11
- }.each do |file_format, dump_method|
12
- context "with '.#{file_format}'" do
13
- it_behaves_like 'a serializer' do
14
- let(:properties) { Rambling::Trie::Configuration::Properties.new }
15
- let(:serializer) { described_class.new properties }
16
- let(:file_format) { :zip }
17
-
18
- let(:filepath) { File.join tmp_path, "trie-root.#{file_format}.zip" }
19
- let(:format_content) { ->(content) { zip dump_method.call content } }
20
- let(:filename) { File.basename(filepath).gsub %r{\.zip}, '' }
21
-
22
- before { properties.tmp_path = tmp_path }
23
- end
24
- end
25
- end
26
-
27
- def zip content
28
- cursor = Zip::OutputStream.write_buffer do |io|
29
- io.put_next_entry filename
30
- io.write content
31
- end
32
-
33
- cursor.rewind
34
- cursor.read
35
- end
36
- end
@@ -1,89 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Stringifyable do
6
- describe '#as_word' do
7
- let(:node) { Rambling::Trie::Nodes::Raw.new }
8
-
9
- context 'with an empty node' do
10
- before { add_word node, '' }
11
-
12
- it 'returns nil' do
13
- expect(node.as_word).to be_empty
14
- end
15
- end
16
-
17
- context 'with one letter' do
18
- before do
19
- node.letter = :a
20
- add_word node, ''
21
- end
22
-
23
- it 'returns the expected one letter word' do
24
- expect(node.as_word).to eq 'a'
25
- end
26
- end
27
-
28
- context 'with a small word' do
29
- before do
30
- node.letter = :a
31
- add_word node, 'll'
32
- end
33
-
34
- it 'returns the expected small word' do
35
- expect(node[:l][:l].as_word).to eq 'all'
36
- end
37
-
38
- it 'raises an error for a non terminal node' do
39
- expect { node[:l].as_word }
40
- .to raise_error Rambling::Trie::InvalidOperation
41
- end
42
- end
43
-
44
- context 'with a long word' do
45
- before do
46
- node.letter = :b
47
- add_word node, 'eautiful'
48
- end
49
-
50
- it 'returns the expected long word' do
51
- expect(node[:e][:a][:u][:t][:i][:f][:u][:l].as_word).to eq 'beautiful'
52
- end
53
- end
54
-
55
- context 'with a node with nil letter' do
56
- let(:node) { Rambling::Trie::Nodes::Raw.new nil }
57
-
58
- it 'returns nil' do
59
- expect(node.as_word).to be_empty
60
- end
61
- end
62
-
63
- context 'with a compressed node' do
64
- let(:compressor) { Rambling::Trie::Compressor.new }
65
- let(:compressed_node) { compressor.compress node }
66
-
67
- before do
68
- node.letter = :a
69
- add_words node, %w(m dd)
70
- end
71
-
72
- [
73
- [:m, 'am'],
74
- [:d, 'add'],
75
- ].each do |test_params|
76
- key, expected = test_params
77
-
78
- it "returns the words for terminal nodes (#{key} => #{expected})" do
79
- expect(compressed_node[key].as_word).to eq expected
80
- end
81
- end
82
-
83
- it 'raises an error for non terminal nodes' do
84
- expect { compressed_node.as_word }
85
- .to raise_error Rambling::Trie::InvalidOperation
86
- end
87
- end
88
- end
89
- end