Class: Kotoshu::Dictionary::Custom

Inherits:
Base
  • Object
show all
Defined in:
lib/kotoshu/dictionary/custom.rb

Overview

Custom in-memory dictionary.

This is a simple dictionary that stores words in memory, designed for runtime customization and user-defined words.

Examples:

Creating an empty dictionary

dict = Custom.new(language_code: "en-US")
dict.add_word("Kotoshu")
dict.lookup?("Kotoshu")  # => true

Creating with initial words

dict = Custom.new(words: %w[hello world], language_code: "en")
dict.lookup?("hello")  # => true

Instance Attribute Summary collapse

Attributes inherited from Base

#language_code, #locale, #metadata

Instance Method Summary collapse

Methods inherited from Base

#each_word, #empty?, load, #lookup?, register_type, registry, #size, #to_s, #type, #words_matching, #words_with_prefix

Constructor Details

#initialize(language_code:, words: [], locale: nil, case_sensitive: false, metadata: {}) ⇒ Custom

Create a new Custom dictionary.

Parameters:

  • words (Array<String>) (defaults to: [])

    Initial words (optional)

  • language_code (String)

    The language code

  • locale (String, nil) (defaults to: nil)

    The locale (optional)

  • case_sensitive (Boolean) (defaults to: false)

    Whether lookups are case-sensitive

  • metadata (Hash) (defaults to: {})

    Additional metadata (optional)



31
32
33
34
35
36
37
38
39
40
# File 'lib/kotoshu/dictionary/custom.rb', line 31

def initialize(language_code:, words: [], locale: nil, case_sensitive: false, metadata: {})
  super(language_code, locale: locale, metadata: )

  @case_sensitive = case_sensitive
  @words = normalize_words(words)
  @word_set = build_word_set

  # Register this dictionary type
  self.class.register_type(:custom) unless Dictionary.registry.key?(:custom)
end

Instance Attribute Details

#case_sensitiveBoolean (readonly)

Returns Whether lookups are case-sensitive.

Returns:

  • (Boolean)

    Whether lookups are case-sensitive



22
23
24
# File 'lib/kotoshu/dictionary/custom.rb', line 22

def case_sensitive
  @case_sensitive
end

Instance Method Details

#add_word(word, flags: []) ⇒ Boolean

Add a word to the dictionary.

Parameters:

  • word (String)

    The word to add

  • flags (Array<String>) (defaults to: [])

    Flags (ignored for Custom)

Returns:

  • (Boolean)

    True if added



85
86
87
88
89
90
91
92
93
94
95
# File 'lib/kotoshu/dictionary/custom.rb', line 85

def add_word(word, flags: [])
  return false if word.nil? || word.empty?

  lookup_word = normalize_word(word)
  return false if @word_set.key?(lookup_word)

  @words << lookup_word
  @word_set[lookup_word] = @words.length - 1

  true
end

#clearself

Clear all words from the dictionary.

Returns:

  • (self)

    Self for chaining



123
124
125
126
127
# File 'lib/kotoshu/dictionary/custom.rb', line 123

def clear
  @words.clear
  @word_set.clear
  self
end

#lookup(word) ⇒ Boolean

Check if a word exists in the dictionary.

Parameters:

  • word (String)

    The word to look up

Returns:

  • (Boolean)

    True if the word exists



46
47
48
49
50
51
# File 'lib/kotoshu/dictionary/custom.rb', line 46

def lookup(word)
  return false if word.nil? || word.empty?

  lookup_word = @case_sensitive ? word : word.downcase
  @word_set.key?(lookup_word)
end

#merge(other) ⇒ self

Merge another dictionary into this one.

Examples:

Merging another dictionary

dict1 = Custom.new(words: %w[hello], language_code: "en")
dict2 = Custom.new(words: %w[world], language_code: "en")
dict1.merge(dict2)

Merging an array of words

dict.merge(%w[test example])

Parameters:

  • other (Base, Array<String>)

    Dictionary or words to merge

Returns:

  • (self)

    Self for chaining



148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/kotoshu/dictionary/custom.rb', line 148

def merge(other)
  words_to_add = if other.is_a?(Base)
                   other.words
                 elsif other.is_a?(Array)
                   other
                 else
                   []
                 end

  words_to_add.each { |word| add_word(word) }

  self
end

#readonly?Boolean

Check if the dictionary is read-only.

Returns:

  • (Boolean)

    Always false for Custom dictionary



132
133
134
# File 'lib/kotoshu/dictionary/custom.rb', line 132

def readonly?
  false
end

#remove_word(word) ⇒ Boolean

Remove a word from the dictionary.

Parameters:

  • word (String)

    The word to remove

Returns:

  • (Boolean)

    True if removed



101
102
103
104
105
106
107
108
109
110
111
# File 'lib/kotoshu/dictionary/custom.rb', line 101

def remove_word(word)
  return false if word.nil? || word.empty?

  lookup_word = normalize_word(word)
  return false unless @word_set.key?(lookup_word)

  index = @word_set.delete(lookup_word)
  @words.delete_at(index)

  true
end

#suggest(word, max_suggestions: 10) ⇒ Array<String>

Generate spelling suggestions.

Uses edit distance to find similar words in the dictionary.

Parameters:

  • word (String)

    The misspelled word

  • max_suggestions (Integer) (defaults to: 10)

    Maximum suggestions

Returns:

  • (Array<String>)

    List of suggested words



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/kotoshu/dictionary/custom.rb', line 60

def suggest(word, max_suggestions: 10)
  return [] if word.nil? || word.empty?

  lookup_word = @case_sensitive ? word : word.downcase

  # Find words with same prefix
  prefix_len = [lookup_word.length - 1, 2].max
  prefix = lookup_word[0...prefix_len]
  candidates = @words.select { |w| w.start_with?(prefix) }

  # Calculate edit distances
  candidates.map do |dict_word|
    dist = edit_distance(lookup_word, dict_word)
    [dict_word, dist]
  end.select { |_, dist| dist.positive? && dist <= 2 }
            .sort_by { |_, dist| dist }
            .first(max_suggestions)
            .map(&:first)
end

#wordsArray<String>

Get all words in the dictionary.

Returns:

  • (Array<String>)

    All words



116
117
118
# File 'lib/kotoshu/dictionary/custom.rb', line 116

def words
  @words.dup
end