rambling-trie 2.4.0 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
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.