Class: Kotoshu::Suggestions::Suggestion

Inherits:
Lutaml::Model::Serializable
  • Object
show all
Defined in:
lib/kotoshu/suggestions/suggestion.rb

Overview

A single suggestion with associated metadata and behavior.

Serialized via lutaml-model. Use to_hash / Suggestion.as_json(instance) / Suggestion.from_hash(hash) / Suggestion.from_json(string) for the wire forms — no hand-rolled to_h / as_json on the model.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(word: nil, distance: 0, confidence: 1.0, source: "unknown", **metadata) ⇒ Suggestion

Support the legacy **metadata kwarg catch-all so existing callers (e.g., Suggestion.new(word:, distance:, source:, original_length: 5)) continue to work; extra kwargs land in the metadata attribute. Source is stored as a string for clean serialization; from_source? normalizes Symbol/String comparison so callers can pass either.

word defaults to nil purely to accommodate lutaml-model's deserialization pathway, which allocates a shell via new(lutaml_register:) before applying attribute values through the deserialize pipeline. Direct callers must still pass word: — a Suggestion without a word is degenerate and not user-facing.



30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/kotoshu/suggestions/suggestion.rb', line 30

def initialize(word: nil, distance: 0, confidence: 1.0, source: "unknown", **)
  lutaml_register = .delete(:lutaml_register)
  kwargs = {
    word: word,
    distance: distance,
    confidence: confidence,
    source: source.to_s,
    metadata: 
  }
  kwargs[:lutaml_register] = lutaml_register if lutaml_register
  super(**kwargs)
end

Class Method Details

.from_word(word, source: :unknown) ⇒ Suggestion

Create a suggestion from a simple word (convenience method).

Parameters:

  • word (String)

    The word

  • source (String, Symbol) (defaults to: :unknown)

    The source

Returns:



149
150
151
# File 'lib/kotoshu/suggestions/suggestion.rb', line 149

def self.from_word(word, source: :unknown)
  new(word: word, distance: 0, confidence: 1.0, source: source)
end

Instance Method Details

#<=>(other) ⇒ Integer?

Compare suggestions for sorting (higher combined score first).

Ranking priority (following CSpell/Hunspell approach):

  1. Combined score (higher is better)
  2. Edit distance (lower is better)
  3. Length similarity (prefer similar length to original word)
  4. N-gram similarity (more shared n-grams is better)
  5. Alphabetical (ONLY as final tiebreaker)

Parameters:

Returns:

  • (Integer, nil)

    -1, 0, or 1; nil if other is not a Suggestion



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/kotoshu/suggestions/suggestion.rb', line 99

def <=>(other)
  return nil unless other.is_a?(Suggestion)

  score_cmp = other.combined_score <=> combined_score
  return score_cmp unless score_cmp.zero?

  distance_cmp = distance <=> other.distance
  return distance_cmp unless distance_cmp.zero?

  orig_len = [:original_length] || word.length
  other_orig_len = other.[:original_length] || other.word.length

  my_len_diff = (word.length - orig_len).abs
  other_len_diff = (other.word.length - other_orig_len).abs

  len_cmp = my_len_diff <=> other_len_diff
  return len_cmp unless len_cmp.zero?

  my_ngram = [:ngram_score] || 0
  other_ngram = other.[:ngram_score] || 0

  ngram_cmp = other_ngram <=> my_ngram
  return ngram_cmp unless ngram_cmp.zero?

  word.downcase <=> other.word.downcase
end

#==(other) ⇒ Object Also known as: eql?



126
127
128
129
130
# File 'lib/kotoshu/suggestions/suggestion.rb', line 126

def ==(other)
  return false unless other.is_a?(Suggestion)

  word.downcase == other.word.downcase
end

#combined_score(distance_weight: 0.3, confidence_weight: 0.7) ⇒ Float

Calculate combined score considering distance and confidence.

Parameters:

  • distance_weight (Float) (defaults to: 0.3)

    Weight for distance (default: 0.3)

  • confidence_weight (Float) (defaults to: 0.7)

    Weight for confidence (default: 0.7)

Returns:

  • (Float)

    Combined score (0.0 to 1.0, higher is better)



62
63
64
65
66
67
# File 'lib/kotoshu/suggestions/suggestion.rb', line 62

def combined_score(distance_weight: 0.3, confidence_weight: 0.7)
  normalized_distance = [distance, 5].min / 5.0
  distance_score = 1.0 - normalized_distance

  (distance_score * distance_weight) + (confidence * confidence_weight)
end

#from_source?(source) ⇒ Boolean

Check if this suggestion comes from a specific source.

Source is stored as a string; comparison normalizes Symbol/String.

Parameters:

  • source (String, Symbol)

    The source to check

Returns:

  • (Boolean)

    True if this suggestion came from the source



84
85
86
# File 'lib/kotoshu/suggestions/suggestion.rb', line 84

def from_source?(source)
  self.source == source.to_s
end

#hashObject



133
134
135
# File 'lib/kotoshu/suggestions/suggestion.rb', line 133

def hash
  word.downcase.hash
end

#high_confidence?Boolean

Check if this is a high-confidence suggestion.

Returns:

  • (Boolean)

    True if confidence >= 0.8



46
47
48
# File 'lib/kotoshu/suggestions/suggestion.rb', line 46

def high_confidence?
  confidence >= 0.8
end

#low_confidence?Boolean

Check if this is a low-confidence suggestion.

Returns:

  • (Boolean)

    True if confidence < 0.5



53
54
55
# File 'lib/kotoshu/suggestions/suggestion.rb', line 53

def low_confidence?
  confidence < 0.5
end

#same_word?(other) ⇒ Boolean

Check if this suggestion is the same word as another.

Parameters:

  • other (Suggestion, String)

    The other suggestion or word string

Returns:

  • (Boolean)

    True if words match (case-insensitive)



73
74
75
76
# File 'lib/kotoshu/suggestions/suggestion.rb', line 73

def same_word?(other)
  other_word = other.is_a?(Suggestion) ? other.word : other.to_s
  word.downcase == other_word.downcase
end

#to_sObject Also known as: inspect



137
138
139
140
# File 'lib/kotoshu/suggestions/suggestion.rb', line 137

def to_s
  format("Suggestion(word: '%<word>s', distance: %<distance>d, confidence: %<confidence>.2f, source: %<source>s)",
         word: word, distance: distance, confidence: confidence, source: source)
end