fuzzzy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,165 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fuzzzy::Mongoid::Index do
4
+ let(:context){{
5
+ :index_name => 'indexedcity:name',
6
+ :method => :soundex
7
+ }}
8
+
9
+ describe '.define_fuzzzy_index' do
10
+ context 'without index' do
11
+ let!(:city){City}
12
+ specify{city.fuzzzy_indexes.should be_nil}
13
+ specify{city.has_fuzzzy_indexes?.should be_false}
14
+ end
15
+
16
+ context 'with default index' do
17
+ let!(:city){IndexedCity}
18
+ specify{city.fuzzzy_indexes.should be_instance_of(Hash)}
19
+ specify{city.fuzzzy_indexes.values.should have(1).index}
20
+ specify{city.fuzzzy_indexes[:name].should == context}
21
+ specify{city.has_fuzzzy_indexes?.should be_true}
22
+ end
23
+ end
24
+
25
+ describe '.indexer' do
26
+ specify{IndexedCity.indexer(:soundex).should be_instance_of(Fuzzzy::Soundex::Indexer)}
27
+ specify{City.indexer(:soundex).should be_nil}
28
+ specify do
29
+ lambda{
30
+ IndexedCity.indexer(:blablabla)
31
+ }.should raise_error
32
+ end
33
+ end
34
+
35
+ describe '.searcher' do
36
+ specify{IndexedCity.searcher(:soundex).should be_instance_of(Fuzzzy::Soundex::Searcher)}
37
+ specify{City.searcher(:soundex).should be_nil}
38
+ specify do
39
+ lambda{
40
+ IndexedCity.searcher(:blablabla)
41
+ }.should raise_error
42
+ end
43
+ end
44
+
45
+ describe '.search_by' do
46
+ let(:query){'String'}
47
+
48
+ context 'by indexed field' do
49
+ let(:searcher){mock(:searcher)}
50
+
51
+ before do
52
+ searcher.should_receive(:search).with(search_context)
53
+ IndexedCity.stub(:searcher => searcher)
54
+ end
55
+
56
+ context 'with default context' do
57
+ let(:search_context){context.merge(:query => query)}
58
+ specify{IndexedCity.search_by(:name, query)}
59
+ end
60
+
61
+ context 'with custom context' do
62
+ let(:search_context){context.merge(
63
+ :query => query,
64
+ :only_ids => true,
65
+ :sort_method => :alpha,
66
+ :distance => 3
67
+ )}
68
+
69
+ specify{IndexedCity.search_by(:name, query, {
70
+ :only_ids => true,
71
+ :sort_method => :alpha,
72
+ :distance => 3
73
+ })}
74
+ end
75
+ end
76
+
77
+ context 'by unindexed field' do
78
+ specify do
79
+ lambda{
80
+ IndexedCity.search_by(:country, query)
81
+ }.should raise_error
82
+ end
83
+ end
84
+ end
85
+
86
+ context do
87
+ let(:model){IndexedCity.new(:id => BSON::ObjectId.new, :name => 'Moscow', :country => 'Russia')}
88
+ let(:indexer){mock(:indexer)}
89
+
90
+ describe '.create_fuzzzy_indexes' do
91
+ context do
92
+ let(:index_context){context.merge(
93
+ :id => model.id,
94
+ :dictionary_string => model.name
95
+ )}
96
+
97
+ before do
98
+ indexer.should_receive(:create_index).with(index_context)
99
+ IndexedCity.stub(:indexer => indexer)
100
+ end
101
+
102
+ specify{model.create_fuzzzy_indexes{}}
103
+ end
104
+
105
+ context 'with multi fields index' do
106
+ before do
107
+ IndexedCity.define_fuzzzy_index(:country)
108
+ indexer.should_receive(:create_index).exactly(2).times
109
+ IndexedCity.stub(:indexer => indexer)
110
+ end
111
+
112
+ after do
113
+ IndexedCity.clear_fuzzzy_index(:country)
114
+ end
115
+
116
+ specify{model.create_fuzzzy_indexes{}}
117
+ end
118
+
119
+ context 'with empty changed attributes' do
120
+ let(:index_context){context.merge(
121
+ :id => model.id,
122
+ :dictionary_string => model.name
123
+ )}
124
+
125
+ before do
126
+ model.stub(:changed => [])
127
+ indexer.should_not_receive(:create_index)
128
+ IndexedCity.stub(:indexer => indexer)
129
+ end
130
+
131
+ specify{model.create_fuzzzy_indexes{}}
132
+ end
133
+ end
134
+
135
+ describe '.delete_fuzzzy_indexes' do
136
+ context do
137
+ let(:index_context){context.merge(
138
+ :id => model.id,
139
+ :dictionary_string => model.name
140
+ )}
141
+
142
+ before do
143
+ indexer.should_receive(:delete_index).with(index_context)
144
+ IndexedCity.stub(:indexer => indexer)
145
+ end
146
+
147
+ specify{model.delete_fuzzzy_indexes{}}
148
+ end
149
+
150
+ context 'with multi fields index' do
151
+ before do
152
+ IndexedCity.define_fuzzzy_index(:country)
153
+ indexer.should_receive(:delete_index).exactly(2).times
154
+ IndexedCity.stub(:indexer => indexer)
155
+ end
156
+
157
+ after do
158
+ IndexedCity.clear_fuzzzy_index(:country)
159
+ end
160
+
161
+ specify{model.delete_fuzzzy_indexes{}}
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ class TestRedis
4
+ include Fuzzzy::Redis
5
+
6
+ def index_type
7
+ 'index_type'
8
+ end
9
+
10
+ def index_name
11
+ 'model_name:field'
12
+ end
13
+
14
+ def context
15
+ {}
16
+ end
17
+ end
18
+
19
+ class TestRedis2
20
+ include Fuzzzy::Redis
21
+ end
22
+
23
+
24
+ describe Fuzzzy::Redis do
25
+ subject{TestRedis.new}
26
+
27
+ describe '#shared_key' do
28
+ specify{subject.shared_key.should == 'fuzzzy:model_name:field'}
29
+ end
30
+
31
+ describe '#index_key' do
32
+ specify{subject.index_key('key1').should == 'fuzzzy:model_name:field:index_type:key1'}
33
+ specify{subject.index_key('key1', 'key2').should == 'fuzzzy:model_name:field:index_type:key1:key2'}
34
+ specify{subject.index_key('key1', 2).should == 'fuzzzy:model_name:field:index_type:key1:2'}
35
+ specify do
36
+ lambda{
37
+ subject.index_key
38
+ }.should raise_error
39
+ end
40
+ context do
41
+ subject{TestRedis2.new}
42
+ specify do
43
+ lambda{
44
+ subject.index_key('key1')
45
+ }.should raise_error
46
+ end
47
+ specify do
48
+ lambda{
49
+ subject.index_key('key1', 'key2')
50
+ }.should raise_error
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fuzzzy::Soundex::Indexer do
4
+ let(:indexer){Fuzzzy::Soundex::Indexer.new}
5
+ let(:context){{
6
+ :index_name => 'city:name',
7
+ :method => :soundex,
8
+ :dictionary_string => dictionary_string,
9
+ :id => id
10
+ }}
11
+ let(:dictionary_string){'moscow'}
12
+ let(:soundex){Text::Soundex.soundex(dictionary_string)}
13
+ let(:id){'12345'}
14
+
15
+ before do
16
+ keys = Fuzzzy.redis.keys("*")
17
+ Fuzzzy.redis.del(*keys) if keys.length > 1
18
+ end
19
+
20
+ describe '.create_index' do
21
+ before do
22
+ indexer.create_index(context)
23
+ end
24
+
25
+ specify{Fuzzzy.redis.smembers('fuzzzy:city:name:soundex_i:' + soundex).should == [id]}
26
+ specify{Fuzzzy.redis.get('fuzzzy:city:name:dictionary:' + id).should == dictionary_string}
27
+ specify{Fuzzzy.redis.hgetall(Fuzzzy::Redis.counter_key).should == {'city:name' => '1'}}
28
+ end
29
+
30
+ describe '.delete_index' do
31
+ before do
32
+ indexer.create_index(context)
33
+ indexer.delete_index(context)
34
+ end
35
+
36
+ specify{Fuzzzy.redis.exists('fuzzzy:city:name:soundex_i:' + soundex).should be_false}
37
+ specify{Fuzzzy.redis.exists('fuzzzy:city:name:dictionary:' + id).should be_false}
38
+ specify{Fuzzzy.redis.hgetall(Fuzzzy::Redis.counter_key).should == {'city:name' => '0'}}
39
+ end
40
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fuzzzy::Soundex::Searcher do
4
+ let(:searcher){Fuzzzy::Soundex::Searcher.new}
5
+ let(:context){{
6
+ :index_name => 'city:name',
7
+ :method => :soundex,
8
+ :query => query_string
9
+ }}
10
+
11
+ before do
12
+ keys = Fuzzzy.redis.keys("*")
13
+ Fuzzzy.redis.del(*keys) if keys.length > 1
14
+ end
15
+
16
+ def add_index id, dictionary_string
17
+ Fuzzzy.redis.sadd('fuzzzy:city:name:soundex_i:' + Text::Soundex.soundex(dictionary_string), id)
18
+ Fuzzzy.redis.set('fuzzzy:city:name:dictionary:' + id, dictionary_string)
19
+ end
20
+
21
+ describe '#search' do
22
+ context 'single word' do
23
+ before do
24
+ add_index(id, dictionary_string)
25
+ end
26
+
27
+ let(:query_string){'mascow'}
28
+ let(:dictionary_string){'moscow'}
29
+ let(:id){'12345'}
30
+
31
+ specify{searcher.search(context).should == [id]}
32
+ end
33
+
34
+ context 'many words' do
35
+ before do
36
+ add_index('12345', 'moscow')
37
+ add_index('12346', 'piterburger')
38
+ add_index('12347', 'piterberg')
39
+ add_index('12348', 'piterburg')
40
+ add_index('12349', 'pitsburg')
41
+ add_index('12350', 'moscowcity')
42
+ end
43
+
44
+ let(:query_string){'mascow'}
45
+
46
+ specify{searcher.search(context).should == ['12345']}
47
+ specify{searcher.search(context.merge(:query => 'mascw')).should == ['12345']}
48
+ specify{searcher.search(context.merge(:query => 'peterberg')).should == ['12346', '12347', '12348']}
49
+ specify{searcher.search(context.merge(
50
+ :query => 'piterburg',
51
+ :sort_by => :distance
52
+ )).should == ['12348', '12347', '12346']}
53
+ specify{searcher.search(context.merge(
54
+ :query => 'piterburg',
55
+ :sort_by => :alpha
56
+ )).should == ['12347', '12348', '12346']}
57
+ specify{searcher.search(context.merge(
58
+ :query => 'piterburg',
59
+ :distance => 0
60
+ )).should == ['12348']}
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,22 @@
1
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
2
+ ENV['RACK_ENV'] = 'test'
3
+ require "rspec"
4
+ require 'mongoid'
5
+ require 'fuzzzy'
6
+ require Fuzzzy.root.join('spec', 'models', 'city')
7
+ require Fuzzzy.root.join('spec', 'models', 'indexed_city')
8
+
9
+ Fuzzzy.redis = Redis.new(:host => 'localhost', :database => 10)
10
+ Fuzzzy.logger = Mongoid.logger = nil
11
+ Mongoid.load!(Fuzzzy.root.join('spec', 'config', 'mongoid.yml'))
12
+
13
+ RSpec.configure do |config|
14
+ config.mock_with :rspec
15
+ config.after :suite do
16
+ Mongoid.master.collections.select{|c| c.name !~ /system/ }.each(&:drop)
17
+ keys = Fuzzzy.redis.keys("*")
18
+ if keys.length > 1
19
+ Fuzzzy.redis.del(*keys)
20
+ end
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,325 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fuzzzy
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Undr
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2012-07-19 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: &id001 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "2"
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: yard
28
+ requirement: &id002 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: ruby-debug19
39
+ requirement: &id003 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: bson_ext
50
+ requirement: &id004 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: mongoid
61
+ requirement: &id005 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *id005
70
+ - !ruby/object:Gem::Dependency
71
+ name: pry
72
+ requirement: &id006 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: *id006
81
+ - !ruby/object:Gem::Dependency
82
+ name: ruby-prof
83
+ requirement: &id007 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: "0"
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: *id007
92
+ - !ruby/object:Gem::Dependency
93
+ name: bundler
94
+ requirement: &id008 !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: "0"
100
+ type: :runtime
101
+ prerelease: false
102
+ version_requirements: *id008
103
+ - !ruby/object:Gem::Dependency
104
+ name: rake
105
+ requirement: &id009 !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: "0"
111
+ type: :runtime
112
+ prerelease: false
113
+ version_requirements: *id009
114
+ - !ruby/object:Gem::Dependency
115
+ name: activesupport
116
+ requirement: &id010 !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: "0"
122
+ type: :runtime
123
+ prerelease: false
124
+ version_requirements: *id010
125
+ - !ruby/object:Gem::Dependency
126
+ name: eventmachine
127
+ requirement: &id011 !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: "0"
133
+ type: :runtime
134
+ prerelease: false
135
+ version_requirements: *id011
136
+ - !ruby/object:Gem::Dependency
137
+ name: yajl-ruby
138
+ requirement: &id012 !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: "0"
144
+ type: :runtime
145
+ prerelease: false
146
+ version_requirements: *id012
147
+ - !ruby/object:Gem::Dependency
148
+ name: levenshtein-ffi
149
+ requirement: &id013 !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: "0"
155
+ type: :runtime
156
+ prerelease: false
157
+ version_requirements: *id013
158
+ - !ruby/object:Gem::Dependency
159
+ name: text
160
+ requirement: &id014 !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: "0"
166
+ type: :runtime
167
+ prerelease: false
168
+ version_requirements: *id014
169
+ - !ruby/object:Gem::Dependency
170
+ name: grape
171
+ requirement: &id015 !ruby/object:Gem::Requirement
172
+ none: false
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: "0"
177
+ type: :runtime
178
+ prerelease: false
179
+ version_requirements: *id015
180
+ - !ruby/object:Gem::Dependency
181
+ name: hiredis
182
+ requirement: &id016 !ruby/object:Gem::Requirement
183
+ none: false
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: "0"
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: *id016
191
+ - !ruby/object:Gem::Dependency
192
+ name: redis
193
+ requirement: &id017 !ruby/object:Gem::Requirement
194
+ none: false
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: "0"
199
+ type: :runtime
200
+ prerelease: false
201
+ version_requirements: *id017
202
+ - !ruby/object:Gem::Dependency
203
+ name: daemons
204
+ requirement: &id018 !ruby/object:Gem::Requirement
205
+ none: false
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: "0"
210
+ type: :runtime
211
+ prerelease: false
212
+ version_requirements: *id018
213
+ - !ruby/object:Gem::Dependency
214
+ name: ZenTest
215
+ requirement: &id019 !ruby/object:Gem::Requirement
216
+ none: false
217
+ requirements:
218
+ - - "="
219
+ - !ruby/object:Gem::Version
220
+ version: 4.5.0
221
+ type: :runtime
222
+ prerelease: false
223
+ version_requirements: *id019
224
+ - !ruby/object:Gem::Dependency
225
+ name: RubyInline
226
+ requirement: &id020 !ruby/object:Gem::Requirement
227
+ none: false
228
+ requirements:
229
+ - - ">="
230
+ - !ruby/object:Gem::Version
231
+ version: "0"
232
+ type: :runtime
233
+ prerelease: false
234
+ version_requirements: *id020
235
+ description: Fuzzy Search client and server
236
+ email:
237
+ - lilipoper@gmail.com
238
+ executables: []
239
+
240
+ extensions: []
241
+
242
+ extra_rdoc_files: []
243
+
244
+ files:
245
+ - .gitignore
246
+ - .rspec
247
+ - .travis.yml
248
+ - Gemfile
249
+ - README.md
250
+ - Rakefile
251
+ - benchmark/data/cities.csv
252
+ - benchmark/fuzzzy_benchmark.rb
253
+ - benchmark/test_ngram.rb
254
+ - benchmark/test_soundex.rb
255
+ - config.ru
256
+ - dictionary/en_stopwords.yml
257
+ - fuzzzy.gemspec
258
+ - lib/fuzzzy.rb
259
+ - lib/fuzzzy/index.rb
260
+ - lib/fuzzzy/methods/indexer.rb
261
+ - lib/fuzzzy/methods/method_base.rb
262
+ - lib/fuzzzy/methods/ngram/base.rb
263
+ - lib/fuzzzy/methods/ngram/indexer.rb
264
+ - lib/fuzzzy/methods/ngram/searcher.rb
265
+ - lib/fuzzzy/methods/soundex/base.rb
266
+ - lib/fuzzzy/methods/soundex/indexer.rb
267
+ - lib/fuzzzy/methods/soundex/searcher.rb
268
+ - lib/fuzzzy/orm/mongoid/index.rb
269
+ - lib/fuzzzy/redis.rb
270
+ - lib/fuzzzy/server/http.rb
271
+ - lib/fuzzzy/version.rb
272
+ - spec/config/mongoid.yml
273
+ - spec/models/city.rb
274
+ - spec/models/indexed_city.rb
275
+ - spec/ngram/indexer_spec.rb
276
+ - spec/ngram/searcher_spec.rb
277
+ - spec/orm/mongoid/index_spec.rb
278
+ - spec/redis_spec.rb
279
+ - spec/soundex/indexer_spec.rb
280
+ - spec/soundex/searcher_spec.rb
281
+ - spec/spec_helper.rb
282
+ homepage: http://github.com/undr/fuzzzy
283
+ licenses: []
284
+
285
+ post_install_message:
286
+ rdoc_options: []
287
+
288
+ require_paths:
289
+ - lib
290
+ required_ruby_version: !ruby/object:Gem::Requirement
291
+ none: false
292
+ requirements:
293
+ - - ">="
294
+ - !ruby/object:Gem::Version
295
+ hash: -1332638981100280004
296
+ segments:
297
+ - 0
298
+ version: "0"
299
+ required_rubygems_version: !ruby/object:Gem::Requirement
300
+ none: false
301
+ requirements:
302
+ - - ">="
303
+ - !ruby/object:Gem::Version
304
+ hash: -1332638981100280004
305
+ segments:
306
+ - 0
307
+ version: "0"
308
+ requirements: []
309
+
310
+ rubyforge_project: fuzzzy
311
+ rubygems_version: 1.8.21
312
+ signing_key:
313
+ specification_version: 3
314
+ summary: Fuzzy Search client and server
315
+ test_files:
316
+ - spec/config/mongoid.yml
317
+ - spec/models/city.rb
318
+ - spec/models/indexed_city.rb
319
+ - spec/ngram/indexer_spec.rb
320
+ - spec/ngram/searcher_spec.rb
321
+ - spec/orm/mongoid/index_spec.rb
322
+ - spec/redis_spec.rb
323
+ - spec/soundex/indexer_spec.rb
324
+ - spec/soundex/searcher_spec.rb
325
+ - spec/spec_helper.rb