rambling-trie 2.3.1 → 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 +2 -0
- data/LICENSE +1 -1
- data/README.md +45 -20
- data/lib/rambling/trie/comparable.rb +1 -2
- data/lib/rambling/trie/compressible.rb +2 -4
- data/lib/rambling/trie/compressor.rb +2 -12
- data/lib/rambling/trie/configuration/properties.rb +4 -11
- data/lib/rambling/trie/configuration/provider_collection.rb +10 -20
- data/lib/rambling/trie/container.rb +20 -32
- data/lib/rambling/trie/enumerable.rb +1 -2
- data/lib/rambling/trie/nodes/compressed.rb +1 -2
- data/lib/rambling/trie/nodes/missing.rb +1 -2
- data/lib/rambling/trie/nodes/node.rb +14 -27
- data/lib/rambling/trie/readers/plain_text.rb +1 -2
- data/lib/rambling/trie/readers/reader.rb +2 -4
- data/lib/rambling/trie/serializers/marshal.rb +10 -19
- data/lib/rambling/trie/serializers/yaml.rb +8 -15
- data/lib/rambling/trie/serializers/zip.rb +1 -1
- data/lib/rambling/trie/version.rb +1 -1
- data/lib/rambling/trie.rb +11 -16
- data/rambling-trie.gemspec +4 -4
- data/spec/integration/rambling/trie_spec.rb +36 -4
- data/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +7 -7
- data/spec/lib/rambling/trie/container_spec.rb +4 -4
- data/spec/lib/rambling/trie/nodes/compressed_spec.rb +6 -0
- data/spec/lib/rambling/trie/nodes/raw_spec.rb +6 -4
- data/spec/lib/rambling/trie/serializers/file_spec.rb +1 -1
- data/spec/lib/rambling/trie/serializers/marshal_spec.rb +1 -1
- data/spec/lib/rambling/trie/serializers/yaml_spec.rb +1 -1
- data/spec/lib/rambling/trie/serializers/zip_spec.rb +4 -4
- data/spec/lib/rambling/trie_spec.rb +11 -11
- data/spec/spec_helper.rb +5 -5
- data/spec/support/shared_examples/a_container_word.rb +3 -3
- data/spec/support/shared_examples/a_serializable_trie.rb +1 -1
- data/spec/support/shared_examples/a_serializer.rb +2 -2
- data/spec/support/shared_examples/a_trie_node.rb +3 -2
- metadata +8 -8
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
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -12,7 +12,8 @@
|
|
12
12
|
[![Code Climate Grade][code_climate_grade_badge]][code_climate_link]
|
13
13
|
[![Code Climate Issue Count][code_climate_issues_badge]][code_climate_link]
|
14
14
|
|
15
|
-
The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wiki], which includes compression abilities
|
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.
|
16
17
|
|
17
18
|
## Installing the Rambling Trie
|
18
19
|
|
@@ -57,7 +58,8 @@ Rambling::Trie.create do |trie|
|
|
57
58
|
end
|
58
59
|
```
|
59
60
|
|
60
|
-
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:
|
61
63
|
|
62
64
|
``` ruby
|
63
65
|
trie = Rambling::Trie.create '/path/to/file'
|
@@ -74,7 +76,10 @@ the
|
|
74
76
|
trie
|
75
77
|
```
|
76
78
|
|
77
|
-
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.
|
78
83
|
|
79
84
|
### Operations
|
80
85
|
|
@@ -98,7 +103,8 @@ trie.word? 'word'
|
|
98
103
|
trie.include? 'word'
|
99
104
|
```
|
100
105
|
|
101
|
-
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?`:
|
102
108
|
|
103
109
|
``` ruby
|
104
110
|
trie.partial_word? 'partial_word'
|
@@ -119,7 +125,8 @@ trie.words_within 'ifdxawesome45someword3' # => ['if', 'aw', 'awe', ...]
|
|
119
125
|
trie.words_within 'tktktktk' # => []
|
120
126
|
```
|
121
127
|
|
122
|
-
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?`:
|
123
130
|
|
124
131
|
``` ruby
|
125
132
|
trie.words_within? 'ifdxawesome45someword3' # => true
|
@@ -128,13 +135,15 @@ trie.words_within? 'tktktktk' # => false
|
|
128
135
|
|
129
136
|
### Compression
|
130
137
|
|
131
|
-
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:
|
132
140
|
|
133
141
|
``` ruby
|
134
142
|
trie.compress!
|
135
143
|
```
|
136
144
|
|
137
|
-
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).
|
138
147
|
|
139
148
|
> _**Note**: The `#compress!` method acts over the trie instance it belongs to
|
140
149
|
> and replaces the root `Node`. Also, adding words after compression (with `#add` or
|
@@ -155,7 +164,8 @@ compressed_trie.compressed? # => true
|
|
155
164
|
|
156
165
|
### Enumeration
|
157
166
|
|
158
|
-
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:
|
159
169
|
|
160
170
|
``` ruby
|
161
171
|
trie.each { |word| puts word }
|
@@ -166,7 +176,10 @@ trie.all? { |word| word.include? 'x' }
|
|
166
176
|
|
167
177
|
### Serialization
|
168
178
|
|
169
|
-
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.
|
170
183
|
|
171
184
|
To store a trie on disk, you can use `.dump` like this:
|
172
185
|
|
@@ -174,7 +187,8 @@ To store a trie on disk, you can use `.dump` like this:
|
|
174
187
|
Rambling::Trie.dump trie, '/path/to/file'
|
175
188
|
```
|
176
189
|
|
177
|
-
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:
|
178
192
|
|
179
193
|
``` ruby
|
180
194
|
trie = Rambling::Trie.load '/path/to/file'
|
@@ -184,14 +198,15 @@ trie = Rambling::Trie.load '/path/to/file'
|
|
184
198
|
|
185
199
|
Currently, these formats are supported to store tries on disk:
|
186
200
|
|
187
|
-
|
188
|
-
|
201
|
+
* Ruby's [binary (Marshal)][marshal] format
|
202
|
+
* [YAML][yaml]
|
189
203
|
|
190
204
|
> When dumping into or loading from disk, the format is determined
|
191
205
|
> automatically based on the file extension, so `.yml` or `.yaml` files will be
|
192
206
|
> handled through `YAML` and `.marshal` files through `Marshal`.
|
193
207
|
|
194
|
-
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:
|
195
210
|
|
196
211
|
``` bash
|
197
212
|
gem install rubyzip
|
@@ -246,12 +261,14 @@ end
|
|
246
261
|
|
247
262
|
### Further Documentation
|
248
263
|
|
249
|
-
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].
|
250
266
|
|
251
267
|
## Compatible Ruby and Rails versions
|
252
268
|
|
253
269
|
The Rambling Trie has been tested with the following Ruby versions:
|
254
270
|
|
271
|
+
* 3.3.x
|
255
272
|
* 3.2.x
|
256
273
|
* 3.1.x
|
257
274
|
* 3.0.x
|
@@ -271,21 +288,29 @@ The Rambling Trie has been tested with the following Ruby versions:
|
|
271
288
|
|
272
289
|
## Contributing to Rambling Trie
|
273
290
|
|
274
|
-
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].
|
275
293
|
|
276
294
|
## License and copyright
|
277
295
|
|
278
|
-
Copyright (c) 2012-
|
296
|
+
Copyright (c) 2012-2024 Edgar González
|
279
297
|
|
280
298
|
MIT License
|
281
299
|
|
282
|
-
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:
|
283
304
|
|
284
|
-
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.
|
285
307
|
|
286
|
-
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.
|
287
312
|
|
288
|
-
[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.
|
313
|
+
[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.4.0
|
289
314
|
[badge_fury_link]: https://badge.fury.io/rb/rambling-trie
|
290
315
|
[chruby]: https://github.com/postmodern/chruby
|
291
316
|
[code_climate_grade_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/gpa.svg
|
@@ -7,8 +7,7 @@ module Rambling
|
|
7
7
|
# Compares two nodes.
|
8
8
|
# @param [Nodes::Node] other the node to compare against.
|
9
9
|
# @return [Boolean] +true+ if the nodes' {Nodes::Node#letter #letter} and
|
10
|
-
# {Nodes::Node#children_tree #children_tree} are equal, +false+
|
11
|
-
# otherwise.
|
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,10 +4,8 @@ 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
10
|
!(root? || terminal?) && 1 == children_tree.size
|
13
11
|
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,21 +6,18 @@ module Rambling
|
|
6
6
|
# Provides configurable properties for Rambling::Trie.
|
7
7
|
class Properties
|
8
8
|
# The configured {Readers Readers}.
|
9
|
-
# @return [ProviderCollection<Readers::Reader>] the mapping of
|
10
|
-
# configured {Readers 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<Serializers::Serializer>] the mapping of
|
15
|
-
# configured {Serializers 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 returns a {Nodes::Node Node}
|
23
|
-
# when called.
|
20
|
+
# The configured +root_builder+, which returns a {Nodes::Node Node} when called.
|
24
21
|
# @return [Proc<Nodes::Node>] the configured +root_builder+.
|
25
22
|
attr_accessor :root_builder
|
26
23
|
|
@@ -50,11 +47,7 @@ module Rambling
|
|
50
47
|
|
51
48
|
def reset_readers
|
52
49
|
plain_text_reader = Rambling::Trie::Readers::PlainText.new
|
53
|
-
|
54
|
-
@readers = Rambling::Trie::Configuration::ProviderCollection.new(
|
55
|
-
:reader,
|
56
|
-
txt: plain_text_reader,
|
57
|
-
)
|
50
|
+
@readers = Rambling::Trie::Configuration::ProviderCollection.new :reader, txt: plain_text_reader
|
58
51
|
end
|
59
52
|
|
60
53
|
def reset_serializers
|
@@ -16,11 +16,10 @@ module Rambling
|
|
16
16
|
# Sets the default provider. Needs to be one of the configured
|
17
17
|
# providers.
|
18
18
|
# @param [TProvider] provider the provider to use as default.
|
19
|
-
# @raise [ArgumentError] when the given provider is not in the
|
20
|
-
# provider collection.
|
19
|
+
# @raise [ArgumentError] when the given provider is not in the provider collection.
|
21
20
|
# @note If no providers have been configured, +nil+ will be assigned.
|
22
|
-
# @return [TProvider, nil] the default provider to use when a provider
|
23
|
-
#
|
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.
|
@@ -36,35 +35,28 @@ 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
|
-
# @param [TProvider] 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.
|
43
40
|
# @return [TProvider] the provider just added.
|
44
41
|
def add extension, provider
|
45
42
|
providers[extension] = provider
|
46
43
|
end
|
47
44
|
|
48
45
|
def default= provider
|
49
|
-
unless contains? provider
|
50
|
-
raise ArgumentError,
|
51
|
-
"default #{name} should be part of configured #{name}s"
|
52
|
-
end
|
46
|
+
raise ArgumentError, "default #{name} should be part of configured #{name}s" unless contains? provider
|
53
47
|
|
54
48
|
@default = provider
|
55
49
|
end
|
56
50
|
|
57
51
|
# List of configured providers.
|
58
|
-
# @return [Hash<Symbol, TProvider>] the mapping of extensions to their
|
59
|
-
# corresponding providers.
|
52
|
+
# @return [Hash<Symbol, TProvider>] the mapping of extensions to their corresponding providers.
|
60
53
|
def providers
|
61
54
|
@providers ||= {}
|
62
55
|
end
|
63
56
|
|
64
57
|
# Resolves the provider from a filepath based on the file extension.
|
65
58
|
# @param [String] filepath the filepath to resolve into a provider.
|
66
|
-
# @return [TProvider, nil] the provider for the given file's extension.
|
67
|
-
# {#default} if not found.
|
59
|
+
# @return [TProvider, nil] the provider for the given file's extension. {#default} if not found.
|
68
60
|
def resolve filepath
|
69
61
|
providers[file_format filepath] || default
|
70
62
|
end
|
@@ -88,8 +80,7 @@ module Rambling
|
|
88
80
|
# Get provider corresponding to a given format.
|
89
81
|
# @param [Symbol] format the format to search for in the collection.
|
90
82
|
# @return [TProvider] the provider corresponding to that format.
|
91
|
-
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D
|
92
|
-
# Hash#[]
|
83
|
+
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D Hash#[]
|
93
84
|
def [] format
|
94
85
|
providers[format]
|
95
86
|
end
|
@@ -113,8 +104,7 @@ module Rambling
|
|
113
104
|
end
|
114
105
|
|
115
106
|
def contains? provider
|
116
|
-
provider.nil? ||
|
117
|
-
(providers.any? && provider_instances.include?(provider))
|
107
|
+
provider.nil? || (providers.any? && provider_instances.include?(provider))
|
118
108
|
end
|
119
109
|
|
120
110
|
alias_method :provider_instances, :values
|
@@ -41,22 +41,19 @@ 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.
|
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
47
|
# @return [self]
|
48
|
-
# @note This method replaces the root {Nodes::Raw Raw} node with a
|
49
|
-
# {Nodes::Compressed Compressed} version of it.
|
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?
|
62
59
|
|
@@ -65,8 +62,7 @@ module Rambling
|
|
65
62
|
|
66
63
|
# Checks if a path for a word or partial word exists in the trie.
|
67
64
|
# @param [String] word the word or partial word to look for in the trie.
|
68
|
-
# @return [Boolean] +true+ if the word or partial word is found, +false+
|
69
|
-
# otherwise.
|
65
|
+
# @return [Boolean] +true+ if the word or partial word is found, +false+ otherwise.
|
70
66
|
# @see Nodes::Node#partial_word?
|
71
67
|
def partial_word? word = ''
|
72
68
|
root.partial_word? word.chars
|
@@ -74,8 +70,8 @@ module Rambling
|
|
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
|
-
#
|
73
|
+
# @return [Boolean] +true+ only if the word is found and the last character corresponds to a terminal node,
|
74
|
+
# +false+ otherwise.
|
79
75
|
# @see Nodes::Node#word?
|
80
76
|
def word? word = ''
|
81
77
|
root.word? word.chars
|
@@ -83,18 +79,15 @@ module Rambling
|
|
83
79
|
|
84
80
|
# Returns all words that start with the specified characters.
|
85
81
|
# @param [String] word the word to look for in the trie.
|
86
|
-
# @return [Array<String>] all the words contained in the trie that start
|
87
|
-
# with the specified characters.
|
82
|
+
# @return [Array<String>] all the words contained in the trie that start with the specified characters.
|
88
83
|
# @see Nodes::Node#scan
|
89
84
|
def scan word = ''
|
90
85
|
root.scan(word.chars).to_a
|
91
86
|
end
|
92
87
|
|
93
|
-
# Returns all words within a string that match a word contained in the
|
94
|
-
# trie.
|
88
|
+
# Returns all words within a string that match a word contained in the trie.
|
95
89
|
# @param [String] phrase the string to look for matching words in.
|
96
|
-
# @return [Enumerator<String>] all the words in the given string that
|
97
|
-
# match a word in the trie.
|
90
|
+
# @return [Enumerator<String>] all the words in the given string that match a word in the trie.
|
98
91
|
# @yield [String] each word found in phrase.
|
99
92
|
def words_within phrase
|
100
93
|
words_within_root(phrase).to_a
|
@@ -102,8 +95,7 @@ module Rambling
|
|
102
95
|
|
103
96
|
# Checks if there are any valid words in a given string.
|
104
97
|
# @param [String] phrase the string to look for matching words in.
|
105
|
-
# @return [Boolean] +true+ if any word within phrase is contained in the
|
106
|
-
# trie, +false+ otherwise.
|
98
|
+
# @return [Boolean] +true+ if any word within phrase is contained in the trie, +false+ otherwise.
|
107
99
|
# @see Container#words_within
|
108
100
|
def words_within? phrase
|
109
101
|
words_within_root(phrase).any?
|
@@ -141,33 +133,29 @@ module Rambling
|
|
141
133
|
end
|
142
134
|
|
143
135
|
# Root node's child nodes.
|
144
|
-
# @return [Array<Nodes::Node>] the array of children nodes contained in
|
145
|
-
# the root node.
|
136
|
+
# @return [Array<Nodes::Node>] the array of children nodes contained in the root node.
|
146
137
|
# @see Nodes::Node#children
|
147
138
|
def children
|
148
139
|
root.children
|
149
140
|
end
|
150
141
|
|
151
142
|
# Root node's children tree.
|
152
|
-
# @return [Hash<Symbol, Nodes::Node>] the children tree hash contained in
|
153
|
-
#
|
143
|
+
# @return [Hash<Symbol, Nodes::Node>] the children tree hash contained in the root node, consisting of
|
144
|
+
# +:letter => node+.
|
154
145
|
# @see Nodes::Node#children_tree
|
155
146
|
def children_tree
|
156
147
|
root.children_tree
|
157
148
|
end
|
158
149
|
|
159
|
-
# Indicates if the root {Nodes::Node Node} can be
|
160
|
-
#
|
161
|
-
# @return [Boolean] +true+ for non-{Nodes::Node#terminal? terminal}
|
162
|
-
# 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.
|
163
152
|
def compressed?
|
164
153
|
root.compressed?
|
165
154
|
end
|
166
155
|
|
167
156
|
# Array of words contained in the root {Nodes::Node Node}.
|
168
157
|
# @return [Array<String>] all words contained in this trie.
|
169
|
-
# @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-to_a
|
170
|
-
# Enumerable#to_a
|
158
|
+
# @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-to_a Enumerable#to_a
|
171
159
|
def to_a
|
172
160
|
root.to_a
|
173
161
|
end
|
@@ -7,8 +7,7 @@ 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.
|
@@ -11,8 +11,7 @@ module Rambling
|
|
11
11
|
# @raise [InvalidOperation] if the trie is already compressed.
|
12
12
|
# @return [void]
|
13
13
|
def add _
|
14
|
-
raise Rambling::Trie::InvalidOperation,
|
15
|
-
'Cannot add word to compressed trie'
|
14
|
+
raise Rambling::Trie::InvalidOperation, 'Cannot add word to compressed trie'
|
16
15
|
end
|
17
16
|
|
18
17
|
# Always return +true+ for a compressed node.
|
@@ -3,8 +3,7 @@
|
|
3
3
|
module Rambling
|
4
4
|
module Trie
|
5
5
|
module Nodes
|
6
|
-
# A representation of a missing node in the trie data structure. Returned
|
7
|
-
# when a node is not found.
|
6
|
+
# A representation of a missing node in the trie data structure. Returned when a node is not found.
|
8
7
|
class Missing < Rambling::Trie::Nodes::Node
|
9
8
|
end
|
10
9
|
end
|
@@ -22,8 +22,7 @@ module Rambling
|
|
22
22
|
attr_reader :letter
|
23
23
|
|
24
24
|
# Child nodes tree.
|
25
|
-
# @return [Hash<Symbol, Node>] the children tree hash, consisting of
|
26
|
-
# +:letter => node+.
|
25
|
+
# @return [Hash<Symbol, Node>] the children tree hash, consisting of +:letter => node+.
|
27
26
|
attr_accessor :children_tree
|
28
27
|
|
29
28
|
# Parent node.
|
@@ -40,8 +39,7 @@ module Rambling
|
|
40
39
|
end
|
41
40
|
|
42
41
|
# Child nodes.
|
43
|
-
# @return [Array<Node>] the array of child nodes contained
|
44
|
-
# in the current node.
|
42
|
+
# @return [Array<Node>] the array of child nodes contained in the current node.
|
45
43
|
def children
|
46
44
|
children_tree.values
|
47
45
|
end
|
@@ -57,8 +55,7 @@ module Rambling
|
|
57
55
|
end
|
58
56
|
|
59
57
|
# Indicates if the current node is the root node.
|
60
|
-
# @return [Boolean] +true+ if the node does not have a parent, +false+
|
61
|
-
# otherwise.
|
58
|
+
# @return [Boolean] +true+ if the node does not have a parent, +false+ otherwise.
|
62
59
|
def root?
|
63
60
|
!parent
|
64
61
|
end
|
@@ -70,7 +67,7 @@ module Rambling
|
|
70
67
|
end
|
71
68
|
|
72
69
|
# Mark {Node Node} as terminal.
|
73
|
-
# @return [
|
70
|
+
# @return [self] the modified node.
|
74
71
|
def terminal!
|
75
72
|
self.terminal = true
|
76
73
|
self
|
@@ -82,8 +79,7 @@ module Rambling
|
|
82
79
|
|
83
80
|
# Checks if a path for a set of characters exists in the trie.
|
84
81
|
# @param [Array<String>] chars the characters to look for in the trie.
|
85
|
-
# @return [Boolean] +true+ if the characters are found, +false+
|
86
|
-
# otherwise.
|
82
|
+
# @return [Boolean] +true+ if the characters are found, +false+ otherwise.
|
87
83
|
def partial_word? chars
|
88
84
|
return true if chars.empty?
|
89
85
|
|
@@ -92,8 +88,7 @@ module Rambling
|
|
92
88
|
|
93
89
|
# Checks if a path for set of characters represents a word in the trie.
|
94
90
|
# @param [Array<String>] chars the characters to look for in the trie.
|
95
|
-
# @return [Boolean] +true+ if the characters are found and form a word,
|
96
|
-
# +false+ otherwise.
|
91
|
+
# @return [Boolean] +true+ if the characters are found and form a word, +false+ otherwise.
|
97
92
|
def word? chars = []
|
98
93
|
return terminal? if chars.empty?
|
99
94
|
|
@@ -112,8 +107,7 @@ module Rambling
|
|
112
107
|
|
113
108
|
# Returns all words that match a prefix of any length within chars.
|
114
109
|
# @param [String] chars the chars to base the prefix on.
|
115
|
-
# @return [Enumerator<String>] all the words that match a prefix
|
116
|
-
# by chars.
|
110
|
+
# @return [Enumerator<String>] all the words that match a prefix by chars.
|
117
111
|
# @yield [String] each word found.
|
118
112
|
def match_prefix chars
|
119
113
|
return enum_for :match_prefix, chars unless block_given?
|
@@ -128,8 +122,7 @@ module Rambling
|
|
128
122
|
# Get {Node Node} corresponding to a given letter.
|
129
123
|
# @param [Symbol] letter the letter to search for in the node.
|
130
124
|
# @return [Node] the node corresponding to that letter.
|
131
|
-
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D
|
132
|
-
# Hash#[]
|
125
|
+
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D Hash#[]
|
133
126
|
def [] letter
|
134
127
|
children_tree[letter]
|
135
128
|
end
|
@@ -137,31 +130,25 @@ module Rambling
|
|
137
130
|
# Set the {Node Node} that corresponds to a given letter.
|
138
131
|
# @param [Symbol] letter the letter to insert or update in the node's
|
139
132
|
# @param [Node] node the {Node Node} to assign to that letter.
|
140
|
-
# @return [Node] the node corresponding to the inserted or
|
141
|
-
#
|
142
|
-
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D
|
143
|
-
# Hash#[]
|
133
|
+
# @return [Node] the node corresponding to the inserted or updated letter.
|
134
|
+
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D Hash#[]
|
144
135
|
def []= letter, node
|
145
136
|
children_tree[letter] = node
|
146
137
|
end
|
147
138
|
|
148
|
-
# Check if a {Node Node}'s children tree contains a given
|
149
|
-
# letter.
|
139
|
+
# Check if a {Node Node}'s children tree contains a given letter.
|
150
140
|
# @param [Symbol] letter the letter to search for in the node.
|
151
141
|
# @return [Boolean] +true+ if the letter is present, +false+ otherwise.
|
152
|
-
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-has_key-3F
|
153
|
-
# Hash#key?
|
142
|
+
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-has_key-3F Hash#key?
|
154
143
|
def key? letter
|
155
144
|
children_tree.key? letter
|
156
145
|
end
|
157
146
|
|
158
147
|
# Delete a given letter and its corresponding {Node Node} from
|
159
148
|
# this {Node Node}'s children tree.
|
160
|
-
# @param [Symbol] letter the letter to delete from the node's children
|
161
|
-
# tree.
|
149
|
+
# @param [Symbol] letter the letter to delete from the node's children tree.
|
162
150
|
# @return [Node] the node corresponding to the deleted letter.
|
163
|
-
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-delete
|
164
|
-
# Hash#delete
|
151
|
+
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-delete Hash#delete
|
165
152
|
def delete letter
|
166
153
|
children_tree.delete letter
|
167
154
|
end
|
@@ -6,8 +6,7 @@ module Rambling
|
|
6
6
|
# File reader for +.txt+ files.
|
7
7
|
class PlainText < Reader
|
8
8
|
# Yields each word read from a +.txt+ file.
|
9
|
-
# @param [String] filepath the full path of the file to load the words
|
10
|
-
# from.
|
9
|
+
# @param [String] filepath the full path of the file to load the words from.
|
11
10
|
# @yield [String] Each line read from the file.
|
12
11
|
# @return [self]
|
13
12
|
def each_word filepath
|