rambling-trie 2.3.0 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -0
- data/LICENSE +1 -1
- data/README.md +25 -11
- data/lib/rambling/trie/comparable.rb +2 -2
- data/lib/rambling/trie/compressible.rb +3 -3
- data/lib/rambling/trie/configuration/properties.rb +10 -9
- data/lib/rambling/trie/configuration/provider_collection.rb +15 -13
- data/lib/rambling/trie/container.rb +17 -19
- data/lib/rambling/trie/enumerable.rb +3 -0
- data/lib/rambling/trie/nodes/compressed.rb +3 -3
- data/lib/rambling/trie/nodes/node.rb +14 -14
- data/lib/rambling/trie/nodes/raw.rb +2 -2
- data/lib/rambling/trie/readers/plain_text.rb +9 -4
- data/lib/rambling/trie/readers/reader.rb +21 -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 +3 -2
- data/lib/rambling/trie/serializers/serializer.rb +27 -0
- data/lib/rambling/trie/serializers/yaml.rb +3 -2
- 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 +11 -9
- data/rambling-trie.gemspec +5 -1
- data/spec/integration/rambling/trie_spec.rb +13 -16
- 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 +42 -14
- data/spec/lib/rambling/trie/container_spec.rb +200 -325
- 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/node_spec.rb +1 -1
- data/spec/lib/rambling/trie/nodes/raw_spec.rb +26 -23
- 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 +1 -3
- data/spec/lib/rambling/trie/serializers/marshal_spec.rb +1 -3
- data/spec/lib/rambling/trie/serializers/serializer_spec.rb +21 -0
- data/spec/lib/rambling/trie/serializers/yaml_spec.rb +1 -3
- 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 +106 -44
- data/spec/spec_helper.rb +15 -8
- 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 +4 -8
- data/spec/support/shared_examples/a_serializer.rb +36 -13
- data/spec/support/shared_examples/a_trie_data_structure.rb +24 -10
- data/spec/support/shared_examples/a_trie_node.rb +19 -12
- data/spec/support/shared_examples/a_trie_node_implementation.rb +40 -43
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3af7f8936c101be83262b9535524bdcd3381bb76b857e7a44f331c932c67afb4
|
4
|
+
data.tar.gz: e1b9dfc8f88822404c82f95b3fac6a376d3433d15535e8fc0dd454b4669f9e52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8bc211404f2a209892aa7de20f20ce5b61f481f117f4ac2f3c45cceaf7076e690229487c7f2dd4613d5725fdf38e4a616efe082b27d4055c359f5801457f704d
|
7
|
+
data.tar.gz: 21cb664d6abccbc565fa8c2441c54c18d3ab8a4ccf8ae2457f4671b6b2b579ccd4893a400b3756af82bc261afa8c804db352bf68b6aa0105ab91396b90e1f2be
|
data/Gemfile
CHANGED
@@ -17,10 +17,14 @@ 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
|
24
25
|
gem 'guard-rspec'
|
25
26
|
gem 'rubocop', require: false
|
27
|
+
gem 'rubocop-performance', require: false
|
28
|
+
gem 'rubocop-rake', require: false
|
29
|
+
gem 'rubocop-rspec', require: false
|
26
30
|
end
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,16 @@
|
|
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]
|
6
|
+
|
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]
|
4
14
|
|
5
15
|
The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wiki], which includes compression abilities and is designed to be very fast to traverse.
|
6
16
|
|
@@ -167,7 +177,7 @@ Rambling::Trie.dump trie, '/path/to/file'
|
|
167
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, you can retrieve a previously stored one with `.load` like this:
|
168
178
|
|
169
179
|
``` ruby
|
170
|
-
trie = Rambling::Trie.load
|
180
|
+
trie = Rambling::Trie.load '/path/to/file'
|
171
181
|
```
|
172
182
|
|
173
183
|
#### Supported formats
|
@@ -197,7 +207,7 @@ Then, you can load contents form a `.zip` file like this:
|
|
197
207
|
|
198
208
|
``` ruby
|
199
209
|
require 'zip'
|
200
|
-
trie = Rambling::Trie.load
|
210
|
+
trie = Rambling::Trie.load '/path/to/file.zip'
|
201
211
|
```
|
202
212
|
|
203
213
|
> For `.zip` files, the format is also determined automatically based on the
|
@@ -265,7 +275,7 @@ Take a look at the [contributing guide][rambling_trie_contributing_guide] to get
|
|
265
275
|
|
266
276
|
## License and copyright
|
267
277
|
|
268
|
-
Copyright (c) 2012-
|
278
|
+
Copyright (c) 2012-2023 Edgar González
|
269
279
|
|
270
280
|
MIT License
|
271
281
|
|
@@ -275,19 +285,25 @@ The above copyright notice and this permission notice shall be included in all c
|
|
275
285
|
|
276
286
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
277
287
|
|
278
|
-
[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg
|
288
|
+
[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.3.0
|
279
289
|
[badge_fury_link]: https://badge.fury.io/rb/rambling-trie
|
280
290
|
[chruby]: https://github.com/postmodern/chruby
|
281
|
-
[
|
282
|
-
[
|
291
|
+
[code_climate_grade_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/gpa.svg
|
292
|
+
[code_climate_issues_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/issue_count.svg
|
293
|
+
[code_climate_link]: https://codeclimate.com/github/gonzedge/rambling-trie
|
283
294
|
[coveralls_badge]: https://img.shields.io/coveralls/gonzedge/rambling-trie.svg
|
284
295
|
[coveralls_link]: https://coveralls.io/r/gonzedge/rambling-trie
|
296
|
+
[downloads_badge]: https://img.shields.io/gem/dt/rambling-trie.svg
|
297
|
+
[downloads_link]: https://rubygems.org/gems/rambling-trie
|
285
298
|
[gemnasium_badge]: https://gemnasium.com/gonzedge/rambling-trie.svg
|
286
299
|
[gemnasium_link]: https://gemnasium.com/gonzedge/rambling-trie
|
300
|
+
[github_action_build_badge]: https://github.com/gonzedge/rambling-trie/actions/workflows/ruby.yml/badge.svg
|
301
|
+
[github_action_build_link]: https://github.com/gonzedge/rambling-trie/actions/workflows/ruby.yml
|
302
|
+
[github_action_codeql_badge]: https://github.com/gonzedge/rambling-trie/actions/workflows/codeql.yml/badge.svg
|
303
|
+
[github_action_codeql_link]: https://github.com/gonzedge/rambling-trie/actions/workflows/codeql.yml
|
287
304
|
[github_user_gonzedge]: https://github.com/gonzedge
|
288
305
|
[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
|
306
|
+
[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg
|
291
307
|
[license_link]: https://opensource.org/licenses/mit-license.php
|
292
308
|
[marshal]: https://ruby-doc.org/core-2.7.0/Marshal.html
|
293
309
|
[rambling_trie_configuration]: https://github.com/gonzedge/rambling-trie#configuration
|
@@ -298,7 +314,5 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
298
314
|
[rubydoc_github]: http://rubydoc.info/github/gonzedge/rambling-trie
|
299
315
|
[rubyzip]: https://github.com/rubyzip/rubyzip
|
300
316
|
[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
317
|
[trie_wiki]: https://en.wikipedia.org/wiki/Trie
|
304
318
|
[yaml]: https://ruby-doc.org/stdlib-2.7.0/libdoc/yaml/rdoc/YAML.html
|
@@ -6,8 +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,
|
9
|
+
# @return [Boolean] +true+ if the nodes' {Nodes::Node#letter #letter} and
|
10
|
+
# {Nodes::Node#children_tree #children_tree} are equal, +false+
|
11
11
|
# otherwise.
|
12
12
|
def == other
|
13
13
|
letter == other.letter &&
|
@@ -6,10 +6,10 @@ module Rambling
|
|
6
6
|
module Compressible
|
7
7
|
# Indicates if the current {Rambling::Trie::Nodes::Node Node} can be
|
8
8
|
# compressed or not.
|
9
|
-
# @return [Boolean]
|
10
|
-
# with one child,
|
9
|
+
# @return [Boolean] +true+ for non-{Nodes::Node#terminal? terminal} nodes
|
10
|
+
# with one child, +false+ otherwise.
|
11
11
|
def compressible?
|
12
|
-
!(root? || terminal?) && children_tree.size
|
12
|
+
!(root? || terminal?) && 1 == children_tree.size
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -6,26 +6,26 @@ 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
|
10
|
-
# Readers}.
|
9
|
+
# @return [ProviderCollection<Readers::Reader>] the mapping of
|
10
|
+
# configured {Readers Readers}.
|
11
11
|
attr_reader :readers
|
12
12
|
|
13
13
|
# The configured {Serializers Serializers}.
|
14
|
-
# @return [ProviderCollection] the mapping of
|
15
|
-
# Serializers}.
|
14
|
+
# @return [ProviderCollection<Serializers::Serializer>] the mapping of
|
15
|
+
# configured {Serializers Serializers}.
|
16
16
|
attr_reader :serializers
|
17
17
|
|
18
18
|
# The configured {Compressor Compressor}.
|
19
19
|
# @return [Compressor] the configured compressor.
|
20
20
|
attr_accessor :compressor
|
21
21
|
|
22
|
-
# The configured root_builder
|
23
|
-
#
|
24
|
-
# @return [Proc<Nodes::Node>] the configured root_builder
|
22
|
+
# The configured +root_builder+, which returns a {Nodes::Node Node}
|
23
|
+
# when called.
|
24
|
+
# @return [Proc<Nodes::Node>] the configured +root_builder+.
|
25
25
|
attr_accessor :root_builder
|
26
26
|
|
27
|
-
# The configured tmp_path
|
28
|
-
# @return [String] the configured tmp_path
|
27
|
+
# The configured +tmp_path+, which will be used for throwaway files.
|
28
|
+
# @return [String] the configured +tmp_path+.
|
29
29
|
attr_accessor :tmp_path
|
30
30
|
|
31
31
|
# Returns a new properties instance.
|
@@ -34,6 +34,7 @@ module Rambling
|
|
34
34
|
end
|
35
35
|
|
36
36
|
# Resets back to default properties.
|
37
|
+
# @return [void]
|
37
38
|
def reset
|
38
39
|
reset_readers
|
39
40
|
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,18 @@ 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 [
|
18
|
+
# @param [TProvider] provider the provider to use as default.
|
19
19
|
# @raise [ArgumentError] when the given provider is not in the
|
20
20
|
# provider collection.
|
21
|
-
# @note If no providers have been configured,
|
22
|
-
# @return [
|
21
|
+
# @note If no providers have been configured, +nil+ will be assigned.
|
22
|
+
# @return [TProvider, nil] the default provider to use when a provider
|
23
23
|
# cannot be resolved in {ProviderCollection#resolve #resolve}.
|
24
24
|
attr_reader :default
|
25
25
|
|
26
26
|
# Creates a new provider collection.
|
27
|
-
# @param [
|
28
|
-
# @param [Hash] providers the configured providers.
|
29
|
-
# @param [
|
27
|
+
# @param [Symbol] name the name for this provider collection.
|
28
|
+
# @param [Hash<Symbol, TProvider>] providers the configured providers.
|
29
|
+
# @param [TProvider, nil] default the configured default provider.
|
30
30
|
def initialize name, providers = {}, default = nil
|
31
31
|
@name = name
|
32
32
|
@configured_providers = providers
|
@@ -38,8 +38,9 @@ module Rambling
|
|
38
38
|
# Adds a new provider to the provider collection.
|
39
39
|
# @param [Symbol] extension the extension that the provider will
|
40
40
|
# correspond to.
|
41
|
-
# @param [
|
41
|
+
# @param [TProvider] provider the provider to add to the provider
|
42
42
|
# collection.
|
43
|
+
# @return [TProvider] the provider just added.
|
43
44
|
def add extension, provider
|
44
45
|
providers[extension] = provider
|
45
46
|
end
|
@@ -54,21 +55,22 @@ module Rambling
|
|
54
55
|
end
|
55
56
|
|
56
57
|
# List of configured providers.
|
57
|
-
# @return [Hash] the mapping of extensions to their
|
58
|
-
# providers.
|
58
|
+
# @return [Hash<Symbol, TProvider>] the mapping of extensions to their
|
59
|
+
# corresponding providers.
|
59
60
|
def providers
|
60
61
|
@providers ||= {}
|
61
62
|
end
|
62
63
|
|
63
64
|
# Resolves the provider from a filepath based on the file extension.
|
64
65
|
# @param [String] filepath the filepath to resolve into a provider.
|
65
|
-
# @return [
|
66
|
-
#
|
66
|
+
# @return [TProvider, nil] the provider for the given file's extension.
|
67
|
+
# {#default} if not found.
|
67
68
|
def resolve filepath
|
68
69
|
providers[file_format filepath] || default
|
69
70
|
end
|
70
71
|
|
71
72
|
# Resets the provider collection to the initial values.
|
73
|
+
# @return [void]
|
72
74
|
def reset
|
73
75
|
providers.clear
|
74
76
|
configured_providers.each { |k, v| self[k] = v }
|
@@ -85,7 +87,7 @@ module Rambling
|
|
85
87
|
|
86
88
|
# Get provider corresponding to a given format.
|
87
89
|
# @param [Symbol] format the format to search for in the collection.
|
88
|
-
# @return [
|
90
|
+
# @return [TProvider] the provider corresponding to that format.
|
89
91
|
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D
|
90
92
|
# Hash#[]
|
91
93
|
def [] format
|
@@ -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
|
@@ -44,7 +44,7 @@ module Rambling
|
|
44
44
|
# Compresses the existing trie using redundant node elimination. Marks
|
45
45
|
# the trie as compressed. Does nothing if the trie has already been
|
46
46
|
# compressed.
|
47
|
-
# @return [
|
47
|
+
# @return [self]
|
48
48
|
# @note This method replaces the root {Nodes::Raw Raw} node with a
|
49
49
|
# {Nodes::Compressed Compressed} version of it.
|
50
50
|
def compress!
|
@@ -59,25 +59,24 @@ module Rambling
|
|
59
59
|
# compressed.
|
60
60
|
def compress
|
61
61
|
return self if root.compressed?
|
62
|
+
|
62
63
|
Rambling::Trie::Container.new compress_root, compressor
|
63
64
|
end
|
64
65
|
|
65
66
|
# Checks if a path for a word or partial word exists in the trie.
|
66
67
|
# @param [String] word the word or partial word to look for in the trie.
|
67
|
-
# @return [Boolean]
|
68
|
+
# @return [Boolean] +true+ if the word or partial word is found, +false+
|
68
69
|
# otherwise.
|
69
|
-
# @see Nodes::
|
70
|
-
# @see Nodes::Compressed#partial_word?
|
70
|
+
# @see Nodes::Node#partial_word?
|
71
71
|
def partial_word? word = ''
|
72
72
|
root.partial_word? word.chars
|
73
73
|
end
|
74
74
|
|
75
75
|
# Checks if a whole word exists in the trie.
|
76
76
|
# @param [String] word the word to look for in the trie.
|
77
|
-
# @return [Boolean]
|
78
|
-
# character corresponds to a terminal node,
|
79
|
-
# @see Nodes::
|
80
|
-
# @see Nodes::Compressed#word?
|
77
|
+
# @return [Boolean] +true+ only if the word is found and the last
|
78
|
+
# character corresponds to a terminal node, +false+ otherwise.
|
79
|
+
# @see Nodes::Node#word?
|
81
80
|
def word? word = ''
|
82
81
|
root.word? word.chars
|
83
82
|
end
|
@@ -86,8 +85,7 @@ module Rambling
|
|
86
85
|
# @param [String] word the word to look for in the trie.
|
87
86
|
# @return [Array<String>] all the words contained in the trie that start
|
88
87
|
# with the specified characters.
|
89
|
-
# @see Nodes::
|
90
|
-
# @see Nodes::Compressed#scan
|
88
|
+
# @see Nodes::Node#scan
|
91
89
|
def scan word = ''
|
92
90
|
root.scan(word.chars).to_a
|
93
91
|
end
|
@@ -98,15 +96,14 @@ module Rambling
|
|
98
96
|
# @return [Enumerator<String>] all the words in the given string that
|
99
97
|
# match a word in the trie.
|
100
98
|
# @yield [String] each word found in phrase.
|
101
|
-
# @see Nodes::Node#words_within
|
102
99
|
def words_within phrase
|
103
100
|
words_within_root(phrase).to_a
|
104
101
|
end
|
105
102
|
|
106
103
|
# Checks if there are any valid words in a given string.
|
107
104
|
# @param [String] phrase the string to look for matching words in.
|
108
|
-
# @return [Boolean]
|
109
|
-
# trie,
|
105
|
+
# @return [Boolean] +true+ if any word within phrase is contained in the
|
106
|
+
# trie, +false+ otherwise.
|
110
107
|
# @see Container#words_within
|
111
108
|
def words_within? phrase
|
112
109
|
words_within_root(phrase).any?
|
@@ -114,13 +111,14 @@ module Rambling
|
|
114
111
|
|
115
112
|
# Compares two trie data structures.
|
116
113
|
# @param [Container] other the trie to compare against.
|
117
|
-
# @return [Boolean]
|
114
|
+
# @return [Boolean] +true+ if the tries are equal, +false+ otherwise.
|
118
115
|
def == other
|
119
116
|
root == other.root
|
120
117
|
end
|
121
118
|
|
122
119
|
# Iterates over the words contained in the trie.
|
123
120
|
# @yield [String] the words contained in this trie node.
|
121
|
+
# @return [self]
|
124
122
|
def each
|
125
123
|
return enum_for :each unless block_given?
|
126
124
|
|
@@ -151,8 +149,8 @@ module Rambling
|
|
151
149
|
end
|
152
150
|
|
153
151
|
# Root node's children tree.
|
154
|
-
# @return [
|
155
|
-
# the root node
|
152
|
+
# @return [Hash<Symbol, Nodes::Node>] the children tree hash contained in
|
153
|
+
# the root node, consisting of +:letter => node+.
|
156
154
|
# @see Nodes::Node#children_tree
|
157
155
|
def children_tree
|
158
156
|
root.children_tree
|
@@ -160,8 +158,8 @@ module Rambling
|
|
160
158
|
|
161
159
|
# Indicates if the root {Nodes::Node Node} can be
|
162
160
|
# compressed or not.
|
163
|
-
# @return [Boolean]
|
164
|
-
# nodes with one child,
|
161
|
+
# @return [Boolean] +true+ for non-{Nodes::Node#terminal? terminal}
|
162
|
+
# nodes with one child, +false+ otherwise.
|
165
163
|
def compressed?
|
166
164
|
root.compressed?
|
167
165
|
end
|
@@ -13,6 +13,7 @@ module Rambling
|
|
13
13
|
|
14
14
|
# Iterates over the words contained in the trie.
|
15
15
|
# @yield [String] the words contained in this trie node.
|
16
|
+
# @return [self]
|
16
17
|
def each
|
17
18
|
return enum_for :each unless block_given?
|
18
19
|
|
@@ -23,6 +24,8 @@ module Rambling
|
|
23
24
|
yield word
|
24
25
|
end
|
25
26
|
end
|
27
|
+
|
28
|
+
self
|
26
29
|
end
|
27
30
|
end
|
28
31
|
end
|
@@ -9,14 +9,14 @@ module Rambling
|
|
9
9
|
# trying to add a word to the current compressed trie node
|
10
10
|
# @param [String] _ the word to add to the trie.
|
11
11
|
# @raise [InvalidOperation] if the trie is already compressed.
|
12
|
-
# @return [
|
12
|
+
# @return [void]
|
13
13
|
def add _
|
14
14
|
raise Rambling::Trie::InvalidOperation,
|
15
15
|
'Cannot add word to compressed trie'
|
16
16
|
end
|
17
17
|
|
18
|
-
# Always return
|
19
|
-
# @return [Boolean] always
|
18
|
+
# Always return +true+ for a compressed node.
|
19
|
+
# @return [Boolean] always +true+ for a compressed node.
|
20
20
|
def compressed?
|
21
21
|
true
|
22
22
|
end
|
@@ -22,8 +22,8 @@ module Rambling
|
|
22
22
|
attr_reader :letter
|
23
23
|
|
24
24
|
# Child nodes tree.
|
25
|
-
# @return [Hash] the
|
26
|
-
# node
|
25
|
+
# @return [Hash<Symbol, Node>] the children tree hash, consisting of
|
26
|
+
# +:letter => node+.
|
27
27
|
attr_accessor :children_tree
|
28
28
|
|
29
29
|
# Parent node.
|
@@ -31,7 +31,7 @@ module Rambling
|
|
31
31
|
attr_accessor :parent
|
32
32
|
|
33
33
|
# Creates a new node.
|
34
|
-
# @param [Symbol, nil] letter the Node's letter value
|
34
|
+
# @param [Symbol, nil] letter the Node's letter value.
|
35
35
|
# @param [Node, nil] parent the parent of the current node.
|
36
36
|
def initialize letter = nil, parent = nil, children_tree = {}
|
37
37
|
@letter = letter
|
@@ -40,7 +40,7 @@ module Rambling
|
|
40
40
|
end
|
41
41
|
|
42
42
|
# Child nodes.
|
43
|
-
# @return [Array<Node>] the array of
|
43
|
+
# @return [Array<Node>] the array of child nodes contained
|
44
44
|
# in the current node.
|
45
45
|
def children
|
46
46
|
children_tree.values
|
@@ -51,20 +51,20 @@ module Rambling
|
|
51
51
|
def first_child
|
52
52
|
return if children_tree.empty?
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
# rubocop:disable Lint/UnreachableLoop
|
55
|
+
children_tree.each_value { |child| return child }
|
56
|
+
# rubocop:enable Lint/UnreachableLoop
|
57
57
|
end
|
58
58
|
|
59
59
|
# Indicates if the current node is the root node.
|
60
|
-
# @return [Boolean]
|
60
|
+
# @return [Boolean] +true+ if the node does not have a parent, +false+
|
61
61
|
# otherwise.
|
62
62
|
def root?
|
63
63
|
!parent
|
64
64
|
end
|
65
65
|
|
66
66
|
# Indicates if a {Node Node} is terminal or not.
|
67
|
-
# @return [Boolean]
|
67
|
+
# @return [Boolean] +true+ for terminal nodes, +false+ otherwise.
|
68
68
|
def terminal?
|
69
69
|
!!terminal
|
70
70
|
end
|
@@ -82,7 +82,7 @@ module Rambling
|
|
82
82
|
|
83
83
|
# Checks if a path for a set of characters exists in the trie.
|
84
84
|
# @param [Array<String>] chars the characters to look for in the trie.
|
85
|
-
# @return [Boolean]
|
85
|
+
# @return [Boolean] +true+ if the characters are found, +false+
|
86
86
|
# otherwise.
|
87
87
|
def partial_word? chars
|
88
88
|
return true if chars.empty?
|
@@ -92,8 +92,8 @@ module Rambling
|
|
92
92
|
|
93
93
|
# Checks if a path for set of characters represents a word in the trie.
|
94
94
|
# @param [Array<String>] chars the characters to look for in the trie.
|
95
|
-
# @return [Boolean]
|
96
|
-
#
|
95
|
+
# @return [Boolean] +true+ if the characters are found and form a word,
|
96
|
+
# +false+ otherwise.
|
97
97
|
def word? chars = []
|
98
98
|
return terminal? if chars.empty?
|
99
99
|
|
@@ -148,7 +148,7 @@ module Rambling
|
|
148
148
|
# Check if a {Node Node}'s children tree contains a given
|
149
149
|
# letter.
|
150
150
|
# @param [Symbol] letter the letter to search for in the node.
|
151
|
-
# @return [Boolean]
|
151
|
+
# @return [Boolean] +true+ if the letter is present, +false+ otherwise.
|
152
152
|
# @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-has_key-3F
|
153
153
|
# Hash#key?
|
154
154
|
def key? letter
|
@@ -156,7 +156,7 @@ module Rambling
|
|
156
156
|
end
|
157
157
|
|
158
158
|
# Delete a given letter and its corresponding {Node Node} from
|
159
|
-
#
|
159
|
+
# this {Node Node}'s children tree.
|
160
160
|
# @param [Symbol] letter the letter to delete from the node's children
|
161
161
|
# tree.
|
162
162
|
# @return [Node] the node corresponding to the deleted letter.
|
@@ -17,8 +17,8 @@ module Rambling
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
# Always return
|
21
|
-
# @return [Boolean] always
|
20
|
+
# Always return +false+ for a raw (uncompressed) node.
|
21
|
+
# @return [Boolean] always +false+ for a raw (uncompressed) node.
|
22
22
|
def compressed?
|
23
23
|
false
|
24
24
|
end
|
@@ -3,14 +3,19 @@
|
|
3
3
|
module Rambling
|
4
4
|
module Trie
|
5
5
|
module Readers
|
6
|
-
# File reader for
|
7
|
-
class PlainText
|
8
|
-
# Yields each word read from a
|
6
|
+
# File reader for +.txt+ files.
|
7
|
+
class PlainText < Reader
|
8
|
+
# Yields each word read from a +.txt+ file.
|
9
9
|
# @param [String] filepath the full path of the file to load the words
|
10
10
|
# from.
|
11
11
|
# @yield [String] Each line read from the file.
|
12
|
+
# @return [self]
|
12
13
|
def each_word filepath
|
13
|
-
|
14
|
+
return enum_for :each_word unless block_given?
|
15
|
+
|
16
|
+
::File.foreach(filepath) { |line| yield line.chomp! }
|
17
|
+
|
18
|
+
self
|
14
19
|
end
|
15
20
|
end
|
16
21
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rambling
|
4
|
+
module Trie
|
5
|
+
module Readers
|
6
|
+
# Base class for all readers.
|
7
|
+
class Reader
|
8
|
+
# Yields each word read from given file.
|
9
|
+
# @abstract Subclass and override {#each_word} to fit to a particular
|
10
|
+
# file format.
|
11
|
+
# @param [String] filepath the full path of the file to load the words
|
12
|
+
# from.
|
13
|
+
# @yield [String] Each line read from the file.
|
14
|
+
# @return [self]
|
15
|
+
def each_word filepath
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -4,7 +4,7 @@ module Rambling
|
|
4
4
|
module Trie
|
5
5
|
module Serializers
|
6
6
|
# Basic file serializer. Dumps/loads string contents from files.
|
7
|
-
class File
|
7
|
+
class File < Serializer
|
8
8
|
# Loads contents from a specified filepath.
|
9
9
|
# @param [String] filepath the filepath to load contents from.
|
10
10
|
# @return [String] all contents of the file.
|
@@ -3,13 +3,14 @@
|
|
3
3
|
module Rambling
|
4
4
|
module Trie
|
5
5
|
module Serializers
|
6
|
-
# Serializer for Ruby marshal format (
|
7
|
-
class Marshal
|
6
|
+
# Serializer for Ruby marshal format (+.marshal+) files.
|
7
|
+
class Marshal < Serializer
|
8
8
|
# Creates a new Marshal serializer.
|
9
9
|
# @param [Serializer] serializer the serializer responsible to write to
|
10
10
|
# and read from disk.
|
11
11
|
def initialize serializer = nil
|
12
12
|
@serializer = serializer || Rambling::Trie::Serializers::File.new
|
13
|
+
super()
|
13
14
|
end
|
14
15
|
|
15
16
|
# Loads marshaled object from contents in filepath and deserializes it
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rambling
|
4
|
+
module Trie
|
5
|
+
module Serializers
|
6
|
+
# Base class for all serializers.
|
7
|
+
class Serializer
|
8
|
+
# Loads contents from a specified filepath.
|
9
|
+
# @abstract Subclass and override {#load} to parse the desired format.
|
10
|
+
# @param [String] filepath the filepath to load contents from.
|
11
|
+
# @return [TContents] parsed contents from given file.
|
12
|
+
def load filepath
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
# Dumps contents into a specified filepath.
|
17
|
+
# @abstract Subclass and override {#dump} to output the desired format.
|
18
|
+
# @param [TContents] contents the contents to dump into given file.
|
19
|
+
# @param [String] filepath the filepath to dump the contents to.
|
20
|
+
# @return [Numeric] number of bytes written to disk.
|
21
|
+
def dump contents, filepath
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -3,13 +3,14 @@
|
|
3
3
|
module Rambling
|
4
4
|
module Trie
|
5
5
|
module Serializers
|
6
|
-
# Serializer for Ruby yaml format (
|
7
|
-
class Yaml
|
6
|
+
# Serializer for Ruby yaml format (+.yaml+, or +.yml+) files.
|
7
|
+
class Yaml < Serializer
|
8
8
|
# Creates a new Yaml serializer.
|
9
9
|
# @param [Serializer] serializer the serializer responsible to write to
|
10
10
|
# and read from disk.
|
11
11
|
def initialize serializer = nil
|
12
12
|
@serializer = serializer || Rambling::Trie::Serializers::File.new
|
13
|
+
super()
|
13
14
|
end
|
14
15
|
|
15
16
|
# Loads serialized object from YAML file in filepath and deserializes
|