LittleWeasel 3.0.4 → 4.0.0

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 (152) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.reek.yml +17 -0
  4. data/.rspec +4 -2
  5. data/.rubocop.yml +187 -0
  6. data/.ruby-version +1 -1
  7. data/.yardopts +2 -0
  8. data/Gemfile +3 -1
  9. data/LittleWeasel.gemspec +31 -18
  10. data/README.md +408 -42
  11. data/Rakefile +296 -3
  12. data/lib/LittleWeasel.rb +5 -184
  13. data/lib/LittleWeasel/block_results.rb +81 -0
  14. data/lib/LittleWeasel/configure.rb +98 -0
  15. data/lib/LittleWeasel/dictionary.rb +125 -0
  16. data/lib/LittleWeasel/dictionary_key.rb +48 -0
  17. data/lib/LittleWeasel/dictionary_manager.rb +85 -0
  18. data/lib/LittleWeasel/errors/dictionary_file_already_loaded_error.rb +9 -0
  19. data/lib/LittleWeasel/errors/dictionary_file_empty_error.rb +8 -0
  20. data/lib/LittleWeasel/errors/dictionary_file_not_found_error.rb +8 -0
  21. data/lib/LittleWeasel/errors/dictionary_file_too_large_error.rb +16 -0
  22. data/lib/LittleWeasel/errors/language_required_error.rb +8 -0
  23. data/lib/LittleWeasel/errors/must_override_error.rb +8 -0
  24. data/lib/LittleWeasel/filters/en_us/currency_filter.rb +19 -0
  25. data/lib/LittleWeasel/filters/en_us/numeric_filter.rb +19 -0
  26. data/lib/LittleWeasel/filters/en_us/single_character_word_filter.rb +21 -0
  27. data/lib/LittleWeasel/filters/word_filter.rb +59 -0
  28. data/lib/LittleWeasel/filters/word_filter_managable.rb +80 -0
  29. data/lib/LittleWeasel/filters/word_filter_validatable.rb +31 -0
  30. data/lib/LittleWeasel/filters/word_filterable.rb +19 -0
  31. data/lib/LittleWeasel/filters/word_filters_validatable.rb +29 -0
  32. data/lib/LittleWeasel/metadata/dictionary_metadata.rb +145 -0
  33. data/lib/LittleWeasel/metadata/invalid_words_metadata.rb +134 -0
  34. data/lib/LittleWeasel/metadata/invalid_words_service_results.rb +45 -0
  35. data/lib/LittleWeasel/metadata/metadata_observable_validatable.rb +22 -0
  36. data/lib/LittleWeasel/metadata/metadata_observerable.rb +90 -0
  37. data/lib/LittleWeasel/metadata/metadatable.rb +136 -0
  38. data/lib/LittleWeasel/modules/class_name_to_symbol.rb +26 -0
  39. data/lib/LittleWeasel/modules/configurable.rb +26 -0
  40. data/lib/LittleWeasel/modules/deep_dup.rb +11 -0
  41. data/lib/LittleWeasel/modules/dictionary_cache_keys.rb +34 -0
  42. data/lib/LittleWeasel/modules/dictionary_cache_servicable.rb +26 -0
  43. data/lib/LittleWeasel/modules/dictionary_cache_validatable.rb +20 -0
  44. data/lib/LittleWeasel/modules/dictionary_creator_servicable.rb +27 -0
  45. data/lib/LittleWeasel/modules/dictionary_file_loader.rb +67 -0
  46. data/lib/LittleWeasel/modules/dictionary_key_validatable.rb +19 -0
  47. data/lib/LittleWeasel/modules/dictionary_keyable.rb +24 -0
  48. data/lib/LittleWeasel/modules/dictionary_loader_servicable.rb +27 -0
  49. data/lib/LittleWeasel/modules/dictionary_metadata_servicable.rb +29 -0
  50. data/lib/LittleWeasel/modules/dictionary_metadata_validatable.rb +17 -0
  51. data/lib/LittleWeasel/modules/dictionary_sourceable.rb +26 -0
  52. data/lib/LittleWeasel/modules/dictionary_validatable.rb +30 -0
  53. data/lib/LittleWeasel/modules/language.rb +23 -0
  54. data/lib/LittleWeasel/modules/language_validatable.rb +16 -0
  55. data/lib/LittleWeasel/modules/locale.rb +40 -0
  56. data/lib/LittleWeasel/modules/order_validatable.rb +18 -0
  57. data/lib/LittleWeasel/modules/orderable.rb +17 -0
  58. data/lib/LittleWeasel/modules/region.rb +23 -0
  59. data/lib/LittleWeasel/modules/region_validatable.rb +16 -0
  60. data/lib/LittleWeasel/modules/tag_validatable.rb +16 -0
  61. data/lib/LittleWeasel/modules/taggable.rb +31 -0
  62. data/lib/LittleWeasel/modules/word_results_validatable.rb +28 -0
  63. data/lib/LittleWeasel/preprocessors/en_us/capitalize_preprocessor.rb +22 -0
  64. data/lib/LittleWeasel/preprocessors/preprocessed_word.rb +28 -0
  65. data/lib/LittleWeasel/preprocessors/preprocessed_word_validatable.rb +55 -0
  66. data/lib/LittleWeasel/preprocessors/preprocessed_words.rb +55 -0
  67. data/lib/LittleWeasel/preprocessors/preprocessed_words_validatable.rb +27 -0
  68. data/lib/LittleWeasel/preprocessors/word_preprocessable.rb +19 -0
  69. data/lib/LittleWeasel/preprocessors/word_preprocessor.rb +122 -0
  70. data/lib/LittleWeasel/preprocessors/word_preprocessor_managable.rb +114 -0
  71. data/lib/LittleWeasel/preprocessors/word_preprocessor_validatable.rb +40 -0
  72. data/lib/LittleWeasel/preprocessors/word_preprocessors_validatable.rb +24 -0
  73. data/lib/LittleWeasel/services/dictionary_cache_service.rb +262 -0
  74. data/lib/LittleWeasel/services/dictionary_creator_service.rb +94 -0
  75. data/lib/LittleWeasel/services/dictionary_file_loader_service.rb +37 -0
  76. data/lib/LittleWeasel/services/dictionary_killer_service.rb +35 -0
  77. data/lib/LittleWeasel/services/dictionary_loader_service.rb +59 -0
  78. data/lib/LittleWeasel/services/dictionary_metadata_service.rb +114 -0
  79. data/lib/LittleWeasel/services/invalid_words_service.rb +59 -0
  80. data/lib/LittleWeasel/version.rb +3 -1
  81. data/lib/LittleWeasel/word_results.rb +146 -0
  82. data/spec/factories/dictionary.rb +43 -0
  83. data/spec/factories/dictionary_cache_service.rb +95 -0
  84. data/spec/factories/dictionary_creator_service.rb +16 -0
  85. data/spec/factories/dictionary_file_loader_service.rb +13 -0
  86. data/spec/factories/dictionary_hash.rb +39 -0
  87. data/spec/factories/dictionary_key.rb +14 -0
  88. data/spec/factories/dictionary_killer_service.rb +14 -0
  89. data/spec/factories/dictionary_loader_service.rb +14 -0
  90. data/spec/factories/dictionary_manager.rb +10 -0
  91. data/spec/factories/dictionary_metadata.rb +16 -0
  92. data/spec/factories/dictionary_metadata_service.rb +16 -0
  93. data/spec/factories/numeric_filter.rb +12 -0
  94. data/spec/factories/preprocessed_word.rb +16 -0
  95. data/spec/factories/preprocessed_words.rb +41 -0
  96. data/spec/factories/single_character_word_filter.rb +12 -0
  97. data/spec/factories/word_results.rb +16 -0
  98. data/spec/lib/LittleWeasel/block_results_spec.rb +248 -0
  99. data/spec/lib/LittleWeasel/configure_spec.rb +74 -0
  100. data/spec/lib/LittleWeasel/dictionary_key_spec.rb +118 -0
  101. data/spec/lib/LittleWeasel/dictionary_manager_spec.rb +116 -0
  102. data/spec/lib/LittleWeasel/dictionary_spec.rb +289 -0
  103. data/spec/lib/LittleWeasel/filters/en_us/currency_filter_spec.rb +80 -0
  104. data/spec/lib/LittleWeasel/filters/en_us/numeric_filter_spec.rb +66 -0
  105. data/spec/lib/LittleWeasel/filters/en_us/single_character_word_filter_spec.rb +58 -0
  106. data/spec/lib/LittleWeasel/filters/word_filter_managable_spec.rb +180 -0
  107. data/spec/lib/LittleWeasel/filters/word_filter_spec.rb +151 -0
  108. data/spec/lib/LittleWeasel/filters/word_filter_validatable_spec.rb +94 -0
  109. data/spec/lib/LittleWeasel/filters/word_filters_validatable_spec.rb +48 -0
  110. data/spec/lib/LittleWeasel/integraton_tests/dictionary_integration_spec.rb +201 -0
  111. data/spec/lib/LittleWeasel/metadata/dictionary_creator_servicable_spec.rb +54 -0
  112. data/spec/lib/LittleWeasel/metadata/dictionary_metadata_spec.rb +209 -0
  113. data/spec/lib/LittleWeasel/metadata/invalid_words_metadata_spec.rb +155 -0
  114. data/spec/lib/LittleWeasel/metadata/metadata_observerable_spec.rb +31 -0
  115. data/spec/lib/LittleWeasel/metadata/metadatable_spec.rb +35 -0
  116. data/spec/lib/LittleWeasel/modules/class_name_to_symbol_spec.rb +21 -0
  117. data/spec/lib/LittleWeasel/modules/dictionary_file_loader_spec.rb +125 -0
  118. data/spec/lib/LittleWeasel/modules/dictionary_sourceable_spec.rb +44 -0
  119. data/spec/lib/LittleWeasel/modules/language_spec.rb +52 -0
  120. data/spec/lib/LittleWeasel/modules/locale_spec.rb +140 -0
  121. data/spec/lib/LittleWeasel/modules/region_spec.rb +52 -0
  122. data/spec/lib/LittleWeasel/preprocessors/en_us/capitalize_preprocessor_spec.rb +34 -0
  123. data/spec/lib/LittleWeasel/preprocessors/preprocessed_word_spec.rb +105 -0
  124. data/spec/lib/LittleWeasel/preprocessors/preprocessed_word_validatable_spec.rb +143 -0
  125. data/spec/lib/LittleWeasel/preprocessors/preprocessed_words_spec.rb +77 -0
  126. data/spec/lib/LittleWeasel/preprocessors/preprocessed_words_validatable_spec.rb +58 -0
  127. data/spec/lib/LittleWeasel/preprocessors/word_preprocessor_managable_spec.rb +216 -0
  128. data/spec/lib/LittleWeasel/preprocessors/word_preprocessor_spec.rb +175 -0
  129. data/spec/lib/LittleWeasel/preprocessors/word_preprocessor_validatable_spec.rb +109 -0
  130. data/spec/lib/LittleWeasel/preprocessors/word_preprocessors_validatable_spec.rb +49 -0
  131. data/spec/lib/LittleWeasel/services/dictionary_cache_service_spec.rb +444 -0
  132. data/spec/lib/LittleWeasel/services/dictionary_creator_service_spec.rb +119 -0
  133. data/spec/lib/LittleWeasel/services/dictionary_file_loader_service_spec.rb +71 -0
  134. data/spec/lib/LittleWeasel/services/dictionary_loader_service_spec.rb +50 -0
  135. data/spec/lib/LittleWeasel/services/dictionary_metadata_service_spec.rb +279 -0
  136. data/spec/lib/LittleWeasel/word_results_spec.rb +275 -0
  137. data/spec/lib/LittleWeasel/workflow/workflow_spec.rb +20 -0
  138. data/spec/spec_helper.rb +117 -6
  139. data/spec/support/factory_bot.rb +15 -0
  140. data/spec/support/file_helpers.rb +32 -0
  141. data/spec/support/files/empty-dictionary.txt +0 -0
  142. data/{lib/dictionary → spec/support/files/en-US-big.txt} +262156 -31488
  143. data/spec/support/files/en-US-tagged.txt +26 -0
  144. data/spec/support/files/en-US.txt +26 -0
  145. data/spec/support/files/en.txt +26 -0
  146. data/spec/support/files/es-ES.txt +27 -0
  147. data/spec/support/files/es.txt +27 -0
  148. data/spec/support/general_helpers.rb +68 -0
  149. data/spec/support/shared_contexts.rb +108 -0
  150. data/spec/support/shared_examples.rb +105 -0
  151. metadata +408 -65
  152. data/spec/checker/checker_spec.rb +0 -286
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe LittleWeasel do
6
+ subject do
7
+ described_class.configure { |config| }
8
+ described_class.configuration
9
+ end
10
+
11
+ context 'default configurable settings' do
12
+ describe '#max_dictionary_file_megabytes' do
13
+ it 'set to 5 by default' do
14
+ expect(subject.max_dictionary_file_megabytes).to eq 5
15
+ end
16
+ end
17
+
18
+ describe '#max_invalid_words_bytesize' do
19
+ it 'set to 25_000 by default' do
20
+ expect(subject.max_invalid_words_bytesize).to eq 25_000
21
+ end
22
+ end
23
+
24
+ describe '#metadata_observers' do
25
+ it 'set to an Array with InvalidWordsMetadata by default' do
26
+ expect(subject.metadata_observers).to eq [
27
+ LittleWeasel::Metadata::InvalidWordsMetadata
28
+ ]
29
+ end
30
+ end
31
+
32
+ describe '#word_block_regex' do
33
+ it 'set to the default regex to split work blocks by default' do
34
+ expect(subject.word_block_regex).to eq /[[[:word:]]'-]+/
35
+ end
36
+ end
37
+ end
38
+
39
+ #.configuration
40
+ describe '.configuration' do
41
+ context 'when passing a block' do
42
+ subject do
43
+ described_class.configure do |config|
44
+ config.max_dictionary_file_megabytes = max_dictionary_file_megabytes
45
+ config.metadata_observers = metadata_observers
46
+ config.word_block_regex = word_block_regex
47
+ end
48
+ described_class.configuration
49
+ end
50
+
51
+ let(:max_dictionary_file_megabytes) { 1_222_333 }
52
+ let(:metadata_observers) { %i(observer0 observer1) }
53
+ let(:word_block_regex) { :word_block_regex }
54
+
55
+ describe '#max_dictionary_file_megabytes=' do
56
+ it 'sets the value' do
57
+ expect(subject.max_dictionary_file_megabytes).to eq max_dictionary_file_megabytes
58
+ end
59
+ end
60
+
61
+ describe '#metadata_observers=' do
62
+ it 'sets the value' do
63
+ expect(subject.metadata_observers).to eq metadata_observers
64
+ end
65
+ end
66
+
67
+ describe '#word_block_regex=' do
68
+ it 'sets the value' do
69
+ expect(subject.word_block_regex).to eq word_block_regex
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe LittleWeasel::DictionaryKey, type: :class do
6
+ subject { described_class.new(language: language, region: region, tag: tag) }
7
+
8
+ let(:language) {}
9
+ let(:region) {}
10
+ let(:tag) {}
11
+
12
+ #.new
13
+ describe '.new' do
14
+ context 'when passing valid arguments' do
15
+ let(:language) { :EN }
16
+ let(:region) { :us }
17
+ let(:tag) { :TAGGED}
18
+
19
+ it 'instantiates the object' do
20
+ expect { subject }.to_not raise_error
21
+ end
22
+
23
+ it 'normalizes language and converts it to lowercase' do
24
+ expect(subject.language).to eq :en
25
+ end
26
+
27
+ it 'normalizes region and converts it to uppercase' do
28
+ expect(subject.region).to eq :US
29
+ end
30
+
31
+ it 'leaves tag case unchanged' do
32
+ expect(subject.tag).to eq :TAGGED
33
+ end
34
+ end
35
+
36
+ context 'when passing invalid arguments' do
37
+ context 'when passing an invalid language' do
38
+ it 'raises an error' do
39
+ expect { subject }.to raise_error "Argument language '#{language}' is not a Symbol."
40
+ end
41
+ end
42
+
43
+ context 'when passing an invalid region' do
44
+ let(:language) { :en }
45
+ let(:region) { 1 }
46
+
47
+ it 'raises an error' do
48
+ expect { subject }.to raise_error "Argument region '#{region}' is not a Symbol."
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ #.key
55
+ describe '.key' do
56
+ let(:language) { :xx }
57
+ let(:region) { :yy }
58
+ let(:tag) { :zz }
59
+
60
+ it 'returns the locale' do
61
+ expect(described_class.key language: language, region: region, tag: tag).to eq 'xx-YY-zz'
62
+ end
63
+ end
64
+
65
+ #key
66
+ describe '#key' do
67
+ context 'with no tag' do
68
+ context 'with language' do
69
+ let(:language) { :EN }
70
+
71
+ it 'returns the key in the form of a locale String that includes language only (e.g. "en")' do
72
+ expect(subject.key).to eq 'en'
73
+ end
74
+ end
75
+
76
+ context 'with language and region' do
77
+ let(:language) { :EN }
78
+ let(:region) { :us }
79
+
80
+ it 'returns the key in the form of a locale String that includes language and region (e.g. "en-US")' do
81
+ expect(subject.key).to eq 'en-US'
82
+ end
83
+ end
84
+ end
85
+
86
+ context 'with a tag' do
87
+ let(:tag) { :tagged }
88
+
89
+ context 'with language and a tag' do
90
+ let(:language) { :EN }
91
+
92
+ it 'returns the key in the form of a locale String that includes the language and appended tag (e.g. "en-tag")' do
93
+ expect(subject.key).to eq 'en-tagged'
94
+ end
95
+ end
96
+
97
+ context 'with language and region' do
98
+ let(:language) { :EN }
99
+ let(:region) { :us }
100
+
101
+ it 'returns the key in the form of a locale String that includes language, region and the appended tag (e.g. "en-US-tag")' do
102
+ expect(subject.key).to eq 'en-US-tagged'
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ #to_s
109
+ describe '#to_s' do
110
+ let(:language) { :en }
111
+ let(:region) { :us }
112
+ let(:tag) { :tagged }
113
+
114
+ it '#to_s is an alias for #key' do
115
+ expect(subject.to_s).to eq 'en-US-tagged'
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe LittleWeasel::DictionaryManager do
6
+ subject { create(:dictionary_manager) }
7
+
8
+ let(:dictionary_cache_service) { create(:dictionary_cache_service, dictionary_key: dictionary_key, dictionary_cache: dictionary_cache)}
9
+ let(:dictionary_metadata_service) { create(:dictionary_metadata_service, dictionary_key: dictionary_key, dictionary_cache: dictionary_cache, dictionary_metadata: dictionary_metadata)}
10
+ let(:dictionary_key) { create(:dictionary_key, language: language, region: region, tag: tag) }
11
+ let(:dictionary_cache) { subject.dictionary_cache }
12
+ let(:dictionary_metadata) { subject.dictionary_metadata }
13
+
14
+ let(:language) { :en }
15
+ let(:region) { :us }
16
+ let(:tag) {}
17
+ let(:file) { dictionary_path_for(file_name: dictionary_key.key) }
18
+
19
+ let(:metadata_key) do
20
+ dictionary_cache_service.dictionary_object.dictionary_metadata_object.observers.keys.first
21
+ end
22
+
23
+ before(:each) do
24
+ subject.init
25
+ end
26
+
27
+ #.new
28
+ describe '.new' do
29
+ it 'does not raise an error' do
30
+ expect { subject }.not_to raise_error
31
+ end
32
+ end
33
+
34
+ #create_dictionary_from_file
35
+ describe '#create_dictionary_from_file' do
36
+ context 'when the dictionary DOES NOT exist' do
37
+ it 'creates a dictionary and returns a dictionary object' do
38
+ expect(subject.create_dictionary_from_file(dictionary_key: dictionary_key, file: file)).to be_kind_of LittleWeasel::Dictionary
39
+ end
40
+ end
41
+
42
+ context 'when the dictionary already exists' do
43
+ before do
44
+ subject.create_dictionary_from_file(dictionary_key: dictionary_key, file: file)
45
+ end
46
+
47
+ it 'raises an error' do
48
+ expect { subject.create_dictionary_from_file(dictionary_key: dictionary_key, file: file) }
49
+ .to raise_error("The dictionary source associated with key '#{dictionary_key.key}' already exists.")
50
+ end
51
+ end
52
+ end
53
+
54
+ #create_dictionary_from_memory
55
+ describe '#create_dictionary_from_memory' do
56
+ let(:dictionary_words) { dictionary_words_for(dictionary_file_path: file) }
57
+
58
+ context 'when the dictionary reference does not exist and the dictionary is not cached' do
59
+ it 'adds a dictionary reference caches the dictionary and returns a dictionary object' do
60
+ expect(subject.create_dictionary_from_memory(dictionary_key: dictionary_key, dictionary_words: dictionary_words)).to be_kind_of LittleWeasel::Dictionary
61
+ expect(dictionary_cache_service.dictionary_reference?).to eq true
62
+ expect(dictionary_cache_service.dictionary_object?).to eq true
63
+ end
64
+ end
65
+
66
+ context 'when the dictionary reference exists' do
67
+ before do
68
+ subject.create_dictionary_from_memory(dictionary_key: dictionary_key, dictionary_words: dictionary_words)
69
+ end
70
+
71
+ it 'raises an error' do
72
+ expect { subject.create_dictionary_from_memory(dictionary_key: dictionary_key, dictionary_words: dictionary_words) }
73
+ .to raise_error "The dictionary source associated with key '#{dictionary_key.key}' already exists."
74
+ end
75
+ end
76
+ end
77
+
78
+ #kill
79
+ describe '#kill_dictionary' do
80
+ context 'dictionaries created from files' do
81
+ before do
82
+ subject.create_dictionary_from_file(dictionary_key: dictionary_key, file: file)
83
+ end
84
+
85
+ it 'removes the dictionary, file source reference and metadata from the dictionary cache' do
86
+ metadata_key # Capture this before we unload the dictionary
87
+ subject.kill_dictionary(dictionary_key: dictionary_key)
88
+ expect(dictionary_cache_service.dictionary_exists?).to eq false
89
+ expect(dictionary_cache_service.dictionary_reference?).to eq false
90
+ expect(dictionary_metadata_service.dictionary_metadata?(metadata_key: metadata_key)).to eq false
91
+ end
92
+
93
+ it 'returns the dictionary manager instance' do
94
+ expect(subject.kill_dictionary(dictionary_key: dictionary_key)).to eq subject
95
+ end
96
+ end
97
+
98
+ context 'dictionaries created from memory' do
99
+ before do
100
+ subject.create_dictionary_from_memory(dictionary_key: dictionary_key, dictionary_words: %w(Abel Cain Deborah Elijah))
101
+ end
102
+
103
+ it 'removes the dictionary, memory source reference and metadata from the dictionary cache' do
104
+ metadata_key # Capture this before we unload the dictionary
105
+ subject.kill_dictionary(dictionary_key: dictionary_key)
106
+ expect(dictionary_cache_service.dictionary_exists?).to eq false
107
+ expect(dictionary_cache_service.dictionary_reference?).to eq false
108
+ expect(dictionary_metadata_service.dictionary_metadata?(metadata_key: metadata_key)).to eq false
109
+ end
110
+
111
+ it 'returns the dictionary manager instance' do
112
+ expect(subject.kill_dictionary(dictionary_key: dictionary_key)).to eq subject
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,289 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe LittleWeasel::Dictionary do
6
+ include_context 'dictionary keys'
7
+ include_context 'mock word filters'
8
+
9
+ DictionaryResultsHelpers = Support::GeneralHelpers::DictionaryResultsHelpers
10
+
11
+
12
+ subject { create(:dictionary, dictionary_key: dictionary_key, dictionary_cache: dictionary_cache, dictionary_words: dictionary_words, word_filters: word_filters) }
13
+
14
+ before(:each) { LittleWeasel.configure { |config| config.reset } }
15
+ before { dictionary_cache_service }
16
+
17
+ let(:dictionary_cache_service) { create(:dictionary_cache_service, dictionary_key: dictionary_key, dictionary_cache: dictionary_cache, dictionary_file_source: dictionary_key.key) }
18
+ let(:dictionary_key) { dictionary_key_for(language: :en, region: :us, tag: :big) }
19
+ let(:dictionary_cache) { {} }
20
+ let(:dictionary_metadata) { {} }
21
+ let(:dictionary_file_path) { dictionary_path_for(file_name: dictionary_key.key) }
22
+ let(:dictionary_words) { dictionary_words_for(dictionary_file_path: dictionary_file_path) }
23
+ let(:word_filters) {}
24
+
25
+ def block_results_include?(block_results, word)
26
+ word_results = block_results.word_results.find do |word_results|
27
+ word_results.original_word == word
28
+ end
29
+ [word_results.present?, word_results&.word_valid]
30
+ end
31
+
32
+ #.new
33
+ describe '.new' do
34
+ context 'with a valid dictionary words Array' do
35
+ it 'instantiates without error' do
36
+ expect { subject }.to_not raise_error
37
+ end
38
+ end
39
+
40
+ context 'with an invalid dictionary words Array' do
41
+ context 'when nil' do
42
+ let(:dictionary_words) {}
43
+
44
+ it 'raises an error' do
45
+ expect { subject }.to raise_error ArgumentError
46
+ end
47
+ end
48
+
49
+ context 'when not an Array' do
50
+ let(:dictionary_words) { :not_an_array }
51
+
52
+ it 'raises an error' do
53
+ expect { subject }.to raise_error ArgumentError
54
+ end
55
+ end
56
+ end
57
+
58
+ describe 'word_filter:' do
59
+ context 'when argument word_filters is nil' do
60
+ it 'no word filters will be used' do
61
+ expect(subject.word_filters).to be_blank
62
+ end
63
+ end
64
+
65
+ context 'when argument word_filters is an empty Array ([])' do
66
+ let(:word_filters) { [] }
67
+
68
+ it 'no word filters will be used' do
69
+ expect(subject.word_filters.count).to eq 0
70
+ end
71
+ end
72
+
73
+ context 'when argument word_filters is NOT nil' do
74
+ let(:word_filters) { [WordFilter01.new, WordFilter02.new] }
75
+
76
+ it 'the dictionary will use the word filters passed' do
77
+ expect(subject.word_filters.count).to eq 2
78
+ expect(subject.word_filters).to include(a_kind_of(WordFilter01))
79
+ expect(subject.word_filters).to include(a_kind_of(WordFilter02))
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ #.to_hash
86
+ describe '.to_hash' do
87
+ let(:expected_hash) do
88
+ {
89
+ 'this' => true,
90
+ 'is' => true,
91
+ 'a' => true,
92
+ 'test' => true
93
+ }
94
+ end
95
+
96
+ it 'returns a Hash of dictionary words' do
97
+ expect(described_class.to_hash(dictionary_words: %w(this is a test))).to eq expected_hash
98
+ end
99
+ end
100
+
101
+ #detached?
102
+ describe '#detached?' do
103
+ before do
104
+ subject
105
+ end
106
+
107
+ let(:dictionary_cache_service) { create(:dictionary_cache_service, dictionary_key: dictionary_key, dictionary_cache: dictionary_cache, dictionary_file_source: dictionary_key.key, load: true) }
108
+
109
+ context 'when the dictionary object is in the dictionary cache' do
110
+ it 'returns false' do
111
+ dictionary_cache_service
112
+ expect(dictionary_cache_service.dictionary_object?).to eq true
113
+ expect(subject.detached?).to eq false
114
+ end
115
+ end
116
+
117
+ context 'when the dictionary object is NOT in the dictionary cache' do
118
+ before do
119
+ dictionary_cache_service
120
+ dictionary_killer_service = create(:dictionary_killer_service, dictionary_key: dictionary_key, dictionary_cache: dictionary_cache, dictionary_metadata: dictionary_metadata)
121
+ dictionary_killer_service.execute
122
+ end
123
+
124
+ it 'returns true' do
125
+ expect(dictionary_cache_service.dictionary_object?).to eq false
126
+ expect(subject.detached?).to eq true
127
+ end
128
+ end
129
+ end
130
+
131
+ #key
132
+ describe '#key' do
133
+ it 'returns the expected key' do
134
+ expect(subject.key).to eq dictionary_key.key
135
+ end
136
+ end
137
+
138
+ #count
139
+ describe '#count' do
140
+ before do
141
+ subject.word_results('badword')
142
+ end
143
+
144
+ it 'returns the count of all valid words' do
145
+ expect(subject.count).to eq dictionary_words.count
146
+ end
147
+ end
148
+
149
+ #count_all_words
150
+ describe '#count_all_words' do
151
+ before do
152
+ subject.word_results('badword')
153
+ end
154
+
155
+ it 'returns the count of all valid and invalid words' do
156
+ expect(subject.count_all_words).to eq dictionary_words.count + 1
157
+ end
158
+ end
159
+
160
+ #count_invalid_words
161
+ describe '#count_invalid_words' do
162
+ before do
163
+ subject.word_results('badword')
164
+ end
165
+
166
+ it 'returns the count of all invalid words' do
167
+ expect(subject.count_invalid_words).to eq 1
168
+ end
169
+ end
170
+
171
+ #word_results
172
+ describe '#word_results' do
173
+ context 'when argument word is INVALID' do
174
+ context 'when not a String' do
175
+ let(:word) { :not_a_string }
176
+
177
+ it 'raises an error' do
178
+ expect { subject.word_results(word) }.to raise_error "Argument word is not a String: #{word.class}"
179
+ end
180
+ end
181
+ end
182
+
183
+ context 'when searching for words in the dictionary' do
184
+ context 'when the word is found' do
185
+ it 'returns true' do
186
+ expect(subject.word_results('dog').success?).to eq true
187
+ end
188
+ end
189
+
190
+ context 'when the word is not found' do
191
+ it 'returns false' do
192
+ expect(subject.word_results('badword').success?).to eq false
193
+ end
194
+ end
195
+ end
196
+ end
197
+
198
+ #block_results
199
+ describe '#block_results' do
200
+ context 'when nil is passed' do
201
+ it 'raises an error' do
202
+ expect { subject.block_results nil }.to raise_error(/Argument word_block is not a String/)
203
+ end
204
+ end
205
+
206
+ context 'when an empty String is passed' do
207
+ it 'raises an error' do
208
+ expect { subject.block_results '' }.to raise_error(/Argument word_block is empty/)
209
+ end
210
+ end
211
+
212
+ context 'when a valid block of words is passed' do
213
+ subject do
214
+ create(:dictionary,
215
+ dictionary_key: dictionary_key,
216
+ dictionary_cache: dictionary_cache,
217
+ dictionary_words: dictionary_words,
218
+ word_filters: word_filters).block_results word_block
219
+ end
220
+
221
+ let(:word_filters) { [LittleWeasel::Filters::EnUs::NumericFilter.new] }
222
+ let(:word_block) do
223
+ "I'm older than you bubble-butt; I was born in 1964, before your time!"
224
+ end
225
+
226
+ it 'returns a WordResults object with the correct data about the words passed' do
227
+ DictionaryResultsHelpers.print_block_results word_block, subject
228
+
229
+ expect(subject.word_results.count).to eq 13
230
+ expect(block_results_include?(subject, "I'm")).to eq [true, true]
231
+ expect(block_results_include?(subject, 'older')).to eq [true, true]
232
+ expect(block_results_include?(subject, 'than')).to eq [true, true]
233
+ expect(block_results_include?(subject, 'you')).to eq [true, true]
234
+ expect(block_results_include?(subject, 'bubble-butt')).to eq [true, false]
235
+ expect(block_results_include?(subject, 'I')).to eq [true, true]
236
+ expect(block_results_include?(subject, 'was')).to eq [true, true]
237
+ expect(block_results_include?(subject, 'born')).to eq [true, true]
238
+ expect(block_results_include?(subject, 'in')).to eq [true, true]
239
+ expect(block_results_include?(subject, '1964')).to eq [true, false]
240
+ expect(block_results_include?(subject, 'before')).to eq [true, true]
241
+ expect(block_results_include?(subject, 'your')).to eq [true, true]
242
+ expect(block_results_include?(subject, 'time')).to eq [true, true]
243
+ end
244
+ end
245
+ end
246
+
247
+ # Configuration
248
+ context 'configuration options that alter behavior' do
249
+ context 'when max_invalid_words_bytesize? is true' do
250
+ context 'when a word is not found' do
251
+ context 'when the max_invalid_words_bytesize threashold has not been exceeded' do
252
+ it 'adds the word to the cache' do
253
+ expect { subject.word_results('badword') }.to change { subject.count_all_words }.by(1)
254
+ end
255
+ end
256
+
257
+ context 'when the max_invalid_words_bytesize threashold HAS been exceeded' do
258
+ before do
259
+ LittleWeasel.configure { |config| config.max_invalid_words_bytesize = 30 }
260
+ end
261
+
262
+ it 'does NOT add the word to the cache' do
263
+ expect do
264
+ subject.word_results('IWillBeCached01')
265
+ subject.word_results('IWillBeCached02')
266
+ subject.word_results('IWontBeCached01')
267
+ subject.word_results('IWontBeCached02')
268
+ end.to change { subject.count_all_words }.by(2)
269
+ end
270
+ end
271
+ end
272
+ end
273
+
274
+ context 'when max_invalid_words_bytesize? is false' do
275
+ before do
276
+ LittleWeasel.configure { |config| config.max_invalid_words_bytesize = 0 }
277
+ end
278
+
279
+ it 'does NOT add the word to the cache' do
280
+ expect do
281
+ subject.word_results('IWillBeCached01')
282
+ subject.word_results('IWillBeCached02')
283
+ subject.word_results('IWontBeCached01')
284
+ subject.word_results('IWontBeCached02')
285
+ end.to change { subject.count_all_words }.by(0)
286
+ end
287
+ end
288
+ end
289
+ end