keyword_search_yjchen 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,112 @@
1
+ require File.dirname(__FILE__) << '/keyword_search/definition.rb'
2
+
3
+ module KeywordSearch
4
+
5
+ class ParseError < ::SyntaxError; end
6
+
7
+ class << self
8
+
9
+ %%{
10
+
11
+ machine parser;
12
+
13
+ action start {
14
+ tokstart = p;
15
+ }
16
+
17
+ action key {
18
+ key = word
19
+ results[key] ||= []
20
+ }
21
+
22
+ action default {
23
+ key = nil
24
+ }
25
+
26
+ action word {
27
+ word = data[tokstart..p-1]
28
+ }
29
+
30
+ action value {
31
+ (results[key || :default] ||= []) << [ word, positive_match ]
32
+ }
33
+
34
+ action negative_match {
35
+ positive_match = false
36
+ }
37
+
38
+ action positive_match {
39
+ positive_match = true
40
+ }
41
+
42
+ action quote { quotes += 1 }
43
+
44
+ action unquote { quotes -= 1 }
45
+
46
+ seperators = ' '+ | / *[,|] */ ;
47
+
48
+ bareword = ( [^ '"(:] . [^ "):]* ) > start % word ; # allow apostrophes
49
+ dquoted = '"' @ quote ( [^"]* > start % word ) :>> '"' @ unquote;
50
+ squoted = '\'' @ quote ( [^']* > start % word ) :>> '\'' @ unquote;
51
+
52
+ anyword = dquoted | squoted | bareword ;
53
+
54
+ anyvalue = anyword % value ;
55
+ multivalues = anyvalue ( seperators anyvalue )* ;
56
+ groupedvalues = '(' @ quote multivalues :>> ')' @ unquote;
57
+
58
+ value = groupedvalues | anyvalue ;
59
+
60
+ pair = bareword % key ':' value ;
61
+
62
+ value_only = value > default ;
63
+
64
+ match_mode = ('-' % negative_match | '+'? % positive_match ) ;
65
+
66
+ definition = match_mode? <: ( pair | value_only ) ;
67
+
68
+ definitions = definition ( ' '+ definition )*;
69
+
70
+ main := ' '* definitions? ' '* 0
71
+ @!{ raise ParseError, "At offset #{p}, near: '#{data[p,10]}'" };
72
+
73
+ }%%
74
+
75
+ def search(input_string, definition=nil, &block)
76
+ definition ||= Definition.new(&block)
77
+ results = parse(input_string)
78
+ results.each do |key, terms|
79
+ definition.handle(key, terms)
80
+ end
81
+ results
82
+ end
83
+
84
+ #######
85
+ private
86
+ #######
87
+
88
+ def parse(input) #:nodoc:
89
+ data = input + ' '
90
+ %% write data;
91
+ p = 0
92
+ eof = nil
93
+ word = nil
94
+ pe = data.length
95
+ key = nil
96
+ positive_match = nil
97
+ tokstart = nil
98
+ results = {}
99
+ quotes = 0
100
+ %% write init;
101
+ %% write exec;
102
+ unless quotes.zero?
103
+ raise ParseError, "Unclosed quotes"
104
+ end
105
+ results
106
+ end
107
+
108
+ end
109
+
110
+ end
111
+
112
+
@@ -0,0 +1,336 @@
1
+ require 'minitest/spec'
2
+ require 'minitest/autorun'
3
+
4
+ require File.dirname(__FILE__) + '/../lib/keyword_search'
5
+
6
+ describe "KeywordSearch" do
7
+
8
+ NAME_AND_AGE = %<bruce williams age:26>
9
+ NAME_QUOTED_AND_AGE = %<"bruce williams" age:26>
10
+ NAME_AND_QUOTED_AGE = %<bruce williams age:"26">
11
+ DEFAULT_AGE_WITH_QUOTED_AGE = %<26 name:"bruce williams">
12
+ DEFAULT_AGE_WITH_SINGLE_QUOTED_AGE = %<26 name:'bruce williams'>
13
+ NAME_WITH_NESTED_SINGLE_QUOTES = %<"d'arcy d'uberville" age:28>
14
+ NAME_AND_GROUPED_AGE = %<coda hale age:(27)>
15
+ NAME_AND_GROUPED_QUOTED_AGE = %<coda hale age:("27")>
16
+ NAME_AND_GROUPED_QUOTED_AGES = %<coda hale age:("27" 34 '48')>
17
+ GROUPED_NAMES_AND_AGE = %<(coda bruce 'hale' "williams") age:20>
18
+
19
+ it "default keyword" do
20
+ result = nil
21
+ KeywordSearch.search(NAME_AND_AGE) do |with|
22
+ with.default_keyword :name
23
+ with.keyword :name do |values|
24
+ result = values.join(' ')
25
+ end
26
+ end
27
+ result.must_equal 'bruce williams'
28
+ assert_equal 'bruce williams', result
29
+ end
30
+
31
+ it "grouped default keywords" do
32
+ result = nil
33
+ KeywordSearch.search(GROUPED_NAMES_AND_AGE) do |with|
34
+ with.default_keyword :name
35
+ with.keyword :name do |values|
36
+ result = values
37
+ end
38
+ end
39
+ assert_equal ['coda', 'bruce', 'hale', 'williams'], result
40
+ end
41
+
42
+ it "unquoted keyword term" do
43
+ result = nil
44
+ KeywordSearch.search(NAME_AND_AGE) do |with|
45
+ with.keyword :age do |values|
46
+ result = Integer(values.first)
47
+ end
48
+ end
49
+ assert_equal 26, result
50
+ end
51
+
52
+ it "unquoted grouped keyword term" do
53
+ result = nil
54
+ KeywordSearch.search(NAME_AND_GROUPED_AGE) do |with|
55
+ with.keyword :age do |values|
56
+ result = Integer(values.first)
57
+ end
58
+ end
59
+ assert_equal 27, result
60
+ end
61
+
62
+ it "quoted grouped keyword term" do
63
+ result = nil
64
+ KeywordSearch.search(NAME_AND_GROUPED_QUOTED_AGE) do |with|
65
+ with.keyword :age do |values|
66
+ result = Integer(values.first)
67
+ end
68
+ end
69
+ assert_equal 27, result
70
+ end
71
+
72
+ it "mixed grouped keyword terms" do
73
+ result = nil
74
+ KeywordSearch.search(NAME_AND_GROUPED_QUOTED_AGES) do |with|
75
+ with.keyword :age do |values|
76
+ result = values.map { |v| v.to_i }
77
+ end
78
+ end
79
+ assert_equal [27, 34, 48], result
80
+ end
81
+
82
+ it "quoted default keyword term" do
83
+ result = nil
84
+ KeywordSearch.search(NAME_QUOTED_AND_AGE) do |with|
85
+ with.default_keyword :name
86
+ with.keyword :name do |values|
87
+ result = values.join(' ')
88
+ end
89
+ end
90
+ assert_equal 'bruce williams', result
91
+ end
92
+
93
+ it "quoted keyword term" do
94
+ result = nil
95
+ KeywordSearch.search(NAME_AND_QUOTED_AGE) do |with|
96
+ with.keyword :age do |values|
97
+ result = Integer(values.first)
98
+ end
99
+ end
100
+ assert_equal 26, result
101
+ end
102
+
103
+ it "quoted keyword term with whitespace" do
104
+ result = nil
105
+ KeywordSearch.search(DEFAULT_AGE_WITH_QUOTED_AGE) do |with|
106
+ with.default_keyword :age
107
+ with.keyword :name do |values|
108
+ result = values.first
109
+ end
110
+ end
111
+ assert_equal 'bruce williams', result
112
+ end
113
+
114
+ it "single quoted keyword term with whitespace" do
115
+ result = nil
116
+ r = KeywordSearch.search(DEFAULT_AGE_WITH_SINGLE_QUOTED_AGE) do |with|
117
+ with.default_keyword :age
118
+ with.keyword :name do |values|
119
+ result = values.first
120
+ end
121
+ end
122
+ assert_equal 'bruce williams', result
123
+ end
124
+
125
+ it "nested single quote is accumulated" do
126
+ result = nil
127
+ KeywordSearch.search(NAME_WITH_NESTED_SINGLE_QUOTES) do |with|
128
+ with.default_keyword :name
129
+ with.keyword :name do |values|
130
+ result = values.first
131
+ end
132
+ end
133
+ assert_equal %<d'arcy d'uberville>, result
134
+ end
135
+
136
+ it "nested double quote is accumulated" do
137
+ result = nil
138
+ KeywordSearch.search(%<'he was called "jake"'>) do |with|
139
+ with.default_keyword :text
140
+ with.keyword :text do |values|
141
+ result = values.first
142
+ end
143
+ end
144
+ assert_equal %<he was called "jake">, result
145
+ end
146
+
147
+ it "bare single quote in unquoted literal is accumulated" do
148
+ result = nil
149
+ KeywordSearch.search(%<bruce's age:27>) do |with|
150
+ with.default_keyword :text
151
+ with.keyword :text do |values|
152
+ result = values.first
153
+ end
154
+ end
155
+ assert_equal %<bruce's>, result
156
+ end
157
+
158
+ it "single quoted literal is accumulated" do
159
+ result = nil
160
+ KeywordSearch.search(%<foo 'bruce williams' age:27>) do |with|
161
+ with.default_keyword :text
162
+ with.keyword :text do |values|
163
+ result = values.last
164
+ end
165
+ end
166
+ assert_equal %<bruce williams>, result
167
+ end
168
+
169
+ it "period in literal is accumulated" do
170
+ result = nil
171
+ KeywordSearch.search(%<okay... age:27>) do |with|
172
+ with.default_keyword :text
173
+ with.keyword :text do |values|
174
+ result = values.first
175
+ end
176
+ end
177
+ assert_equal %<okay...>, result
178
+ end
179
+
180
+ it "parse error results in exception" do
181
+ assert_raises(KeywordSearch::ParseError) do
182
+ KeywordSearch.search(%<we_do_not_allow:! or ::>) do |with|
183
+ with.default_keyword :text
184
+ with.keyword :text do |values|
185
+ result = values.first
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ it "can use apostrophes in unquoted literal" do
192
+ result = nil
193
+ KeywordSearch.search(%<d'correct>) do |with|
194
+ with.default_keyword :text
195
+ with.keyword :text do |values|
196
+ result = values.first
197
+ end
198
+ end
199
+ assert_equal "d'correct", result
200
+ end
201
+
202
+ it "can use apostrophes in unquoted literal values" do
203
+ result = nil
204
+ KeywordSearch.search(%<text:d'correct>) do |with|
205
+ with.default_keyword :text
206
+ with.keyword :text do |values|
207
+ result = values.first
208
+ end
209
+ end
210
+ assert_equal "d'correct", result
211
+ end
212
+
213
+ it "cannot use an apostrophe at the beginning on an unquoted literal" do
214
+ assert_raises(KeywordSearch::ParseError) do
215
+ KeywordSearch.search(%<'thisiswrong>) do |with|
216
+ with.default_keyword :text
217
+ with.keyword :text do |values|
218
+ result = values.first
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ it "keywords are case sensitive" do
225
+ result = nil
226
+ KeywordSearch.search(%<Text:justtesting>) do |with|
227
+ with.keyword :text do |values|
228
+ result = :small
229
+ end
230
+ with.keyword :Text do |values|
231
+ result = :big
232
+ end
233
+ end
234
+ assert_equal :big, result
235
+ end
236
+
237
+ it "values are case sensitive" do
238
+ result = nil
239
+ KeywordSearch.search(%<text:Big>) do |with|
240
+ with.keyword :text do |values|
241
+ result = values.first
242
+ end
243
+ end
244
+ assert_equal 'Big', result
245
+ end
246
+
247
+ it "spaces are condensed" do
248
+ result = nil
249
+ KeywordSearch.search(%< this is some text >) do |with|
250
+ with.default_keyword :text
251
+ with.keyword :text do |values|
252
+ result = values
253
+ end
254
+ end
255
+ assert_equal %w(this is some text), result
256
+ end
257
+
258
+ it "an empty search is successful" do
259
+ result = nil
260
+ KeywordSearch.search(%<>) do |with|
261
+ with.default_keyword :text
262
+ with.keyword :text do |values|
263
+ result = values
264
+ end
265
+ end
266
+ assert_nil result
267
+ end
268
+
269
+ it 'a negative search' do
270
+ result = nil
271
+
272
+ KeywordSearch.search(%<-site:google.com>) do |with|
273
+ with.keyword :site do |values, positive|
274
+ result = [ values, positive ]
275
+ end
276
+ end
277
+ assert_equal [ [ 'google.com' ], false ], result
278
+ end
279
+
280
+ it 'a positive search' do
281
+ result = nil
282
+
283
+ KeywordSearch.search(%<+site:google.com>) do |with|
284
+ with.keyword :site do |values, positive|
285
+ result = [ values, positive ]
286
+ end
287
+ end
288
+ assert_equal [ [ 'google.com' ], true ], result
289
+ end
290
+
291
+ it 'a search with no sign' do
292
+ result = nil
293
+
294
+ KeywordSearch.search(%<site:google.com>) do |with|
295
+ with.keyword :site do |values, positive|
296
+ result = [ values, positive ]
297
+ end
298
+ end
299
+ assert_equal [ [ 'google.com' ], true ], result
300
+ end
301
+
302
+ it 'a term should default to positive with no sign' do
303
+ result = nil
304
+
305
+ KeywordSearch.search(%<-site:google.com inurl:atom>) do |with|
306
+ with.keyword :inurl do |values, positive|
307
+ result = [ values, positive ]
308
+ end
309
+ end
310
+ assert_equal [ %w(atom), true ], result
311
+ end
312
+
313
+ it 'a negative and positive search to the default keyword' do
314
+ result = []
315
+
316
+ KeywordSearch.search(%<text -google.com search>) do |with|
317
+ with.default_keyword :text
318
+ with.keyword :text do |values, positive|
319
+ result << [ values, positive ]
320
+ end
321
+ end
322
+ assert_equal [ [ %w(text search), true ], [ %w(google.com), false ] ], result
323
+ end
324
+
325
+ it 'a negative search to the default keyword with quotes' do
326
+ result = []
327
+
328
+ KeywordSearch.search(%<-google.com>) do |with|
329
+ with.default_keyword :text
330
+ with.keyword :text do |values, positive|
331
+ result << [ values, positive ]
332
+ end
333
+ end
334
+ assert_equal [ [ %w(google.com), false ] ], result
335
+ end
336
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: keyword_search_yjchen
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Bruce Williams
8
+ - Eric Lindvall
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: '1.3'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: '1.3'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ description:
43
+ email:
44
+ - brwcodes@gmail.com
45
+ - eric@sevenscale.com
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - .gitignore
51
+ - .travis.yml
52
+ - Gemfile
53
+ - LICENSE
54
+ - Manifest
55
+ - README.md
56
+ - Rakefile
57
+ - keyword_search.gemspec
58
+ - lib/keyword_search.rb
59
+ - lib/keyword_search.rl
60
+ - lib/keyword_search/definition.rb
61
+ - lib/keyword_search/version.rb
62
+ - test/test_keyword_search.rb
63
+ homepage: http://github.com/bruce/keyword_search
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options:
69
+ - --charset=UTF-8
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 2.0.3
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: Generic library to parse GMail-style search strings for keyword/value pairs;
88
+ supports definition of valid keywords and handling of quoted values.
89
+ test_files:
90
+ - test/test_keyword_search.rb