picky 3.6.7 → 3.6.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/lib/picky/backends/file/basic.rb +1 -1
  2. data/lib/picky/backends/file/json.rb +5 -1
  3. data/lib/picky/backends/file.rb +7 -0
  4. data/lib/picky/backends/memory.rb +7 -0
  5. data/lib/picky/backends/redis/basic.rb +3 -11
  6. data/lib/picky/backends/redis/directly_manipulable.rb +48 -0
  7. data/lib/picky/backends/redis/list.rb +39 -15
  8. data/lib/picky/backends/redis/string.rb +17 -9
  9. data/lib/picky/backends/redis.rb +102 -66
  10. data/lib/picky/backends/sqlite/array.rb +38 -0
  11. data/lib/picky/backends/sqlite/basic.rb +100 -0
  12. data/lib/picky/backends/sqlite/directly_manipulable.rb +42 -0
  13. data/lib/picky/backends/sqlite/value.rb +34 -0
  14. data/lib/picky/backends/sqlite.rb +14 -4
  15. data/lib/picky/bundle.rb +12 -5
  16. data/lib/picky/bundle_indexed.rb +15 -2
  17. data/lib/picky/bundle_indexing.rb +6 -5
  18. data/lib/picky/bundle_realtime.rb +22 -31
  19. data/lib/picky/categories_realtime.rb +1 -1
  20. data/lib/picky/category_indexed.rb +1 -1
  21. data/lib/picky/category_indexing.rb +7 -5
  22. data/lib/picky/category_realtime.rb +17 -5
  23. data/lib/picky/generators/strategy.rb +4 -0
  24. data/lib/picky/index_indexing.rb +1 -4
  25. data/lib/picky/index_realtime.rb +16 -6
  26. data/lib/picky/indexers/base.rb +7 -1
  27. data/lib/picky/indexes.rb +1 -0
  28. data/lib/picky/loader.rb +11 -7
  29. data/lib/picky/query/allocation.rb +1 -1
  30. data/lib/picky/query/indexes.rb +2 -2
  31. data/lib/picky/query/token.rb +1 -1
  32. data/lib/picky/search.rb +20 -8
  33. data/lib/picky/tokenizer.rb +6 -6
  34. data/lib/picky/wrappers/bundle/delegators.rb +3 -1
  35. data/spec/category_realtime_spec.rb +33 -0
  36. data/spec/functional/backends/file_spec.rb +98 -0
  37. data/spec/functional/backends/memory_spec.rb +96 -0
  38. data/spec/functional/backends/redis_spec.rb +107 -0
  39. data/spec/functional/backends/sqlite_spec.rb +104 -0
  40. data/spec/{specific → functional}/dynamic_weights_spec.rb +0 -0
  41. data/spec/{specific → functional}/exact_first_spec.rb +2 -4
  42. data/spec/functional/max_allocations_spec.rb +33 -0
  43. data/spec/{specific → functional}/realtime_spec.rb +0 -0
  44. data/spec/{specific → functional}/regression_spec.rb +0 -0
  45. data/spec/{specific → functional}/speed_spec.rb +0 -0
  46. data/spec/lib/backends/file/basic_spec.rb +1 -1
  47. data/spec/lib/backends/redis/basic_spec.rb +12 -13
  48. data/spec/lib/backends/redis/directly_manipulable_spec.rb +91 -0
  49. data/spec/lib/backends/redis/float_spec.rb +17 -17
  50. data/spec/lib/backends/redis/list_spec.rb +9 -9
  51. data/spec/lib/backends/sqlite/array_spec.rb +143 -0
  52. data/spec/lib/backends/sqlite/directly_manipulable_spec.rb +65 -0
  53. data/spec/lib/backends/sqlite/{db_spec.rb → value_spec.rb} +2 -7
  54. data/spec/lib/backends/sqlite_spec.rb +22 -20
  55. data/spec/lib/category_indexed_spec.rb +1 -1
  56. data/spec/lib/category_indexing_spec.rb +2 -2
  57. data/spec/lib/index_indexing_spec.rb +0 -7
  58. data/spec/lib/index_realtime_spec.rb +34 -0
  59. data/spec/lib/indexed/bundle_realtime_spec.rb +166 -75
  60. data/spec/lib/indexers/base_spec.rb +13 -1
  61. data/spec/lib/search_spec.rb +31 -20
  62. metadata +58 -34
  63. data/lib/picky/backends/sqlite/db.rb +0 -84
@@ -135,14 +135,14 @@ Case sensitive? #{@case_sensitive ? "Yes." : "-"}
135
135
  !@case_sensitive
136
136
  end
137
137
 
138
- def maximum_tokens amount
139
- @maximum_tokens = amount
138
+ def max_words amount
139
+ @max_words = amount
140
140
  end
141
141
  def cap words
142
- words.slice!(@maximum_tokens..-1) if cap?(words)
142
+ words.slice!(@max_words..-1) if cap?(words)
143
143
  end
144
144
  def cap? words
145
- @maximum_tokens && words.size > @maximum_tokens
145
+ @max_words && words.size > @max_words
146
146
  end
147
147
 
148
148
  # Checks if the right argument type has been given.
@@ -160,7 +160,7 @@ Case sensitive? #{@case_sensitive ? "Yes." : "-"}
160
160
  stopwords options[:stopwords] if options[:stopwords]
161
161
  splits_text_on options[:splits_text_on] || /\s/
162
162
  normalizes_words options[:normalizes_words] if options[:normalizes_words]
163
- maximum_tokens options[:maximum_tokens]
163
+ max_words options[:max_words]
164
164
  rejects_token_if &(options[:rejects_token_if] || :blank?)
165
165
  case_sensitive options[:case_sensitive] unless options[:case_sensitive].nil?
166
166
  end
@@ -203,7 +203,7 @@ Case sensitive? #{@case_sensitive ? "Yes." : "-"}
203
203
  #
204
204
  # Does:
205
205
  # * Split the text into words.
206
- # * Cap the amount of tokens if maximum_tokens is set.
206
+ # * Cap the amount of tokens if max_words is set.
207
207
  #
208
208
  def pretokenize text
209
209
  words = split text
@@ -7,7 +7,6 @@ module Picky
7
7
  module Delegator
8
8
 
9
9
  delegate :add,
10
- :clear_realtime_mapping,
11
10
 
12
11
  :inverted,
13
12
  :weights,
@@ -18,6 +17,8 @@ module Picky
18
17
  :restore,
19
18
  :delete,
20
19
 
20
+ :reset_backend,
21
+
21
22
  :raise_unless_cache_exists,
22
23
  :raise_unless_index_exists,
23
24
  :raise_unless_similarity_exists,
@@ -53,6 +54,7 @@ module Picky
53
54
  :clear_weights,
54
55
  :clear_similarity,
55
56
  :clear_configuration,
57
+ :clear_realtime,
56
58
  :identifier,
57
59
  :ids,
58
60
  :load,
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ describe Picky::Category, "Realtime API" do
6
+
7
+ Thing = Struct.new :id, :text
8
+
9
+ let(:category) do
10
+ index = Picky::Index.new :some_index_name
11
+ category = described_class.new :text, index
12
+ end
13
+
14
+ it 'offers an add method' do
15
+ category.add Thing.new(1, 'text')
16
+ end
17
+ it 'offers a remove method' do
18
+ category.remove 1
19
+ end
20
+ it 'offers a replace method' do
21
+ category.replace Thing.new(1, 'text')
22
+ end
23
+ it 'offers a << method' do
24
+ category << Thing.new(1, 'text')
25
+ end
26
+ # it 'offers a >> method' do
27
+ # Thing.new(1, 'text') >> category # I mean, as long as we're dreaming.
28
+ # end
29
+ it 'offers an unshift method' do
30
+ category.unshift Thing.new(1, 'text')
31
+ end
32
+
33
+ end
@@ -0,0 +1,98 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ # Describes a Picky index that uses the File backend
6
+ # for data storage.
7
+ #
8
+ # TODO Everything should just fail.
9
+ #
10
+ describe Picky::Backends::File do
11
+
12
+ class Book
13
+ attr_reader :id, :title, :author
14
+ def initialize id, title, author
15
+ @id, @title, @author = id, title, author
16
+ end
17
+ end
18
+
19
+ attr_reader :data, :books
20
+
21
+ let(:data) do
22
+ Picky::Index.new(:books) do
23
+ key_format :to_s # TODO Also make to_i work.
24
+ source []
25
+ category :title, partial: Picky::Partial::Postfix.new(from: 1)
26
+ category :author, similarity: Picky::Generators::Similarity::DoubleMetaphone.new(3)
27
+ end
28
+ end
29
+ let(:books) { Picky::Search.new data }
30
+
31
+ its = ->(*) do
32
+ it 'searching for it' do
33
+ books.search('title').ids.should == ['1']
34
+ end
35
+ it 'searching for it using multiple words' do
36
+ books.search('title author').ids.should == ['1']
37
+ end
38
+ it 'searching for it using partial' do
39
+ books.search('tit').ids.should == ['1']
40
+ end
41
+ it 'searching for it using similarity' do
42
+ books.search('aothor~').ids.should == ['1']
43
+ end
44
+ it 'handles removing' do
45
+ data.remove 1
46
+
47
+ books.search('title').ids.should == []
48
+ end
49
+ it 'handles removing with more than one entry' do
50
+ data.add Book.new(2, 'title', 'author')
51
+
52
+ books.search('title').ids.should == ['2', '1'] # TODO Should be ['2', '1']
53
+
54
+ data.remove '1'
55
+
56
+ books.search('title').ids.should == ['2']
57
+ end
58
+ it 'handles removing with three entries' do
59
+ data.add Book.new(2, 'title', 'author')
60
+ data.add Book.new(3, 'title', 'author')
61
+
62
+ books.search('title').ids.should == ['3', '2', '1'] # TODO Should be ['3', '2', '1']
63
+
64
+ data.remove '1'
65
+
66
+ books.search('title').ids.should == ['3', '2']
67
+ end
68
+ it 'handles replacing' do
69
+ data.replace Book.new(1, 'toitle', 'oithor')
70
+
71
+ books.search('title').ids.should == []
72
+ books.search('toitle').ids.should == ['1']
73
+ end
74
+ it 'handles clearing' do
75
+ data.clear
76
+
77
+ books.search('title').ids.should == []
78
+ end
79
+ it 'handles dumping and loading' do
80
+ data.dump
81
+ data.load
82
+
83
+ books.search('title').ids.should == ['1']
84
+ end
85
+ end
86
+
87
+ context 'immediately indexing backend (no dump needed)' do
88
+ before(:each) do
89
+ data.backend described_class.new
90
+ data.clear
91
+
92
+ data.add Book.new(1, 'title', 'author')
93
+ end
94
+
95
+ instance_eval &its
96
+ end
97
+
98
+ end
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ # Describes a Picky index that uses the Memory backend
6
+ # for data storage.
7
+ #
8
+ describe Picky::Backends::Memory do
9
+
10
+ class Book
11
+ attr_reader :id, :title, :author
12
+ def initialize id, title, author
13
+ @id, @title, @author = id, title, author
14
+ end
15
+ end
16
+
17
+ attr_reader :data, :books
18
+
19
+ let(:data) do
20
+ Picky::Index.new(:books) do
21
+ key_format :to_s # TODO Also make to_i work.
22
+ source []
23
+ category :title, partial: Picky::Partial::Postfix.new(from: 1)
24
+ category :author, similarity: Picky::Generators::Similarity::DoubleMetaphone.new(3)
25
+ end
26
+ end
27
+ let(:books) { Picky::Search.new data }
28
+
29
+ its = ->(*) do
30
+ it 'searching for it' do
31
+ books.search('title').ids.should == ['1']
32
+ end
33
+ it 'searching for it using multiple words' do
34
+ books.search('title author').ids.should == ['1']
35
+ end
36
+ it 'searching for it using partial' do
37
+ books.search('tit').ids.should == ['1']
38
+ end
39
+ it 'searching for it using similarity' do
40
+ books.search('aothor~').ids.should == ['1']
41
+ end
42
+ it 'handles removing' do
43
+ data.remove 1
44
+
45
+ books.search('title').ids.should == []
46
+ end
47
+ it 'handles removing with more than one entry' do
48
+ data.add Book.new(2, 'title', 'author')
49
+
50
+ books.search('title').ids.should == ['2', '1'] # TODO Should be ['2', '1']
51
+
52
+ data.remove '1'
53
+
54
+ books.search('title').ids.should == ['2']
55
+ end
56
+ it 'handles removing with three entries' do
57
+ data.add Book.new(2, 'title', 'author')
58
+ data.add Book.new(3, 'title', 'author')
59
+
60
+ books.search('title').ids.should == ['3', '2', '1'] # TODO Should be ['3', '2', '1']
61
+
62
+ data.remove '1'
63
+
64
+ books.search('title').ids.should == ['3', '2']
65
+ end
66
+ it 'handles replacing' do
67
+ data.replace Book.new(1, 'toitle', 'oithor')
68
+
69
+ books.search('title').ids.should == []
70
+ books.search('toitle').ids.should == ['1']
71
+ end
72
+ it 'handles clearing' do
73
+ data.clear
74
+
75
+ books.search('title').ids.should == []
76
+ end
77
+ it 'handles dumping and loading' do
78
+ data.dump
79
+ data.load
80
+
81
+ books.search('title').ids.should == ['1']
82
+ end
83
+ end
84
+
85
+ context 'immediately indexing backend (no dump needed)' do
86
+ before(:each) do
87
+ data.backend described_class.new
88
+ data.clear
89
+
90
+ data.add Book.new(1, 'title', 'author')
91
+ end
92
+
93
+ instance_eval &its
94
+ end
95
+
96
+ end
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ # Describes a Picky index that uses the Redis backend
6
+ # for data storage.
7
+ #
8
+ describe Picky::Backends::Redis do
9
+
10
+ class Book
11
+ attr_reader :id, :title, :author
12
+ def initialize id, title, author
13
+ @id, @title, @author = id, title, author
14
+ end
15
+ end
16
+
17
+ attr_reader :data, :books
18
+
19
+ let(:data) do
20
+ Picky::Index.new(:books) do
21
+ key_format :to_s # TODO Also make to_i work.
22
+ source []
23
+ category :title, partial: Picky::Partial::Postfix.new(from: 1)
24
+ category :author, similarity: Picky::Generators::Similarity::DoubleMetaphone.new(3)
25
+ end
26
+ end
27
+ let(:books) { Picky::Search.new data }
28
+
29
+ its = ->(*) do
30
+ it 'searching for it' do
31
+ books.search('title').ids.should == ['1']
32
+ end
33
+ it 'searching for it using multiple words' do
34
+ books.search('title author').ids.should == ['1']
35
+ end
36
+ it 'searching for it using partial' do
37
+ books.search('tit').ids.should == ['1']
38
+ end
39
+ it 'searching for it using similarity' do
40
+ books.search('aothor~').ids.should == ['1']
41
+ end
42
+ it 'handles removing' do
43
+ data.remove 1
44
+
45
+ books.search('title').ids.should == []
46
+ end
47
+ it 'handles removing with more than one entry' do
48
+ data.add Book.new(2, 'title', 'author')
49
+
50
+ books.search('title').ids.should == ['2', '1']
51
+
52
+ data.remove '1'
53
+
54
+ books.search('title').ids.should == ['2']
55
+ end
56
+ it 'handles removing with three entries' do
57
+ data.add Book.new(2, 'title', 'author')
58
+ data.add Book.new(3, 'title', 'author')
59
+
60
+ books.search('title').ids.should == ['3', '2', '1'] # TODO Should be ['3', '2', '1']
61
+
62
+ data.remove '1'
63
+
64
+ books.search('title').ids.should == ['3', '2']
65
+ end
66
+ it 'handles replacing' do
67
+ data.replace Book.new(1, 'toitle', 'oithor')
68
+
69
+ books.search('title').ids.should == []
70
+ books.search('toitle').ids.should == ['1']
71
+ end
72
+ it 'handles clearing' do
73
+ data.clear
74
+
75
+ books.search('title').ids.should == []
76
+ end
77
+ it 'handles dumping and loading' do
78
+ data.dump
79
+ data.load
80
+
81
+ books.search('title').ids.should == ['1']
82
+ end
83
+ end
84
+
85
+ context 'default backend (dump needed)' do
86
+ before(:each) do
87
+ data.backend Picky::Backends::Redis.new
88
+ data.clear
89
+
90
+ data.add Book.new(1, 'title', 'author')
91
+ end
92
+
93
+ instance_eval &its
94
+ end
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
106
+
107
+ end
@@ -0,0 +1,104 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ # Describes a Picky index that uses the SQLite backend
6
+ # for data storage.
7
+ #
8
+ describe Picky::Backends::SQLite do
9
+
10
+ class Book
11
+ attr_reader :id, :title, :author
12
+ def initialize id, title, author
13
+ @id, @title, @author = id, title, author
14
+ end
15
+ end
16
+
17
+ let(:data) do
18
+ Picky::Index.new(:books) do
19
+ source []
20
+ category :title, partial: Picky::Partial::Postfix.new(from: 1)
21
+ category :author, similarity: Picky::Generators::Similarity::DoubleMetaphone.new(3)
22
+ end
23
+ end
24
+ let(:books) { Picky::Search.new data }
25
+
26
+ its = ->(*) do
27
+ it 'searching for it' do
28
+ books.search('title').ids.should == [1]
29
+ end
30
+ it 'searching for it using multiple words' do
31
+ books.search('title author').ids.should == [1]
32
+ end
33
+ it 'searching for it using partial' do
34
+ books.search('tit').ids.should == [1]
35
+ end
36
+ it 'searching for it using similarity' do
37
+ books.search('aothor~').ids.should == [1]
38
+ end
39
+ it 'handles removing' do
40
+ data.remove 1
41
+
42
+ books.search('title').ids.should == []
43
+ end
44
+ it 'handles removing with more than one entry' do
45
+ data.add Book.new(2, 'title', 'author')
46
+
47
+ books.search('title').ids.should == [2, 1]
48
+
49
+ data.remove 1
50
+
51
+ books.search('title').ids.should == [2]
52
+ end
53
+ it 'handles clearing' do
54
+ data.clear
55
+
56
+ books.search('title').ids.should == []
57
+ end
58
+ it 'handles dumping and loading' do
59
+ data.dump
60
+ data.load
61
+
62
+ books.search('title').ids.should == [1]
63
+ 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
+ it 'handles replacing' do
75
+ data.replace Book.new(1, 'toitle', 'oithor')
76
+
77
+ books.search('title').ids.should == []
78
+ books.search('toitle').ids.should == [1]
79
+ end
80
+ end
81
+
82
+ context 'default backend (dump needed)' do
83
+ before(:each) do
84
+ data.backend described_class.new
85
+ data.clear
86
+
87
+ data.add Book.new(1, 'title', 'author')
88
+ end
89
+
90
+ instance_eval &its
91
+ end
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
103
+
104
+ end
@@ -2,11 +2,9 @@
2
2
  #
3
3
  require 'spec_helper'
4
4
 
5
- describe "Weights" do
5
+ describe "exact first" do
6
6
 
7
- # This tests the weights option.
8
- #
9
- it 'can handle dynamic weights' do
7
+ it 'returns exact results first' do
10
8
  index = Picky::Index.new :exact_first do
11
9
  source { [] }
12
10
  category :text, partial: Picky::Partial::Substring.new(from: 1)
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ describe 'Search#max_allocations' do
6
+
7
+ it 'offers the option max_allocations' do
8
+ index = Picky::Index.new :dynamic_weights do
9
+ category :text1
10
+ category :text2
11
+ end
12
+
13
+ index.add Struct.new(:id, :text1, :text2).new(1, 'hello world', 'hello world')
14
+
15
+ try = Picky::Search.new index
16
+
17
+ try.search('hello world').allocations.size.should == 4
18
+ try.search('hello world').ids.should == [1,1,1,1]
19
+
20
+ try_again = Picky::Search.new index do
21
+ max_allocations 2
22
+ end
23
+
24
+ try_again.search('hello world').allocations.size.should == 2
25
+ try_again.search('hello world').ids.should == [1,1]
26
+
27
+ try_again.max_allocations 1
28
+
29
+ try_again.search('hello world').allocations.size.should == 1
30
+ try_again.search('hello world').ids.should == [1]
31
+ end
32
+
33
+ end
File without changes
File without changes
File without changes
@@ -13,7 +13,7 @@ describe Picky::Backends::File::Basic do
13
13
 
14
14
  describe 'initial' do
15
15
  it 'returns the container that is used for indexing' do
16
- basic.initial.should == nil
16
+ basic.initial.should == {}
17
17
  end
18
18
  end
19
19
 
@@ -5,39 +5,38 @@ describe Picky::Backends::Redis::Basic do
5
5
  let(:client) { stub :client }
6
6
 
7
7
  context 'without options' do
8
- let(:index) { described_class.new client, :some_namespace }
8
+ let(:backend) { described_class.new client, :some_namespace }
9
9
 
10
10
  describe 'load, retrieve, delete' do
11
11
  it 'is nothing they do (at least on the backend)' do
12
- index.should_receive(:client).never
12
+ backend.should_receive(:client).never
13
13
 
14
- index.load
15
- index.retrieve
16
- index.delete
14
+ backend.load
15
+ backend.retrieve
17
16
  end
18
17
  end
19
18
 
20
19
  describe 'empty' do
21
- it 'returns the container that is used for indexing' do
22
- index.empty.should == {}
20
+ it 'returns the container that is used for backending' do
21
+ backend.empty.should == {}
23
22
  end
24
23
  end
25
24
 
26
25
  describe 'initial' do
27
26
  it 'is correct' do
28
- index.initial.class.should == described_class
27
+ backend.initial.should == {}
29
28
  end
30
29
  end
31
30
 
32
31
  describe 'to_s' do
33
32
  it 'returns the cache path with the default file extension' do
34
- index.to_s.should == 'Picky::Backends::Redis::Basic(some_namespace:*)'
33
+ backend.to_s.should == 'Picky::Backends::Redis::Basic(some_namespace:*)'
35
34
  end
36
35
  end
37
36
  end
38
37
 
39
38
  context 'with options' do
40
- let(:index) do
39
+ let(:backend) do
41
40
  described_class.new client,
42
41
  :some_namespace,
43
42
  empty: [],
@@ -45,14 +44,14 @@ describe Picky::Backends::Redis::Basic do
45
44
  end
46
45
 
47
46
  describe 'empty' do
48
- it 'returns the container that is used for indexing' do
49
- index.empty.should == []
47
+ it 'returns the container that is used for backending' do
48
+ backend.empty.should == []
50
49
  end
51
50
  end
52
51
 
53
52
  describe 'initial' do
54
53
  it 'is correct' do
55
- index.initial.class.should == Array
54
+ backend.initial.class.should == Array
56
55
  end
57
56
  end
58
57
  end