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