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,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe LittleWeasel::Preprocessors::WordPreprocessorValidatable, type: :module do
6
+ subject { MockSubject.new }
7
+
8
+ WordPreprocessorValidatable = described_class
9
+
10
+ class MockSubject
11
+ include WordPreprocessorValidatable
12
+ end
13
+
14
+ class MockWordPreprocessor < LittleWeasel::Preprocessors::WordPreprocessor
15
+ def preprocess(word)
16
+ [true, "#{word}-preprocessed"]
17
+ end
18
+ end
19
+
20
+ let(:order) { 0 }
21
+ let(:preprocessor_on) { true }
22
+ let(:word_preprocessor) do
23
+ word_preprocessor = MockWordPreprocessor.new order: order
24
+ word_preprocessor.preprocessor_on = preprocessor_on
25
+ word_preprocessor
26
+ end
27
+
28
+ shared_examples 'an instance method is missing' do
29
+ before do
30
+ allow(word_preprocessor).to receive(:respond_to?).with(method).and_return(false)
31
+ end
32
+
33
+ it 'raises an error' do
34
+ expect { WordPreprocessorValidatable.validate_word_preprocessor word_preprocessor: word_preprocessor }.to raise_error expected_error_message
35
+ end
36
+ end
37
+
38
+ shared_examples 'a class method is missing' do
39
+ before do
40
+ allow(word_preprocessor.class).to receive(:respond_to?).with(method).and_return(false)
41
+ end
42
+
43
+ it 'raises an error' do
44
+ expect { WordPreprocessorValidatable.validate_word_preprocessor word_preprocessor: word_preprocessor }.to raise_error expected_error_message
45
+ end
46
+ end
47
+
48
+ #.validate_word_preprocessor
49
+ describe '.validate_word_preprocessor' do
50
+ before do
51
+ allow(word_preprocessor.class).to receive(:respond_to?).and_call_original
52
+ allow(word_preprocessor).to receive(:respond_to?).and_call_original
53
+ end
54
+
55
+ context 'when the object quacks right' do
56
+ it 'passes validation' do
57
+ expect { WordPreprocessorValidatable.validate_word_preprocessor word_preprocessor: word_preprocessor }.to_not raise_error
58
+ end
59
+ end
60
+
61
+ context 'when the object DOES NOT quack right' do
62
+ let(:expected_error_message) { /Argument word_preprocessor: does not respond to/ }
63
+
64
+ context 'when a class method is missing' do
65
+ context 'when the class does not respond to .preprocess' do
66
+ let(:method) { :preprocess }
67
+ it_behaves_like 'a class method is missing'
68
+ end
69
+
70
+ context 'when the class does not respond to .preprocess?' do
71
+ let(:method) { :preprocess? }
72
+ it_behaves_like 'a class method is missing'
73
+ end
74
+ end
75
+
76
+ context 'when an instance method is missing' do
77
+ context 'when the object does not respond to #preprocess' do
78
+ let(:method) { :preprocess }
79
+ it_behaves_like 'an instance method is missing'
80
+ end
81
+
82
+ context 'when the object does not respond to #preprocess?' do
83
+ let(:method) { :preprocess? }
84
+ it_behaves_like 'an instance method is missing'
85
+ end
86
+
87
+ context 'when the object does not respond to #preprocessor_off?' do
88
+ let(:method) { :preprocessor_off? }
89
+ it_behaves_like 'an instance method is missing'
90
+ end
91
+
92
+ context 'when the object does not respond to #preprocessor_on' do
93
+ let(:method) { :preprocessor_on }
94
+ it_behaves_like 'an instance method is missing'
95
+ end
96
+
97
+ context 'when the object does not respond to #preprocessor_on=' do
98
+ let(:method) { :preprocessor_on= }
99
+ it_behaves_like 'an instance method is missing'
100
+ end
101
+
102
+ context 'when the object does not respond to #preprocessor_on?' do
103
+ let(:method) { :preprocessor_on? }
104
+ it_behaves_like 'an instance method is missing'
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe LittleWeasel::Preprocessors::WordPreprocessorsValidatable, type: :module do
6
+ subject { MockSubject.new }
7
+
8
+ WordPreprocessorsValidatable = described_class
9
+
10
+ class MockSubject
11
+ include WordPreprocessorsValidatable
12
+ end
13
+
14
+ subject { MockSubject.new }
15
+
16
+ class MockWordPreprocessor < LittleWeasel::Preprocessors::WordPreprocessor
17
+ def initialize(order: 0)
18
+ super order: order
19
+ self.preprocessor_on = preprocessor_on
20
+ end
21
+
22
+ class << self
23
+ def preprocess(word) [true, "#{word}-0"]; end
24
+ end
25
+ end
26
+
27
+ #.validate_word_preprocessors
28
+ describe '.validate_word_preprocessors' do
29
+ context 'when passing a blank Array' do
30
+ it 'passes validaton' do
31
+ expect { WordPreprocessorsValidatable.validate_word_preprocessors(word_preprocessors: []) }.to_not raise_error
32
+ end
33
+ end
34
+
35
+ context 'when passing a an Array with valid word preprocessors' do
36
+ it 'passes validation' do
37
+ expect { WordPreprocessorsValidatable.validate_word_preprocessors(word_preprocessors: [MockWordPreprocessor.new]) }.to_not raise_error
38
+ end
39
+ end
40
+
41
+ context 'when passing an INVALID argument' do
42
+ context 'when passing an invalid Array' do
43
+ it 'raises an error' do
44
+ expect { WordPreprocessorsValidatable.validate_word_preprocessors(word_preprocessors: :not_an_array) }.to raise_error(/Argument word_preprocessors is not an Array/)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,444 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe LittleWeasel::Services::DictionaryCacheService do
6
+ include_context 'dictionary cache'
7
+ include_context 'dictionary keys'
8
+ include_context 'dictionary sourceable'
9
+
10
+ subject { create(:dictionary_cache_service, dictionary_cache: dictionary_cache) }
11
+
12
+ let(:en_us_dictionary_key) { dictionary_key_for(language: :en, region: :us) }
13
+ let(:en_gb_dictionary_key) { dictionary_key_for(language: :en, region: :gb) }
14
+ let(:es_es_dictionary_key) { dictionary_key_for(language: :es, region: :es) }
15
+
16
+ let(:dictionary_key) { en_us_dictionary_key }
17
+ let(:key) { dictionary_key.key }
18
+ let(:file) { dictionary_path_for(file_name: key) }
19
+ let(:file_minus_ext) { key }
20
+ let(:dictionary_cache) { {} }
21
+ let!(:initialized_dictionary_cache) { LittleWeasel::Modules::DictionaryCacheKeys.initialize_dictionary_cache(dictionary_cache: {}) }
22
+
23
+ shared_examples 'the dictionary_cache object reference has not changed' do
24
+ it 'the dictionary_cache object has not changed' do
25
+ expect(actual_dictionary_cache).to eq expected_dictionary_cache
26
+ end
27
+ end
28
+
29
+ describe 'class methods' do
30
+ #.init
31
+ describe '.init' do
32
+ subject! { create(:dictionary_cache_service, dictionary_file_source: true, dictionary_cache: dictionary_cache) }
33
+
34
+ before do
35
+ create(:dictionary_cache_service, dictionary_file_source: true, dictionary_cache: dictionary_cache, dictionary_key: en_gb_dictionary_key)
36
+ end
37
+
38
+ it 'resets the cache to an initiaized state for all keys in the cache' do
39
+ expect { described_class.init(dictionary_cache: dictionary_cache) }.to change { dictionary_cache }.to(initialized_dictionary_cache)
40
+ end
41
+
42
+ describe 'maintains dictionary_cache object integrity' do
43
+ it_behaves_like 'the dictionary_cache object reference has not changed' do
44
+ before { subject }
45
+ let(:actual_dictionary_cache) { described_class.init(dictionary_cache: dictionary_cache) }
46
+ let(:expected_dictionary_cache) { dictionary_cache }
47
+ end
48
+ end
49
+ end
50
+
51
+ #.init?
52
+ describe '.init?' do
53
+ context 'when passing an initialized dictionary cache Hash' do
54
+ it 'returns true' do
55
+ expect(described_class.init? dictionary_cache: initialized_dictionary_cache).to eq true
56
+ end
57
+ end
58
+
59
+ context 'when passing a NON-initialized dictionary cache Hash' do
60
+ before do
61
+ subject.add_dictionary_source source: file
62
+ end
63
+
64
+ it 'returns false' do
65
+ expect(described_class.init? dictionary_cache: dictionary_cache).to eq false
66
+ end
67
+ end
68
+ end
69
+
70
+ #.count
71
+ describe '.count' do
72
+ context 'when there are no dictionary references' do
73
+ subject { create(:dictionary_cache_service) }
74
+
75
+ it 'returns 0' do
76
+ expect(described_class.count(dictionary_cache: subject.dictionary_cache)).to eq 0
77
+ end
78
+ end
79
+
80
+ context 'when there are are dictionary references' do
81
+ subject { create(:dictionary_cache_service, dictionary_file_source: true) }
82
+
83
+ it 'returns the dictionary reference count' do
84
+ expect(described_class.count(dictionary_cache: subject.dictionary_cache)).to eq 1
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ #init
91
+ describe '#init' do
92
+ subject! { create(:dictionary_cache_service, dictionary_file_source: true, dictionary_cache: dictionary_cache) }
93
+
94
+ let!(:subject2) { create(:dictionary_cache_service, dictionary_file_source: true, dictionary_cache: dictionary_cache, dictionary_key: en_gb_dictionary_key) }
95
+ let!(:original_dictionary_cache) { dictionary_cache }
96
+
97
+ it 'resets the cache to an initiaized state for the GIVEN KEY ONLY' do
98
+ expect { subject.init }.to change { dictionary_cache }.from(original_dictionary_cache).to(subject2.dictionary_cache)
99
+ expect { subject2.init }.to change { dictionary_cache }.from(original_dictionary_cache).to(subject.dictionary_cache)
100
+ end
101
+
102
+ describe 'maintains dictionary_cache object integrity' do
103
+ it_behaves_like 'the dictionary_cache object reference has not changed' do
104
+ let(:actual_dictionary_cache) { subject.init.dictionary_cache }
105
+ let(:expected_dictionary_cache) { dictionary_cache }
106
+ end
107
+ end
108
+ end
109
+
110
+ #dictionary_reference?
111
+ describe '#dictionary_reference?' do
112
+ subject { create(:dictionary_cache_service, dictionary_key: dictionary_key, dictionary_file_source: true, dictionary_cache: dictionary_cache) }
113
+
114
+ context 'when the dictionary reference exists' do
115
+ it 'returns true' do
116
+ expect(subject.dictionary_reference?).to eq true
117
+ end
118
+ end
119
+
120
+ context 'when the dictionary reference DOES NOT exist' do
121
+ subject { create(:dictionary_cache_service, dictionary_key: es_es_dictionary_key, dictionary_cache: dictionary_cache) }
122
+
123
+ before do
124
+ create(:dictionary_cache_service, dictionary_key: en_us_dictionary_key, dictionary_cache: dictionary_cache)
125
+ .add_dictionary_source source: memory_source
126
+ create(:dictionary_cache_service, dictionary_key: en_gb_dictionary_key, dictionary_cache: dictionary_cache)
127
+ .add_dictionary_source source: dictionary_path_for(file_name: en_gb_dictionary_key.key)
128
+ end
129
+
130
+ it 'returns false' do
131
+ expect(subject.dictionary_reference?).to eq false
132
+ end
133
+ end
134
+
135
+ describe 'maintains dictionary_cache object integrity' do
136
+ it_behaves_like 'the dictionary_cache object reference has not changed' do
137
+ let(:actual_dictionary_cache) { subject.dictionary_cache }
138
+ let(:expected_dictionary_cache) { dictionary_cache }
139
+ end
140
+ end
141
+ end
142
+
143
+ #add_dictionary_source source: memory_source
144
+ describe '#add_dictionary_source source: memory_source' do
145
+ subject! do
146
+ create(:dictionary_cache_service, dictionary_cache: dictionary_cache, dictionary_key: dictionary_key)
147
+ .add_dictionary_source source: memory_source
148
+ end
149
+
150
+ context 'when a dictionary already exists' do
151
+ it 'raises an error' do
152
+ expect do
153
+ create(:dictionary_cache_service, dictionary_key: dictionary_key, dictionary_cache: subject.dictionary_cache)
154
+ .add_dictionary_source source: memory_source
155
+ end.to raise_error "The dictionary source associated with key '#{key}' already exists."
156
+ end
157
+ end
158
+
159
+ context 'when a dictionary reference for the key DOES NOT already exist' do
160
+ let(:dictionary_cache_service) do
161
+ create(:dictionary_cache_service, dictionary_key: en_gb_dictionary_key, dictionary_cache: subject.dictionary_cache)
162
+ end
163
+
164
+ before do
165
+ dictionary_cache_service.add_dictionary_source source: memory_source
166
+ end
167
+
168
+ let(:dictionary_source) { dictionary_cache_service.dictionary_source }
169
+
170
+ it 'creates a new dictionary reference' do
171
+ expect(dictionary_cache_service.dictionary_reference?).to eq true
172
+ end
173
+
174
+ it 'creates a unique memory source' do
175
+ expect(LittleWeasel::Modules::DictionarySourceable.memory_source? dictionary_source).to be_truthy
176
+ expect(dictionary_source == subject.dictionary_source).to_not eq true
177
+ end
178
+ end
179
+
180
+ describe 'maintains dictionary_cache object integrity' do
181
+ it_behaves_like 'the dictionary_cache object reference has not changed' do
182
+ subject { create(:dictionary_cache_service, dictionary_key: dictionary_key, dictionary_cache: dictionary_cache) }
183
+ let(:actual_dictionary_cache) { subject.add_dictionary_source(source: memory_source).dictionary_cache }
184
+ let(:expected_dictionary_cache) { dictionary_cache }
185
+ end
186
+ end
187
+ end
188
+
189
+ #add_dictionary_source
190
+ describe '#add_dictionary_source' do
191
+ context 'when a dictionary reference for the key already exists' do
192
+ before do
193
+ create(:dictionary_cache_service, dictionary_cache: dictionary_cache, dictionary_key: dictionary_key)
194
+ .add_dictionary_source(source: file)
195
+ end
196
+
197
+ it 'raises an error' do
198
+ expect do
199
+ create(:dictionary_cache_service, dictionary_cache: dictionary_cache, dictionary_key: dictionary_key, dictionary_cache: subject.dictionary_cache)
200
+ .add_dictionary_source(source: file)
201
+ end.to raise_error "The dictionary source associated with key '#{key}' already exists."
202
+ end
203
+ end
204
+
205
+ context 'when a dictionary reference for the key DOES NOT already exist' do
206
+ subject! do
207
+ create(:dictionary_cache_service, dictionary_cache: dictionary_cache, dictionary_key: dictionary_key)
208
+ .add_dictionary_source(source: file)
209
+ end
210
+
211
+ let(:en_gb_file) do
212
+ "#{ dictionary_path_for(file_name: en_gb_dictionary_key.key) }"
213
+ end
214
+
215
+ it 'creates a new dictionary reference' do
216
+ dictionary_cache_service = create(:dictionary_cache_service, dictionary_key: en_gb_dictionary_key, dictionary_cache: subject.dictionary_cache)
217
+ dictionary_cache_service.add_dictionary_source source: en_gb_file
218
+ expect(dictionary_cache_service.dictionary_reference?).to eq true
219
+ end
220
+
221
+ context 'when the file source already exists' do
222
+ it 'reuses the existing file source' do
223
+ dictionary_cache_service = create(:dictionary_cache_service, dictionary_key: en_gb_dictionary_key, dictionary_cache: subject.dictionary_cache)
224
+ # Note: We're using the same file as en-US dictionary key, so
225
+ # the file source is NOT unique and will be reused.
226
+ dictionary_cache_service.add_dictionary_source source: file
227
+ expect(LittleWeasel::Modules::DictionarySourceable.file_source? dictionary_cache_service.dictionary_source).to be_truthy
228
+ expect(dictionary_cache_service.dictionary_source == subject.dictionary_source).to eq true
229
+ end
230
+ end
231
+
232
+ context 'when the file source DOES NOT already exists' do
233
+ it 'creates a unique file source' do
234
+ dictionary_cache_service = create(:dictionary_cache_service, dictionary_key: en_gb_dictionary_key, dictionary_cache: subject.dictionary_cache)
235
+ # Note: We're using file that is DIFFERENT from the file being used by the
236
+ # en-US dictionary key, the file source created will be unique.
237
+ dictionary_cache_service.add_dictionary_source source: en_gb_file
238
+ expect(LittleWeasel::Modules::DictionarySourceable.file_source? dictionary_cache_service.dictionary_source).to be_truthy
239
+ expect(dictionary_cache_service.dictionary_source == subject.dictionary_source).to eq false
240
+ end
241
+ end
242
+ end
243
+
244
+ describe 'maintains dictionary_cache object integrity' do
245
+ it_behaves_like 'the dictionary_cache object reference has not changed' do
246
+ subject { create(:dictionary_cache_service, dictionary_key: dictionary_key, dictionary_cache: dictionary_cache) }
247
+ let(:actual_dictionary_cache) { subject.add_dictionary_source(source: file).dictionary_cache }
248
+ let(:expected_dictionary_cache) { dictionary_cache }
249
+ end
250
+ end
251
+ end
252
+
253
+ #dictionary_file
254
+ describe '#dictionary_file' do
255
+ context 'when a file source is used' do
256
+ subject! { create(:dictionary_cache_service, dictionary_key: dictionary_key).add_dictionary_source(source: file) }
257
+
258
+ it 'returns the dictionary file' do
259
+ expect(subject.dictionary_file).to eq file
260
+ end
261
+ end
262
+
263
+ context 'when a memory source is used' do
264
+ subject! { create(:dictionary_cache_service, dictionary_key: dictionary_key).add_dictionary_source source: memory_source }
265
+
266
+ let(:dictionary_words) { dictionary_words_for(dictionary_file_path: file) }
267
+
268
+ it 'returns the dictionary file' do
269
+ expect(LittleWeasel::Modules::DictionarySourceable.memory_source? subject.dictionary_file).to be_truthy
270
+ end
271
+ end
272
+ end
273
+
274
+ #dictionary_id
275
+ describe '#dictionary_id' do
276
+ context 'when a dictionary id exists for the given dictionary key' do
277
+ before do
278
+ subject.add_dictionary_source source: memory_source
279
+ end
280
+
281
+ it 'returns the key' do
282
+ expect(subject.dictionary_id).to_not be_nil
283
+ end
284
+ end
285
+
286
+ context 'when a dictionary id DOES NOT exist for the given dictionary key' do
287
+ it 'returns nil' do
288
+ expect(subject.dictionary_id).to be_nil
289
+ end
290
+ end
291
+ end
292
+
293
+ #dictionary_id!
294
+ describe '#dictionary_id!' do
295
+ context 'when a dictionary id associated with the dictionary key exists' do
296
+ subject { create(:dictionary_cache_service, dictionary_cache: dictionary_cache, dictionary_key: dictionary_key, dictionary_file_source: true) }
297
+
298
+ it 'returns the dictionary id' do
299
+ expect { subject.dictionary_id! }.to_not raise_error
300
+ end
301
+ end
302
+
303
+ context 'when a dictionary id associated with the dictionary key DOES NOT exist' do
304
+ subject { create(:dictionary_cache_service) }
305
+
306
+ it 'raises an error' do
307
+ expect { subject.dictionary_id! }.to raise_error "A dictionary id could not be found for key '#{key}'."
308
+ end
309
+ end
310
+ end
311
+
312
+ #dictionary_exists?
313
+ describe '#dictionary_exists?' do
314
+ context 'when the dictionary reference does not exist' do
315
+ subject { create(:dictionary_cache_service, dictionary_cache: dictionary_cache) }
316
+
317
+ it 'returns false' do
318
+ expect(subject.dictionary_exists?).to eq false
319
+ end
320
+ end
321
+
322
+ context 'when the dictionary is already loaded' do
323
+ subject { create(:dictionary_cache_service, dictionary_cache: dictionary_cache, dictionary_file_source: true, load: true) }
324
+
325
+ it 'returns true' do
326
+ expect(subject.dictionary_exists?).to eq true
327
+ end
328
+ end
329
+
330
+ context 'when the dictionary is NOT already loaded' do
331
+ subject { create(:dictionary_cache_service, dictionary_cache: dictionary_cache, dictionary_file_source: true) }
332
+
333
+ it 'returns false' do
334
+ expect(subject.dictionary_exists?).to eq false
335
+ end
336
+ end
337
+ end
338
+
339
+ #dictionary_object
340
+ describe '#dictionary_object' do
341
+ context 'when the dictionary object is already cached/loaded' do
342
+ subject { create(:dictionary_cache_service, dictionary_file_source: true, load: true) }
343
+
344
+ it 'returns the dictionary object' do
345
+ expect(subject.dictionary_object).to be_kind_of LittleWeasel::Dictionary
346
+ end
347
+ end
348
+
349
+ context 'when the dictionary object is NOT already cached/loaded' do
350
+ context 'when the dictionary reference exists' do
351
+ it 'returns an object that is not present?' do
352
+ expect(create(:dictionary_cache_service, dictionary_file_source: true).dictionary_object).to_not be_present
353
+ end
354
+ end
355
+
356
+ context 'when the dictionary reference DOES NOT exist' do
357
+ it 'returns an object that is not present?' do
358
+ expect(create(:dictionary_cache_service).dictionary_object).to_not be_present
359
+ end
360
+ end
361
+ end
362
+ end
363
+
364
+ #dictionary_object!
365
+ describe '#dictionary_object!' do
366
+ describe 'when the dictionary is NOT in the cache' do
367
+ it 'raises an error' do
368
+ expect { subject.dictionary_object! }.to raise_error("The dictionary object associated with argument key '#{key}' is not in the cache.")
369
+ end
370
+ end
371
+
372
+ describe 'when the dictionary is loaded/cached' do
373
+ subject { create(:dictionary_cache_service, dictionary_file_source: true, load: true) }
374
+
375
+ it 'returns the dictionary cache for the dictionary' do
376
+ expect(subject.dictionary_reference?).to eq true
377
+ expect(subject.dictionary_exists?).to eq true
378
+ expect(subject.dictionary_object!).to be_kind_of LittleWeasel::Dictionary
379
+ end
380
+ end
381
+ end
382
+
383
+ #dictionary_object=
384
+ describe '#dictionary_object=' do
385
+ context 'when the dictionary object passed is invalid' do
386
+ subject { create(:dictionary_cache_service) }
387
+
388
+ context 'when nil' do
389
+ it 'raises an error' do
390
+ expect { subject.dictionary_object = nil }.to raise_error 'Argument object is not a Dictionary object'
391
+ end
392
+ end
393
+
394
+ context 'when not a Dictionary object' do
395
+ it 'raises an error' do
396
+ expect { subject.dictionary_object = :wrong_object }.to raise_error 'Argument object is not a Dictionary object'
397
+ end
398
+ end
399
+ end
400
+
401
+ context 'when there is NO dictionary reference' do
402
+ before do
403
+ allow(dictionary_object).to receive(:is_a?).and_return(true)
404
+ end
405
+
406
+ subject { create(:dictionary_cache_service, dictionary_cache: dictionary_cache, dictionary_key: dictionary_key) }
407
+
408
+ let(:dictionary_object) { Object.new }
409
+
410
+ it 'raises an error' do
411
+ expect { subject.dictionary_object = dictionary_object }.to raise_error "The dictionary reference associated with key '#{key}' could not be found."
412
+ end
413
+ end
414
+
415
+ context 'when the dictionary is already loaded/cached and different from the dictionary object passed' do
416
+ subject { create(:dictionary_cache_service, dictionary_cache: dictionary_cache, dictionary_key: dictionary_key, dictionary_file_source: true, load: true) }
417
+
418
+ let(:dictionary) { create(:dictionary, dictionary_cache: dictionary_cache, dictionary_key: dictionary_key) }
419
+
420
+ it 'raises an error' do
421
+ expect { subject.dictionary_object = dictionary }.to raise_error "The dictionary is already loaded/cached for key '#{key}'; use #unload or #kill first."
422
+ end
423
+ end
424
+
425
+ context 'when the dictionary is already loaded/cached and the dictionary object is the same as the one that is loaded/cached' do
426
+ subject { create(:dictionary_cache_service, dictionary_file_source: true, load: true) }
427
+
428
+ it 'returns the same object' do
429
+ expect(subject.dictionary_object = subject.dictionary_object).to eq subject.dictionary_object
430
+ end
431
+ end
432
+
433
+ context 'when the dictionary is NOT already loaded/cached' do
434
+ subject { create(:dictionary_cache_service, dictionary_key: dictionary_key, dictionary_cache: dictionary_cache, dictionary_file_source: true) }
435
+
436
+ let(:dictionary) { create(:dictionary, dictionary_key: dictionary_key, dictionary_cache: dictionary_cache) }
437
+
438
+ it 'updates the dictionary object' do
439
+ expect { subject.dictionary_object = dictionary }.to_not raise_error
440
+ expect(subject.dictionary_object).to eq dictionary
441
+ end
442
+ end
443
+ end
444
+ end