LittleWeasel 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.idea/.rakeTasks +1 -1
  4. data/.idea/LittleWeasel.iml +5 -18
  5. data/.idea/workspace.xml +198 -109
  6. data/.reek.yml +17 -0
  7. data/.rspec +4 -2
  8. data/.rubocop.yml +187 -0
  9. data/.ruby-version +1 -0
  10. data/.yardopts +2 -0
  11. data/CHANGELOG.md +16 -0
  12. data/Gemfile +3 -1
  13. data/LittleWeasel.gemspec +31 -18
  14. data/README.md +408 -42
  15. data/Rakefile +296 -3
  16. data/lib/LittleWeasel.rb +5 -171
  17. data/lib/LittleWeasel/block_results.rb +81 -0
  18. data/lib/LittleWeasel/configure.rb +98 -0
  19. data/lib/LittleWeasel/dictionary.rb +125 -0
  20. data/lib/LittleWeasel/dictionary_key.rb +48 -0
  21. data/lib/LittleWeasel/dictionary_manager.rb +85 -0
  22. data/lib/LittleWeasel/errors/dictionary_file_already_loaded_error.rb +9 -0
  23. data/lib/LittleWeasel/errors/dictionary_file_empty_error.rb +8 -0
  24. data/lib/LittleWeasel/errors/dictionary_file_not_found_error.rb +8 -0
  25. data/lib/LittleWeasel/errors/dictionary_file_too_large_error.rb +16 -0
  26. data/lib/LittleWeasel/errors/language_required_error.rb +8 -0
  27. data/lib/LittleWeasel/errors/must_override_error.rb +8 -0
  28. data/lib/LittleWeasel/filters/en_us/currency_filter.rb +19 -0
  29. data/lib/LittleWeasel/filters/en_us/numeric_filter.rb +19 -0
  30. data/lib/LittleWeasel/filters/en_us/single_character_word_filter.rb +21 -0
  31. data/lib/LittleWeasel/filters/word_filter.rb +59 -0
  32. data/lib/LittleWeasel/filters/word_filter_managable.rb +80 -0
  33. data/lib/LittleWeasel/filters/word_filter_validatable.rb +31 -0
  34. data/lib/LittleWeasel/filters/word_filterable.rb +19 -0
  35. data/lib/LittleWeasel/filters/word_filters_validatable.rb +29 -0
  36. data/lib/LittleWeasel/metadata/dictionary_metadata.rb +145 -0
  37. data/lib/LittleWeasel/metadata/invalid_words_metadata.rb +134 -0
  38. data/lib/LittleWeasel/metadata/invalid_words_service_results.rb +45 -0
  39. data/lib/LittleWeasel/metadata/metadata_observable_validatable.rb +22 -0
  40. data/lib/LittleWeasel/metadata/metadata_observerable.rb +90 -0
  41. data/lib/LittleWeasel/metadata/metadatable.rb +136 -0
  42. data/lib/LittleWeasel/modules/class_name_to_symbol.rb +26 -0
  43. data/lib/LittleWeasel/modules/configurable.rb +26 -0
  44. data/lib/LittleWeasel/modules/deep_dup.rb +11 -0
  45. data/lib/LittleWeasel/modules/dictionary_cache_keys.rb +34 -0
  46. data/lib/LittleWeasel/modules/dictionary_cache_servicable.rb +26 -0
  47. data/lib/LittleWeasel/modules/dictionary_cache_validatable.rb +20 -0
  48. data/lib/LittleWeasel/modules/dictionary_creator_servicable.rb +27 -0
  49. data/lib/LittleWeasel/modules/dictionary_file_loader.rb +67 -0
  50. data/lib/LittleWeasel/modules/dictionary_key_validatable.rb +19 -0
  51. data/lib/LittleWeasel/modules/dictionary_keyable.rb +24 -0
  52. data/lib/LittleWeasel/modules/dictionary_loader_servicable.rb +27 -0
  53. data/lib/LittleWeasel/modules/dictionary_metadata_servicable.rb +29 -0
  54. data/lib/LittleWeasel/modules/dictionary_metadata_validatable.rb +17 -0
  55. data/lib/LittleWeasel/modules/dictionary_sourceable.rb +26 -0
  56. data/lib/LittleWeasel/modules/dictionary_validatable.rb +30 -0
  57. data/lib/LittleWeasel/modules/language.rb +23 -0
  58. data/lib/LittleWeasel/modules/language_validatable.rb +16 -0
  59. data/lib/LittleWeasel/modules/locale.rb +40 -0
  60. data/lib/LittleWeasel/modules/order_validatable.rb +18 -0
  61. data/lib/LittleWeasel/modules/orderable.rb +17 -0
  62. data/lib/LittleWeasel/modules/region.rb +23 -0
  63. data/lib/LittleWeasel/modules/region_validatable.rb +16 -0
  64. data/lib/LittleWeasel/modules/tag_validatable.rb +16 -0
  65. data/lib/LittleWeasel/modules/taggable.rb +31 -0
  66. data/lib/LittleWeasel/modules/word_results_validatable.rb +28 -0
  67. data/lib/LittleWeasel/preprocessors/en_us/capitalize_preprocessor.rb +22 -0
  68. data/lib/LittleWeasel/preprocessors/preprocessed_word.rb +28 -0
  69. data/lib/LittleWeasel/preprocessors/preprocessed_word_validatable.rb +55 -0
  70. data/lib/LittleWeasel/preprocessors/preprocessed_words.rb +55 -0
  71. data/lib/LittleWeasel/preprocessors/preprocessed_words_validatable.rb +27 -0
  72. data/lib/LittleWeasel/preprocessors/word_preprocessable.rb +19 -0
  73. data/lib/LittleWeasel/preprocessors/word_preprocessor.rb +122 -0
  74. data/lib/LittleWeasel/preprocessors/word_preprocessor_managable.rb +114 -0
  75. data/lib/LittleWeasel/preprocessors/word_preprocessor_validatable.rb +40 -0
  76. data/lib/LittleWeasel/preprocessors/word_preprocessors_validatable.rb +24 -0
  77. data/lib/LittleWeasel/services/dictionary_cache_service.rb +262 -0
  78. data/lib/LittleWeasel/services/dictionary_creator_service.rb +94 -0
  79. data/lib/LittleWeasel/services/dictionary_file_loader_service.rb +37 -0
  80. data/lib/LittleWeasel/services/dictionary_killer_service.rb +35 -0
  81. data/lib/LittleWeasel/services/dictionary_loader_service.rb +59 -0
  82. data/lib/LittleWeasel/services/dictionary_metadata_service.rb +114 -0
  83. data/lib/LittleWeasel/services/invalid_words_service.rb +59 -0
  84. data/lib/LittleWeasel/version.rb +3 -1
  85. data/lib/LittleWeasel/word_results.rb +146 -0
  86. data/spec/factories/dictionary.rb +43 -0
  87. data/spec/factories/dictionary_cache_service.rb +95 -0
  88. data/spec/factories/dictionary_creator_service.rb +16 -0
  89. data/spec/factories/dictionary_file_loader_service.rb +13 -0
  90. data/spec/factories/dictionary_hash.rb +39 -0
  91. data/spec/factories/dictionary_key.rb +14 -0
  92. data/spec/factories/dictionary_killer_service.rb +14 -0
  93. data/spec/factories/dictionary_loader_service.rb +14 -0
  94. data/spec/factories/dictionary_manager.rb +10 -0
  95. data/spec/factories/dictionary_metadata.rb +16 -0
  96. data/spec/factories/dictionary_metadata_service.rb +16 -0
  97. data/spec/factories/numeric_filter.rb +12 -0
  98. data/spec/factories/preprocessed_word.rb +16 -0
  99. data/spec/factories/preprocessed_words.rb +41 -0
  100. data/spec/factories/single_character_word_filter.rb +12 -0
  101. data/spec/factories/word_results.rb +16 -0
  102. data/spec/lib/LittleWeasel/block_results_spec.rb +248 -0
  103. data/spec/lib/LittleWeasel/configure_spec.rb +74 -0
  104. data/spec/lib/LittleWeasel/dictionary_key_spec.rb +118 -0
  105. data/spec/lib/LittleWeasel/dictionary_manager_spec.rb +116 -0
  106. data/spec/lib/LittleWeasel/dictionary_spec.rb +289 -0
  107. data/spec/lib/LittleWeasel/filters/en_us/currency_filter_spec.rb +80 -0
  108. data/spec/lib/LittleWeasel/filters/en_us/numeric_filter_spec.rb +66 -0
  109. data/spec/lib/LittleWeasel/filters/en_us/single_character_word_filter_spec.rb +58 -0
  110. data/spec/lib/LittleWeasel/filters/word_filter_managable_spec.rb +180 -0
  111. data/spec/lib/LittleWeasel/filters/word_filter_spec.rb +151 -0
  112. data/spec/lib/LittleWeasel/filters/word_filter_validatable_spec.rb +94 -0
  113. data/spec/lib/LittleWeasel/filters/word_filters_validatable_spec.rb +48 -0
  114. data/spec/lib/LittleWeasel/integraton_tests/dictionary_integration_spec.rb +201 -0
  115. data/spec/lib/LittleWeasel/metadata/dictionary_creator_servicable_spec.rb +54 -0
  116. data/spec/lib/LittleWeasel/metadata/dictionary_metadata_spec.rb +209 -0
  117. data/spec/lib/LittleWeasel/metadata/invalid_words_metadata_spec.rb +155 -0
  118. data/spec/lib/LittleWeasel/metadata/metadata_observerable_spec.rb +31 -0
  119. data/spec/lib/LittleWeasel/metadata/metadatable_spec.rb +35 -0
  120. data/spec/lib/LittleWeasel/modules/class_name_to_symbol_spec.rb +21 -0
  121. data/spec/lib/LittleWeasel/modules/dictionary_file_loader_spec.rb +125 -0
  122. data/spec/lib/LittleWeasel/modules/dictionary_sourceable_spec.rb +44 -0
  123. data/spec/lib/LittleWeasel/modules/language_spec.rb +52 -0
  124. data/spec/lib/LittleWeasel/modules/locale_spec.rb +140 -0
  125. data/spec/lib/LittleWeasel/modules/region_spec.rb +52 -0
  126. data/spec/lib/LittleWeasel/preprocessors/en_us/capitalize_preprocessor_spec.rb +34 -0
  127. data/spec/lib/LittleWeasel/preprocessors/preprocessed_word_spec.rb +105 -0
  128. data/spec/lib/LittleWeasel/preprocessors/preprocessed_word_validatable_spec.rb +143 -0
  129. data/spec/lib/LittleWeasel/preprocessors/preprocessed_words_spec.rb +77 -0
  130. data/spec/lib/LittleWeasel/preprocessors/preprocessed_words_validatable_spec.rb +58 -0
  131. data/spec/lib/LittleWeasel/preprocessors/word_preprocessor_managable_spec.rb +216 -0
  132. data/spec/lib/LittleWeasel/preprocessors/word_preprocessor_spec.rb +175 -0
  133. data/spec/lib/LittleWeasel/preprocessors/word_preprocessor_validatable_spec.rb +109 -0
  134. data/spec/lib/LittleWeasel/preprocessors/word_preprocessors_validatable_spec.rb +49 -0
  135. data/spec/lib/LittleWeasel/services/dictionary_cache_service_spec.rb +444 -0
  136. data/spec/lib/LittleWeasel/services/dictionary_creator_service_spec.rb +119 -0
  137. data/spec/lib/LittleWeasel/services/dictionary_file_loader_service_spec.rb +71 -0
  138. data/spec/lib/LittleWeasel/services/dictionary_loader_service_spec.rb +50 -0
  139. data/spec/lib/LittleWeasel/services/dictionary_metadata_service_spec.rb +279 -0
  140. data/spec/lib/LittleWeasel/word_results_spec.rb +275 -0
  141. data/spec/lib/LittleWeasel/workflow/workflow_spec.rb +20 -0
  142. data/spec/spec_helper.rb +117 -6
  143. data/spec/support/factory_bot.rb +15 -0
  144. data/spec/support/file_helpers.rb +32 -0
  145. data/spec/support/files/empty-dictionary.txt +0 -0
  146. data/{lib/dictionary → spec/support/files/en-US-big.txt} +262156 -31488
  147. data/spec/support/files/en-US-tagged.txt +26 -0
  148. data/spec/support/files/en-US.txt +26 -0
  149. data/spec/support/files/en.txt +26 -0
  150. data/spec/support/files/es-ES.txt +27 -0
  151. data/spec/support/files/es.txt +27 -0
  152. data/spec/support/general_helpers.rb +68 -0
  153. data/spec/support/shared_contexts.rb +108 -0
  154. data/spec/support/shared_examples.rb +105 -0
  155. metadata +415 -52
  156. data/.rbenv-version +0 -1
  157. data/spec/checker/checker_spec.rb +0 -237
@@ -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