rambling-trie 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -0
  3. data/LICENSE +1 -1
  4. data/README.md +68 -29
  5. data/lib/rambling/trie/comparable.rb +2 -3
  6. data/lib/rambling/trie/compressible.rb +3 -5
  7. data/lib/rambling/trie/compressor.rb +2 -12
  8. data/lib/rambling/trie/configuration/properties.rb +8 -14
  9. data/lib/rambling/trie/configuration/provider_collection.rb +19 -27
  10. data/lib/rambling/trie/container.rb +28 -42
  11. data/lib/rambling/trie/enumerable.rb +4 -2
  12. data/lib/rambling/trie/nodes/compressed.rb +4 -5
  13. data/lib/rambling/trie/nodes/missing.rb +1 -2
  14. data/lib/rambling/trie/nodes/node.rb +21 -34
  15. data/lib/rambling/trie/nodes/raw.rb +2 -2
  16. data/lib/rambling/trie/readers/plain_text.rb +10 -6
  17. data/lib/rambling/trie/readers/reader.rb +19 -0
  18. data/lib/rambling/trie/readers.rb +1 -1
  19. data/lib/rambling/trie/serializers/file.rb +1 -1
  20. data/lib/rambling/trie/serializers/marshal.rb +12 -20
  21. data/lib/rambling/trie/serializers/serializer.rb +27 -0
  22. data/lib/rambling/trie/serializers/yaml.rb +10 -16
  23. data/lib/rambling/trie/serializers/zip.rb +9 -5
  24. data/lib/rambling/trie/serializers.rb +1 -1
  25. data/lib/rambling/trie/stringifyable.rb +1 -1
  26. data/lib/rambling/trie/version.rb +1 -1
  27. data/lib/rambling/trie.rb +19 -22
  28. data/rambling-trie.gemspec +9 -5
  29. data/spec/integration/rambling/trie_spec.rb +49 -20
  30. data/spec/lib/rambling/trie/comparable_spec.rb +29 -39
  31. data/spec/lib/rambling/trie/compressor_spec.rb +17 -14
  32. data/spec/lib/rambling/trie/configuration/properties_spec.rb +25 -7
  33. data/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +44 -16
  34. data/spec/lib/rambling/trie/container_spec.rb +202 -327
  35. data/spec/lib/rambling/trie/enumerable_spec.rb +18 -10
  36. data/spec/lib/rambling/trie/inspectable_spec.rb +9 -3
  37. data/spec/lib/rambling/trie/nodes/compressed_spec.rb +6 -0
  38. data/spec/lib/rambling/trie/nodes/node_spec.rb +1 -1
  39. data/spec/lib/rambling/trie/nodes/raw_spec.rb +32 -27
  40. data/spec/lib/rambling/trie/readers/plain_text_spec.rb +11 -1
  41. data/spec/lib/rambling/trie/readers/reader_spec.rb +14 -0
  42. data/spec/lib/rambling/trie/serializers/file_spec.rb +2 -4
  43. data/spec/lib/rambling/trie/serializers/marshal_spec.rb +2 -4
  44. data/spec/lib/rambling/trie/serializers/serializer_spec.rb +21 -0
  45. data/spec/lib/rambling/trie/serializers/yaml_spec.rb +2 -4
  46. data/spec/lib/rambling/trie/serializers/zip_spec.rb +24 -16
  47. data/spec/lib/rambling/trie/stringifyable_spec.rb +17 -13
  48. data/spec/lib/rambling/trie_spec.rb +107 -45
  49. data/spec/spec_helper.rb +16 -9
  50. data/spec/support/shared_examples/a_compressible_trie.rb +9 -3
  51. data/spec/support/shared_examples/a_container_partial_word.rb +17 -0
  52. data/spec/support/shared_examples/a_container_scan.rb +14 -0
  53. data/spec/support/shared_examples/a_container_word.rb +43 -0
  54. data/spec/support/shared_examples/a_container_words_within.rb +44 -0
  55. data/spec/support/shared_examples/a_serializable_trie.rb +5 -9
  56. data/spec/support/shared_examples/a_serializer.rb +37 -14
  57. data/spec/support/shared_examples/a_trie_data_structure.rb +24 -10
  58. data/spec/support/shared_examples/a_trie_node.rb +22 -14
  59. data/spec/support/shared_examples/a_trie_node_implementation.rb +40 -43
  60. metadata +25 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7acf86172aa12a848c9590aa0ec0aee132b70f30bf15b720d95e7bc675a8d13
4
- data.tar.gz: 8c08f7abfee53e44d9599160397a21b3e8a9e597125ce52feedbc98f4ad65e62
3
+ metadata.gz: 25c794ace94646da9b2892ea80c8df575cb3c95fc870790df2b50edde7fbb91e
4
+ data.tar.gz: e2be8d009e65109b52a1f36f524701b2d9452855aeceb8870e02fe7db52b150f
5
5
  SHA512:
6
- metadata.gz: c697d039484c41aa733eae791f16b4f82e3b7c6048b006ba64281794834ec54cf5b00f555b3bac196df5589d8dbf779f06fa887a659bb9ee61f822bee7fbdee5
7
- data.tar.gz: fcd664c6802aaf8565820a43f52db146b97e010be2c3a2c64c477a4f6643da02fdbe8238678780d9630f9e6877a8772200af7e4c6e0fb0f16bb9028b382d6099
6
+ metadata.gz: cc61981cb9a93450b0f6159adb497f30de7fa7a7ddf98c69a3baa64ed9cd8757aa035d3f818b080822714b2b5505ed5cefbff7217ce952856630bacab2dc3afd
7
+ data.tar.gz: 1afc2883a31ee9bbf63172c20d806ed952d40bc65527f582308fbe61b8c83dddc3aa3b3ab1b300ded46bf7dbd2f6e73340d22019de4ca82e0587a81bb789725c
data/Gemfile CHANGED
@@ -17,10 +17,16 @@ end
17
17
 
18
18
  group :test do
19
19
  gem 'coveralls_reborn', '~> 0.27.0', require: false
20
+ gem 'rspec_junit_formatter'
20
21
  gem 'simplecov', require: false
21
22
  end
22
23
 
23
24
  group :local do
25
+ gem 'flog', require: false
24
26
  gem 'guard-rspec'
27
+ gem 'mdl', require: false
25
28
  gem 'rubocop', require: false
29
+ gem 'rubocop-performance', require: false
30
+ gem 'rubocop-rake', require: false
31
+ gem 'rubocop-rspec', require: false
26
32
  end
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-2017 Edgar Gonzalez
1
+ Copyright (c) 2012-2024 Edgar González
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,8 +1,19 @@
1
1
  # Rambling Trie
2
2
 
3
- [![Gem Version][badge_fury_badge]][badge_fury_link] [![Build Status][travis_ci_badge]][travis_ci_link] [![Code Climate][code_climate_badge]][code_climage_link] [![Coverage Status][coveralls_badge]][coveralls_link] [![Documentation Status][inch_ci_badge]][inch_ci_link] [![License][license_badge]][license_link]
3
+ [![Gem Version][badge_fury_badge]][badge_fury_link]
4
+ [![Downloads][downloads_badge]][downloads_link]
5
+ [![License][license_badge]][license_link]
4
6
 
5
- The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wiki], which includes compression abilities and is designed to be very fast to traverse.
7
+ [![Build Status][github_action_build_badge]][github_action_build_link]
8
+ [![Coverage Status][coveralls_badge]][coveralls_link]
9
+ [![Documentation Status][inch_ci_badge]][rubydoc]
10
+ [![CodeQL Status][github_action_codeql_badge]][github_action_codeql_link]
11
+
12
+ [![Code Climate Grade][code_climate_grade_badge]][code_climate_link]
13
+ [![Code Climate Issue Count][code_climate_issues_badge]][code_climate_link]
14
+
15
+ The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wiki], which includes compression abilities
16
+ and is designed to be very fast to traverse.
6
17
 
7
18
  ## Installing the Rambling Trie
8
19
 
@@ -47,7 +58,8 @@ Rambling::Trie.create do |trie|
47
58
  end
48
59
  ```
49
60
 
50
- Additionally, you can provide the path to a file that contains all the words to be added to the trie, and it will read the file and create the complete structure for you, like this:
61
+ Additionally, you can provide the path to a file that contains all the words to be added to the trie, and it will read
62
+ the file and create the complete structure for you, like this:
51
63
 
52
64
  ``` ruby
53
65
  trie = Rambling::Trie.create '/path/to/file'
@@ -64,7 +76,10 @@ the
64
76
  trie
65
77
  ```
66
78
 
67
- If you want to use a custom file format, you will need to provide a custom file reader that defines an `#each_word` method that yields each word contained in the file. Look at the [`PlainText` reader][rambling_trie_plain_text_reader] class for an example, and at the [Configuration section][rambling_trie_configuration] to see how to add your own custom file readers.
79
+ If you want to use a custom file format, you will need to provide a custom `Reader` that defines an `#each_word` method
80
+ that yields each word contained in the file. Look at the [`PlainText` reader][rambling_trie_plain_text_reader] class for
81
+ an example, and at the [Configuration section][rambling_trie_configuration] to see how to add your own custom file
82
+ readers.
68
83
 
69
84
  ### Operations
70
85
 
@@ -88,7 +103,8 @@ trie.word? 'word'
88
103
  trie.include? 'word'
89
104
  ```
90
105
 
91
- If you wish to find if part of a word exists in the trie instance, you should call `#partial_word?` or its alias `#match?`:
106
+ If you wish to find if part of a word exists in the trie instance, you should call `#partial_word?` or its
107
+ alias `#match?`:
92
108
 
93
109
  ``` ruby
94
110
  trie.partial_word? 'partial_word'
@@ -109,7 +125,8 @@ trie.words_within 'ifdxawesome45someword3' # => ['if', 'aw', 'awe', ...]
109
125
  trie.words_within 'tktktktk' # => []
110
126
  ```
111
127
 
112
- Or, if you're just interested in knowing whether a given string contains any valid words or not, you can use `#words_within?`:
128
+ Or, if you're just interested in knowing whether a given string contains any valid words or not, you can
129
+ use `#words_within?`:
113
130
 
114
131
  ``` ruby
115
132
  trie.words_within? 'ifdxawesome45someword3' # => true
@@ -118,13 +135,15 @@ trie.words_within? 'tktktktk' # => false
118
135
 
119
136
  ### Compression
120
137
 
121
- By default, the Rambling Trie works as a standard trie. Starting from version 0.1.0, you can obtain a compressed trie from the standard one, by using the compression feature. Just call the `#compress!` method on the trie instance:
138
+ By default, the Rambling Trie works as a standard trie. Starting from version 0.1.0, you can obtain a compressed trie
139
+ from the standard one, by using the compression feature. Just call the `#compress!` method on the trie instance:
122
140
 
123
141
  ``` ruby
124
142
  trie.compress!
125
143
  ```
126
144
 
127
- This will reduce the size of the trie by using redundant node elimination (redundant nodes are the only-child non-terminal nodes).
145
+ This will reduce the size of the trie by using redundant node elimination (redundant nodes are the only-child
146
+ non-terminal nodes).
128
147
 
129
148
  > _**Note**: The `#compress!` method acts over the trie instance it belongs to
130
149
  > and replaces the root `Node`. Also, adding words after compression (with `#add` or
@@ -145,7 +164,8 @@ compressed_trie.compressed? # => true
145
164
 
146
165
  ### Enumeration
147
166
 
148
- Starting from version 0.4.2, you can use any `Enumerable` method over a trie instance, and it will iterate over each word contained in the trie. You can now do things like:
167
+ Starting from version 0.4.2, you can use any `Enumerable` method over a trie instance, and it will iterate over each
168
+ word contained in the trie. You can now do things like:
149
169
 
150
170
  ``` ruby
151
171
  trie.each { |word| puts word }
@@ -156,7 +176,10 @@ trie.all? { |word| word.include? 'x' }
156
176
 
157
177
  ### Serialization
158
178
 
159
- Starting from version 1.0.0, you can store a full trie instance on disk and retrieve/use it later on. Loading a trie from disk takes less time, less cpu and less memory than loading every word into the trie every time. This is particularly useful for production applications, when you have word lists that you know are going to be static, or that change with little frequency.
179
+ Starting from version 1.0.0, you can store a full trie instance on disk and retrieve/use it later on. Loading a trie
180
+ from disk takes less time, less cpu and less memory than loading every word into the trie every time. This is
181
+ particularly useful for production applications, when you have word lists that you know are going to be static, or that
182
+ change with little frequency.
160
183
 
161
184
  To store a trie on disk, you can use `.dump` like this:
162
185
 
@@ -164,24 +187,26 @@ To store a trie on disk, you can use `.dump` like this:
164
187
  Rambling::Trie.dump trie, '/path/to/file'
165
188
  ```
166
189
 
167
- Then, when you need to use a trie next time, you don't have to create a new one with all the necessary words. Rather, you can retrieve a previously stored one with `.load` like this:
190
+ Then, when you need to use a trie next time, you don't have to create a new one with all the necessary words. Rather,
191
+ you can retrieve a previously stored one with `.load` like this:
168
192
 
169
193
  ``` ruby
170
- trie = Rambling::Trie.load trie, '/path/to/file'
194
+ trie = Rambling::Trie.load '/path/to/file'
171
195
  ```
172
196
 
173
197
  #### Supported formats
174
198
 
175
199
  Currently, these formats are supported to store tries on disk:
176
200
 
177
- - Ruby's [binary (Marshal)][marshal] format
178
- - [YAML][yaml]
201
+ * Ruby's [binary (Marshal)][marshal] format
202
+ * [YAML][yaml]
179
203
 
180
204
  > When dumping into or loading from disk, the format is determined
181
205
  > automatically based on the file extension, so `.yml` or `.yaml` files will be
182
206
  > handled through `YAML` and `.marshal` files through `Marshal`.
183
207
 
184
- Optionally, you can use a `.zip` version of the supported formats. In order to do so, you'll have to install the [`rubyzip`][rubyzip] gem:
208
+ Optionally, you can use a `.zip` version of the supported formats. In order to do so, you'll have to install
209
+ the [`rubyzip`][rubyzip] gem:
185
210
 
186
211
  ``` bash
187
212
  gem install rubyzip
@@ -197,7 +222,7 @@ Then, you can load contents form a `.zip` file like this:
197
222
 
198
223
  ``` ruby
199
224
  require 'zip'
200
- trie = Rambling::Trie.load trie, '/path/to/file.zip'
225
+ trie = Rambling::Trie.load '/path/to/file.zip'
201
226
  ```
202
227
 
203
228
  > For `.zip` files, the format is also determined automatically based on the
@@ -236,12 +261,14 @@ end
236
261
 
237
262
  ### Further Documentation
238
263
 
239
- You can find further API documentation on the autogenerated [rambling-trie gem RubyDoc.info page][rubydoc] or if you want edge documentation, you can go the [GitHub project RubyDoc.info page][rubydoc_github].
264
+ You can find further API documentation on the autogenerated [rambling-trie gem RubyDoc.info page][rubydoc] or if you
265
+ want edge documentation, you can go the [GitHub project RubyDoc.info page][rubydoc_github].
240
266
 
241
267
  ## Compatible Ruby and Rails versions
242
268
 
243
269
  The Rambling Trie has been tested with the following Ruby versions:
244
270
 
271
+ * 3.3.x
245
272
  * 3.2.x
246
273
  * 3.1.x
247
274
  * 3.0.x
@@ -261,33 +288,47 @@ The Rambling Trie has been tested with the following Ruby versions:
261
288
 
262
289
  ## Contributing to Rambling Trie
263
290
 
264
- Take a look at the [contributing guide][rambling_trie_contributing_guide] to get started, or fire a question to [@gonzedge][github_user_gonzedge].
291
+ Take a look at the [contributing guide][rambling_trie_contributing_guide] to get started, or fire a question
292
+ to [@gonzedge][github_user_gonzedge].
265
293
 
266
294
  ## License and copyright
267
295
 
268
- Copyright (c) 2012-2017 Edgar Gonzalez
296
+ Copyright (c) 2012-2024 Edgar González
269
297
 
270
298
  MIT License
271
299
 
272
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
300
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
301
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
302
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
303
+ persons to whom the Software is furnished to do so, subject to the following conditions:
273
304
 
274
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
305
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
306
+ Software.
275
307
 
276
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
308
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
309
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
310
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
311
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
277
312
 
278
- [badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg
313
+ [badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.4.0
279
314
  [badge_fury_link]: https://badge.fury.io/rb/rambling-trie
280
315
  [chruby]: https://github.com/postmodern/chruby
281
- [code_climage_link]: https://codeclimate.com/github/gonzedge/rambling-trie
282
- [code_climate_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/gpa.svg
316
+ [code_climate_grade_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/gpa.svg
317
+ [code_climate_issues_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/issue_count.svg
318
+ [code_climate_link]: https://codeclimate.com/github/gonzedge/rambling-trie
283
319
  [coveralls_badge]: https://img.shields.io/coveralls/gonzedge/rambling-trie.svg
284
320
  [coveralls_link]: https://coveralls.io/r/gonzedge/rambling-trie
321
+ [downloads_badge]: https://img.shields.io/gem/dt/rambling-trie.svg
322
+ [downloads_link]: https://rubygems.org/gems/rambling-trie
285
323
  [gemnasium_badge]: https://gemnasium.com/gonzedge/rambling-trie.svg
286
324
  [gemnasium_link]: https://gemnasium.com/gonzedge/rambling-trie
325
+ [github_action_build_badge]: https://github.com/gonzedge/rambling-trie/actions/workflows/ruby.yml/badge.svg
326
+ [github_action_build_link]: https://github.com/gonzedge/rambling-trie/actions/workflows/ruby.yml
327
+ [github_action_codeql_badge]: https://github.com/gonzedge/rambling-trie/actions/workflows/codeql.yml/badge.svg
328
+ [github_action_codeql_link]: https://github.com/gonzedge/rambling-trie/actions/workflows/codeql.yml
287
329
  [github_user_gonzedge]: https://github.com/gonzedge
288
330
  [inch_ci_badge]: https://inch-ci.org/github/gonzedge/rambling-trie.svg?branch=master
289
- [inch_ci_link]: https://inch-ci.org/github/gonzedge/rambling-trie
290
- [license_badge]: https://badges.frapsoft.com/os/mit/mit.svg?v=103
331
+ [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg
291
332
  [license_link]: https://opensource.org/licenses/mit-license.php
292
333
  [marshal]: https://ruby-doc.org/core-2.7.0/Marshal.html
293
334
  [rambling_trie_configuration]: https://github.com/gonzedge/rambling-trie#configuration
@@ -298,7 +339,5 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
298
339
  [rubydoc_github]: http://rubydoc.info/github/gonzedge/rambling-trie
299
340
  [rubyzip]: https://github.com/rubyzip/rubyzip
300
341
  [rvm]: https://rvm.io
301
- [travis_ci_badge]: https://travis-ci.com/gonzedge/rambling-trie.svg?branch=master
302
- [travis_ci_link]: https://travis-ci.com/github/gonzedge/rambling-trie
303
342
  [trie_wiki]: https://en.wikipedia.org/wiki/Trie
304
343
  [yaml]: https://ruby-doc.org/stdlib-2.7.0/libdoc/yaml/rdoc/YAML.html
@@ -6,9 +6,8 @@ module Rambling
6
6
  module Comparable
7
7
  # Compares two nodes.
8
8
  # @param [Nodes::Node] other the node to compare against.
9
- # @return [Boolean] `true` if the nodes' {Nodes::Node#letter #letter} and
10
- # {Nodes::Node#children_tree #children_tree} are equal, `false`
11
- # otherwise.
9
+ # @return [Boolean] +true+ if the nodes' {Nodes::Node#letter #letter} and
10
+ # {Nodes::Node#children_tree #children_tree} are equal, +false+ otherwise.
12
11
  def == other
13
12
  letter == other.letter &&
14
13
  terminal? == other.terminal? &&
@@ -4,12 +4,10 @@ module Rambling
4
4
  module Trie
5
5
  # Provides the compressible behavior for the trie data structure.
6
6
  module Compressible
7
- # Indicates if the current {Rambling::Trie::Nodes::Node Node} can be
8
- # compressed or not.
9
- # @return [Boolean] `true` for non-{Nodes::Node#terminal? terminal} nodes
10
- # with one child, `false` otherwise.
7
+ # Indicates if the current {Rambling::Trie::Nodes::Node Node} can be compressed or not.
8
+ # @return [Boolean] +true+ for non-{Nodes::Node#terminal? terminal} nodes with one child, +false+ otherwise.
11
9
  def compressible?
12
- !(root? || terminal?) && children_tree.size == 1
10
+ !(root? || terminal?) && 1 == children_tree.size
13
11
  end
14
12
  end
15
13
  end
@@ -24,21 +24,11 @@ module Rambling
24
24
  def merge node, other
25
25
  letter = node.letter.to_s << other.letter.to_s
26
26
 
27
- new_compressed_node(
28
- letter.to_sym,
29
- node.parent,
30
- other.children_tree,
31
- other.terminal?,
32
- )
27
+ new_compressed_node letter.to_sym, node.parent, other.children_tree, other.terminal?
33
28
  end
34
29
 
35
30
  def compress_children_and_copy node
36
- new_compressed_node(
37
- node.letter,
38
- node.parent,
39
- compress_children(node.children_tree),
40
- node.terminal?,
41
- )
31
+ new_compressed_node node.letter, node.parent, compress_children(node.children_tree), node.terminal?
42
32
  end
43
33
 
44
34
  def compress_children tree
@@ -6,26 +6,23 @@ module Rambling
6
6
  # Provides configurable properties for Rambling::Trie.
7
7
  class Properties
8
8
  # The configured {Readers Readers}.
9
- # @return [ProviderCollection] the mapping of configured {Readers
10
- # Readers}.
9
+ # @return [ProviderCollection<Readers::Reader>] the mapping of configured {Readers Readers}.
11
10
  attr_reader :readers
12
11
 
13
12
  # The configured {Serializers Serializers}.
14
- # @return [ProviderCollection] the mapping of configured {Serializers
15
- # Serializers}.
13
+ # @return [ProviderCollection<Serializers::Serializer>] the mapping of configured {Serializers Serializers}.
16
14
  attr_reader :serializers
17
15
 
18
16
  # The configured {Compressor Compressor}.
19
17
  # @return [Compressor] the configured compressor.
20
18
  attr_accessor :compressor
21
19
 
22
- # The configured root_builder, which should return a {Nodes::Node Node}
23
- # when called.
24
- # @return [Proc<Nodes::Node>] the configured root_builder.
20
+ # The configured +root_builder+, which returns a {Nodes::Node Node} when called.
21
+ # @return [Proc<Nodes::Node>] the configured +root_builder+.
25
22
  attr_accessor :root_builder
26
23
 
27
- # The configured tmp_path, which will be used for throwaway files.
28
- # @return [String] the configured tmp_path.
24
+ # The configured +tmp_path+, which will be used for throwaway files.
25
+ # @return [String] the configured +tmp_path+.
29
26
  attr_accessor :tmp_path
30
27
 
31
28
  # Returns a new properties instance.
@@ -34,6 +31,7 @@ module Rambling
34
31
  end
35
32
 
36
33
  # Resets back to default properties.
34
+ # @return [void]
37
35
  def reset
38
36
  reset_readers
39
37
  reset_serializers
@@ -49,11 +47,7 @@ module Rambling
49
47
 
50
48
  def reset_readers
51
49
  plain_text_reader = Rambling::Trie::Readers::PlainText.new
52
-
53
- @readers = Rambling::Trie::Configuration::ProviderCollection.new(
54
- :reader,
55
- txt: plain_text_reader,
56
- )
50
+ @readers = Rambling::Trie::Configuration::ProviderCollection.new :reader, txt: plain_text_reader
57
51
  end
58
52
 
59
53
  def reset_serializers
@@ -6,7 +6,7 @@ module Rambling
6
6
  # Collection of configurable providers.
7
7
  class ProviderCollection
8
8
  # The name of this provider collection.
9
- # @return [String] the name of this provider collection.
9
+ # @return [Symbol] the name of this provider collection.
10
10
  attr_reader :name
11
11
 
12
12
  # @overload default
@@ -15,18 +15,17 @@ module Rambling
15
15
  # @overload default=(provider)
16
16
  # Sets the default provider. Needs to be one of the configured
17
17
  # providers.
18
- # @param [Object] provider the provider to use as default.
19
- # @raise [ArgumentError] when the given provider is not in the
20
- # provider collection.
21
- # @note If no providers have been configured, `nil` will be assigned.
22
- # @return [Object, nil] the default provider to use when a provider
23
- # cannot be resolved in {ProviderCollection#resolve #resolve}.
18
+ # @param [TProvider] provider the provider to use as default.
19
+ # @raise [ArgumentError] when the given provider is not in the provider collection.
20
+ # @note If no providers have been configured, +nil+ will be assigned.
21
+ # @return [TProvider, nil] the default provider to use when a provider cannot be resolved in
22
+ # {ProviderCollection#resolve #resolve}.
24
23
  attr_reader :default
25
24
 
26
25
  # Creates a new provider collection.
27
- # @param [String] name the name for this provider collection.
28
- # @param [Hash] providers the configured providers.
29
- # @param [Object] default the configured default provider.
26
+ # @param [Symbol] name the name for this provider collection.
27
+ # @param [Hash<Symbol, TProvider>] providers the configured providers.
28
+ # @param [TProvider, nil] default the configured default provider.
30
29
  def initialize name, providers = {}, default = nil
31
30
  @name = name
32
31
  @configured_providers = providers
@@ -36,39 +35,34 @@ module Rambling
36
35
  end
37
36
 
38
37
  # Adds a new provider to the provider collection.
39
- # @param [Symbol] extension the extension that the provider will
40
- # correspond to.
41
- # @param [provider] provider the provider to add to the provider
42
- # collection.
38
+ # @param [Symbol] extension the extension that the provider will correspond to.
39
+ # @param [TProvider] provider the provider to add to the provider collection.
40
+ # @return [TProvider] the provider just added.
43
41
  def add extension, provider
44
42
  providers[extension] = provider
45
43
  end
46
44
 
47
45
  def default= provider
48
- unless contains? provider
49
- raise ArgumentError,
50
- "default #{name} should be part of configured #{name}s"
51
- end
46
+ raise ArgumentError, "default #{name} should be part of configured #{name}s" unless contains? provider
52
47
 
53
48
  @default = provider
54
49
  end
55
50
 
56
51
  # List of configured providers.
57
- # @return [Hash] the mapping of extensions to their corresponding
58
- # providers.
52
+ # @return [Hash<Symbol, TProvider>] the mapping of extensions to their corresponding providers.
59
53
  def providers
60
54
  @providers ||= {}
61
55
  end
62
56
 
63
57
  # Resolves the provider from a filepath based on the file extension.
64
58
  # @param [String] filepath the filepath to resolve into a provider.
65
- # @return [Object] the provider corresponding to the file extension in
66
- # this provider collection. {#default} if not found.
59
+ # @return [TProvider, nil] the provider for the given file's extension. {#default} if not found.
67
60
  def resolve filepath
68
61
  providers[file_format filepath] || default
69
62
  end
70
63
 
71
64
  # Resets the provider collection to the initial values.
65
+ # @return [void]
72
66
  def reset
73
67
  providers.clear
74
68
  configured_providers.each { |k, v| self[k] = v }
@@ -85,9 +79,8 @@ module Rambling
85
79
 
86
80
  # Get provider corresponding to a given format.
87
81
  # @param [Symbol] format the format to search for in the collection.
88
- # @return [Object] the provider corresponding to that format.
89
- # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D
90
- # Hash#[]
82
+ # @return [TProvider] the provider corresponding to that format.
83
+ # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D Hash#[]
91
84
  def [] format
92
85
  providers[format]
93
86
  end
@@ -111,8 +104,7 @@ module Rambling
111
104
  end
112
105
 
113
106
  def contains? provider
114
- provider.nil? ||
115
- (providers.any? && provider_instances.include?(provider))
107
+ provider.nil? || (providers.any? && provider_instances.include?(provider))
116
108
  end
117
109
 
118
110
  alias_method :provider_instances, :values
@@ -13,7 +13,7 @@ module Rambling
13
13
  # Creates a new trie.
14
14
  # @param [Nodes::Node] root the root node for the trie
15
15
  # @param [Compressor] compressor responsible for compressing the trie
16
- # @yield [Container] the trie just created.
16
+ # @yield [self] the trie just initialized.
17
17
  def initialize root, compressor
18
18
  @root = root
19
19
  @compressor = compressor
@@ -41,72 +41,61 @@ module Rambling
41
41
  words.map { |word| add word }
42
42
  end
43
43
 
44
- # Compresses the existing trie using redundant node elimination. Marks
45
- # the trie as compressed. Does nothing if the trie has already been
46
- # compressed.
47
- # @return [Container] self
48
- # @note This method replaces the root {Nodes::Raw Raw} node with a
49
- # {Nodes::Compressed Compressed} version of it.
44
+ # Compresses the existing trie using redundant node elimination.
45
+ # Marks the trie as compressed.
46
+ # Does nothing if the trie has already been compressed.
47
+ # @return [self]
48
+ # @note This method replaces the root {Nodes::Raw Raw} node with a {Nodes::Compressed Compressed} version of it.
50
49
  def compress!
51
50
  self.root = compress_root unless root.compressed?
52
51
  self
53
52
  end
54
53
 
55
- # Compresses the existing trie using redundant node elimination. Returns
56
- # a new trie with the compressed root.
57
- # @return [Container] A new {Container} with the {Nodes::Compressed
58
- # Compressed} root node or self if the trie has already been
59
- # compressed.
54
+ # Compresses the existing trie using redundant node elimination. Returns a new trie with the compressed root.
55
+ # @return [Container] A new {Container} with the {Nodes::Compressed Compressed} root node
56
+ # or self if the trie has already been compressed.
60
57
  def compress
61
58
  return self if root.compressed?
59
+
62
60
  Rambling::Trie::Container.new compress_root, compressor
63
61
  end
64
62
 
65
63
  # Checks if a path for a word or partial word exists in the trie.
66
64
  # @param [String] word the word or partial word to look for in the trie.
67
- # @return [Boolean] `true` if the word or partial word is found, `false`
68
- # otherwise.
69
- # @see Nodes::Raw#partial_word?
70
- # @see Nodes::Compressed#partial_word?
65
+ # @return [Boolean] +true+ if the word or partial word is found, +false+ otherwise.
66
+ # @see Nodes::Node#partial_word?
71
67
  def partial_word? word = ''
72
68
  root.partial_word? word.chars
73
69
  end
74
70
 
75
71
  # Checks if a whole word exists in the trie.
76
72
  # @param [String] word the word to look for in the trie.
77
- # @return [Boolean] `true` only if the word is found and the last
78
- # character corresponds to a terminal node, `false` otherwise.
79
- # @see Nodes::Raw#word?
80
- # @see Nodes::Compressed#word?
73
+ # @return [Boolean] +true+ only if the word is found and the last character corresponds to a terminal node,
74
+ # +false+ otherwise.
75
+ # @see Nodes::Node#word?
81
76
  def word? word = ''
82
77
  root.word? word.chars
83
78
  end
84
79
 
85
80
  # Returns all words that start with the specified characters.
86
81
  # @param [String] word the word to look for in the trie.
87
- # @return [Array<String>] all the words contained in the trie that start
88
- # with the specified characters.
89
- # @see Nodes::Raw#scan
90
- # @see Nodes::Compressed#scan
82
+ # @return [Array<String>] all the words contained in the trie that start with the specified characters.
83
+ # @see Nodes::Node#scan
91
84
  def scan word = ''
92
85
  root.scan(word.chars).to_a
93
86
  end
94
87
 
95
- # Returns all words within a string that match a word contained in the
96
- # trie.
88
+ # Returns all words within a string that match a word contained in the trie.
97
89
  # @param [String] phrase the string to look for matching words in.
98
- # @return [Enumerator<String>] all the words in the given string that
99
- # match a word in the trie.
90
+ # @return [Enumerator<String>] all the words in the given string that match a word in the trie.
100
91
  # @yield [String] each word found in phrase.
101
- # @see Nodes::Node#words_within
102
92
  def words_within phrase
103
93
  words_within_root(phrase).to_a
104
94
  end
105
95
 
106
96
  # Checks if there are any valid words in a given string.
107
97
  # @param [String] phrase the string to look for matching words in.
108
- # @return [Boolean] `true` if any word within phrase is contained in the
109
- # trie, `false` otherwise.
98
+ # @return [Boolean] +true+ if any word within phrase is contained in the trie, +false+ otherwise.
110
99
  # @see Container#words_within
111
100
  def words_within? phrase
112
101
  words_within_root(phrase).any?
@@ -114,13 +103,14 @@ module Rambling
114
103
 
115
104
  # Compares two trie data structures.
116
105
  # @param [Container] other the trie to compare against.
117
- # @return [Boolean] `true` if the tries are equal, `false` otherwise.
106
+ # @return [Boolean] +true+ if the tries are equal, +false+ otherwise.
118
107
  def == other
119
108
  root == other.root
120
109
  end
121
110
 
122
111
  # Iterates over the words contained in the trie.
123
112
  # @yield [String] the words contained in this trie node.
113
+ # @return [self]
124
114
  def each
125
115
  return enum_for :each unless block_given?
126
116
 
@@ -143,33 +133,29 @@ module Rambling
143
133
  end
144
134
 
145
135
  # Root node's child nodes.
146
- # @return [Array<Nodes::Node>] the array of children nodes contained in
147
- # the root node.
136
+ # @return [Array<Nodes::Node>] the array of children nodes contained in the root node.
148
137
  # @see Nodes::Node#children
149
138
  def children
150
139
  root.children
151
140
  end
152
141
 
153
142
  # Root node's children tree.
154
- # @return [Array<Nodes::Node>] the array of children nodes contained in
155
- # the root node.
143
+ # @return [Hash<Symbol, Nodes::Node>] the children tree hash contained in the root node, consisting of
144
+ # +:letter => node+.
156
145
  # @see Nodes::Node#children_tree
157
146
  def children_tree
158
147
  root.children_tree
159
148
  end
160
149
 
161
- # Indicates if the root {Nodes::Node Node} can be
162
- # compressed or not.
163
- # @return [Boolean] `true` for non-{Nodes::Node#terminal? terminal}
164
- # nodes with one child, `false` otherwise.
150
+ # Indicates if the root {Nodes::Node Node} can be compressed or not.
151
+ # @return [Boolean] +true+ for non-{Nodes::Node#terminal? terminal} nodes with one child, +false+ otherwise.
165
152
  def compressed?
166
153
  root.compressed?
167
154
  end
168
155
 
169
156
  # Array of words contained in the root {Nodes::Node Node}.
170
157
  # @return [Array<String>] all words contained in this trie.
171
- # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-to_a
172
- # Enumerable#to_a
158
+ # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-to_a Enumerable#to_a
173
159
  def to_a
174
160
  root.to_a
175
161
  end
@@ -7,12 +7,12 @@ module Rambling
7
7
  include ::Enumerable
8
8
 
9
9
  # Returns number of words contained in the trie
10
- # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-count
11
- # Enumerable#count
10
+ # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-count Enumerable#count
12
11
  alias_method :size, :count
13
12
 
14
13
  # Iterates over the words contained in the trie.
15
14
  # @yield [String] the words contained in this trie node.
15
+ # @return [self]
16
16
  def each
17
17
  return enum_for :each unless block_given?
18
18
 
@@ -23,6 +23,8 @@ module Rambling
23
23
  yield word
24
24
  end
25
25
  end
26
+
27
+ self
26
28
  end
27
29
  end
28
30
  end