class QueryParser attr_reader :terms, :exclusions def initialize(query) @terms = [] @exclusions = [] query = query.clone while match = query.match(/\-?".+?"/) range = match.begin(0)...match.end(0) phrase = query[range] query[range] = ' ' negative = phrase.start_with?('-') phrase = phrase.gsub(/^\-/, '').gsub(/^"|"$/, '').gsub(/[^\w\-]+/, ' ').strip if negative @exclusions << phrase else @terms << phrase end end terms = query.gsub(/[^\w\-]+/, ' ').strip.split(/ +/) negative, positive = terms.partition { |x| x.start_with?('-') } @terms += positive @exclusions += negative.map { |x| x[1..-1] }.reject(&:empty?) end end