keyword_search_yjchen 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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