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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +26 -0
  3. data/Guardfile +10 -0
  4. data/LICENSE +26 -0
  5. data/README.md +301 -0
  6. data/Rakefile +15 -0
  7. data/lib/rambling-trie.rb +3 -0
  8. data/lib/rambling/trie.rb +119 -0
  9. data/lib/rambling/trie/comparable.rb +19 -0
  10. data/lib/rambling/trie/compressible.rb +16 -0
  11. data/lib/rambling/trie/compressor.rb +64 -0
  12. data/lib/rambling/trie/configuration.rb +16 -0
  13. data/lib/rambling/trie/configuration/properties.rb +75 -0
  14. data/lib/rambling/trie/configuration/provider_collection.rb +122 -0
  15. data/lib/rambling/trie/container.rb +226 -0
  16. data/lib/rambling/trie/enumerable.rb +29 -0
  17. data/lib/rambling/trie/inspectable.rb +39 -0
  18. data/lib/rambling/trie/invalid_operation.rb +15 -0
  19. data/lib/rambling/trie/nodes.rb +18 -0
  20. data/lib/rambling/trie/nodes/compressed.rb +98 -0
  21. data/lib/rambling/trie/nodes/missing.rb +12 -0
  22. data/lib/rambling/trie/nodes/node.rb +183 -0
  23. data/lib/rambling/trie/nodes/raw.rb +82 -0
  24. data/lib/rambling/trie/readers.rb +15 -0
  25. data/lib/rambling/trie/readers/plain_text.rb +18 -0
  26. data/lib/rambling/trie/serializers.rb +18 -0
  27. data/lib/rambling/trie/serializers/file.rb +27 -0
  28. data/lib/rambling/trie/serializers/marshal.rb +48 -0
  29. data/lib/rambling/trie/serializers/yaml.rb +55 -0
  30. data/lib/rambling/trie/serializers/zip.rb +74 -0
  31. data/lib/rambling/trie/stringifyable.rb +26 -0
  32. data/lib/rambling/trie/version.rb +8 -0
  33. data/rambling-trie-opal.gemspec +36 -0
  34. data/spec/assets/test_words.en_US.txt +23 -0
  35. data/spec/assets/test_words.es_DO.txt +24 -0
  36. data/spec/integration/rambling/trie_spec.rb +87 -0
  37. data/spec/lib/rambling/trie/comparable_spec.rb +97 -0
  38. data/spec/lib/rambling/trie/compressor_spec.rb +108 -0
  39. data/spec/lib/rambling/trie/configuration/properties_spec.rb +57 -0
  40. data/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +149 -0
  41. data/spec/lib/rambling/trie/container_spec.rb +591 -0
  42. data/spec/lib/rambling/trie/enumerable_spec.rb +42 -0
  43. data/spec/lib/rambling/trie/inspectable_spec.rb +56 -0
  44. data/spec/lib/rambling/trie/nodes/compressed_spec.rb +37 -0
  45. data/spec/lib/rambling/trie/nodes/node_spec.rb +9 -0
  46. data/spec/lib/rambling/trie/nodes/raw_spec.rb +179 -0
  47. data/spec/lib/rambling/trie/readers/plain_text_spec.rb +16 -0
  48. data/spec/lib/rambling/trie/serializers/file_spec.rb +13 -0
  49. data/spec/lib/rambling/trie/serializers/marshal_spec.rb +12 -0
  50. data/spec/lib/rambling/trie/serializers/yaml_spec.rb +12 -0
  51. data/spec/lib/rambling/trie/serializers/zip_spec.rb +28 -0
  52. data/spec/lib/rambling/trie/stringifyable_spec.rb +85 -0
  53. data/spec/lib/rambling/trie_spec.rb +182 -0
  54. data/spec/spec_helper.rb +37 -0
  55. data/spec/support/config.rb +15 -0
  56. data/spec/support/helpers/add_word.rb +20 -0
  57. data/spec/support/helpers/one_line_heredoc.rb +11 -0
  58. data/spec/support/shared_examples/a_compressible_trie.rb +40 -0
  59. data/spec/support/shared_examples/a_serializable_trie.rb +30 -0
  60. data/spec/support/shared_examples/a_serializer.rb +37 -0
  61. data/spec/support/shared_examples/a_trie_data_structure.rb +31 -0
  62. data/spec/support/shared_examples/a_trie_node.rb +127 -0
  63. data/spec/support/shared_examples/a_trie_node_implementation.rb +152 -0
  64. data/spec/tmp/.gitkeep +0 -0
  65. 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,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rambling
4
+ module Trie
5
+ # Current version of the rambling-trie.
6
+ VERSION = '2.1.1'
7
+ end
8
+ 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,23 @@
1
+ are
2
+ beautiful
3
+ course
4
+ false
5
+ hello
6
+ hi
7
+ is
8
+ it
9
+ mine
10
+ my
11
+ no
12
+ of
13
+ ours
14
+ today
15
+ true
16
+ truth
17
+ whatever
18
+ where
19
+ who
20
+ yeah
21
+ you
22
+ your
23
+ yours
@@ -0,0 +1,24 @@
1
+ claro
2
+ donde
3
+ dónde
4
+ eres
5
+ es
6
+ eso
7
+ falso
8
+ hermoso
9
+ hola
10
+ hoy
11
+ mi
12
+ mío
13
+ no
14
+ nuestro
15
+ ola
16
+ quien
17
+ quién
18
+ si
19
+ tu
20
+ tus
21
+ tuyos
22
+ verdad
23
+ verdadero
24
+ 🙃
@@ -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