rambling-trie 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/README.md +16 -10
  4. data/lib/rambling/trie/compressor.rb +2 -0
  5. data/lib/rambling/trie/configuration/properties.rb +5 -2
  6. data/lib/rambling/trie/configuration/provider_collection.rb +2 -2
  7. data/lib/rambling/trie/container.rb +12 -1
  8. data/lib/rambling/trie/enumerable.rb +1 -1
  9. data/lib/rambling/trie/nodes/node.rb +4 -4
  10. data/lib/rambling/trie/nodes/raw.rb +2 -1
  11. data/lib/rambling/trie/readers/plain_text.rb +1 -1
  12. data/lib/rambling/trie/serializers/file.rb +1 -3
  13. data/lib/rambling/trie/serializers/marshal.rb +3 -3
  14. data/lib/rambling/trie/serializers/yaml.rb +2 -2
  15. data/lib/rambling/trie/serializers/zip.rb +2 -0
  16. data/lib/rambling/trie/version.rb +1 -1
  17. data/lib/rambling/trie.rb +1 -1
  18. data/rambling-trie.gemspec +3 -9
  19. metadata +7 -122
  20. data/spec/assets/test_words.en_US.txt +0 -23
  21. data/spec/assets/test_words.es_DO.txt +0 -24
  22. data/spec/integration/rambling/trie_spec.rb +0 -116
  23. data/spec/lib/rambling/trie/comparable_spec.rb +0 -87
  24. data/spec/lib/rambling/trie/compressor_spec.rb +0 -111
  25. data/spec/lib/rambling/trie/configuration/properties_spec.rb +0 -75
  26. data/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +0 -177
  27. data/spec/lib/rambling/trie/container_spec.rb +0 -466
  28. data/spec/lib/rambling/trie/enumerable_spec.rb +0 -50
  29. data/spec/lib/rambling/trie/inspectable_spec.rb +0 -62
  30. data/spec/lib/rambling/trie/nodes/compressed_spec.rb +0 -43
  31. data/spec/lib/rambling/trie/nodes/node_spec.rb +0 -9
  32. data/spec/lib/rambling/trie/nodes/raw_spec.rb +0 -184
  33. data/spec/lib/rambling/trie/readers/plain_text_spec.rb +0 -26
  34. data/spec/lib/rambling/trie/readers/reader_spec.rb +0 -14
  35. data/spec/lib/rambling/trie/serializers/file_spec.rb +0 -11
  36. data/spec/lib/rambling/trie/serializers/marshal_spec.rb +0 -10
  37. data/spec/lib/rambling/trie/serializers/serializer_spec.rb +0 -21
  38. data/spec/lib/rambling/trie/serializers/yaml_spec.rb +0 -10
  39. data/spec/lib/rambling/trie/serializers/zip_spec.rb +0 -36
  40. data/spec/lib/rambling/trie/stringifyable_spec.rb +0 -89
  41. data/spec/lib/rambling/trie_spec.rb +0 -244
  42. data/spec/spec_helper.rb +0 -42
  43. data/spec/support/config.rb +0 -15
  44. data/spec/support/helpers/add_word.rb +0 -20
  45. data/spec/support/helpers/one_line_heredoc.rb +0 -11
  46. data/spec/support/shared_examples/a_compressible_trie.rb +0 -46
  47. data/spec/support/shared_examples/a_container_partial_word.rb +0 -17
  48. data/spec/support/shared_examples/a_container_scan.rb +0 -14
  49. data/spec/support/shared_examples/a_container_word.rb +0 -43
  50. data/spec/support/shared_examples/a_container_words_within.rb +0 -44
  51. data/spec/support/shared_examples/a_serializable_trie.rb +0 -26
  52. data/spec/support/shared_examples/a_serializer.rb +0 -60
  53. data/spec/support/shared_examples/a_trie_data_structure.rb +0 -45
  54. data/spec/support/shared_examples/a_trie_node.rb +0 -135
  55. data/spec/support/shared_examples/a_trie_node_implementation.rb +0 -149
  56. data/spec/tmp/.gitkeep +0 -0
@@ -1,466 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Rambling::Trie::Container do
6
- subject(:container) { described_class.new root, compressor }
7
-
8
- let(:compressor) { Rambling::Trie::Compressor.new }
9
- let(:root) { Rambling::Trie::Nodes::Raw.new }
10
-
11
- describe '.new' do
12
- it 'uses the provided node as root' do
13
- expect(container.root).to be root
14
- end
15
-
16
- context 'with a block' do
17
- it 'yields the container' do
18
- yielded = nil
19
-
20
- container = described_class.new root, compressor do |c|
21
- yielded = c
22
- end
23
-
24
- expect(yielded).to be container
25
- end
26
- end
27
- end
28
-
29
- describe '#add' do
30
- # rubocop:disable RSpec/MultipleExpectations
31
- it 'adds the word to the root node' do
32
- add_word container, 'hello'
33
-
34
- expect(root.children.size).to eq 1
35
- expect(root.to_a).to eq %w(hello)
36
- end
37
- # rubocop:enable RSpec/MultipleExpectations
38
- end
39
-
40
- describe '#concat' do
41
- # rubocop:disable RSpec/MultipleExpectations
42
- it 'adds all the words to the root node' do
43
- container.concat %w(other words)
44
-
45
- expect(root.children.size).to eq 2
46
- expect(root.to_a).to eq %w(other words)
47
- end
48
-
49
- it 'returns all the corresponding nodes' do
50
- nodes = container.concat %w(other words)
51
-
52
- expect(nodes.first.letter).to eq :o
53
- expect(nodes.last.letter).to eq :w
54
- end
55
- # rubocop:enable RSpec/MultipleExpectations
56
- end
57
-
58
- describe '#compress' do
59
- let(:node) { Rambling::Trie::Nodes::Compressed.new }
60
-
61
- before do
62
- allow(compressor).to receive(:compress).and_return node
63
-
64
- add_word root, 'yes'
65
- node[:yes] = Rambling::Trie::Nodes::Compressed.new
66
- end
67
-
68
- it 'compresses the trie using the compressor' do
69
- container.compress
70
-
71
- expect(compressor).to have_received(:compress).with root
72
- end
73
-
74
- # rubocop:disable RSpec/MultipleExpectations
75
- it 'returns a container with the new root' do
76
- new_container = container.compress
77
-
78
- expect(new_container.root).not_to eq root
79
- expect(new_container.root).to eq node
80
- end
81
- # rubocop:enable RSpec/MultipleExpectations
82
-
83
- it 'returns a new container' do
84
- expect(container.compress).not_to eq container
85
- end
86
-
87
- it 'can compress multiple times' do
88
- container.compress
89
- container.compress
90
-
91
- expect(compressor).to have_received(:compress).twice
92
- end
93
-
94
- it 'cannot compress the result' do
95
- new_container = container.compress
96
- new_container.compress
97
-
98
- expect(compressor).to have_received(:compress).once
99
- end
100
- end
101
-
102
- describe '#compress!' do
103
- let(:node) { Rambling::Trie::Nodes::Compressed.new }
104
-
105
- context 'with a mocked result' do
106
- before do
107
- allow(compressor).to receive(:compress).and_return node
108
-
109
- add_word root, 'yes'
110
- node[:yes] = Rambling::Trie::Nodes::Compressed.new
111
- end
112
-
113
- it 'compresses the trie using the compressor' do
114
- container.compress!
115
-
116
- expect(compressor).to have_received(:compress).with root
117
- end
118
-
119
- # rubocop:disable RSpec/MultipleExpectations
120
- it 'changes to the root returned by the compressor' do
121
- container.compress!
122
-
123
- expect(container.root).not_to eq root
124
- expect(container.root).to eq node
125
- end
126
- # rubocop:enable RSpec/MultipleExpectations
127
-
128
- it 'returns itself' do
129
- expect(container.compress!).to eq container
130
- end
131
-
132
- it 'does not compress multiple times' do
133
- container.compress!
134
- allow(node).to receive(:compressed?).and_return(true)
135
-
136
- container.compress!
137
- expect(compressor).to have_received(:compress).once
138
- end
139
-
140
- # rubocop:disable RSpec/MultipleExpectations
141
- it 'gets a new root from the compressor' do
142
- container.compress!
143
-
144
- expect(container.root).not_to be root
145
- expect(container.root).to be_compressed
146
- expect(root).not_to be_compressed
147
- end
148
- # rubocop:enable RSpec/MultipleExpectations
149
- end
150
-
151
- it 'generates a new root with the words from the passed root' do
152
- words = %w(a few words hello hell)
153
-
154
- add_words container, words
155
- container.compress!
156
-
157
- words.each { |word| expect(container).to include word }
158
- end
159
-
160
- describe 'and trying to add a word' do
161
- it 'raises an error' do
162
- add_words container, %w(repay rest repaint)
163
- container.compress!
164
-
165
- expect do
166
- add_word container, 'restaurant'
167
- end.to raise_error Rambling::Trie::InvalidOperation
168
- end
169
- end
170
- end
171
-
172
- describe '#word?' do
173
- it_behaves_like 'a propagating node' do
174
- let(:method_name) { :word? }
175
- end
176
-
177
- context 'when word is contained' do
178
- before { add_words container, %w(hello high) }
179
-
180
- it_behaves_like 'a matching container#word'
181
-
182
- context 'with compressed root' do
183
- before { container.compress! }
184
-
185
- it_behaves_like 'a matching container#word'
186
- end
187
- end
188
-
189
- context 'when word is not contained' do
190
- before { add_word container, 'hello' }
191
-
192
- it_behaves_like 'a non-matching container#word'
193
-
194
- context 'with compressed root' do
195
- before { container.compress! }
196
-
197
- it_behaves_like 'a non-matching container#word'
198
- end
199
- end
200
- end
201
-
202
- describe '#partial_word?' do
203
- context 'with underlying node' do
204
- it_behaves_like 'a propagating node' do
205
- let(:method_name) { :partial_word? }
206
- end
207
- end
208
-
209
- context 'when word is contained' do
210
- before { add_words container, %w(hello high) }
211
-
212
- it_behaves_like 'a matching container#partial_word'
213
-
214
- context 'with compressed root' do
215
- before { container.compress! }
216
-
217
- it_behaves_like 'a matching container#partial_word'
218
- end
219
- end
220
-
221
- context 'when word is not contained' do
222
- before { add_word container, 'hello' }
223
-
224
- it_behaves_like 'a non-matching container#partial_word'
225
-
226
- context 'with compressed root' do
227
- before { container.compress! }
228
-
229
- it_behaves_like 'a non-matching container#partial_word'
230
- end
231
- end
232
- end
233
-
234
- describe '#scan' do
235
- context 'when words that match are contained' do
236
- before do
237
- add_words container, %w(hi hello high hell highlight histerical)
238
- end
239
-
240
- it_behaves_like 'a matching container#scan'
241
-
242
- context 'with compressed root' do
243
- before { container.compress! }
244
-
245
- it_behaves_like 'a matching container#scan'
246
- end
247
- end
248
-
249
- context 'when words that match are not contained' do
250
- before { add_word container, 'hello' }
251
-
252
- it 'returns an empty array' do
253
- expect(container.scan 'hi').to eq %w()
254
- end
255
-
256
- context 'with compressed root' do
257
- before { container.compress! }
258
-
259
- it 'returns an empty array' do
260
- expect(container.scan 'hi').to eq %w()
261
- end
262
- end
263
- end
264
- end
265
-
266
- describe '#words_within' do
267
- before { add_words container, %w(one word and other words) }
268
-
269
- context 'when phrase does not contain any words' do
270
- it 'returns an empty array' do
271
- expect(container.words_within 'xyz').to match_array []
272
- end
273
-
274
- context 'with compressed node' do
275
- before { container.compress! }
276
-
277
- it 'returns an empty array' do
278
- expect(container.words_within 'xyz').to match_array []
279
- end
280
- end
281
- end
282
-
283
- context 'when phrase contains one word at the start of the phrase' do
284
- it_behaves_like 'a matching container#words_within'
285
-
286
- context 'with compressed node' do
287
- before { container.compress! }
288
-
289
- it_behaves_like 'a matching container#words_within'
290
- end
291
- end
292
-
293
- context 'when phrase contains one word at the end of the phrase' do
294
- it 'returns an array with the word found in the phrase' do
295
- expect(container.words_within 'xyz word').to match_array %w(word)
296
- end
297
-
298
- context 'with compressed node' do
299
- before { container.compress! }
300
-
301
- it 'returns an array with the word found in the phrase' do
302
- expect(container.words_within 'xyz word').to match_array %w(word)
303
- end
304
- end
305
- end
306
-
307
- context 'when phrase contains a few words' do
308
- it_behaves_like 'a non-matching container#words_within'
309
-
310
- context 'with compressed node' do
311
- before { container.compress! }
312
-
313
- it_behaves_like 'a non-matching container#words_within'
314
- end
315
- end
316
- end
317
-
318
- describe '#words_within?' do
319
- before { add_words container, %w(one word and other words) }
320
-
321
- it_behaves_like 'a matching container#words_within?'
322
-
323
- context 'with compressed node' do
324
- before { container.compress! }
325
-
326
- it_behaves_like 'a non-matching container#words_within?'
327
- end
328
- end
329
-
330
- describe '#==' do
331
- context 'when the root nodes are the same' do
332
- let :other_container do
333
- described_class.new container.root, compressor
334
- end
335
-
336
- it 'returns true' do
337
- expect(container).to eq other_container
338
- end
339
- end
340
-
341
- context 'when the root nodes are not the same' do
342
- let(:other_root) { Rambling::Trie::Nodes::Raw.new }
343
- let :other_container do
344
- described_class.new other_root, compressor
345
- end
346
-
347
- before { add_word other_container, 'hola' }
348
-
349
- it 'returns false' do
350
- expect(container).not_to eq other_container
351
- end
352
- end
353
- end
354
-
355
- describe '#each' do
356
- before { add_words container, %w(yes no why) }
357
-
358
- it 'returns an enumerator when no block is given' do
359
- expect(container.each).to be_instance_of Enumerator
360
- end
361
-
362
- it 'iterates through all words contained' do
363
- expect(container.each.to_a).to eq %w(yes no why)
364
- end
365
- end
366
-
367
- describe '#inspect' do
368
- before { add_words container, %w(a few words hello hell) }
369
-
370
- it 'returns the container class name plus the root inspection' do
371
- expect(container.inspect).to eq one_line <<~CONTAINER
372
- #<Rambling::Trie::Container root: #<Rambling::Trie::Nodes::Raw letter: nil,
373
- terminal: nil,
374
- children: [:a, :f, :w, :h]>>
375
- CONTAINER
376
- end
377
- end
378
-
379
- describe 'delegates and aliases' do
380
- before do
381
- allow(root).to receive_messages(
382
- :[] => nil,
383
- add: nil,
384
- as_word: nil,
385
- children: nil,
386
- children_tree: nil,
387
- compressed?: nil,
388
- each: nil,
389
- key?: nil,
390
- inspect: nil,
391
- letter: nil,
392
- parent: nil,
393
- partial_word?: nil,
394
- scan: nil,
395
- size: nil,
396
- to_s: nil,
397
- word?: nil,
398
- )
399
- end
400
-
401
- it 'aliases `#include?` to `#word?`' do
402
- container.include? 'words'
403
- expect(root).to have_received(:word?).with %w(w o r d s)
404
- end
405
-
406
- it 'aliases `#match?` to `#partial_word?`' do
407
- container.match? 'words'
408
- expect(root).to have_received(:partial_word?).with %w(w o r d s)
409
- end
410
-
411
- it 'aliases `#words` to `#scan`' do
412
- container.words 'hig'
413
- expect(root).to have_received(:scan).with %w(h i g)
414
- end
415
-
416
- it 'aliases `#<<` to `#add`' do
417
- container << 'words'
418
- expect(root).to have_received(:add).with %i(s d r o w)
419
- end
420
-
421
- it 'delegates `#[]` to the root node' do
422
- container[:yep]
423
- expect(root).to have_received(:[]).with :yep
424
- end
425
-
426
- it 'delegates `#children` to the root node' do
427
- container.children
428
- expect(root).to have_received :children
429
- end
430
-
431
- it 'delegates `#children_tree` to the root node' do
432
- container.children_tree
433
- expect(root).to have_received :children_tree
434
- end
435
-
436
- it 'delegates `#compressed?` to the root node' do
437
- container.compressed?
438
- expect(root).to have_received :compressed?
439
- end
440
-
441
- it 'delegates `#key?` to the root node' do
442
- container.key? :yup
443
- expect(root).to have_received(:key?).with :yup
444
- end
445
-
446
- it 'aliases `#has_key?` to `#key?`' do
447
- container.has_key? :yup
448
- expect(root).to have_received(:key?).with :yup
449
- end
450
-
451
- it 'aliases `#has_letter?` to `#has_key?`' do
452
- container.has_letter? :yup
453
- expect(root).to have_received(:key?).with :yup
454
- end
455
-
456
- it 'delegates `#inspect` to the root node' do
457
- container.inspect
458
- expect(root).to have_received :inspect
459
- end
460
-
461
- it 'delegates `#size` to the root node' do
462
- container.size
463
- expect(root).to have_received :size
464
- end
465
- end
466
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- module Rambling
6
- module Trie
7
- describe Enumerable do
8
- let(:node) { Rambling::Trie::Nodes::Raw.new }
9
- let(:words) { %w(add some words and another word) }
10
-
11
- before { add_words node, words }
12
-
13
- describe '#each' do
14
- it 'returns an enumerator when no block is given' do
15
- expect(node.each).to be_an Enumerator
16
- end
17
-
18
- it 'has the same word count as the trie' do
19
- expect(node.count).to eq words.count
20
- end
21
-
22
- it 'includes every word contained in the trie' do
23
- node.each { |word| expect(words).to include word }
24
- end
25
-
26
- it 'returns the enumerable when a block is given' do
27
- expect(node.each { |_| }).to eq node
28
- end
29
- end
30
-
31
- describe '#size' do
32
- it 'delegates to #count' do
33
- expect(node.size).to eq words.size
34
- end
35
- end
36
-
37
- it 'includes #all? from the core Enumerable module' do
38
- expect(node.all? { |word| words.include? word }).to be true
39
- end
40
-
41
- it 'includes #any? from the core Enumerable module' do
42
- expect(node.any? { |word| word.start_with? 's' }).to be true
43
- end
44
-
45
- it 'includes #to_a from the core Enumerable module' do
46
- expect(node.to_a).to match_array words
47
- end
48
- end
49
- end
50
- end
@@ -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