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,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Errors
|
|
5
|
+
# This class describes an error when a the dictionary file is too large.
|
|
6
|
+
class DictionaryFileTooLargeError < StandardError
|
|
7
|
+
def initialize(msg: nil)
|
|
8
|
+
unless msg.present?
|
|
9
|
+
msg = 'The dictionary file size is larger than ' \
|
|
10
|
+
"max_dictionary_file_megabytes: #{LittleWeasel.configuration.max_dictionary_file_megabytes}"
|
|
11
|
+
end
|
|
12
|
+
super msg
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../errors/must_override_error'
|
|
4
|
+
require_relative '../word_filter'
|
|
5
|
+
|
|
6
|
+
module LittleWeasel
|
|
7
|
+
module Filters
|
|
8
|
+
module EnUs
|
|
9
|
+
# This class represents a currency filter.
|
|
10
|
+
class CurrencyFilter < WordFilter
|
|
11
|
+
class << self
|
|
12
|
+
def filter_match?(word)
|
|
13
|
+
/^[-+]?\$[[:digit:]]{1,3}(?:,?[[:digit:]]{3})*(?:\.[[:digit:]]{2})?$/.match? word.to_s
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../errors/must_override_error'
|
|
4
|
+
require_relative '../word_filter'
|
|
5
|
+
|
|
6
|
+
module LittleWeasel
|
|
7
|
+
module Filters
|
|
8
|
+
module EnUs
|
|
9
|
+
# This class represents a numeric filter.
|
|
10
|
+
class NumericFilter < WordFilter
|
|
11
|
+
class << self
|
|
12
|
+
def filter_match?(word)
|
|
13
|
+
/^[-+]?[[:digit:]]{1,3}(?:,?[[:digit:]]{3})*(?:\.[[:digit:]]{1,2})?$/.match? word.to_s
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../errors/must_override_error'
|
|
4
|
+
require_relative '../word_filter'
|
|
5
|
+
|
|
6
|
+
module LittleWeasel
|
|
7
|
+
module Filters
|
|
8
|
+
module EnUs
|
|
9
|
+
# This class represents a filter for single character words.
|
|
10
|
+
class SingleCharacterWordFilter < WordFilter
|
|
11
|
+
class << self
|
|
12
|
+
def filter_match?(word)
|
|
13
|
+
return false unless word.is_a? String
|
|
14
|
+
|
|
15
|
+
/^[aAI]{1}$/.match? word.to_s
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../errors/must_override_error'
|
|
4
|
+
require_relative '../modules/class_name_to_symbol'
|
|
5
|
+
|
|
6
|
+
module LittleWeasel
|
|
7
|
+
module Filters
|
|
8
|
+
# This module provides methods/functionality for filtering dictionary words.
|
|
9
|
+
class WordFilter
|
|
10
|
+
include Modules::ClassNameToSymbol
|
|
11
|
+
|
|
12
|
+
attr_reader :filter_on
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
filter_on!
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
# Should return true if this word matches the filter criteria; false,
|
|
20
|
+
# otherwise. This class method is unlike the instance method in that it
|
|
21
|
+
# does not consider whether or not this filter is "on" or "off"; it
|
|
22
|
+
# simply returns true or false based on whether or not the word matches
|
|
23
|
+
# the filter.
|
|
24
|
+
def filter_match?(_word)
|
|
25
|
+
raise Errors::MustOverrideError
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def filter_on=(value)
|
|
30
|
+
raise ArgumentError, "Argument value is not true or false: #{value.class}" \
|
|
31
|
+
unless [true, false].include? value
|
|
32
|
+
|
|
33
|
+
@filter_on = value
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def filter_match?(word)
|
|
37
|
+
return false if filter_off?
|
|
38
|
+
|
|
39
|
+
self.class.filter_match? word
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def filter_on!
|
|
43
|
+
self.filter_on = true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def filter_off!
|
|
47
|
+
self.filter_on = false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def filter_on?
|
|
51
|
+
filter_on
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def filter_off?
|
|
55
|
+
!filter_on?
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'word_filterable'
|
|
4
|
+
require_relative 'word_filters_validatable'
|
|
5
|
+
|
|
6
|
+
module LittleWeasel
|
|
7
|
+
module Filters
|
|
8
|
+
# This module provides methods/functionality to manage word filters.
|
|
9
|
+
# Word fliters are processes through which words are passed; if the
|
|
10
|
+
# process returns true, the word should be considered valid and all
|
|
11
|
+
# subsequent filters ignored; if the process returns false, the word
|
|
12
|
+
# should be passed to the next filter, and so on. When using word
|
|
13
|
+
# filters, you need to consider whether or not metadata observers
|
|
14
|
+
# should be notified of the word now that it is considered "valid"
|
|
15
|
+
# although may not literally be a valid word in the dictionary.
|
|
16
|
+
module WordFilterManagable
|
|
17
|
+
include WordFilterable
|
|
18
|
+
include WordFiltersValidatable
|
|
19
|
+
|
|
20
|
+
# Override attr_reader word_filter found in WordFilterable
|
|
21
|
+
# so that we don't raise nil errors when using word_filters.
|
|
22
|
+
def word_filters
|
|
23
|
+
@word_filters ||= []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def clear_filters
|
|
27
|
+
self.word_filters = []
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Appends word filters to the #word_filters Array.
|
|
31
|
+
#
|
|
32
|
+
# If Argument word_filter is nil, a block must be passed to populate
|
|
33
|
+
# the word_filters with an Array of valid word filter objects.
|
|
34
|
+
#
|
|
35
|
+
# This method is used for adding/appending word filters to the
|
|
36
|
+
# word_filters Array. To replace word filters, use #replace_filters;
|
|
37
|
+
# to perform any other manipulation of the word_filters Array,
|
|
38
|
+
# use #word_filters directly.
|
|
39
|
+
def add_filters(word_filters: nil)
|
|
40
|
+
return if word_filters.is_a?(Array) && word_filters.blank?
|
|
41
|
+
|
|
42
|
+
raise 'A block is required if argument word_filters is nil' if word_filters.nil? && !block_given?
|
|
43
|
+
|
|
44
|
+
word_filters ||= []
|
|
45
|
+
yield word_filters if block_given?
|
|
46
|
+
|
|
47
|
+
validate_word_filters word_filters: word_filters
|
|
48
|
+
|
|
49
|
+
self.word_filters.concat word_filters
|
|
50
|
+
end
|
|
51
|
+
alias append_filters add_filters
|
|
52
|
+
|
|
53
|
+
def replace_filters(word_filters:)
|
|
54
|
+
clear_filters
|
|
55
|
+
add_filters word_filters: word_filters
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def filters_on=(on)
|
|
59
|
+
raise ArgumentError, "Argument on is not true or false: #{on.class}" unless [true, false].include?(on)
|
|
60
|
+
|
|
61
|
+
word_filters.each { |word_filter| word_filter.filter_on = on }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def filters_matched(word)
|
|
65
|
+
raise ArgumentError, "Argument word is not a String: #{word.class}" unless word.is_a? String
|
|
66
|
+
|
|
67
|
+
return [] if word_filters.blank?
|
|
68
|
+
return [] if word.empty?
|
|
69
|
+
|
|
70
|
+
word_filters.filter_map do |word_filter|
|
|
71
|
+
word_filter.to_sym if word_filter.filter_match?(word)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def filter_match?(word)
|
|
76
|
+
filters_matched(word).present?
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Filters
|
|
5
|
+
# This module validates word filter types.
|
|
6
|
+
module WordFilterValidatable
|
|
7
|
+
def self.validate(word_filter:)
|
|
8
|
+
raise ArgumentError, "Argument word_filter does not quack right: #{word_filter.class}" \
|
|
9
|
+
unless valid_word_filter?(word_filter: word_filter)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# You can use your own word filter types as long as they quack correctly;
|
|
13
|
+
# however, you are responsible for the behavior of these required methods/
|
|
14
|
+
# attributes. It's probably better to follow the pattern of existing word
|
|
15
|
+
# filter objects (e.g. Filters::EnUs::NumericFilter) and inherit from
|
|
16
|
+
# Filters::WordFilter.
|
|
17
|
+
def self.valid_word_filter?(word_filter:)
|
|
18
|
+
word_filter.respond_to?(:filter_on?) &&
|
|
19
|
+
word_filter.respond_to?(:filter_off?) &&
|
|
20
|
+
word_filter.respond_to?(:filter_on) &&
|
|
21
|
+
word_filter.respond_to?(:filter_on=) &&
|
|
22
|
+
word_filter.respond_to?(:filter_match?) &&
|
|
23
|
+
word_filter.class.respond_to?(:filter_match?)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def validate_word_filter(word_filter:)
|
|
27
|
+
WordFilterValidatable.validate word_filter: word_filter
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'word_filters_validatable'
|
|
4
|
+
|
|
5
|
+
module LittleWeasel
|
|
6
|
+
module Filters
|
|
7
|
+
# This module provides the word_filters attribute for objects that support
|
|
8
|
+
# word filters.
|
|
9
|
+
module WordFilterable
|
|
10
|
+
@word_filters = []
|
|
11
|
+
|
|
12
|
+
attr_reader :word_filters
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
attr_writer :word_filters
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'word_filter_validatable'
|
|
4
|
+
|
|
5
|
+
module LittleWeasel
|
|
6
|
+
module Filters
|
|
7
|
+
# This module provides methods to validate an Array of word filters.
|
|
8
|
+
module WordFiltersValidatable
|
|
9
|
+
extend WordFilterValidatable
|
|
10
|
+
|
|
11
|
+
def self.validate(word_filters:)
|
|
12
|
+
return if word_filters.blank?
|
|
13
|
+
|
|
14
|
+
unless word_filters.is_a? Array
|
|
15
|
+
raise ArgumentError,
|
|
16
|
+
"Argument word_filters is not an Array: #{word_filters.class}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
word_filters.each do |word_filter|
|
|
20
|
+
validate_word_filter word_filter: word_filter
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def validate_word_filters(word_filters:)
|
|
25
|
+
WordFiltersValidatable.validate word_filters: word_filters
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/module/delegation'
|
|
4
|
+
require 'observer'
|
|
5
|
+
require_relative '../modules/class_name_to_symbol'
|
|
6
|
+
require_relative '../modules/configurable'
|
|
7
|
+
require_relative '../modules/dictionary_cache_keys'
|
|
8
|
+
require_relative '../modules/dictionary_cache_servicable'
|
|
9
|
+
require_relative '../modules/dictionary_metadata_servicable'
|
|
10
|
+
require_relative 'metadata_observable_validatable'
|
|
11
|
+
require_relative 'metadatable'
|
|
12
|
+
|
|
13
|
+
module LittleWeasel
|
|
14
|
+
module Metadata
|
|
15
|
+
# This class manages metadata objects related to dictionaries. Metadata
|
|
16
|
+
# objects defined in LittleWeasel::Configuration#metadata_observers are
|
|
17
|
+
# added as observers, provided they are in a state to observe
|
|
18
|
+
# (see Metadata::Metadatable, Metadata::InvalidWords::InvalidWordsMetadata,
|
|
19
|
+
# etc.).
|
|
20
|
+
class DictionaryMetadata
|
|
21
|
+
include Observable
|
|
22
|
+
include Metadata::Metadatable
|
|
23
|
+
include Metadata::MetadataObservableValidatable
|
|
24
|
+
include Modules::ClassNameToSymbol
|
|
25
|
+
include Modules::Configurable
|
|
26
|
+
include Modules::DictionaryCacheKeys
|
|
27
|
+
include Modules::DictionaryCacheServicable
|
|
28
|
+
include Modules::DictionaryMetadataServicable
|
|
29
|
+
|
|
30
|
+
delegate :[], to: :observers
|
|
31
|
+
|
|
32
|
+
attr_reader :dictionary_words, :observers
|
|
33
|
+
|
|
34
|
+
def initialize(dictionary_words:, dictionary_key:, dictionary_cache:, dictionary_metadata:)
|
|
35
|
+
validate_dictionary_key dictionary_key: dictionary_key
|
|
36
|
+
self.dictionary_key = dictionary_key
|
|
37
|
+
|
|
38
|
+
validate_dictionary_cache dictionary_cache: dictionary_cache
|
|
39
|
+
self.dictionary_cache = dictionary_cache
|
|
40
|
+
|
|
41
|
+
validate_dictionary_metadata dictionary_metadata: dictionary_metadata
|
|
42
|
+
self.dictionary_metadata = dictionary_metadata
|
|
43
|
+
|
|
44
|
+
unless dictionary_words.is_a? Hash
|
|
45
|
+
raise ArgumentError,
|
|
46
|
+
"Argument dictionary_words is not a Hash: #{dictionary_words.class.name}."
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
self.dictionary_words = dictionary_words
|
|
50
|
+
self.observers = {}
|
|
51
|
+
|
|
52
|
+
refresh
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def init(_params: nil)
|
|
56
|
+
dictionary_metadata_service.init(metadata_key: metadata_key)
|
|
57
|
+
self.metadata = {}
|
|
58
|
+
notify action: :init
|
|
59
|
+
refresh_local_metadata
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def refresh(_params: nil)
|
|
64
|
+
refresh_local_metadata
|
|
65
|
+
if metadata.present?
|
|
66
|
+
# If there is metadata in the dictionary cache, notify the observers
|
|
67
|
+
# to use it...
|
|
68
|
+
notify action: :refresh
|
|
69
|
+
else
|
|
70
|
+
# ...otherwise, notify the observers to initialize themselves.
|
|
71
|
+
init
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def notify(action:, params: nil)
|
|
76
|
+
if count_observers.positive?
|
|
77
|
+
changed
|
|
78
|
+
notify_observers action, params
|
|
79
|
+
end
|
|
80
|
+
self
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def add_observers(force: false)
|
|
84
|
+
delete_observers if force
|
|
85
|
+
|
|
86
|
+
raise 'Observers have already been added; use #add_observers(force: true) instead' if count_observers.positive?
|
|
87
|
+
|
|
88
|
+
observer_classes = config.metadata_observers
|
|
89
|
+
yield observer_classes if block_given?
|
|
90
|
+
|
|
91
|
+
observer_classes.each do |o|
|
|
92
|
+
# If the medatata observer is not in a state to observe,
|
|
93
|
+
# or is turned "off", skip it...
|
|
94
|
+
#
|
|
95
|
+
# See Metadata::MetadataObserverable.observe? comments.
|
|
96
|
+
next unless o.observe?
|
|
97
|
+
|
|
98
|
+
# If this observer has already beed added, don't add it again.
|
|
99
|
+
next if observers.key? o.metadata_key
|
|
100
|
+
|
|
101
|
+
observer = o.new(dictionary_metadata_object: self,
|
|
102
|
+
dictionary_words: dictionary_words,
|
|
103
|
+
dictionary_key: dictionary_key,
|
|
104
|
+
dictionary_cache: dictionary_cache,
|
|
105
|
+
dictionary_metadata: dictionary_metadata)
|
|
106
|
+
|
|
107
|
+
# Only add metadata objects that are capable of observing
|
|
108
|
+
# (i.e. #observe?).
|
|
109
|
+
add_observer observer if observer.observe?
|
|
110
|
+
end
|
|
111
|
+
# This is how each metadata object gets initialized. Only notify if
|
|
112
|
+
# there are any observers.
|
|
113
|
+
notify(action: :init) if count_observers.positive?
|
|
114
|
+
self
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def add_observer(observer, func = :update)
|
|
118
|
+
validate_metadata_observable observer
|
|
119
|
+
|
|
120
|
+
super
|
|
121
|
+
observers[observer.metadata_key] = observer
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def delete_observer(observer)
|
|
125
|
+
validate_metadata_observable observer
|
|
126
|
+
|
|
127
|
+
super
|
|
128
|
+
observers.delete(observer.metadata_key)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def delete_observers
|
|
132
|
+
super
|
|
133
|
+
self.observers = {}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
attr_writer :dictionary_words, :observers
|
|
139
|
+
|
|
140
|
+
def update_dictionary_metadata(value:)
|
|
141
|
+
dictionary_metadata_service.set_dictionary_metadata(value: value, metadata_key: metadata_key)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|