rambling-trie 2.4.0 → 2.5.1

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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +28 -0
  3. data/Gemfile +20 -8
  4. data/Guardfile +16 -5
  5. data/README.md +38 -32
  6. data/Rakefile +6 -0
  7. data/Steepfile +35 -0
  8. data/lib/rambling/trie/comparable.rb +2 -2
  9. data/lib/rambling/trie/compressible.rb +1 -1
  10. data/lib/rambling/trie/compressor.rb +22 -19
  11. data/lib/rambling/trie/configuration/properties.rb +10 -6
  12. data/lib/rambling/trie/configuration/provider_collection.rb +14 -9
  13. data/lib/rambling/trie/configuration.rb +2 -3
  14. data/lib/rambling/trie/container.rb +32 -24
  15. data/lib/rambling/trie/enumerable.rb +5 -6
  16. data/lib/rambling/trie/nodes/compressed.rb +26 -16
  17. data/lib/rambling/trie/nodes/node.rb +35 -12
  18. data/lib/rambling/trie/nodes/raw.rb +18 -20
  19. data/lib/rambling/trie/nodes.rb +2 -3
  20. data/lib/rambling/trie/readers/plain_text.rb +3 -3
  21. data/lib/rambling/trie/readers.rb +2 -3
  22. data/lib/rambling/trie/serializers/file.rb +1 -3
  23. data/lib/rambling/trie/serializers/marshal.rb +4 -4
  24. data/lib/rambling/trie/serializers/yaml.rb +3 -3
  25. data/lib/rambling/trie/serializers/zip.rb +13 -5
  26. data/lib/rambling/trie/serializers.rb +2 -3
  27. data/lib/rambling/trie/stringifyable.rb +1 -1
  28. data/lib/rambling/trie/version.rb +1 -1
  29. data/lib/rambling/trie.rb +12 -15
  30. data/rambling-trie.gemspec +4 -10
  31. data/sig/lib/rambling/trie/comparable.rbs +17 -0
  32. data/sig/lib/rambling/trie/compressible.rbs +17 -0
  33. data/sig/lib/rambling/trie/compressor.rbs +17 -0
  34. data/sig/lib/rambling/trie/configuration/properties.rbs +28 -0
  35. data/sig/lib/rambling/trie/configuration/provider_collection.rbs +47 -0
  36. data/sig/lib/rambling/trie/container.rbs +69 -0
  37. data/sig/lib/rambling/trie/enumerable.rbs +23 -0
  38. data/sig/lib/rambling/trie/inspectable.rbs +27 -0
  39. data/sig/lib/rambling/trie/invalid_operation.rbs +7 -0
  40. data/sig/lib/rambling/trie/nodes/compressed.rbs +25 -0
  41. data/sig/lib/rambling/trie/nodes/missing.rbs +9 -0
  42. data/sig/lib/rambling/trie/nodes/node.rbs +69 -0
  43. data/sig/lib/rambling/trie/nodes/raw.rbs +27 -0
  44. data/sig/lib/rambling/trie/readers/plain_text.rbs +9 -0
  45. data/sig/lib/rambling/trie/readers/reader.rbs +9 -0
  46. data/sig/lib/rambling/trie/serializers/file.rbs +8 -0
  47. data/sig/lib/rambling/trie/serializers/marshal.rbs +13 -0
  48. data/sig/lib/rambling/trie/serializers/serializer.rbs +10 -0
  49. data/sig/lib/rambling/trie/serializers/yaml.rbs +13 -0
  50. data/sig/lib/rambling/trie/serializers/zip.rbs +21 -0
  51. data/sig/lib/rambling/trie/stringifyable.rbs +21 -0
  52. data/sig/lib/rambling/trie.rbs +27 -0
  53. data/sig/lib/zip/entry.rbs +11 -0
  54. data/sig/lib/zip/file.rbs +11 -0
  55. metadata +34 -123
  56. data/spec/assets/test_words.en_US.txt +0 -23
  57. data/spec/assets/test_words.es_DO.txt +0 -24
  58. data/spec/integration/rambling/trie_spec.rb +0 -116
  59. data/spec/lib/rambling/trie/comparable_spec.rb +0 -87
  60. data/spec/lib/rambling/trie/compressor_spec.rb +0 -111
  61. data/spec/lib/rambling/trie/configuration/properties_spec.rb +0 -75
  62. data/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +0 -177
  63. data/spec/lib/rambling/trie/container_spec.rb +0 -466
  64. data/spec/lib/rambling/trie/enumerable_spec.rb +0 -50
  65. data/spec/lib/rambling/trie/inspectable_spec.rb +0 -62
  66. data/spec/lib/rambling/trie/nodes/compressed_spec.rb +0 -43
  67. data/spec/lib/rambling/trie/nodes/node_spec.rb +0 -9
  68. data/spec/lib/rambling/trie/nodes/raw_spec.rb +0 -184
  69. data/spec/lib/rambling/trie/readers/plain_text_spec.rb +0 -26
  70. data/spec/lib/rambling/trie/readers/reader_spec.rb +0 -14
  71. data/spec/lib/rambling/trie/serializers/file_spec.rb +0 -11
  72. data/spec/lib/rambling/trie/serializers/marshal_spec.rb +0 -10
  73. data/spec/lib/rambling/trie/serializers/serializer_spec.rb +0 -21
  74. data/spec/lib/rambling/trie/serializers/yaml_spec.rb +0 -10
  75. data/spec/lib/rambling/trie/serializers/zip_spec.rb +0 -36
  76. data/spec/lib/rambling/trie/stringifyable_spec.rb +0 -89
  77. data/spec/lib/rambling/trie_spec.rb +0 -244
  78. data/spec/spec_helper.rb +0 -42
  79. data/spec/support/config.rb +0 -15
  80. data/spec/support/helpers/add_word.rb +0 -20
  81. data/spec/support/helpers/one_line_heredoc.rb +0 -11
  82. data/spec/support/shared_examples/a_compressible_trie.rb +0 -46
  83. data/spec/support/shared_examples/a_container_partial_word.rb +0 -17
  84. data/spec/support/shared_examples/a_container_scan.rb +0 -14
  85. data/spec/support/shared_examples/a_container_word.rb +0 -43
  86. data/spec/support/shared_examples/a_container_words_within.rb +0 -44
  87. data/spec/support/shared_examples/a_serializable_trie.rb +0 -26
  88. data/spec/support/shared_examples/a_serializer.rb +0 -60
  89. data/spec/support/shared_examples/a_trie_data_structure.rb +0 -45
  90. data/spec/support/shared_examples/a_trie_node.rb +0 -135
  91. data/spec/support/shared_examples/a_trie_node_implementation.rb +0 -149
  92. data/spec/tmp/.gitkeep +0 -0
@@ -28,7 +28,7 @@ module Rambling
28
28
  # @see Nodes::Raw#add
29
29
  # @see Nodes::Compressed#add
30
30
  def add word
31
- root.add char_symbols word
31
+ root.add reversed_char_symbols word
32
32
  end
33
33
 
34
34
  # Adds all provided words to the trie.
@@ -62,16 +62,27 @@ module Rambling
62
62
 
63
63
  # Checks if a path for a word or partial word exists in the trie.
64
64
  # @param [String] word the word or partial word to look for in the trie.
65
- # @return [Boolean] +true+ if the word or partial word is found, +false+ otherwise.
65
+ # @return [Boolean] `true` if the word or partial word is found, `false` otherwise.
66
66
  # @see Nodes::Node#partial_word?
67
67
  def partial_word? word = ''
68
68
  root.partial_word? word.chars
69
69
  end
70
70
 
71
+ # Adds all provided words to the trie.
72
+ # @param [Array<String>] words the words to add the branch from.
73
+ # @return [Array<Nodes::Node>] the collection of nodes added.
74
+ # @raise [InvalidOperation] if the trie is already compressed.
75
+ # @see #concat
76
+ # @see Nodes::Raw#add
77
+ # @see Nodes::Compressed#add
78
+ def push *words
79
+ concat words
80
+ end
81
+
71
82
  # Checks if a whole word exists in the trie.
72
83
  # @param [String] word the word to look for in the trie.
73
- # @return [Boolean] +true+ only if the word is found and the last character corresponds to a terminal node,
74
- # +false+ otherwise.
84
+ # @return [Boolean] `true` only if the word is found and the last character corresponds to a terminal node,
85
+ # `false` otherwise.
75
86
  # @see Nodes::Node#word?
76
87
  def word? word = ''
77
88
  root.word? word.chars
@@ -87,7 +98,7 @@ module Rambling
87
98
 
88
99
  # Returns all words within a string that match a word contained in the trie.
89
100
  # @param [String] phrase the string to look for matching words in.
90
- # @return [Enumerator<String>] all the words in the given string that match a word in the trie.
101
+ # @return [Array<String>] all the words in the given string that match a word in the trie.
91
102
  # @yield [String] each word found in phrase.
92
103
  def words_within phrase
93
104
  words_within_root(phrase).to_a
@@ -95,7 +106,7 @@ module Rambling
95
106
 
96
107
  # Checks if there are any valid words in a given string.
97
108
  # @param [String] phrase the string to look for matching words in.
98
- # @return [Boolean] +true+ if any word within phrase is contained in the trie, +false+ otherwise.
109
+ # @return [Boolean] `true` if any word within phrase is contained in the trie, `false` otherwise.
99
110
  # @see Container#words_within
100
111
  def words_within? phrase
101
112
  words_within_root(phrase).any?
@@ -103,7 +114,7 @@ module Rambling
103
114
 
104
115
  # Compares two trie data structures.
105
116
  # @param [Container] other the trie to compare against.
106
- # @return [Boolean] +true+ if the tries are equal, +false+ otherwise.
117
+ # @return [Boolean] `true` if the tries are equal, `false` otherwise.
107
118
  def == other
108
119
  root == other.root
109
120
  end
@@ -114,9 +125,7 @@ module Rambling
114
125
  def each
115
126
  return enum_for :each unless block_given?
116
127
 
117
- root.each do |word|
118
- yield word
119
- end
128
+ root.each { |word| yield word }
120
129
  end
121
130
 
122
131
  # @return [String] a string representation of the container.
@@ -141,21 +150,21 @@ module Rambling
141
150
 
142
151
  # Root node's children tree.
143
152
  # @return [Hash<Symbol, Nodes::Node>] the children tree hash contained in the root node, consisting of
144
- # +:letter => node+.
153
+ # `:letter => node`.
145
154
  # @see Nodes::Node#children_tree
146
155
  def children_tree
147
156
  root.children_tree
148
157
  end
149
158
 
150
159
  # 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.
160
+ # @return [Boolean] `true` for non-{Nodes::Node#terminal? terminal} nodes with one child, `false` otherwise.
152
161
  def compressed?
153
162
  root.compressed?
154
163
  end
155
164
 
156
165
  # Array of words contained in the root {Nodes::Node Node}.
157
166
  # @return [Array<String>] all words contained in this trie.
158
- # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-to_a Enumerable#to_a
167
+ # @see https://ruby-doc.org/3.3.0/Enumerable.html#method-i-to_a Enumerable#to_a
159
168
  def to_a
160
169
  root.to_a
161
170
  end
@@ -190,22 +199,21 @@ module Rambling
190
199
  return enum_for :words_within_root, phrase unless block_given?
191
200
 
192
201
  chars = phrase.chars
193
- 0.upto(chars.length - 1).each do |starting_index|
194
- new_phrase = chars.slice starting_index..(chars.length - 1)
195
- root.match_prefix new_phrase do |word|
196
- yield word
197
- end
198
- end
202
+ size = chars.length
203
+ # rubocop:disable Style/CommentedKeyword
204
+ 0.upto(size - 1).each do |starting_index|
205
+ new_phrase = chars.slice starting_index, size # : Array[String]
206
+ root.match_prefix(new_phrase) { |word| yield word }
207
+ end # : Enumerator[String, void]
208
+ # rubocop:enable Style/CommentedKeyword
199
209
  end
200
210
 
201
211
  def compress_root
202
- compressor.compress root
212
+ compressor.compress root # : Nodes::Compressed
203
213
  end
204
214
 
205
- def char_symbols word
206
- symbols = []
207
- word.reverse.each_char { |c| symbols << c.to_sym }
208
- symbols
215
+ def reversed_char_symbols word
216
+ word.reverse.chars.map(&:to_sym).to_a
209
217
  end
210
218
  end
211
219
  end
@@ -6,8 +6,11 @@ module Rambling
6
6
  module Enumerable
7
7
  include ::Enumerable
8
8
 
9
+ # Empty enumerator constant for early each exits.
10
+ EMPTY_ENUMERATOR = [].to_enum :each
11
+
9
12
  # Returns number of words contained in the trie
10
- # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-count Enumerable#count
13
+ # @see https://ruby-doc.org/3.3.0/Enumerable.html#method-i-count Enumerable#count
11
14
  alias_method :size, :count
12
15
 
13
16
  # Iterates over the words contained in the trie.
@@ -18,11 +21,7 @@ module Rambling
18
21
 
19
22
  yield as_word if terminal?
20
23
 
21
- children_tree.each_value do |child|
22
- child.each do |word|
23
- yield word
24
- end
25
- end
24
+ children_tree.each_value { |child| child.each { |word| yield word } }
26
25
 
27
26
  self
28
27
  end
@@ -4,7 +4,19 @@ module Rambling
4
4
  module Trie
5
5
  module Nodes
6
6
  # A representation of a node in an compressed trie data structure.
7
+ # :reek:RepeatedConditional { max_ifs: 4 }
7
8
  class Compressed < Rambling::Trie::Nodes::Node
9
+ # Creates a new compressed node.
10
+ # @param [Symbol, nil] letter the Node's letter value.
11
+ # @param [Node, nil] parent the parent of the current node.
12
+ # @param [Hash<Symbol, Node>] children_tree the children tree of the current node.
13
+ def initialize letter = nil, parent = nil, children_tree = {}
14
+ super
15
+
16
+ # Ensure all children have the current compressed node as the parent
17
+ children_tree.each_value { |child| child.parent = self }
18
+ end
19
+
8
20
  # Always raises {Rambling::Trie::InvalidOperation InvalidOperation} when
9
21
  # trying to add a word to the current compressed trie node
10
22
  # @param [String] _ the word to add to the trie.
@@ -14,8 +26,8 @@ module Rambling
14
26
  raise Rambling::Trie::InvalidOperation, 'Cannot add word to compressed trie'
15
27
  end
16
28
 
17
- # Always return +true+ for a compressed node.
18
- # @return [Boolean] always +true+ for a compressed node.
29
+ # Always return `true` for a compressed node.
30
+ # @return [Boolean] always `true` for a compressed node.
19
31
  def compressed?
20
32
  true
21
33
  end
@@ -23,13 +35,13 @@ module Rambling
23
35
  private
24
36
 
25
37
  def partial_word_chars? chars
26
- child = children_tree[chars.first.to_sym]
38
+ child = children_tree[(chars.first || raise).to_sym]
27
39
  return false unless child
28
40
 
29
41
  child_letter = child.letter.to_s
30
42
 
31
43
  if chars.size >= child_letter.size
32
- letter = chars.slice!(0, child_letter.size).join
44
+ letter = (chars.shift(child_letter.size) || raise).join
33
45
  return child.partial_word? chars if child_letter == letter
34
46
  end
35
47
 
@@ -39,7 +51,7 @@ module Rambling
39
51
  end
40
52
 
41
53
  def word_chars? chars
42
- letter = chars.slice! 0
54
+ letter = chars.shift || raise
43
55
  letter_sym = letter.to_sym
44
56
 
45
57
  child = children_tree[letter_sym]
@@ -50,7 +62,7 @@ module Rambling
50
62
 
51
63
  break if chars.empty?
52
64
 
53
- letter << chars.slice!(0)
65
+ letter << (chars.shift || raise)
54
66
  letter_sym = letter.to_sym
55
67
  end
56
68
 
@@ -58,13 +70,13 @@ module Rambling
58
70
  end
59
71
 
60
72
  def closest_node chars
61
- child = children_tree[chars.first.to_sym]
73
+ child = children_tree[(chars.first || raise).to_sym]
62
74
  return missing unless child
63
75
 
64
76
  child_letter = child.letter.to_s
65
77
 
66
78
  if chars.size >= child_letter.size
67
- letter = chars.slice!(0, child_letter.size).join
79
+ letter = (chars.shift(child_letter.size) || raise).join
68
80
  return child.scan chars if child_letter == letter
69
81
  end
70
82
 
@@ -77,19 +89,17 @@ module Rambling
77
89
  def children_match_prefix chars
78
90
  return enum_for :children_match_prefix, chars unless block_given?
79
91
 
80
- return if chars.empty?
92
+ return EMPTY_ENUMERATOR if chars.empty?
81
93
 
82
- child = children_tree[chars.first.to_sym]
83
- return unless child
94
+ child = children_tree[(chars.first || raise).to_sym]
95
+ return EMPTY_ENUMERATOR unless child
84
96
 
85
97
  child_letter = child.letter.to_s
86
- letter = chars.slice!(0, child_letter.size).join
98
+ letter = (chars.shift(child_letter.size) || raise).join
87
99
 
88
- return unless child_letter == letter
100
+ return EMPTY_ENUMERATOR unless child_letter == letter
89
101
 
90
- child.match_prefix chars do |word|
91
- yield word
92
- end
102
+ child.match_prefix(chars) { |word| yield word }
93
103
  end
94
104
  end
95
105
  end
@@ -4,6 +4,8 @@ module Rambling
4
4
  module Trie
5
5
  module Nodes
6
6
  # A representation of a node in the trie data structure.
7
+ # :reek:MissingSafeMethod { exclude: [ terminal! ] }
8
+ # :reek:RepeatedConditional { max_ifs: 3 }
7
9
  class Node
8
10
  include Rambling::Trie::Compressible
9
11
  include Rambling::Trie::Enumerable
@@ -22,7 +24,7 @@ module Rambling
22
24
  attr_reader :letter
23
25
 
24
26
  # Child nodes tree.
25
- # @return [Hash<Symbol, Node>] the children tree hash, consisting of +:letter => node+.
27
+ # @return [Hash<Symbol, Node>] the children tree hash, consisting of `:letter => node`.
26
28
  attr_accessor :children_tree
27
29
 
28
30
  # Parent node.
@@ -32,6 +34,7 @@ module Rambling
32
34
  # Creates a new node.
33
35
  # @param [Symbol, nil] letter the Node's letter value.
34
36
  # @param [Node, nil] parent the parent of the current node.
37
+ # @param [Hash<Symbol, Node>] children_tree the children tree of the current node.
35
38
  def initialize letter = nil, parent = nil, children_tree = {}
36
39
  @letter = letter
37
40
  @parent = parent
@@ -52,16 +55,18 @@ module Rambling
52
55
  # rubocop:disable Lint/UnreachableLoop
53
56
  children_tree.each_value { |child| return child }
54
57
  # rubocop:enable Lint/UnreachableLoop
58
+
59
+ nil
55
60
  end
56
61
 
57
62
  # Indicates if the current node is the root node.
58
- # @return [Boolean] +true+ if the node does not have a parent, +false+ otherwise.
63
+ # @return [Boolean] `true` if the node does not have a parent, `false` otherwise.
59
64
  def root?
60
65
  !parent
61
66
  end
62
67
 
63
68
  # Indicates if a {Node Node} is terminal or not.
64
- # @return [Boolean] +true+ for terminal nodes, +false+ otherwise.
69
+ # @return [Boolean] `true` for terminal nodes, `false` otherwise.
65
70
  def terminal?
66
71
  !!terminal
67
72
  end
@@ -79,7 +84,7 @@ module Rambling
79
84
 
80
85
  # Checks if a path for a set of characters exists in the trie.
81
86
  # @param [Array<String>] chars the characters to look for in the trie.
82
- # @return [Boolean] +true+ if the characters are found, +false+ otherwise.
87
+ # @return [Boolean] `true` if the characters are found, `false` otherwise.
83
88
  def partial_word? chars
84
89
  return true if chars.empty?
85
90
 
@@ -88,7 +93,7 @@ module Rambling
88
93
 
89
94
  # Checks if a path for set of characters represents a word in the trie.
90
95
  # @param [Array<String>] chars the characters to look for in the trie.
91
- # @return [Boolean] +true+ if the characters are found and form a word, +false+ otherwise.
96
+ # @return [Boolean] `true` if the characters are found and form a word, `false` otherwise.
92
97
  def word? chars = []
93
98
  return terminal? if chars.empty?
94
99
 
@@ -106,7 +111,7 @@ module Rambling
106
111
  end
107
112
 
108
113
  # Returns all words that match a prefix of any length within chars.
109
- # @param [String] chars the chars to base the prefix on.
114
+ # @param [Array[String]] chars the chars to base the prefix on.
110
115
  # @return [Enumerator<String>] all the words that match a prefix by chars.
111
116
  # @yield [String] each word found.
112
117
  def match_prefix chars
@@ -122,7 +127,7 @@ module Rambling
122
127
  # Get {Node Node} corresponding to a given letter.
123
128
  # @param [Symbol] letter the letter to search for in the node.
124
129
  # @return [Node] the node corresponding to that letter.
125
- # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D Hash#[]
130
+ # @see https://ruby-doc.org/3.3.0/Hash.html#method-i-5B-5D Hash#[]
126
131
  def [] letter
127
132
  children_tree[letter]
128
133
  end
@@ -131,15 +136,15 @@ module Rambling
131
136
  # @param [Symbol] letter the letter to insert or update in the node's
132
137
  # @param [Node] node the {Node Node} to assign to that letter.
133
138
  # @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#[]
139
+ # @see https://ruby-doc.org/3.3.0/Hash.html#method-i-5B-5D Hash#[]
135
140
  def []= letter, node
136
141
  children_tree[letter] = node
137
142
  end
138
143
 
139
144
  # Check if a {Node Node}'s children tree contains a given letter.
140
145
  # @param [Symbol] letter the letter to search for in the node.
141
- # @return [Boolean] +true+ if the letter is present, +false+ otherwise.
142
- # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-has_key-3F Hash#key?
146
+ # @return [Boolean] `true` if the letter is present, `false` otherwise.
147
+ # @see https://ruby-doc.org/3.3.0/Hash.html#method-i-has_key-3F Hash#key?
143
148
  def key? letter
144
149
  children_tree.key? letter
145
150
  end
@@ -147,8 +152,8 @@ module Rambling
147
152
  # Delete a given letter and its corresponding {Node Node} from
148
153
  # this {Node Node}'s children tree.
149
154
  # @param [Symbol] letter the letter to delete from the node's children tree.
150
- # @return [Node] the node corresponding to the deleted letter.
151
- # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-delete Hash#delete
155
+ # @return [Node, nil] the node corresponding to the deleted letter.
156
+ # @see https://ruby-doc.org/3.3.0/Hash.html#method-i-delete Hash#delete
152
157
  def delete letter
153
158
  children_tree.delete letter
154
159
  end
@@ -164,6 +169,24 @@ module Rambling
164
169
  private
165
170
 
166
171
  attr_accessor :terminal
172
+
173
+ # abstract methods
174
+
175
+ def children_match_prefix chars
176
+ raise NotImplementedError
177
+ end
178
+
179
+ def partial_word_chars? chars
180
+ raise NotImplementedError
181
+ end
182
+
183
+ def word_chars? chars
184
+ raise NotImplementedError
185
+ end
186
+
187
+ def closest_node chars
188
+ raise NotImplementedError
189
+ end
167
190
  end
168
191
  end
169
192
  end
@@ -4,21 +4,23 @@ module Rambling
4
4
  module Trie
5
5
  module Nodes
6
6
  # A representation of a node in an uncompressed trie data structure.
7
+ # :reek:RepeatedConditional { max_ifs: 4 }
7
8
  class Raw < Rambling::Trie::Nodes::Node
8
9
  # Adds a word to the current raw (uncompressed) trie node.
9
- # @param [Array<Symbol>] chars the char array to add to the trie.
10
- # @return [Raw] the added/modified node based on the word added.
10
+ # @param [Array<Symbol>] reversed_chars the char array to add to the trie, in reverse order.
11
+ # @return [Node] the added/modified node based on the word added.
11
12
  # @note This method clears the contents of the chars variable.
12
- def add chars
13
- if chars.empty?
14
- terminal!
13
+ def add reversed_chars
14
+ if reversed_chars.empty?
15
+ terminal! unless root?
16
+ self
15
17
  else
16
- add_to_children_tree chars
18
+ add_to_children_tree reversed_chars
17
19
  end
18
20
  end
19
21
 
20
- # Always return +false+ for a raw (uncompressed) node.
21
- # @return [Boolean] always +false+ for a raw (uncompressed) node.
22
+ # Always return `false` for a raw (uncompressed) node.
23
+ # @return [Boolean] always `false` for a raw (uncompressed) node.
22
24
  def compressed?
23
25
  false
24
26
  end
@@ -26,7 +28,7 @@ module Rambling
26
28
  private
27
29
 
28
30
  def add_to_children_tree chars
29
- letter = chars.pop
31
+ letter = chars.pop || raise
30
32
  child = children_tree[letter] || new_node(letter)
31
33
  child.add chars
32
34
  child
@@ -39,7 +41,7 @@ module Rambling
39
41
  end
40
42
 
41
43
  def partial_word_chars? chars = []
42
- letter = chars.shift.to_sym
44
+ letter = (chars.shift || raise).to_sym
43
45
  child = children_tree[letter]
44
46
  return false unless child
45
47
 
@@ -47,7 +49,7 @@ module Rambling
47
49
  end
48
50
 
49
51
  def word_chars? chars = []
50
- letter = chars.shift.to_sym
52
+ letter = (chars.shift || raise).to_sym
51
53
  child = children_tree[letter]
52
54
  return false unless child
53
55
 
@@ -55,7 +57,7 @@ module Rambling
55
57
  end
56
58
 
57
59
  def closest_node chars
58
- letter = chars.shift.to_sym
60
+ letter = (chars.shift || raise).to_sym
59
61
  child = children_tree[letter]
60
62
  return missing unless child
61
63
 
@@ -65,16 +67,12 @@ module Rambling
65
67
  def children_match_prefix chars
66
68
  return enum_for :children_match_prefix, chars unless block_given?
67
69
 
68
- return if chars.empty?
70
+ return EMPTY_ENUMERATOR if chars.empty?
69
71
 
70
- letter = chars.shift.to_sym
71
- child = children_tree[letter]
72
-
73
- return unless child
72
+ child = children_tree[(chars.shift || raise).to_sym]
73
+ return EMPTY_ENUMERATOR unless child
74
74
 
75
- child.match_prefix chars do |word|
76
- yield word
77
- end
75
+ child.match_prefix(chars) { |word| yield word }
78
76
  end
79
77
  end
80
78
  end
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- %w(node missing compressed raw).each do |file|
4
- require File.join('rambling', 'trie', 'nodes', file)
5
- end
3
+ path = File.join 'rambling', 'trie', 'nodes'
4
+ %w(node missing compressed raw).each { |file| require File.join(path, file) }
6
5
 
7
6
  module Rambling
8
7
  module Trie
@@ -3,14 +3,14 @@
3
3
  module Rambling
4
4
  module Trie
5
5
  module Readers
6
- # File reader for +.txt+ files.
6
+ # File reader for `.txt` files.
7
7
  class PlainText < Reader
8
- # Yields each word read from a +.txt+ file.
8
+ # Yields each word read from a `.txt` file.
9
9
  # @param [String] filepath the full path of the file to load the words from.
10
10
  # @yield [String] Each line read from the file.
11
11
  # @return [self]
12
12
  def each_word filepath
13
- return enum_for :each_word unless block_given?
13
+ return enum_for :each_word, filepath unless block_given?
14
14
 
15
15
  ::File.foreach(filepath) { |line| yield line.chomp! }
16
16
 
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- %w(reader plain_text).each do |file|
4
- require File.join('rambling', 'trie', 'readers', file)
5
- end
3
+ path = File.join 'rambling', 'trie', 'readers'
4
+ %w(reader plain_text).each { |file| require File.join(path, file) }
6
5
 
7
6
  module Rambling
8
7
  module Trie
@@ -17,9 +17,7 @@ module Rambling
17
17
  # @param [String] filepath the filepath to dump the contents to.
18
18
  # @return [Numeric] number of bytes written to disk.
19
19
  def dump contents, filepath
20
- ::File.open filepath, 'w+' do |f|
21
- f.write contents
22
- end
20
+ ::File.write filepath, contents
23
21
  end
24
22
  end
25
23
  end
@@ -3,7 +3,7 @@
3
3
  module Rambling
4
4
  module Trie
5
5
  module Serializers
6
- # Serializer for Ruby marshal format (+.marshal+) files.
6
+ # Serializer for Ruby marshal format (`.marshal`) files.
7
7
  class Marshal < Serializer
8
8
  # Creates a new Marshal serializer.
9
9
  # @param [Serializer] serializer the serializer responsible to write to and read from disk.
@@ -15,8 +15,8 @@ module Rambling
15
15
  # Loads marshaled object from contents in filepath and deserializes it into a {Nodes::Node Node}.
16
16
  # @param [String] filepath the full path of the file to load the marshaled object from.
17
17
  # @return [Nodes::Node] The deserialized {Nodes::Node Node}.
18
- # @see https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load Marshal.load
19
- # @note Use of {https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load Marshal.load} is generally
18
+ # @see https://ruby-doc.org/3.3.0/Marshal.html#method-c-load Marshal.load
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
22
  ::Marshal.load serializer.load filepath
@@ -26,7 +26,7 @@ module Rambling
26
26
  # @param [Nodes::Node] node the node to serialize
27
27
  # @param [String] filepath the full path of the file to dump the marshaled object into.
28
28
  # @return [Numeric] number of bytes written to disk.
29
- # @see https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-dump Marshal.dump
29
+ # @see https://ruby-doc.org/3.3.0/Marshal.html#method-c-dump Marshal.dump
30
30
  def dump node, filepath
31
31
  serializer.dump ::Marshal.dump(node), filepath
32
32
  end
@@ -3,7 +3,7 @@
3
3
  module Rambling
4
4
  module Trie
5
5
  module Serializers
6
- # Serializer for Ruby yaml format (+.yaml+, or +.yml+) files.
6
+ # Serializer for Ruby yaml format (`.yaml`, or `.yml`) files.
7
7
  class Yaml < Serializer
8
8
  # Creates a new Yaml serializer.
9
9
  # @param [Serializer] serializer the serializer responsible to write to and read from disk.
@@ -15,7 +15,7 @@ module Rambling
15
15
  # Loads serialized object from YAML file in filepath and deserializes it into a {Nodes::Node Node}.
16
16
  # @param [String] filepath the full path of the file to load the serialized YAML object from.
17
17
  # @return [Nodes::Node] The deserialized {Nodes::Node Node}.
18
- # @see https://ruby-doc.org/stdlib-2.7.0/libdoc/psych/rdoc/Psych.html#method-c-safe_load Psych.safe_load
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
20
  require 'yaml'
21
21
  ::YAML.safe_load(
@@ -33,7 +33,7 @@ module Rambling
33
33
  # @param [Nodes::Node] node the node to serialize
34
34
  # @param [String] filepath the full path of the file to dump the YAML object into.
35
35
  # @return [Numeric] number of bytes written to disk.
36
- # @see https://ruby-doc.org/stdlib-2.7.0/libdoc/psych/rdoc/Psych.html#method-c-dump Psych.dump
36
+ # @see https://ruby-doc.org/3.3.0/exts/psych/Psych.html#method-c-dump Psych.dump
37
37
  def dump node, filepath
38
38
  require 'yaml'
39
39
  serializer.dump ::YAML.dump(node), filepath
@@ -3,9 +3,9 @@
3
3
  module Rambling
4
4
  module Trie
5
5
  module Serializers
6
- # Zip file serializer. Dumps/loads contents from +.zip+ files.
7
- # Automatically detects if zip file contains a +.marshal+ or +.yml+ file,
8
- # or any other registered +:format => serializer+ combo.
6
+ # Zip file serializer. Dumps/loads contents from `.zip` files.
7
+ # Automatically detects if zip file contains a `.marshal` or `.yml` file,
8
+ # or any other registered `:format => serializer` combo.
9
9
  class Zip < Serializer
10
10
  # Creates a new Zip serializer.
11
11
  # @param [Configuration::Properties] properties the configuration
@@ -26,10 +26,15 @@ module Rambling
26
26
 
27
27
  ::Zip::File.open filepath do |zip|
28
28
  entry = zip.entries.first
29
- entry_path = path entry.name
29
+ raise unless entry
30
+
31
+ entry_name = entry.name
32
+ entry_path = path entry_name
30
33
  entry.extract entry_path
31
34
 
32
- serializer = serializers.resolve entry.name
35
+ serializer = serializers.resolve entry_name
36
+ raise unless serializer
37
+
33
38
  serializer.load entry_path
34
39
  end
35
40
  end
@@ -48,6 +53,9 @@ module Rambling
48
53
 
49
54
  entry_path = path filename
50
55
  serializer = serializers.resolve filename
56
+
57
+ raise unless serializer
58
+
51
59
  serializer.dump contents, entry_path
52
60
 
53
61
  zip.add filename, entry_path
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- %w(serializer file marshal yaml zip).each do |file|
4
- require File.join('rambling', 'trie', 'serializers', file)
5
- end
3
+ path = File.join 'rambling', 'trie', 'serializers'
4
+ %w(serializer file marshal yaml zip).each { |file| require File.join(path, file) }
6
5
 
7
6
  module Rambling
8
7
  module Trie
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Rambling
4
4
  module Trie
5
- # Provides the +String+ representation behavior for the trie data structure.
5
+ # Provides the `String` representation behavior for the trie data structure.
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.