rambling-trie 2.6.0 → 2.7.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/Dockerfile +2 -1
- data/README.md +2 -2
- data/Steepfile +5 -1
- data/lib/rambling/trie/comparable.rb +4 -2
- data/lib/rambling/trie/compressible.rb +1 -1
- data/lib/rambling/trie/compressor.rb +2 -2
- data/lib/rambling/trie/configuration/properties.rb +3 -1
- data/lib/rambling/trie/configuration/provider_collection.rb +7 -7
- data/lib/rambling/trie/container.rb +37 -16
- data/lib/rambling/trie/enumerable.rb +8 -4
- data/lib/rambling/trie/nodes/compressed.rb +26 -18
- data/lib/rambling/trie/nodes/missing.rb +17 -0
- data/lib/rambling/trie/nodes/node.rb +25 -22
- data/lib/rambling/trie/nodes/raw.rb +3 -3
- data/lib/rambling/trie/not_implemented.rb +23 -0
- data/lib/rambling/trie/readers/plain_text.rb +4 -1
- data/lib/rambling/trie/readers/reader.rb +5 -2
- data/lib/rambling/trie/serializers/marshal.rb +5 -0
- data/lib/rambling/trie/serializers/serializer.rb +8 -4
- data/lib/rambling/trie/serializers/yaml.rb +5 -0
- data/lib/rambling/trie/serializers/zip.rb +31 -21
- data/lib/rambling/trie/stringifyable.rb +2 -5
- data/lib/rambling/trie/version.rb +1 -1
- data/lib/rambling/trie.rb +11 -7
- data/sig/lib/rambling/trie/comparable.rbs +4 -2
- data/sig/lib/rambling/trie/compressible.rbs +1 -1
- data/sig/lib/rambling/trie/compressor.rbs +1 -1
- data/sig/lib/rambling/trie/configuration/properties.rbs +1 -1
- data/sig/lib/rambling/trie/container.rbs +9 -8
- data/sig/lib/rambling/trie/enumerable.rbs +5 -4
- data/sig/lib/rambling/trie/inspectable.rbs +3 -3
- data/sig/lib/rambling/trie/nodes/compressed.rbs +4 -2
- data/sig/lib/rambling/trie/nodes/missing.rbs +9 -1
- data/sig/lib/rambling/trie/nodes/node.rbs +3 -2
- data/sig/lib/rambling/trie/nodes/raw.rbs +1 -1
- data/sig/lib/rambling/trie/not_implemented.rbs +10 -0
- data/sig/lib/rambling/trie/readers/plain_text.rbs +1 -1
- data/sig/lib/rambling/trie/readers/reader.rbs +2 -0
- data/sig/lib/rambling/trie/serializers/marshal.rbs +1 -1
- data/sig/lib/rambling/trie/serializers/serializer.rbs +2 -0
- data/sig/lib/rambling/trie/serializers/yaml.rbs +1 -1
- data/sig/lib/rambling/trie/serializers/zip.rbs +4 -2
- data/sig/lib/rambling/trie/stringifyable.rbs +2 -2
- data/sig/lib/rambling/trie.rbs +10 -8
- metadata +4 -4
- data/sig/lib/zip/entry.rbs +0 -11
- data/sig/lib/zip/file.rbs +0 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3a9d76d13a38a54c80ca90236346dcfe280fea62d46d8e9318efc8f2653b6f40
|
|
4
|
+
data.tar.gz: 0ab262b5f456d0e299fc16614bb0c7103406899b0a88dce3ef69d0d1f403fd3c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 13ccb7f63311ae91544442fe75e1620ecb91ef87501150fa46f454f80b7b4d51cda69ebeb8c82e474173db815e5f536b9cf03cccb3fa8e6233facfbd7f265949
|
|
7
|
+
data.tar.gz: dfab4eaea2613f6ad5957579089056441d3f01533112fff081504da2be2e18f77267350f6cedd4c61d65d88075cf0e83d22e5124370fac45fa2dadc36b22ddcb
|
data/Dockerfile
CHANGED
data/README.md
CHANGED
|
@@ -299,7 +299,7 @@ The Rambling Trie has been tested with the following Ruby versions:
|
|
|
299
299
|
|
|
300
300
|
## Compatible RBS and Steep versions
|
|
301
301
|
|
|
302
|
-
Type signatures for `Rambling::Trie` are included in the [`sig` directory](./sig)! The current version (`2.
|
|
302
|
+
Type signatures for `Rambling::Trie` are included in the [`sig` directory](./sig)! The current version (`2.7.0`) was
|
|
303
303
|
checked with RBS `3.10.4` and Steep `1.10.0`.
|
|
304
304
|
|
|
305
305
|
## Contributing to Rambling Trie
|
|
@@ -327,7 +327,7 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER I
|
|
|
327
327
|
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
328
328
|
|
|
329
329
|
[asdf]: https://asdf-vm.com/
|
|
330
|
-
[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.
|
|
330
|
+
[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.7.0
|
|
331
331
|
[badge_fury_link]: https://badge.fury.io/rb/rambling-trie
|
|
332
332
|
[chruby]: https://github.com/postmodern/chruby
|
|
333
333
|
[code_climate_grade_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/gpa.svg
|
data/Steepfile
CHANGED
|
@@ -13,9 +13,13 @@ target :lib do
|
|
|
13
13
|
# check 'Rakefile'
|
|
14
14
|
# check 'Steepfile'
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
collection_config 'rbs_collection.yaml'
|
|
17
|
+
|
|
18
|
+
library 'rubyzip'
|
|
19
|
+
library 'rake'
|
|
17
20
|
library 'yaml'
|
|
18
21
|
library 'securerandom'
|
|
22
|
+
library 'tmpdir'
|
|
19
23
|
|
|
20
24
|
# configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
|
|
21
25
|
# configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
|
|
@@ -6,11 +6,13 @@ 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] `true` if the nodes' {Nodes::Node#letter #letter}
|
|
10
|
-
# {Nodes::Node#
|
|
9
|
+
# @return [Boolean] `true` if the nodes' {Nodes::Node#letter #letter},
|
|
10
|
+
# {Nodes::Node#terminal? #terminal?}, {Nodes::Node#value #value}, and
|
|
11
|
+
# {Nodes::Node#children_tree #children_tree} are all equal, `false` otherwise.
|
|
11
12
|
def == other
|
|
12
13
|
letter == other.letter &&
|
|
13
14
|
terminal? == other.terminal? &&
|
|
15
|
+
value == other.value &&
|
|
14
16
|
children_tree == other.children_tree
|
|
15
17
|
end
|
|
16
18
|
end
|
|
@@ -7,7 +7,7 @@ module Rambling
|
|
|
7
7
|
# Indicates if the current {Rambling::Trie::Nodes::Node Node} can be compressed or not.
|
|
8
8
|
# @return [Boolean] `true` for non-{Nodes::Node#terminal? terminal} nodes with one child, `false` otherwise.
|
|
9
9
|
def compressible?
|
|
10
|
-
!
|
|
10
|
+
!root? && !terminal? && children_tree.one?
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -37,7 +37,7 @@ module Rambling
|
|
|
37
37
|
if other.terminal?
|
|
38
38
|
compressed.terminal!
|
|
39
39
|
value = other.value
|
|
40
|
-
compressed.value = value
|
|
40
|
+
compressed.value = value unless value.nil?
|
|
41
41
|
end
|
|
42
42
|
compressed
|
|
43
43
|
end
|
|
@@ -48,7 +48,7 @@ module Rambling
|
|
|
48
48
|
if node.terminal?
|
|
49
49
|
compressed.terminal!
|
|
50
50
|
value = node.value
|
|
51
|
-
compressed.value = value
|
|
51
|
+
compressed.value = value unless value.nil?
|
|
52
52
|
end
|
|
53
53
|
compressed
|
|
54
54
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'tmpdir'
|
|
4
|
+
|
|
3
5
|
module Rambling
|
|
4
6
|
module Trie
|
|
5
7
|
module Configuration
|
|
@@ -39,7 +41,7 @@ module Rambling
|
|
|
39
41
|
|
|
40
42
|
@compressor = Rambling::Trie::Compressor.new
|
|
41
43
|
@root_builder = -> { Rambling::Trie::Nodes::Raw.new }
|
|
42
|
-
@tmp_path =
|
|
44
|
+
@tmp_path = Dir.tmpdir
|
|
43
45
|
end
|
|
44
46
|
|
|
45
47
|
private
|
|
@@ -17,7 +17,6 @@ module Rambling
|
|
|
17
17
|
# providers.
|
|
18
18
|
# @param [TProvider] provider the provider to use as default.
|
|
19
19
|
# @raise [ArgumentError] when the given provider is not in the provider collection.
|
|
20
|
-
# @note If no providers have been configured, `nil` will be assigned.
|
|
21
20
|
# @return [TProvider, nil] the default provider to use when a provider cannot be resolved in
|
|
22
21
|
# {ProviderCollection#resolve #resolve}.
|
|
23
22
|
attr_reader :default
|
|
@@ -25,7 +24,8 @@ module Rambling
|
|
|
25
24
|
# Creates a new provider collection.
|
|
26
25
|
# @param [Symbol] name the name for this provider collection.
|
|
27
26
|
# @param [Hash<Symbol, TProvider>] providers the configured providers.
|
|
28
|
-
# @param [TProvider, nil] default the configured default provider.
|
|
27
|
+
# @param [TProvider, nil] default the configured default provider. When +nil+ (or no providers
|
|
28
|
+
# are given), falls back to the first configured provider, or +nil+ if none exist.
|
|
29
29
|
def initialize name, providers = {}, default = nil
|
|
30
30
|
@name = name
|
|
31
31
|
@configured_providers = providers
|
|
@@ -74,9 +74,9 @@ module Rambling
|
|
|
74
74
|
self.default = configured_default
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
#
|
|
78
|
-
# @return [Array<Symbol>] the
|
|
79
|
-
# @see https://ruby-doc.org/3.3.0/Hash.html#method-i-
|
|
77
|
+
# List the formats of configured providers.
|
|
78
|
+
# @return [Array<Symbol>] the formats of all configured providers.
|
|
79
|
+
# @see https://ruby-doc.org/3.3.0/Hash.html#method-i-keys
|
|
80
80
|
# Hash#keys
|
|
81
81
|
def formats
|
|
82
82
|
providers.keys
|
|
@@ -84,7 +84,7 @@ module Rambling
|
|
|
84
84
|
|
|
85
85
|
# Get provider corresponding to a given format.
|
|
86
86
|
# @param [Symbol] format the format to search for in the collection.
|
|
87
|
-
# @return [TProvider] the provider corresponding to that format.
|
|
87
|
+
# @return [TProvider, nil] the provider corresponding to that format, or +nil+ if not found.
|
|
88
88
|
# @see https://ruby-doc.org/3.3.0/Hash.html#method-i-5B-5D Hash#[]
|
|
89
89
|
def [] format
|
|
90
90
|
providers[format]
|
|
@@ -109,7 +109,7 @@ module Rambling
|
|
|
109
109
|
def contains? provider
|
|
110
110
|
return true if provider.nil?
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
provider_instances.include?(provider || raise)
|
|
113
113
|
end
|
|
114
114
|
|
|
115
115
|
alias_method :provider_instances, :values
|
|
@@ -22,7 +22,8 @@ module Rambling
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
# Adds a word to the trie.
|
|
25
|
-
# @param [String] word the word to add the
|
|
25
|
+
# @param [String] word the word to add to the trie.
|
|
26
|
+
# @param [Object, nil] value the value to associate with the word.
|
|
26
27
|
# @return [Nodes::Node] the just added branch's root node.
|
|
27
28
|
# @raise [InvalidOperation] if the trie is already compressed.
|
|
28
29
|
# @see Nodes::Raw#add
|
|
@@ -32,13 +33,22 @@ module Rambling
|
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
# Adds all provided words to the trie.
|
|
35
|
-
# @param [Array<String>] words the words to add the
|
|
36
|
+
# @param [Array<String>] words the words to add to the trie.
|
|
37
|
+
# @param [Array<Object>, nil] values the values to associate with each word, in the same order.
|
|
36
38
|
# @return [Array<Nodes::Node>] the collection of nodes added.
|
|
37
39
|
# @raise [InvalidOperation] if the trie is already compressed.
|
|
40
|
+
# @raise [ArgumentError] if words and values are given but differ in size.
|
|
38
41
|
# @see Nodes::Raw#add
|
|
39
42
|
# @see Nodes::Compressed#add
|
|
40
43
|
def concat words, values = nil
|
|
41
44
|
if values
|
|
45
|
+
words_size = words.size
|
|
46
|
+
values_size = values.size
|
|
47
|
+
unless words_size == values_size
|
|
48
|
+
raise ArgumentError,
|
|
49
|
+
"words and values must have the same size (words: #{words_size}, values: #{values_size})"
|
|
50
|
+
end
|
|
51
|
+
|
|
42
52
|
words.each_with_index.map { |word, index| add(word, values[index]) }
|
|
43
53
|
else
|
|
44
54
|
words.map { |word| add word }
|
|
@@ -56,10 +66,18 @@ module Rambling
|
|
|
56
66
|
end
|
|
57
67
|
|
|
58
68
|
# Compresses the existing trie using redundant node elimination. Returns a new trie with the compressed root.
|
|
59
|
-
# @return [Container] A new {Container} with the {Nodes::Compressed Compressed} root node
|
|
60
|
-
#
|
|
69
|
+
# @return [Container] A new {Container} with the {Nodes::Compressed Compressed} root node.
|
|
70
|
+
# @deprecated Calling {#compress} on an already-compressed trie is deprecated and will raise
|
|
71
|
+
# {InvalidOperation} in the next major version. Use {#compressed?} to guard if needed.
|
|
61
72
|
def compress
|
|
62
|
-
|
|
73
|
+
if root.compressed?
|
|
74
|
+
warn <<~WARN.chomp.tr("\n", ' ')
|
|
75
|
+
[DEPRECATED] Calling `compress` on an already-compressed trie is deprecated
|
|
76
|
+
and will raise `InvalidOperation` in the next major version.
|
|
77
|
+
Called from #{caller_locations(1, 1)&.first}
|
|
78
|
+
WARN
|
|
79
|
+
return Rambling::Trie::Container.new root, compressor
|
|
80
|
+
end
|
|
63
81
|
|
|
64
82
|
Rambling::Trie::Container.new compress_root, compressor
|
|
65
83
|
end
|
|
@@ -73,7 +91,7 @@ module Rambling
|
|
|
73
91
|
end
|
|
74
92
|
|
|
75
93
|
# Adds all provided words to the trie.
|
|
76
|
-
# @param [
|
|
94
|
+
# @param [String] words the words to add to the trie.
|
|
77
95
|
# @return [Array<Nodes::Node>] the collection of nodes added.
|
|
78
96
|
# @raise [InvalidOperation] if the trie is already compressed.
|
|
79
97
|
# @see #concat
|
|
@@ -103,7 +121,6 @@ module Rambling
|
|
|
103
121
|
# Returns all words within a string that match a word contained in the trie.
|
|
104
122
|
# @param [String] phrase the string to look for matching words in.
|
|
105
123
|
# @return [Array<String>] all the words in the given string that match a word in the trie.
|
|
106
|
-
# @yield [String] each word found in phrase.
|
|
107
124
|
def words_within phrase
|
|
108
125
|
words_within_root(phrase).to_a
|
|
109
126
|
end
|
|
@@ -130,6 +147,8 @@ module Rambling
|
|
|
130
147
|
return enum_for :each unless block_given?
|
|
131
148
|
|
|
132
149
|
root.each { |word| yield word }
|
|
150
|
+
|
|
151
|
+
self
|
|
133
152
|
end
|
|
134
153
|
|
|
135
154
|
# @return [String] a string representation of the container.
|
|
@@ -181,8 +200,8 @@ module Rambling
|
|
|
181
200
|
root.key? letter
|
|
182
201
|
end
|
|
183
202
|
|
|
184
|
-
#
|
|
185
|
-
# @return [Integer] the number of
|
|
203
|
+
# Number of words contained in the trie.
|
|
204
|
+
# @return [Integer] the number of words stored in the trie.
|
|
186
205
|
def size
|
|
187
206
|
root.size
|
|
188
207
|
end
|
|
@@ -203,13 +222,12 @@ module Rambling
|
|
|
203
222
|
return enum_for :words_within_root, phrase unless block_given?
|
|
204
223
|
|
|
205
224
|
chars = phrase.chars
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
0.upto(size - 1).each do |starting_index|
|
|
209
|
-
new_phrase = chars.slice starting_index, size # : Array[String]
|
|
225
|
+
chars.each_index do |starting_index|
|
|
226
|
+
new_phrase = chars[starting_index..] || raise
|
|
210
227
|
root.match_prefix(new_phrase) { |word| yield word }
|
|
211
|
-
end
|
|
212
|
-
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
self
|
|
213
231
|
end
|
|
214
232
|
|
|
215
233
|
def compress_root
|
|
@@ -217,7 +235,10 @@ module Rambling
|
|
|
217
235
|
end
|
|
218
236
|
|
|
219
237
|
def reversed_char_symbols word
|
|
220
|
-
|
|
238
|
+
# @type var chars: Array[String]
|
|
239
|
+
chars = word.chars
|
|
240
|
+
chars.reverse!
|
|
241
|
+
chars.map(&:to_sym)
|
|
221
242
|
end
|
|
222
243
|
end
|
|
223
244
|
end
|
|
@@ -6,10 +6,6 @@ module Rambling
|
|
|
6
6
|
module Enumerable
|
|
7
7
|
include ::Enumerable
|
|
8
8
|
|
|
9
|
-
# Empty enumerator constant for early each exits.
|
|
10
|
-
EMPTY_ENUMERATOR = [] # : Array[String]
|
|
11
|
-
.to_enum :each
|
|
12
|
-
|
|
13
9
|
# Returns number of words contained in the trie
|
|
14
10
|
# @see https://ruby-doc.org/3.3.0/Enumerable.html#method-i-count Enumerable#count
|
|
15
11
|
alias_method :size, :count
|
|
@@ -26,6 +22,14 @@ module Rambling
|
|
|
26
22
|
|
|
27
23
|
self
|
|
28
24
|
end
|
|
25
|
+
|
|
26
|
+
# Returns a new empty enumerator for early-exit returns.
|
|
27
|
+
# A method rather than a constant to prevent shared mutable state.
|
|
28
|
+
def empty_enum
|
|
29
|
+
# @type var empty_array: Array[String]
|
|
30
|
+
empty_array = []
|
|
31
|
+
empty_array.each
|
|
32
|
+
end
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
end
|
|
@@ -19,10 +19,10 @@ module Rambling
|
|
|
19
19
|
|
|
20
20
|
# Always raises {Rambling::Trie::InvalidOperation InvalidOperation} when
|
|
21
21
|
# trying to add a word to the current compressed trie node
|
|
22
|
-
# @param [
|
|
23
|
-
# @
|
|
24
|
-
# @
|
|
25
|
-
def add
|
|
22
|
+
# @param [Array<Symbol>] _word the word chars to add to the trie.
|
|
23
|
+
# @param [Object, nil] _value the value to associate with the word.
|
|
24
|
+
# @raise [InvalidOperation] always.
|
|
25
|
+
def add _word, _value = nil
|
|
26
26
|
raise Rambling::Trie::InvalidOperation, 'Cannot add word to compressed trie'
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -42,12 +42,12 @@ module Rambling
|
|
|
42
42
|
|
|
43
43
|
if chars.size >= child_letter.size
|
|
44
44
|
letter = (chars.shift(child_letter.size) || raise).join
|
|
45
|
-
return
|
|
46
|
-
end
|
|
45
|
+
return false unless child_letter == letter
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
child.partial_word? chars
|
|
48
|
+
else
|
|
49
|
+
child_letter.start_with? chars.join
|
|
50
|
+
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def word_chars? chars
|
|
@@ -75,29 +75,37 @@ module Rambling
|
|
|
75
75
|
|
|
76
76
|
child_letter = child.letter.to_s
|
|
77
77
|
|
|
78
|
-
if chars.size
|
|
79
|
-
|
|
80
|
-
return child.scan chars if child_letter == letter
|
|
78
|
+
if chars.size < child_letter.size
|
|
79
|
+
return child_letter.start_with?(chars.join) ? child : missing
|
|
81
80
|
end
|
|
82
81
|
|
|
83
|
-
letter = chars.join
|
|
84
|
-
|
|
82
|
+
letter = (chars.shift(child_letter.size) || raise).join
|
|
83
|
+
return missing unless child_letter == letter
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
child.scan chars
|
|
87
86
|
end
|
|
88
87
|
|
|
89
88
|
def children_match_prefix chars
|
|
90
89
|
return enum_for :children_match_prefix, chars unless block_given?
|
|
91
90
|
|
|
92
|
-
return
|
|
91
|
+
return empty_enum if chars.empty?
|
|
93
92
|
|
|
94
93
|
child = children_tree[(chars.first || raise).to_sym]
|
|
95
|
-
return
|
|
94
|
+
return empty_enum unless child
|
|
96
95
|
|
|
96
|
+
match_child_prefix(child, chars) { |word| yield word }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def match_child_prefix child, chars
|
|
97
100
|
child_letter = child.letter.to_s
|
|
101
|
+
|
|
102
|
+
# stop early if we already know that the remaining characters in the
|
|
103
|
+
# given phrase do not even cover the current node's compressed key
|
|
104
|
+
return empty_enum if chars.size < child_letter.size
|
|
105
|
+
|
|
98
106
|
letter = (chars.shift(child_letter.size) || raise).join
|
|
99
107
|
|
|
100
|
-
return
|
|
108
|
+
return empty_enum unless child_letter == letter
|
|
101
109
|
|
|
102
110
|
child.match_prefix(chars) { |word| yield word }
|
|
103
111
|
end
|
|
@@ -5,6 +5,23 @@ module Rambling
|
|
|
5
5
|
module Nodes
|
|
6
6
|
# A representation of a missing node in the trie data structure. Returned when a node is not found.
|
|
7
7
|
class Missing < Rambling::Trie::Nodes::Node
|
|
8
|
+
def partial_word? _
|
|
9
|
+
false
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def word_chars? _
|
|
15
|
+
false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def closest_node _
|
|
19
|
+
self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def children_match_prefix chars
|
|
23
|
+
enum_for :children_match_prefix, chars unless block_given?
|
|
24
|
+
end
|
|
8
25
|
end
|
|
9
26
|
end
|
|
10
27
|
end
|
|
@@ -7,6 +7,7 @@ module Rambling
|
|
|
7
7
|
# :reek:MissingSafeMethod { exclude: [ terminal! ] }
|
|
8
8
|
# :reek:RepeatedConditional { max_ifs: 3 }
|
|
9
9
|
class Node
|
|
10
|
+
include NotImplemented
|
|
10
11
|
include Rambling::Trie::Compressible
|
|
11
12
|
include Rambling::Trie::Enumerable
|
|
12
13
|
include Rambling::Trie::Comparable
|
|
@@ -32,17 +33,19 @@ module Rambling
|
|
|
32
33
|
attr_accessor :parent
|
|
33
34
|
|
|
34
35
|
# Arbitrary value stored in this node
|
|
35
|
-
# @return [TValue, nil] the
|
|
36
|
+
# @return [TValue, nil] the value stored in this node.
|
|
36
37
|
attr_accessor :value
|
|
37
38
|
|
|
38
39
|
# Creates a new node.
|
|
39
40
|
# @param [Symbol, nil] letter the Node's letter value.
|
|
40
41
|
# @param [Node, nil] parent the parent of the current node.
|
|
41
|
-
# @param [Hash<Symbol, Node
|
|
42
|
-
|
|
42
|
+
# @param [Hash<Symbol, Node>, nil] children_tree the children tree of the current node,
|
|
43
|
+
# or +nil+ to start with an empty tree. When a hash is provided, ownership transfers
|
|
44
|
+
# to the node; callers must not retain references to or mutate the hash after passing it.
|
|
45
|
+
def initialize letter = nil, parent = nil, children_tree = nil
|
|
43
46
|
@letter = letter
|
|
44
47
|
@parent = parent
|
|
45
|
-
@children_tree = children_tree
|
|
48
|
+
@children_tree = children_tree || {}
|
|
46
49
|
end
|
|
47
50
|
|
|
48
51
|
# Child nodes.
|
|
@@ -54,13 +57,7 @@ module Rambling
|
|
|
54
57
|
# First child node.
|
|
55
58
|
# @return [Node, nil] the first child contained in the current node.
|
|
56
59
|
def first_child
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
# rubocop:disable Lint/UnreachableLoop
|
|
60
|
-
children_tree.each_value { |child| return child }
|
|
61
|
-
# rubocop:enable Lint/UnreachableLoop
|
|
62
|
-
|
|
63
|
-
nil
|
|
60
|
+
children_tree.each_value.first
|
|
64
61
|
end
|
|
65
62
|
|
|
66
63
|
# Indicates if the current node is the root node.
|
|
@@ -137,7 +134,7 @@ module Rambling
|
|
|
137
134
|
end
|
|
138
135
|
|
|
139
136
|
# Set the {Node Node} that corresponds to a given letter.
|
|
140
|
-
# @param [Symbol] letter the letter to insert or update in the node's
|
|
137
|
+
# @param [Symbol] letter the letter to insert or update in the node's children tree.
|
|
141
138
|
# @param [Node] node the {Node Node} to assign to that letter.
|
|
142
139
|
# @return [Node] the node corresponding to the inserted or updated letter.
|
|
143
140
|
# @see https://ruby-doc.org/3.3.0/Hash.html#method-i-5B-5D Hash#[]
|
|
@@ -174,22 +171,28 @@ module Rambling
|
|
|
174
171
|
|
|
175
172
|
attr_accessor :terminal
|
|
176
173
|
|
|
177
|
-
# abstract
|
|
178
|
-
|
|
179
|
-
def children_match_prefix
|
|
180
|
-
|
|
174
|
+
# @abstract Subclass and override {#children_match_prefix} to match a prefix against child nodes.
|
|
175
|
+
# @raise [NotImplementedError] when not overridden by a subclass
|
|
176
|
+
def children_match_prefix _chars
|
|
177
|
+
not_implemented
|
|
181
178
|
end
|
|
182
179
|
|
|
183
|
-
|
|
184
|
-
|
|
180
|
+
# @abstract Subclass and override {#partial_word_chars?} to check for a partial-word path.
|
|
181
|
+
# @raise [NotImplementedError] when not overridden by a subclass
|
|
182
|
+
def partial_word_chars? _chars
|
|
183
|
+
not_implemented
|
|
185
184
|
end
|
|
186
185
|
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
# @abstract Subclass and override {#word_chars?} to check for a full-word path.
|
|
187
|
+
# @raise [NotImplementedError] when not overridden by a subclass
|
|
188
|
+
def word_chars? _chars
|
|
189
|
+
not_implemented
|
|
189
190
|
end
|
|
190
191
|
|
|
191
|
-
|
|
192
|
-
|
|
192
|
+
# @abstract Subclass and override {#closest_node} to return the deepest matching node.
|
|
193
|
+
# @raise [NotImplementedError] when not overridden by a subclass
|
|
194
|
+
def closest_node _chars
|
|
195
|
+
not_implemented
|
|
193
196
|
end
|
|
194
197
|
end
|
|
195
198
|
end
|
|
@@ -9,7 +9,7 @@ module Rambling
|
|
|
9
9
|
# Adds a word to the current raw (uncompressed) trie node.
|
|
10
10
|
# @param [Array<Symbol>] reversed_chars the char array to add to the trie, in reverse order.
|
|
11
11
|
# @return [Node] the added/modified node based on the word added.
|
|
12
|
-
# @note This method
|
|
12
|
+
# @note This method consumes the array by popping each element during recursion, leaving it empty on return.
|
|
13
13
|
def add reversed_chars, value = nil
|
|
14
14
|
if reversed_chars.empty?
|
|
15
15
|
unless root?
|
|
@@ -70,10 +70,10 @@ module Rambling
|
|
|
70
70
|
def children_match_prefix chars
|
|
71
71
|
return enum_for :children_match_prefix, chars unless block_given?
|
|
72
72
|
|
|
73
|
-
return
|
|
73
|
+
return empty_enum if chars.empty?
|
|
74
74
|
|
|
75
75
|
child = children_tree[(chars.shift || raise).to_sym]
|
|
76
|
-
return
|
|
76
|
+
return empty_enum unless child
|
|
77
77
|
|
|
78
78
|
child.match_prefix(chars) { |word| yield word }
|
|
79
79
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rambling
|
|
4
|
+
# :reek:IrresponsibleModule (unclear why this is necessary here but not in other submodules)
|
|
5
|
+
module Trie
|
|
6
|
+
# Provides a private helper for marking abstract methods.
|
|
7
|
+
# @api private
|
|
8
|
+
module NotImplemented
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# Raises {NotImplementedError} with the concrete class and calling method name.
|
|
12
|
+
# @raise [NotImplementedError] always, with message
|
|
13
|
+
# <code>"ClassName#method_name is not implemented"</code>
|
|
14
|
+
# @return [void]
|
|
15
|
+
def not_implemented
|
|
16
|
+
raise NotImplementedError,
|
|
17
|
+
"#{self.class}##{caller_locations(1, 1)&.first&.label} is not implemented"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private_constant :NotImplemented
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -12,7 +12,10 @@ module Rambling
|
|
|
12
12
|
def each_word filepath
|
|
13
13
|
return enum_for :each_word, filepath unless block_given?
|
|
14
14
|
|
|
15
|
-
::File.foreach(filepath)
|
|
15
|
+
::File.foreach(filepath) do |line|
|
|
16
|
+
line.chomp!
|
|
17
|
+
yield line
|
|
18
|
+
end
|
|
16
19
|
|
|
17
20
|
self
|
|
18
21
|
end
|
|
@@ -5,13 +5,16 @@ module Rambling
|
|
|
5
5
|
module Readers
|
|
6
6
|
# Base class for all readers.
|
|
7
7
|
class Reader
|
|
8
|
+
include NotImplemented
|
|
9
|
+
|
|
8
10
|
# Yields each word read from given file.
|
|
9
11
|
# @abstract Subclass and override {#each_word} to fit to a particular file format.
|
|
10
12
|
# @param [String] filepath the full path of the file to load the words from.
|
|
11
13
|
# @yield [String] Each line read from the file.
|
|
12
14
|
# @return [self]
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
# @raise [NotImplementedError] when not overridden by a subclass
|
|
16
|
+
def each_word _filepath
|
|
17
|
+
not_implemented
|
|
15
18
|
end
|
|
16
19
|
end
|
|
17
20
|
end
|
|
@@ -19,6 +19,11 @@ module Rambling
|
|
|
19
19
|
# @note Use of {https://ruby-doc.org/3.3.0/Marshal.html#method-c-load Marshal.load} is generally
|
|
20
20
|
# discouraged. Only use this with trusted input.
|
|
21
21
|
def load filepath
|
|
22
|
+
warn <<~WARN.chomp.tr("\n", ' ')
|
|
23
|
+
WARNING: Marshal.load is being used to deserialize trie data.
|
|
24
|
+
Loading untrusted input via Marshal.load can execute arbitrary code.
|
|
25
|
+
Only load Marshal data from trusted sources.
|
|
26
|
+
WARN
|
|
22
27
|
::Marshal.load serializer.load filepath
|
|
23
28
|
end
|
|
24
29
|
|
|
@@ -5,12 +5,15 @@ module Rambling
|
|
|
5
5
|
module Serializers
|
|
6
6
|
# Base class for all serializers.
|
|
7
7
|
class Serializer
|
|
8
|
+
include NotImplemented
|
|
9
|
+
|
|
8
10
|
# Loads contents from a specified filepath.
|
|
9
11
|
# @abstract Subclass and override {#load} to parse the desired format.
|
|
10
12
|
# @param [String] filepath the filepath to load contents from.
|
|
11
13
|
# @return [TContents] parsed contents from given file.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
# @raise [NotImplementedError] when not overridden by a subclass
|
|
15
|
+
def load _filepath
|
|
16
|
+
not_implemented
|
|
14
17
|
end
|
|
15
18
|
|
|
16
19
|
# Dumps contents into a specified filepath.
|
|
@@ -18,8 +21,9 @@ module Rambling
|
|
|
18
21
|
# @param [TContents] contents the contents to dump into given file.
|
|
19
22
|
# @param [String] filepath the filepath to dump the contents to.
|
|
20
23
|
# @return [Numeric] number of bytes written to disk.
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
# @raise [NotImplementedError] when not overridden by a subclass
|
|
25
|
+
def dump _contents, _filepath
|
|
26
|
+
not_implemented
|
|
23
27
|
end
|
|
24
28
|
end
|
|
25
29
|
end
|
|
@@ -17,6 +17,11 @@ module Rambling
|
|
|
17
17
|
# @return [Nodes::Node] The deserialized {Nodes::Node Node}.
|
|
18
18
|
# @see https://ruby-doc.org/3.3.0/exts/psych/Psych.html#method-c-safe_load Psych.safe_load
|
|
19
19
|
def load filepath
|
|
20
|
+
warn <<~WARN.chomp.tr("\n", ' ')
|
|
21
|
+
WARNING: YAML aliases are enabled.
|
|
22
|
+
Loading untrusted YAML with aliases: true can trigger a billion-laughs memory attack.
|
|
23
|
+
Only load YAML data from trusted sources.
|
|
24
|
+
WARN
|
|
20
25
|
require 'yaml'
|
|
21
26
|
::YAML.safe_load(
|
|
22
27
|
serializer.load(filepath),
|
|
@@ -18,47 +18,47 @@ module Rambling
|
|
|
18
18
|
# Unzip contents from specified filepath and load in contents from
|
|
19
19
|
# unzipped files.
|
|
20
20
|
# @param [String] filepath the filepath to load contents from.
|
|
21
|
-
# @return [
|
|
21
|
+
# @return [Nodes::Node] all contents of the unzipped loaded file.
|
|
22
22
|
# @see https://github.com/rubyzip/rubyzip#reading-a-zip-file Zip
|
|
23
23
|
# reading a file
|
|
24
24
|
def load filepath
|
|
25
25
|
require 'zip'
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
clean_up_tmp_files do |tmp_paths|
|
|
28
|
+
::Zip::File.open filepath do |zip|
|
|
29
|
+
entry = zip.entries.first
|
|
30
|
+
raise unless entry
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
entry_name = entry.name
|
|
33
|
+
entry_path = path_with_random_prefix entry_name
|
|
34
|
+
tmp_paths << entry_path
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
raise unless serializer
|
|
36
|
+
entry.extract ::File.basename(entry_path), destination_directory: tmp_path
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
(serializers.resolve(entry_name) || raise).load entry_path
|
|
39
|
+
end
|
|
39
40
|
end
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
# Dumps contents and zips into a specified filepath.
|
|
43
44
|
# @param [String] contents the contents to dump.
|
|
44
45
|
# @param [String] filepath the filepath to dump the contents to.
|
|
45
|
-
# @return [
|
|
46
|
+
# @return [Integer] number of bytes written to disk.
|
|
46
47
|
# @see https://github.com/rubyzip/rubyzip#basic-zip-archive-creation
|
|
47
48
|
# Zip archive creation
|
|
48
49
|
def dump contents, filepath
|
|
49
50
|
require 'zip'
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
clean_up_tmp_files do |tmp_paths|
|
|
53
|
+
::Zip::File.open filepath, create: true do |zip|
|
|
54
|
+
filename = ::File.basename filepath, '.zip'
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
entry_path = path_with_random_prefix filename
|
|
57
|
+
tmp_paths << entry_path
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
zip.add filename, entry_path
|
|
59
|
+
(serializers.resolve(filename) || raise).dump contents, entry_path
|
|
60
|
+
zip.add filename, entry_path
|
|
61
|
+
end
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
::File.size filepath
|
|
@@ -76,10 +76,20 @@ module Rambling
|
|
|
76
76
|
properties.tmp_path
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
-
def
|
|
79
|
+
def path_with_random_prefix filename
|
|
80
80
|
require 'securerandom'
|
|
81
81
|
::File.join tmp_path, "#{SecureRandom.uuid}-#{filename}"
|
|
82
82
|
end
|
|
83
|
+
|
|
84
|
+
def clean_up_tmp_files
|
|
85
|
+
# @type var tmp_paths: Array[String]
|
|
86
|
+
tmp_paths = []
|
|
87
|
+
begin
|
|
88
|
+
yield tmp_paths
|
|
89
|
+
ensure
|
|
90
|
+
tmp_paths.each { |path| ::FileUtils.rm_f path }
|
|
91
|
+
end
|
|
92
|
+
end
|
|
83
93
|
end
|
|
84
94
|
end
|
|
85
95
|
end
|
|
@@ -6,12 +6,9 @@ module Rambling
|
|
|
6
6
|
module Stringifyable
|
|
7
7
|
# String representation of the current node, if it is a terminal node.
|
|
8
8
|
# @return [String] the string representation of the current node.
|
|
9
|
-
# @raise [InvalidOperation] if node
|
|
9
|
+
# @raise [InvalidOperation] if the node has a letter and is not terminal.
|
|
10
10
|
def as_word
|
|
11
|
-
if letter && !terminal?
|
|
12
|
-
raise Rambling::Trie::InvalidOperation,
|
|
13
|
-
'Cannot represent branch as a word'
|
|
14
|
-
end
|
|
11
|
+
raise Rambling::Trie::InvalidOperation, 'Cannot represent branch as a word' if letter && !terminal?
|
|
15
12
|
|
|
16
13
|
to_s
|
|
17
14
|
end
|
data/lib/rambling/trie.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
path = File.join 'rambling', 'trie'
|
|
4
4
|
%w(
|
|
5
|
-
comparable compressible compressor configuration container enumerable inspectable invalid_operation
|
|
5
|
+
comparable compressible compressor configuration container enumerable inspectable invalid_operation not_implemented
|
|
6
6
|
readers serializers stringifyable nodes version
|
|
7
7
|
).each { |file| require File.join(path, file) }
|
|
8
8
|
|
|
@@ -10,6 +10,9 @@ path = File.join 'rambling', 'trie'
|
|
|
10
10
|
module Rambling
|
|
11
11
|
# Entry point for `rambling-trie` API.
|
|
12
12
|
module Trie
|
|
13
|
+
PROPERTIES_MUTEX = Mutex.new
|
|
14
|
+
private_constant :PROPERTIES_MUTEX
|
|
15
|
+
|
|
13
16
|
class << self
|
|
14
17
|
# Creates a new `Rambling::Trie`. Entry point for the `rambling-trie` API.
|
|
15
18
|
# @param [String, nil] filepath the file to load the words from.
|
|
@@ -21,11 +24,9 @@ module Rambling
|
|
|
21
24
|
root = root_builder.call
|
|
22
25
|
|
|
23
26
|
Rambling::Trie::Container.new root, compressor do |container|
|
|
24
|
-
# noinspection RubyMismatchedArgumentType
|
|
25
27
|
if filepath
|
|
26
|
-
reader
|
|
27
|
-
|
|
28
|
-
(reader || raise).each_word(filepath) { |word| container << word }
|
|
28
|
+
input_reader = reader || readers.resolve(filepath) || raise(ArgumentError, "no reader for #{filepath}")
|
|
29
|
+
input_reader.each_word(filepath) { |word| container << word }
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
yield container if block_given? # steep:ignore
|
|
@@ -62,7 +63,6 @@ module Rambling
|
|
|
62
63
|
# @see Serializers Serializers.
|
|
63
64
|
def dump trie, filepath, serializer = nil
|
|
64
65
|
serializer ||= serializers.resolve filepath
|
|
65
|
-
# noinspection RubyNilAnalysis
|
|
66
66
|
(serializer || raise).dump trie.root, filepath
|
|
67
67
|
end
|
|
68
68
|
|
|
@@ -77,7 +77,11 @@ module Rambling
|
|
|
77
77
|
private
|
|
78
78
|
|
|
79
79
|
def properties
|
|
80
|
-
@properties
|
|
80
|
+
return @properties if @properties
|
|
81
|
+
|
|
82
|
+
PROPERTIES_MUTEX.synchronize do
|
|
83
|
+
@properties ||= Rambling::Trie::Configuration::Properties.new
|
|
84
|
+
end
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
def readers
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
module Rambling
|
|
2
2
|
module Trie
|
|
3
|
-
module Comparable[TValue < _Inspect]
|
|
3
|
+
module Comparable[TValue < BasicObject & _Inspect & _Nilable]
|
|
4
4
|
def ==: (Nodes::Node[TValue]) -> bool
|
|
5
5
|
|
|
6
6
|
private
|
|
7
7
|
|
|
8
8
|
# abstract methods
|
|
9
9
|
|
|
10
|
-
def letter: -> Symbol
|
|
10
|
+
def letter: -> Symbol?
|
|
11
|
+
|
|
12
|
+
def value: -> TValue?
|
|
11
13
|
|
|
12
14
|
def terminal?: -> bool
|
|
13
15
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Rambling
|
|
2
2
|
module Trie
|
|
3
3
|
module Configuration
|
|
4
|
-
class Properties[TValue < _Inspect]
|
|
4
|
+
class Properties[TValue < BasicObject & _Inspect & _Nilable]
|
|
5
5
|
attr_reader readers: ProviderCollection[Readers::Reader]
|
|
6
6
|
attr_reader serializers: ProviderCollection[Serializers::Serializer[Nodes::Node[TValue]]]
|
|
7
7
|
attr_accessor compressor: Compressor[TValue]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Rambling
|
|
2
2
|
module Trie
|
|
3
|
-
class Container[TValue < _Inspect]
|
|
3
|
+
class Container[TValue < BasicObject & _Inspect & _Nilable]
|
|
4
4
|
include ::Enumerable[String]
|
|
5
5
|
|
|
6
6
|
@compressor: Compressor[TValue]
|
|
@@ -17,15 +17,16 @@ module Rambling
|
|
|
17
17
|
|
|
18
18
|
def compress: -> Container[TValue]
|
|
19
19
|
|
|
20
|
-
def each: { (String) -> void } ->
|
|
20
|
+
def each: { (String) -> void } -> Container[TValue]
|
|
21
|
+
| -> Enumerator[String, void]
|
|
21
22
|
|
|
22
|
-
def partial_word?: (String) -> bool
|
|
23
|
+
def partial_word?: (?String) -> bool
|
|
23
24
|
|
|
24
25
|
def push: (*String) -> Array[Nodes::Node[TValue]]
|
|
25
26
|
|
|
26
|
-
def word?: (String) -> bool
|
|
27
|
+
def word?: (?String) -> bool
|
|
27
28
|
|
|
28
|
-
def scan: (String) -> Array[String]
|
|
29
|
+
def scan: (?String) -> Array[String]
|
|
29
30
|
|
|
30
31
|
def words_within: (String) -> Array[String]
|
|
31
32
|
|
|
@@ -45,11 +46,11 @@ module Rambling
|
|
|
45
46
|
|
|
46
47
|
def key?: (Symbol) -> bool
|
|
47
48
|
|
|
48
|
-
def size: ->
|
|
49
|
+
def size: -> Integer
|
|
49
50
|
|
|
50
51
|
alias include? word?
|
|
51
52
|
alias match? partial_word?
|
|
52
|
-
alias words
|
|
53
|
+
alias words scan
|
|
53
54
|
alias << add
|
|
54
55
|
alias has_key? key?
|
|
55
56
|
alias has_letter? key?
|
|
@@ -59,7 +60,7 @@ module Rambling
|
|
|
59
60
|
attr_reader compressor: Compressor[TValue]
|
|
60
61
|
attr_writer root: Nodes::Node[TValue]
|
|
61
62
|
|
|
62
|
-
def words_within_root: (String) ?{ (String) -> void } -> Enumerator[String, void]
|
|
63
|
+
def words_within_root: (String) ?{ (String) -> void } -> (Container[TValue] | Enumerator[String, void])
|
|
63
64
|
|
|
64
65
|
def compress_root: -> Nodes::Compressed[TValue]
|
|
65
66
|
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
module Rambling
|
|
2
2
|
module Trie
|
|
3
|
-
module Enumerable[TValue < _Inspect]
|
|
3
|
+
module Enumerable[TValue < BasicObject & _Inspect & _Nilable]
|
|
4
4
|
include ::Enumerable[String]
|
|
5
5
|
|
|
6
|
-
EMPTY_ENUMERATOR: Enumerator[String, void]
|
|
7
|
-
|
|
8
6
|
alias size count
|
|
9
7
|
|
|
10
|
-
def each: { (String) -> void } ->
|
|
8
|
+
def each: { (String) -> void } -> Enumerable[TValue]
|
|
9
|
+
| -> Enumerator[String, void]
|
|
11
10
|
|
|
12
11
|
private
|
|
13
12
|
|
|
@@ -15,6 +14,8 @@ module Rambling
|
|
|
15
14
|
|
|
16
15
|
def as_word: -> String
|
|
17
16
|
|
|
17
|
+
def empty_enum: -> Enumerator[String, void]
|
|
18
|
+
|
|
18
19
|
def terminal?: -> bool
|
|
19
20
|
|
|
20
21
|
def children_tree: -> Hash[Symbol, Nodes::Node[TValue]]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Rambling
|
|
2
2
|
module Trie
|
|
3
|
-
module Inspectable[TValue < _Inspect]
|
|
3
|
+
module Inspectable[TValue < BasicObject & _Inspect & _Nilable]
|
|
4
4
|
|
|
5
5
|
def inspect: -> String
|
|
6
6
|
|
|
@@ -20,9 +20,9 @@ module Rambling
|
|
|
20
20
|
|
|
21
21
|
# abstract methods
|
|
22
22
|
|
|
23
|
-
def letter: -> Symbol
|
|
23
|
+
def letter: -> Symbol?
|
|
24
24
|
|
|
25
|
-
def value: -> TValue
|
|
25
|
+
def value: -> TValue?
|
|
26
26
|
|
|
27
27
|
def terminal: -> bool?
|
|
28
28
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module Rambling
|
|
2
2
|
module Trie
|
|
3
3
|
module Nodes
|
|
4
|
-
class Compressed[TValue < _Inspect] < Node[TValue]
|
|
4
|
+
class Compressed[TValue < BasicObject & _Inspect & _Nilable] < Node[TValue]
|
|
5
5
|
def initialize: (?Symbol?, ?Node[TValue]?, ?Hash[Symbol, Node[TValue]]) -> void
|
|
6
6
|
|
|
7
|
-
def add: (Array[Symbol], ?TValue) -> Node[TValue]
|
|
7
|
+
def add: (Array[Symbol], ?TValue?) -> Node[TValue]
|
|
8
8
|
|
|
9
9
|
def compressed?: -> bool
|
|
10
10
|
|
|
@@ -14,6 +14,8 @@ module Rambling
|
|
|
14
14
|
|
|
15
15
|
def children_match_prefix: (Array[String]) { (String) -> void } -> Enumerator[String, void]
|
|
16
16
|
|
|
17
|
+
def match_child_prefix: (Node[TValue], Array[String]) { (String) -> void } -> Enumerator[String, void]
|
|
18
|
+
|
|
17
19
|
def partial_word_chars?: (Array[String]) -> bool
|
|
18
20
|
|
|
19
21
|
def word_chars?: (Array[String]) -> bool
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
module Rambling
|
|
2
2
|
module Trie
|
|
3
3
|
module Nodes
|
|
4
|
-
class Missing[TValue < _Inspect] < Node[TValue]
|
|
4
|
+
class Missing[TValue < BasicObject & _Inspect & _Nilable] < Node[TValue]
|
|
5
5
|
def initialize: -> void
|
|
6
|
+
def partial_word?: (Array[String] chars) -> bool
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def word_chars?: (Array[String] chars) -> bool
|
|
11
|
+
def closest_node: (Array[String] chars) -> Node[TValue]
|
|
12
|
+
def children_match_prefix: (Array[String] chars) -> void
|
|
13
|
+
| (Array[String] chars) { (String word) -> void } -> void
|
|
6
14
|
end
|
|
7
15
|
end
|
|
8
16
|
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
module Rambling
|
|
2
2
|
module Trie
|
|
3
3
|
module Nodes
|
|
4
|
-
class Node[TValue < _Inspect]
|
|
4
|
+
class Node[TValue < BasicObject & _Inspect & _Nilable]
|
|
5
|
+
include NotImplemented
|
|
5
6
|
include Compressible[TValue]
|
|
6
7
|
include Enumerable[TValue]
|
|
7
8
|
include Comparable[TValue]
|
|
@@ -13,7 +14,7 @@ module Rambling
|
|
|
13
14
|
attr_accessor parent: Node[TValue]?
|
|
14
15
|
attr_accessor value: TValue?
|
|
15
16
|
|
|
16
|
-
def initialize: (?Symbol?, ?Node[TValue]?, ?Hash[Symbol, Node[TValue]]) -> void
|
|
17
|
+
def initialize: (?Symbol?, ?Node[TValue]?, ?Hash[Symbol, Node[TValue]]?) -> void
|
|
17
18
|
|
|
18
19
|
def add: (Array[Symbol], ?TValue?) -> Node[TValue]
|
|
19
20
|
|
|
@@ -2,7 +2,7 @@ module Rambling
|
|
|
2
2
|
module Trie
|
|
3
3
|
module Readers
|
|
4
4
|
class PlainText < Reader
|
|
5
|
-
def each_word: (String) { (String
|
|
5
|
+
def each_word: (String) { (String) -> void } -> (Enumerator[String, void] | PlainText)
|
|
6
6
|
end
|
|
7
7
|
end
|
|
8
8
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Rambling
|
|
2
2
|
module Trie
|
|
3
3
|
module Serializers
|
|
4
|
-
class Zip[TValue < _Inspect] < Serializer[Nodes::Node[TValue]]
|
|
4
|
+
class Zip[TValue < BasicObject & _Inspect & _Nilable] < Serializer[Nodes::Node[TValue]]
|
|
5
5
|
@properties: Configuration::Properties[TValue]
|
|
6
6
|
|
|
7
7
|
def initialize: (Configuration::Properties[TValue]) -> void
|
|
@@ -14,7 +14,9 @@ module Rambling
|
|
|
14
14
|
|
|
15
15
|
def tmp_path: -> String
|
|
16
16
|
|
|
17
|
-
def
|
|
17
|
+
def path_with_random_prefix: (String) -> String
|
|
18
|
+
|
|
19
|
+
def clean_up_tmp_files: [T] { (Array[String]) -> T } -> T
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Rambling
|
|
2
2
|
module Trie
|
|
3
|
-
module Stringifyable[TValue < _Inspect]
|
|
3
|
+
module Stringifyable[TValue < BasicObject & _Inspect & _Nilable]
|
|
4
4
|
def as_word: -> String
|
|
5
5
|
|
|
6
6
|
def to_s: -> String
|
|
@@ -9,7 +9,7 @@ module Rambling
|
|
|
9
9
|
|
|
10
10
|
# abstract methods
|
|
11
11
|
|
|
12
|
-
def letter: -> Symbol
|
|
12
|
+
def letter: -> Symbol?
|
|
13
13
|
|
|
14
14
|
def terminal?: -> bool
|
|
15
15
|
|
data/sig/lib/rambling/trie.rbs
CHANGED
|
@@ -2,24 +2,26 @@ module Rambling
|
|
|
2
2
|
module Trie
|
|
3
3
|
VERSION: String
|
|
4
4
|
|
|
5
|
-
def self.create: [TValue < _Inspect] (?String?, ?Readers::Reader?) ?{ (Container[TValue]) -> void } -> Container[TValue]
|
|
5
|
+
def self.create: [TValue < BasicObject & _Inspect & _Nilable] (?String?, ?Readers::Reader?) ?{ (Container[TValue]) -> void } -> Container[TValue]
|
|
6
6
|
|
|
7
|
-
def self.load: [TValue < _Inspect] (String, ?Serializers::Serializer[Nodes::Node[TValue]]?) ?{ (Container[TValue]) -> void } -> Container[TValue]
|
|
7
|
+
def self.load: [TValue < BasicObject & _Inspect & _Nilable] (String, ?Serializers::Serializer[Nodes::Node[TValue]]?) ?{ (Container[TValue]) -> void } -> Container[TValue]
|
|
8
8
|
|
|
9
|
-
def self.dump: [TValue < _Inspect] (Container[TValue], String, ?Serializers::Serializer[Nodes::Node[TValue]]?) -> void
|
|
9
|
+
def self.dump: [TValue < BasicObject & _Inspect & _Nilable] (Container[TValue], String, ?Serializers::Serializer[Nodes::Node[TValue]]?) -> void
|
|
10
10
|
|
|
11
|
-
def self.config: [TValue < _Inspect] ?{ (Configuration::Properties[TValue]) -> void } -> Configuration::Properties[TValue]
|
|
11
|
+
def self.config: [TValue < BasicObject & _Inspect & _Nilable] ?{ (Configuration::Properties[TValue]) -> void } -> Configuration::Properties[TValue]
|
|
12
12
|
|
|
13
13
|
private
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
PROPERTIES_MUTEX: Mutex
|
|
16
|
+
|
|
17
|
+
def self.properties: [TValue < BasicObject & _Inspect & _Nilable] -> Configuration::Properties[TValue]
|
|
16
18
|
|
|
17
19
|
def self.readers: -> Configuration::ProviderCollection[Readers::Reader]
|
|
18
20
|
|
|
19
|
-
def self.serializers: [TValue < _Inspect] -> Configuration::ProviderCollection[Serializers::Serializer[Nodes::Node[TValue]]]
|
|
21
|
+
def self.serializers: [TValue < BasicObject & _Inspect & _Nilable] -> Configuration::ProviderCollection[Serializers::Serializer[Nodes::Node[TValue]]]
|
|
20
22
|
|
|
21
|
-
def self.compressor: [TValue < _Inspect] -> Compressor[TValue]
|
|
23
|
+
def self.compressor: [TValue < BasicObject & _Inspect & _Nilable] -> Compressor[TValue]
|
|
22
24
|
|
|
23
|
-
def self.root_builder: [TValue < _Inspect] -> ^() -> Nodes::Node[TValue]
|
|
25
|
+
def self.root_builder: [TValue < BasicObject & _Inspect & _Nilable] -> ^() -> Nodes::Node[TValue]
|
|
24
26
|
end
|
|
25
27
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rambling-trie
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Edgar Gonzalez
|
|
@@ -43,6 +43,7 @@ files:
|
|
|
43
43
|
- lib/rambling/trie/nodes/missing.rb
|
|
44
44
|
- lib/rambling/trie/nodes/node.rb
|
|
45
45
|
- lib/rambling/trie/nodes/raw.rb
|
|
46
|
+
- lib/rambling/trie/not_implemented.rb
|
|
46
47
|
- lib/rambling/trie/readers.rb
|
|
47
48
|
- lib/rambling/trie/readers/plain_text.rb
|
|
48
49
|
- lib/rambling/trie/readers/reader.rb
|
|
@@ -70,6 +71,7 @@ files:
|
|
|
70
71
|
- sig/lib/rambling/trie/nodes/missing.rbs
|
|
71
72
|
- sig/lib/rambling/trie/nodes/node.rbs
|
|
72
73
|
- sig/lib/rambling/trie/nodes/raw.rbs
|
|
74
|
+
- sig/lib/rambling/trie/not_implemented.rbs
|
|
73
75
|
- sig/lib/rambling/trie/readers/plain_text.rbs
|
|
74
76
|
- sig/lib/rambling/trie/readers/reader.rbs
|
|
75
77
|
- sig/lib/rambling/trie/serializers/file.rbs
|
|
@@ -78,8 +80,6 @@ files:
|
|
|
78
80
|
- sig/lib/rambling/trie/serializers/yaml.rbs
|
|
79
81
|
- sig/lib/rambling/trie/serializers/zip.rbs
|
|
80
82
|
- sig/lib/rambling/trie/stringifyable.rbs
|
|
81
|
-
- sig/lib/zip/entry.rbs
|
|
82
|
-
- sig/lib/zip/file.rbs
|
|
83
83
|
homepage: https://github.com/gonzedge/rambling-trie
|
|
84
84
|
licenses:
|
|
85
85
|
- MIT
|
|
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
104
104
|
- !ruby/object:Gem::Version
|
|
105
105
|
version: '0'
|
|
106
106
|
requirements: []
|
|
107
|
-
rubygems_version: 4.0.
|
|
107
|
+
rubygems_version: 4.0.6
|
|
108
108
|
specification_version: 4
|
|
109
109
|
summary: A Ruby implementation of the trie data structure.
|
|
110
110
|
test_files: []
|
data/sig/lib/zip/entry.rbs
DELETED