rambling-trie 0.9.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/LICENSE +1 -1
- data/README.md +133 -26
- data/Rakefile +1 -2
- data/lib/rambling/trie.rb +53 -9
- data/lib/rambling/trie/comparable.rb +16 -0
- data/lib/rambling/trie/compressable.rb +14 -0
- data/lib/rambling/trie/compressed_node.rb +38 -14
- data/lib/rambling/trie/compressor.rb +14 -10
- data/lib/rambling/trie/configuration.rb +11 -0
- data/lib/rambling/trie/configuration/properties.rb +66 -0
- data/lib/rambling/trie/configuration/provider_collection.rb +101 -0
- data/lib/rambling/trie/container.rb +57 -17
- data/lib/rambling/trie/enumerable.rb +1 -1
- data/lib/rambling/trie/forwardable.rb +9 -4
- data/lib/rambling/trie/inspectable.rb +37 -0
- data/lib/rambling/trie/invalid_operation.rb +3 -2
- data/lib/rambling/trie/missing_node.rb +2 -1
- data/lib/rambling/trie/node.rb +40 -30
- data/lib/rambling/trie/raw_node.rb +29 -13
- data/lib/rambling/trie/readers.rb +11 -0
- data/lib/rambling/trie/readers/plain_text.rb +26 -0
- data/lib/rambling/trie/serializers.rb +11 -0
- data/lib/rambling/trie/serializers/file.rb +25 -0
- data/lib/rambling/trie/serializers/marshal.rb +38 -0
- data/lib/rambling/trie/serializers/yaml.rb +39 -0
- data/lib/rambling/trie/serializers/zip.rb +67 -0
- data/lib/rambling/trie/stringifyable.rb +20 -0
- data/lib/rambling/trie/version.rb +1 -1
- data/rambling-trie.gemspec +2 -2
- data/spec/integration/rambling/trie_spec.rb +45 -49
- data/spec/lib/rambling/trie/comparable_spec.rb +104 -0
- data/spec/lib/rambling/trie/compressed_node_spec.rb +44 -0
- data/spec/lib/rambling/trie/configuration/properties_spec.rb +49 -0
- data/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +165 -0
- data/spec/lib/rambling/trie/container_spec.rb +127 -38
- data/spec/lib/rambling/trie/{inspector_spec.rb → inspectable_spec.rb} +7 -5
- data/spec/lib/rambling/trie/raw_node_spec.rb +22 -41
- data/spec/lib/rambling/trie/readers/plain_text_spec.rb +14 -0
- data/spec/lib/rambling/trie/serializers/file_spec.rb +11 -0
- data/spec/lib/rambling/trie/serializers/marshal_spec.rb +14 -0
- data/spec/lib/rambling/trie/serializers/yaml_spec.rb +14 -0
- data/spec/lib/rambling/trie/serializers/zip_spec.rb +30 -0
- data/spec/lib/rambling/trie/stringifyable_spec.rb +82 -0
- data/spec/lib/rambling/trie_spec.rb +120 -7
- data/spec/spec_helper.rb +7 -1
- data/spec/support/config.rb +5 -0
- data/spec/support/shared_examples/a_compressable_trie.rb +26 -0
- data/spec/support/shared_examples/a_serializable_trie.rb +26 -0
- data/spec/support/shared_examples/a_serializer.rb +29 -0
- data/spec/support/shared_examples/a_trie_data_structure.rb +29 -0
- data/spec/tmp/.gitkeep +0 -0
- metadata +51 -24
- data/lib/rambling/trie/compression.rb +0 -13
- data/lib/rambling/trie/inspector.rb +0 -11
- data/lib/rambling/trie/plain_text_reader.rb +0 -23
- data/lib/rambling/trie/tasks/gem.rb +0 -17
- data/lib/rambling/trie/tasks/helpers/path.rb +0 -17
- data/lib/rambling/trie/tasks/helpers/performance_report.rb +0 -17
- data/lib/rambling/trie/tasks/helpers/time.rb +0 -7
- data/lib/rambling/trie/tasks/performance.rb +0 -15
- data/lib/rambling/trie/tasks/performance/all.rb +0 -17
- data/lib/rambling/trie/tasks/performance/benchmark.rb +0 -201
- data/lib/rambling/trie/tasks/performance/directory.rb +0 -11
- data/lib/rambling/trie/tasks/performance/flamegraph.rb +0 -119
- data/lib/rambling/trie/tasks/performance/profile/call_tree.rb +0 -147
- data/lib/rambling/trie/tasks/performance/profile/memory.rb +0 -143
- data/spec/lib/rambling/trie/plain_text_reader_spec.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e58cb5a9636b79abd8fb93b4fae30ec3486871a
|
4
|
+
data.tar.gz: 5cb485068db0e4a889692433eedb1aa1682394f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d035ffc3fa86ee5be924cac9f73701df016221158e5654d3c908ec2adf034f76bf2d9081d56027c5e22c812a99241f671de64826f6b094fba153c62014edaeb
|
7
|
+
data.tar.gz: ac2151ec179554ed23d990e92fdfbce683ca88086f04eaa4becf4ad392c77a947327766ea59c4de561e62d741ccd815d637241f415e16fcebbebb2d712a4cf0a
|
data/Gemfile
CHANGED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[![Gem Version][badge_fury_badge]][badge_fury_link] [![Dependency Status][gemnasium_badge]][gemnasium_link] [![Build Status][travis_ci_badge]][travis_ci_link] [![Code Climate][code_climate_badge]][code_climage_link] [![Coverage Status][coveralls_badge]][coveralls_link] [![Documentation Status][inch_ci_badge]][inch_ci_link]
|
4
4
|
|
5
|
-
The Rambling Trie is a
|
5
|
+
The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wiki], which includes compression abilities and is designed to be very fast to traverse.
|
6
6
|
|
7
7
|
## Installing the Rambling Trie
|
8
8
|
|
@@ -13,7 +13,7 @@ You will need:
|
|
13
13
|
* Ruby 2.1.0 or up
|
14
14
|
* RubyGems
|
15
15
|
|
16
|
-
See [RVM][rvm]
|
16
|
+
See [RVM][rvm], [rbenv][rbenv] or [chruby][chruby] for more information on how to manage Ruby versions.
|
17
17
|
|
18
18
|
### Installation
|
19
19
|
|
@@ -29,15 +29,17 @@ Or, include it in your `Gemfile` and bundle it:
|
|
29
29
|
gem 'rambling-trie'
|
30
30
|
```
|
31
31
|
|
32
|
-
##
|
32
|
+
## Using the Rambling Trie
|
33
33
|
|
34
|
-
|
34
|
+
### Creation
|
35
|
+
|
36
|
+
To create a new trie, initialize it like this:
|
35
37
|
|
36
38
|
``` ruby
|
37
39
|
trie = Rambling::Trie.create
|
38
40
|
```
|
39
41
|
|
40
|
-
You can also provide a block and the created instance will be yielded for you to perform any operation on it:
|
42
|
+
You can also provide a block and the created trie instance will be yielded for you to perform any operation on it:
|
41
43
|
|
42
44
|
``` ruby
|
43
45
|
Rambling::Trie.create do |trie|
|
@@ -62,52 +64,67 @@ the
|
|
62
64
|
trie
|
63
65
|
```
|
64
66
|
|
65
|
-
If you want to use a custom file format, you will need to provide a custom file reader that defines
|
67
|
+
If you want to use a custom file format, you will need to provide a custom file reader that defines an `#each_word` method that yields each word contained in the file. Look at the [`PlainText` reader][rambling_trie_plain_text_reader] class for an example, and at the [Configuration section][rambling_trie_configuration] to see how to add your own custom file readers.
|
68
|
+
|
69
|
+
### Operations
|
66
70
|
|
67
|
-
To add new words to the trie, use
|
71
|
+
To add new words to the trie, use `#add` or its alias `#<<`:
|
68
72
|
|
69
73
|
``` ruby
|
70
74
|
trie.add 'word'
|
71
75
|
trie << 'word'
|
72
76
|
```
|
73
77
|
|
74
|
-
And to find out if a word already exists in the trie, use
|
78
|
+
And to find out if a word already exists in the trie, use `#word?` or its alias `#include?`:
|
75
79
|
|
76
80
|
``` ruby
|
77
81
|
trie.word? 'word'
|
78
82
|
trie.include? 'word'
|
79
83
|
```
|
80
84
|
|
81
|
-
If you wish to find if part of a word exists in the trie instance, you should call
|
85
|
+
If you wish to find if part of a word exists in the trie instance, you should call `#partial_word?` or its alias `#match?`:
|
82
86
|
|
83
87
|
``` ruby
|
84
88
|
trie.partial_word? 'partial_word'
|
85
89
|
trie.match? 'partial_word'
|
86
90
|
```
|
87
91
|
|
88
|
-
To get all the words that start with a particular string, you can use `
|
92
|
+
To get all the words that start with a particular string, you can use `#scan` or its alias `#words`:
|
89
93
|
|
90
94
|
``` ruby
|
91
95
|
trie.scan 'hi' # => ['hi', 'high', 'highlight', ...]
|
92
96
|
trie.words 'hi' # => ['hi', 'high', 'highlight', ...]
|
93
97
|
```
|
94
98
|
|
99
|
+
To get all the words within a given string, you can use `#words_within`:
|
100
|
+
|
101
|
+
``` ruby
|
102
|
+
trie.words_within 'ifdxawesome45someword3' # => ['if', 'aw', 'awe', ...]
|
103
|
+
trie.words_within 'tktktktk' # => []
|
104
|
+
```
|
105
|
+
|
106
|
+
Or, if you're just interested in knowing whether a given string contains any valid words or not, you can use `#words_within?`:
|
107
|
+
|
108
|
+
``` ruby
|
109
|
+
trie.words_within? 'ifdxawesome45someword3' # => true
|
110
|
+
trie.words_within? 'tktktktk' # => false
|
111
|
+
```
|
112
|
+
|
95
113
|
### Compression
|
96
114
|
|
97
|
-
By default, the Rambling Trie works as a
|
98
|
-
Starting from version 0.1.0, you can obtain a Compressed Trie from the Standard one, by using the compression feature.
|
99
|
-
Just call the `compress!` method on the trie instance:
|
115
|
+
By default, the Rambling Trie works as a standard trie. Starting from version 0.1.0, you can obtain a compressed trie from the standard one, by using the compression feature. Just call the `#compress!` method on the trie instance:
|
100
116
|
|
101
117
|
``` ruby
|
102
118
|
trie.compress!
|
103
119
|
```
|
104
120
|
|
105
|
-
This will reduce the
|
121
|
+
This will reduce the size of the trie by using redundant node elimination (redundant nodes are the only-child non-terminal nodes).
|
106
122
|
|
107
|
-
|
108
|
-
|
123
|
+
> _**Note**: The `#compress!` method acts over the trie instance it belongs to
|
124
|
+
> and is destructive. Also, adding words after compression (with `#add` or
|
125
|
+
> `#<<`) is not supported._
|
109
126
|
|
110
|
-
You can find out if a trie instance is compressed by calling the
|
127
|
+
You can find out if a trie instance is compressed by calling the `#compressed?` method:
|
111
128
|
|
112
129
|
``` ruby
|
113
130
|
trie.compressed?
|
@@ -118,15 +135,93 @@ trie.compressed?
|
|
118
135
|
Starting from version 0.4.2, you can use any `Enumerable` method over a trie instance, and it will iterate over each word contained in the trie. You can now do things like:
|
119
136
|
|
120
137
|
``` ruby
|
121
|
-
trie.each
|
122
|
-
puts word
|
123
|
-
end
|
124
|
-
|
138
|
+
trie.each { |word| puts word }
|
125
139
|
trie.any? { |word| word.include? 'x' }
|
140
|
+
trie.all? { |word| word.include? 'x' }
|
126
141
|
# etc.
|
127
142
|
```
|
128
143
|
|
129
|
-
|
144
|
+
### Serialization
|
145
|
+
|
146
|
+
Starting from version 1.0.0, you can store a full trie instance on disk and retrieve/use it later on. Loading a trie from disk takes less time, less cpu and less memory than loading every word into the trie every time. This is particularly useful for production applications, when you have word lists that you know are going to be static, or that change with little frequency.
|
147
|
+
|
148
|
+
To store a trie on disk, you can use `.dump` like this:
|
149
|
+
|
150
|
+
``` ruby
|
151
|
+
Rambling::Trie.dump trie, '/path/to/file'
|
152
|
+
```
|
153
|
+
|
154
|
+
Then, when you need to use a trie next time, you don't have to create a new one with all the necessary words. Rather, you can retrieve a previously stored one with `.load` like this:
|
155
|
+
|
156
|
+
``` ruby
|
157
|
+
trie = Rambling::Trie.load trie, '/path/to/file'
|
158
|
+
```
|
159
|
+
|
160
|
+
#### Supported formats
|
161
|
+
|
162
|
+
Currently, these formats are supported to store tries on disk:
|
163
|
+
|
164
|
+
- Ruby's [binary (Marshal)][marshal] format
|
165
|
+
- [YAML][yaml]
|
166
|
+
|
167
|
+
> When dumping into or loading from disk, the format is determined
|
168
|
+
> automatically based on the file extension, so `.yml` or `.yaml` files will be
|
169
|
+
> handled through `YAML` and `.marshal` files through `Marshal`.
|
170
|
+
|
171
|
+
Optionally, you can use a `.zip` version of the supported formats. In order to do so, you'll have to install the [`rubyzip`][rubyzip] gem:
|
172
|
+
|
173
|
+
``` bash
|
174
|
+
gem install rubyzip
|
175
|
+
```
|
176
|
+
|
177
|
+
Or, include it in your `Gemfile` and bundle it:
|
178
|
+
|
179
|
+
``` ruby
|
180
|
+
gem 'rubyzip'
|
181
|
+
```
|
182
|
+
|
183
|
+
Then, you can load contents form a `.zip` file like this:
|
184
|
+
|
185
|
+
``` ruby
|
186
|
+
require 'zip'
|
187
|
+
trie = Rambling::Trie.load trie, '/path/to/file.zip'
|
188
|
+
```
|
189
|
+
|
190
|
+
> For `.zip` files, the format is also determined automatically based on the
|
191
|
+
> file extension, so `.yml.zip` or `.yaml.zip` files will be handled through
|
192
|
+
> `YAML` after decompression and `.marshal.zip` files through `Marshal`.
|
193
|
+
|
194
|
+
### Configuration
|
195
|
+
|
196
|
+
Starting from version 1.0.0, you can change the configuration values used by Rambling Trie. You can now supply:
|
197
|
+
|
198
|
+
* A `Compressor` object
|
199
|
+
* A root `Node` builder
|
200
|
+
* More `Readers` (implement `#each_word`)
|
201
|
+
* Change the default `reader`
|
202
|
+
* More `Serializers` (implement `#dump` and `#load`)
|
203
|
+
* Change the default `serializer`
|
204
|
+
|
205
|
+
You can configure those values by using `.config` like this:
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
require 'rambling-trie'
|
209
|
+
|
210
|
+
Rambling::Trie.config do |config|
|
211
|
+
config.compressor = MyCompressor.new
|
212
|
+
config.root_builder = lambda { MyNode.new }
|
213
|
+
|
214
|
+
config.readers.add :html, MyHtmlReader.new
|
215
|
+
config.readers.default = config.readers[:html]
|
216
|
+
|
217
|
+
config.serializers.add :json, MyJsonSerializer.new
|
218
|
+
config.serializers.default = config.serializers[:yml]
|
219
|
+
end
|
220
|
+
|
221
|
+
# Create a trie or load one from disk and do things with it...
|
222
|
+
```
|
223
|
+
|
224
|
+
### Further Documentation
|
130
225
|
|
131
226
|
You can find further API documentation on the autogenerated [rambling-trie gem RubyDoc.info page][rubydoc] or if you want edge documentation, you can go the [GitHub project RubyDoc.info page][rubydoc_github].
|
132
227
|
|
@@ -139,16 +234,19 @@ The Rambling Trie has been tested with the following Ruby versions:
|
|
139
234
|
* 2.2.x
|
140
235
|
* 2.1.x
|
141
236
|
|
142
|
-
|
237
|
+
**No longer supported**:
|
238
|
+
|
239
|
+
* 2.0.x (might still work, but is not officially supported)
|
240
|
+
* 1.9.x
|
241
|
+
* 1.8.x
|
143
242
|
|
144
243
|
## Contributing to Rambling Trie
|
145
244
|
|
146
|
-
|
147
|
-
Also, be sure to add tests for any feature you may develop or bug you may fix.
|
245
|
+
Take a look at the [contributing guide][rambling_trie_contributing_guide] to get started, or fire a question to [@gonzedge][github_user_gonzedge].
|
148
246
|
|
149
247
|
## License and copyright
|
150
248
|
|
151
|
-
Copyright (c) 2012-
|
249
|
+
Copyright (c) 2012-2017 Edgar Gonzalez
|
152
250
|
|
153
251
|
MIT License
|
154
252
|
|
@@ -160,17 +258,26 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
160
258
|
|
161
259
|
[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg
|
162
260
|
[badge_fury_link]: https://badge.fury.io/rb/rambling-trie
|
261
|
+
[chruby]: https://github.com/postmodern/chruby
|
163
262
|
[code_climage_link]: https://codeclimate.com/github/gonzedge/rambling-trie
|
164
263
|
[code_climate_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/gpa.svg
|
165
264
|
[coveralls_badge]: https://img.shields.io/coveralls/gonzedge/rambling-trie.svg
|
166
265
|
[coveralls_link]: https://coveralls.io/r/gonzedge/rambling-trie
|
167
266
|
[gemnasium_badge]: https://gemnasium.com/gonzedge/rambling-trie.svg
|
168
267
|
[gemnasium_link]: https://gemnasium.com/gonzedge/rambling-trie
|
268
|
+
[github_user_gonzedge]: https://github.com/gonzedge
|
169
269
|
[inch_ci_badge]: https://inch-ci.org/github/gonzedge/rambling-trie.svg?branch=master
|
170
270
|
[inch_ci_link]: https://inch-ci.org/github/gonzedge/rambling-trie
|
271
|
+
[marshal]: https://ruby-doc.org/core-2.4.0/Marshal.html
|
272
|
+
[rambling_trie_configuration]: https://github.com/gonzedge/rambling-trie#configuration
|
273
|
+
[rambling_trie_contributing_guide]: https://github.com/gonzedge/rambling-trie/blob/master/CONTRIBUTING.md
|
274
|
+
[rambling_trie_plain_text_reader]: https://github.com/gonzedge/rambling-trie/blob/master/lib/rambling/trie/readers/plain_text.rb
|
171
275
|
[rbenv]: https://github.com/sstephenson/rbenv
|
172
276
|
[rubydoc]: http://rubydoc.info/gems/rambling-trie
|
173
277
|
[rubydoc_github]: http://rubydoc.info/github/gonzedge/rambling-trie
|
278
|
+
[rubyzip]: https://github.com/rubyzip/rubyzip
|
174
279
|
[rvm]: https://rvm.io
|
175
280
|
[travis_ci_badge]: https://travis-ci.org/gonzedge/rambling-trie.svg
|
176
281
|
[travis_ci_link]: https://travis-ci.org/gonzedge/rambling-trie
|
282
|
+
[trie_wiki]: https://en.wikipedia.org/wiki/Trie
|
283
|
+
[yaml]: https://ruby-doc.org/stdlib-2.4.0/libdoc/yaml/rdoc/YAML.html
|
data/Rakefile
CHANGED
data/lib/rambling/trie.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'forwardable'
|
2
|
+
|
2
3
|
%w{
|
3
|
-
forwardable
|
4
|
-
invalid_operation
|
5
|
-
raw_node version
|
4
|
+
forwardable comparable compressable compressor configuration container
|
5
|
+
enumerable inspectable invalid_operation readers serializers stringifyable
|
6
|
+
node missing_node compressed_node raw_node version
|
6
7
|
}.each do |file|
|
7
8
|
require File.join('rambling', 'trie', file)
|
8
9
|
end
|
@@ -12,15 +13,25 @@ module Rambling
|
|
12
13
|
# Entry point for rambling-trie API.
|
13
14
|
module Trie
|
14
15
|
class << self
|
15
|
-
|
16
|
+
extend Rambling::Trie::Forwardable
|
17
|
+
|
18
|
+
delegate [
|
19
|
+
:readers,
|
20
|
+
:serializers,
|
21
|
+
:compressor,
|
22
|
+
:root_builder
|
23
|
+
] => :properties
|
24
|
+
|
25
|
+
# Creates a new Rambling::Trie. Entry point for the Rambling::Trie API.
|
16
26
|
# @param [String, nil] filepath the file to load the words from.
|
27
|
+
# @param [Reader, nil] reader the file parser to get each word. See
|
28
|
+
# {Rambling::Trie::Readers Readers}.
|
17
29
|
# @return [Container] the trie just created.
|
18
30
|
# @yield [Container] the trie just created.
|
19
31
|
def create filepath = nil, reader = nil
|
20
|
-
|
21
|
-
|
22
|
-
Rambling::Trie::Container.new do |container|
|
32
|
+
Rambling::Trie::Container.new root_builder.call, compressor do |container|
|
23
33
|
if filepath
|
34
|
+
reader ||= readers.resolve filepath
|
24
35
|
reader.each_word filepath do |word|
|
25
36
|
container << word
|
26
37
|
end
|
@@ -30,10 +41,43 @@ module Rambling
|
|
30
41
|
end
|
31
42
|
end
|
32
43
|
|
44
|
+
# Loads an existing trie from disk into memory.
|
45
|
+
# @param [String] filepath the file to load the words from.
|
46
|
+
# @param [Serializer, nil] serializer the object responsible of loading the trie
|
47
|
+
# from disk. See {Rambling::Trie::Serializers Serializers}.
|
48
|
+
# @return [Container] the trie just loaded.
|
49
|
+
# @yield [Container] the trie just loaded.
|
50
|
+
def load filepath, serializer = nil
|
51
|
+
serializer ||= serializers.resolve filepath
|
52
|
+
root = serializer.load filepath
|
53
|
+
Rambling::Trie::Container.new root, compressor do |container|
|
54
|
+
yield container if block_given?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Dumps an existing trie from memory into disk.
|
59
|
+
# @param [Container] trie the trie to dump into disk.
|
60
|
+
# @param [String] filepath the file to dump to serialized trie into.
|
61
|
+
# @param [Serializer, nil] serializer the object responsible of
|
62
|
+
# serializing and dumping the trie into disk. See
|
63
|
+
# {Rambling::Trie::Serializers Serializers}.
|
64
|
+
def dump trie, filepath, serializer = nil
|
65
|
+
serializer ||= serializers.resolve filepath
|
66
|
+
serializer.dump trie.root, filepath
|
67
|
+
end
|
68
|
+
|
69
|
+
# Provides configuration properties for the Rambling::Trie gem.
|
70
|
+
# @return [Properties] the configured properties of the gem.
|
71
|
+
# @yield [Properties] the configured properties of the gem.
|
72
|
+
def config
|
73
|
+
yield properties if block_given?
|
74
|
+
properties
|
75
|
+
end
|
76
|
+
|
33
77
|
private
|
34
78
|
|
35
|
-
def
|
36
|
-
Rambling::Trie::
|
79
|
+
def properties
|
80
|
+
@properties ||= Rambling::Trie::Configuration::Properties.new
|
37
81
|
end
|
38
82
|
end
|
39
83
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rambling
|
2
|
+
module Trie
|
3
|
+
# Provides the comparable behavior for the trie data structure.
|
4
|
+
module Comparable
|
5
|
+
# Compares two nodes.
|
6
|
+
# @param [Node] other the node to compare against.
|
7
|
+
# @return [Boolean] `true` if the nodes' {Node#letter #letter} and
|
8
|
+
# {Node#children_tree #children_tree} are equal, `false` otherwise.
|
9
|
+
def == other
|
10
|
+
letter == other.letter &&
|
11
|
+
terminal? == other.terminal? &&
|
12
|
+
children_tree == other.children_tree
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Rambling
|
2
|
+
module Trie
|
3
|
+
# Provides the compressable behavior for the trie data structure.
|
4
|
+
module Compressable
|
5
|
+
# Indicates if the current {Rambling::Trie::Node Node} can be compressed
|
6
|
+
# or not.
|
7
|
+
# @return [Boolean] `true` for non-{Node#terminal? terminal} nodes with
|
8
|
+
# one child, `false` otherwise.
|
9
|
+
def compressable?
|
10
|
+
!(root? || terminal?) && children_tree.size == 1
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,39 +1,41 @@
|
|
1
1
|
module Rambling
|
2
2
|
module Trie
|
3
|
-
# A representation of a node in an compressed
|
3
|
+
# A representation of a node in an compressed trie data structure.
|
4
4
|
class CompressedNode < Rambling::Trie::Node
|
5
|
-
# Always raises
|
6
|
-
#
|
7
|
-
# @param [String] word the word to add the
|
5
|
+
# Always raises {Rambling::Trie::InvalidOperation InvalidOperation} when
|
6
|
+
# trying to add a word to the current compressed trie node
|
7
|
+
# @param [String] word the word to add to the trie.
|
8
8
|
# @raise [InvalidOperation] if the trie is already compressed.
|
9
|
+
# @return [nil] this never returns as it always raises an exception.
|
9
10
|
def add word
|
10
|
-
raise Rambling::Trie::InvalidOperation, 'Cannot add
|
11
|
+
raise Rambling::Trie::InvalidOperation, 'Cannot add word to compressed trie'
|
11
12
|
end
|
12
13
|
|
13
|
-
# Checks if a path for set of characters exists in the trie.
|
14
|
-
# @param [Array] chars the characters to look for in the trie.
|
14
|
+
# Checks if a path for set a of characters exists in the trie.
|
15
|
+
# @param [Array<String>] chars the characters to look for in the trie.
|
15
16
|
# @return [Boolean] `true` if the characters are found, `false` otherwise.
|
16
17
|
def partial_word? chars
|
17
18
|
chars.empty? || has_partial_word?(chars)
|
18
19
|
end
|
19
20
|
|
20
21
|
# Checks if a path for set of characters represents a word in the trie.
|
21
|
-
# @param [Array] chars the characters to look for in the trie.
|
22
|
+
# @param [Array<String>] chars the characters to look for in the trie.
|
22
23
|
# @return [Boolean] `true` if the characters are found and form a word,
|
23
|
-
#
|
24
|
+
# `false` otherwise.
|
24
25
|
def word? chars
|
25
26
|
chars.empty? ? terminal? : has_word?(chars)
|
26
27
|
end
|
27
28
|
|
28
|
-
# Returns
|
29
|
-
# @param [Array] chars the characters to look for in the trie.
|
30
|
-
# @return [
|
29
|
+
# Returns the node that starts with the specified characters.
|
30
|
+
# @param [Array<String>] chars the characters to look for in the trie.
|
31
|
+
# @return [Node] the node that matches the specified characters.
|
32
|
+
# {MissingNode MissingNode} when not found.
|
31
33
|
def scan chars
|
32
34
|
chars.empty? ? self : closest_node(chars)
|
33
35
|
end
|
34
36
|
|
35
|
-
# Always return `true` for a
|
36
|
-
# @return [Boolean] always true for a
|
37
|
+
# Always return `true` for a compressed node.
|
38
|
+
# @return [Boolean] always `true` for a compressed node.
|
37
39
|
def compressed?
|
38
40
|
true
|
39
41
|
end
|
@@ -65,6 +67,28 @@ module Rambling
|
|
65
67
|
recursive_get(:scan, chars) || Rambling::Trie::MissingNode.new
|
66
68
|
end
|
67
69
|
|
70
|
+
def children_match_prefix chars
|
71
|
+
return enum_for :children_match_prefix, chars unless block_given?
|
72
|
+
|
73
|
+
current_key = nil
|
74
|
+
|
75
|
+
while !chars.empty?
|
76
|
+
if current_key
|
77
|
+
current_key << chars.slice!(0)
|
78
|
+
else
|
79
|
+
current_key = chars.slice!(0)
|
80
|
+
end
|
81
|
+
|
82
|
+
child = children_tree[current_key.to_sym]
|
83
|
+
|
84
|
+
if child
|
85
|
+
child.match_prefix chars do |word|
|
86
|
+
yield word
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
68
92
|
def recursive_get method, chars
|
69
93
|
current_length = 0
|
70
94
|
current_key = current_key chars.slice!(0)
|