rambling-trie-opal 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +26 -0
- data/Guardfile +10 -0
- data/LICENSE +26 -0
- data/README.md +301 -0
- data/Rakefile +15 -0
- data/lib/rambling-trie.rb +3 -0
- data/lib/rambling/trie.rb +119 -0
- data/lib/rambling/trie/comparable.rb +19 -0
- data/lib/rambling/trie/compressible.rb +16 -0
- data/lib/rambling/trie/compressor.rb +64 -0
- data/lib/rambling/trie/configuration.rb +16 -0
- data/lib/rambling/trie/configuration/properties.rb +75 -0
- data/lib/rambling/trie/configuration/provider_collection.rb +122 -0
- data/lib/rambling/trie/container.rb +226 -0
- data/lib/rambling/trie/enumerable.rb +29 -0
- data/lib/rambling/trie/inspectable.rb +39 -0
- data/lib/rambling/trie/invalid_operation.rb +15 -0
- data/lib/rambling/trie/nodes.rb +18 -0
- data/lib/rambling/trie/nodes/compressed.rb +98 -0
- data/lib/rambling/trie/nodes/missing.rb +12 -0
- data/lib/rambling/trie/nodes/node.rb +183 -0
- data/lib/rambling/trie/nodes/raw.rb +82 -0
- data/lib/rambling/trie/readers.rb +15 -0
- data/lib/rambling/trie/readers/plain_text.rb +18 -0
- data/lib/rambling/trie/serializers.rb +18 -0
- data/lib/rambling/trie/serializers/file.rb +27 -0
- data/lib/rambling/trie/serializers/marshal.rb +48 -0
- data/lib/rambling/trie/serializers/yaml.rb +55 -0
- data/lib/rambling/trie/serializers/zip.rb +74 -0
- data/lib/rambling/trie/stringifyable.rb +26 -0
- data/lib/rambling/trie/version.rb +8 -0
- data/rambling-trie-opal.gemspec +36 -0
- data/spec/assets/test_words.en_US.txt +23 -0
- data/spec/assets/test_words.es_DO.txt +24 -0
- data/spec/integration/rambling/trie_spec.rb +87 -0
- data/spec/lib/rambling/trie/comparable_spec.rb +97 -0
- data/spec/lib/rambling/trie/compressor_spec.rb +108 -0
- data/spec/lib/rambling/trie/configuration/properties_spec.rb +57 -0
- data/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +149 -0
- data/spec/lib/rambling/trie/container_spec.rb +591 -0
- data/spec/lib/rambling/trie/enumerable_spec.rb +42 -0
- data/spec/lib/rambling/trie/inspectable_spec.rb +56 -0
- data/spec/lib/rambling/trie/nodes/compressed_spec.rb +37 -0
- data/spec/lib/rambling/trie/nodes/node_spec.rb +9 -0
- data/spec/lib/rambling/trie/nodes/raw_spec.rb +179 -0
- data/spec/lib/rambling/trie/readers/plain_text_spec.rb +16 -0
- data/spec/lib/rambling/trie/serializers/file_spec.rb +13 -0
- data/spec/lib/rambling/trie/serializers/marshal_spec.rb +12 -0
- data/spec/lib/rambling/trie/serializers/yaml_spec.rb +12 -0
- data/spec/lib/rambling/trie/serializers/zip_spec.rb +28 -0
- data/spec/lib/rambling/trie/stringifyable_spec.rb +85 -0
- data/spec/lib/rambling/trie_spec.rb +182 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/support/config.rb +15 -0
- data/spec/support/helpers/add_word.rb +20 -0
- data/spec/support/helpers/one_line_heredoc.rb +11 -0
- data/spec/support/shared_examples/a_compressible_trie.rb +40 -0
- data/spec/support/shared_examples/a_serializable_trie.rb +30 -0
- data/spec/support/shared_examples/a_serializer.rb +37 -0
- data/spec/support/shared_examples/a_trie_data_structure.rb +31 -0
- data/spec/support/shared_examples/a_trie_node.rb +127 -0
- data/spec/support/shared_examples/a_trie_node_implementation.rb +152 -0
- data/spec/tmp/.gitkeep +0 -0
- metadata +179 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# %w(plain_text).each do |file|
|
4
|
+
# require File.join('rambling', 'trie', 'readers', file)
|
5
|
+
# end
|
6
|
+
|
7
|
+
require 'rambling/trie/readers/plain_text'
|
8
|
+
|
9
|
+
module Rambling
|
10
|
+
module Trie
|
11
|
+
# Namespace for all readers.
|
12
|
+
module Readers
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rambling
|
4
|
+
module Trie
|
5
|
+
module Readers
|
6
|
+
# File reader for .txt files.
|
7
|
+
class PlainText
|
8
|
+
# Yields each word read from a .txt file.
|
9
|
+
# @param [String] filepath the full path of the file to load the words
|
10
|
+
# from.
|
11
|
+
# @yield [String] Each line read from the file.
|
12
|
+
def each_word filepath
|
13
|
+
File.foreach(filepath) { |line| yield line.chomp! }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# %w(file marshal yaml zip).each do |file|
|
4
|
+
# require File.join('rambling', 'trie', 'serializers', file)
|
5
|
+
# end
|
6
|
+
|
7
|
+
require 'rambling/trie/serializers/file'
|
8
|
+
require 'rambling/trie/serializers/marshal'
|
9
|
+
require 'rambling/trie/serializers/yaml'
|
10
|
+
# require 'rambling/trie/serializers/zip'
|
11
|
+
|
12
|
+
module Rambling
|
13
|
+
module Trie
|
14
|
+
# Namespace for all serializers.
|
15
|
+
module Serializers
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rambling
|
4
|
+
module Trie
|
5
|
+
module Serializers
|
6
|
+
# Basic file serializer. Dumps/loads string contents from files.
|
7
|
+
class File
|
8
|
+
# Loads contents from a specified filepath.
|
9
|
+
# @param [String] filepath the filepath to load contents from.
|
10
|
+
# @return [String] all contents of the file.
|
11
|
+
def load filepath
|
12
|
+
::File.read filepath
|
13
|
+
end
|
14
|
+
|
15
|
+
# Dumps contents into a specified filepath.
|
16
|
+
# @param [String] contents the contents to dump.
|
17
|
+
# @param [String] filepath the filepath to dump the contents to.
|
18
|
+
# @return [Numeric] number of bytes written to disk.
|
19
|
+
def dump contents, filepath
|
20
|
+
::File.open filepath, 'w+' do |f|
|
21
|
+
f.write contents
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rambling
|
4
|
+
module Trie
|
5
|
+
module Serializers
|
6
|
+
# Serializer for Ruby marshal format (.marshal) files.
|
7
|
+
class Marshal
|
8
|
+
# Creates a new Marshal serializer.
|
9
|
+
# @param [Serializer] serializer the serializer responsible to write to
|
10
|
+
# and read from disk.
|
11
|
+
def initialize serializer = nil
|
12
|
+
@serializer = serializer || Rambling::Trie::Serializers::File.new
|
13
|
+
end
|
14
|
+
|
15
|
+
# Loads marshaled object from contents in filepath and deserializes it
|
16
|
+
# into a {Nodes::Node Node}.
|
17
|
+
# @param [String] filepath the full path of the file to load the
|
18
|
+
# marshaled object from.
|
19
|
+
# @return [Nodes::Node] The deserialized {Nodes::Node Node}.
|
20
|
+
# @see https://ruby-doc.org/core-2.5.0/Marshal.html#method-c-load
|
21
|
+
# Marshal.load
|
22
|
+
# @note Use of
|
23
|
+
# {https://ruby-doc.org/core-2.5.0/Marshal.html#method-c-load
|
24
|
+
# Marshal.load} is generally discouraged. Only use this with trusted
|
25
|
+
# input.
|
26
|
+
def load filepath
|
27
|
+
::Marshal.load serializer.load filepath
|
28
|
+
end
|
29
|
+
|
30
|
+
# Serializes a {Nodes::Node Node} and dumps it as a marshaled object
|
31
|
+
# into filepath.
|
32
|
+
# @param [Nodes::Node] node the node to serialize
|
33
|
+
# @param [String] filepath the full path of the file to dump the
|
34
|
+
# marshaled object into.
|
35
|
+
# @return [Numeric] number of bytes written to disk.
|
36
|
+
# @see https://ruby-doc.org/core-2.5.0/Marshal.html#method-c-dump
|
37
|
+
# Marshal.dump
|
38
|
+
def dump node, filepath
|
39
|
+
serializer.dump ::Marshal.dump(node), filepath
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :serializer
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rambling
|
4
|
+
module Trie
|
5
|
+
module Serializers
|
6
|
+
# Serializer for Ruby yaml format (.yaml) files.
|
7
|
+
class Yaml
|
8
|
+
# Creates a new Yaml serializer.
|
9
|
+
# @param [Serializer] serializer the serializer responsible to write to
|
10
|
+
# and read from disk.
|
11
|
+
def initialize serializer = nil
|
12
|
+
@serializer = serializer || Rambling::Trie::Serializers::File.new
|
13
|
+
end
|
14
|
+
|
15
|
+
# Loads serialized object from YAML file in filepath and deserializes
|
16
|
+
# it into a {Nodes::Node Node}.
|
17
|
+
# @param [String] filepath the full path of the file to load the
|
18
|
+
# serialized YAML object from.
|
19
|
+
# @return [Nodes::Node] The deserialized {Nodes::Node Node}.
|
20
|
+
# @see https://ruby-doc.org/stdlib-2.5.0/libdoc/psych/rdoc/Psych.html#method-c-safe_load
|
21
|
+
# Psych.safe_load
|
22
|
+
def load filepath
|
23
|
+
require 'yaml'
|
24
|
+
::YAML.safe_load(
|
25
|
+
serializer.load(filepath),
|
26
|
+
[
|
27
|
+
Symbol,
|
28
|
+
Rambling::Trie::Nodes::Raw,
|
29
|
+
Rambling::Trie::Nodes::Compressed,
|
30
|
+
],
|
31
|
+
[],
|
32
|
+
true,
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Serializes a {Nodes::Node Node} and dumps it as a YAML object into
|
37
|
+
# filepath.
|
38
|
+
# @param [Nodes::Node] node the node to serialize
|
39
|
+
# @param [String] filepath the full path of the file to dump the YAML
|
40
|
+
# object into.
|
41
|
+
# @return [Numeric] number of bytes written to disk.
|
42
|
+
# @see https://ruby-doc.org/stdlib-2.5.0/libdoc/psych/rdoc/Psych.html#method-c-dump
|
43
|
+
# Psych.dump
|
44
|
+
def dump node, filepath
|
45
|
+
require 'yaml'
|
46
|
+
serializer.dump ::YAML.dump(node), filepath
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_reader :serializer
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rambling
|
4
|
+
module Trie
|
5
|
+
module Serializers
|
6
|
+
# Zip file serializer. Dumps/loads contents from zip files. Automatically
|
7
|
+
# detects if zip file contains `.marshal` or `.yml` file
|
8
|
+
class Zip
|
9
|
+
# Creates a new Zip serializer.
|
10
|
+
# @param [Configuration::Properties] properties the configuration
|
11
|
+
# properties set up so far.
|
12
|
+
def initialize properties
|
13
|
+
@properties = properties
|
14
|
+
end
|
15
|
+
|
16
|
+
# Unzip contents from specified filepath and load in contents from
|
17
|
+
# unzipped files.
|
18
|
+
# @param [String] filepath the filepath to load contents from.
|
19
|
+
# @return [String] all contents of the unzipped loaded file.
|
20
|
+
# @see https://github.com/rubyzip/rubyzip#reading-a-zip-file Zip
|
21
|
+
# reading a file
|
22
|
+
def load filepath
|
23
|
+
require 'zip'
|
24
|
+
|
25
|
+
::Zip::File.open filepath do |zip|
|
26
|
+
entry = zip.entries.first
|
27
|
+
entry_path = path entry.name
|
28
|
+
entry.extract entry_path
|
29
|
+
|
30
|
+
serializer = serializers.resolve entry.name
|
31
|
+
serializer.load entry_path
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Dumps contents and zips into a specified filepath.
|
36
|
+
# @param [String] contents the contents to dump.
|
37
|
+
# @param [String] filepath the filepath to dump the contents to.
|
38
|
+
# @return [Numeric] number of bytes written to disk.
|
39
|
+
# @see https://github.com/rubyzip/rubyzip#basic-zip-archive-creation
|
40
|
+
# Zip archive creation
|
41
|
+
def dump contents, filepath
|
42
|
+
require 'zip'
|
43
|
+
|
44
|
+
::Zip::File.open filepath, ::Zip::File::CREATE do |zip|
|
45
|
+
filename = ::File.basename filepath, '.zip'
|
46
|
+
|
47
|
+
entry_path = path filename
|
48
|
+
serializer = serializers.resolve filename
|
49
|
+
serializer.dump contents, entry_path
|
50
|
+
|
51
|
+
zip.add filename, entry_path
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
attr_reader :properties
|
58
|
+
|
59
|
+
def serializers
|
60
|
+
properties.serializers
|
61
|
+
end
|
62
|
+
|
63
|
+
def tmp_path
|
64
|
+
properties.tmp_path
|
65
|
+
end
|
66
|
+
|
67
|
+
def path filename
|
68
|
+
require 'securerandom'
|
69
|
+
::File.join tmp_path, "#{SecureRandom.uuid}-#{filename}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rambling
|
4
|
+
module Trie
|
5
|
+
# Provides the String representation behavior for the trie data structure.
|
6
|
+
module Stringifyable
|
7
|
+
# String representation of the current node, if it is a terminal node.
|
8
|
+
# @return [String] the string representation of the current node.
|
9
|
+
# @raise [InvalidOperation] if node is not terminal or is root.
|
10
|
+
def as_word
|
11
|
+
if letter && !terminal?
|
12
|
+
raise Rambling::Trie::InvalidOperation,
|
13
|
+
'Cannot represent branch as a word'
|
14
|
+
end
|
15
|
+
|
16
|
+
to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
# String representation of the current node.
|
20
|
+
# @return [String] the string representation of the current node.
|
21
|
+
def to_s
|
22
|
+
parent.to_s + letter.to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
4
|
+
require 'rambling/trie/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.authors = ['Ribose Inc.']
|
8
|
+
gem.email = ['open.source@ribose.com']
|
9
|
+
|
10
|
+
gem.description = <<~DESCRIPTION.gsub(%r{\s+}, ' ')
|
11
|
+
The original Rambling Trie gem but Opal-compatible.
|
12
|
+
DESCRIPTION
|
13
|
+
|
14
|
+
gem.summary = 'A Ruby implementation (Opal Compatible) of the trie data structure.'
|
15
|
+
gem.homepage = 'http://github.com/interscript/rambling-trie'
|
16
|
+
gem.date = Time.now.strftime '%Y-%m-%d'
|
17
|
+
|
18
|
+
executables = `git ls-files -- bin/*`.split "\n"
|
19
|
+
files = `git ls-files -- {lib,*file,*.gemspec,LICENSE*,README*}`.split "\n"
|
20
|
+
test_files = `git ls-files -- {test,spec,features}/*`.split "\n"
|
21
|
+
|
22
|
+
gem.executables = executables.map { |f| File.basename f }
|
23
|
+
gem.files = files
|
24
|
+
gem.test_files = test_files
|
25
|
+
gem.require_paths = %w(lib)
|
26
|
+
|
27
|
+
gem.name = 'rambling-trie-opal'
|
28
|
+
gem.license = 'MIT'
|
29
|
+
gem.version = Rambling::Trie::VERSION
|
30
|
+
gem.platform = Gem::Platform::RUBY
|
31
|
+
gem.required_ruby_version = '~> 2.4'
|
32
|
+
|
33
|
+
gem.add_development_dependency 'rake', '~> 13.0'
|
34
|
+
gem.add_development_dependency 'rspec', '~> 3.9'
|
35
|
+
gem.add_development_dependency 'yard', '~> 0.9.25'
|
36
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'zip'
|
5
|
+
|
6
|
+
describe Rambling::Trie do
|
7
|
+
let(:assets_path) { File.join ::SPEC_ROOT, 'assets' }
|
8
|
+
|
9
|
+
context 'when providing words directly' do
|
10
|
+
it_behaves_like 'a compressible trie' do
|
11
|
+
let(:trie) { Rambling::Trie.create }
|
12
|
+
let(:words) { %w(a couple of words for our full trie integration test) }
|
13
|
+
|
14
|
+
before do
|
15
|
+
trie.concat words
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when provided with words with unicode characters' do
|
21
|
+
it_behaves_like 'a compressible trie' do
|
22
|
+
let(:trie) { Rambling::Trie.create }
|
23
|
+
let(:words) do
|
24
|
+
%w(poquísimas palabras para nuestra prueba de integración completa 🙃)
|
25
|
+
end
|
26
|
+
|
27
|
+
before do
|
28
|
+
trie.concat words
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when provided with a filepath' do
|
34
|
+
let(:trie) { Rambling::Trie.create filepath }
|
35
|
+
let(:words) { File.readlines(filepath).map(&:chomp) }
|
36
|
+
|
37
|
+
context 'with english words' do
|
38
|
+
it_behaves_like 'a compressible trie' do
|
39
|
+
let(:filepath) { File.join assets_path, 'test_words.en_US.txt' }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with unicode characters' do
|
44
|
+
it_behaves_like 'a compressible trie' do
|
45
|
+
let(:filepath) { File.join assets_path, 'test_words.es_DO.txt' }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'dump and load' do
|
51
|
+
let(:words_filepath) { File.join assets_path, 'test_words.en_US.txt' }
|
52
|
+
let(:words) { File.readlines(words_filepath).map(&:chomp) }
|
53
|
+
|
54
|
+
context 'when serialized with Ruby marshal format (default)' do
|
55
|
+
it_behaves_like 'a serializable trie' do
|
56
|
+
let(:trie_to_serialize) { Rambling::Trie.create words_filepath }
|
57
|
+
let(:format) { :marshal }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when serialized with YAML' do
|
62
|
+
it_behaves_like 'a serializable trie' do
|
63
|
+
let(:trie_to_serialize) { Rambling::Trie.create words_filepath }
|
64
|
+
let(:format) { :yml }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# context 'when serialized with zipped Ruby marshal format' do
|
69
|
+
# before do
|
70
|
+
# @original_on_exists_proc = ::Zip.on_exists_proc
|
71
|
+
# @original_continue_on_exists_proc = ::Zip.continue_on_exists_proc
|
72
|
+
# ::Zip.on_exists_proc = true
|
73
|
+
# ::Zip.continue_on_exists_proc = true
|
74
|
+
# end
|
75
|
+
|
76
|
+
# after do
|
77
|
+
# ::Zip.on_exists_proc = @original_on_exists_proc
|
78
|
+
# ::Zip.continue_on_exists_proc = @original_continue_on_exists_proc
|
79
|
+
# end
|
80
|
+
|
81
|
+
# it_behaves_like 'a serializable trie' do
|
82
|
+
# let(:trie_to_serialize) { Rambling::Trie.create words_filepath }
|
83
|
+
# let(:format) { 'marshal.zip' }
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
end
|
87
|
+
end
|