Class: Kotoshu::Suggestions::Strategies::BaseStrategy
- Inherits:
-
Object
- Object
- Kotoshu::Suggestions::Strategies::BaseStrategy
- Defined in:
- lib/kotoshu/suggestions/strategies/base_strategy.rb
Overview
Base class for suggestion strategies.
Subclasses must implement the #generate method.
Direct Known Subclasses
CompositeStrategy, EditDistanceStrategy, KeyboardProximityStrategy, NgramStrategy, PhoneticStrategy, SemanticStrategy, SymSpellStrategy
Instance Attribute Summary collapse
-
#config ⇒ Hash
readonly
Strategy configuration.
-
#name ⇒ Symbol
readonly
Strategy name.
Instance Method Summary collapse
-
#calculate_ngram_similarity(word1, word2) ⇒ Float
Calculate typo correction similarity between two words.
-
#create_suggestion(word, distance: 0, confidence: 1.0, **metadata) ⇒ Suggestion
Create a suggestion from a word.
-
#create_suggestion_set(words, distances: {}, original_word: nil) ⇒ SuggestionSet
Create a suggestion set from words.
-
#enabled? ⇒ Boolean
Check if this strategy is enabled.
-
#generate(context) ⇒ SuggestionSet
abstract
Generate suggestions for a word.
-
#generate_ngrams(word, n) ⇒ Set<String>
Generate n-grams for a word.
-
#get_config(key, default = nil) ⇒ Object
Get a configuration value.
-
#handles?(context) ⇒ Boolean
Check if this strategy should handle the context.
-
#has_config?(key) ⇒ Boolean
Check if a config value is present.
-
#initialize(name: :base, **config) ⇒ BaseStrategy
constructor
Create a new base strategy.
-
#max_results(default = 10) ⇒ Integer
Get the max results configuration.
-
#priority ⇒ Integer
Get the priority for this strategy.
-
#to_s ⇒ String
(also: #inspect)
Convert strategy to string.
Constructor Details
#initialize(name: :base, **config) ⇒ BaseStrategy
Create a new base strategy.
30 31 32 33 34 35 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 30 def initialize(name: :base, **config) @name = name.to_sym @config = config @enabled = config.fetch(:enabled, true) @max_results = config.fetch(:max_results, 10) end |
Instance Attribute Details
#config ⇒ Hash (readonly)
Returns Strategy configuration.
22 23 24 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 22 def config @config end |
#name ⇒ Symbol (readonly)
Returns Strategy name.
19 20 21 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 19 def name @name end |
Instance Method Details
#calculate_ngram_similarity(word1, word2) ⇒ Float
Calculate typo correction similarity between two words.
This is a custom similarity metric designed specifically for spelling correction, combining:
-
Character overlap (how many characters are shared)
-
Prefix weight (common prefix is very important for typos)
-
Suffix weight (common ending is also important)
-
Length penalty (very different lengths are less similar)
Returns a value from 0.0 (no similarity) to 1.0 (identical).
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 163 def calculate_ngram_similarity(word1, word2) return 0 if word1.nil? || word2.nil? || word1.empty? || word2.empty? w1 = word1.downcase w2 = word2.downcase # Identical strings have maximum similarity return 1.0 if w1 == w2 len1 = w1.length len2 = w2.length max_len = [len1, len2].max # Calculate common prefix length (up to 4 characters) prefix_len = 0 (0...[len1, len2, 4].min).each do |i| break if w1[i] != w2[i] prefix_len += 1 end # Calculate common suffix length suffix_len = 0 (1..[len1, len2, 4].min).each do |i| break if w1[-i] != w2[-i] suffix_len += 1 end # Calculate character overlap (how many characters from w1 are in w2) w2_chars = w2.chars overlap = w1.chars.count { |c| w2_chars.include?(c) } # Calculate similarity score # 1. Base score from character overlap similarity = overlap.to_f / max_len # 2. Prefix bonus (common start is very important for typos) prefix_bonus = prefix_len * 0.15 # 3. Suffix bonus (common ending is also important) suffix_bonus = suffix_len * 0.05 # 4. Length penalty (very different lengths are less similar) length_diff = (len1 - len2).abs length_penalty = length_diff * 0.1 # Combine all factors similarity = similarity + prefix_bonus + suffix_bonus - length_penalty # Cap at 1.0, floor at 0.0 [[similarity, 1.0].min, 0.0].max end |
#create_suggestion(word, distance: 0, confidence: 1.0, **metadata) ⇒ Suggestion
Create a suggestion from a word.
106 107 108 109 110 111 112 113 114 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 106 def create_suggestion(word, distance: 0, confidence: 1.0, **) Suggestion.new( word: word, distance: distance, confidence: confidence, source: @name, ** ) end |
#create_suggestion_set(words, distances: {}, original_word: nil) ⇒ SuggestionSet
Create a suggestion set from words.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 122 def create_suggestion_set(words, distances: {}, original_word: nil) suggestions = words.map do |word| # Try case-sensitive first, then case-insensitive for distance lookup distance = if distances.key?(word) distances[word] else distances.fetch(word.downcase, 1) end confidence = calculate_confidence(distance) # Calculate n-gram similarity (like Hunspell) for better ranking ngram_score = if original_word calculate_ngram_similarity(original_word, word) else 0 end = { original_length: original_word&.length || word.length, ngram_score: ngram_score } create_suggestion(word, distance: distance, confidence: confidence, **) end SuggestionSet.new(suggestions, max_size: max_results) end |
#enabled? ⇒ Boolean
Check if this strategy is enabled.
50 51 52 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 50 def enabled? @enabled end |
#generate(context) ⇒ SuggestionSet
Subclasses must implement this method.
Generate suggestions for a word.
43 44 45 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 43 def generate(context) raise NotImplementedError, "#{self.class} must implement #generate" end |
#generate_ngrams(word, n) ⇒ Set<String>
Generate n-grams for a word.
220 221 222 223 224 225 226 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 220 def generate_ngrams(word, n) ngrams = Set.new (word.length - n + 1).times do |i| ngrams.add(word[i, n]) end ngrams end |
#get_config(key, default = nil) ⇒ Object
Get a configuration value.
67 68 69 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 67 def get_config(key, default = nil) @config.fetch(key, default) end |
#handles?(context) ⇒ Boolean
Check if this strategy should handle the context.
Default implementation checks if the word is not in the dictionary. Subclasses can override for more specific logic.
93 94 95 96 97 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 93 def handles?(context) return false unless enabled? !dictionary_lookup(context, context.word) end |
#has_config?(key) ⇒ Boolean
Check if a config value is present.
75 76 77 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 75 def has_config?(key) @config.key?(key) end |
#max_results(default = 10) ⇒ Integer
Get the max results configuration.
58 59 60 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 58 def max_results(default = 10) @max_results || default end |
#priority ⇒ Integer
Get the priority for this strategy.
82 83 84 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 82 def priority @config.fetch(:priority, 100) end |
#to_s ⇒ String Also known as: inspect
Convert strategy to string.
231 232 233 |
# File 'lib/kotoshu/suggestions/strategies/base_strategy.rb', line 231 def to_s "#{self.class.name}(name: #{@name}, enabled: #{enabled?})" end |