tanker 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/tanker_spec.rb CHANGED
@@ -2,51 +2,184 @@ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
2
 
3
3
  describe Tanker do
4
4
 
5
- it 'sets configuration' do
6
- conf = {:url => 'http://api.indextank.com'}
7
- Tanker.configuration = conf
5
+ describe "configuration" do
8
6
 
9
- Tanker.configuration.should == conf
10
- end
7
+ it 'sets configuration' do
8
+ conf = {:url => 'http://api.indextank.com', :pagination_backend => :will_paginate}
9
+ Tanker.configuration = conf
11
10
 
12
- it 'checks for configuration when the module is included' do
13
- Tanker.configuration = nil
11
+ Tanker.configuration.should == conf
12
+ end
14
13
 
15
- lambda {
16
- Dummy.send(:include, Tanker)
17
- }.should raise_error(Tanker::NotConfigured)
18
- end
14
+ it 'adds default values to configuration on set if needed' do
15
+ conf = {:url => 'http://api.indextank.com'}
16
+ Tanker.configuration = conf
17
+ Tanker.configuration.should == conf.merge(:pagination_backend => :will_paginate)
18
+ end
19
19
 
20
- it 'should requiquire a block when seting up tanker model' do
21
- Tanker.configuration = {:url => 'http://api.indextank.com'}
22
- Dummy.send(:include, Tanker)
23
- lambda {
24
- Dummy.send(:tankit, 'dummy index')
25
- }.should raise_error(Tanker::NoBlockGiven)
26
- end
20
+ it 'checks for configuration when the module is included' do
21
+ Tanker.configuration = nil
27
22
 
28
- it 'should set indexable fields' do
29
- Tanker.configuration = {:url => 'http://api.indextank.com'}
30
- Dummy.send(:include, Tanker)
31
- Dummy.send(:tankit, 'dummy index') do
32
- indexes :field
23
+ lambda {
24
+ Class.new.send(:include, Tanker)
25
+ }.should raise_error(Tanker::NotConfigured)
26
+ end
27
+
28
+ it 'should not add model to .included_in if not configured' do
29
+ Tanker.configuration = nil
30
+ begin
31
+ dummy_class = Class.new
32
+ dummy_class.send(:include, Tanker)
33
+ rescue Tanker::NotConfigured => e
34
+ Tanker.included_in.should_not include dummy_class
35
+ end
33
36
  end
34
37
 
35
- dummy_instance = Dummy.new
36
- dummy_instance.tanker_config.indexes.any? {|field, block| field == :field }.should == true
37
38
  end
38
39
 
39
- it 'should allow blocks for indexable field data' do
40
- Tanker.configuration = {:url => 'http://api.indextank.com'}
41
- Dummy.send(:include, Tanker)
42
- Dummy.send(:tankit, 'dummy index') do
43
- indexes :class_name do
44
- self.class.name
40
+ describe ".tankit" do
41
+
42
+ before :each do
43
+ Tanker.configuration = {:url => 'http://api.indextank.com'}
44
+ @dummy_class = Class.new do
45
+ include Tanker
46
+ end
47
+ end
48
+
49
+ after :each do
50
+ Tanker.instance_variable_set(:@included_in, Tanker.included_in - [@dummy_class])
51
+ end
52
+
53
+ it 'should require a block when setting up tanker model' do
54
+ lambda {
55
+ @dummy_class.send(:tankit, 'dummy index')
56
+ }.should raise_error(Tanker::NoBlockGiven)
57
+ end
58
+
59
+ it 'should set indexable fields' do
60
+ @dummy_class.send(:tankit, 'dummy index') do
61
+ indexes :field
62
+ end
63
+
64
+ dummy_instance = @dummy_class.new
65
+ dummy_instance.tanker_config.indexes.any? {|field, block| field == :field }.should == true
66
+ end
67
+
68
+ it 'should allow blocks for indexable field data' do
69
+ @dummy_class.send(:tankit, 'dummy index') do
70
+ indexes :class_name do
71
+ self.class.name
72
+ end
73
+ end
74
+
75
+ dummy_instance = @dummy_class.new
76
+ dummy_instance.tanker_config.indexes.any? {|field, block| field == :class_name }.should == true
77
+ end
78
+
79
+ it 'should overwrite the previous index name if provided' do
80
+ @dummy_class.send(:tankit, 'first index') do
81
+ end
82
+ @dummy_class.send(:tankit, 'second index') do
83
+ end
84
+
85
+ dummy_instance = @dummy_class.new
86
+ dummy_instance.tanker_config.index_name.should == 'second index'
87
+ end
88
+
89
+ it 'should keep the previous index name if not provided' do
90
+ @dummy_class.send(:tankit, 'dummy index') do
91
+ end
92
+ @dummy_class.send(:tankit) do
93
+ end
94
+
95
+ dummy_instance = @dummy_class.new
96
+ dummy_instance.tanker_config.index_name.should == 'dummy index'
97
+ end
98
+
99
+ it 'should keep previously indexed fields' do
100
+ @dummy_class.send(:tankit, 'dummy index') do
101
+ indexes :something
102
+ end
103
+ @dummy_class.send(:tankit, 'dummy index') do
104
+ indexes :something_else
105
+ end
106
+
107
+ dummy_instance = @dummy_class.new
108
+ Hash[*dummy_instance.tanker_config.indexes.flatten].keys.should == [:something, :something_else]
109
+ end
110
+
111
+ it 'should overwrite previously indexed fields if re-indexed' do
112
+ @dummy_class.send(:tankit, 'dummy index') do
113
+ indexes :something do
114
+ "first"
115
+ end
116
+ end
117
+ @dummy_class.send(:tankit, 'dummy index') do
118
+ indexes :something do
119
+ "second"
120
+ end
121
+ end
122
+
123
+ dummy_instance = @dummy_class.new
124
+ dummy_instance.stub!(:id => 1)
125
+ dummy_instance.tanker_index_data[:something].should == "second"
126
+ end
127
+
128
+ it 'should merge with previously defined variables' do
129
+ @dummy_class.send(:tankit, 'dummy index') do
130
+ variables do
131
+ {
132
+ 0 => 3.1415927,
133
+ 1 => 2.7182818
134
+ }
135
+ end
136
+ end
137
+ @dummy_class.send(:tankit, 'dummy index') do
138
+ variables do
139
+ {
140
+ 0 => 1.618034
141
+ }
142
+ end
143
+ end
144
+
145
+ dummy_instance = @dummy_class.new
146
+ dummy_instance.tanker_index_options[:variables].should == { 0 => 1.618034, 1 => 2.7182818 }
147
+ end
148
+
149
+ it 'should allow setting of __type by supplying :as option' do
150
+ @dummy_class.send(:tankit, 'dummy index', { :as => 'MySpecialModel' }) do
45
151
  end
152
+
153
+ dummy_instance = @dummy_class.new
154
+ dummy_instance.stub!(:id => 1)
155
+ dummy_instance.tanker_index_data[:__type].should == 'MySpecialModel'
46
156
  end
47
157
 
48
- dummy_instance = Dummy.new
49
- dummy_instance.tanker_config.indexes.any? {|field, block| field == :class_name }.should == true
158
+ it "can be initially defined in one module and extended in the including class" do
159
+ dummy_module = Module.new do
160
+ def self.included(base)
161
+ base.send :include, Tanker
162
+
163
+ base.tankit 'dummy index' do
164
+ indexes :name
165
+ end
166
+ end
167
+ end
168
+
169
+ dummy_class = Class.new do
170
+ include dummy_module
171
+
172
+ tankit 'another index' do
173
+ indexes :email
174
+ end
175
+ end
176
+
177
+ dummy_instance = dummy_class.new
178
+ dummy_instance.tanker_config.index_name.should == 'another index'
179
+ Hash[*dummy_instance.tanker_config.indexes.flatten].keys.should == [:name, :email]
180
+
181
+ Tanker.instance_variable_set(:@included_in, Tanker.included_in - [dummy_class])
182
+ end
50
183
  end
51
184
 
52
185
  describe 'tanker instance' do
@@ -63,8 +196,10 @@ describe Tanker do
63
196
  {
64
197
  "matches" => 1,
65
198
  "results" => [{
66
- "docid" => Person.new.it_doc_id,
67
- "name" => 'pedro'
199
+ "docid" => Person.new.it_doc_id,
200
+ "name" => 'pedro',
201
+ "__type" => 'Person',
202
+ "__id" => '1'
68
203
  }],
69
204
  "search_time" => 1
70
205
  }
@@ -82,10 +217,38 @@ describe Tanker do
82
217
  collection.current_page.should == 1
83
218
  end
84
219
 
220
+ it 'should handle string and integer ids in search results' do
221
+ Person.tanker_index.should_receive(:search).and_return(
222
+ {
223
+ "matches" => 2,
224
+ "results" => [{
225
+ "docid" => 'Person mystring1d',
226
+ "name" => 'pedro',
227
+ "__type" => 'Person',
228
+ "__id" => 'mystring1d'
229
+ },{
230
+ "docid" => 'Person 1',
231
+ "name" => 'jaun',
232
+ "__type" => 'Person',
233
+ "__id" => '1'
234
+ }],
235
+ "search_time" => 1
236
+ }
237
+ )
238
+
239
+ Person.should_receive(:find).with(['mystring1d', '1']).and_return(
240
+ [Person.new, Person.new]
241
+ )
242
+
243
+ collection = Person.search_tank('hey!')
244
+ collection.class.should == WillPaginate::Collection
245
+ collection.total_entries.should == 2
246
+ end
247
+
85
248
  it 'should be able to use multi-value query phrases' do
86
249
  Person.tanker_index.should_receive(:search).with(
87
- "__any:(hey! location_id:(1) location_id:(2)) __type:(Person)",
88
- {:start => 0, :len => 10}
250
+ 'name:(hey! location_id:(1) location_id:(2)) OR last_name:(hey! location_id:(1) location_id:(2)) __type:("Person")',
251
+ anything
89
252
  ).and_return({'results' => [], 'matches' => 0})
90
253
 
91
254
  collection = Person.search_tank('hey!', :conditions => {:location_id => [1,2]})
@@ -93,11 +256,8 @@ describe Tanker do
93
256
 
94
257
  it 'should be able to use filter_functions' do
95
258
  Person.tanker_index.should_receive(:search).with(
96
- "__any:(hey!) __type:(Person)",
97
- { :start => 0,
98
- :len => 10,
99
- :filter_function2 => "0:10,20:40"
100
- }
259
+ anything,
260
+ hash_including(:filter_function2 => "0:10,20:40")
101
261
  ).and_return({'results' => [], 'matches' => 0})
102
262
 
103
263
  collection = Person.search_tank('hey!',
@@ -107,11 +267,8 @@ describe Tanker do
107
267
  end
108
268
  it 'should be able to use filter_docvars' do
109
269
  Person.tanker_index.should_receive(:search).with(
110
- "__any:(hey!) __type:(Person)",
111
- { :start => 0,
112
- :len => 10,
113
- :filter_docvar3 => "*:7,80:100"
114
- }
270
+ anything,
271
+ hash_including(:filter_docvar3 => "*:7,80:100")
115
272
  ).and_return({'results' => [], 'matches' => 0})
116
273
 
117
274
  collection = Person.search_tank('hey!',
@@ -127,12 +284,16 @@ describe Tanker do
127
284
  {
128
285
  "matches" => 2,
129
286
  "results" => [{
130
- "docid" => 'Dog 7',
131
- "name" => 'fido'
287
+ "docid" => 'Dog 7',
288
+ "name" => 'fido',
289
+ "__type" => 'Dog',
290
+ "__id" => '7'
132
291
  },
133
292
  {
134
- "docid" => 'Cat 9',
135
- "name" => 'fluffy'
293
+ "docid" => 'Cat 9',
294
+ "name" => 'fluffy',
295
+ "__type" => 'Cat',
296
+ "__id" => '9'
136
297
  }],
137
298
  "search_time" => 1
138
299
  }
@@ -153,6 +314,82 @@ describe Tanker do
153
314
  collection.current_page.should == 1
154
315
  end
155
316
 
317
+ it 'should be able to search for modularized model classes' do
318
+ Foo::Bar.tanker_index.
319
+ should_receive(:search).
320
+ with(/__type:\(.*"Foo Bar".*\)/, anything).
321
+ and_return({
322
+ "results" => [{
323
+ "docid" => 'Foo::Bar 42',
324
+ "__type" => 'Foo::Bar',
325
+ "__id" => '42'
326
+ }]
327
+ })
328
+
329
+ Foo::Bar.should_receive(:find).and_return([stub(:id => 42)])
330
+
331
+ Foo::Bar.search_tank('bar')
332
+ end
333
+
334
+ it 'should be able to perform a search without pagination' do
335
+ Person.tanker_index.should_receive(:search).and_return(
336
+ {
337
+ "matches" => 2,
338
+ "results" => [{
339
+ "docid" => 'Person 1',
340
+ "name" => 'pedro',
341
+ "__type" => 'Person',
342
+ "__id" => '1'
343
+ },{
344
+ "docid" => 'Person 2',
345
+ "name" => 'jaun',
346
+ "__type" => 'Person',
347
+ "__id" => '2'
348
+ }],
349
+ "search_time" => 1
350
+ }
351
+ )
352
+
353
+ Person.should_receive(:find).with(['1', '2']).and_return(
354
+ [Person.new, Person.new]
355
+ )
356
+
357
+ collection = Person.search_tank('hey!', :paginate => false)
358
+ collection.class.should == Array
359
+ collection.size.should == 2
360
+ end
361
+
362
+ it 'should be able to perform a search with pagination settings in :paginate option' do
363
+ Person.tanker_index.should_receive(:search).and_return(
364
+ {
365
+ "matches" => 2,
366
+ "results" => [{
367
+ "docid" => 'Person 1',
368
+ "name" => 'pedro',
369
+ "__type" => 'Person',
370
+ "__id" => '1'
371
+ },{
372
+ "docid" => 'Person 2',
373
+ "name" => 'jaun',
374
+ "__type" => 'Person',
375
+ "__id" => '2'
376
+ }],
377
+ "search_time" => 1
378
+ }
379
+ )
380
+
381
+ Person.should_receive(:find).with(['1', '2']).and_return(
382
+ [Person.new, Person.new]
383
+ )
384
+
385
+ collection = Person.search_tank('hey!', :paginate => { :page => 2, :per_page => 1 })
386
+ collection.class.should == WillPaginate::Collection
387
+ collection.total_entries.should == 2
388
+ collection.total_pages.should == 2
389
+ collection.per_page.should == 1
390
+ collection.current_page.should == 2
391
+ end
392
+
156
393
  it 'should be able to update the index' do
157
394
  person = Person.new(:name => 'Name', :last_name => 'Last Name')
158
395
 
@@ -161,6 +398,7 @@ describe Tanker do
161
398
  {
162
399
  :__any => "#{$frozen_moment.to_i} . Last Name . Name",
163
400
  :__type => 'Person',
401
+ :__id => 1,
164
402
  :name => 'Name',
165
403
  :last_name => 'Last Name',
166
404
  :timestamp => $frozen_moment.to_i
@@ -186,6 +424,7 @@ describe Tanker do
186
424
  :fields => {
187
425
  :__any => "#{$frozen_moment.to_i} . Last Name . Name",
188
426
  :__type => 'Person',
427
+ :__id => 1,
189
428
  :name => 'Name',
190
429
  :last_name => 'Last Name',
191
430
  :timestamp => $frozen_moment.to_i
@@ -209,5 +448,96 @@ describe Tanker do
209
448
  person.delete_tank_indexes
210
449
  end
211
450
 
451
+ describe 'snippets' do
452
+ it 'should not call find method but instead create new instances the models matched the search with the snippetted fields as snippet_ attributes' do
453
+ Person.tanker_index.should_receive(:search).and_return(
454
+ {
455
+ "matches" => 1,
456
+ "results" => [{
457
+ "docid" => Person.new.it_doc_id,
458
+ 'snippet_name' => 'ped...',
459
+ "__type" => 'Person',
460
+ "__id" => '1'
461
+ }],
462
+ "search_time" => 1
463
+ })
464
+
465
+ collection = Person.search_tank('hey!', :snippets => [:name])
466
+ collection[0].name_snippet.should == 'ped...'
467
+ end
468
+ end
469
+
470
+ describe 'fetch' do
471
+ it 'should not call find method but instead create new instances the models matched the search with the fetched fields as attributes' do
472
+ Person.tanker_index.should_receive(:search).and_return(
473
+ {
474
+ "matches" => 1,
475
+ "results" => [{
476
+ "docid" => Person.new.it_doc_id,
477
+ 'name' => 'Osama',
478
+ "__type" => 'Person',
479
+ "__id" => '1'
480
+ }],
481
+ "search_time" => 1
482
+ })
483
+
484
+ collection = Person.search_tank('terrorist', :fetch => [:name])
485
+ collection[0].name.should == 'Osama'
486
+ end
487
+ end
488
+ end
489
+
490
+ describe "Kaminari support" do
491
+
492
+ before :all do
493
+ Tanker.configuration = {:url => 'http://api.indextank.com', :pagination_backend => :kaminari}
494
+ end
495
+
496
+ after :all do
497
+ Tanker.configuration = {}
498
+ end
499
+
500
+ it 'should raise error message if Kaminari gem is not required' do
501
+ Person.tanker_index.should_receive(:search).and_return(
502
+ {
503
+ "matches" => 1,
504
+ "results" => [{
505
+ "docid" => Person.new.it_doc_id,
506
+ "name" => 'pedro',
507
+ "__type" => 'Person',
508
+ "__id" => '1'
509
+ }],
510
+ "search_time" => 1
511
+ }
512
+ )
513
+ Person.should_receive(:find).and_return([Person.new])
514
+
515
+ lambda { Person.search_tank('test') }.should raise_error(Tanker::BadConfiguration)
516
+ end
517
+
518
+ it 'should be able to return Kaminari compatible array for a search' do
519
+ require 'kaminari'
520
+ Person.tanker_index.should_receive(:search).and_return(
521
+ {
522
+ "matches" => 1,
523
+ "results" => [{
524
+ "docid" => Person.new.it_doc_id,
525
+ "name" => 'pedro',
526
+ "__type" => 'Person',
527
+ "__id" => '1'
528
+ }],
529
+ "search_time" => 1
530
+ }
531
+ )
532
+
533
+ Person.should_receive(:find).and_return([Person.new])
534
+
535
+ array = Person.search_tank('hey!')
536
+ array.class.should == Tanker::KaminariPaginatedArray
537
+ array.total_count.should == 1
538
+ array.num_pages.should == 1
539
+ array.limit_value.should == 10
540
+ array.current_page.should == 1
541
+ end
212
542
  end
213
543
  end
@@ -1,23 +1,32 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
2
 
3
- class Dummy
4
- include Tanker
3
+ describe Tanker::Utilities do
5
4
 
6
- tankit 'dummy index' do
7
- indexes :name
8
- end
5
+ before(:each) do
6
+
7
+ @included_in = Tanker.instance_variable_get :@included_in
8
+ Tanker.instance_variable_set :@included_in, []
9
9
 
10
- end
10
+ class Dummy
11
+ include Tanker
11
12
 
13
+ tankit 'dummy index' do
14
+ indexes :name
15
+ end
12
16
 
13
- describe Tanker::Utilities do
17
+ end
18
+ end
19
+
20
+ after(:each) do
21
+ Tanker.instance_variable_set :@included_in, @included_in
22
+ end
14
23
 
15
24
  it "should get the models where Tanker module was included" do
16
- (Tanker::Utilities.get_model_classes - [Dummy, Person, Dog, Cat]).should == []
25
+ (Tanker::Utilities.get_model_classes - [Dummy]).should == []
17
26
  end
18
27
 
19
28
  it "should get the available indexes" do
20
- Tanker::Utilities.get_available_indexes.should == ["people", "animals", "dummy index"]
29
+ Tanker::Utilities.get_available_indexes.should == ["dummy index"]
21
30
  end
22
31
 
23
32
  end
data/tanker.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{tanker}
8
- s.version = "1.0.0"
8
+ s.version = "1.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["@kidpollo", "Jack Danger Canty"]
12
- s.date = %q{2011-04-02}
11
+ s.authors = [%q{@kidpollo}, %q{Jack Danger Canty}]
12
+ s.date = %q{2011-06-06}
13
13
  s.description = %q{IndexTank is a great search indexing service, this gem tries to make any orm keep in sync with indextank with ease}
14
14
  s.email = %q{kidpollo@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -27,19 +27,23 @@ Gem::Specification.new do |s|
27
27
  "lib/indextank_client.rb",
28
28
  "lib/tanker.rb",
29
29
  "lib/tanker/configuration.rb",
30
+ "lib/tanker/paginated_array.rb",
30
31
  "lib/tanker/railtie.rb",
31
32
  "lib/tanker/tasks/tanker.rake",
32
33
  "lib/tanker/utilities.rb",
34
+ "spec/integration_spec.rb",
35
+ "spec/integration_spec_conf.rb.example",
33
36
  "spec/spec_helper.rb",
34
37
  "spec/tanker_spec.rb",
35
38
  "spec/utilities_spec.rb",
36
39
  "tanker.gemspec"
37
40
  ]
38
41
  s.homepage = %q{http://github.com/kidpollo/tanker}
39
- s.require_paths = ["lib"]
40
- s.rubygems_version = %q{1.7.1}
42
+ s.require_paths = [%q{lib}]
43
+ s.rubygems_version = %q{1.8.5}
41
44
  s.summary = %q{IndexTank integration to your favorite orm}
42
45
  s.test_files = [
46
+ "spec/integration_spec.rb",
43
47
  "spec/spec_helper.rb",
44
48
  "spec/tanker_spec.rb",
45
49
  "spec/utilities_spec.rb"
@@ -50,14 +54,20 @@ Gem::Specification.new do |s|
50
54
 
51
55
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
52
56
  s.add_runtime_dependency(%q<jeweler>, [">= 0"])
57
+ s.add_runtime_dependency(%q<json>, [">= 1.5.1"])
53
58
  s.add_runtime_dependency(%q<will_paginate>, [">= 2.3.15"])
59
+ s.add_runtime_dependency(%q<kaminari>, [">= 0"])
54
60
  else
55
61
  s.add_dependency(%q<jeweler>, [">= 0"])
62
+ s.add_dependency(%q<json>, [">= 1.5.1"])
56
63
  s.add_dependency(%q<will_paginate>, [">= 2.3.15"])
64
+ s.add_dependency(%q<kaminari>, [">= 0"])
57
65
  end
58
66
  else
59
67
  s.add_dependency(%q<jeweler>, [">= 0"])
68
+ s.add_dependency(%q<json>, [">= 1.5.1"])
60
69
  s.add_dependency(%q<will_paginate>, [">= 2.3.15"])
70
+ s.add_dependency(%q<kaminari>, [">= 0"])
61
71
  end
62
72
  end
63
73