From f52efae271ddb376e7223405c3a74edd7ed598b9 Mon Sep 17 00:00:00 2001 From: Bruno Wagner Goncalves Date: Fri, 1 Aug 2014 17:49:13 -0300 Subject: Changed names according to new convention on the fake service --- fake-service/lib/pixelated_service/search.rb | 133 +++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 fake-service/lib/pixelated_service/search.rb (limited to 'fake-service/lib/pixelated_service/search.rb') diff --git a/fake-service/lib/pixelated_service/search.rb b/fake-service/lib/pixelated_service/search.rb new file mode 100644 index 00000000..e8f9d9fd --- /dev/null +++ b/fake-service/lib/pixelated_service/search.rb @@ -0,0 +1,133 @@ +# Syntax notes for search: +# you can put a - in front of any search term to negate it +# you can scope a search by putting a name of a scope, a colon and then the search term WITHOUT a space. +# scoping will allow you to search for more things than otherwise available +# an unknown scope name will be assumed to be a header to search +# you can surround a search term in quotes to search for the whole thing +# multiple search terms will be ANDed together +# you can OR things by using the keyword OR/or - if you have it without parens, you will or the whole left with the whole right, until we find another or. +# if you use parenthesis, you can group together terms +# search in:_default_, in:all, in:trash, in:sent, in:drafts will only work for the WHOLE search. You can do a negation on a scoped search if it's in:trash, in:sent or in:drafts, but not for in:all + +module PixelatedService + class Search + def initialize(q) + if q + @qtree, @search_scope = Search.compile(q) + else + @qtree, @search_scope = TrueMatch.new, PixelatedService::MailScopeFilter::Default + end + end + + def restrict(input) + @search_scope.new(input).select do |mm| + @qtree.match?(mm) + end + end + + REGEXP_DQUOTED = /"[^"]*"/ + REGEXP_SQUOTED = /'[^']*'/ + REGEXP_SCOPE = /\w+:(".*?"|'.*?'|[^\s\)]+)/ + REGEXP_OTHER = /[^\s\)]+/ + + def self.scan_literal(qs) + if qs.check(REGEXP_DQUOTED) + StringMatch.new(qs.scan(REGEXP_DQUOTED), true) + elsif qs.check(REGEXP_SQUOTED) + StringMatch.new(qs.scan(REGEXP_SQUOTED), true) + elsif qs.check(REGEXP_OTHER) + StringMatch.new(qs.scan(REGEXP_OTHER)) + end + end + + def self.combine_search_scopes(l, r) + l + r + end + + def self.compile(q, qs = StringScanner.new(q)) + qtree = AndMatch.new + search_scope = PixelatedService::MailScopeFilter::Default + until qs.eos? + if qs.check(/\)/) + qs.scan(/\)/) + return optimized(qtree), search_scope + end + + negated = false + if qs.check(/-/) + negated = true + qs.scan(/-/) + end + + if qs.check(/or/i) + qs.scan(/or/i) + left = qtree + qtree = OrMatch.new(left, AndMatch.new) + else + res = + if qs.check(/\(/) + qs.scan(/\(/) + v, sc = compile(q, qs) + search_scope = search_scope + sc + v + elsif qs.check(REGEXP_DQUOTED) + StringMatch.new(qs.scan(REGEXP_DQUOTED), true) + elsif qs.check(REGEXP_SQUOTED) + StringMatch.new(qs.scan(REGEXP_SQUOTED), true) + elsif qs.check(REGEXP_SCOPE) + scope = qs.scan(/\w+/) + qs.scan(/:/) + rest_node = scan_literal(qs) + v = ScopeMatch.new(scope, rest_node) + if v.is_search_scope? && !negated + search_scope = search_scope + v.search_scope + TrueMatch.new + else + v + end + elsif qs.check(REGEXP_OTHER) + StringMatch.new(qs.scan(REGEXP_OTHER)) + end + res = NegateMatch.new(res) if negated + qtree << res + end + + qs.scan(/\s+/) + end + return optimized(qtree), search_scope + end + + def self.optimized(tree) + case tree + when AndMatch + data = tree.data.reject { |d| TrueMatch === d } + if data.length == 1 + optimized(data.first) + else + AndMatch.new(data.map { |n| optimized(n)} ) + end + when OrMatch + if tree.right.is_a?(AndMatch) && tree.right.data.empty? + optimized(tree.left) + else + OrMatch.new(optimized(tree.left), optimized(tree.right)) + end + when NegateMatch + if tree.data.is_a?(NegateMatch) + optimized(tree.data.data) + else + NegateMatch.new(optimized(tree.data)) + end + else + tree + end + end + end +end + +require 'pixelated_service/search/string_match' +require 'pixelated_service/search/scope_match' +require 'pixelated_service/search/negate_match' +require 'pixelated_service/search/and_match' +require 'pixelated_service/search/or_match' +require 'pixelated_service/search/true_match' -- cgit v1.2.3