picky 3.6.8 → 3.6.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -31,7 +31,7 @@ module Picky
31
31
  # together.
32
32
  #
33
33
  def empty
34
- @empty && @empty.clone || (@immediate ? self : {})
34
+ @empty && @empty.clone || (@immediate ? self.reset : {})
35
35
  end
36
36
 
37
37
  # The initial content before loading.
@@ -40,7 +40,7 @@ module Picky
40
40
  # this just returns the same thing as #load.
41
41
  #
42
42
  def initial
43
- @initial && @initial.clone || (@immediate ? self : {})
43
+ @initial && @initial.clone || (@immediate ? self.reset : {})
44
44
  end
45
45
 
46
46
  # Returns itself.
@@ -55,6 +55,13 @@ module Picky
55
55
  # Nothing.
56
56
  end
57
57
 
58
+ # Clears the whole namespace.
59
+ #
60
+ def reset
61
+ clear
62
+ self
63
+ end
64
+
58
65
  #
59
66
  #
60
67
  def to_s
@@ -13,8 +13,12 @@ module Picky
13
13
  # Note: Works like the StringHash method, but
14
14
  # returns a float corresponding to that string.
15
15
  #
16
+ # Note: nil.to_f returns 0.0. That's why the
17
+ # code below looks a bit funny.
18
+ #
16
19
  def [] key
17
- super.to_f
20
+ float = super
21
+ float && float.to_f
18
22
  end
19
23
 
20
24
  end
@@ -21,7 +21,7 @@ module Picky
21
21
  # Deletes the list for the key.
22
22
  #
23
23
  def delete key
24
- client.del key
24
+ client.del "#{namespace}:#{key}"
25
25
  end
26
26
 
27
27
  # Writes the hash into Redis.
@@ -61,6 +61,7 @@ module Picky
61
61
  i += 1
62
62
  client.zadd redis_key, i, value
63
63
  end
64
+
64
65
  self[key] # TODO Performance?
65
66
  end
66
67
 
@@ -101,6 +101,11 @@ module Picky
101
101
  # Move this method to the actual backends?
102
102
  #
103
103
  def ids combinations, amount, offset
104
+ # TODO FIXME This is actually not correct:
105
+ # A dumped/loaded Redis backend should use
106
+ # the Redis backend calculation method.
107
+ # So loaded? would be more appropriate.
108
+ #
104
109
  if immediate
105
110
  # Just checked once on the first call.
106
111
  #
@@ -6,9 +6,15 @@ module Picky
6
6
 
7
7
  class Array < Basic
8
8
 
9
+ def create_table
10
+ db.execute 'create table key_value (key varchar(255), value text);'
11
+ end
12
+
9
13
  def []= key, array
10
- if array.empty?
11
- db.execute 'insert or replace into key_value (key, value) values (?,?)', key.to_s, Yajl::Encoder.encode(array)
14
+ unless array.empty?
15
+ db.execute 'INSERT OR REPLACE INTO key_value (key,value) VALUES (?,?)',
16
+ key.to_s,
17
+ Yajl::Encoder.encode(array)
12
18
  end
13
19
 
14
20
  DirectlyManipulable.make self, array, key
@@ -16,9 +22,10 @@ module Picky
16
22
  end
17
23
 
18
24
  def [] key
19
- res = db.execute "select value from key_value where key = ? limit 1;", key.to_s
25
+ res = db.execute "SELECT value FROM key_value WHERE key = ? LIMIT 1",
26
+ key.to_s
20
27
 
21
- return res unless res
28
+ return nil unless res
22
29
 
23
30
  array = res.empty? ? [] : Yajl::Parser.parse(res.first.first)
24
31
  DirectlyManipulable.make self, array, key
@@ -26,7 +33,7 @@ module Picky
26
33
  end
27
34
 
28
35
  def delete key
29
- db.execute "delete from key_value where key = (?)", key.to_s
36
+ db.execute "DELETE FROM key_value WHERE key = (?)", key.to_s
30
37
  end
31
38
 
32
39
  end
@@ -20,11 +20,11 @@ module Picky
20
20
  end
21
21
 
22
22
  def initial
23
- @initial && @initial.clone || (@self_indexed ? self : {})
23
+ @initial && @initial.clone || (@self_indexed ? self.reset : {})
24
24
  end
25
25
 
26
26
  def empty
27
- @empty && @empty.clone || (@self_indexed ? self.reset_db.asynchronous : {})
27
+ @empty && @empty.clone || (@self_indexed ? self.reset.asynchronous : {})
28
28
  end
29
29
 
30
30
  def dump internal
@@ -45,7 +45,7 @@ module Picky
45
45
  end
46
46
 
47
47
  def dump_sqlite internal
48
- reset_db
48
+ reset
49
49
 
50
50
  transaction do
51
51
  # Note: Internal structures need to
@@ -58,17 +58,24 @@ module Picky
58
58
  end
59
59
  end
60
60
 
61
- def reset_db
61
+ def reset
62
62
  create_directory cache_path
63
63
  lazily_initialize_client
64
64
 
65
+ truncate_db
66
+
67
+ self
68
+ end
69
+
70
+ def truncate_db
65
71
  # TODO Could this be replaced by a truncate statement?
66
72
  #
67
- db.execute 'drop table if exists key_value;'
68
- db.execute 'create table key_value (key varchar(255), value text);'
69
- db.execute 'create index key_idx on key_value (key);'
73
+ drop_table
74
+ create_table
75
+ end
70
76
 
71
- self
77
+ def drop_table
78
+ db.execute 'drop table if exists key_value;'
72
79
  end
73
80
 
74
81
  def asynchronous
@@ -0,0 +1,19 @@
1
+ module Picky
2
+
3
+ module Backends
4
+
5
+ class SQLite
6
+
7
+ class IntegerKeyArray < Array
8
+
9
+ def create_table
10
+ db.execute 'create table key_value (key integer PRIMARY KEY, value text);'
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,19 @@
1
+ module Picky
2
+
3
+ module Backends
4
+
5
+ class SQLite
6
+
7
+ class StringKeyArray < Array
8
+
9
+ def create_table
10
+ db.execute 'create table key_value (key varchar(255) PRIMARY KEY, value text);'
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -6,8 +6,12 @@ module Picky
6
6
 
7
7
  class Value < Basic
8
8
 
9
+ def create_table
10
+ db.execute 'create table key_value (key varchar(255) PRIMARY KEY, value text);'
11
+ end
12
+
9
13
  def []= key, value
10
- db.execute 'insert or replace into key_value (key, value) values (?,?)',
14
+ db.execute 'INSERT OR REPLACE INTO key_value (key, value) VALUES (?,?)',
11
15
  key.to_s,
12
16
  Yajl::Encoder.encode(value)
13
17
 
@@ -15,14 +19,14 @@ module Picky
15
19
  end
16
20
 
17
21
  def [] key
18
- res = db.execute "select value from key_value where key = ? limit 1;", key.to_s
22
+ res = db.execute "SELECT value FROM key_value WHERE key = ? LIMIT 1;", key.to_s
19
23
  return nil if res.empty?
20
24
 
21
25
  Yajl::Parser.parse res.first.first
22
26
  end
23
27
 
24
28
  def delete key
25
- db.execute "delete from key_value where key = (?)", key.to_s
29
+ db.execute "DELETE FROM key_value WHERE key = (?)", key.to_s
26
30
  end
27
31
 
28
32
  end
@@ -20,7 +20,7 @@ module Picky
20
20
  #
21
21
  def create_inverted bundle
22
22
  extract_lambda_or(inverted, bundle) ||
23
- Array.new(bundle.index_path(:inverted), self_indexed: self_indexed)
23
+ StringKeyArray.new(bundle.index_path(:inverted), self_indexed: self_indexed)
24
24
  end
25
25
  # Returns an object that on #initial, #load returns an object that responds to:
26
26
  # [:token] # => 1.23 (a weight)
@@ -34,7 +34,7 @@ module Picky
34
34
  #
35
35
  def create_similarity bundle
36
36
  extract_lambda_or(similarity, bundle) ||
37
- Array.new(bundle.index_path(:similarity), self_indexed: self_indexed)
37
+ StringKeyArray.new(bundle.index_path(:similarity), self_indexed: self_indexed)
38
38
  end
39
39
  # Returns an object that on #initial, #load returns an object that responds to:
40
40
  # [:key] # => value (a value for this config key)
@@ -48,7 +48,7 @@ module Picky
48
48
  #
49
49
  def create_realtime bundle
50
50
  extract_lambda_or(similarity, bundle) ||
51
- Array.new(bundle.index_path(:realtime), self_indexed: self_indexed)
51
+ IntegerKeyArray.new(bundle.index_path(:realtime), self_indexed: self_indexed)
52
52
  end
53
53
 
54
54
  # Returns the result ids for the allocation.
@@ -40,6 +40,8 @@ module Picky
40
40
  ids.delete id
41
41
  ids.send where, id
42
42
  else
43
+ # Update the realtime index.
44
+ #
43
45
  str_or_syms << str_or_sym
44
46
 
45
47
  # TODO Introduce a new method?
data/lib/picky/loader.rb CHANGED
@@ -134,6 +134,8 @@ module Picky
134
134
  load_relative 'backends/sqlite/basic'
135
135
  load_relative 'backends/sqlite/array'
136
136
  load_relative 'backends/sqlite/value'
137
+ load_relative 'backends/sqlite/string_key_array'
138
+ load_relative 'backends/sqlite/integer_key_array'
137
139
 
138
140
  # Indexing and Indexed things.
139
141
  #
@@ -128,6 +128,10 @@ Case sensitive? #{@case_sensitive ? "Yes." : "-"}
128
128
  tokens.reject! &@reject_condition
129
129
  end
130
130
 
131
+ # Case sensitivity.
132
+ #
133
+ # Note: If false, simply downcases the data/query.
134
+ #
131
135
  def case_sensitive case_sensitive
132
136
  @case_sensitive = case_sensitive
133
137
  end
@@ -135,6 +139,9 @@ Case sensitive? #{@case_sensitive ? "Yes." : "-"}
135
139
  !@case_sensitive
136
140
  end
137
141
 
142
+ # The maximum amount of words
143
+ # to pass into the search engine.
144
+ #
138
145
  def max_words amount
139
146
  @max_words = amount
140
147
  end
@@ -0,0 +1,227 @@
1
+ require 'spec_helper'
2
+
3
+ describe Picky::Bundle do
4
+
5
+ before(:each) do
6
+ @index = Picky::Index.new :some_index
7
+ @category = Picky::Category.new :some_category, @index
8
+
9
+ @weights = Picky::Generators::Weights::Default
10
+ @partial = Picky::Generators::Partial::Default
11
+ @similarity = Picky::Generators::Similarity::DoubleMetaphone.new 3
12
+ @bundle = described_class.new :some_name,
13
+ @category,
14
+ @weights,
15
+ @partial,
16
+ @similarity,
17
+ backend: Picky::Backends::Memory.new
18
+ end
19
+
20
+ it 'is by default an SQLite Array' do
21
+ @bundle.realtime.should be_kind_of(Hash)
22
+ end
23
+ it 'is by default an SQLite Array' do
24
+ @bundle.inverted.should be_kind_of(Hash)
25
+ end
26
+ it 'is by default an SQLite Value' do
27
+ @bundle.weights.should be_kind_of(Hash)
28
+ end
29
+ it 'is by default an SQLite Array' do
30
+ @bundle.similarity.should be_kind_of(Hash)
31
+ end
32
+
33
+ context 'strings' do
34
+ describe 'combined' do
35
+ it 'works correctly' do
36
+ @bundle.add 1, 'title'
37
+ @bundle.add 2, 'title'
38
+
39
+ @bundle.realtime[1].should == ['title']
40
+ @bundle.realtime[2].should == ['title']
41
+ @bundle.inverted['title'].should == [2,1]
42
+ @bundle.weights['title'].should == 0.693
43
+ @bundle.similarity['TTL'].should == ['title']
44
+ end
45
+ it 'works correctly' do
46
+ @bundle.add 1, 'title'
47
+ @bundle.add 2, 'title'
48
+ @bundle.remove 1
49
+ @bundle.remove 2
50
+
51
+ @bundle.realtime[1].should == nil
52
+ @bundle.realtime[2].should == nil
53
+ @bundle.inverted['title'].should == nil
54
+ @bundle.weights['title'].should == nil
55
+ @bundle.similarity['TTL'].should == nil
56
+ end
57
+ it 'works correctly' do
58
+ @bundle.add 1, 'title'
59
+ @bundle.add 1, 'other'
60
+ @bundle.add 1, 'whatever'
61
+ @bundle.remove 1
62
+
63
+ @bundle.realtime[1].should == nil
64
+ @bundle.realtime[2].should == nil
65
+ @bundle.inverted['title'].should == nil
66
+ @bundle.weights['title'].should == nil
67
+ @bundle.similarity['TTL'].should == nil
68
+ end
69
+ it 'works correctly' do
70
+ @bundle.add 1, 'title'
71
+ @bundle.add 2, 'thing'
72
+ @bundle.add 1, 'other'
73
+ @bundle.remove 1
74
+
75
+ @bundle.realtime[1].should == nil
76
+ @bundle.realtime[2].should == ['thing']
77
+ @bundle.inverted['thing'].should == [2]
78
+ @bundle.weights['thing'].should == 0.0
79
+ @bundle.similarity['0NK'].should == ['thing']
80
+ end
81
+ it 'works correctly' do
82
+ @bundle.add 1, 'title'
83
+ @bundle.add 1, 'title'
84
+
85
+ @bundle.realtime[1].should == ['title']
86
+ @bundle.inverted['title'].should == [1]
87
+ @bundle.weights['title'].should == 0.0
88
+ @bundle.similarity['TTL'].should == ['title']
89
+ end
90
+ it 'works correctly' do
91
+ @bundle.add 1, 'title'
92
+ @bundle.remove 1
93
+ @bundle.remove 1
94
+
95
+ @bundle.realtime[1].should == nil
96
+ @bundle.inverted['title'].should == nil
97
+ @bundle.weights['title'].should == nil
98
+ @bundle.similarity['TTL'].should == nil
99
+ end
100
+ end
101
+
102
+ describe 'add' do
103
+ it 'works correctly' do
104
+ @bundle.add 1, 'title'
105
+
106
+ @bundle.realtime[1].should == ['title']
107
+
108
+ @bundle.add 2, 'other'
109
+
110
+ @bundle.realtime[1].should == ['title']
111
+ @bundle.realtime[2].should == ['other']
112
+
113
+ @bundle.add 1, 'thing'
114
+
115
+ @bundle.realtime[1].should == ['title', 'thing']
116
+ @bundle.realtime[2].should == ['other']
117
+ end
118
+ it 'works correctly' do
119
+ @bundle.add 1, 'title'
120
+
121
+ @bundle.weights['title'].should == 0.0
122
+ @bundle.inverted['title'].should == [1]
123
+ @bundle.similarity['TTL'].should == ['title']
124
+ end
125
+ end
126
+ end
127
+
128
+ context 'symbols' do
129
+ describe 'combined' do
130
+ it 'works correctly' do
131
+ @bundle.add 1, :title
132
+ @bundle.add 2, :title
133
+
134
+ @bundle.realtime.should == { 1 => [:title], 2 => [:title] }
135
+ @bundle.inverted.should == { :title => [2,1] }
136
+ @bundle.weights.should == { :title => 0.693 }
137
+ @bundle.similarity.should == { :TTL => [:title] }
138
+
139
+ @bundle.realtime[1].should == [:title]
140
+ @bundle.realtime[2].should == [:title]
141
+ @bundle.inverted[:title].should == [2,1]
142
+ @bundle.weights[:title].should == 0.693
143
+ @bundle.similarity[:TTL].should == [:title]
144
+ end
145
+ it 'works correctly' do
146
+ @bundle.add 1, :title
147
+ @bundle.add 2, :title
148
+ @bundle.remove 1
149
+ @bundle.remove 2
150
+
151
+ @bundle.realtime[1].should == nil
152
+ @bundle.realtime[2].should == nil
153
+ @bundle.inverted[:title].should == nil
154
+ @bundle.weights[:title].should == nil
155
+ @bundle.similarity[:TTL].should == nil
156
+ end
157
+ it 'works correctly' do
158
+ @bundle.add 1, :title
159
+ @bundle.add 1, :other
160
+ @bundle.add 1, :whatever
161
+ @bundle.remove 1
162
+
163
+ @bundle.realtime[1].should == nil
164
+ @bundle.inverted[:title].should == nil
165
+ @bundle.weights[:title].should == nil
166
+ @bundle.similarity[:TTL].should == nil
167
+ end
168
+ it 'works correctly' do
169
+ @bundle.add 1, :title
170
+ @bundle.add 2, :thing
171
+ @bundle.add 1, :other
172
+ @bundle.remove 1
173
+
174
+ @bundle.realtime[1].should == nil
175
+ @bundle.realtime[2].should == [:thing]
176
+ @bundle.inverted[:thing].should == [2]
177
+ @bundle.weights[:thing].should == 0.0
178
+ @bundle.similarity[:'0NK'].should == [:thing]
179
+ end
180
+ it 'works correctly' do
181
+ @bundle.add 1, :title
182
+ @bundle.add 1, :title
183
+
184
+ @bundle.realtime[1].should == [:title]
185
+ @bundle.inverted[:title].should == [1]
186
+ @bundle.weights[:title].should == 0.0
187
+ @bundle.similarity[:'TTL'].should == [:title]
188
+ end
189
+ it 'works correctly' do
190
+ @bundle.add 1, :title
191
+ @bundle.remove 1
192
+ @bundle.remove 1
193
+
194
+ @bundle.realtime[1].should == nil
195
+ @bundle.inverted[:title].should == nil
196
+ @bundle.weights[:title].should == nil
197
+ @bundle.similarity[:TTL].should == nil
198
+ end
199
+ end
200
+
201
+ describe 'add' do
202
+ it 'works correctly' do
203
+ @bundle.add 1, :title
204
+
205
+ @bundle.realtime[1].should == [:title]
206
+
207
+ @bundle.add 2, :other
208
+
209
+ @bundle.realtime[1].should == [:title]
210
+ @bundle.realtime[2].should == [:other]
211
+
212
+ @bundle.add 1, :thing
213
+
214
+ @bundle.realtime[1].should == [:title, :thing]
215
+ @bundle.realtime[2].should == [:other]
216
+ end
217
+ it 'works correctly' do
218
+ @bundle.add 1, :title
219
+
220
+ @bundle.weights[:title].should == 0.0
221
+ @bundle.inverted[:title].should == [1]
222
+ @bundle.similarity[:TTL].should == [:title]
223
+ end
224
+ end
225
+ end
226
+
227
+ end
@@ -0,0 +1,224 @@
1
+ require 'spec_helper'
2
+
3
+ describe Picky::Bundle do
4
+
5
+ before(:each) do
6
+ @index = Picky::Index.new :some_index
7
+ @category = Picky::Category.new :some_category, @index
8
+
9
+ @weights = Picky::Generators::Weights::Default
10
+ @partial = Picky::Generators::Partial::Default
11
+ @similarity = Picky::Generators::Similarity::DoubleMetaphone.new 3
12
+ @bundle = described_class.new :some_name,
13
+ @category,
14
+ @weights,
15
+ @partial,
16
+ @similarity,
17
+ backend: Picky::Backends::Redis.new(immediate: true)
18
+ end
19
+
20
+ it 'is by default an SQLite Array' do
21
+ @bundle.realtime.should be_kind_of(Picky::Backends::Redis::List)
22
+ end
23
+ it 'is by default an SQLite Array' do
24
+ @bundle.inverted.should be_kind_of(Picky::Backends::Redis::List)
25
+ end
26
+ it 'is by default an SQLite Value' do
27
+ @bundle.weights.should be_kind_of(Picky::Backends::Redis::Float)
28
+ end
29
+ it 'is by default an SQLite Array' do
30
+ @bundle.similarity.should be_kind_of(Picky::Backends::Redis::List)
31
+ end
32
+
33
+ context 'strings' do
34
+ describe 'combined' do
35
+ it 'works correctly' do
36
+ @bundle.add '1', 'title'
37
+ @bundle.add '2', 'title'
38
+
39
+ @bundle.realtime['1'].should == ['title']
40
+ @bundle.realtime['2'].should == ['title']
41
+ @bundle.inverted['title'].should == ['2','1']
42
+ @bundle.weights['title'].should == 0.693
43
+ @bundle.similarity['TTL'].should == ['title']
44
+ end
45
+ it 'works correctly' do
46
+ @bundle.add '1', 'title'
47
+ @bundle.add '2', 'title'
48
+ @bundle.remove '1'
49
+ @bundle.remove '2'
50
+
51
+ @bundle.realtime['1'].should == []
52
+ @bundle.realtime['2'].should == []
53
+ @bundle.inverted['title'].should == []
54
+ @bundle.weights['title'].should == nil
55
+ @bundle.similarity['TTL'].should == []
56
+ end
57
+ it 'works correctly' do
58
+ @bundle.add '1', 'title'
59
+ @bundle.add '1', 'other'
60
+ @bundle.add '1', 'whatever'
61
+ @bundle.remove '1'
62
+
63
+ @bundle.realtime['1'].should == []
64
+ @bundle.realtime['2'].should == []
65
+ @bundle.inverted['title'].should == []
66
+ @bundle.weights['title'].should == nil
67
+ @bundle.similarity['TTL'].should == []
68
+ end
69
+ it 'works correctly' do
70
+ @bundle.add '1', 'title'
71
+ @bundle.add '2', 'thing'
72
+ @bundle.add '1', 'other'
73
+ @bundle.remove '1'
74
+
75
+ @bundle.realtime['1'].should == []
76
+ @bundle.realtime['2'].should == ['thing']
77
+ @bundle.inverted['thing'].should == ['2']
78
+ @bundle.weights['thing'].should == 0.0
79
+ @bundle.similarity['0NK'].should == ['thing']
80
+ end
81
+ it 'works correctly' do
82
+ @bundle.add '1', 'title'
83
+ @bundle.add '1', 'title'
84
+
85
+ @bundle.realtime['1'].should == ['title']
86
+ @bundle.inverted['title'].should == ['1']
87
+ @bundle.weights['title'].should == 0.0
88
+ @bundle.similarity['TTL'].should == ['title']
89
+ end
90
+ it 'works correctly' do
91
+ @bundle.add '1', 'title'
92
+ @bundle.remove '1'
93
+ @bundle.remove '1'
94
+
95
+ @bundle.realtime['1'].should == []
96
+ @bundle.inverted['title'].should == []
97
+ @bundle.weights['title'].should == nil
98
+ @bundle.similarity['TTL'].should == []
99
+ end
100
+ end
101
+
102
+ describe 'add' do
103
+ it 'works correctly' do
104
+ @bundle.add '1', 'title'
105
+
106
+ @bundle.realtime['1'].should == ['title']
107
+
108
+ @bundle.add '2', 'other'
109
+
110
+ @bundle.realtime['1'].should == ['title']
111
+ @bundle.realtime['2'].should == ['other']
112
+
113
+ @bundle.add '1', 'thing'
114
+
115
+ @bundle.realtime['1'].should == ['title', 'thing']
116
+ @bundle.realtime['2'].should == ['other']
117
+ end
118
+ it 'works correctly' do
119
+ @bundle.add '1', 'title'
120
+
121
+ @bundle.weights['title'].should == 0.0
122
+ @bundle.inverted['title'].should == ['1']
123
+ @bundle.similarity['TTL'].should == ['title']
124
+ end
125
+ end
126
+ end
127
+
128
+ # TODO Add symbols.
129
+ #
130
+ # context 'symbols' do
131
+ # describe 'combined' do
132
+ # it 'works correctly' do
133
+ # @bundle.add '1', :title
134
+ # @bundle.add '2', :title
135
+ #
136
+ # @bundle.realtime['1'].should == [:title]
137
+ # @bundle.realtime['2'].should == [:title]
138
+ # @bundle.inverted[:title].should == [2,1]
139
+ # @bundle.weights[:title].should == 0.693
140
+ # @bundle.similarity[:TTL].should == [:title]
141
+ # end
142
+ # it 'works correctly' do
143
+ # @bundle.add '1', :title
144
+ # @bundle.add '2', :title
145
+ # @bundle.remove 1
146
+ # @bundle.remove 2
147
+ #
148
+ # @bundle.realtime['1'].should == []
149
+ # @bundle.realtime['2'].should == []
150
+ # @bundle.inverted[:title].should == []
151
+ # @bundle.weights[:title].should == nil
152
+ # @bundle.similarity[:TTL].should == []
153
+ # end
154
+ # it 'works correctly' do
155
+ # @bundle.add '1', :title
156
+ # @bundle.add '1', :other
157
+ # @bundle.add '1', :whatever
158
+ # @bundle.remove 1
159
+ #
160
+ # @bundle.realtime['1'].should == []
161
+ # @bundle.inverted[:title].should == []
162
+ # @bundle.weights[:title].should == nil
163
+ # @bundle.similarity[:TTL].should == []
164
+ # end
165
+ # it 'works correctly' do
166
+ # @bundle.add '1', :title
167
+ # @bundle.add '2', :thing
168
+ # @bundle.add '1', :other
169
+ # @bundle.remove 1
170
+ #
171
+ # @bundle.realtime['1'].should == []
172
+ # @bundle.realtime['2'].should == [:thing]
173
+ # @bundle.inverted[:thing].should == ['2']
174
+ # @bundle.weights[:thing].should == 0.0
175
+ # @bundle.similarity[:'0NK'].should == [:thing]
176
+ # end
177
+ # it 'works correctly' do
178
+ # @bundle.add '1', :title
179
+ # @bundle.add '1', :title
180
+ #
181
+ # @bundle.realtime['1'].should == [:title]
182
+ # @bundle.inverted[:title].should == ['1']
183
+ # @bundle.weights[:title].should == 0.0
184
+ # @bundle.similarity[:'TTL'].should == [:title]
185
+ # end
186
+ # it 'works correctly' do
187
+ # @bundle.add '1', :title
188
+ # @bundle.remove 1
189
+ # @bundle.remove 1
190
+ #
191
+ # @bundle.realtime['1'].should == []
192
+ # @bundle.inverted[:title].should == []
193
+ # @bundle.weights[:title].should == nil
194
+ # @bundle.similarity[:TTL].should == []
195
+ # end
196
+ # end
197
+ #
198
+ # describe 'add' do
199
+ # it 'works correctly' do
200
+ # @bundle.add '1', :title
201
+ #
202
+ # @bundle.realtime['1'].should == [:title]
203
+ #
204
+ # @bundle.add '2', :other
205
+ #
206
+ # @bundle.realtime['1'].should == [:title]
207
+ # @bundle.realtime['2'].should == [:other]
208
+ #
209
+ # @bundle.add '1', :thing
210
+ #
211
+ # @bundle.realtime['1'].should == [:title, :thing]
212
+ # @bundle.realtime['2'].should == [:other]
213
+ # end
214
+ # it 'works correctly' do
215
+ # @bundle.add '1', :title
216
+ #
217
+ # @bundle.weights[:title].should == 0.0
218
+ # @bundle.inverted[:title].should == ['1']
219
+ # @bundle.similarity[:TTL].should == [:title]
220
+ # end
221
+ # end
222
+ # end
223
+
224
+ end
@@ -93,15 +93,15 @@ describe Picky::Backends::Redis do
93
93
  instance_eval &its
94
94
  end
95
95
 
96
- # context 'immediately indexing backend (no dump needed)' do
97
- # before(:each) do
98
- # data.backend Picky::Backends::Redis.new(immediate: true)
99
- # data.clear
100
- #
101
- # data.add Book.new(1, 'title', 'author')
102
- # end
103
- #
104
- # instance_eval &its
105
- # end
96
+ context 'immediately indexing backend (no dump needed)' do
97
+ before(:each) do
98
+ data.backend Picky::Backends::Redis.new(immediate: true)
99
+ data.clear
100
+
101
+ data.add Book.new(1, 'title', 'author')
102
+ end
103
+
104
+ instance_eval &its
105
+ end
106
106
 
107
107
  end
@@ -0,0 +1,224 @@
1
+ require 'spec_helper'
2
+
3
+ describe Picky::Bundle do
4
+
5
+ before(:each) do
6
+ @index = Picky::Index.new :some_index
7
+ @category = Picky::Category.new :some_category, @index
8
+
9
+ @weights = Picky::Generators::Weights::Default
10
+ @partial = Picky::Generators::Partial::Default
11
+ @similarity = Picky::Generators::Similarity::DoubleMetaphone.new 3
12
+ @bundle = described_class.new :some_name,
13
+ @category,
14
+ @weights,
15
+ @partial,
16
+ @similarity,
17
+ backend: Picky::Backends::SQLite.new(self_indexed: true)
18
+ end
19
+
20
+ it 'is by default an SQLite Array' do
21
+ @bundle.realtime.should be_kind_of(Picky::Backends::SQLite::Array)
22
+ end
23
+ it 'is by default an SQLite Array' do
24
+ @bundle.inverted.should be_kind_of(Picky::Backends::SQLite::Array)
25
+ end
26
+ it 'is by default an SQLite Value' do
27
+ @bundle.weights.should be_kind_of(Picky::Backends::SQLite::Value)
28
+ end
29
+ it 'is by default an SQLite Array' do
30
+ @bundle.similarity.should be_kind_of(Picky::Backends::SQLite::Array)
31
+ end
32
+
33
+ context 'strings' do
34
+ describe 'combined' do
35
+ it 'works correctly' do
36
+ @bundle.add 1, 'title'
37
+ @bundle.add 2, 'title'
38
+
39
+ @bundle.realtime[1].should == ['title']
40
+ @bundle.realtime[2].should == ['title']
41
+ @bundle.inverted['title'].should == [2,1]
42
+ @bundle.weights['title'].should == 0.693
43
+ @bundle.similarity['TTL'].should == ['title']
44
+ end
45
+ it 'works correctly' do
46
+ @bundle.add 1, 'title'
47
+ @bundle.add 2, 'title'
48
+ @bundle.remove 1
49
+ @bundle.remove 2
50
+
51
+ @bundle.realtime[1].should == []
52
+ @bundle.realtime[2].should == []
53
+ @bundle.inverted['title'].should == []
54
+ @bundle.weights['title'].should == nil
55
+ @bundle.similarity['TTL'].should == []
56
+ end
57
+ it 'works correctly' do
58
+ @bundle.add 1, 'title'
59
+ @bundle.add 1, 'other'
60
+ @bundle.add 1, 'whatever'
61
+ @bundle.remove 1
62
+
63
+ @bundle.realtime[1].should == []
64
+ @bundle.realtime[2].should == []
65
+ @bundle.inverted['title'].should == []
66
+ @bundle.weights['title'].should == nil
67
+ @bundle.similarity['TTL'].should == []
68
+ end
69
+ it 'works correctly' do
70
+ @bundle.add 1, 'title'
71
+ @bundle.add 2, 'thing'
72
+ @bundle.add 1, 'other'
73
+ @bundle.remove 1
74
+
75
+ @bundle.realtime[1].should == []
76
+ @bundle.realtime[2].should == ['thing']
77
+ @bundle.inverted['thing'].should == [2]
78
+ @bundle.weights['thing'].should == 0.0
79
+ @bundle.similarity['0NK'].should == ['thing']
80
+ end
81
+ it 'works correctly' do
82
+ @bundle.add 1, 'title'
83
+ @bundle.add 1, 'title'
84
+
85
+ @bundle.realtime[1].should == ['title']
86
+ @bundle.inverted['title'].should == [1]
87
+ @bundle.weights['title'].should == 0.0
88
+ @bundle.similarity['TTL'].should == ['title']
89
+ end
90
+ it 'works correctly' do
91
+ @bundle.add 1, 'title'
92
+ @bundle.remove 1
93
+ @bundle.remove 1
94
+
95
+ @bundle.realtime[1].should == []
96
+ @bundle.inverted['title'].should == []
97
+ @bundle.weights['title'].should == nil
98
+ @bundle.similarity['TTL'].should == []
99
+ end
100
+ end
101
+
102
+ describe 'add' do
103
+ it 'works correctly' do
104
+ @bundle.add 1, 'title'
105
+
106
+ @bundle.realtime[1].should == ['title']
107
+
108
+ @bundle.add 2, 'other'
109
+
110
+ @bundle.realtime[1].should == ['title']
111
+ @bundle.realtime[2].should == ['other']
112
+
113
+ @bundle.add 1, 'thing'
114
+
115
+ @bundle.realtime[1].should == ['title', 'thing']
116
+ @bundle.realtime[2].should == ['other']
117
+ end
118
+ it 'works correctly' do
119
+ @bundle.add 1, 'title'
120
+
121
+ @bundle.weights['title'].should == 0.0
122
+ @bundle.inverted['title'].should == [1]
123
+ @bundle.similarity['TTL'].should == ['title']
124
+ end
125
+ end
126
+ end
127
+
128
+ # TODO Add symbols.
129
+ #
130
+ # context 'symbols' do
131
+ # describe 'combined' do
132
+ # it 'works correctly' do
133
+ # @bundle.add 1, :title
134
+ # @bundle.add 2, :title
135
+ #
136
+ # @bundle.realtime[1].should == [:title]
137
+ # @bundle.realtime[2].should == [:title]
138
+ # @bundle.inverted[:title].should == [2,1]
139
+ # @bundle.weights[:title].should == 0.693
140
+ # @bundle.similarity[:TTL].should == [:title]
141
+ # end
142
+ # it 'works correctly' do
143
+ # @bundle.add 1, :title
144
+ # @bundle.add 2, :title
145
+ # @bundle.remove 1
146
+ # @bundle.remove 2
147
+ #
148
+ # @bundle.realtime[1].should == []
149
+ # @bundle.realtime[2].should == []
150
+ # @bundle.inverted[:title].should == []
151
+ # @bundle.weights[:title].should == nil
152
+ # @bundle.similarity[:TTL].should == []
153
+ # end
154
+ # it 'works correctly' do
155
+ # @bundle.add 1, :title
156
+ # @bundle.add 1, :other
157
+ # @bundle.add 1, :whatever
158
+ # @bundle.remove 1
159
+ #
160
+ # @bundle.realtime[1].should == []
161
+ # @bundle.inverted[:title].should == []
162
+ # @bundle.weights[:title].should == nil
163
+ # @bundle.similarity[:TTL].should == []
164
+ # end
165
+ # it 'works correctly' do
166
+ # @bundle.add 1, :title
167
+ # @bundle.add 2, :thing
168
+ # @bundle.add 1, :other
169
+ # @bundle.remove 1
170
+ #
171
+ # @bundle.realtime[1].should == []
172
+ # @bundle.realtime[2].should == [:thing]
173
+ # @bundle.inverted[:thing].should == [2]
174
+ # @bundle.weights[:thing].should == 0.0
175
+ # @bundle.similarity[:'0NK'].should == [:thing]
176
+ # end
177
+ # it 'works correctly' do
178
+ # @bundle.add 1, :title
179
+ # @bundle.add 1, :title
180
+ #
181
+ # @bundle.realtime[1].should == [:title]
182
+ # @bundle.inverted[:title].should == [1]
183
+ # @bundle.weights[:title].should == 0.0
184
+ # @bundle.similarity[:'TTL'].should == [:title]
185
+ # end
186
+ # it 'works correctly' do
187
+ # @bundle.add 1, :title
188
+ # @bundle.remove 1
189
+ # @bundle.remove 1
190
+ #
191
+ # @bundle.realtime[1].should == []
192
+ # @bundle.inverted[:title].should == []
193
+ # @bundle.weights[:title].should == nil
194
+ # @bundle.similarity[:TTL].should == []
195
+ # end
196
+ # end
197
+ #
198
+ # describe 'add' do
199
+ # it 'works correctly' do
200
+ # @bundle.add 1, :title
201
+ #
202
+ # @bundle.realtime[1].should == [:title]
203
+ #
204
+ # @bundle.add 2, :other
205
+ #
206
+ # @bundle.realtime[1].should == [:title]
207
+ # @bundle.realtime[2].should == [:other]
208
+ #
209
+ # @bundle.add 1, :thing
210
+ #
211
+ # @bundle.realtime[1].should == [:title, :thing]
212
+ # @bundle.realtime[2].should == [:other]
213
+ # end
214
+ # it 'works correctly' do
215
+ # @bundle.add 1, :title
216
+ #
217
+ # @bundle.weights[:title].should == 0.0
218
+ # @bundle.inverted[:title].should == [1]
219
+ # @bundle.similarity[:TTL].should == [:title]
220
+ # end
221
+ # end
222
+ # end
223
+
224
+ end
@@ -50,6 +50,16 @@ describe Picky::Backends::SQLite do
50
50
 
51
51
  books.search('title').ids.should == [2]
52
52
  end
53
+ it 'handles removing with three entries' do
54
+ data.add Book.new(2, 'title', 'author')
55
+ data.add Book.new(3, 'title', 'author')
56
+
57
+ books.search('title').ids.should == [3, 2, 1]
58
+
59
+ data.remove 1
60
+
61
+ books.search('title').ids.should == [3, 2]
62
+ end
53
63
  it 'handles clearing' do
54
64
  data.clear
55
65
 
@@ -61,16 +71,6 @@ describe Picky::Backends::SQLite do
61
71
 
62
72
  books.search('title').ids.should == [1]
63
73
  end
64
- it 'handles removing with three entries' do
65
- data.add Book.new(2, 'title', 'author')
66
- data.add Book.new(3, 'title', 'author')
67
-
68
- books.search('title').ids.should == [3, 2, 1]
69
-
70
- data.remove 1
71
-
72
- books.search('title').ids.should == [3, 2]
73
- end
74
74
  it 'handles replacing' do
75
75
  data.replace Book.new(1, 'toitle', 'oithor')
76
76
 
@@ -90,15 +90,15 @@ describe Picky::Backends::SQLite do
90
90
  instance_eval &its
91
91
  end
92
92
 
93
- # context 'immediately indexing backend (no dump needed)' do
94
- # before(:each) do
95
- # data.backend described_class.new(self_indexed: true)
96
- # data.clear
97
- #
98
- # data.add Book.new(1, 'title', 'author')
99
- # end
100
- #
101
- # instance_eval &its
102
- # end
93
+ context 'immediately indexing backend (no dump needed)' do
94
+ before(:each) do
95
+ data.backend described_class.new(self_indexed: true)
96
+ data.clear
97
+
98
+ data.add Book.new(1, 'title', 'author')
99
+ end
100
+
101
+ instance_eval &its
102
+ end
103
103
 
104
104
  end
@@ -30,4 +30,35 @@ describe 'Search#max_allocations' do
30
30
  try_again.search('hello world').ids.should == [1]
31
31
  end
32
32
 
33
+ it 'gets faster' do
34
+ index = Picky::Index.new :dynamic_weights do
35
+ category :text1
36
+ category :text2
37
+ category :text3
38
+ category :text4
39
+ end
40
+
41
+ thing = Struct.new(:id, :text1, :text2, :text3, :text4)
42
+ index.add thing.new(1, 'hello world', 'hello world', 'hello world', 'hello world')
43
+ index.add thing.new(2, 'hello world', 'hello world', 'hello world', 'hello world')
44
+ index.add thing.new(3, 'hello world', 'hello world', 'hello world', 'hello world')
45
+ index.add thing.new(4, 'hello world', 'hello world', 'hello world', 'hello world')
46
+ index.add thing.new(5, 'hello world', 'hello world', 'hello world', 'hello world')
47
+ index.add thing.new(6, 'hello world', 'hello world', 'hello world', 'hello world')
48
+
49
+ try = Picky::Search.new index
50
+
51
+ threshold = performance_of do
52
+ try.search('hello world')
53
+ end
54
+
55
+ try_again = Picky::Search.new index do
56
+ max_allocations 1
57
+ end
58
+
59
+ performance_of do
60
+ try_again.search('hello world')
61
+ end.should < (threshold*2/3)
62
+ end
63
+
33
64
  end
@@ -27,6 +27,11 @@ describe Picky::Backends::Redis::Float do
27
27
 
28
28
  backend['anything'].should == 1.23
29
29
  end
30
+ it 'returns whatever it gets from the backend' do
31
+ client.should_receive(:hget).any_number_of_times.and_return nil
32
+
33
+ backend['anything'].should == nil
34
+ end
30
35
  end
31
36
 
32
37
  describe 'to_s' do
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: 3.6.8
4
+ version: 3.6.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-29 00:00:00.000000000 Z
12
+ date: 2011-11-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70319172184220 !ruby/object:Gem::Requirement
16
+ requirement: &70133025519700 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,21 +21,21 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70319172184220
24
+ version_requirements: *70133025519700
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: picky-client
27
- requirement: &70319172181920 !ruby/object:Gem::Requirement
27
+ requirement: &70133025518760 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
31
31
  - !ruby/object:Gem::Version
32
- version: 3.6.8
32
+ version: 3.6.9
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70319172181920
35
+ version_requirements: *70133025518760
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rack
38
- requirement: &70319172180560 !ruby/object:Gem::Requirement
38
+ requirement: &70133025518340 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70319172180560
46
+ version_requirements: *70133025518340
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rack_fast_escape
49
- requirement: &70319172222400 !ruby/object:Gem::Requirement
49
+ requirement: &70133025517860 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70319172222400
57
+ version_requirements: *70133025517860
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: text
60
- requirement: &70319172220440 !ruby/object:Gem::Requirement
60
+ requirement: &70133025517220 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *70319172220440
68
+ version_requirements: *70133025517220
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: yajl-ruby
71
- requirement: &70319172237300 !ruby/object:Gem::Requirement
71
+ requirement: &70133025516620 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *70319172237300
79
+ version_requirements: *70133025516620
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: activesupport
82
- requirement: &70319172277680 !ruby/object:Gem::Requirement
82
+ requirement: &70133025515700 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '3.0'
88
88
  type: :runtime
89
89
  prerelease: false
90
- version_requirements: *70319172277680
90
+ version_requirements: *70133025515700
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: unicorn
93
- requirement: &70319172274760 !ruby/object:Gem::Requirement
93
+ requirement: &70133025514840 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :runtime
100
100
  prerelease: false
101
- version_requirements: *70319172274760
101
+ version_requirements: *70133025514840
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: sinatra
104
- requirement: &70319172284740 !ruby/object:Gem::Requirement
104
+ requirement: &70133025513920 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,7 +109,7 @@ dependencies:
109
109
  version: '0'
110
110
  type: :runtime
111
111
  prerelease: false
112
- version_requirements: *70319172284740
112
+ version_requirements: *70133025513920
113
113
  description: Fast Ruby semantic text search engine with comfortable single field interface.
114
114
  email: florian.hanke+picky@gmail.com
115
115
  executables:
@@ -146,6 +146,8 @@ files:
146
146
  - lib/picky/backends/sqlite/array.rb
147
147
  - lib/picky/backends/sqlite/basic.rb
148
148
  - lib/picky/backends/sqlite/directly_manipulable.rb
149
+ - lib/picky/backends/sqlite/integer_key_array.rb
150
+ - lib/picky/backends/sqlite/string_key_array.rb
149
151
  - lib/picky/backends/sqlite/value.rb
150
152
  - lib/picky/backends/sqlite.rb
151
153
  - lib/picky/bundle.rb
@@ -261,8 +263,11 @@ files:
261
263
  - spec/category_realtime_spec.rb
262
264
  - spec/ext/performant_spec.rb
263
265
  - spec/functional/backends/file_spec.rb
266
+ - spec/functional/backends/memory_bundle_realtime_spec.rb
264
267
  - spec/functional/backends/memory_spec.rb
268
+ - spec/functional/backends/redis_bundle_realtime_spec.rb
265
269
  - spec/functional/backends/redis_spec.rb
270
+ - spec/functional/backends/sqlite_bundle_realtime_spec.rb
266
271
  - spec/functional/backends/sqlite_spec.rb
267
272
  - spec/functional/dynamic_weights_spec.rb
268
273
  - spec/functional/exact_first_spec.rb
@@ -401,8 +406,11 @@ test_files:
401
406
  - spec/category_realtime_spec.rb
402
407
  - spec/ext/performant_spec.rb
403
408
  - spec/functional/backends/file_spec.rb
409
+ - spec/functional/backends/memory_bundle_realtime_spec.rb
404
410
  - spec/functional/backends/memory_spec.rb
411
+ - spec/functional/backends/redis_bundle_realtime_spec.rb
405
412
  - spec/functional/backends/redis_spec.rb
413
+ - spec/functional/backends/sqlite_bundle_realtime_spec.rb
406
414
  - spec/functional/backends/sqlite_spec.rb
407
415
  - spec/functional/dynamic_weights_spec.rb
408
416
  - spec/functional/exact_first_spec.rb