blob: f7b24ca32571d7f938562ba15cddbdf87a7eb7f1 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
# Very simple search for contacts. The search string will be something that will be prefix matched
# using a boundary before but not after. If you put in more than one word, those two will be searched
# and ANDed together. You can use double quotes or single quotes to do the obvious thing instead
module PixelatedService
class ContactsSearch
def initialize(q)
@qtree = ContactsSearch.compile(q)
end
def restrict(input)
input.select do |mm|
@qtree.match?(mm)
end
end
REGEXP_DQUOTED = /"[^"]*"/
REGEXP_SQUOTED = /'[^']*'/
REGEXP_OTHER = /[^\s]+/
class AndMatch
attr_reader :data
def initialize(data = [])
@data = data
end
def <<(node)
@data << node
end
def match?(c)
self.data.all? { |mm| mm.match?(c) }
end
end
class StringMatch
def initialize(data, quoted=false)
@data = Regexp.new(Regexp.quote(if quoted
data[1..-2]
else
data
end), Regexp::IGNORECASE)
@exact_match = /\b#{@data}/
end
def match_string?(str)
Array(str).any? { |ff| @exact_match.match ff }
end
def match?(c)
match_string? ([c.name] + c.addresses.to_a).compact
end
end
def self.compile(q)
qs = StringScanner.new(q)
qtree = AndMatch.new
until qs.eos?
res =
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
qtree << res
qs.scan(/\s+/)
end
qtree
end
end
end
|