LittleWeasel 3.0.3 → 5.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/CHANGELOG.md +22 -1
- data/Gemfile +3 -1
- data/Jenkinsfile +20 -0
- data/LittleWeasel.gemspec +31 -18
- data/README.md +408 -42
- data/Rakefile +296 -3
- 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 +91 -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 +134 -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 +18 -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 +17 -0
- data/lib/LittleWeasel/modules/dictionary_keyable.rb +24 -0
- data/lib/LittleWeasel/modules/dictionary_metadata_servicable.rb +29 -0
- data/lib/LittleWeasel/modules/dictionary_metadata_validatable.rb +15 -0
- data/lib/LittleWeasel/modules/dictionary_source_validatable.rb +15 -0
- data/lib/LittleWeasel/modules/dictionary_sourceable.rb +86 -0
- data/lib/LittleWeasel/modules/dictionary_validatable.rb +18 -0
- data/lib/LittleWeasel/modules/language.rb +24 -0
- data/lib/LittleWeasel/modules/language_validatable.rb +14 -0
- data/lib/LittleWeasel/modules/locale.rb +23 -0
- data/lib/LittleWeasel/modules/order_validatable.rb +16 -0
- data/lib/LittleWeasel/modules/orderable.rb +17 -0
- data/lib/LittleWeasel/modules/region.rb +24 -0
- data/lib/LittleWeasel/modules/region_validatable.rb +14 -0
- data/lib/LittleWeasel/modules/tag_validatable.rb +14 -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 +29 -0
- data/lib/LittleWeasel/preprocessors/preprocessed_word_validatable.rb +56 -0
- data/lib/LittleWeasel/preprocessors/preprocessed_words.rb +59 -0
- data/lib/LittleWeasel/preprocessors/preprocessed_words_validatable.rb +28 -0
- data/lib/LittleWeasel/preprocessors/word_preprocessable.rb +19 -0
- data/lib/LittleWeasel/preprocessors/word_preprocessor.rb +123 -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 +211 -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_metadata_service.rb +116 -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/lib/LittleWeasel.rb +5 -184
- 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_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 +166 -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 +81 -0
- data/spec/lib/LittleWeasel/modules/language_spec.rb +112 -0
- data/spec/lib/LittleWeasel/modules/locale_spec.rb +95 -0
- data/spec/lib/LittleWeasel/modules/region_spec.rb +112 -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 +242 -0
- data/spec/lib/LittleWeasel/preprocessors/word_preprocessor_spec.rb +218 -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_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 +46 -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 +107 -0
- data/spec/support/shared_examples.rb +105 -0
- metadata +378 -38
- data/spec/checker/checker_spec.rb +0 -286
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/module/delegation'
|
|
4
|
+
require_relative 'dictionary_key_validatable'
|
|
5
|
+
|
|
6
|
+
module LittleWeasel
|
|
7
|
+
module Modules
|
|
8
|
+
# This module defines attributes and functionality for a dictionary
|
|
9
|
+
# key. A dictionary key is a unique key (basically a locale and optional
|
|
10
|
+
# tag suffix) that is used to link a dictionary to the dictionary cache
|
|
11
|
+
# and dictionary metadata objects.
|
|
12
|
+
module DictionaryKeyable
|
|
13
|
+
include Modules::DictionaryKeyValidatable
|
|
14
|
+
|
|
15
|
+
attr_reader :dictionary_key
|
|
16
|
+
|
|
17
|
+
delegate :key, to: :dictionary_key
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
attr_writer :dictionary_key
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../dictionary_key'
|
|
4
|
+
require_relative '../services/dictionary_metadata_service'
|
|
5
|
+
require_relative 'dictionary_cache_validatable'
|
|
6
|
+
require_relative 'dictionary_metadata_validatable'
|
|
7
|
+
|
|
8
|
+
module LittleWeasel
|
|
9
|
+
module Modules
|
|
10
|
+
# This module defines methods and attributes to consume the dictionary
|
|
11
|
+
# metadata service.
|
|
12
|
+
module DictionaryMetadataServicable
|
|
13
|
+
include DictionaryKeyable
|
|
14
|
+
include DictionaryCacheValidatable
|
|
15
|
+
include DictionaryMetadataValidatable
|
|
16
|
+
|
|
17
|
+
attr_reader :dictionary_cache, :dictionary_key, :dictionary_metadata
|
|
18
|
+
|
|
19
|
+
def dictionary_metadata_service
|
|
20
|
+
Services::DictionaryMetadataService.new(dictionary_key: dictionary_key, dictionary_cache: dictionary_cache,
|
|
21
|
+
dictionary_metadata: dictionary_metadata)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
attr_writer :dictionary_cache, :dictionary_key, :dictionary_metadata
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Modules
|
|
5
|
+
# This module provides methods to validate a dictionary metadata object.
|
|
6
|
+
module DictionaryMetadataValidatable
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def validate_dictionary_metadata(dictionary_metadata:)
|
|
10
|
+
raise ArgumentError, "Argument dictionary_metadata is not a valid Hash object: #{dictionary_metadata.class}" \
|
|
11
|
+
unless dictionary_metadata.is_a? Hash
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Modules
|
|
5
|
+
# This module provides methods to validate a dictionary source.
|
|
6
|
+
module DictionarySourceValidatable
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def validate_dictionary_source(dictionary_source:)
|
|
10
|
+
raise ArgumentError, 'Argument dictionary_source is not present' \
|
|
11
|
+
unless dictionary_source.present?
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
require_relative '../modules/dictionary_cache_keys'
|
|
5
|
+
require_relative '../modules/dictionary_source_validatable'
|
|
6
|
+
require_relative '../modules/dictionary_validatable'
|
|
7
|
+
|
|
8
|
+
module LittleWeasel
|
|
9
|
+
module Modules
|
|
10
|
+
# This module provides methods to manage dictionary sources.
|
|
11
|
+
module DictionarySourceable
|
|
12
|
+
include Modules::DictionaryCacheKeys
|
|
13
|
+
include Modules::DictionarySourceValidatable
|
|
14
|
+
include Modules::DictionaryValidatable
|
|
15
|
+
|
|
16
|
+
MEMORY_SOURCE = '*'
|
|
17
|
+
|
|
18
|
+
def self.file_source?(dictionary_source)
|
|
19
|
+
!memory_source? dictionary_source
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.memory_source?(dictionary_source)
|
|
23
|
+
dictionary_source =~ /^#{Regexp.quote(MEMORY_SOURCE)}[0-9a-fA-F]{8}$/
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def memory_source
|
|
27
|
+
"#{MEMORY_SOURCE}#{SecureRandom.uuid[0..7]}"
|
|
28
|
+
end
|
|
29
|
+
module_function :memory_source
|
|
30
|
+
|
|
31
|
+
# Adds a dictionary source. A "dictionary source" specifies the source from which
|
|
32
|
+
# the dictionary ultimately obtains its words.
|
|
33
|
+
#
|
|
34
|
+
# @param source [String] the dictionary source. This can be a file path
|
|
35
|
+
# or a memory source indicator to signify that the dictionary was created
|
|
36
|
+
# dynamically from memory.
|
|
37
|
+
def add_dictionary_source(dictionary_source:)
|
|
38
|
+
validate_dictionary_source_does_not_exist dictionary_cache_service: self
|
|
39
|
+
|
|
40
|
+
set_dictionary_reference \
|
|
41
|
+
dictionary_id: dictionary_id_associated_with(dictionary_source: dictionary_source)
|
|
42
|
+
# Only set the dictionary source if it doesn't already exist because settings
|
|
43
|
+
# the dictionary source wipes out the #dictionary_object; dictionary objects
|
|
44
|
+
# can have more than one dictionary reference pointing to them, and we don't
|
|
45
|
+
# want to blow away the #dictionary_object, metadata, or any other data
|
|
46
|
+
# associated with it if it already exists.
|
|
47
|
+
set_dictionary_source(dictionary_source: dictionary_source) unless dictionary?
|
|
48
|
+
self
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def dictionary_source
|
|
52
|
+
dictionary_cache.dig(DICTIONARY_CACHE, DICTIONARIES, dictionary_id, SOURCE)
|
|
53
|
+
end
|
|
54
|
+
alias dictionary_file dictionary_source
|
|
55
|
+
|
|
56
|
+
def dictionary_source!
|
|
57
|
+
raise ArgumentError, "A dictionary source could not be found for key '#{key}'." \
|
|
58
|
+
unless dictionary_reference?
|
|
59
|
+
|
|
60
|
+
dictionary_cache[DICTIONARY_CACHE][DICTIONARIES][dictionary_id!][SOURCE]
|
|
61
|
+
end
|
|
62
|
+
alias dictionary_file! dictionary_source!
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
# Sets the dictionary source in the dictionary cache.
|
|
67
|
+
def set_dictionary_source(dictionary_source:)
|
|
68
|
+
dictionary_cache[DICTIONARY_CACHE][DICTIONARIES][dictionary_id!] = {
|
|
69
|
+
SOURCE => dictionary_source,
|
|
70
|
+
DICTIONARY_OBJECT => {}
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Returns the dictionary_id for the dictionary_source if it exists in
|
|
75
|
+
# dictionaries; otherwise, returns the new dictionary id that should
|
|
76
|
+
# be used.
|
|
77
|
+
def dictionary_id_associated_with(dictionary_source:)
|
|
78
|
+
dictionaries = dictionary_cache.dig(DICTIONARY_CACHE, DICTIONARIES)
|
|
79
|
+
dictionaries&.each_pair do |dictionary_id, dictionary_hash|
|
|
80
|
+
return dictionary_id if dictionary_source == dictionary_hash[SOURCE]
|
|
81
|
+
end
|
|
82
|
+
SecureRandom.uuid[0..7]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Modules
|
|
5
|
+
# This module provides validations related to dictionaries in
|
|
6
|
+
# the dictionary cache.
|
|
7
|
+
module DictionaryValidatable
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def validate_dictionary_source_does_not_exist(dictionary_cache_service:)
|
|
11
|
+
# If a dictionary_reference exists, the dictionary_source must exist.
|
|
12
|
+
if dictionary_cache_service.dictionary_reference?
|
|
13
|
+
raise "The dictionary source associated with key '#{dictionary_cache_service.key}' already exists."
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/object/blank'
|
|
4
|
+
|
|
5
|
+
module LittleWeasel
|
|
6
|
+
module Modules
|
|
7
|
+
# Provides methods for normalizing language for a locale.
|
|
8
|
+
module Language
|
|
9
|
+
def language?
|
|
10
|
+
language.present?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def normalize_language!
|
|
14
|
+
self.language = normalize_language language
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
def normalize_language(language)
|
|
20
|
+
language&.downcase
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Modules
|
|
5
|
+
# This module provides methods to validate a language.
|
|
6
|
+
module LanguageValidatable
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def validate_language(language:)
|
|
10
|
+
raise ArgumentError, "Argument language '#{language}' is not a Symbol." unless language.is_a? Symbol
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'language'
|
|
4
|
+
require_relative 'region'
|
|
5
|
+
|
|
6
|
+
module LittleWeasel
|
|
7
|
+
module Modules
|
|
8
|
+
# This module provides methods to handle conversion of parts of a locale to
|
|
9
|
+
# their string counter parts.
|
|
10
|
+
module Locale
|
|
11
|
+
include Language
|
|
12
|
+
include Region
|
|
13
|
+
|
|
14
|
+
def locale
|
|
15
|
+
language = normalize_language self.language
|
|
16
|
+
return language.to_s unless region?
|
|
17
|
+
|
|
18
|
+
region = normalize_region self.region
|
|
19
|
+
"#{language}-#{region}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Modules
|
|
5
|
+
# This module provides methods to validate a value that can be used
|
|
6
|
+
# in sorting.
|
|
7
|
+
module OrderValidatable
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def validate_order(order:)
|
|
11
|
+
raise ArgumentError, "Argument order is not an Integer: #{order.class}" unless order.is_a? Integer
|
|
12
|
+
raise ArgumentError, "Argument order '#{order}' is not a a number from 0-n" if order.negative?
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Modules
|
|
5
|
+
# This module provides attribtues and methods to manage objects that can be
|
|
6
|
+
# ordered or sorted.
|
|
7
|
+
module Orderable
|
|
8
|
+
include OrderValidatable
|
|
9
|
+
|
|
10
|
+
attr_reader :order
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
attr_writer :order
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/object/blank'
|
|
4
|
+
|
|
5
|
+
module LittleWeasel
|
|
6
|
+
module Modules
|
|
7
|
+
# Provides methods for normalizing a region for a locale.
|
|
8
|
+
module Region
|
|
9
|
+
def region?
|
|
10
|
+
region.present?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def normalize_region!
|
|
14
|
+
self.region = normalize_region region
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
def normalize_region(region)
|
|
20
|
+
region&.upcase
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Modules
|
|
5
|
+
# This module provides methods to validate a region.
|
|
6
|
+
module RegionValidatable
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def validate_region(region:)
|
|
10
|
+
raise ArgumentError, "Argument region '#{region}' is not a Symbol." unless region.blank? || region.is_a?(Symbol)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Modules
|
|
5
|
+
# This module provides methods to validate a tag.
|
|
6
|
+
module TagValidatable
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def validate_tag(tag:)
|
|
10
|
+
raise ArgumentError, "Argument tag '#{tag}' is not a Symbol." unless tag.blank? || tag.is_a?(Symbol)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'tag_validatable'
|
|
4
|
+
|
|
5
|
+
module LittleWeasel
|
|
6
|
+
module Modules
|
|
7
|
+
# This module provides methods to manage objects that can be tagged.
|
|
8
|
+
# A tag is a value that can be included as part of a DictionaryKey
|
|
9
|
+
# object to make it unique across locales.
|
|
10
|
+
#
|
|
11
|
+
# @examples
|
|
12
|
+
#
|
|
13
|
+
# en-US-<tag>
|
|
14
|
+
#
|
|
15
|
+
# Where <tag> = a String to make this locale unique across locales
|
|
16
|
+
# of the same language and region.
|
|
17
|
+
module Taggable
|
|
18
|
+
include TagValidatable
|
|
19
|
+
|
|
20
|
+
attr_reader :tag
|
|
21
|
+
|
|
22
|
+
def tagged?
|
|
23
|
+
tag.present?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_writer :tag
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Modules
|
|
5
|
+
# This module provides methods to validate a word results
|
|
6
|
+
module WordResultsValidatable
|
|
7
|
+
def validate_original_word
|
|
8
|
+
raise ArgumentError, "Argument original_word is not a String: #{original_word.class}" \
|
|
9
|
+
unless original_word.is_a? String
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def validate_filters_matched
|
|
13
|
+
raise ArgumentError, "Argument filters_matched is not an Array: #{filters_matched.class}" \
|
|
14
|
+
unless filters_matched.is_a? Array
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def validate_word_cached
|
|
18
|
+
raise ArgumentError, "Argument word_cached is not true or false: #{word_cached.class}" \
|
|
19
|
+
unless [true, false].include? word_cached
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def vaidate_word_valid
|
|
23
|
+
raise ArgumentError, "Argument word_valid is not true or false: #{word_cached.class}" \
|
|
24
|
+
unless [true, false].include? word_valid
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../word_preprocessor'
|
|
4
|
+
|
|
5
|
+
module LittleWeasel
|
|
6
|
+
module Preprocessors
|
|
7
|
+
module EnUs
|
|
8
|
+
# This preprocessor capitializes a word.
|
|
9
|
+
class CapitalizePreprocessor < WordPreprocessor
|
|
10
|
+
def initialize(order: 0)
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def preprocess(word)
|
|
16
|
+
[true, word.capitalize]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Preprocessors
|
|
5
|
+
# This class represents a word that has passed through
|
|
6
|
+
# Preprocessor::WordPreprocessor processing. Word preprocessors
|
|
7
|
+
# are used to preprocess a word before it is passed to any
|
|
8
|
+
# Filters::WordFilters, and before it is compared against the
|
|
9
|
+
# dictionary for validity.
|
|
10
|
+
# :reek:Attribute, ignored - Fixing this would result in nothing but trivial setter methods
|
|
11
|
+
class PreprocessedWord
|
|
12
|
+
attr_accessor :original_word, :preprocessed, :preprocessed_word, :preprocessor, :preprocessor_order
|
|
13
|
+
|
|
14
|
+
def initialize(original_word:, preprocessed:, preprocessed_word:, preprocessor:, preprocessor_order:)
|
|
15
|
+
self.original_word = original_word
|
|
16
|
+
self.preprocessed_word = preprocessed_word
|
|
17
|
+
self.preprocessed = preprocessed
|
|
18
|
+
self.preprocessor = preprocessor
|
|
19
|
+
self.preprocessor_order = preprocessor_order
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns true if the word was preprocessed; false, if the word
|
|
23
|
+
# was not preprocessed by this preprocessor.
|
|
24
|
+
def preprocessed?
|
|
25
|
+
preprocessed
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Preprocessors
|
|
5
|
+
# This module provides functionality that validates preprocessed word types.
|
|
6
|
+
# rubocop: disable Layout/LineLength
|
|
7
|
+
# :reek:ManualDispatch, ignored - these methods are raising errors, not performing conditional code execution
|
|
8
|
+
module PreprocessedWordValidatable
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def validate_prepreprocessed_word(preprocessed_word:)
|
|
12
|
+
validate_original_word preprocessed_word: preprocessed_word
|
|
13
|
+
validate_preprocessed_word preprocessed_word: preprocessed_word
|
|
14
|
+
validate_preprocessed preprocessed_word: preprocessed_word
|
|
15
|
+
validate_preprocessor preprocessed_word: preprocessed_word
|
|
16
|
+
validate_preprocessor_order preprocessed_word: preprocessed_word
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def validation_error_message(object:, respond_to:)
|
|
20
|
+
"Argument preprocessed_word: does not respond to: #{object}#{respond_to}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def validate_original_word(preprocessed_word:)
|
|
24
|
+
preprocessed_word_class = preprocessed_word.class
|
|
25
|
+
raise validation_error_message(object: preprocessed_word_class, respond_to: '#original_word') unless preprocessed_word.respond_to?(:original_word)
|
|
26
|
+
raise validation_error_message(object: preprocessed_word_class, respond_to: '#original_word=') unless preprocessed_word.respond_to?(:original_word=)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def validate_preprocessed_word(preprocessed_word:)
|
|
30
|
+
preprocessed_word_class = preprocessed_word.class
|
|
31
|
+
raise validation_error_message(object: preprocessed_word_class, respond_to: '#preprocessed_word') unless preprocessed_word.respond_to?(:preprocessed_word)
|
|
32
|
+
raise validation_error_message(object: preprocessed_word_class, respond_to: '#preprocessed_word=') unless preprocessed_word.respond_to?(:preprocessed_word=)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def validate_preprocessed(preprocessed_word:)
|
|
36
|
+
preprocessed_word_class = preprocessed_word.class
|
|
37
|
+
raise validation_error_message(object: preprocessed_word_class, respond_to: '#preprocessed') unless preprocessed_word.respond_to?(:preprocessed)
|
|
38
|
+
raise validation_error_message(object: preprocessed_word_class, respond_to: '#preprocessed=') unless preprocessed_word.respond_to?(:preprocessed=)
|
|
39
|
+
raise validation_error_message(object: preprocessed_word_class, respond_to: '#preprocessed?') unless preprocessed_word.respond_to?(:preprocessed?)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def validate_preprocessor(preprocessed_word:)
|
|
43
|
+
preprocessed_word_class = preprocessed_word.class
|
|
44
|
+
raise validation_error_message(object: preprocessed_word_class, respond_to: '#preprocessor') unless preprocessed_word.respond_to?(:preprocessor)
|
|
45
|
+
raise validation_error_message(object: preprocessed_word_class, respond_to: '#preprocessor=') unless preprocessed_word.respond_to?(:preprocessor=)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def validate_preprocessor_order(preprocessed_word:)
|
|
49
|
+
preprocessed_word_class = preprocessed_word.class
|
|
50
|
+
raise validation_error_message(object: preprocessed_word_class, respond_to: '#preprocessor_order') unless preprocessed_word.respond_to?(:preprocessor_order)
|
|
51
|
+
raise validation_error_message(object: preprocessed_word_class, respond_to: '#preprocessor_order=') unless preprocessed_word.respond_to?(:preprocessor_order=)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
# rubocop: enable Layout/LineLength
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LittleWeasel
|
|
4
|
+
module Preprocessors
|
|
5
|
+
# This class provides a container for Preprocessors::PreprocessedWord
|
|
6
|
+
# objects.
|
|
7
|
+
class PreprocessedWords
|
|
8
|
+
attr_reader :original_word, :preprocessed_words
|
|
9
|
+
|
|
10
|
+
# original_word:String the unsullied word before any preprocessing has
|
|
11
|
+
# been applied to it.
|
|
12
|
+
# preprocessed_words:Array, Preprocessors::PreprocessedWord, an Array
|
|
13
|
+
# of Preprocessors::PreprocessedWord objects that represents the
|
|
14
|
+
# original_word having passed through each successive
|
|
15
|
+
# Preprocessors::WordPreprocessor.
|
|
16
|
+
def initialize(original_word:, preprocessed_words:)
|
|
17
|
+
self.original_word = original_word
|
|
18
|
+
self.preprocessed_words = preprocessed_words
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
# Returns true if the word was passed through any preprocessing. If
|
|
23
|
+
# this is the case, #preprocessed_word may be different than
|
|
24
|
+
# #original_word.
|
|
25
|
+
def preprocessed?(preprocessed_words:)
|
|
26
|
+
# TODO: Do we need to check for preprocessors where
|
|
27
|
+
# #preprocessed? is true? or does preprocessed_words
|
|
28
|
+
# contain only preprocessed word objects where
|
|
29
|
+
# #preprocessed? is true?
|
|
30
|
+
preprocessed_words.present?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def preprocessed_word(preprocessed_words:)
|
|
34
|
+
return unless preprocessed? preprocessed_words: preprocessed_words
|
|
35
|
+
|
|
36
|
+
preprocessed_words.max_by(&:preprocessor_order).preprocessed_word
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def preprocessed_words=(value)
|
|
41
|
+
value ||= []
|
|
42
|
+
@preprocessed_words = value
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def preprocessed_word
|
|
46
|
+
self.class.preprocessed_word preprocessed_words: preprocessed_words
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Returns true if the word was preprocessed
|
|
50
|
+
def preprocessed?
|
|
51
|
+
self.class.preprocessed? preprocessed_words: preprocessed_words
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
attr_writer :original_word
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'preprocessed_word_validatable'
|
|
4
|
+
|
|
5
|
+
module LittleWeasel
|
|
6
|
+
module Preprocessors
|
|
7
|
+
# This module provides methods to validate preprocessed words types.
|
|
8
|
+
# rubocop: disable Layout/LineLength
|
|
9
|
+
module PreprocessedWordsValidatable
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# :reek:ManualDispatch, ignored - this is raising an error, not conditional code execution
|
|
13
|
+
def validate_prepreprocessed_words(preprocessed_words:)
|
|
14
|
+
raise ArgumentError, validation_error_message(object: preprocessed_words, respond_to: :original_word) unless preprocessed_words.respond_to? :original_word
|
|
15
|
+
raise ArgumentError, validation_error_message(object: preprocessed_words, respond_to: :preprocessed_words) unless preprocessed_words.respond_to? :preprocessed_words
|
|
16
|
+
|
|
17
|
+
preprocessed_words&.preprocessed_words&.each do |preprocessed_word|
|
|
18
|
+
PreprocessedWordValidatable.validate_prepreprocessed_word preprocessed_word: preprocessed_word
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def validation_error_message(object:, respond_to:)
|
|
23
|
+
"Argument preprocessed_words does not respond to: #{object.class}##{respond_to}"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
# rubocop: enable Layout/LineLength
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'word_preprocessors_validatable'
|
|
4
|
+
|
|
5
|
+
module LittleWeasel
|
|
6
|
+
module Preprocessors
|
|
7
|
+
# This module provides the word_preprocessors attribute for objects
|
|
8
|
+
# that support word preprocessors.
|
|
9
|
+
module WordPreprocessable
|
|
10
|
+
@word_preprocessors = []
|
|
11
|
+
|
|
12
|
+
attr_reader :word_preprocessors
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
attr_writer :word_preprocessors
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|