rambling-trie 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.travis.yml +6 -1
- data/Gemfile +3 -1
- data/LICENSE +1 -1
- data/README.markdown +26 -15
- data/lib/rambling/trie.rb +1 -1
- data/lib/rambling/trie/branches.rb +20 -13
- data/lib/rambling/trie/compressor.rb +3 -5
- data/lib/rambling/trie/enumerable.rb +1 -1
- data/lib/rambling/trie/invalid_operation.rb +1 -1
- data/lib/rambling/trie/node.rb +6 -7
- data/lib/rambling/trie/plain_text_reader.rb +3 -3
- data/lib/rambling/trie/root.rb +5 -13
- data/lib/rambling/trie/tasks/performance.rb +4 -4
- data/lib/rambling/trie/version.rb +1 -1
- data/rambling-trie.gemspec +6 -5
- data/spec/integration/rambling/trie_spec.rb +3 -3
- data/spec/lib/rambling/trie/branches_spec.rb +5 -6
- data/spec/lib/rambling/trie/enumerable_spec.rb +2 -2
- data/spec/lib/rambling/trie/inspector_spec.rb +2 -2
- data/spec/lib/rambling/trie/node_spec.rb +14 -14
- data/spec/lib/rambling/trie/plain_text_reader_spec.rb +1 -1
- data/spec/lib/rambling/trie/root_spec.rb +33 -41
- data/spec/lib/rambling/trie_spec.rb +7 -6
- data/spec/spec_helper.rb +9 -7
- metadata +31 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6379fbb202c3257cad63367006a150b801b69649
|
4
|
+
data.tar.gz: 9b4b9f07ec20f5e7a2aef641d06501a03cc20195
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 043f1af6cd0b8390585e44b73e63101810f5506198e0ee5adbbe8708b394c8a0bc3db5ce3bdfae4e5fbcb9c1b6692cebf25f5412df2d74926352119690aed573
|
7
|
+
data.tar.gz: 7de76f2ad5e324e1a500bd2f33a80ade73a9c7a1488062ce4ea01fa982dad33955dd724c469ad1f7eeb4c49e69c1e91fc46e62270eaa65b44db5cb288ccc4362
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -2,10 +2,12 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
+
gem 'coveralls', require: false
|
6
|
+
|
5
7
|
group :test do
|
6
8
|
gem 'rake'
|
7
9
|
gem 'guard-rspec'
|
8
10
|
gem 'rb-fsevent'
|
9
11
|
gem 'rb-inotify'
|
10
|
-
gem 'simplecov', require: false
|
12
|
+
gem 'simplecov', '~> 0.9.1', require: false
|
11
13
|
end
|
data/LICENSE
CHANGED
data/README.markdown
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
# Rambling Trie
|
1
|
+
# Rambling Trie
|
2
|
+
|
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]
|
2
4
|
|
3
5
|
The Rambling Trie is a custom implementation of the Trie data structure with Ruby, which includes compression abilities and is designed to be very fast to traverse.
|
4
6
|
|
@@ -8,17 +10,18 @@ The Rambling Trie is a custom implementation of the Trie data structure with Rub
|
|
8
10
|
|
9
11
|
You will need:
|
10
12
|
|
11
|
-
* Ruby 1.9.
|
13
|
+
* Ruby 1.9.3 or up
|
12
14
|
* RubyGems
|
13
15
|
|
14
|
-
See [RVM]
|
16
|
+
See [RVM][rvm] or [rbenv][rbenv] for more information on how to manage Ruby versions.
|
15
17
|
|
16
18
|
### Installation
|
17
19
|
|
18
20
|
You can either install it manually with:
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
+
``` bash
|
23
|
+
gem install rambling-trie
|
24
|
+
```
|
22
25
|
|
23
26
|
Or, include it in your `Gemfile` and bundle it:
|
24
27
|
|
@@ -143,23 +146,17 @@ trie.any? { |word| word.include? 'x' }
|
|
143
146
|
|
144
147
|
## Further Documentation
|
145
148
|
|
146
|
-
You can find further API documentation on the autogenerated [rambling-trie gem RubyDoc.info page]
|
149
|
+
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].
|
147
150
|
|
148
151
|
## Compatible Ruby and Rails versions
|
149
152
|
|
150
153
|
The Rambling Trie has been tested with the following Ruby versions:
|
151
154
|
|
155
|
+
* 2.1.x
|
152
156
|
* 2.0.0
|
153
157
|
* 1.9.3
|
154
|
-
* 1.9.2
|
155
|
-
|
156
|
-
And the following Rails versions:
|
157
|
-
|
158
|
-
* 3.2.x
|
159
|
-
* 3.1.x
|
160
158
|
|
161
|
-
|
162
|
-
Ruby 1.8.7 is not supported.
|
159
|
+
Ruby 1.8.7 and 1.9.2 are not supported.
|
163
160
|
|
164
161
|
## Contributing to Rambling Trie
|
165
162
|
|
@@ -168,7 +165,7 @@ Also, be sure to add tests for any feature you may develop or bug you may fix.
|
|
168
165
|
|
169
166
|
## License and copyright
|
170
167
|
|
171
|
-
Copyright (c) 2012-
|
168
|
+
Copyright (c) 2012-2014 Edgar Gonzalez
|
172
169
|
|
173
170
|
MIT License
|
174
171
|
|
@@ -178,3 +175,17 @@ The above copyright notice and this permission notice shall be included in all c
|
|
178
175
|
|
179
176
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
180
177
|
|
178
|
+
[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg
|
179
|
+
[badge_fury_link]: https://badge.fury.io/rb/rambling-trie
|
180
|
+
[code_climate_badge]: https://codeclimate.com/github/gonzedge/rambling-trie.png
|
181
|
+
[code_climage_link]: https://codeclimate.com/github/gonzedge/rambling-trie
|
182
|
+
[coveralls_badge]: https://coveralls.io/repos/gonzedge/rambling-trie/badge.png
|
183
|
+
[coveralls_link]: https://coveralls.io/r/gonzedge/rambling-trie
|
184
|
+
[gemnasium_badge]: https://gemnasium.com/gonzedge/rambling-trie.svg
|
185
|
+
[gemnasium_link]: https://gemnasium.com/gonzedge/rambling-trie
|
186
|
+
[travis_ci_badge]: https://secure.travis-ci.org/gonzedge/rambling-trie.svg
|
187
|
+
[travis_ci_link]: https://travis-ci.org/gonzedge/rambling-trie
|
188
|
+
[rvm]: https://rvm.io
|
189
|
+
[rbenv]: https://github.com/sstephenson/rbenv
|
190
|
+
[rubydoc]: http://rubydoc.info/gems/rambling-trie
|
191
|
+
[rubydoc_github]: http://rubydoc.info/github/gonzedge/rambling-trie
|
data/lib/rambling/trie.rb
CHANGED
@@ -14,7 +14,7 @@ module Rambling
|
|
14
14
|
# @param [String, nil] filepath the file to load the words from.
|
15
15
|
# @return [Root] the trie just created.
|
16
16
|
# @yield [Root] the trie just created.
|
17
|
-
def create
|
17
|
+
def create filepath = nil, reader = PlainTextReader.new
|
18
18
|
Root.new do |root|
|
19
19
|
reader.each_word(filepath) { |word| root << word } if filepath
|
20
20
|
yield root if block_given?
|
@@ -7,7 +7,7 @@ module Rambling
|
|
7
7
|
# @return [Node] the just added branch's root node.
|
8
8
|
# @raise [InvalidOperation] if the trie is already compressed.
|
9
9
|
# @note This method clears the contents of the word variable.
|
10
|
-
def add
|
10
|
+
def add word
|
11
11
|
raise InvalidOperation, 'Cannot add branch to compressed trie' if compressed?
|
12
12
|
if word.empty?
|
13
13
|
self.terminal = true
|
@@ -16,19 +16,26 @@ module Rambling
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
# Alias for #add
|
20
|
+
# @param [String] word the word to add the branch from.
|
21
|
+
# @return [Node] the just added branch's root node.
|
22
|
+
# @raise [InvalidOperation] if the trie is already compressed.
|
23
|
+
# @see Branches#add
|
24
|
+
def << word
|
25
|
+
add word
|
26
|
+
end
|
20
27
|
|
21
28
|
protected
|
22
29
|
|
23
|
-
def partial_word_when_uncompressed?
|
30
|
+
def partial_word_when_uncompressed? chars
|
24
31
|
chars.empty? || fulfills_uncompressed_condition?(:partial_word_when_uncompressed?, chars)
|
25
32
|
end
|
26
33
|
|
27
|
-
def partial_word_when_compressed?
|
34
|
+
def partial_word_when_compressed? chars
|
28
35
|
chars.empty? || compressed_trie_has_partial_word?(chars)
|
29
36
|
end
|
30
37
|
|
31
|
-
def word_when_uncompressed?
|
38
|
+
def word_when_uncompressed? chars
|
32
39
|
if chars.empty?
|
33
40
|
terminal?
|
34
41
|
else
|
@@ -36,7 +43,7 @@ module Rambling
|
|
36
43
|
end
|
37
44
|
end
|
38
45
|
|
39
|
-
def word_when_compressed?
|
46
|
+
def word_when_compressed? chars
|
40
47
|
if chars.empty?
|
41
48
|
terminal?
|
42
49
|
else
|
@@ -46,7 +53,7 @@ module Rambling
|
|
46
53
|
|
47
54
|
private
|
48
55
|
|
49
|
-
def add_to_children_tree
|
56
|
+
def add_to_children_tree word
|
50
57
|
first_letter = word.slice(0).to_sym
|
51
58
|
|
52
59
|
if children_tree.has_key? first_letter
|
@@ -59,7 +66,7 @@ module Rambling
|
|
59
66
|
end
|
60
67
|
end
|
61
68
|
|
62
|
-
def compressed_trie_has_partial_word?
|
69
|
+
def compressed_trie_has_partial_word? chars
|
63
70
|
current_length = 0
|
64
71
|
current_key, current_key_string = current_key chars.slice!(0)
|
65
72
|
|
@@ -67,26 +74,26 @@ module Rambling
|
|
67
74
|
current_length += 1
|
68
75
|
|
69
76
|
if current_key_string.length == current_length || chars.empty?
|
70
|
-
return children_tree[current_key].partial_word_when_compressed?
|
77
|
+
return children_tree[current_key].partial_word_when_compressed? chars
|
71
78
|
end
|
72
79
|
end while current_key_string[current_length] == chars.slice!(0)
|
73
80
|
|
74
81
|
false
|
75
82
|
end
|
76
83
|
|
77
|
-
def compressed_trie_has_word?
|
84
|
+
def compressed_trie_has_word? chars
|
78
85
|
current_key_string = ''
|
79
86
|
|
80
87
|
while !chars.empty?
|
81
88
|
current_key_string << chars.slice!(0)
|
82
89
|
current_key = current_key_string.to_sym
|
83
|
-
return children_tree[current_key].word_when_compressed?
|
90
|
+
return children_tree[current_key].word_when_compressed? chars if children_tree.has_key? current_key
|
84
91
|
end
|
85
92
|
|
86
93
|
false
|
87
94
|
end
|
88
95
|
|
89
|
-
def current_key
|
96
|
+
def current_key letter
|
90
97
|
current_key_string = current_key = nil
|
91
98
|
|
92
99
|
children_tree.keys.each do |key|
|
@@ -101,7 +108,7 @@ module Rambling
|
|
101
108
|
[current_key, current_key_string]
|
102
109
|
end
|
103
110
|
|
104
|
-
def fulfills_uncompressed_condition?
|
111
|
+
def fulfills_uncompressed_condition? method, chars
|
105
112
|
first_letter_sym = chars.slice!(0).to_sym
|
106
113
|
children_tree.has_key?(first_letter_sym) && children_tree[first_letter_sym].send(method, chars)
|
107
114
|
end
|
@@ -27,7 +27,7 @@ module Rambling
|
|
27
27
|
!(root? || terminal?) && children_tree.size == 1
|
28
28
|
end
|
29
29
|
|
30
|
-
def merge_with!
|
30
|
+
def merge_with! child
|
31
31
|
delete_old_key_on_parent!
|
32
32
|
redefine_self! child
|
33
33
|
|
@@ -35,12 +35,10 @@ module Rambling
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def delete_old_key_on_parent!
|
38
|
-
|
39
|
-
|
40
|
-
parent.delete letter
|
38
|
+
parent.delete letter if parent
|
41
39
|
end
|
42
40
|
|
43
|
-
def redefine_self!
|
41
|
+
def redefine_self! merged_node
|
44
42
|
self.letter = letter.to_s << merged_node.letter.to_s
|
45
43
|
self.children_tree = merged_node.children_tree
|
46
44
|
self.terminal = merged_node.terminal?
|
@@ -7,7 +7,7 @@ module Rambling
|
|
7
7
|
alias_method :size, :count
|
8
8
|
|
9
9
|
# Calls block once for each of the words contained in the trie. If no block given, an Enumerator is returned.
|
10
|
-
def each
|
10
|
+
def each &block
|
11
11
|
enumerator = Enumerator.new do |words|
|
12
12
|
words << as_word if terminal?
|
13
13
|
children.each { |child| child.each { |word| words << word } }
|
data/lib/rambling/trie/node.rb
CHANGED
@@ -26,7 +26,7 @@ module Rambling
|
|
26
26
|
# Creates a new Node.
|
27
27
|
# @param [String, nil] word the word from which to create this Node and his branch.
|
28
28
|
# @param [Node, nil] parent the parent of this node.
|
29
|
-
def initialize
|
29
|
+
def initialize word = nil, parent = nil
|
30
30
|
self.parent = parent
|
31
31
|
self.children_tree = {}
|
32
32
|
|
@@ -74,12 +74,11 @@ module Rambling
|
|
74
74
|
attr_writer :children_tree
|
75
75
|
attr_accessor :terminal
|
76
76
|
|
77
|
-
def letter=
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
parent[letter] = self if parent
|
77
|
+
def letter= new_letter
|
78
|
+
if new_letter
|
79
|
+
@letter = new_letter.to_sym
|
80
|
+
parent[letter] = self if parent
|
81
|
+
end
|
83
82
|
end
|
84
83
|
end
|
85
84
|
end
|
@@ -5,17 +5,17 @@ module Rambling
|
|
5
5
|
# Yields each word read from a .txt file
|
6
6
|
# @param [String] filepath the full path of the file to load the words from.
|
7
7
|
# @yield [String] Each line read from the file.
|
8
|
-
def each_word
|
8
|
+
def each_word filepath
|
9
9
|
each_line(filepath) { |line| yield line.chomp }
|
10
10
|
end
|
11
11
|
|
12
12
|
private
|
13
13
|
|
14
|
-
def each_line
|
14
|
+
def each_line filepath
|
15
15
|
open(filepath) { |file| file.each_line { |line| yield line } }
|
16
16
|
end
|
17
17
|
|
18
|
-
def open
|
18
|
+
def open filepath
|
19
19
|
File.open(filepath) { |file| yield file }
|
20
20
|
end
|
21
21
|
end
|
data/lib/rambling/trie/root.rb
CHANGED
@@ -16,22 +16,14 @@ module Rambling
|
|
16
16
|
# @raise [InvalidOperation] if the trie is already compressed.
|
17
17
|
# @see Branches#add
|
18
18
|
# @note Avoids clearing the contents of the word variable.
|
19
|
-
def add
|
19
|
+
def add word
|
20
20
|
super word.clone
|
21
21
|
end
|
22
22
|
|
23
|
-
alias_method :<<, :add
|
24
|
-
|
25
|
-
# @deprecated Use `#partial_word?` instead.
|
26
|
-
def branch?(word = '')
|
27
|
-
warn 'The `#branch?` method will be deprecated, please use `#partial_word?` instead.'
|
28
|
-
partial_word? word
|
29
|
-
end
|
30
|
-
|
31
23
|
# Compresses the existing tree using redundant node elimination. Flags the trie as compressed.
|
32
24
|
# @return [Root] self
|
33
25
|
def compress!
|
34
|
-
self.compressed =
|
26
|
+
self.compressed = compressed? || !!compress_tree!
|
35
27
|
self
|
36
28
|
end
|
37
29
|
|
@@ -44,7 +36,7 @@ module Rambling
|
|
44
36
|
# Checks if a path for a word or partial word exists in the trie.
|
45
37
|
# @param [String] word the word or partial word to look for in the trie.
|
46
38
|
# @return [Boolean] `true` if the word or partial word is found, `false` otherwise.
|
47
|
-
def partial_word?
|
39
|
+
def partial_word? word = ''
|
48
40
|
is? :partial_word, word
|
49
41
|
end
|
50
42
|
|
@@ -59,7 +51,7 @@ module Rambling
|
|
59
51
|
# Checks if a whole word exists in the trie.
|
60
52
|
# @param [String] word the word to look for in the trie.
|
61
53
|
# @return [Boolean] `true` only if the word is found and the last character corresponds to a terminal node.
|
62
|
-
def word?
|
54
|
+
def word? word = ''
|
63
55
|
is? :word, word
|
64
56
|
end
|
65
57
|
|
@@ -69,7 +61,7 @@ module Rambling
|
|
69
61
|
|
70
62
|
attr_accessor :compressed
|
71
63
|
|
72
|
-
def is?
|
64
|
+
def is? method, word
|
73
65
|
method = compressed? ? "#{method}_when_compressed?" : "#{method}_when_uncompressed?"
|
74
66
|
send method, word.chars.to_a
|
75
67
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'benchmark'
|
2
2
|
|
3
3
|
namespace :performance do
|
4
|
-
def report
|
4
|
+
def report name, trie, output
|
5
5
|
words = %w(hi help beautiful impressionism anthropological)
|
6
6
|
methods = [:word?, :partial_word?]
|
7
7
|
|
@@ -9,13 +9,13 @@ namespace :performance do
|
|
9
9
|
methods.each do |method|
|
10
10
|
output.puts "`#{method}`:"
|
11
11
|
words.each do |word|
|
12
|
-
output.print "#{word} - #{trie.send
|
12
|
+
output.print "#{word} - #{trie.send method, word}".ljust 30
|
13
13
|
output.puts Benchmark.measure { 200_000.times { trie.send method, word }}
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def generate_report
|
18
|
+
def generate_report filename = nil
|
19
19
|
output = filename.nil? ? $stdout : File.open(filename, 'a+')
|
20
20
|
|
21
21
|
output.puts "\nReport for rambling-trie version #{Rambling::Trie::VERSION}"
|
@@ -39,7 +39,7 @@ namespace :performance do
|
|
39
39
|
output.close
|
40
40
|
end
|
41
41
|
|
42
|
-
def path
|
42
|
+
def path *filename
|
43
43
|
File.join File.dirname(__FILE__), '..', '..', '..', '..', *filename
|
44
44
|
end
|
45
45
|
|
data/rambling-trie.gemspec
CHANGED
@@ -16,12 +16,13 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.require_paths = ['lib']
|
17
17
|
|
18
18
|
gem.name = 'rambling-trie'
|
19
|
+
gem.license = 'MIT'
|
19
20
|
gem.version = Rambling::Trie::VERSION
|
20
21
|
gem.platform = Gem::Platform::RUBY
|
21
22
|
|
22
|
-
gem.add_development_dependency 'rspec', '
|
23
|
-
gem.add_development_dependency 'rake', '
|
24
|
-
gem.add_development_dependency 'ruby-prof', '
|
25
|
-
gem.add_development_dependency 'yard', '
|
26
|
-
gem.add_development_dependency 'redcarpet', '
|
23
|
+
gem.add_development_dependency 'rspec', '~> 3.1'
|
24
|
+
gem.add_development_dependency 'rake', '~> 10.4'
|
25
|
+
gem.add_development_dependency 'ruby-prof', '~> 0.15.2'
|
26
|
+
gem.add_development_dependency 'yard', '~> 0.8.7'
|
27
|
+
gem.add_development_dependency 'redcarpet', '~> 3.2.1'
|
27
28
|
end
|
@@ -2,18 +2,18 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Rambling::Trie do
|
4
4
|
describe 'when a filepath is provided' do
|
5
|
-
let(:filepath) { File.join
|
5
|
+
let(:filepath) { File.join ::SPEC_ROOT, 'assets', 'test_words.txt' }
|
6
6
|
let(:words) { File.readlines(filepath).map &:chomp }
|
7
7
|
subject { Rambling::Trie.create filepath }
|
8
8
|
|
9
9
|
it 'contains all the words from the file' do
|
10
|
-
words.each { |word| expect(subject).to include
|
10
|
+
words.each { |word| expect(subject).to include word }
|
11
11
|
end
|
12
12
|
|
13
13
|
describe 'and the trie is compressed' do
|
14
14
|
it 'still contains all the words from the file' do
|
15
15
|
subject.compress!
|
16
|
-
words.each { |word| expect(subject).to include
|
16
|
+
words.each { |word| expect(subject).to include word }
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -12,7 +12,7 @@ module Rambling
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'does not increment the child count' do
|
15
|
-
expect(node).to
|
15
|
+
expect(node.children.size).to eq 1
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'marks it as terminal' do
|
@@ -32,17 +32,16 @@ module Rambling
|
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'does not increment any child count' do
|
35
|
-
expect(node).to
|
36
|
-
expect(node[:a]).to
|
37
|
-
expect(node[:a][:c]).to
|
38
|
-
expect(node[:a][:c][:k]).to
|
35
|
+
expect(node.children.size).to eq 1
|
36
|
+
expect(node[:a].children.size).to eq 1
|
37
|
+
expect(node[:a][:c].children.size).to eq 1
|
38
|
+
expect(node[:a][:c][:k].children.size).to eq 0
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
describe '#<<' do
|
44
44
|
let(:node) { Node.new }
|
45
|
-
let(:word) { 'word' }
|
46
45
|
|
47
46
|
it 'delegates to #add' do
|
48
47
|
expect((node << 'a').letter).to eq :a
|
@@ -28,8 +28,8 @@ module Rambling
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'includes the core Enumerable module' do
|
31
|
-
expect(root.all? { |word| words.include? word }).to
|
32
|
-
expect(root.any? { |word| word.start_with? 's' }).to
|
31
|
+
expect(root.all? { |word| words.include? word }).to be true
|
32
|
+
expect(root.any? { |word| word.start_with? 's' }).to be true
|
33
33
|
expect(root.to_a).to match_array words
|
34
34
|
end
|
35
35
|
end
|
@@ -13,8 +13,8 @@ module Rambling
|
|
13
13
|
|
14
14
|
describe '#inspect' do
|
15
15
|
it 'returns a pretty printed version of the node' do
|
16
|
-
expect(root.inspect).to eq
|
17
|
-
expect(node.inspect).to eq
|
16
|
+
expect(root.inspect).to eq "#<Rambling::Trie::Root letter: nil, children: [:o, :t, :w]>"
|
17
|
+
expect(node.inspect).to eq "#<Rambling::Trie::Node letter: :o, children: [:n]>"
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -4,31 +4,31 @@ module Rambling
|
|
4
4
|
module Trie
|
5
5
|
describe Node do
|
6
6
|
it 'delegates `#[]` to its children tree' do
|
7
|
-
subject.children_tree.
|
7
|
+
expect(subject.children_tree).to receive(:[]).with(:key).and_return('value')
|
8
8
|
expect(subject[:key]).to eq 'value'
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'delegates `#[]=` to its children tree' do
|
12
|
-
subject.children_tree.
|
12
|
+
expect(subject.children_tree).to receive(:[]=).with(:key, 'value')
|
13
13
|
subject[:key] = 'value'
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'delegates `#delete` to its children tree' do
|
17
|
-
subject.children_tree.
|
17
|
+
expect(subject.children_tree).to receive(:delete).with(:key).and_return('value')
|
18
18
|
expect(subject.delete :key).to eq 'value'
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'delegates `#has_key?` to its children tree' do
|
22
|
-
subject.children_tree.
|
22
|
+
expect(subject.children_tree).to receive(:has_key?).with(:present_key).and_return(true)
|
23
23
|
expect(subject).to have_key(:present_key)
|
24
24
|
|
25
|
-
subject.children_tree.
|
25
|
+
expect(subject.children_tree).to receive(:has_key?).with(:absent_key).and_return(false)
|
26
26
|
expect(subject).not_to have_key(:absent_key)
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'delegates `#children` to its children tree values' do
|
30
|
-
children = [double(
|
31
|
-
subject.children_tree.
|
30
|
+
children = [double(:child_1), double(:child_2)]
|
31
|
+
expect(subject.children_tree).to receive(:values).and_return(children)
|
32
32
|
expect(subject.children).to eq children
|
33
33
|
end
|
34
34
|
|
@@ -47,7 +47,7 @@ module Rambling
|
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'includes no children' do
|
50
|
-
expect(subject).to
|
50
|
+
expect(subject.children.size).to eq 0
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'is not a terminal node' do
|
@@ -71,7 +71,7 @@ module Rambling
|
|
71
71
|
end
|
72
72
|
|
73
73
|
it 'includes no children' do
|
74
|
-
expect(subject).to
|
74
|
+
expect(subject.children.size).to eq 0
|
75
75
|
end
|
76
76
|
|
77
77
|
it 'is not a terminal node' do
|
@@ -95,7 +95,7 @@ module Rambling
|
|
95
95
|
end
|
96
96
|
|
97
97
|
it 'includes no children' do
|
98
|
-
expect(subject).to
|
98
|
+
expect(subject.children.size).to eq 0
|
99
99
|
end
|
100
100
|
|
101
101
|
it 'is a terminal node' do
|
@@ -111,7 +111,7 @@ module Rambling
|
|
111
111
|
end
|
112
112
|
|
113
113
|
it 'includes one child' do
|
114
|
-
expect(subject).to
|
114
|
+
expect(subject.children.size).to eq 1
|
115
115
|
end
|
116
116
|
|
117
117
|
it 'includes a child with the expected letter' do
|
@@ -200,12 +200,12 @@ module Rambling
|
|
200
200
|
end
|
201
201
|
|
202
202
|
describe '#compressed?' do
|
203
|
-
let(:root) { double
|
203
|
+
let(:root) { double :root }
|
204
204
|
subject { Node.new '', root }
|
205
205
|
|
206
206
|
context 'parent is compressed' do
|
207
207
|
before do
|
208
|
-
root.
|
208
|
+
allow(root).to receive(:compressed?).and_return true
|
209
209
|
end
|
210
210
|
|
211
211
|
it 'returns true' do
|
@@ -215,7 +215,7 @@ module Rambling
|
|
215
215
|
|
216
216
|
context 'parent is not compressed' do
|
217
217
|
before do
|
218
|
-
root.
|
218
|
+
allow(root).to receive(:compressed?).and_return false
|
219
219
|
end
|
220
220
|
|
221
221
|
it 'returns false' do
|
@@ -11,7 +11,7 @@ module Rambling
|
|
11
11
|
|
12
12
|
describe '.new' do
|
13
13
|
it 'has no children' do
|
14
|
-
expect(subject).to
|
14
|
+
expect(subject.children.size).to eq 0
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'has no letter' do
|
@@ -42,8 +42,8 @@ module Rambling
|
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'executes the block' do
|
45
|
-
expect(subject).to
|
46
|
-
expect(subject.word? 'test').to
|
45
|
+
expect(subject.children.size).to eq 1
|
46
|
+
expect(subject.word? 'test').to be true
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -82,7 +82,7 @@ module Rambling
|
|
82
82
|
|
83
83
|
it 'compresses into a single node without children' do
|
84
84
|
expect(subject[:all].letter).to eq :all
|
85
|
-
expect(subject[:all]).to
|
85
|
+
expect(subject[:all].children.size).to eq 0
|
86
86
|
expect(subject[:all]).to be_terminal
|
87
87
|
expect(subject[:all]).to be_compressed
|
88
88
|
end
|
@@ -97,13 +97,13 @@ module Rambling
|
|
97
97
|
|
98
98
|
it 'compresses into corresponding three nodes' do
|
99
99
|
expect(subject[:a].letter).to eq :a
|
100
|
-
expect(subject[:a]).to
|
100
|
+
expect(subject[:a].children.size).to eq 2
|
101
101
|
|
102
102
|
expect(subject[:a][:ll].letter).to eq :ll
|
103
103
|
expect(subject[:a][:sk].letter).to eq :sk
|
104
104
|
|
105
|
-
expect(subject[:a][:ll]).to
|
106
|
-
expect(subject[:a][:sk]).to
|
105
|
+
expect(subject[:a][:ll].children.size).to eq 0
|
106
|
+
expect(subject[:a][:sk].children.size).to eq 0
|
107
107
|
|
108
108
|
expect(subject[:a][:ll]).to be_terminal
|
109
109
|
expect(subject[:a][:sk]).to be_terminal
|
@@ -120,19 +120,19 @@ module Rambling
|
|
120
120
|
subject.compress!
|
121
121
|
|
122
122
|
expect(subject[:re].letter).to eq :re
|
123
|
-
expect(subject[:re]).to
|
123
|
+
expect(subject[:re].children.size).to eq 2
|
124
124
|
|
125
125
|
expect(subject[:re][:pa].letter).to eq :pa
|
126
126
|
expect(subject[:re][:st].letter).to eq :st
|
127
127
|
|
128
|
-
expect(subject[:re][:pa]).to
|
129
|
-
expect(subject[:re][:st]).to
|
128
|
+
expect(subject[:re][:pa].children.size).to eq 2
|
129
|
+
expect(subject[:re][:st].children.size).to eq 0
|
130
130
|
|
131
131
|
expect(subject[:re][:pa][:y].letter).to eq :y
|
132
132
|
expect(subject[:re][:pa][:int].letter).to eq :int
|
133
133
|
|
134
|
-
expect(subject[:re][:pa][:y]).to
|
135
|
-
expect(subject[:re][:pa][:int]).to
|
134
|
+
expect(subject[:re][:pa][:y].children.size).to eq 0
|
135
|
+
expect(subject[:re][:pa][:int].children.size).to eq 0
|
136
136
|
|
137
137
|
expect(subject[:re][:pa][:y].parent).to eq subject[:re][:pa]
|
138
138
|
expect(subject[:re][:pa][:int].parent).to eq subject[:re][:pa]
|
@@ -174,8 +174,8 @@ module Rambling
|
|
174
174
|
end
|
175
175
|
|
176
176
|
it 'matches the whole word' do
|
177
|
-
expect(subject.word? 'hello').to
|
178
|
-
expect(subject.word? 'high').to
|
177
|
+
expect(subject.word? 'hello').to be true
|
178
|
+
expect(subject.word? 'high').to be true
|
179
179
|
end
|
180
180
|
|
181
181
|
it 'is aliased as #include?' do
|
@@ -189,8 +189,8 @@ module Rambling
|
|
189
189
|
end
|
190
190
|
|
191
191
|
it 'matches the whole word' do
|
192
|
-
expect(subject.word? 'hello').to
|
193
|
-
expect(subject.word? 'high').to
|
192
|
+
expect(subject.word? 'hello').to be true
|
193
|
+
expect(subject.word? 'high').to be true
|
194
194
|
end
|
195
195
|
end
|
196
196
|
end
|
@@ -201,7 +201,7 @@ module Rambling
|
|
201
201
|
end
|
202
202
|
|
203
203
|
it 'does not match the whole word' do
|
204
|
-
expect(subject.word? 'halt').to
|
204
|
+
expect(subject.word? 'halt').to be false
|
205
205
|
end
|
206
206
|
|
207
207
|
it 'is aliased as #include?' do
|
@@ -214,7 +214,7 @@ module Rambling
|
|
214
214
|
end
|
215
215
|
|
216
216
|
it 'does not match the whole word' do
|
217
|
-
expect(subject.word? 'halt').to
|
217
|
+
expect(subject.word? 'halt').to be false
|
218
218
|
end
|
219
219
|
end
|
220
220
|
end
|
@@ -224,16 +224,8 @@ module Rambling
|
|
224
224
|
it 'is aliased as #match?' do
|
225
225
|
subject << 'hello'
|
226
226
|
subject << 'high'
|
227
|
-
expect(subject.match? 'hel').to
|
228
|
-
expect(subject.match? 'hig').to
|
229
|
-
end
|
230
|
-
|
231
|
-
it 'is aliased as #branch?, but with a warning' do
|
232
|
-
subject << 'hello'
|
233
|
-
subject << 'high'
|
234
|
-
subject.should_receive(:warn).with('The `#branch?` method will be deprecated, please use `#partial_word?` instead.').twice
|
235
|
-
expect(subject.branch? 'hel').to be_true
|
236
|
-
expect(subject.branch? 'hig').to be_true
|
227
|
+
expect(subject.match? 'hel').to be true
|
228
|
+
expect(subject.match? 'hig').to be true
|
237
229
|
end
|
238
230
|
|
239
231
|
context 'word is contained' do
|
@@ -243,8 +235,8 @@ module Rambling
|
|
243
235
|
end
|
244
236
|
|
245
237
|
it 'matches part of the word' do
|
246
|
-
expect(subject.partial_word? 'hell').to
|
247
|
-
expect(subject.partial_word? 'hig').to
|
238
|
+
expect(subject.partial_word? 'hell').to be true
|
239
|
+
expect(subject.partial_word? 'hig').to be true
|
248
240
|
end
|
249
241
|
|
250
242
|
context 'and the root has been compressed' do
|
@@ -253,13 +245,13 @@ module Rambling
|
|
253
245
|
end
|
254
246
|
|
255
247
|
it 'matches part of the word' do
|
256
|
-
expect(subject.partial_word? 'h').to
|
257
|
-
expect(subject.partial_word? 'he').to
|
258
|
-
expect(subject.partial_word? 'hell').to
|
259
|
-
expect(subject.partial_word? 'hello').to
|
260
|
-
expect(subject.partial_word? 'hi').to
|
261
|
-
expect(subject.partial_word? 'hig').to
|
262
|
-
expect(subject.partial_word? 'high').to
|
248
|
+
expect(subject.partial_word? 'h').to be true
|
249
|
+
expect(subject.partial_word? 'he').to be true
|
250
|
+
expect(subject.partial_word? 'hell').to be true
|
251
|
+
expect(subject.partial_word? 'hello').to be true
|
252
|
+
expect(subject.partial_word? 'hi').to be true
|
253
|
+
expect(subject.partial_word? 'hig').to be true
|
254
|
+
expect(subject.partial_word? 'high').to be true
|
263
255
|
end
|
264
256
|
end
|
265
257
|
end
|
@@ -270,8 +262,8 @@ module Rambling
|
|
270
262
|
end
|
271
263
|
|
272
264
|
it 'does not match any part of the word' do
|
273
|
-
expect(subject.partial_word? 'ha').to
|
274
|
-
expect(subject.partial_word? 'hal').to
|
265
|
+
expect(subject.partial_word? 'ha').to be false
|
266
|
+
expect(subject.partial_word? 'hal').to be false
|
275
267
|
end
|
276
268
|
|
277
269
|
context 'and the root has been compressed' do
|
@@ -280,8 +272,8 @@ module Rambling
|
|
280
272
|
end
|
281
273
|
|
282
274
|
it 'does not match any part of the word' do
|
283
|
-
expect(subject.partial_word? 'ha').to
|
284
|
-
expect(subject.partial_word? 'hal').to
|
275
|
+
expect(subject.partial_word? 'ha').to be false
|
276
|
+
expect(subject.partial_word? 'hal').to be false
|
285
277
|
end
|
286
278
|
end
|
287
279
|
end
|
@@ -3,9 +3,9 @@ require 'spec_helper'
|
|
3
3
|
module Rambling
|
4
4
|
describe Trie do
|
5
5
|
describe '.create' do
|
6
|
-
let(:root) { double
|
6
|
+
let(:root) { double :root }
|
7
7
|
|
8
|
-
before { Trie::Root.
|
8
|
+
before { allow(Trie::Root).to receive(:new).and_yield(root).and_return root }
|
9
9
|
|
10
10
|
it 'returns a new instance of the trie root node' do
|
11
11
|
expect(Trie.create).to eq root
|
@@ -21,16 +21,17 @@ module Rambling
|
|
21
21
|
|
22
22
|
context 'with a filepath' do
|
23
23
|
let(:filepath) { 'test_words.txt' }
|
24
|
-
let(:reader) { double
|
24
|
+
let(:reader) { double :reader }
|
25
25
|
let(:words) { %w(a couple of test words over here) }
|
26
26
|
|
27
27
|
before do
|
28
|
-
|
29
|
-
words.
|
28
|
+
receive_and_yield = receive(:each_word)
|
29
|
+
words.inject(receive_and_yield) { |yielder, word| yielder.and_yield word }
|
30
|
+
allow(reader).to receive_and_yield
|
30
31
|
end
|
31
32
|
|
32
33
|
it 'loads every word' do
|
33
|
-
words.each { |word| root.
|
34
|
+
words.each { |word| expect(root).to receive(:<<).with(word) }
|
34
35
|
|
35
36
|
Trie.create filepath, reader
|
36
37
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
SimpleCov::Formatter::HTMLFormatter,
|
6
|
+
Coveralls::SimpleCov::Formatter
|
7
|
+
]
|
8
|
+
|
2
9
|
SimpleCov.start do
|
3
10
|
add_filter '/spec/'
|
4
11
|
end
|
5
12
|
|
6
13
|
require 'rspec'
|
7
14
|
require 'rambling-trie'
|
8
|
-
::SPEC_ROOT = File.dirname
|
15
|
+
::SPEC_ROOT = File.dirname __FILE__
|
9
16
|
|
10
17
|
RSpec.configure do |config|
|
11
18
|
config.order = :random
|
12
|
-
config.treat_symbols_as_metadata_keys_with_true_values = true
|
13
19
|
config.run_all_when_everything_filtered = true
|
14
|
-
config.
|
15
|
-
|
16
|
-
config.expect_with :rspec do |c|
|
17
|
-
c.syntax = :expect
|
18
|
-
end
|
20
|
+
config.raise_errors_for_deprecations!
|
19
21
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rambling-trie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Edgar Gonzalez
|
@@ -9,78 +9,78 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-12-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- -
|
18
|
+
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version:
|
20
|
+
version: '3.1'
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- -
|
25
|
+
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version:
|
27
|
+
version: '3.1'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rake
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- -
|
32
|
+
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 10.
|
34
|
+
version: '10.4'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- -
|
39
|
+
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 10.
|
41
|
+
version: '10.4'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: ruby-prof
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- -
|
46
|
+
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: 0.
|
48
|
+
version: 0.15.2
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- -
|
53
|
+
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: 0.
|
55
|
+
version: 0.15.2
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: yard
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- -
|
60
|
+
- - "~>"
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: 0.8.
|
62
|
+
version: 0.8.7
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- -
|
67
|
+
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: 0.8.
|
69
|
+
version: 0.8.7
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: redcarpet
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- -
|
74
|
+
- - "~>"
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
76
|
+
version: 3.2.1
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- -
|
81
|
+
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version:
|
83
|
+
version: 3.2.1
|
84
84
|
description: The Rambling Trie is a custom implementation of the Trie data structure
|
85
85
|
with Ruby, which includes compression abilities and is designed to be very fast
|
86
86
|
to traverse.
|
@@ -91,9 +91,10 @@ executables: []
|
|
91
91
|
extensions: []
|
92
92
|
extra_rdoc_files: []
|
93
93
|
files:
|
94
|
-
- .
|
95
|
-
- .
|
96
|
-
- .
|
94
|
+
- ".coveralls.yml"
|
95
|
+
- ".gitignore"
|
96
|
+
- ".rspec"
|
97
|
+
- ".travis.yml"
|
97
98
|
- Gemfile
|
98
99
|
- Guardfile
|
99
100
|
- LICENSE
|
@@ -126,7 +127,8 @@ files:
|
|
126
127
|
- spec/lib/rambling/trie_spec.rb
|
127
128
|
- spec/spec_helper.rb
|
128
129
|
homepage: http://github.com/gonzedge/rambling-trie
|
129
|
-
licenses:
|
130
|
+
licenses:
|
131
|
+
- MIT
|
130
132
|
metadata: {}
|
131
133
|
post_install_message:
|
132
134
|
rdoc_options: []
|
@@ -134,17 +136,17 @@ require_paths:
|
|
134
136
|
- lib
|
135
137
|
required_ruby_version: !ruby/object:Gem::Requirement
|
136
138
|
requirements:
|
137
|
-
- -
|
139
|
+
- - ">="
|
138
140
|
- !ruby/object:Gem::Version
|
139
141
|
version: '0'
|
140
142
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
143
|
requirements:
|
142
|
-
- -
|
144
|
+
- - ">="
|
143
145
|
- !ruby/object:Gem::Version
|
144
146
|
version: '0'
|
145
147
|
requirements: []
|
146
148
|
rubyforge_project:
|
147
|
-
rubygems_version: 2.
|
149
|
+
rubygems_version: 2.4.3
|
148
150
|
signing_key:
|
149
151
|
specification_version: 4
|
150
152
|
summary: A custom implementation of the trie data structure.
|