Class: Kotoshu::Suggestions::Suggestion

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

Overview

A single suggestion with associated metadata and behavior. This is MORE model-driven than Spylls which returns plain strings.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of Suggestion.

Parameters:

  • word (String)

    The suggested word

  • distance (Integer) (defaults to: 0)

    Edit distance from original (lower is better)

  • confidence (Float) (defaults to: 1.0)

    Confidence score (0.0 to 1.0, higher is better)

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

    The strategy that produced this suggestion

  • metadata (Hash)

    Additional metadata about the suggestion



15
16
17
18
19
20
21
22
# File 'lib/kotoshu/suggestions/suggestion.rb', line 15

def initialize(word:, distance: 0, confidence: 1.0, source: :unknown, **)
  @word = word
  @distance = distance
  @confidence = confidence
  @source = source
  @metadata = 
  freeze
end

Instance Attribute Details

#confidenceObject (readonly)

Returns the value of attribute confidence.



8
9
10
# File 'lib/kotoshu/suggestions/suggestion.rb', line 8

def confidence
  @confidence
end

#distanceObject (readonly)

Returns the value of attribute distance.



8
9
10
# File 'lib/kotoshu/suggestions/suggestion.rb', line 8

def distance
  @distance
end

#metadataObject (readonly)

Returns the value of attribute metadata.



8
9
10
# File 'lib/kotoshu/suggestions/suggestion.rb', line 8

def 
  @metadata
end

#sourceObject (readonly)

Returns the value of attribute source.



8
9
10
# File 'lib/kotoshu/suggestions/suggestion.rb', line 8

def source
  @source
end

#wordObject (readonly)

Returns the value of attribute word.



8
9
10
# File 'lib/kotoshu/suggestions/suggestion.rb', line 8

def word
  @word
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:



169
170
171
# File 'lib/kotoshu/suggestions/suggestion.rb', line 169

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)

    -1, 0, or 1



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/kotoshu/suggestions/suggestion.rb', line 79

def <=>(other)
  # First by combined score (descending)
  score_cmp = other.combined_score <=> combined_score
  return score_cmp unless score_cmp.zero?

  # Then by distance (ascending)
  distance_cmp = @distance <=> other.distance
  return distance_cmp unless distance_cmp.zero?

  # Then by length similarity (like CSpell - prefer words of similar length)
  # We need access to original word length, which is stored in metadata
  orig_len = @metadata[:original_length] || @word.length
  other_orig_len = other.[:original_length] || other.word.length

  # Calculate absolute difference from original 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?

  # Then by n-gram similarity (like Hunspell - more shared n-grams is better)
  # We use pre-computed n-gram score from metadata if available
  my_ngram = @metadata[:ngram_score] || 0
  other_ngram = other.[:ngram_score] || 0

  ngram_cmp = other_ngram <=> my_ngram  # Higher is better
  return ngram_cmp unless ngram_cmp.zero?

  # Finally by word alphabetically (ascending) - ONLY as final tiebreaker
  @word.downcase <=> other.word.downcase
end

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

Check equality with another suggestion.

Parameters:

  • other (Object)

    The other object

Returns:

  • (Boolean)

    True if equal



116
117
118
119
120
# File 'lib/kotoshu/suggestions/suggestion.rb', line 116

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

  @word.downcase == other.word.downcase
end

#as_jsonHash

Convert suggestion to JSON-compatible hash.

Returns:

  • (Hash)

    JSON-compatible hash



146
147
148
# File 'lib/kotoshu/suggestions/suggestion.rb', line 146

def as_json(*)
  to_h
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)



43
44
45
46
47
48
49
# File 'lib/kotoshu/suggestions/suggestion.rb', line 43

def combined_score(distance_weight: 0.3, confidence_weight: 0.7)
  # Normalize distance (assume max meaningful distance is 5)
  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.

Parameters:

  • source (String, Symbol)

    The source to check

Returns:

  • (Boolean)

    True if this suggestion came from the source



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

def from_source?(source)
  @source == source
end

#hashInteger

Hash value for use in Hash keys.

Returns:

  • (Integer)

    Hash code



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

def hash
  @word.downcase.hash
end

#high_confidence?Boolean

Check if this is a high-confidence suggestion.

Returns:

  • (Boolean)

    True if confidence >= 0.8



27
28
29
# File 'lib/kotoshu/suggestions/suggestion.rb', line 27

def high_confidence?
  @confidence >= 0.8
end

#inspectString

Inspect the suggestion.

Returns:

  • (String)

    Inspection string



160
161
162
# File 'lib/kotoshu/suggestions/suggestion.rb', line 160

def inspect
  to_s
end

#low_confidence?Boolean

Check if this is a low-confidence suggestion.

Returns:

  • (Boolean)

    True if confidence < 0.5



34
35
36
# File 'lib/kotoshu/suggestions/suggestion.rb', line 34

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)



55
56
57
58
# File 'lib/kotoshu/suggestions/suggestion.rb', line 55

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

#to_hHash

Convert suggestion to hash.

Returns:

  • (Hash)

    Suggestion as hash



133
134
135
136
137
138
139
140
141
# File 'lib/kotoshu/suggestions/suggestion.rb', line 133

def to_h
  {
    word: @word,
    distance: @distance,
    confidence: @confidence,
    source: @source,
    combined_score: combined_score
  }.merge(@metadata)
end

#to_sString

String representation.

Returns:

  • (String)

    String representation



153
154
155
# File 'lib/kotoshu/suggestions/suggestion.rb', line 153

def to_s
  "Suggestion(word: '#{@word}', distance: #{@distance}, confidence: #{format("%.2f", @confidence)}, source: #{@source})"
end