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.
Files changed (151) 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/CHANGELOG.md +22 -1
  9. data/Gemfile +3 -1
  10. data/Jenkinsfile +20 -0
  11. data/LittleWeasel.gemspec +31 -18
  12. data/README.md +408 -42
  13. data/Rakefile +296 -3
  14. data/lib/LittleWeasel/block_results.rb +81 -0
  15. data/lib/LittleWeasel/configure.rb +98 -0
  16. data/lib/LittleWeasel/dictionary.rb +125 -0
  17. data/lib/LittleWeasel/dictionary_key.rb +48 -0
  18. data/lib/LittleWeasel/dictionary_manager.rb +91 -0
  19. data/lib/LittleWeasel/errors/dictionary_file_already_loaded_error.rb +9 -0
  20. data/lib/LittleWeasel/errors/dictionary_file_empty_error.rb +8 -0
  21. data/lib/LittleWeasel/errors/dictionary_file_not_found_error.rb +8 -0
  22. data/lib/LittleWeasel/errors/dictionary_file_too_large_error.rb +16 -0
  23. data/lib/LittleWeasel/errors/language_required_error.rb +8 -0
  24. data/lib/LittleWeasel/errors/must_override_error.rb +8 -0
  25. data/lib/LittleWeasel/filters/en_us/currency_filter.rb +19 -0
  26. data/lib/LittleWeasel/filters/en_us/numeric_filter.rb +19 -0
  27. data/lib/LittleWeasel/filters/en_us/single_character_word_filter.rb +21 -0
  28. data/lib/LittleWeasel/filters/word_filter.rb +59 -0
  29. data/lib/LittleWeasel/filters/word_filter_managable.rb +80 -0
  30. data/lib/LittleWeasel/filters/word_filter_validatable.rb +31 -0
  31. data/lib/LittleWeasel/filters/word_filterable.rb +19 -0
  32. data/lib/LittleWeasel/filters/word_filters_validatable.rb +29 -0
  33. data/lib/LittleWeasel/metadata/dictionary_metadata.rb +145 -0
  34. data/lib/LittleWeasel/metadata/invalid_words_metadata.rb +134 -0
  35. data/lib/LittleWeasel/metadata/invalid_words_service_results.rb +45 -0
  36. data/lib/LittleWeasel/metadata/metadata_observable_validatable.rb +22 -0
  37. data/lib/LittleWeasel/metadata/metadata_observerable.rb +90 -0
  38. data/lib/LittleWeasel/metadata/metadatable.rb +134 -0
  39. data/lib/LittleWeasel/modules/class_name_to_symbol.rb +26 -0
  40. data/lib/LittleWeasel/modules/configurable.rb +26 -0
  41. data/lib/LittleWeasel/modules/deep_dup.rb +11 -0
  42. data/lib/LittleWeasel/modules/dictionary_cache_keys.rb +34 -0
  43. data/lib/LittleWeasel/modules/dictionary_cache_servicable.rb +26 -0
  44. data/lib/LittleWeasel/modules/dictionary_cache_validatable.rb +18 -0
  45. data/lib/LittleWeasel/modules/dictionary_creator_servicable.rb +27 -0
  46. data/lib/LittleWeasel/modules/dictionary_file_loader.rb +67 -0
  47. data/lib/LittleWeasel/modules/dictionary_key_validatable.rb +17 -0
  48. data/lib/LittleWeasel/modules/dictionary_keyable.rb +24 -0
  49. data/lib/LittleWeasel/modules/dictionary_metadata_servicable.rb +29 -0
  50. data/lib/LittleWeasel/modules/dictionary_metadata_validatable.rb +15 -0
  51. data/lib/LittleWeasel/modules/dictionary_source_validatable.rb +15 -0
  52. data/lib/LittleWeasel/modules/dictionary_sourceable.rb +86 -0
  53. data/lib/LittleWeasel/modules/dictionary_validatable.rb +18 -0
  54. data/lib/LittleWeasel/modules/language.rb +24 -0
  55. data/lib/LittleWeasel/modules/language_validatable.rb +14 -0
  56. data/lib/LittleWeasel/modules/locale.rb +23 -0
  57. data/lib/LittleWeasel/modules/order_validatable.rb +16 -0
  58. data/lib/LittleWeasel/modules/orderable.rb +17 -0
  59. data/lib/LittleWeasel/modules/region.rb +24 -0
  60. data/lib/LittleWeasel/modules/region_validatable.rb +14 -0
  61. data/lib/LittleWeasel/modules/tag_validatable.rb +14 -0
  62. data/lib/LittleWeasel/modules/taggable.rb +31 -0
  63. data/lib/LittleWeasel/modules/word_results_validatable.rb +28 -0
  64. data/lib/LittleWeasel/preprocessors/en_us/capitalize_preprocessor.rb +22 -0
  65. data/lib/LittleWeasel/preprocessors/preprocessed_word.rb +29 -0
  66. data/lib/LittleWeasel/preprocessors/preprocessed_word_validatable.rb +56 -0
  67. data/lib/LittleWeasel/preprocessors/preprocessed_words.rb +59 -0
  68. data/lib/LittleWeasel/preprocessors/preprocessed_words_validatable.rb +28 -0
  69. data/lib/LittleWeasel/preprocessors/word_preprocessable.rb +19 -0
  70. data/lib/LittleWeasel/preprocessors/word_preprocessor.rb +123 -0
  71. data/lib/LittleWeasel/preprocessors/word_preprocessor_managable.rb +114 -0
  72. data/lib/LittleWeasel/preprocessors/word_preprocessor_validatable.rb +40 -0
  73. data/lib/LittleWeasel/preprocessors/word_preprocessors_validatable.rb +24 -0
  74. data/lib/LittleWeasel/services/dictionary_cache_service.rb +211 -0
  75. data/lib/LittleWeasel/services/dictionary_creator_service.rb +94 -0
  76. data/lib/LittleWeasel/services/dictionary_file_loader_service.rb +37 -0
  77. data/lib/LittleWeasel/services/dictionary_killer_service.rb +35 -0
  78. data/lib/LittleWeasel/services/dictionary_metadata_service.rb +116 -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/lib/LittleWeasel.rb +5 -184
  83. data/spec/factories/dictionary.rb +43 -0
  84. data/spec/factories/dictionary_cache_service.rb +95 -0
  85. data/spec/factories/dictionary_creator_service.rb +16 -0
  86. data/spec/factories/dictionary_file_loader_service.rb +13 -0
  87. data/spec/factories/dictionary_hash.rb +39 -0
  88. data/spec/factories/dictionary_key.rb +14 -0
  89. data/spec/factories/dictionary_killer_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 +166 -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 +81 -0
  119. data/spec/lib/LittleWeasel/modules/language_spec.rb +112 -0
  120. data/spec/lib/LittleWeasel/modules/locale_spec.rb +95 -0
  121. data/spec/lib/LittleWeasel/modules/region_spec.rb +112 -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 +242 -0
  128. data/spec/lib/LittleWeasel/preprocessors/word_preprocessor_spec.rb +218 -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_metadata_service_spec.rb +279 -0
  135. data/spec/lib/LittleWeasel/word_results_spec.rb +275 -0
  136. data/spec/lib/LittleWeasel/workflow/workflow_spec.rb +20 -0
  137. data/spec/spec_helper.rb +117 -6
  138. data/spec/support/factory_bot.rb +15 -0
  139. data/spec/support/file_helpers.rb +46 -0
  140. data/spec/support/files/empty-dictionary.txt +0 -0
  141. data/{lib/dictionary → spec/support/files/en-US-big.txt} +262156 -31488
  142. data/spec/support/files/en-US-tagged.txt +26 -0
  143. data/spec/support/files/en-US.txt +26 -0
  144. data/spec/support/files/en.txt +26 -0
  145. data/spec/support/files/es-ES.txt +27 -0
  146. data/spec/support/files/es.txt +27 -0
  147. data/spec/support/general_helpers.rb +68 -0
  148. data/spec/support/shared_contexts.rb +107 -0
  149. data/spec/support/shared_examples.rb +105 -0
  150. metadata +378 -38
  151. 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