rambling-trie 2.3.0 → 2.4.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.
- checksums.yaml +4 -4
- data/Gemfile +6 -0
- data/LICENSE +1 -1
- data/README.md +68 -29
- data/lib/rambling/trie/comparable.rb +2 -3
- data/lib/rambling/trie/compressible.rb +3 -5
- data/lib/rambling/trie/compressor.rb +2 -12
- data/lib/rambling/trie/configuration/properties.rb +8 -14
- data/lib/rambling/trie/configuration/provider_collection.rb +19 -27
- data/lib/rambling/trie/container.rb +28 -42
- data/lib/rambling/trie/enumerable.rb +4 -2
- data/lib/rambling/trie/nodes/compressed.rb +4 -5
- data/lib/rambling/trie/nodes/missing.rb +1 -2
- data/lib/rambling/trie/nodes/node.rb +21 -34
- data/lib/rambling/trie/nodes/raw.rb +2 -2
- data/lib/rambling/trie/readers/plain_text.rb +10 -6
- data/lib/rambling/trie/readers/reader.rb +19 -0
- data/lib/rambling/trie/readers.rb +1 -1
- data/lib/rambling/trie/serializers/file.rb +1 -1
- data/lib/rambling/trie/serializers/marshal.rb +12 -20
- data/lib/rambling/trie/serializers/serializer.rb +27 -0
- data/lib/rambling/trie/serializers/yaml.rb +10 -16
- data/lib/rambling/trie/serializers/zip.rb +9 -5
- data/lib/rambling/trie/serializers.rb +1 -1
- data/lib/rambling/trie/stringifyable.rb +1 -1
- data/lib/rambling/trie/version.rb +1 -1
- data/lib/rambling/trie.rb +19 -22
- data/rambling-trie.gemspec +9 -5
- data/spec/integration/rambling/trie_spec.rb +49 -20
- data/spec/lib/rambling/trie/comparable_spec.rb +29 -39
- data/spec/lib/rambling/trie/compressor_spec.rb +17 -14
- data/spec/lib/rambling/trie/configuration/properties_spec.rb +25 -7
- data/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +44 -16
- data/spec/lib/rambling/trie/container_spec.rb +202 -327
- data/spec/lib/rambling/trie/enumerable_spec.rb +18 -10
- data/spec/lib/rambling/trie/inspectable_spec.rb +9 -3
- data/spec/lib/rambling/trie/nodes/compressed_spec.rb +6 -0
- data/spec/lib/rambling/trie/nodes/node_spec.rb +1 -1
- data/spec/lib/rambling/trie/nodes/raw_spec.rb +32 -27
- data/spec/lib/rambling/trie/readers/plain_text_spec.rb +11 -1
- data/spec/lib/rambling/trie/readers/reader_spec.rb +14 -0
- data/spec/lib/rambling/trie/serializers/file_spec.rb +2 -4
- data/spec/lib/rambling/trie/serializers/marshal_spec.rb +2 -4
- data/spec/lib/rambling/trie/serializers/serializer_spec.rb +21 -0
- data/spec/lib/rambling/trie/serializers/yaml_spec.rb +2 -4
- data/spec/lib/rambling/trie/serializers/zip_spec.rb +24 -16
- data/spec/lib/rambling/trie/stringifyable_spec.rb +17 -13
- data/spec/lib/rambling/trie_spec.rb +107 -45
- data/spec/spec_helper.rb +16 -9
- data/spec/support/shared_examples/a_compressible_trie.rb +9 -3
- data/spec/support/shared_examples/a_container_partial_word.rb +17 -0
- data/spec/support/shared_examples/a_container_scan.rb +14 -0
- data/spec/support/shared_examples/a_container_word.rb +43 -0
- data/spec/support/shared_examples/a_container_words_within.rb +44 -0
- data/spec/support/shared_examples/a_serializable_trie.rb +5 -9
- data/spec/support/shared_examples/a_serializer.rb +37 -14
- data/spec/support/shared_examples/a_trie_data_structure.rb +24 -10
- data/spec/support/shared_examples/a_trie_node.rb +22 -14
- data/spec/support/shared_examples/a_trie_node_implementation.rb +40 -43
- metadata +25 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25c794ace94646da9b2892ea80c8df575cb3c95fc870790df2b50edde7fbb91e
|
4
|
+
data.tar.gz: e2be8d009e65109b52a1f36f524701b2d9452855aeceb8870e02fe7db52b150f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
data/README.md
CHANGED
@@ -1,8 +1,19 @@
|
|
1
1
|
# Rambling Trie
|
2
2
|
|
3
|
-
[![Gem Version][badge_fury_badge]][badge_fury_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
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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,
|
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
|
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
|
-
|
178
|
-
|
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
|
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
|
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
|
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
|
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-
|
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
|
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
|
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
|
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
|
-
[
|
282
|
-
[
|
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
|
-
[
|
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]
|
10
|
-
# {Nodes::Node#children_tree #children_tree} are equal,
|
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
|
-
#
|
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
|
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
|
23
|
-
#
|
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
|
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 [
|
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 [
|
19
|
-
# @raise [ArgumentError] when the given provider is not in the
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
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 [
|
28
|
-
# @param [Hash] providers the configured providers.
|
29
|
-
# @param [
|
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
|
-
#
|
41
|
-
# @
|
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 [
|
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 [
|
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 [
|
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.
|
45
|
-
# the trie as compressed.
|
46
|
-
# compressed.
|
47
|
-
# @return [
|
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
|
-
#
|
57
|
-
#
|
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]
|
68
|
-
#
|
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]
|
78
|
-
#
|
79
|
-
# @see Nodes::
|
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
|
-
#
|
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]
|
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]
|
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 [
|
155
|
-
#
|
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
|
-
#
|
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
|