keyword_search 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,11 @@
1
+ = 1.3.0 / 2007-10-09
2
+
3
+ * Conversion to Ragel-based parser (faster, less resource-intensive)
4
+ * Better support for other character sets, allow apostrophes in
5
+ unquoted words
6
+ * Test suite now uses test/spec
7
+ * API Should be backwards compatible
8
+
1
9
  = 1.2.0 / 2007-05-09
2
10
 
3
11
  * Raises KeywordSearch::ParseError instead of returning an empty Hash if an error occurs during parsing
data/Manifest.txt CHANGED
@@ -3,9 +3,6 @@ Manifest.txt
3
3
  README.txt
4
4
  Rakefile
5
5
  lib/keyword_search.rb
6
+ lib/keyword_search.rl
6
7
  lib/keyword_search/definition.rb
7
- lib/keyword_search/evaluator.rb
8
- lib/keyword_search/grammar.rb
9
- lib/keyword_search/parser.rb
10
- lib/keyword_search/tokenizer.rb
11
8
  test/test_keyword_search.rb
data/README.txt CHANGED
@@ -17,8 +17,6 @@ Various notes:
17
17
  * Input is automatically downcased (both keywords and values should be assumed to be in lowercase)
18
18
 
19
19
  Development Roadmap:
20
- 1.1:: Expand supported character set for keywords and values
21
- (currently supports a-z)
22
20
  2.0:: Add negation and grouping (will break API backwards compatibility)
23
21
 
24
22
  == SYNOPSIS:
@@ -59,7 +57,6 @@ Here's an example of usage from Rails (though the library is generic, and could
59
57
 
60
58
  == REQUIREMENTS:
61
59
 
62
- * dhaka
63
60
  * hoe
64
61
 
65
62
  == INSTALL:
data/Rakefile CHANGED
@@ -2,9 +2,8 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
- require './lib/keyword_search.rb'
6
5
 
7
- Hoe.new('keyword_search', KeywordSearch::VERSION) do |p|
6
+ Hoe.new('keyword_search', '1.3.0') do |p|
8
7
  p.rubyforge_name = 'codefluency'
9
8
  p.summary = 'Generic support for extracting GMail-style search keywords/values from strings'
10
9
  p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
@@ -12,31 +11,10 @@ Hoe.new('keyword_search', KeywordSearch::VERSION) do |p|
12
11
  p.author = 'Bruce Williams'
13
12
  p.email = 'bruce@codefluency.com'
14
13
  p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
15
- p.extra_deps = [['dhaka', '= 2.1.0']]
16
14
  end
17
15
 
18
- task :rebuild_parser do
19
- require 'dhaka'
20
- parser = Dhaka::Parser.new(KeywordSearch::Grammar)
21
- File.open('lib/keyword_search/parser.rb', 'w') do |file|
22
- file << parser.compile_to_ruby_source_as('KeywordSearch::Parser')
23
- end
16
+ rule '.rb' => '.rl' do |t|
17
+ sh "ragel -R #{t.source} | rlgen-ruby -o #{t.name}"
24
18
  end
25
19
 
26
- task :rebuild_lexer do
27
- require 'dhaka'
28
- lexer = Dhaka::Lexer.new(KeywordSearch::LexerSpec)
29
- File.open('lib/keyword_search/lexer.rb', 'w') do |file|
30
- file << lexer.compile_to_ruby_source_as('KeywordSearch::Lexer')
31
- end
32
- end
33
-
34
- task :rebuild_lexer do
35
- require 'dhaka'
36
- lexer = Dhaka::Lexer.new(KeywordSearch::LexerSpec)
37
- File.open('lib/keyword_search/lexer.rb', 'w') do |file|
38
- file << lexer.compile_to_ruby_source_as('KeywordSearch::Lexer')
39
- end
40
- end
41
-
42
- # vim: syntax=Ruby
20
+ task :ragel => 'lib/keyword_search.rb'
@@ -1,31 +1,265 @@
1
- require 'dhaka'
2
-
3
- dirname = File.join(File.dirname(__FILE__), 'keyword_search')
4
- %w|grammar parser lexer_spec lexer evaluator definition|.each do |dependency|
5
- require File.join(dirname, dependency)
6
- end
1
+ # line 1 "lib/keyword_search.rl"
2
+ require File.dirname(__FILE__) << '/keyword_search/definition.rb'
7
3
 
8
4
  module KeywordSearch
9
-
10
- class ParseError < ::SyntaxError; end
11
-
12
- VERSION = '1.2.0'
13
-
5
+
6
+ class ParseError < ::SyntaxError; end
7
+
14
8
  class << self
9
+
10
+ # line 44 "lib/keyword_search.rl"
11
+
15
12
  def search(input_string, definition=nil, &block)
16
- @evaluator ||= Evaluator.new
17
13
  definition ||= Definition.new(&block)
18
- parse_result = Parser.parse(Lexer.lex(input_string))
19
- unless parse_result.has_error?
20
- results = @evaluator.evaluate(parse_result.parse_tree)
21
- results.each do |key, terms|
22
- definition.handle(key, terms)
23
- end
24
- results
25
- else
26
- raise ParseError, "Unexpected token #{parse_result.unexpected_token.inspect}"
14
+ results = parse(input_string)
15
+ results.each do |key, terms|
16
+ definition.handle(key, terms)
27
17
  end
18
+ results
19
+ end
20
+
21
+ #######
22
+ private
23
+ #######
24
+
25
+ def parse(input) #:nodoc:
26
+ data = input + ' '
27
+
28
+ # line 30 "lib/keyword_search.rb"
29
+ class << self
30
+ attr_accessor :_parser_actions
31
+ private :_parser_actions, :_parser_actions=
32
+ end
33
+ self._parser_actions = [
34
+ 0, 1, 3, 1, 4, 2, 0, 2,
35
+ 2, 1, 0
36
+ ]
37
+
38
+ class << self
39
+ attr_accessor :_parser_key_offsets
40
+ private :_parser_key_offsets, :_parser_key_offsets=
41
+ end
42
+ self._parser_key_offsets = [
43
+ 0, 0, 5, 8, 12, 15, 16, 17,
44
+ 18
45
+ ]
46
+
47
+ class << self
48
+ attr_accessor :_parser_trans_keys
49
+ private :_parser_trans_keys, :_parser_trans_keys=
50
+ end
51
+ self._parser_trans_keys = [
52
+ 0, 32, 34, 39, 58, 32, 34, 58,
53
+ 32, 34, 39, 58, 32, 34, 58, 34,
54
+ 32, 39, 32, 34, 58, 0
55
+ ]
56
+
57
+ class << self
58
+ attr_accessor :_parser_single_lengths
59
+ private :_parser_single_lengths, :_parser_single_lengths=
60
+ end
61
+ self._parser_single_lengths = [
62
+ 0, 5, 3, 4, 3, 1, 1, 1,
63
+ 3
64
+ ]
65
+
66
+ class << self
67
+ attr_accessor :_parser_range_lengths
68
+ private :_parser_range_lengths, :_parser_range_lengths=
69
+ end
70
+ self._parser_range_lengths = [
71
+ 0, 0, 0, 0, 0, 0, 0, 0,
72
+ 0
73
+ ]
74
+
75
+ class << self
76
+ attr_accessor :_parser_index_offsets
77
+ private :_parser_index_offsets, :_parser_index_offsets=
78
+ end
79
+ self._parser_index_offsets = [
80
+ 0, 0, 6, 10, 15, 19, 21, 23,
81
+ 25
82
+ ]
83
+
84
+ class << self
85
+ attr_accessor :_parser_trans_targs_wi
86
+ private :_parser_trans_targs_wi, :_parser_trans_targs_wi=
87
+ end
88
+ self._parser_trans_targs_wi = [
89
+ 8, 0, 5, 7, 0, 2, 1, 0,
90
+ 3, 2, 0, 5, 7, 0, 4, 1,
91
+ 0, 0, 4, 6, 5, 1, 0, 6,
92
+ 7, 1, 0, 3, 2, 0
93
+ ]
94
+
95
+ class << self
96
+ attr_accessor :_parser_trans_actions_wi
97
+ private :_parser_trans_actions_wi, :_parser_trans_actions_wi=
98
+ end
99
+ self._parser_trans_actions_wi = [
100
+ 5, 3, 5, 5, 3, 5, 1, 0,
101
+ 0, 0, 0, 8, 8, 0, 8, 1,
102
+ 0, 0, 0, 0, 0, 1, 0, 0,
103
+ 0, 1, 0, 0, 0, 0
104
+ ]
105
+
106
+ class << self
107
+ attr_accessor :parser_start
108
+ end
109
+ self.parser_start = 1;
110
+ class << self
111
+ attr_accessor :parser_first_final
112
+ end
113
+ self.parser_first_final = 8;
114
+ class << self
115
+ attr_accessor :parser_error
116
+ end
117
+ self.parser_error = 0;
118
+
119
+ class << self
120
+ attr_accessor :parser_en_main
121
+ end
122
+ self.parser_en_main = 1;
123
+
124
+ # line 62 "lib/keyword_search.rl"
125
+ p = 0
126
+ pe = data.length
127
+ key = nil
128
+ tokstart = nil
129
+ results = {}
130
+
131
+ # line 133 "lib/keyword_search.rb"
132
+ begin
133
+ p ||= 0
134
+ pe ||= data.length
135
+ cs = parser_start
136
+ end
137
+ # line 68 "lib/keyword_search.rl"
138
+
139
+ # line 141 "lib/keyword_search.rb"
140
+ begin
141
+ _klen, _trans, _keys, _acts, _nacts = nil
142
+ if p != pe
143
+ if cs != 0
144
+ while true
145
+ _break_resume = false
146
+ begin
147
+ _break_again = false
148
+ _keys = _parser_key_offsets[cs]
149
+ _trans = _parser_index_offsets[cs]
150
+ _klen = _parser_single_lengths[cs]
151
+ _break_match = false
152
+
153
+ begin
154
+ if _klen > 0
155
+ _lower = _keys
156
+ _upper = _keys + _klen - 1
157
+
158
+ loop do
159
+ break if _upper < _lower
160
+ _mid = _lower + ( (_upper - _lower) >> 1 )
161
+
162
+ if data[p] < _parser_trans_keys[_mid]
163
+ _upper = _mid - 1
164
+ elsif data[p] > _parser_trans_keys[_mid]
165
+ _lower = _mid + 1
166
+ else
167
+ _trans += (_mid - _keys)
168
+ _break_match = true
169
+ break
170
+ end
171
+ end # loop
172
+ break if _break_match
173
+ _keys += _klen
174
+ _trans += _klen
175
+ end
176
+ _klen = _parser_range_lengths[cs]
177
+ if _klen > 0
178
+ _lower = _keys
179
+ _upper = _keys + (_klen << 1) - 2
180
+ loop do
181
+ break if _upper < _lower
182
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1)
183
+ if data[p] < _parser_trans_keys[_mid]
184
+ _upper = _mid - 2
185
+ elsif data[p] > _parser_trans_keys[_mid+1]
186
+ _lower = _mid + 2
187
+ else
188
+ _trans += ((_mid - _keys) >> 1)
189
+ _break_match = true
190
+ break
191
+ end
192
+ end # loop
193
+ break if _break_match
194
+ _trans += _klen
195
+ end
196
+ end while false
197
+ cs = _parser_trans_targs_wi[_trans]
198
+ break if _parser_trans_actions_wi[_trans] == 0
199
+ _acts = _parser_trans_actions_wi[_trans]
200
+ _nacts = _parser_actions[_acts]
201
+ _acts += 1
202
+ while _nacts > 0
203
+ _nacts -= 1
204
+ _acts += 1
205
+ case _parser_actions[_acts - 1]
206
+ when 0:
207
+ # line 13 "lib/keyword_search.rl"
208
+ begin
209
+
210
+ tokstart = p;
211
+ end
212
+ # line 13 "lib/keyword_search.rl"
213
+ when 1:
214
+ # line 17 "lib/keyword_search.rl"
215
+ begin
216
+
217
+ key = data[tokstart...p-1]
218
+ results[key] ||= []
219
+ end
220
+ # line 17 "lib/keyword_search.rl"
221
+ when 2:
222
+ # line 22 "lib/keyword_search.rl"
223
+ begin
224
+
225
+ key = nil
226
+ end
227
+ # line 22 "lib/keyword_search.rl"
228
+ when 3:
229
+ # line 26 "lib/keyword_search.rl"
230
+ begin
231
+
232
+ value = data[tokstart..p-1]
233
+ value = value[1..-2] if ["'", '"'].include?(value[0,1])
234
+ (results[key || :default] ||= []) << value
235
+ end
236
+ # line 26 "lib/keyword_search.rl"
237
+ when 4:
238
+ # line 42 "lib/keyword_search.rl"
239
+ begin
240
+ raise ParseError, "At offset #{p}, near: '#{data[p,10]}'" end
241
+ # line 42 "lib/keyword_search.rl"
242
+ # line 244 "lib/keyword_search.rb"
243
+ end # action switch
244
+ end
245
+ end while false
246
+ break if _break_resume
247
+ break if cs == 0
248
+ p += 1
249
+ break if p == pe
250
+ end
251
+ end
252
+ end
253
+ end
254
+ # line 69 "lib/keyword_search.rl"
255
+
256
+ # line 258 "lib/keyword_search.rb"
257
+ # line 70 "lib/keyword_search.rl"
258
+ results
28
259
  end
260
+
29
261
  end
30
262
 
31
- end
263
+ end
264
+
265
+
@@ -0,0 +1,85 @@
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 = data[tokstart...p-1]
19
+ results[key] ||= []
20
+ }
21
+
22
+ action default {
23
+ key = nil
24
+ }
25
+
26
+ action value {
27
+ value = data[tokstart..p-1]
28
+ value = value[1..-2] if ["'", '"'].include?(value[0,1])
29
+ (results[key || :default] ||= []) << value
30
+ }
31
+
32
+ action quote { quotes += 1 }
33
+
34
+ action unquote { quotes -= 1 }
35
+
36
+ bareword = [^ '":] [^ ":]*; # allow apostrophes
37
+ dquoted = '"' @ quote any* :>> '"' @ unquote;
38
+ squoted = '\'' @ quote any* :>> '\'' @ unquote;
39
+
40
+ value = ( dquoted | squoted | bareword );
41
+
42
+ pair = (bareword > start ':') % key value > start % value ;
43
+
44
+ definition = ( pair | value > start > default % value) ' ';
45
+ main := definition** 0
46
+ @!{ raise ParseError, "At offset #{p}, near: '#{data[p,10]}'" };
47
+
48
+ }%%
49
+
50
+ def search(input_string, definition=nil, &block)
51
+ definition ||= Definition.new(&block)
52
+ results = parse(input_string)
53
+ results.each do |key, terms|
54
+ definition.handle(key, terms)
55
+ end
56
+ results
57
+ end
58
+
59
+ #######
60
+ private
61
+ #######
62
+
63
+ def parse(input) #:nodoc:
64
+ data = input + ' '
65
+ %% write data;
66
+ p = 0
67
+ pe = data.length
68
+ key = nil
69
+ tokstart = nil
70
+ results = {}
71
+ quotes = 0
72
+ %% write init;
73
+ %% write exec;
74
+ %% write eof;
75
+ unless quotes.zero?
76
+ raise ParseError, "Unclosed quotes"
77
+ end
78
+ results
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+
@@ -4,28 +4,29 @@ module KeywordSearch
4
4
 
5
5
  class Keyword
6
6
 
7
- attr_reader :name, :description
8
-
7
+ attr_reader :name, :description, :handler
9
8
  def initialize(name, description=nil, &handler)
10
9
  @name, @description = name, description
11
10
  @handler = handler
12
11
  end
13
12
 
14
13
  def handle(value)
15
- @handler.call(value)
14
+ handler.call(value)
16
15
  end
17
16
 
18
17
  end
19
18
 
20
- attr_reader :keywords
21
19
  def initialize
22
- @keywords = []
23
20
  @default_keyword = nil
24
21
  yield self if block_given?
25
22
  end
23
+
24
+ def keywords
25
+ @keywords ||= []
26
+ end
26
27
 
27
28
  def keyword(name, description=nil, &block)
28
- @keywords << Keyword.new(name, description, &block)
29
+ keywords << Keyword.new(name, description, &block)
29
30
  end
30
31
 
31
32
  def default_keyword(name)
@@ -35,7 +36,7 @@ module KeywordSearch
35
36
  def handle(key, values)
36
37
  key = @default_keyword if key == :default
37
38
  return false unless key
38
- if k = @keywords.detect{|kw| kw.name == key.to_sym}
39
+ if k = keywords.detect { |kw| kw.name == key.to_sym}
39
40
  k.handle(values)
40
41
  end
41
42
  end
@@ -1,7 +1,11 @@
1
1
  require 'test/unit'
2
+
3
+ require 'rubygems' rescue nil
4
+ require 'test/spec'
5
+
2
6
  require File.dirname(__FILE__) + '/../lib/keyword_search'
3
7
 
4
- class TestKeywordSearch < Test::Unit::TestCase
8
+ context "KeywordSearch" do
5
9
 
6
10
  NAME_AND_AGE = %<bruce williams age:26>
7
11
  NAME_QUOTED_AND_AGE = %<"bruce williams" age:26>
@@ -10,7 +14,7 @@ class TestKeywordSearch < Test::Unit::TestCase
10
14
  DEFAULT_AGE_WITH_SINGLE_QUOTED_AGE = %<26 name:'bruce williams'>
11
15
  NAME_WITH_NESTED_SINGLE_QUOTES = %<"d'arcy d'uberville" age:28>
12
16
 
13
- def test_default_keyword
17
+ specify "default keyword" do
14
18
  result = nil
15
19
  KeywordSearch.search(NAME_AND_AGE) do |with|
16
20
  with.default_keyword :name
@@ -21,7 +25,7 @@ class TestKeywordSearch < Test::Unit::TestCase
21
25
  assert_equal 'bruce williams', result
22
26
  end
23
27
 
24
- def test_unquoted_keyword_term
28
+ specify "unquoted keyword term" do
25
29
  result = nil
26
30
  KeywordSearch.search(NAME_AND_AGE) do |with|
27
31
  with.keyword :age do |values|
@@ -31,7 +35,7 @@ class TestKeywordSearch < Test::Unit::TestCase
31
35
  assert_equal 26, result
32
36
  end
33
37
 
34
- def test_quoted_default_keyword_term
38
+ specify "quoted default keyword term" do
35
39
  result = nil
36
40
  KeywordSearch.search(NAME_QUOTED_AND_AGE) do |with|
37
41
  with.default_keyword :name
@@ -42,7 +46,7 @@ class TestKeywordSearch < Test::Unit::TestCase
42
46
  assert_equal 'bruce williams', result
43
47
  end
44
48
 
45
- def test_quoted_keyword_term
49
+ specify "quoted keyword term" do
46
50
  result = nil
47
51
  KeywordSearch.search(NAME_AND_QUOTED_AGE) do |with|
48
52
  with.keyword :age do |values|
@@ -52,7 +56,7 @@ class TestKeywordSearch < Test::Unit::TestCase
52
56
  assert_equal 26, result
53
57
  end
54
58
 
55
- def test_quoted_keyword_term_with_whitespace
59
+ specify "quoted keyword term with whitespace" do
56
60
  result = nil
57
61
  KeywordSearch.search(DEFAULT_AGE_WITH_QUOTED_AGE) do |with|
58
62
  with.default_keyword :age
@@ -63,9 +67,9 @@ class TestKeywordSearch < Test::Unit::TestCase
63
67
  assert_equal 'bruce williams', result
64
68
  end
65
69
 
66
- def test_single_quoted_keyword_term_with_whitespace
67
- result = nil
68
- KeywordSearch.search(DEFAULT_AGE_WITH_SINGLE_QUOTED_AGE) do |with|
70
+ specify "single quoted keyword term with whitespace" do
71
+ result = nil
72
+ r = KeywordSearch.search(DEFAULT_AGE_WITH_SINGLE_QUOTED_AGE) do |with|
69
73
  with.default_keyword :age
70
74
  with.keyword :name do |values|
71
75
  result = values.first
@@ -74,7 +78,7 @@ class TestKeywordSearch < Test::Unit::TestCase
74
78
  assert_equal 'bruce williams', result
75
79
  end
76
80
 
77
- def test_nested_single_quote_is_accumulated
81
+ specify "nested single quote is accumulated" do
78
82
  result = nil
79
83
  KeywordSearch.search(NAME_WITH_NESTED_SINGLE_QUOTES) do |with|
80
84
  with.default_keyword :name
@@ -85,7 +89,7 @@ class TestKeywordSearch < Test::Unit::TestCase
85
89
  assert_equal %<d'arcy d'uberville>, result
86
90
  end
87
91
 
88
- def test_nested_double_quote_is_accumulated
92
+ specify "nested double quote is accumulated" do
89
93
  result = nil
90
94
  KeywordSearch.search(%<'he was called "jake"'>) do |with|
91
95
  with.default_keyword :text
@@ -96,7 +100,7 @@ class TestKeywordSearch < Test::Unit::TestCase
96
100
  assert_equal %<he was called "jake">, result
97
101
  end
98
102
 
99
- def test_bare_single_quote_in_unquoted_literal_is_accumulated
103
+ specify "bare single quote in unquoted literal is accumulated" do
100
104
  result = nil
101
105
  KeywordSearch.search(%<bruce's age:27>) do |with|
102
106
  with.default_keyword :text
@@ -107,7 +111,7 @@ class TestKeywordSearch < Test::Unit::TestCase
107
111
  assert_equal %<bruce's>, result
108
112
  end
109
113
 
110
- def test_single_quoted_literal_is_accumulated
114
+ specify "single quoted literal is accumulated" do
111
115
  result = nil
112
116
  KeywordSearch.search(%<foo 'bruce williams' age:27>) do |with|
113
117
  with.default_keyword :text
@@ -118,7 +122,7 @@ class TestKeywordSearch < Test::Unit::TestCase
118
122
  assert_equal %<bruce williams>, result
119
123
  end
120
124
 
121
- def test_period_in_literal_is_accumulated
125
+ specify "period in literal is accumulated" do
122
126
  result = nil
123
127
  KeywordSearch.search(%<okay... age:27>) do |with|
124
128
  with.default_keyword :text
@@ -129,7 +133,7 @@ class TestKeywordSearch < Test::Unit::TestCase
129
133
  assert_equal %<okay...>, result
130
134
  end
131
135
 
132
- def test_parse_error_results_in_exception
136
+ specify "parse error results in exception" do
133
137
  assert_raises(KeywordSearch::ParseError) do
134
138
  KeywordSearch.search(%<we_do_not_allow:! or ::>) do |with|
135
139
  with.default_keyword :text
@@ -140,6 +144,38 @@ class TestKeywordSearch < Test::Unit::TestCase
140
144
  end
141
145
  end
142
146
 
147
+ specify "can use apostrophes in unquoted literal" do
148
+ result = nil
149
+ KeywordSearch.search(%<d'correct>) do |with|
150
+ with.default_keyword :text
151
+ with.keyword :text do |values|
152
+ result = values.first
153
+ end
154
+ end
155
+ assert_equal "d'correct", result
156
+ end
157
+
158
+ specify "can use apostrophes in unquoted literal values" do
159
+ result = nil
160
+ KeywordSearch.search(%<text:d'correct>) do |with|
161
+ with.default_keyword :text
162
+ with.keyword :text do |values|
163
+ result = values.first
164
+ end
165
+ end
166
+ assert_equal "d'correct", result
167
+ end
168
+
169
+ specify "cannot use an apostrophe at the beginning on an unquoted literal" do
170
+ assert_raises(KeywordSearch::ParseError) do
171
+ KeywordSearch.search(%<'thisiswrong>) do |with|
172
+ with.default_keyword :text
173
+ with.keyword :text do |values|
174
+ result = values.first
175
+ end
176
+ end
177
+ end
178
+ end
143
179
  end
144
180
 
145
181
 
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
2
+ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: keyword_search
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.2.0
7
- date: 2007-05-09 00:00:00 -06:00
6
+ version: 1.3.0
7
+ date: 2007-10-09 00:00:00 -05:00
8
8
  summary: Generic support for extracting GMail-style search keywords/values from strings
9
9
  require_paths:
10
10
  - lib
11
11
  email: bruce@codefluency.com
12
12
  homepage: " http://codefluency.rubyforge.org/keyword_search"
13
13
  rubyforge_project: codefluency
14
- description: "== FEATURES/PROBLEMS: The library features a very simple, easy-to-use API. * Define handlers for supported keywords with blocks * Define the default keyword (values not part of a keyword/value pair) Various notes: * Quoted values are supported. * Input is automatically downcased (both keywords and values should be assumed to be in lowercase) Development Roadmap: 1.1:: Expand supported character set for keywords and values (currently supports a-z) 2.0:: Add negation and grouping (will break API backwards compatibility) == SYNOPSIS:"
14
+ description: "== FEATURES/PROBLEMS: The library features a very simple, easy-to-use API. * Define handlers for supported keywords with blocks * Define the default keyword (values not part of a keyword/value pair) Various notes: * Quoted values are supported. * Input is automatically downcased (both keywords and values should be assumed to be in lowercase) Development Roadmap: 2.0:: Add negation and grouping (will break API backwards compatibility) == SYNOPSIS:"
15
15
  autorequire:
16
16
  default_executable:
17
17
  bindir: bin
@@ -34,18 +34,18 @@ files:
34
34
  - README.txt
35
35
  - Rakefile
36
36
  - lib/keyword_search.rb
37
+ - lib/keyword_search.rl
37
38
  - lib/keyword_search/definition.rb
38
- - lib/keyword_search/evaluator.rb
39
- - lib/keyword_search/grammar.rb
40
- - lib/keyword_search/parser.rb
41
- - lib/keyword_search/tokenizer.rb
42
39
  - test/test_keyword_search.rb
43
40
  test_files:
44
41
  - test/test_keyword_search.rb
45
- rdoc_options: []
46
-
47
- extra_rdoc_files: []
48
-
42
+ rdoc_options:
43
+ - --main
44
+ - README.txt
45
+ extra_rdoc_files:
46
+ - History.txt
47
+ - Manifest.txt
48
+ - README.txt
49
49
  executables: []
50
50
 
51
51
  extensions: []
@@ -53,15 +53,6 @@ extensions: []
53
53
  requirements: []
54
54
 
55
55
  dependencies:
56
- - !ruby/object:Gem::Dependency
57
- name: dhaka
58
- version_requirement:
59
- version_requirements: !ruby/object:Gem::Version::Requirement
60
- requirements:
61
- - - "="
62
- - !ruby/object:Gem::Version
63
- version: 2.1.0
64
- version:
65
56
  - !ruby/object:Gem::Dependency
66
57
  name: hoe
67
58
  version_requirement:
@@ -69,5 +60,5 @@ dependencies:
69
60
  requirements:
70
61
  - - ">="
71
62
  - !ruby/object:Gem::Version
72
- version: 1.2.0
63
+ version: 1.3.0
73
64
  version:
@@ -1,35 +0,0 @@
1
- module KeywordSearch
2
-
3
- class Evaluator < Dhaka::Evaluator
4
-
5
- self.grammar = Grammar
6
-
7
- define_evaluation_rules do
8
-
9
- for_multiple_pairs do
10
- child_nodes.inject({}) do |result,child_node|
11
- evaluate(child_node).each do |key,value|
12
- result[key] ||= []
13
- result[key] += value
14
- end
15
- result
16
- end
17
- end
18
-
19
- for_one_pair do
20
- evaluate(child_nodes.first)
21
- end
22
-
23
- for_keyword_and_term do
24
- {child_nodes.first.tokens.first.value => [child_nodes.last.tokens.first.value]}
25
- end
26
-
27
- for_default_keyword_term do
28
- {:default => [child_nodes[0].tokens[0].value]}
29
- end
30
-
31
- end
32
-
33
- end
34
-
35
- end
@@ -1,21 +0,0 @@
1
- module KeywordSearch
2
-
3
- class Grammar < Dhaka::Grammar
4
-
5
- for_symbol(Dhaka::START_SYMBOL_NAME) do
6
- start ['Pairs']
7
- end
8
-
9
- for_symbol 'Pairs' do
10
- one_pair ['Pair']
11
- multiple_pairs ['Pairs', 'Pair']
12
- end
13
-
14
- for_symbol 'Pair' do
15
- keyword_and_term ['s', ':', 's']
16
- default_keyword_term ['s']
17
- end
18
-
19
- end
20
-
21
- end
@@ -1,40 +0,0 @@
1
- class KeywordSearch::Parser < Dhaka::CompiledParser
2
-
3
- self.grammar = KeywordSearch::Grammar
4
-
5
- start_with 0
6
-
7
- at_state(1) {
8
- for_symbols("_End_") { reduce_with "start" }
9
- for_symbols("s") { shift_to 3 }
10
- for_symbols("Pair") { shift_to 2 }
11
- }
12
-
13
- at_state(5) {
14
- for_symbols("_End_", "s") { reduce_with "keyword_and_term" }
15
- }
16
-
17
- at_state(4) {
18
- for_symbols("s") { shift_to 5 }
19
- }
20
-
21
- at_state(2) {
22
- for_symbols("_End_", "s") { reduce_with "multiple_pairs" }
23
- }
24
-
25
- at_state(0) {
26
- for_symbols("Pair") { shift_to 6 }
27
- for_symbols("s") { shift_to 3 }
28
- for_symbols("Pairs") { shift_to 1 }
29
- }
30
-
31
- at_state(6) {
32
- for_symbols("_End_", "s") { reduce_with "one_pair" }
33
- }
34
-
35
- at_state(3) {
36
- for_symbols(":") { shift_to 4 }
37
- for_symbols("_End_", "s") { reduce_with "default_keyword_term" }
38
- }
39
-
40
- end
File without changes