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,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../modules/class_name_to_symbol'
4
+ require_relative '../modules/configurable'
5
+ require_relative '../modules/dictionary_cache_servicable'
6
+ require_relative '../modules/dictionary_keyable'
7
+ require_relative '../services/invalid_words_service'
8
+ require_relative 'metadata_observerable'
9
+
10
+ module LittleWeasel
11
+ module Metadata
12
+ # This class provides the ability to cache words not found in the
13
+ # associated dictionary.
14
+ class InvalidWordsMetadata
15
+ include Metadata::MetadataObserverable
16
+ include Modules::ClassNameToSymbol
17
+ include Modules::Configurable
18
+ include Modules::DictionaryCacheServicable
19
+ include Modules::DictionaryKeyable
20
+ include Modules::DictionaryMetadataServicable
21
+
22
+ delegate :on?, :off?, :value, :value_exceeded?,
23
+ :current_invalid_word_bytesize, :cache_invalid_words?,
24
+ to: :metadata
25
+
26
+ attr_reader :dictionary_metadata_object
27
+
28
+ def initialize(dictionary_metadata_object:, dictionary_metadata:,
29
+ dictionary_cache:, dictionary_key:, dictionary_words:)
30
+ validate_dictionary_key dictionary_key: dictionary_key
31
+ self.dictionary_key = dictionary_key
32
+
33
+ validate_dictionary_cache dictionary_cache: dictionary_cache
34
+ self.dictionary_cache = dictionary_cache
35
+
36
+ validate_dictionary_metadata dictionary_metadata: dictionary_metadata
37
+ self.dictionary_metadata = dictionary_metadata
38
+
39
+ unless dictionary_metadata_object.is_a? Observable
40
+ raise ArgumentError,
41
+ "Argument dictionary_metadata_object is not an Observable: #{dictionary_metadata_object.class}."
42
+ end
43
+
44
+ dictionary_metadata_object.add_observer self
45
+ self.dictionary_metadata_object = dictionary_metadata_object
46
+
47
+ unless dictionary_words.is_a? Hash
48
+ raise ArgumentError,
49
+ "Argument dictionary_words is not a Hash: #{dictionary_words.class}."
50
+ end
51
+
52
+ self.dictionary_words = dictionary_words
53
+ end
54
+
55
+ class << self
56
+ def metadata_key
57
+ to_sym
58
+ end
59
+
60
+ def observe?
61
+ config.max_invalid_words_bytesize?
62
+ end
63
+ end
64
+
65
+ # rubocop: disable Lint/UnusedMethodArgument
66
+ def init(params: nil)
67
+ dictionary_metadata_service.init(metadata_key: metadata_key)
68
+ self.metadata = Services::InvalidWordsService.new(dictionary_words).execute
69
+ self
70
+ end
71
+ # rubocop: enable Lint/UnusedMethodArgument
72
+
73
+ # rubocop: disable Lint/UnusedMethodArgument
74
+ def refresh(params: nil)
75
+ refresh_local_metadata
76
+ init unless metadata.present?
77
+ self
78
+ end
79
+ # rubocop: enable Lint/UnusedMethodArgument
80
+
81
+ # This method is called when a word is being searched in the
82
+ # dictionary.
83
+ def word_search(params:)
84
+ word_results = params[:word_results]
85
+
86
+ # TODO: NOW: Should we be returning #word_valid? or #success?
87
+ return word_results.word_valid? if word_results.word_cached?
88
+
89
+ # If we get here, we know that the word is NOT in the dictionary either
90
+ # as a valid word OR as a cached, INVALID word.
91
+
92
+ # If caching is supposed to take place, cache the word as invalid
93
+ # (not found).
94
+ word = word_results.preprocessed_word_or_original_word
95
+ dictionary_words[word] = false if cache_word? word
96
+ false
97
+ end
98
+
99
+ def update(action, params)
100
+ unless actions_whitelist.include? action
101
+ raise ArgumentError,
102
+ "Argument action is not in the actions_whitelist: #{action}"
103
+ end
104
+
105
+ send(action, params: params)
106
+ self
107
+ end
108
+
109
+ def actions_whitelist
110
+ %i[init refresh word_search]
111
+ end
112
+
113
+ private
114
+
115
+ attr_accessor :dictionary_words
116
+ attr_writer :dictionary_metadata_object
117
+
118
+ def cache_word?(word)
119
+ return false unless metadata.cache_invalid_words?
120
+
121
+ if metadata.value >= (word.bytesize + metadata.current_invalid_word_bytesize)
122
+ metadata.current_invalid_word_bytesize += word.bytesize
123
+ true
124
+ else
125
+ false
126
+ end
127
+ end
128
+
129
+ def update_dictionary_metadata(value:)
130
+ dictionary_metadata_service.set_dictionary_metadata(value: value, metadata_key: metadata_key)
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LittleWeasel
4
+ module Metadata
5
+ # This class provides a container for the results of the
6
+ # InvalidWordsService service.
7
+ class InvalidWordsServiceResults
8
+ attr_accessor :current_invalid_word_bytesize
9
+ attr_reader :max_invalid_words_bytesize
10
+
11
+ def initialize(max_invalid_words_bytesize_on:,
12
+ current_invalid_word_bytesize:, max_invalid_words_bytesize:)
13
+
14
+ self.max_invalid_words_bytesize_on = max_invalid_words_bytesize_on
15
+ self.current_invalid_word_bytesize = current_invalid_word_bytesize
16
+ self.max_invalid_words_bytesize = max_invalid_words_bytesize
17
+ end
18
+
19
+ def on?
20
+ max_invalid_words_bytesize_on
21
+ end
22
+
23
+ def off?
24
+ !on?
25
+ end
26
+
27
+ def value
28
+ max_invalid_words_bytesize
29
+ end
30
+
31
+ def value_exceeded?
32
+ on? && current_invalid_word_bytesize > max_invalid_words_bytesize
33
+ end
34
+
35
+ def cache_invalid_words?
36
+ on? && !value_exceeded?
37
+ end
38
+
39
+ private
40
+
41
+ attr_accessor :max_invalid_words_bytesize_on
42
+ attr_writer :max_invalid_words_bytesize
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'metadata_observerable'
4
+
5
+ module LittleWeasel
6
+ module Metadata
7
+ # This module provides methods to validate MetadataObservable objects.
8
+ module MetadataObservableValidatable
9
+ # This method validates a single MetadataObserverable object.
10
+ def validate_metadata_observable(metadata_observable)
11
+ unless valid_metadata_observable? metadata_observable
12
+ raise 'Argument metadata_observable is not a ' \
13
+ "Metadata::MetadataObserverable object: #{metadata_observable.class}"
14
+ end
15
+ end
16
+
17
+ def valid_metadata_observable?(metadata_observable)
18
+ metadata_observable.is_a? Metadata::MetadataObserverable
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../errors/must_override_error'
4
+ require_relative 'metadatable'
5
+
6
+ module LittleWeasel
7
+ module Metadata
8
+ # Defines methods to support metadata modules that are observers of
9
+ # objects that include Metadata::DictionaryMetadata.
10
+ module MetadataObserverable
11
+ include Metadatable
12
+
13
+ def self.included(base)
14
+ base.extend ClassMethods
15
+ end
16
+
17
+ # class method inclusions for convenience.
18
+ module ClassMethods
19
+ # If the medatata observer is not in a state to observe, or is turned
20
+ # "off", return false; otherwise, return true...
21
+ #
22
+ # Configuration option settings may turn a metadata observer "off";
23
+ # for example, InvalidWordsMedata will not be observable unless
24
+ # LittleWeasel.configuration.max_invalid_words_bytesize? returns true.
25
+ #
26
+ # Other variables may also determine whether or not a metadata object is
27
+ # capable of observing; consequently, an instance-level #observe? method
28
+ # is also availble if this is the case (see below).
29
+ #
30
+ # If the observable state of your metadata object depends on
31
+ # configuration settings ALONE, return true/false using this class-level
32
+ # method, and do not override the instance-level #observe? method.
33
+ #
34
+ # If the observable state of your metadata object can only be determined
35
+ # AFTER the metadata object is instantiated: return true from the the
36
+ # class-level .observe? method; then, override the instance-level
37
+ # #observe? method and return true/false accordingly.
38
+ #
39
+ # If the observable state of your metadata object is determined by BOTH
40
+ # configuration settings AND variables that can only be determined AFTER
41
+ # the metadata object has been instantiated, use both the class-level
42
+ # and instance-level observe? to return true/false accordingly.
43
+ def observe?
44
+ false
45
+ end
46
+ end
47
+
48
+ # Return true/false depending on whether or not this metadata observer
49
+ # is in a state to observe.
50
+ #
51
+ # (See .observe? class-level method comments)
52
+ def observe?
53
+ self.class.observe?
54
+ end
55
+
56
+ # This is an override of Metadata#refresh_local_metadata. See
57
+ # Metadata#refresh_local_metadata comments.
58
+ def refresh_local_metadata
59
+ @metadata = dictionary_metadata_service.get_dictionary_metadata(metadata_key: metadata_key)
60
+ end
61
+
62
+ # This method receives notifications from an observable.
63
+ # object and should be chainable (return self).
64
+ # All actions should be filtered through the
65
+ # actions_whitelist and an error raised if action
66
+ # is not in the actions_whitelist. If **args are used,
67
+ # further filtering should be applied based on the
68
+ # need.
69
+ #
70
+ # @example
71
+ #
72
+ # def update(action, **args)
73
+ # raise ArgumentError unless actions_whitelist.include? action
74
+ #
75
+ # send(action)
76
+ # self
77
+ # end
78
+ def update(_action, **_args)
79
+ raise Errors::MustOverrideError
80
+ end
81
+
82
+ # This method should return actions (messages) that can be sent
83
+ # to this object; for example, at a minimum :init and :refresh
84
+ # need to be in this list
85
+ def actions_whitelist
86
+ %i[init refresh]
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../errors/must_override_error'
4
+ require_relative '../services/dictionary_cache_service'
5
+
6
+ module LittleWeasel
7
+ module Metadata
8
+ # This module defines methods to support objects that manage other objects
9
+ # that manage metadata related to a dictionary/ies.
10
+ module Metadatable
11
+ def self.included(base)
12
+ base.extend ClassMethods
13
+ end
14
+
15
+ # class method inclusions for convenience.
16
+ module ClassMethods
17
+ # Override this method to return the metadata key associated with this
18
+ # metadata object in the dictionary cache.
19
+ def metadata_key
20
+ to_sym
21
+ end
22
+ end
23
+
24
+ def metadata_key
25
+ self.class.metadata_key
26
+ end
27
+
28
+ # This method should UNCONDITIONALLY update the local metadata, using the
29
+ # metadata_key and notify all observers (if any) to initialize themselves
30
+ # as well.
31
+ #
32
+ # This method should be chainable (return self).
33
+ #
34
+ # @example
35
+ #
36
+ # . # Example of a root-level dictionary metadata object (e.g.
37
+ # . # Metadata::DictionaryMetadata)
38
+ # def init(_params: nil)
39
+ # self.metadata = {}
40
+ # notify action: :init
41
+ # refresh_local_metadata
42
+ # unless count_observers.zero? || metadata.present?
43
+ # raise 'Observers were called to #init but the dictionary cache metadata was not initialized'
44
+ # end
45
+ #
46
+ # self
47
+ # end
48
+ #
49
+ # . # Example of a metadata observable object (e.g.
50
+ # . # Metadata::InvalidWords::InvalidWordsMetadata)
51
+ # def init(params: nil)
52
+ # self.metadata = Services::InvalidWordsService.new(dictionary_words).execute
53
+ # self
54
+ # end
55
+ #
56
+ # rubocop: disable Lint/UnusedMethodArgument
57
+ def init(params: nil)
58
+ raise Errors::MustOverrideError
59
+ end
60
+ # rubocop: enable Lint/UnusedMethodArgument
61
+
62
+ # This method should refresh the local metadata from the dictionary cache,
63
+ # if metadata exists in the dictionary cache for the given metatata_key.
64
+ # Otherwise, #init should be called to initialize this object.
65
+ # The idea is that metadata should be shared across metadata objects of
66
+ # the same type that use the same metadata_key.
67
+ #
68
+ # This method should be chainable (return self).
69
+ #
70
+ # @example
71
+ #
72
+ # def refresh(params: nil)
73
+ # refresh_local_metadata
74
+ # init unless metadata.present?
75
+ # self
76
+ # end
77
+ # rubocop: disable Lint/UnusedMethodArgument
78
+ def refresh(params: nil)
79
+ raise Errors::MustOverrideError
80
+ end
81
+ # rubocop: enable Lint/UnusedMethodArgument
82
+
83
+ private
84
+
85
+ attr_reader :metadata
86
+
87
+ # This method should set the metadata in the dictionary cache, using the
88
+ # appropriate metadata key for this object (or nil if the root metadata
89
+ # object) AND set the @metadata local attribute so that a local copy is
90
+ # available for use.
91
+ #
92
+ # When instantiating this object, #init (see #init comments). If an
93
+ # updated copy of the metadata is needed #refresh (see comments) should
94
+ # be called.
95
+ #
96
+ # @example
97
+ #
98
+ # def metadata=(value)
99
+ # dictionary_cache_service = LittleWeasel::Services::DictionaryCacheService.new(
100
+ # dictionary_key: dictionary_key, dictionary_cache: dictionary_cache)
101
+ # dictionary_cache_service.dictionary_metadata_set(
102
+ # metadata_key: METADATA_KEY, value: value)
103
+ # @metadata = value
104
+ # end
105
+ def metadata=(value)
106
+ @metadata = value
107
+ update_dictionary_metadata value: value
108
+ end
109
+
110
+ # This method updates the local metadata ONLY. Use this method if you
111
+ # need to update the local metadata from the dictionary cache metadata.
112
+ #
113
+ # Override this method in metadata observable classes as needed.
114
+ def refresh_local_metadata
115
+ @metadata = dictionary_metadata_service.dictionary_metadata
116
+ end
117
+
118
+ # This method should update the dictionary metadata for the the object
119
+ # when it is called.
120
+ #
121
+ # @example
122
+ #
123
+ # def update_dictionary_metadata(value:)
124
+ # dictionary_cache_service = LittleWeasel::Services::DictionaryCacheService.new(
125
+ # dictionary_key: dictionary_key, dictionary_cache: dictionary_cache)
126
+ # dictionary_cache_service.dictionary_metadata_set(
127
+ # metadata_key: metadata_key, value: value)
128
+ # end
129
+ # rubocop: disable Lint/UnusedMethodArgument
130
+ def update_dictionary_metadata(value:)
131
+ raise Errors::MustOverrideError
132
+ end
133
+ # rubocop: enable Lint/UnusedMethodArgument
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/inflector'
4
+
5
+ module LittleWeasel
6
+ module Modules
7
+ # This module provides methods to convert the class name of the class
8
+ # mixing this module in to snake-case.
9
+ module ClassNameToSymbol
10
+ def self.included(base)
11
+ base.extend(ClassMethods)
12
+ end
13
+
14
+ # class method inclusions for convenience.
15
+ module ClassMethods
16
+ def to_sym
17
+ name.demodulize.underscore.to_sym
18
+ end
19
+ end
20
+
21
+ def to_sym
22
+ self.class.to_sym
23
+ end
24
+ end
25
+ end
26
+ end