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.
- checksums.yaml +5 -5
- data/.gitignore +3 -0
- data/.reek.yml +17 -0
- data/.rspec +4 -2
- data/.rubocop.yml +187 -0
- data/.ruby-version +1 -1
- data/.yardopts +2 -0
- data/Gemfile +3 -1
- data/LittleWeasel.gemspec +31 -18
- data/README.md +408 -42
- data/Rakefile +296 -3
- data/lib/LittleWeasel.rb +5 -184
- data/lib/LittleWeasel/block_results.rb +81 -0
- data/lib/LittleWeasel/configure.rb +98 -0
- data/lib/LittleWeasel/dictionary.rb +125 -0
- data/lib/LittleWeasel/dictionary_key.rb +48 -0
- data/lib/LittleWeasel/dictionary_manager.rb +85 -0
- data/lib/LittleWeasel/errors/dictionary_file_already_loaded_error.rb +9 -0
- data/lib/LittleWeasel/errors/dictionary_file_empty_error.rb +8 -0
- data/lib/LittleWeasel/errors/dictionary_file_not_found_error.rb +8 -0
- data/lib/LittleWeasel/errors/dictionary_file_too_large_error.rb +16 -0
- data/lib/LittleWeasel/errors/language_required_error.rb +8 -0
- data/lib/LittleWeasel/errors/must_override_error.rb +8 -0
- data/lib/LittleWeasel/filters/en_us/currency_filter.rb +19 -0
- data/lib/LittleWeasel/filters/en_us/numeric_filter.rb +19 -0
- data/lib/LittleWeasel/filters/en_us/single_character_word_filter.rb +21 -0
- data/lib/LittleWeasel/filters/word_filter.rb +59 -0
- data/lib/LittleWeasel/filters/word_filter_managable.rb +80 -0
- data/lib/LittleWeasel/filters/word_filter_validatable.rb +31 -0
- data/lib/LittleWeasel/filters/word_filterable.rb +19 -0
- data/lib/LittleWeasel/filters/word_filters_validatable.rb +29 -0
- data/lib/LittleWeasel/metadata/dictionary_metadata.rb +145 -0
- data/lib/LittleWeasel/metadata/invalid_words_metadata.rb +134 -0
- data/lib/LittleWeasel/metadata/invalid_words_service_results.rb +45 -0
- data/lib/LittleWeasel/metadata/metadata_observable_validatable.rb +22 -0
- data/lib/LittleWeasel/metadata/metadata_observerable.rb +90 -0
- data/lib/LittleWeasel/metadata/metadatable.rb +136 -0
- data/lib/LittleWeasel/modules/class_name_to_symbol.rb +26 -0
- data/lib/LittleWeasel/modules/configurable.rb +26 -0
- data/lib/LittleWeasel/modules/deep_dup.rb +11 -0
- data/lib/LittleWeasel/modules/dictionary_cache_keys.rb +34 -0
- data/lib/LittleWeasel/modules/dictionary_cache_servicable.rb +26 -0
- data/lib/LittleWeasel/modules/dictionary_cache_validatable.rb +20 -0
- data/lib/LittleWeasel/modules/dictionary_creator_servicable.rb +27 -0
- data/lib/LittleWeasel/modules/dictionary_file_loader.rb +67 -0
- data/lib/LittleWeasel/modules/dictionary_key_validatable.rb +19 -0
- data/lib/LittleWeasel/modules/dictionary_keyable.rb +24 -0
- data/lib/LittleWeasel/modules/dictionary_loader_servicable.rb +27 -0
- data/lib/LittleWeasel/modules/dictionary_metadata_servicable.rb +29 -0
- data/lib/LittleWeasel/modules/dictionary_metadata_validatable.rb +17 -0
- data/lib/LittleWeasel/modules/dictionary_sourceable.rb +26 -0
- data/lib/LittleWeasel/modules/dictionary_validatable.rb +30 -0
- data/lib/LittleWeasel/modules/language.rb +23 -0
- data/lib/LittleWeasel/modules/language_validatable.rb +16 -0
- data/lib/LittleWeasel/modules/locale.rb +40 -0
- data/lib/LittleWeasel/modules/order_validatable.rb +18 -0
- data/lib/LittleWeasel/modules/orderable.rb +17 -0
- data/lib/LittleWeasel/modules/region.rb +23 -0
- data/lib/LittleWeasel/modules/region_validatable.rb +16 -0
- data/lib/LittleWeasel/modules/tag_validatable.rb +16 -0
- data/lib/LittleWeasel/modules/taggable.rb +31 -0
- data/lib/LittleWeasel/modules/word_results_validatable.rb +28 -0
- data/lib/LittleWeasel/preprocessors/en_us/capitalize_preprocessor.rb +22 -0
- data/lib/LittleWeasel/preprocessors/preprocessed_word.rb +28 -0
- data/lib/LittleWeasel/preprocessors/preprocessed_word_validatable.rb +55 -0
- data/lib/LittleWeasel/preprocessors/preprocessed_words.rb +55 -0
- data/lib/LittleWeasel/preprocessors/preprocessed_words_validatable.rb +27 -0
- data/lib/LittleWeasel/preprocessors/word_preprocessable.rb +19 -0
- data/lib/LittleWeasel/preprocessors/word_preprocessor.rb +122 -0
- data/lib/LittleWeasel/preprocessors/word_preprocessor_managable.rb +114 -0
- data/lib/LittleWeasel/preprocessors/word_preprocessor_validatable.rb +40 -0
- data/lib/LittleWeasel/preprocessors/word_preprocessors_validatable.rb +24 -0
- data/lib/LittleWeasel/services/dictionary_cache_service.rb +262 -0
- data/lib/LittleWeasel/services/dictionary_creator_service.rb +94 -0
- data/lib/LittleWeasel/services/dictionary_file_loader_service.rb +37 -0
- data/lib/LittleWeasel/services/dictionary_killer_service.rb +35 -0
- data/lib/LittleWeasel/services/dictionary_loader_service.rb +59 -0
- data/lib/LittleWeasel/services/dictionary_metadata_service.rb +114 -0
- data/lib/LittleWeasel/services/invalid_words_service.rb +59 -0
- data/lib/LittleWeasel/version.rb +3 -1
- data/lib/LittleWeasel/word_results.rb +146 -0
- data/spec/factories/dictionary.rb +43 -0
- data/spec/factories/dictionary_cache_service.rb +95 -0
- data/spec/factories/dictionary_creator_service.rb +16 -0
- data/spec/factories/dictionary_file_loader_service.rb +13 -0
- data/spec/factories/dictionary_hash.rb +39 -0
- data/spec/factories/dictionary_key.rb +14 -0
- data/spec/factories/dictionary_killer_service.rb +14 -0
- data/spec/factories/dictionary_loader_service.rb +14 -0
- data/spec/factories/dictionary_manager.rb +10 -0
- data/spec/factories/dictionary_metadata.rb +16 -0
- data/spec/factories/dictionary_metadata_service.rb +16 -0
- data/spec/factories/numeric_filter.rb +12 -0
- data/spec/factories/preprocessed_word.rb +16 -0
- data/spec/factories/preprocessed_words.rb +41 -0
- data/spec/factories/single_character_word_filter.rb +12 -0
- data/spec/factories/word_results.rb +16 -0
- data/spec/lib/LittleWeasel/block_results_spec.rb +248 -0
- data/spec/lib/LittleWeasel/configure_spec.rb +74 -0
- data/spec/lib/LittleWeasel/dictionary_key_spec.rb +118 -0
- data/spec/lib/LittleWeasel/dictionary_manager_spec.rb +116 -0
- data/spec/lib/LittleWeasel/dictionary_spec.rb +289 -0
- data/spec/lib/LittleWeasel/filters/en_us/currency_filter_spec.rb +80 -0
- data/spec/lib/LittleWeasel/filters/en_us/numeric_filter_spec.rb +66 -0
- data/spec/lib/LittleWeasel/filters/en_us/single_character_word_filter_spec.rb +58 -0
- data/spec/lib/LittleWeasel/filters/word_filter_managable_spec.rb +180 -0
- data/spec/lib/LittleWeasel/filters/word_filter_spec.rb +151 -0
- data/spec/lib/LittleWeasel/filters/word_filter_validatable_spec.rb +94 -0
- data/spec/lib/LittleWeasel/filters/word_filters_validatable_spec.rb +48 -0
- data/spec/lib/LittleWeasel/integraton_tests/dictionary_integration_spec.rb +201 -0
- data/spec/lib/LittleWeasel/metadata/dictionary_creator_servicable_spec.rb +54 -0
- data/spec/lib/LittleWeasel/metadata/dictionary_metadata_spec.rb +209 -0
- data/spec/lib/LittleWeasel/metadata/invalid_words_metadata_spec.rb +155 -0
- data/spec/lib/LittleWeasel/metadata/metadata_observerable_spec.rb +31 -0
- data/spec/lib/LittleWeasel/metadata/metadatable_spec.rb +35 -0
- data/spec/lib/LittleWeasel/modules/class_name_to_symbol_spec.rb +21 -0
- data/spec/lib/LittleWeasel/modules/dictionary_file_loader_spec.rb +125 -0
- data/spec/lib/LittleWeasel/modules/dictionary_sourceable_spec.rb +44 -0
- data/spec/lib/LittleWeasel/modules/language_spec.rb +52 -0
- data/spec/lib/LittleWeasel/modules/locale_spec.rb +140 -0
- data/spec/lib/LittleWeasel/modules/region_spec.rb +52 -0
- data/spec/lib/LittleWeasel/preprocessors/en_us/capitalize_preprocessor_spec.rb +34 -0
- data/spec/lib/LittleWeasel/preprocessors/preprocessed_word_spec.rb +105 -0
- data/spec/lib/LittleWeasel/preprocessors/preprocessed_word_validatable_spec.rb +143 -0
- data/spec/lib/LittleWeasel/preprocessors/preprocessed_words_spec.rb +77 -0
- data/spec/lib/LittleWeasel/preprocessors/preprocessed_words_validatable_spec.rb +58 -0
- data/spec/lib/LittleWeasel/preprocessors/word_preprocessor_managable_spec.rb +216 -0
- data/spec/lib/LittleWeasel/preprocessors/word_preprocessor_spec.rb +175 -0
- data/spec/lib/LittleWeasel/preprocessors/word_preprocessor_validatable_spec.rb +109 -0
- data/spec/lib/LittleWeasel/preprocessors/word_preprocessors_validatable_spec.rb +49 -0
- data/spec/lib/LittleWeasel/services/dictionary_cache_service_spec.rb +444 -0
- data/spec/lib/LittleWeasel/services/dictionary_creator_service_spec.rb +119 -0
- data/spec/lib/LittleWeasel/services/dictionary_file_loader_service_spec.rb +71 -0
- data/spec/lib/LittleWeasel/services/dictionary_loader_service_spec.rb +50 -0
- data/spec/lib/LittleWeasel/services/dictionary_metadata_service_spec.rb +279 -0
- data/spec/lib/LittleWeasel/word_results_spec.rb +275 -0
- data/spec/lib/LittleWeasel/workflow/workflow_spec.rb +20 -0
- data/spec/spec_helper.rb +117 -6
- data/spec/support/factory_bot.rb +15 -0
- data/spec/support/file_helpers.rb +32 -0
- data/spec/support/files/empty-dictionary.txt +0 -0
- data/{lib/dictionary → spec/support/files/en-US-big.txt} +262156 -31488
- data/spec/support/files/en-US-tagged.txt +26 -0
- data/spec/support/files/en-US.txt +26 -0
- data/spec/support/files/en.txt +26 -0
- data/spec/support/files/es-ES.txt +27 -0
- data/spec/support/files/es.txt +27 -0
- data/spec/support/general_helpers.rb +68 -0
- data/spec/support/shared_contexts.rb +108 -0
- data/spec/support/shared_examples.rb +105 -0
- metadata +408 -65
- 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
|