picky 4.11.1 → 4.11.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,13 +16,40 @@ module Picky
16
16
  # Gets the weight for this token's text.
17
17
  #
18
18
  def weight token
19
- bundle_for(token).weight token.text
19
+ bundle = bundle_for token
20
+ if range = token.range
21
+ # The math is not perfectly correct, but you
22
+ # get my idea. Also, we could return early.
23
+ #
24
+ # TODO Possible to speed up more?
25
+ #
26
+ range.inject(nil) do |sum, text|
27
+ weight = bundle.weight(text)
28
+ weight && (weight + (sum || 0)) || sum
29
+ end
30
+ else
31
+ bundle.weight token.text
32
+ end
20
33
  end
21
34
 
22
35
  # Gets the ids for this token's text.
23
36
  #
24
37
  def ids token
25
- bundle_for(token).ids token.text
38
+ bundle = bundle_for token
39
+ if range = token.range
40
+ # Adding all to an array, then flattening
41
+ # is faster than using ary + ary.
42
+ #
43
+ range.inject([]) do |result, text|
44
+ # It is 30% faster using the empty check
45
+ # than just << [].
46
+ #
47
+ ids = bundle.ids text
48
+ ids.empty? ? result : result << ids
49
+ end.flatten
50
+ else
51
+ bundle.ids token.text
52
+ end
26
53
  end
27
54
 
28
55
  # Returns the right index bundle for this token.
@@ -34,6 +61,8 @@ module Picky
34
61
  # Returns a combination for the token,
35
62
  # or nil, if there is none.
36
63
  #
64
+ # TODO Don't throw away the weight, instead store it in the combination?
65
+ #
37
66
  def combination_for token
38
67
  weight(token) && Query::Combination.new(token, self)
39
68
  end
@@ -43,6 +43,7 @@ module Picky
43
43
  qualify
44
44
  partialize
45
45
  similarize
46
+ rangify
46
47
  remove_illegals
47
48
  self
48
49
  end
@@ -186,6 +187,27 @@ module Picky
186
187
  redefine_illegals
187
188
  end
188
189
 
190
+ # Define a character which makes a token a range token.
191
+ #
192
+ # Default is '-'.
193
+ #
194
+ # Example:
195
+ # Picky::Query::Token.range_character = "…"
196
+ # try.search("year:2000…2008") # Will find results in a range.
197
+ #
198
+ @@range_character = '-'
199
+ def self.range_character= character
200
+ @@range_character = character
201
+ end
202
+ def rangify
203
+ if @text.include? @@range_character
204
+ @range = Range.new *@text.split(@@range_character, 2)
205
+ end
206
+ end
207
+ def range
208
+ @range
209
+ end
210
+
189
211
  # Is this a "similar" character?
190
212
  #
191
213
  def similar?
@@ -4,11 +4,14 @@ require 'spec_helper'
4
4
 
5
5
  describe 'custom delimiters' do
6
6
 
7
+ # TODO Add range query delimiter.
8
+ #
7
9
  after(:each) do
8
10
  Picky::Query::Token.partial_character = '\*'
9
11
  Picky::Query::Token.no_partial_character = '"'
10
12
  Picky::Query::Token.similar_character = '~'
11
13
  Picky::Query::Token.no_similar_character = '"'
14
+ Picky::Query::Token.range_character = '-'
12
15
  Picky::Query::Token.qualifier_text_delimiter = ':'
13
16
  Picky::Query::Token.qualifiers_delimiter = ','
14
17
  end
@@ -76,4 +79,25 @@ describe 'custom delimiters' do
76
79
  Picky::Query::Token.qualifiers_delimiter = '|'
77
80
  try.search("text1|text2?hello text2?world").ids.should == [1]
78
81
  end
82
+
83
+ it 'offers custom range characters to be set' do
84
+ index = Picky::Index.new :custom_range_character do
85
+ category :year
86
+ end
87
+
88
+ rangy = Struct.new :id, :year
89
+
90
+ index.add rangy.new(1, 1977)
91
+ index.add rangy.new(2, 1989)
92
+ index.add rangy.new(3, 2001)
93
+ index.add rangy.new(4, 2012)
94
+ index.add rangy.new(4, 3000)
95
+
96
+ try = Picky::Search.new index
97
+ try.search("1980-2015").ids.should == [2,3,4]
98
+
99
+ try.search("1980…2015").ids.should == []
100
+ Picky::Query::Token.range_character = "…"
101
+ try.search("1980…2015").ids.should == [2,3,4]
102
+ end
79
103
  end
@@ -0,0 +1,89 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ describe 'range queries' do
6
+
7
+ let(:index) do
8
+ index = Picky::Index.new :range_queries do
9
+ category :year
10
+ category :alphabet
11
+ end
12
+
13
+ rangy = Struct.new :id, :year, :alphabet
14
+
15
+ index.add rangy.new(1, 2000, 'g')
16
+ index.add rangy.new(2, 1977, 'f')
17
+ index.add rangy.new(3, 1989, 'a')
18
+ index.add rangy.new(4, 2011, 'u')
19
+ index.add rangy.new(5, 3000, 'v')
20
+ index.add rangy.new(6, 1291, 'z')
21
+ index.add rangy.new(7, 881, 'm')
22
+ index.add rangy.new(8, 1984, 'l')
23
+
24
+ index
25
+ end
26
+ let(:try) { Picky::Search.new index }
27
+
28
+ it 'still works with exact queries' do
29
+ try.search('1980').ids.should == []
30
+ try.search('1989').ids.should == [3]
31
+ end
32
+
33
+ it 'works with misses' do
34
+ try.search('900-1200').ids.should == []
35
+ end
36
+
37
+ it 'survives huge ranges' do
38
+ try.search('0-10000 a').ids.should == [3]
39
+
40
+ # Quote to make it non-partial.
41
+ #
42
+ try.search('0-3000"').ids.should == [7,6,2,8,3,1,4,5]
43
+ end
44
+ it 'is semi-reasonably fast with huge ranges' do
45
+ # Quote to make it non-partial.
46
+ #
47
+ performance_of { try.search('0-3000"') }.should < 0.21
48
+
49
+ # Note it is much much faster with an additional token.
50
+ #
51
+ performance_of { try.search('0-3000 a') }.should < 0.0085
52
+ end
53
+
54
+ it 'handles basic range queries' do
55
+ try.search('1980-2001').ids.should == [8,3,1]
56
+ try.search('f-u').ids.should == [2,1,8,7,4]
57
+ end
58
+
59
+ it 'can handle qualifiers' do
60
+ try.search('year:1980-2001').ids.should == [8,3,1]
61
+ try.search('alphabet:f-u').ids.should == [2,1,8,7,4]
62
+ end
63
+
64
+ it 'can be combined with other search words' do
65
+ try.search('1980-2001 a').ids.should == [3]
66
+ try.search('f-u 881').ids.should == [7]
67
+ end
68
+
69
+ it 'can handle multiple range queries' do
70
+ try.search('1980-2001 a-h').ids.should == [3,1]
71
+ try.search('f-u 881-1977').ids.should == [2,7]
72
+ end
73
+
74
+ it 'can be combined with partial queries' do
75
+ try.search('198* a-h').ids.should == [3]
76
+ try.search('a-h 198').ids.should == [3]
77
+ end
78
+
79
+ it 'works with nonsensical ranges' do
80
+ try.search('h-a').ids.should == []
81
+ end
82
+
83
+ # it 'handles combined range/partial queries' do
84
+ # # TODO This still needs to be refined. It is madness.
85
+ # #
86
+ # try.search('198-200*').ids.should == [8,3,1,4,5,7,6,2]
87
+ # end
88
+
89
+ end
@@ -64,53 +64,120 @@ describe Picky::Category do
64
64
  end
65
65
 
66
66
  describe 'weight' do
67
- before(:each) do
68
- @token = stub :token, :text => :some_text
69
- end
70
- context 'partial bundle' do
71
- before(:each) do
72
- @category.stub! :bundle_for => @partial
67
+ let(:token) { stub :token, :text => :some_text }
68
+ context 'without range' do
69
+ before :each do
70
+ token.stub! :range => nil
71
+ end
72
+ context 'partial bundle' do
73
+ before(:each) do
74
+ @category.stub! :bundle_for => @partial
75
+ end
76
+ it 'should receive weight with the token text' do
77
+ @partial.should_receive(:weight).once.with :some_text
78
+
79
+ @category.weight token
80
+ end
73
81
  end
74
- it 'should receive weight with the token text' do
75
- @partial.should_receive(:weight).once.with :some_text
82
+ context 'exact bundle' do
83
+ before(:each) do
84
+ @category.stub! :bundle_for => @exact
85
+ end
86
+ it 'should receive weight with the token text' do
87
+ @exact.should_receive(:weight).once.with :some_text
76
88
 
77
- @category.weight @token
89
+ @category.weight token
90
+ end
78
91
  end
79
92
  end
80
- context 'exact bundle' do
81
- before(:each) do
82
- @category.stub! :bundle_for => @exact
93
+ context 'with range' do
94
+ before :each do
95
+ token.stub! :range => (1..3)
96
+ end
97
+ context 'partial bundle' do
98
+ before(:each) do
99
+ @category.stub! :bundle_for => @partial
100
+ end
101
+ it 'should receive weight with the token text' do
102
+ @partial.should_receive(:weight).once.times.with(1).and_return(1)
103
+ @partial.should_receive(:weight).once.times.with(2).and_return(2)
104
+ @partial.should_receive(:weight).once.times.with(3).and_return(3)
105
+
106
+ @category.weight(token).should == 6
107
+ end
108
+ it 'returns nil if none hit' do
109
+ @partial.should_receive(:weight).once.times.with(1).and_return(nil)
110
+ @partial.should_receive(:weight).once.times.with(2).and_return(nil)
111
+ @partial.should_receive(:weight).once.times.with(3).and_return(nil)
112
+
113
+ @category.weight(token).should == nil
114
+ end
83
115
  end
84
- it 'should receive weight with the token text' do
85
- @exact.should_receive(:weight).once.with :some_text
116
+ context 'exact bundle' do
117
+ before(:each) do
118
+ @category.stub! :bundle_for => @exact
119
+ end
120
+ it 'should receive weight with the token text' do
121
+ @exact.should_receive(:weight).once.times.with(1).and_return(1)
122
+ @exact.should_receive(:weight).once.times.with(2).and_return(2)
123
+ @exact.should_receive(:weight).once.times.with(3).and_return(3)
86
124
 
87
- @category.weight @token
125
+ @category.weight(token).should == 6
126
+ end
88
127
  end
89
128
  end
90
129
  end
91
130
 
92
131
  describe 'ids' do
93
- before(:each) do
94
- @token = stub :token, :text => :some_text
95
- end
96
- context 'partial bundle' do
97
- before(:each) do
98
- @category.stub! :bundle_for => @partial
132
+ let(:token) { stub :token, :text => :some_text }
133
+ context 'without range' do
134
+ before(:each) { token.stub! :range => nil }
135
+ context 'partial bundle' do
136
+ before(:each) do
137
+ @category.stub! :bundle_for => @partial
138
+ end
139
+ it 'should receive ids with the token text' do
140
+ @partial.should_receive(:ids).once.with :some_text
141
+
142
+ @category.ids token
143
+ end
99
144
  end
100
- it 'should receive ids with the token text' do
101
- @partial.should_receive(:ids).once.with :some_text
145
+ context 'exact bundle' do
146
+ before(:each) do
147
+ @category.stub! :bundle_for => @exact
148
+ end
149
+ it 'should receive ids with the token text' do
150
+ @exact.should_receive(:ids).once.with :some_text
102
151
 
103
- @category.ids @token
152
+ @category.ids token
153
+ end
104
154
  end
105
155
  end
106
- context 'exact bundle' do
107
- before(:each) do
108
- @category.stub! :bundle_for => @exact
156
+ context 'with range' do
157
+ before(:each) { token.stub! :range => (1..3) }
158
+ context 'partial bundle' do
159
+ before(:each) do
160
+ @category.stub! :bundle_for => @partial
161
+ end
162
+ it 'should receive ids with the token text' do
163
+ @partial.should_receive(:ids).once.with(1).and_return [1]
164
+ @partial.should_receive(:ids).once.with(2).and_return [2]
165
+ @partial.should_receive(:ids).once.with(3).and_return [3]
166
+
167
+ @category.ids(token).should == [1,2,3]
168
+ end
109
169
  end
110
- it 'should receive ids with the token text' do
111
- @exact.should_receive(:ids).once.with :some_text
170
+ context 'exact bundle' do
171
+ before(:each) do
172
+ @category.stub! :bundle_for => @exact
173
+ end
174
+ it 'should receive ids with the token text' do
175
+ @exact.should_receive(:ids).once.with(1).and_return [1]
176
+ @exact.should_receive(:ids).once.with(2).and_return [2]
177
+ @exact.should_receive(:ids).once.with(3).and_return [3]
112
178
 
113
- @category.ids @token
179
+ @category.ids(token).should == [1,2,3]
180
+ end
114
181
  end
115
182
  end
116
183
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: picky
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.11.1
4
+ version: 4.11.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-03 00:00:00.000000000 Z
12
+ date: 2012-11-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -34,7 +34,7 @@ dependencies:
34
34
  requirements:
35
35
  - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: 4.11.1
37
+ version: 4.11.2
38
38
  type: :development
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: 4.11.1
45
+ version: 4.11.2
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: text
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -282,6 +282,7 @@ files:
282
282
  - spec/functional/non_specific_ids_larger_than_20_spec.rb
283
283
  - spec/functional/only_spec.rb
284
284
  - spec/functional/pool_spec.rb
285
+ - spec/functional/range_queries_spec.rb
285
286
  - spec/functional/realtime_spec.rb
286
287
  - spec/functional/regression_spec.rb
287
288
  - spec/functional/reloading_spec.rb
@@ -445,6 +446,7 @@ test_files:
445
446
  - spec/functional/non_specific_ids_larger_than_20_spec.rb
446
447
  - spec/functional/only_spec.rb
447
448
  - spec/functional/pool_spec.rb
449
+ - spec/functional/range_queries_spec.rb
448
450
  - spec/functional/realtime_spec.rb
449
451
  - spec/functional/regression_spec.rb
450
452
  - spec/functional/reloading_spec.rb