module BoggleLexicon
BoggleLexicon — WordNet word validation and gloss lookup for Boggle submissions. Public: findable_words, valid_word?, gloss_for, lemma_for Depends: Dictionary, BoggleMorph Tests: test/lib/boggle_lexicon_test.rb
Constants
- DEFAULT_FLAGS
- MAX_GLOSS_LENGTH
- MIN_LENGTH
- SENSE_LINE
Public Instance Methods
Source
# File lib/boggle_lexicon.rb, line 54 def collect_findable(grid, row, col, prefix, visited, found, lexicon, prefixes, exceptions) return if row.negative? || col.negative? || row >= grid.length || col >= grid[row].length key = [row, col] return if visited[key] prefix = "#{prefix}#{grid[row][col]}" accepted = prefix.length >= MIN_LENGTH && lemma_for(prefix, lexicon: lexicon, exceptions: exceptions) found[prefix] = true if accepted return unless prefixes[prefix] || inflection_partial?(prefix, lexicon, exceptions) || accepted visited = visited.merge(key => true) BoggleGrid::DIRECTIONS.each do |dr, dc| collect_findable(grid, row + dr, col + dc, prefix, visited, found, lexicon, prefixes, exceptions) end end
Source
# File lib/boggle_lexicon.rb, line 97 def default_exceptions @default_exceptions ||= BoggleMorph.load_exceptions(dict_dir: Dictionary::WN_DICT_DIR) end
Source
# File lib/boggle_lexicon.rb, line 116 def extract_first_gloss(lines) lines.each do |line| cleaned = Dictionary.clean_line(line) next if cleaned.empty? next if cleaned.match?(/\AOverview of /i) next if cleaned.match?(/\AThe (noun|verb|adj|adverb) /i) next if cleaned.match?(/\A\d+ of \d+ senses of /i) next unless cleaned.match?(/\A\d+\./) match = cleaned.match(SENSE_LINE) return match[3] if match formatted = Dictionary.format_sense_line(cleaned) sense_match = formatted.match(/\A\d+\.\s+.+?\s+—\s+(.+)\z/) return sense_match[1] if sense_match end nil end
Source
# File lib/boggle_lexicon.rb, line 20 def findable_words(grid, words: nil, exceptions: nil) lexicon = words || Dictionary.wordnet_words exc = exceptions || default_exceptions prefixes = search_prefixes(lexicon, exc) found = {} Array(grid).each_with_index do |row, r| Array(row).each_index do |c| collect_findable(grid, r, c, "", {}, found, lexicon, prefixes, exc) end end found.keys.sort end
Source
# File lib/boggle_lexicon.rb, line 102 def gloss_for(word, lookup: Dictionary.default_run) token = word.to_s.strip.downcase return nil if token.length < MIN_LENGTH return nil unless token.match?(/\A[a-z]+\z/) output, _status = Dictionary.run_lookup(token, DEFAULT_FLAGS.dup, run: lookup) gloss = extract_first_gloss(output.lines.map(&:rstrip)) return nil if gloss.nil? || gloss.empty? Dictionary.truncate_text(gloss, MAX_GLOSS_LENGTH) rescue StandardError nil end
Source
# File lib/boggle_lexicon.rb, line 71 def inflection_partial?(prefix, lexicon, exceptions) base = BoggleMorph.lemma_for(prefix, lexicon: lexicon, exceptions: exceptions) return false unless base BoggleMorph.inflected_forms(base, exceptions: exceptions).any? do |form| form.start_with?(prefix) && form.length > prefix.length end end
Source
# File lib/boggle_lexicon.rb, line 91 def lemma_for(word, lexicon: nil, words: nil, exceptions: nil) base_lexicon = lexicon || words || Dictionary.wordnet_words exc = exceptions || default_exceptions BoggleMorph.lemma_for(word, lexicon: base_lexicon, exceptions: exc) end
Source
# File lib/boggle_lexicon.rb, line 33 def lexicon_prefixes(lexicon) prefixes = {} lexicon.each_key do |word| (1..word.length).each do |len| prefixes[word[0, len]] = true end end prefixes end
Source
# File lib/boggle_lexicon.rb, line 43 def search_prefixes(lexicon, exceptions) prefixes = lexicon_prefixes(lexicon) exceptions.each_key do |inflected| (1..inflected.length).each do |len| prefixes[inflected[0, len]] = true end end prefixes end
Source
# File lib/boggle_lexicon.rb, line 82 def valid_word?(word, words: nil, exceptions: nil) token = word.to_s.strip.downcase return false if token.length < MIN_LENGTH return false unless token.match?(/\A[a-z]+\z/) lexicon = words || Dictionary.wordnet_words !lemma_for(token, lexicon: lexicon, exceptions: exceptions).nil? end