picky 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/picky/cacher/partial/default.rb +1 -1
- data/lib/picky/cacher/partial/subtoken.rb +18 -18
- data/lib/picky/cacher/partial_generator.rb +1 -1
- data/lib/picky/extensions/hash.rb +4 -4
- data/lib/picky/extensions/symbol.rb +9 -9
- data/lib/picky/index/bundle.rb +58 -133
- data/lib/picky/index/file/basic.rb +67 -0
- data/lib/picky/index/file/json.rb +24 -0
- data/lib/picky/index/file/marshal.rb +24 -0
- data/lib/picky/index/file/text.rb +28 -0
- data/lib/picky/index/files.rb +135 -0
- data/lib/picky/indexers/base.rb +4 -0
- data/lib/picky/indexes.rb +2 -2
- data/lib/picky/loader.rb +8 -2
- data/lib/picky/sources/delicious.rb +7 -1
- data/project_prototype/app/application.rb +9 -7
- data/spec/lib/cacher/partial/default_spec.rb +3 -3
- data/spec/lib/cacher/partial/subtoken_spec.rb +28 -28
- data/spec/lib/cacher/partial_generator_spec.rb +2 -2
- data/spec/lib/extensions/hash_spec.rb +4 -4
- data/spec/lib/index/bundle_partial_generation_speed_spec.rb +1 -1
- data/spec/lib/index/bundle_spec.rb +47 -46
- data/spec/lib/index/file/basic_spec.rb +15 -0
- data/spec/lib/index/file/json_spec.rb +26 -0
- data/spec/lib/index/file/marshal_spec.rb +26 -0
- data/spec/lib/index/file/text_spec.rb +27 -0
- data/spec/lib/index/files_spec.rb +186 -0
- data/spec/lib/index/type_spec.rb +5 -2
- data/spec/lib/query/combinator_spec.rb +5 -3
- data/spec/lib/sources/delicious_spec.rb +9 -1
- metadata +18 -6
- data/lib/picky/index/bundle_checker.rb +0 -58
- data/spec/lib/index/bundle_checker_spec.rb +0 -67
data/lib/picky/indexes.rb
CHANGED
data/lib/picky/loader.rb
CHANGED
@@ -155,14 +155,20 @@ module Loader
|
|
155
155
|
load_relative 'cacher/weights_generator'
|
156
156
|
load_relative 'cacher/similarity_generator'
|
157
157
|
|
158
|
+
# Index file handling.
|
159
|
+
#
|
160
|
+
load_relative 'index/file/basic'
|
161
|
+
load_relative 'index/file/text'
|
162
|
+
load_relative 'index/file/marshal'
|
163
|
+
load_relative 'index/file/json'
|
164
|
+
load_relative 'index/files'
|
165
|
+
|
158
166
|
# Index types.
|
159
167
|
#
|
160
168
|
load_relative 'index/bundle'
|
161
169
|
load_relative 'index/category'
|
162
170
|
load_relative 'index/type'
|
163
171
|
|
164
|
-
load_relative 'index/bundle_checker'
|
165
|
-
|
166
172
|
load_relative 'index/wrappers/exact_first'
|
167
173
|
|
168
174
|
# Tokens.
|
@@ -3,10 +3,16 @@ module Sources
|
|
3
3
|
class Delicious < Base
|
4
4
|
|
5
5
|
def initialize username, password
|
6
|
-
|
6
|
+
check_gem
|
7
7
|
@username = username
|
8
8
|
@password = password
|
9
9
|
end
|
10
|
+
def check_gem
|
11
|
+
require 'www/delicious'
|
12
|
+
rescue LoadError
|
13
|
+
puts "Delicious gem missing!\nTo use the delicious source, you need to:\n 1. Add the following line to Gemfile:\n gem 'www-delicious'\n 2. Then, run:\n bundle update\n"
|
14
|
+
exit(1)
|
15
|
+
end
|
10
16
|
|
11
17
|
# Harvests the data to index.
|
12
18
|
#
|
@@ -17,14 +17,16 @@ class PickySearch < Application
|
|
17
17
|
books_index = index :books,
|
18
18
|
Sources::CSV.new(:title, :author, :isbn, :year, :publisher, :subjects, :file => 'app/library.csv'),
|
19
19
|
# Use a database as source:
|
20
|
-
# Sources::DB.new('SELECT id, title, author, isbn13 as isbn FROM books', :file => 'app/db.yml'),
|
20
|
+
# Sources::DB.new('SELECT id, title, author, isbn13 as isbn FROM books', :file => 'app/db.yml'),
|
21
|
+
# Or delicious:
|
22
|
+
# Sources::Delicious.new('username', 'password'), # offers title, tags, url fields.
|
21
23
|
field(:title,
|
22
|
-
:partial => Partial::
|
23
|
-
# e.g.
|
24
|
-
# Like this, you'll find
|
25
|
-
:similarity => Similarity::DoubleLevenshtone.new(3)), # Up to three similar title word indexed.
|
26
|
-
field(:author, :partial => Partial::
|
27
|
-
field(:isbn, :partial => Partial::None.new) #
|
24
|
+
:partial => Partial::Substring.new(:from => 1), # Index substrings upwards from character 1 (default: -3),
|
25
|
+
# e.g. picky -> p, pi, pic, pick, picky
|
26
|
+
# Like this, you'll find picky even when entering just a "p".
|
27
|
+
:similarity => Similarity::DoubleLevenshtone.new(3)), # Up to three similar title word indexed (default: no similarity).
|
28
|
+
field(:author, :partial => Partial::Substring.new(:from => 1)),
|
29
|
+
field(:isbn, :partial => Partial::None.new) # Partial substring searching on an ISBN makes not much sense, neither does similarity.
|
28
30
|
|
29
31
|
# Defines the maximum tokens (words) that pass through to the engine.
|
30
32
|
#
|
@@ -3,13 +3,13 @@ require 'spec_helper'
|
|
3
3
|
describe Cacher::Partial::Default do
|
4
4
|
|
5
5
|
it "should be a subtoken" do
|
6
|
-
Cacher::Partial::Default.should be_kind_of(Cacher::Partial::
|
6
|
+
Cacher::Partial::Default.should be_kind_of(Cacher::Partial::Substring)
|
7
7
|
end
|
8
8
|
it "should be a the right down to" do
|
9
|
-
Cacher::Partial::Default.
|
9
|
+
Cacher::Partial::Default.from.should == -3
|
10
10
|
end
|
11
11
|
it "should be a the right starting at" do
|
12
|
-
Cacher::Partial::Default.
|
12
|
+
Cacher::Partial::Default.to.should == -1
|
13
13
|
end
|
14
14
|
|
15
15
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Cacher::Partial::
|
3
|
+
describe Cacher::Partial::Substring do
|
4
4
|
|
5
|
-
context 'default
|
5
|
+
context 'default from' do
|
6
6
|
before(:each) do
|
7
|
-
@cacher = Cacher::Partial::
|
7
|
+
@cacher = Cacher::Partial::Substring.new
|
8
8
|
end
|
9
|
-
describe '
|
9
|
+
describe 'from' do
|
10
10
|
it 'should return the right value' do
|
11
|
-
@cacher.
|
11
|
+
@cacher.from.should == 1
|
12
12
|
end
|
13
13
|
end
|
14
14
|
describe 'generate_from' do
|
@@ -40,10 +40,10 @@ describe Cacher::Partial::Subtoken do
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
43
|
-
context '
|
44
|
-
describe 'negative
|
43
|
+
context 'from set' do
|
44
|
+
describe 'negative from' do
|
45
45
|
before(:each) do
|
46
|
-
@cacher = Cacher::Partial::
|
46
|
+
@cacher = Cacher::Partial::Substring.new :from => -2
|
47
47
|
end
|
48
48
|
it 'should generate the right index' do
|
49
49
|
@cacher.generate_from( :florian => [1], :flavia => [2] ).should == {
|
@@ -54,9 +54,9 @@ describe Cacher::Partial::Subtoken do
|
|
54
54
|
}
|
55
55
|
end
|
56
56
|
end
|
57
|
-
context "large
|
57
|
+
context "large from" do
|
58
58
|
before(:each) do
|
59
|
-
@cacher = Cacher::Partial::
|
59
|
+
@cacher = Cacher::Partial::Substring.new :from => 10
|
60
60
|
end
|
61
61
|
describe 'generate_from' do
|
62
62
|
it 'should generate the right index' do
|
@@ -68,18 +68,18 @@ describe Cacher::Partial::Subtoken do
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
end
|
71
|
-
context 'default
|
71
|
+
context 'default to' do
|
72
72
|
before(:each) do
|
73
|
-
@cacher = Cacher::Partial::
|
73
|
+
@cacher = Cacher::Partial::Substring.new :from => 4
|
74
74
|
end
|
75
|
-
describe '
|
75
|
+
describe 'to' do
|
76
76
|
it 'should return the right value' do
|
77
|
-
@cacher.
|
77
|
+
@cacher.to.should == -1
|
78
78
|
end
|
79
79
|
end
|
80
|
-
describe '
|
80
|
+
describe 'from' do
|
81
81
|
it 'should return the right value' do
|
82
|
-
@cacher.
|
82
|
+
@cacher.from.should == 4
|
83
83
|
end
|
84
84
|
end
|
85
85
|
describe 'generate_from' do
|
@@ -122,18 +122,18 @@ describe Cacher::Partial::Subtoken do
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
end
|
125
|
-
context '
|
125
|
+
context 'to set' do
|
126
126
|
before(:each) do
|
127
|
-
@cacher = Cacher::Partial::
|
127
|
+
@cacher = Cacher::Partial::Substring.new :from => 4, :to => -2
|
128
128
|
end
|
129
|
-
describe '
|
129
|
+
describe 'to' do
|
130
130
|
it 'should return the right value' do
|
131
|
-
@cacher.
|
131
|
+
@cacher.to.should == -2
|
132
132
|
end
|
133
133
|
end
|
134
|
-
describe '
|
134
|
+
describe 'from' do
|
135
135
|
it 'should return the right value' do
|
136
|
-
@cacher.
|
136
|
+
@cacher.from.should == 4
|
137
137
|
end
|
138
138
|
end
|
139
139
|
describe 'generate_from' do
|
@@ -148,18 +148,18 @@ describe Cacher::Partial::Subtoken do
|
|
148
148
|
end
|
149
149
|
end
|
150
150
|
end
|
151
|
-
context '
|
151
|
+
context 'to set' do
|
152
152
|
before(:each) do
|
153
|
-
@cacher = Cacher::Partial::
|
153
|
+
@cacher = Cacher::Partial::Substring.new :from => 4, :to => 0
|
154
154
|
end
|
155
|
-
describe '
|
155
|
+
describe 'to' do
|
156
156
|
it 'should return the right value' do
|
157
|
-
@cacher.
|
157
|
+
@cacher.to.should == 0
|
158
158
|
end
|
159
159
|
end
|
160
|
-
describe '
|
160
|
+
describe 'from' do
|
161
161
|
it 'should return the right value' do
|
162
|
-
@cacher.
|
162
|
+
@cacher.from.should == 4
|
163
163
|
end
|
164
164
|
end
|
165
165
|
describe 'generate_from' do
|
@@ -6,7 +6,7 @@ describe Cacher::PartialGenerator do
|
|
6
6
|
it 'should generate the correct values with a given strategy' do
|
7
7
|
generator = Cacher::PartialGenerator.new :meier => [1], :maier => [2]
|
8
8
|
|
9
|
-
generator.generate(Cacher::Partial::
|
9
|
+
generator.generate(Cacher::Partial::Substring.new).should == {
|
10
10
|
:meier => [1],
|
11
11
|
:meie => [1],
|
12
12
|
:mei => [1],
|
@@ -21,7 +21,7 @@ describe Cacher::PartialGenerator do
|
|
21
21
|
it 'should generate the correct values with a given specific strategy' do
|
22
22
|
generator = Cacher::PartialGenerator.new :meier => [1], :maier => [2]
|
23
23
|
|
24
|
-
generator.generate(Cacher::Partial::
|
24
|
+
generator.generate(Cacher::Partial::Substring.new(:from => 3)).should == {
|
25
25
|
:meier => [1],
|
26
26
|
:meie => [1],
|
27
27
|
:mei => [1],
|
@@ -6,7 +6,7 @@ describe Hash do
|
|
6
6
|
it 'uses the right file' do
|
7
7
|
File.should_receive(:open).once.with('some/file/path.json', 'w')
|
8
8
|
|
9
|
-
{}.
|
9
|
+
{}.dump_json 'some/file/path.json'
|
10
10
|
end
|
11
11
|
it "uses the right encoder" do
|
12
12
|
file = stub :file
|
@@ -14,7 +14,7 @@ describe Hash do
|
|
14
14
|
|
15
15
|
Yajl::Encoder.should_receive(:encode).once.with({ :some => :hash }, file)
|
16
16
|
|
17
|
-
{ :some => :hash }.
|
17
|
+
{ :some => :hash }.dump_json 'unimportant'
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -22,7 +22,7 @@ describe Hash do
|
|
22
22
|
it 'uses the right file' do
|
23
23
|
File.should_receive(:open).once.with('some/file/path.dump', 'w:binary')
|
24
24
|
|
25
|
-
{}.
|
25
|
+
{}.dump_marshalled 'some/file/path.dump'
|
26
26
|
end
|
27
27
|
it "uses the right encoder" do
|
28
28
|
file = stub :file
|
@@ -30,7 +30,7 @@ describe Hash do
|
|
30
30
|
|
31
31
|
Marshal.should_receive(:dump).once.with({ :some => :hash }, file)
|
32
32
|
|
33
|
-
{ :some => :hash }.
|
33
|
+
{ :some => :hash }.dump_marshalled 'unimportant'
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -5,7 +5,7 @@ describe Index::Bundle do
|
|
5
5
|
before(:each) do
|
6
6
|
@category = stub :category, :name => :some_category
|
7
7
|
@type = stub :type, :name => :some_type
|
8
|
-
@partial_strategy = Cacher::Partial::
|
8
|
+
@partial_strategy = Cacher::Partial::Substring.new :from => 1
|
9
9
|
@exact = Index::Bundle.new :some_name, @category, @type, @partial_strategy, nil, nil
|
10
10
|
end
|
11
11
|
|
@@ -17,21 +17,7 @@ describe Index::Bundle do
|
|
17
17
|
@index.identifier.should == 'some_name: some_type some_category'
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
21
|
-
describe 'create_directory' do
|
22
|
-
it 'should use makedirs to create the necessary directory structure' do
|
23
|
-
FileUtils.should_receive(:mkdir_p).once.with 'some/search/root/index/test/some_type'
|
24
|
-
|
25
|
-
@index.create_directory
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe 'cache_directory' do
|
30
|
-
it 'should be correct' do
|
31
|
-
@index.cache_directory.should == 'some/search/root/index/test/some_type'
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
20
|
+
|
35
21
|
describe 'initialize_index_for' do
|
36
22
|
context 'token not yet assigned' do
|
37
23
|
before(:each) do
|
@@ -127,17 +113,7 @@ describe Index::Bundle do
|
|
127
113
|
@index.weight(:existing).should == :specific
|
128
114
|
end
|
129
115
|
end
|
130
|
-
|
131
|
-
describe 'delete_all' do
|
132
|
-
it 'should call delete with all paths' do
|
133
|
-
@index.should_receive(:delete).once.with @index.index_cache_path
|
134
|
-
@index.should_receive(:delete).once.with @index.similarity_cache_path
|
135
|
-
@index.should_receive(:delete).once.with @index.weights_cache_path
|
136
|
-
|
137
|
-
@index.delete_all
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
116
|
+
|
141
117
|
describe 'load' do
|
142
118
|
it 'should trigger loads' do
|
143
119
|
@index.should_receive(:load_index).once.with
|
@@ -190,25 +166,56 @@ describe Index::Bundle do
|
|
190
166
|
end
|
191
167
|
end
|
192
168
|
|
193
|
-
describe '
|
194
|
-
|
195
|
-
@
|
169
|
+
describe 'raise_unless_cache_exists' do
|
170
|
+
before(:each) do
|
171
|
+
@files = stub :files
|
172
|
+
@files.stub! :index_cache_ok? => true
|
173
|
+
@files.stub! :similarity_cache_ok? => true
|
174
|
+
@files.stub! :weights_cache_ok? => true
|
175
|
+
@files.stub! :index_cache_small? => false
|
176
|
+
@files.stub! :similarity_cache_small? => false
|
177
|
+
@files.stub! :weights_cache_small? => false
|
178
|
+
|
179
|
+
@index.stub! :files => @files
|
196
180
|
end
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
181
|
+
context 'weights cache missing' do
|
182
|
+
before(:each) do
|
183
|
+
@files.stub! :weights_cache_ok? => false
|
184
|
+
end
|
185
|
+
it 'should raise' do
|
186
|
+
lambda do
|
187
|
+
@index.raise_unless_cache_exists
|
188
|
+
end.should raise_error("weights cache for some_name: some_type some_category missing.")
|
189
|
+
end
|
201
190
|
end
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
191
|
+
context 'similarity cache missing' do
|
192
|
+
before(:each) do
|
193
|
+
@files.stub! :similarity_cache_ok? => false
|
194
|
+
end
|
195
|
+
it 'should raise' do
|
196
|
+
lambda do
|
197
|
+
@index.raise_unless_cache_exists
|
198
|
+
end.should raise_error("similarity cache for some_name: some_type some_category missing.")
|
199
|
+
end
|
200
|
+
end
|
201
|
+
context 'index cache missing' do
|
202
|
+
before(:each) do
|
203
|
+
@files.stub! :index_cache_ok? => false
|
204
|
+
end
|
205
|
+
it 'should raise' do
|
206
|
+
lambda do
|
207
|
+
@index.raise_unless_cache_exists
|
208
|
+
end.should raise_error("index cache for some_name: some_type some_category missing.")
|
209
|
+
end
|
206
210
|
end
|
207
211
|
end
|
208
|
-
|
212
|
+
|
209
213
|
describe 'initialization' do
|
210
214
|
before(:each) do
|
211
|
-
@
|
215
|
+
@category = stub :category, :name => :some_category
|
216
|
+
@type = stub :type, :name => :some_type
|
217
|
+
|
218
|
+
@index = @index_class.new :some_name, @category, @type, :partial, :weights, :similarity
|
212
219
|
end
|
213
220
|
it 'should initialize the index correctly' do
|
214
221
|
@index.index.should == {}
|
@@ -220,13 +227,7 @@ describe Index::Bundle do
|
|
220
227
|
@index.similarity.should == {}
|
221
228
|
end
|
222
229
|
it 'should initialize the name correctly' do
|
223
|
-
@index.
|
224
|
-
end
|
225
|
-
it 'should initialize the name correctly' do
|
226
|
-
@index.category.should == :some_category
|
227
|
-
end
|
228
|
-
it 'should initialize the name correctly' do
|
229
|
-
@index.type.should == :some_type
|
230
|
+
@index.category.should == @category
|
230
231
|
end
|
231
232
|
it 'should initialize the partial strategy correctly' do
|
232
233
|
@index.partial_strategy.should == :partial
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Index::File::Basic do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@file = Index::File::Basic.new "some/cache/path/to/file"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "backup_file_path_of" do
|
10
|
+
it "returns a backup path relative to the path" do
|
11
|
+
@file.backup_file_path_of('some/path/to/some.index').should == 'some/path/to/backup/some.index'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Index::File::JSON do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@file = Index::File::JSON.new "some_cache_path"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "dump" do
|
10
|
+
it "delegates to the given hash" do
|
11
|
+
hash = stub :hash
|
12
|
+
|
13
|
+
hash.should_receive(:dump_json).once.with "some_cache_path.json"
|
14
|
+
|
15
|
+
@file.dump hash
|
16
|
+
end
|
17
|
+
end
|
18
|
+
describe "retrieve" do
|
19
|
+
it "raises" do
|
20
|
+
lambda do
|
21
|
+
@file.retrieve
|
22
|
+
end.should raise_error("Can't retrieve from marshalled file. Use text file.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Index::File::Marshal do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@file = Index::File::Marshal.new "some_cache_path"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "dump" do
|
10
|
+
it "delegates to the given hash" do
|
11
|
+
hash = stub :hash
|
12
|
+
|
13
|
+
hash.should_receive(:dump_marshalled).once.with "some_cache_path.dump"
|
14
|
+
|
15
|
+
@file.dump hash
|
16
|
+
end
|
17
|
+
end
|
18
|
+
describe "retrieve" do
|
19
|
+
it "raises" do
|
20
|
+
lambda do
|
21
|
+
@file.retrieve
|
22
|
+
end.should raise_error("Can't retrieve from marshalled file. Use text file.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Index::File::Text do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@file = Index::File::Text.new "some_cache_path"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "load" do
|
10
|
+
it "raises" do
|
11
|
+
lambda do
|
12
|
+
@file.load
|
13
|
+
end.should raise_error("Can't load from text file. Use JSON or Marshal.")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
describe "dump" do
|
17
|
+
it "raises" do
|
18
|
+
lambda do
|
19
|
+
@file.dump :anything
|
20
|
+
end.should raise_error("Can't dump to text file. Use JSON or Marshal.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
describe "retrieve" do
|
24
|
+
it
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|