class Runestone::WebSearch
Attributes
values[RW]
Public Class Methods
new(values)
click to toggle source
# File lib/runestone/web_search.rb, line 78 def initialize(values) @values = values end
parse(query, prefix: :last)
click to toggle source
prefix options: :all, :last, :none (default: :last)
# File lib/runestone/web_search.rb, line 27 def self.parse(query, prefix: :last) prefix ||= :last Runestone.normalize!(query) q = [] stack = [] knot = false tokens = query.gsub(/\"\s+\"/, '""').split(' ') tokens.each_with_index do |token, i| token.gsub!(/\(|\)|:|\||!|\&|\*/, '') if token.start_with?('-') knot = true token.delete_prefix!('-') else knot = false end next if token.empty? || token == '""' || %w(' ").include?(token) if token.start_with?('"') && token.end_with?('"') token.delete_prefix!('"') token.delete_suffix!('"') q << Phrase.new([token], negative: knot) elsif token.start_with?('"') token.delete_prefix!('"') stack.push(:phrase) q << Phrase.new([Token.new(token)], negative: knot) elsif token.end_with?('"') token.delete_suffix!('"') q.last.values << Token.new(token) stack.pop else token = Token.new(token, negative: knot) if !knot && prefix == :last && tokens.size - 1 == i token.prefix = true elsif !knot && prefix == :all token.prefix = true end if stack.last == :phrase q.last.values << token else q << token end end end new(q) end
Public Instance Methods
synonymize()
click to toggle source
# File lib/runestone/web_search.rb, line 96 def synonymize parts = [] @values.each do |token| if token.is_a?(Phrase) || token.negative parts << token else parts << [] if parts.empty? || parts.last.is_a?(Phrase) || (!parts.last.is_a?(Array) && parts.last.negative) parts.last << token end end parts.map! do |part| if !part.is_a?(Phrase) && (part.is_a?(Array) || !part.negative) synonymize_part(part) else part end end Runestone::WebSearch.new(parts) end
synonymize_part(part)
click to toggle source
# File lib/runestone/web_search.rb, line 118 def synonymize_part(part) pending_matches = [] matches = [] part.each_with_index do |token, i| pending_matches.select! do |match| if match.end_index + 1 == i && match.substitution[token.value] match.substitution[token.value].map do |nm| if nm.is_a?(Hash) match.end_index = i match.alts = nm true else matches << Match.new(match.start_index..i, Phrase.new(Array(nm), distance: 1)) false end end else false end end if match = Runestone.synonyms[token.value] match.each do |m| if m.is_a?(Hash) pending_matches << PartialMatch.new(i, i, m) else matches << Match.new(i, Phrase.new(m.split(/\s+/), distance: 1)) end end end end matches.select! do |match| if match.index.is_a?(Integer) case part[match.index] when Or part[match.index].values << match.substitution else part[match.index] = Or.new([part[match.index], match.substitution]) end false else true end end groups = matches.inject([]) do |memo, match| if memo.empty? memo << [match] elsif i = memo.index { |k| k.none? { |j| j.index.overlaps?(match.index) } } memo[i] << match else memo << [match] end memo end if groups.empty? And.new(part) else orrs = Or.new([]) groups.each do |g| p = [] p << And.new(part[0..g.first.index.begin-1]) if g.first.index.begin > 0 g.each do |m| p << Or.new([And.new(part[m.index]), m.substitution]) end p << And.new(part[g.last.index.end+1..-1]) if g.last.index.end < part.size orrs.values << And.new(p) end orrs end end
to_s(use_synonyms: true, allow_typos: true)
click to toggle source
# File lib/runestone/web_search.rb, line 196 def to_s(use_synonyms: true, allow_typos: true) self.values.join(' & ') end
typos()
click to toggle source
# File lib/runestone/web_search.rb, line 82 def typos tokens = @values.select{|t| t.is_a?(Token) && !t.negative } sw = Runestone::Corpus.similar_words(*tokens.map(&:value)) q = @values.map do |t| if t.is_a?(Token) && sw.has_key?(t.value) Token.new(t.value, prefix: t.prefix, negative: t.negative, alts: sw[t.value]) else t end end Runestone::WebSearch.new(q) end