class Dictionary class WordPath def initialize(case_sensitive) @case_sensitive = !!case_sensitive @is_leaf = false @word_paths = {} end def case_sensitive? @case_sensitive end def leaf? @is_leaf end def leaf=(is_leaf) @is_leaf = !!is_leaf end def <<(word) raise ArgumentError, 'must be a string' unless word.kind_of?(String) word = word.downcase unless @case_sensitive _append(word.strip) end def find(word) raise ArgumentError, 'must be a string' unless word.kind_of?(String) word = word.downcase unless @case_sensitive _find(word.strip) end def suffixes [].tap do |suffixes| @word_paths.each do |letter, path| suffixes << letter if path.leaf? suffixes.concat(path.suffixes.collect { |suffix| "#{letter}#{suffix}" }) end end end def hash self.class.hash ^ @is_leaf.hash ^ @word_paths.hash ^ @case_sensitive.hash end def ==(obj) obj.class == self.class && obj.hash == self.hash end def inspect "#" end def to_s inspect end protected def _find(word) word_path = @word_paths[word[0]] return nil unless word_path if word.size == 1 word_path else word_path._find(word[1, word.size]) end end def _append(word) return if word.empty? char = word[0] word_path = @word_paths[char] ||= self.class.new(@case_sensitive) if word.size == 1 word_path.leaf = true else word_path._append(word[1, word.size]) end end end end