rambling-trie-opal 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
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