rambling-trie 2.3.1 → 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 +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
|