rambling-trie 2.4.0 → 2.5.0

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 (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