rambling-trie 1.0.3 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +6 -4
- data/Guardfile +3 -1
- data/README.md +4 -4
- data/Rakefile +4 -0
- data/lib/rambling-trie.rb +2 -0
- data/lib/rambling/trie.rb +25 -9
- data/lib/rambling/trie/comparable.rb +4 -1
- data/lib/rambling/trie/compressible.rb +6 -4
- data/lib/rambling/trie/compressor.rb +12 -10
- data/lib/rambling/trie/configuration.rb +3 -1
- data/lib/rambling/trie/configuration/properties.rb +15 -8
- data/lib/rambling/trie/configuration/provider_collection.rb +4 -1
- data/lib/rambling/trie/container.rb +7 -40
- data/lib/rambling/trie/enumerable.rb +2 -0
- data/lib/rambling/trie/inspectable.rb +2 -0
- data/lib/rambling/trie/invalid_operation.rb +3 -1
- data/lib/rambling/trie/nodes.rb +3 -1
- data/lib/rambling/trie/nodes/compressed.rb +53 -70
- data/lib/rambling/trie/nodes/missing.rb +2 -0
- data/lib/rambling/trie/nodes/node.rb +38 -6
- data/lib/rambling/trie/nodes/raw.rb +19 -26
- data/lib/rambling/trie/readers.rb +3 -1
- data/lib/rambling/trie/readers/plain_text.rb +2 -0
- data/lib/rambling/trie/serializers.rb +3 -1
- data/lib/rambling/trie/serializers/file.rb +2 -0
- data/lib/rambling/trie/serializers/marshal.rb +12 -2
- data/lib/rambling/trie/serializers/yaml.rb +18 -2
- data/lib/rambling/trie/serializers/zip.rb +6 -0
- data/lib/rambling/trie/stringifyable.rb +7 -1
- data/lib/rambling/trie/version.rb +3 -1
- data/rambling-trie.gemspec +21 -10
- data/spec/integration/rambling/trie_spec.rb +8 -4
- data/spec/lib/rambling/trie/comparable_spec.rb +2 -0
- data/spec/lib/rambling/trie/compressor_spec.rb +35 -33
- data/spec/lib/rambling/trie/configuration/properties_spec.rb +17 -9
- data/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +10 -14
- data/spec/lib/rambling/trie/container_spec.rb +28 -53
- data/spec/lib/rambling/trie/enumerable_spec.rb +2 -0
- data/spec/lib/rambling/trie/inspectable_spec.rb +32 -7
- data/spec/lib/rambling/trie/nodes/compressed_spec.rb +2 -0
- data/spec/lib/rambling/trie/nodes/node_spec.rb +2 -0
- data/spec/lib/rambling/trie/nodes/raw_spec.rb +2 -0
- data/spec/lib/rambling/trie/readers/plain_text_spec.rb +3 -1
- data/spec/lib/rambling/trie/serializers/file_spec.rb +2 -0
- data/spec/lib/rambling/trie/serializers/marshal_spec.rb +2 -0
- data/spec/lib/rambling/trie/serializers/yaml_spec.rb +2 -0
- data/spec/lib/rambling/trie/serializers/zip_spec.rb +6 -4
- data/spec/lib/rambling/trie/stringifyable_spec.rb +7 -3
- data/spec/lib/rambling/trie_spec.rb +16 -9
- data/spec/spec_helper.rb +10 -7
- data/spec/support/config.rb +6 -0
- data/spec/support/helpers/add_word.rb +2 -0
- data/spec/support/helpers/one_line_heredoc.rb +11 -0
- data/spec/support/shared_examples/a_compressible_trie.rb +7 -3
- data/spec/support/shared_examples/a_serializable_trie.rb +2 -0
- data/spec/support/shared_examples/a_serializer.rb +2 -0
- data/spec/support/shared_examples/a_trie_data_structure.rb +2 -0
- data/spec/support/shared_examples/a_trie_node.rb +15 -5
- data/spec/support/shared_examples/a_trie_node_implementation.rb +10 -6
- metadata +17 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: fd802cb55bb14531c22c64b10e3c278ef20bb828b0680e9e6bea6e275ac2be0c
|
4
|
+
data.tar.gz: 0b6b81b55ce916632604bd3b932b7b67f403cf26f4e655c00fc3fb1f9b362bdd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf9c2b2d7d2af2801483b50bc0daec751c7a14b0694b46c769aa06e800c29069574446f434a941a416a90356bd6b10882c21ec94b6be55e807e45b1e0efefb49
|
7
|
+
data.tar.gz: 7072801a3d3d3debbac169dca5ac73f921d2416e664554be77d2dc1d94e4f82b5104752ed90715ed18d4879834ff1af56c1a23f940da3ef64bd63b1079c72753
|
data/Gemfile
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
source 'https://rubygems.org'
|
3
4
|
|
4
5
|
gemspec
|
@@ -6,19 +7,20 @@ gemspec
|
|
6
7
|
gem 'rubyzip'
|
7
8
|
|
8
9
|
group :development do
|
9
|
-
gem 'ruby-prof'
|
10
|
-
gem 'memory_profiler'
|
11
10
|
gem 'benchmark-ips'
|
12
11
|
gem 'flamegraph'
|
13
|
-
gem '
|
12
|
+
gem 'memory_profiler'
|
14
13
|
gem 'pry'
|
14
|
+
gem 'ruby-prof'
|
15
|
+
gem 'stackprof'
|
15
16
|
end
|
16
17
|
|
17
18
|
group :test do
|
18
|
-
gem 'simplecov', require: false
|
19
19
|
gem 'coveralls', '~>0.8.21', require: false
|
20
|
+
gem 'simplecov', require: false
|
20
21
|
end
|
21
22
|
|
22
23
|
group :local do
|
23
24
|
gem 'guard-rspec'
|
25
|
+
gem 'rubocop', require: false
|
24
26
|
end
|
data/Guardfile
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# A sample Guardfile
|
2
4
|
# More info at https://github.com/guard/guard#readme
|
3
5
|
|
4
6
|
guard 'rspec', cmd: 'rspec', all_on_start: true, all_after_pass: false do
|
5
7
|
watch(%r{^spec/.+_spec\.rb$})
|
6
8
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
-
watch('spec/spec_helper.rb') {
|
9
|
+
watch('spec/spec_helper.rb') { 'spec' }
|
8
10
|
end
|
data/README.md
CHANGED
@@ -10,7 +10,7 @@ The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wik
|
|
10
10
|
|
11
11
|
You will need:
|
12
12
|
|
13
|
-
* Ruby 2.
|
13
|
+
* Ruby 2.3.0 or up
|
14
14
|
* RubyGems
|
15
15
|
|
16
16
|
See [RVM][rvm], [rbenv][rbenv] or [chruby][chruby] for more information on how to manage Ruby versions.
|
@@ -245,12 +245,12 @@ The Rambling Trie has been tested with the following Ruby versions:
|
|
245
245
|
* 2.5.x
|
246
246
|
* 2.4.x
|
247
247
|
* 2.3.x
|
248
|
-
* 2.2.x
|
249
248
|
|
250
249
|
**No longer supported**:
|
251
250
|
|
252
|
-
* 2.
|
253
|
-
* 2.
|
251
|
+
* 2.2.x
|
252
|
+
* 2.1.x
|
253
|
+
* 2.0.x
|
254
254
|
* 1.9.x
|
255
255
|
* 1.8.x
|
256
256
|
|
data/Rakefile
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bundler/gem_tasks'
|
2
4
|
require 'rspec/core/rake_task'
|
5
|
+
require 'rubocop/rake_task'
|
3
6
|
|
4
7
|
require 'rambling-trie'
|
5
8
|
require_relative 'tasks/performance'
|
@@ -7,5 +10,6 @@ require_relative 'tasks/serialization'
|
|
7
10
|
require_relative 'tasks/ips'
|
8
11
|
|
9
12
|
RSpec::Core::RakeTask.new :spec
|
13
|
+
RuboCop::RakeTask.new :rubocop
|
10
14
|
|
11
15
|
task default: :spec
|
data/lib/rambling-trie.rb
CHANGED
data/lib/rambling/trie.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
%w(
|
2
4
|
comparable compressible compressor configuration container enumerable
|
3
5
|
inspectable invalid_operation readers serializers stringifyable nodes
|
4
6
|
version
|
5
|
-
|
7
|
+
).each do |file|
|
6
8
|
require File.join('rambling', 'trie', file)
|
7
9
|
end
|
8
10
|
|
@@ -18,7 +20,9 @@ module Rambling
|
|
18
20
|
# @yield [Container] the trie just created.
|
19
21
|
# @see Rambling::Trie::Readers Readers.
|
20
22
|
def create filepath = nil, reader = nil
|
21
|
-
|
23
|
+
root = root_builder.call
|
24
|
+
|
25
|
+
Rambling::Trie::Container.new root, compressor do |container|
|
22
26
|
if filepath
|
23
27
|
reader ||= readers.resolve filepath
|
24
28
|
reader.each_word filepath do |word|
|
@@ -30,13 +34,20 @@ module Rambling
|
|
30
34
|
end
|
31
35
|
end
|
32
36
|
|
33
|
-
# Loads an existing trie from disk into memory.
|
37
|
+
# Loads an existing trie from disk into memory. By default, it will
|
38
|
+
# deduce the correct way to deserialize based on the file extension.
|
39
|
+
# Available formats are `yml`, `marshal`, and `zip` versions of all the
|
40
|
+
# previous formats. You can also define your own.
|
34
41
|
# @param [String] filepath the file to load the words from.
|
35
|
-
# @param [Serializer, nil] serializer the object responsible of loading
|
36
|
-
# from disk
|
42
|
+
# @param [Serializer, nil] serializer the object responsible of loading
|
43
|
+
# the trie from disk
|
37
44
|
# @return [Container] the trie just loaded.
|
38
45
|
# @yield [Container] the trie just loaded.
|
39
46
|
# @see Rambling::Trie::Serializers Serializers.
|
47
|
+
# @note Use of
|
48
|
+
# {https://ruby-doc.org/core-2.5.0/Marshal.html#method-c-load
|
49
|
+
# Marshal.load} is generally discouraged. Only use the `.marshal`
|
50
|
+
# format with trusted input.
|
40
51
|
def load filepath, serializer = nil
|
41
52
|
serializer ||= serializers.resolve filepath
|
42
53
|
root = serializer.load filepath
|
@@ -45,7 +56,10 @@ module Rambling
|
|
45
56
|
end
|
46
57
|
end
|
47
58
|
|
48
|
-
# Dumps an existing trie from memory into disk.
|
59
|
+
# Dumps an existing trie from memory into disk. By default, it will
|
60
|
+
# deduce the correct way to serialize based on the file extension.
|
61
|
+
# Available formats are `yml`, `marshal`, and `zip` versions of all the
|
62
|
+
# previous formats. You can also define your own.
|
49
63
|
# @param [Container] trie the trie to dump into disk.
|
50
64
|
# @param [String] filepath the file to dump to serialized trie into.
|
51
65
|
# @param [Serializer, nil] serializer the object responsible of
|
@@ -57,8 +71,10 @@ module Rambling
|
|
57
71
|
end
|
58
72
|
|
59
73
|
# Provides configuration properties for the Rambling::Trie gem.
|
60
|
-
# @return [Configuration::Properties] the configured properties of the
|
61
|
-
#
|
74
|
+
# @return [Configuration::Properties] the configured properties of the
|
75
|
+
# gem.
|
76
|
+
# @yield [Configuration::Properties] the configured properties of the
|
77
|
+
# gem.
|
62
78
|
def config
|
63
79
|
yield properties if block_given?
|
64
80
|
properties
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rambling
|
2
4
|
module Trie
|
3
5
|
# Provides the comparable behavior for the trie data structure.
|
@@ -5,7 +7,8 @@ module Rambling
|
|
5
7
|
# Compares two nodes.
|
6
8
|
# @param [Nodes::Node] other the node to compare against.
|
7
9
|
# @return [Boolean] `true` if the nodes' {Nodes::Node#letter #letter} and
|
8
|
-
# {Nodes::Node#children_tree #children_tree} are equal, `false`
|
10
|
+
# {Nodes::Node#children_tree #children_tree} are equal, `false`
|
11
|
+
# otherwise.
|
9
12
|
def == other
|
10
13
|
letter == other.letter &&
|
11
14
|
terminal? == other.terminal? &&
|
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rambling
|
2
4
|
module Trie
|
3
5
|
# Provides the compressible behavior for the trie data structure.
|
4
6
|
module Compressible
|
5
|
-
# Indicates if the current {Rambling::Trie::Nodes::Node Node} can be
|
6
|
-
# or not.
|
7
|
-
# @return [Boolean] `true` for non-{Nodes::Node#terminal? terminal} nodes
|
8
|
-
# one child, `false` otherwise.
|
7
|
+
# Indicates if the current {Rambling::Trie::Nodes::Node Node} can be
|
8
|
+
# compressed or not.
|
9
|
+
# @return [Boolean] `true` for non-{Nodes::Node#terminal? terminal} nodes
|
10
|
+
# with one child, `false` otherwise.
|
9
11
|
def compressible?
|
10
12
|
!(root? || terminal?) && children_tree.size == 1
|
11
13
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rambling
|
2
4
|
module Trie
|
3
5
|
# Responsible for the compression process of a trie data structure.
|
@@ -26,7 +28,7 @@ module Rambling
|
|
26
28
|
letter.to_sym,
|
27
29
|
node.parent,
|
28
30
|
other.children_tree,
|
29
|
-
other.terminal
|
31
|
+
other.terminal?,
|
30
32
|
)
|
31
33
|
end
|
32
34
|
|
@@ -35,26 +37,26 @@ module Rambling
|
|
35
37
|
node.letter,
|
36
38
|
node.parent,
|
37
39
|
compress_children(node.children_tree),
|
38
|
-
node.terminal
|
40
|
+
node.terminal?,
|
39
41
|
)
|
40
42
|
end
|
41
43
|
|
42
|
-
def compress_children
|
43
|
-
|
44
|
+
def compress_children tree
|
45
|
+
new_tree = {}
|
44
46
|
|
45
|
-
|
47
|
+
tree.each do |letter, child|
|
46
48
|
compressed_child = compress child
|
47
|
-
|
49
|
+
new_tree[letter] = compressed_child
|
48
50
|
end
|
49
51
|
|
50
|
-
|
52
|
+
new_tree
|
51
53
|
end
|
52
54
|
|
53
|
-
def new_compressed_node letter, parent,
|
54
|
-
node = Rambling::Trie::Nodes::Compressed.new letter, parent,
|
55
|
+
def new_compressed_node letter, parent, tree, terminal
|
56
|
+
node = Rambling::Trie::Nodes::Compressed.new letter, parent, tree
|
55
57
|
node.terminal! if terminal
|
56
58
|
|
57
|
-
|
59
|
+
tree.each_value { |child| child.parent = node }
|
58
60
|
node
|
59
61
|
end
|
60
62
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rambling
|
2
4
|
module Trie
|
3
5
|
module Configuration
|
@@ -17,8 +19,8 @@ module Rambling
|
|
17
19
|
# @return [Compressor] the configured compressor.
|
18
20
|
attr_accessor :compressor
|
19
21
|
|
20
|
-
# The configured root_builder, which should return a {Nodes::Node Node}
|
21
|
-
# called.
|
22
|
+
# The configured root_builder, which should return a {Nodes::Node Node}
|
23
|
+
# when called.
|
22
24
|
# @return [Proc<Nodes::Node>] the configured root_builder.
|
23
25
|
attr_accessor :root_builder
|
24
26
|
|
@@ -36,9 +38,9 @@ module Rambling
|
|
36
38
|
reset_readers
|
37
39
|
reset_serializers
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
|
41
|
+
@compressor = Rambling::Trie::Compressor.new
|
42
|
+
@root_builder = -> { Rambling::Trie::Nodes::Raw.new }
|
43
|
+
@tmp_path = '/tmp'
|
42
44
|
end
|
43
45
|
|
44
46
|
private
|
@@ -48,7 +50,10 @@ module Rambling
|
|
48
50
|
def reset_readers
|
49
51
|
plain_text_reader = Rambling::Trie::Readers::PlainText.new
|
50
52
|
|
51
|
-
|
53
|
+
@readers = Rambling::Trie::Configuration::ProviderCollection.new(
|
54
|
+
:reader,
|
55
|
+
txt: plain_text_reader,
|
56
|
+
)
|
52
57
|
end
|
53
58
|
|
54
59
|
def reset_serializers
|
@@ -56,11 +61,13 @@ module Rambling
|
|
56
61
|
yaml_serializer = Rambling::Trie::Serializers::Yaml.new
|
57
62
|
zip_serializer = Rambling::Trie::Serializers::Zip.new self
|
58
63
|
|
59
|
-
|
64
|
+
@serializers = Rambling::Trie::Configuration::ProviderCollection.new(
|
65
|
+
:serializer,
|
60
66
|
marshal: marshal_serializer,
|
61
67
|
yml: yaml_serializer,
|
62
68
|
yaml: yaml_serializer,
|
63
|
-
zip: zip_serializer
|
69
|
+
zip: zip_serializer,
|
70
|
+
)
|
64
71
|
end
|
65
72
|
end
|
66
73
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rambling
|
2
4
|
module Trie
|
3
5
|
module Configuration
|
@@ -44,7 +46,8 @@ module Rambling
|
|
44
46
|
|
45
47
|
def default= provider
|
46
48
|
unless contains? provider
|
47
|
-
raise ArgumentError,
|
49
|
+
raise ArgumentError,
|
50
|
+
"default #{name} should be part of configured #{name}s"
|
48
51
|
end
|
49
52
|
|
50
53
|
@default = provider
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rambling
|
2
4
|
module Trie
|
3
5
|
# Wrapper on top of trie data structure.
|
@@ -175,9 +177,9 @@ module Rambling
|
|
175
177
|
# Check if a letter is part of the root {Nodes::Node}'s children tree.
|
176
178
|
# @param [Symbol] letter the letter to search for in the root node.
|
177
179
|
# @return [Boolean] whether the letter is contained or not.
|
178
|
-
# @see Nodes::Node#
|
179
|
-
def
|
180
|
-
root.
|
180
|
+
# @see Nodes::Node#key?
|
181
|
+
def key? letter
|
182
|
+
root.key? letter
|
181
183
|
end
|
182
184
|
|
183
185
|
# Size of the Root {Nodes::Node Node}'s children tree.
|
@@ -186,47 +188,12 @@ module Rambling
|
|
186
188
|
root.size
|
187
189
|
end
|
188
190
|
|
189
|
-
# String representation of the current node, if it is a terminal node.
|
190
|
-
# @return [String] the string representation of the current node.
|
191
|
-
# @raise [InvalidOperation] if node is not terminal or is root.
|
192
|
-
# @deprecated This will always raise an {InvalidOperation} exception.
|
193
|
-
def as_word
|
194
|
-
warn '[DEPRECATION WARNING] `#as_word` is deprecated. Please use `#root#as_word` instead.'
|
195
|
-
root.as_word
|
196
|
-
end
|
197
|
-
|
198
|
-
# Root {Nodes::Node Node}'s letter.
|
199
|
-
# @return [Symbol] the root node's letter
|
200
|
-
# @see Nodes::Node#letter
|
201
|
-
# @deprecated This will always return `nil`.
|
202
|
-
def letter
|
203
|
-
warn '[DEPRECATION WARNING] `#letter` is deprecated. Please use `#root#letter` instead.'
|
204
|
-
root.letter
|
205
|
-
end
|
206
|
-
|
207
|
-
# Root {Nodes::Node Node}'s parent.
|
208
|
-
# @return [Symbol] the root node's parent
|
209
|
-
# @see Nodes::Node#parent
|
210
|
-
# @deprecated This will always return `nil`.
|
211
|
-
def parent
|
212
|
-
warn '[DEPRECATION WARNING] `#parent` is deprecated. Please use `#root#parent` instead.'
|
213
|
-
root.parent
|
214
|
-
end
|
215
|
-
|
216
|
-
# String representation of root {Nodes::Node Node}.
|
217
|
-
# @return [String] the root node's string representation.
|
218
|
-
# @see Stringifyable#to_s
|
219
|
-
# @deprecated This will always return an empty string (`''`).
|
220
|
-
def to_s
|
221
|
-
warn '[DEPRECATION WARNING] `#to_s` is deprecated. Please use `#root#to_s` instead.'
|
222
|
-
root.to_s
|
223
|
-
end
|
224
|
-
|
225
191
|
alias_method :include?, :word?
|
226
192
|
alias_method :match?, :partial_word?
|
227
193
|
alias_method :words, :scan
|
228
194
|
alias_method :<<, :add
|
229
|
-
alias_method :
|
195
|
+
alias_method :has_key?, :key?
|
196
|
+
alias_method :has_letter?, :key?
|
230
197
|
|
231
198
|
private
|
232
199
|
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rambling
|
2
4
|
module Trie
|
3
5
|
# Raised when trying to execute an invalid operation on a trie data
|
4
6
|
# structure.
|
5
|
-
class InvalidOperation <
|
7
|
+
class InvalidOperation < RuntimeError
|
6
8
|
# Creates a new {InvalidOperation InvalidOperation} exception.
|
7
9
|
# @param [String, nil] message the exception message.
|
8
10
|
def initialize message = nil
|
data/lib/rambling/trie/nodes.rb
CHANGED
@@ -1,30 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rambling
|
2
4
|
module Trie
|
3
5
|
module Nodes
|
4
|
-
|
6
|
+
# A representation of a node in an compressed trie data structure.
|
5
7
|
class Compressed < Rambling::Trie::Nodes::Node
|
6
8
|
# Always raises {Rambling::Trie::InvalidOperation InvalidOperation} when
|
7
9
|
# trying to add a word to the current compressed trie node
|
8
|
-
# @param [String]
|
10
|
+
# @param [String] _ the word to add to the trie.
|
9
11
|
# @raise [InvalidOperation] if the trie is already compressed.
|
10
12
|
# @return [nil] this never returns as it always raises an exception.
|
11
|
-
def add
|
12
|
-
raise Rambling::Trie::InvalidOperation,
|
13
|
-
|
14
|
-
|
15
|
-
# Checks if a path for set a of characters exists in the trie.
|
16
|
-
# @param [Array<String>] chars the characters to look for in the trie.
|
17
|
-
# @return [Boolean] `true` if the characters are found, `false` otherwise.
|
18
|
-
def partial_word? chars
|
19
|
-
chars.empty? || has_partial_word?(chars)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Checks if a path for set of characters represents a word in the trie.
|
23
|
-
# @param [Array<String>] chars the characters to look for in the trie.
|
24
|
-
# @return [Boolean] `true` if the characters are found and form a word,
|
25
|
-
# `false` otherwise.
|
26
|
-
def word? chars
|
27
|
-
chars.empty? ? terminal? : has_word?(chars)
|
13
|
+
def add _
|
14
|
+
raise Rambling::Trie::InvalidOperation,
|
15
|
+
'Cannot add word to compressed trie'
|
28
16
|
end
|
29
17
|
|
30
18
|
# Always return `true` for a compressed node.
|
@@ -35,79 +23,74 @@ module Rambling
|
|
35
23
|
|
36
24
|
private
|
37
25
|
|
38
|
-
def
|
39
|
-
|
26
|
+
def partial_word_chars? chars
|
27
|
+
child = children_tree[chars.first.to_sym]
|
28
|
+
return false unless child
|
29
|
+
|
30
|
+
child_letter = child.letter.to_s
|
31
|
+
|
32
|
+
if chars.size >= child_letter.size
|
33
|
+
letter = chars.slice!(0, child_letter.size).join
|
34
|
+
return child.partial_word? chars if child_letter == letter
|
35
|
+
end
|
36
|
+
|
37
|
+
letter = chars.join
|
38
|
+
child_letter = child_letter.slice 0, letter.size
|
39
|
+
child_letter == letter
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
43
|
-
|
42
|
+
def word_chars? chars
|
43
|
+
letter = chars.slice! 0
|
44
|
+
letter_sym = letter.to_sym
|
45
|
+
|
46
|
+
child = children_tree[letter_sym]
|
47
|
+
return false unless child
|
48
|
+
|
49
|
+
loop do
|
50
|
+
return child.word? chars if letter_sym == child.letter
|
44
51
|
|
45
|
-
|
46
|
-
if current_key
|
47
|
-
current_key << chars.slice!(0)
|
48
|
-
else
|
49
|
-
current_key = chars.slice!(0)
|
50
|
-
end
|
52
|
+
break if chars.empty?
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
+
letter << chars.slice!(0)
|
55
|
+
letter_sym = letter.to_sym
|
54
56
|
end
|
55
57
|
|
56
58
|
false
|
57
59
|
end
|
58
60
|
|
59
61
|
def closest_node chars
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def children_match_prefix chars
|
64
|
-
return enum_for :children_match_prefix, chars unless block_given?
|
65
|
-
|
66
|
-
current_key = nil
|
62
|
+
child = children_tree[chars.first.to_sym]
|
63
|
+
return missing unless child
|
67
64
|
|
68
|
-
|
69
|
-
if current_key
|
70
|
-
current_key << chars.slice!(0)
|
71
|
-
else
|
72
|
-
current_key = chars.slice!(0)
|
73
|
-
end
|
65
|
+
child_letter = child.letter.to_s
|
74
66
|
|
75
|
-
|
67
|
+
if chars.size >= child_letter.size
|
68
|
+
letter = chars.slice!(0, child_letter.size).join
|
69
|
+
return child.scan chars if child_letter == letter
|
70
|
+
end
|
76
71
|
|
77
|
-
|
72
|
+
letter = chars.join
|
73
|
+
child_letter = child_letter.slice 0, letter.size
|
78
74
|
|
79
|
-
|
80
|
-
yield word
|
81
|
-
end
|
82
|
-
end
|
75
|
+
child_letter == letter ? child : missing
|
83
76
|
end
|
84
77
|
|
85
|
-
def
|
86
|
-
|
87
|
-
current_key = current_key chars.slice!(0)
|
78
|
+
def children_match_prefix chars
|
79
|
+
return enum_for :children_match_prefix, chars unless block_given?
|
88
80
|
|
89
|
-
|
90
|
-
current_length += 1
|
81
|
+
return if chars.empty?
|
91
82
|
|
92
|
-
|
93
|
-
|
94
|
-
end
|
95
|
-
end while current_key && current_key[current_length] == chars.slice!(0)
|
96
|
-
end
|
83
|
+
child = children_tree[chars.first.to_sym]
|
84
|
+
return unless child
|
97
85
|
|
98
|
-
|
99
|
-
|
86
|
+
child_letter = child.letter.to_s
|
87
|
+
letter = chars.slice!(0, child_letter.size).join
|
100
88
|
|
101
|
-
|
102
|
-
letters_string = letters.to_s
|
89
|
+
return unless child_letter == letter
|
103
90
|
|
104
|
-
|
105
|
-
|
106
|
-
break
|
107
|
-
end
|
91
|
+
child.match_prefix chars do |word|
|
92
|
+
yield word
|
108
93
|
end
|
109
|
-
|
110
|
-
current_key
|
111
94
|
end
|
112
95
|
end
|
113
96
|
end
|