thinking-sphinx 1.3.18 → 1.3.19

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -165,3 +165,10 @@ Since I first released this library, there's been quite a few people who have su
165
165
  * Tomáš Pospíšek
166
166
  * Tom Stuart
167
167
  * James Brooks
168
+ * Mark Dodwell
169
+ * Frédéric Malamitsas
170
+ * Jon Gubman
171
+ * Michael Schuerig
172
+ * Ben Hutton
173
+ * Alfonso Jiménez
174
+ * Szymon Nowak
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.18
1
+ 1.3.19
@@ -27,7 +27,7 @@ Feature: Search and browse models by their defined facets
27
27
  And I should have the facet State
28
28
  And I should have the facet Age
29
29
 
30
- Scenario: Requseting float facets
30
+ Scenario: Requesting float facets
31
31
  Given Sphinx is running
32
32
  And I am searching on alphas
33
33
  When I am requesting facet results
@@ -80,3 +80,11 @@ Feature: Search and browse models by their defined facets
80
80
  And I am searching on posts
81
81
  When I am requesting facet results
82
82
  Then the Comment Ids facet should have 9 keys
83
+
84
+ Scenario: Requesting facets from a subclass
85
+ Given Sphinx is running
86
+ And I am searching on animals
87
+ When I am requesting facet results
88
+ And I want classes included
89
+ Then I should have the facet Class
90
+
@@ -40,3 +40,11 @@ Feature: Sphinx Scopes
40
40
  When I use the with_first_name scope set to "Andrew"
41
41
  And I am retrieving the scoped result count
42
42
  Then I should get a value of 7
43
+
44
+ Scenario: Counts with scopes and additional query terms
45
+ Given Sphinx is running
46
+ And I am searching on people
47
+ When I use the with_first_name scope set to "Andrew"
48
+ And I am retrieving the scoped result count for "Byrne"
49
+ Then I should get a value of 1
50
+
@@ -13,3 +13,7 @@ end
13
13
  When /^I am retrieving the scoped result count$/ do
14
14
  @results = results.search_count
15
15
  end
16
+
17
+ When /^I am retrieving the scoped result count for "([^"]*)"$/ do |query|
18
+ @results = results.search_count query
19
+ end
@@ -1,8 +1,12 @@
1
1
  require 'thinking_sphinx/test'
2
2
 
3
- class Cucumber::ThinkingSphinx::ExternalWorld
4
- def initialize(suppress_delta_output = true)
5
- ::ThinkingSphinx::Test.init
6
- ::ThinkingSphinx::Test.start_with_autostop
3
+ module Cucumber
4
+ module ThinkingSphinx
5
+ class ExternalWorld
6
+ def initialize(suppress_delta_output = true)
7
+ ::ThinkingSphinx::Test.init
8
+ ::ThinkingSphinx::Test.start_with_autostop
9
+ end
10
+ end
7
11
  end
8
12
  end
@@ -322,6 +322,10 @@ module ThinkingSphinx
322
322
  end
323
323
  end
324
324
 
325
+ attr_accessor :excerpts
326
+ attr_accessor :sphinx_attributes
327
+ attr_accessor :matching_fields
328
+
325
329
  def in_index?(suffix)
326
330
  self.class.search_for_id self.sphinx_document_id, sphinx_index_name(suffix)
327
331
  end
@@ -12,7 +12,9 @@ module ThinkingSphinx
12
12
  def self.detect(model)
13
13
  case model.connection.class.name
14
14
  when "ActiveRecord::ConnectionAdapters::MysqlAdapter",
15
- "ActiveRecord::ConnectionAdapters::MysqlplusAdapter"
15
+ "ActiveRecord::ConnectionAdapters::MysqlplusAdapter",
16
+ "ActiveRecord::ConnectionAdapters::Mysql2Adapter",
17
+ "ActiveRecord::ConnectionAdapters::NullDBAdapter"
16
18
  ThinkingSphinx::MysqlAdapter.new model
17
19
  when "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter"
18
20
  ThinkingSphinx::PostgreSQLAdapter.new model
@@ -8,8 +8,9 @@ module ThinkingSphinx
8
8
  "class_crc"
9
9
  end
10
10
 
11
- def value(object, attribute_value)
12
- object.class.name
11
+ def value(object, attribute_hash)
12
+ crc = attribute_hash['class_crc']
13
+ ThinkingSphinx::Configuration.instance.models_by_crc[crc]
13
14
  end
14
15
  end
15
16
  end
@@ -44,7 +44,7 @@ module ThinkingSphinx
44
44
  config = ThinkingSphinx::Configuration.instance
45
45
  rotate = ThinkingSphinx.sphinx_running? ? "--rotate" : ""
46
46
 
47
- output = `#{config.bin_path}#{config.indexer_binary_name} --config '#{config.config_file}' #{rotate} #{model.delta_index_names.join(' ')}`
47
+ output = `#{config.bin_path}#{config.indexer_binary_name} --config "#{config.config_file}" #{rotate} #{model.delta_index_names.join(' ')}`
48
48
  puts(output) unless ThinkingSphinx.suppress_delta_output?
49
49
  end
50
50
 
@@ -71,7 +71,12 @@ module ThinkingSphinx
71
71
  @property.is_a?(Field) ? :string : @property.type
72
72
  end
73
73
 
74
- def value(object, attribute_value)
74
+ def float?
75
+ @property.type == :float
76
+ end
77
+
78
+ def value(object, attribute_hash)
79
+ attribute_value = attribute_hash['@groupby']
75
80
  return translate(object, attribute_value) if translate? || float?
76
81
 
77
82
  case @property.type
@@ -117,9 +122,5 @@ module ThinkingSphinx
117
122
  def column
118
123
  @property.columns.first
119
124
  end
120
-
121
- def float?
122
- @property.type == :float
123
- end
124
125
  end
125
126
  end
@@ -44,23 +44,21 @@ module ThinkingSphinx
44
44
  end
45
45
 
46
46
  def populate
47
- facet_names.each do |name|
48
- search_options = facet_search_options.merge(:group_by => name)
49
- add_from_results name, ThinkingSphinx.search(
50
- *(args + [search_options])
51
- )
52
- end
47
+ ThinkingSphinx::Search.bundle_searches(facet_names) { |sphinx, name|
48
+ sphinx.search *(args + [facet_search_options(name)])
49
+ }.each_with_index { |search, index|
50
+ add_from_results facet_names[index], search
51
+ }
53
52
  end
54
53
 
55
- def facet_search_options
56
- config = ThinkingSphinx::Configuration.instance
57
- max = config.configuration.searchd.max_matches || 1000
58
-
54
+ def facet_search_options(facet_name)
59
55
  options.merge(
60
56
  :group_function => :attr,
61
- :limit => max,
62
- :max_matches => max,
63
- :page => 1
57
+ :limit => max_matches,
58
+ :max_matches => max_matches,
59
+ :page => 1,
60
+ :group_by => facet_name,
61
+ :ids_only => !translate?(facet_name)
64
62
  )
65
63
  end
66
64
 
@@ -101,21 +99,34 @@ module ThinkingSphinx
101
99
  }
102
100
  end
103
101
 
104
- def add_from_results(facet, results)
105
- name = ThinkingSphinx::Facet.name_for(facet)
102
+ def translate?(name)
103
+ facet = facet_from_name(name)
104
+ facet.translate? || facet.float?
105
+ end
106
+
107
+ def config
108
+ ThinkingSphinx::Configuration.instance
109
+ end
110
+
111
+ def max_matches
112
+ @max_matches ||= config.configuration.searchd.max_matches || 1000
113
+ end
114
+
115
+ # example: facet = country_facet; name = :country
116
+ def add_from_results(facet, search)
117
+ name = ThinkingSphinx::Facet.name_for(facet)
118
+ facet = facet_from_name(facet)
106
119
 
107
120
  self[name] ||= {}
108
121
 
109
- return if results.empty?
110
-
111
- facet = facet_from_object(results.first, facet) if facet.is_a?(String)
122
+ return if search.empty?
112
123
 
113
- results.each_with_groupby_and_count { |result, group, count|
114
- facet_value = facet.value(result, group)
124
+ search.each_with_match do |result, match|
125
+ facet_value = facet.value(result, match[:attributes])
115
126
 
116
127
  self[name][facet_value] ||= 0
117
- self[name][facet_value] += count
118
- }
128
+ self[name][facet_value] += match[:attributes]["@count"]
129
+ end
119
130
  end
120
131
 
121
132
  def underlying_value(key, value)
@@ -130,7 +141,24 @@ module ThinkingSphinx
130
141
  end
131
142
 
132
143
  def facet_from_object(object, name)
133
- object.sphinx_facets.detect { |facet| facet.attribute_name == name }
144
+ facet = nil
145
+ klass = object.class
146
+
147
+ while klass != ::ActiveRecord::Base && facet.nil?
148
+ facet = klass.sphinx_facets.detect { |facet|
149
+ facet.attribute_name == name
150
+ }
151
+ klass = klass.superclass
152
+ end
153
+
154
+ facet
155
+ end
156
+
157
+ def facet_from_name(name)
158
+ name = ThinkingSphinx::Facet.name_for(name)
159
+ all_facets.detect { |facet|
160
+ facet.name == name
161
+ }
134
162
  end
135
163
  end
136
164
  end
@@ -57,6 +57,22 @@ module ThinkingSphinx
57
57
  ThinkingSphinx.facets *args
58
58
  end
59
59
 
60
+ def self.bundle_searches(enum)
61
+ client = ThinkingSphinx::Configuration.instance.client
62
+
63
+ searches = enum.collect { |item|
64
+ search = yield ThinkingSphinx, item
65
+ search.append_to client
66
+ search
67
+ }
68
+
69
+ client.run.each_with_index.collect { |results, index|
70
+ searches[index].populate_from_queue results
71
+ }
72
+
73
+ searches
74
+ end
75
+
60
76
  def self.matching_fields(fields, bitmask)
61
77
  matches = []
62
78
  bitstring = bitmask.to_s(2).rjust(32, '0').reverse
@@ -111,6 +127,7 @@ module ThinkingSphinx
111
127
  add_scope(method, *args, &block)
112
128
  return self
113
129
  elsif method == :search_count
130
+ merge_search one_class.search(*args)
114
131
  return scoped_count
115
132
  elsif method.to_s[/^each_with_.*/].nil? && !@array.respond_to?(method)
116
133
  super
@@ -186,6 +203,17 @@ module ThinkingSphinx
186
203
  # Compatibility with older versions of will_paginate
187
204
  alias_method :page_count, :total_pages
188
205
 
206
+ # Query time taken
207
+ #
208
+ # @return [Integer]
209
+ #
210
+ def query_time
211
+ populate
212
+ return 0 if @results[:time].nil?
213
+
214
+ @query_time ||= @results[:time]
215
+ end
216
+
189
217
  # The total number of search results available.
190
218
  #
191
219
  # @return [Integer]
@@ -232,6 +260,13 @@ module ThinkingSphinx
232
260
  end
233
261
  end
234
262
 
263
+ def each_with_match(&block)
264
+ populate
265
+ results[:matches].each_with_index do |match, index|
266
+ yield self[index], match
267
+ end
268
+ end
269
+
235
270
  def excerpt_for(string, model = nil)
236
271
  if model.nil? && one_class
237
272
  model ||= one_class
@@ -241,7 +276,7 @@ module ThinkingSphinx
241
276
  client.excerpts(
242
277
  :docs => [string],
243
278
  :words => results[:words].keys.join(' '),
244
- :index => "#{model.source_of_sphinx_index.sphinx_name}_core"
279
+ :index => options[:index] || "#{model.source_of_sphinx_index.sphinx_name}_core"
245
280
  ).first
246
281
  end
247
282
 
@@ -251,6 +286,29 @@ module ThinkingSphinx
251
286
  self
252
287
  end
253
288
 
289
+ def append_to(client)
290
+ prepare client
291
+ client.append_query query, indexes, comment
292
+ client.reset
293
+ end
294
+
295
+ def populate_from_queue(results)
296
+ return if @populated
297
+ @populated = true
298
+ @results = results
299
+
300
+ if options[:ids_only]
301
+ replace @results[:matches].collect { |match|
302
+ match[:attributes]["sphinx_internal_id"]
303
+ }
304
+ else
305
+ replace instances_from_matches
306
+ add_excerpter
307
+ add_sphinx_attributes
308
+ add_matching_fields if client.rank_mode == :fieldmask
309
+ end
310
+ end
311
+
254
312
  private
255
313
 
256
314
  def config
@@ -289,43 +347,32 @@ module ThinkingSphinx
289
347
 
290
348
  def add_excerpter
291
349
  each do |object|
292
- next if object.respond_to?(:excerpts)
293
-
294
- excerpter = ThinkingSphinx::Excerpter.new self, object
295
- block = lambda { excerpter }
350
+ next if object.nil?
296
351
 
297
- object.singleton_class.instance_eval do
298
- define_method(:excerpts, &block)
299
- end
352
+ object.excerpts = ThinkingSphinx::Excerpter.new self, object
300
353
  end
301
354
  end
302
355
 
303
356
  def add_sphinx_attributes
304
357
  each do |object|
305
- next if object.nil? || object.respond_to?(:sphinx_attributes)
358
+ next if object.nil?
306
359
 
307
360
  match = match_hash object
308
361
  next if match.nil?
309
362
 
310
- object.singleton_class.instance_eval do
311
- define_method(:sphinx_attributes) { match[:attributes] }
312
- end
363
+ object.sphinx_attributes = match[:attributes]
313
364
  end
314
365
  end
315
366
 
316
367
  def add_matching_fields
317
368
  each do |object|
318
- next if object.nil? || object.respond_to?(:matching_fields)
369
+ next if object.nil?
319
370
 
320
371
  match = match_hash object
321
372
  next if match.nil?
322
- fields = ThinkingSphinx::Search.matching_fields(
373
+ object.matching_fields = ThinkingSphinx::Search.matching_fields(
323
374
  @results[:fields], match[:weight]
324
375
  )
325
-
326
- object.singleton_class.instance_eval do
327
- define_method(:matching_fields) { fields }
328
- end
329
376
  end
330
377
  end
331
378
 
@@ -352,6 +399,10 @@ module ThinkingSphinx
352
399
  def client
353
400
  client = config.client
354
401
 
402
+ prepare client
403
+ end
404
+
405
+ def prepare(client)
355
406
  index_options = one_class ?
356
407
  one_class.sphinx_indexes.first.local_options : {}
357
408
 
@@ -588,14 +639,6 @@ MSG
588
639
  end
589
640
 
590
641
  # When passed a Time instance, returns the integer timestamp.
591
- #
592
- # If using Rails 2.1+, need to handle timezones to translate them back to
593
- # UTC, as that's what datetimes will be stored as by MySQL.
594
- #
595
- # in_time_zone is a method that was added for the timezone support in
596
- # Rails 2.1, which is why it's used for testing. I'm sure there's better
597
- # ways, but this does the job.
598
- #
599
642
  def filter_value(value)
600
643
  case value
601
644
  when Range
@@ -603,7 +646,7 @@ MSG
603
646
  when Array
604
647
  value.collect { |v| filter_value(v) }.flatten
605
648
  when Time
606
- value.respond_to?(:in_time_zone) ? [value.utc.to_i] : [value.to_i]
649
+ [value.to_i]
607
650
  when NilClass
608
651
  0
609
652
  else
@@ -4,7 +4,12 @@ namespace :thinking_sphinx do
4
4
  task :app_env do
5
5
  if defined?(RAILS_ROOT)
6
6
  Rake::Task[:environment].invoke
7
- Rails.configuration.cache_classes = false
7
+
8
+ if defined?(Rails.configuration)
9
+ Rails.configuration.cache_classes = false
10
+ else
11
+ Rails::Initializer.run { |config| config.cache_classes = false }
12
+ end
8
13
  end
9
14
 
10
15
  Rake::Task[:merb_env].invoke if defined?(Merb)
@@ -27,9 +27,12 @@ class ThinkingSphinx::Test
27
27
  end
28
28
 
29
29
  def self.run(&block)
30
- start
31
- yield
32
- stop
30
+ begin
31
+ start
32
+ yield
33
+ ensure
34
+ stop
35
+ end
33
36
  end
34
37
 
35
38
  def self.config
@@ -106,7 +106,7 @@ describe "ThinkingSphinx::ActiveRecord::Delta" do
106
106
 
107
107
  it "should call indexer for the delta index" do
108
108
  Person.sphinx_indexes.first.delta_object.should_receive(:`).with(
109
- "#{ThinkingSphinx::Configuration.instance.bin_path}indexer --config '#{ThinkingSphinx::Configuration.instance.config_file}' --rotate person_delta"
109
+ "#{ThinkingSphinx::Configuration.instance.bin_path}indexer --config \"#{ThinkingSphinx::Configuration.instance.config_file}\" --rotate person_delta"
110
110
  )
111
111
 
112
112
  @person.send(:index_delta)
@@ -1,28 +1,26 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ThinkingSphinx::FacetSearch do
4
+ let(:search) { stub('search', :append_to => nil, :empty? => true) }
5
+ let(:config) { ThinkingSphinx::Configuration.instance }
6
+ let(:client) { stub('client', :run => []) }
7
+
8
+ before :each do
9
+ config.stub!(:client => client)
10
+ end
11
+
4
12
  describe 'populate' do
5
- it "should make separate Sphinx queries for each facet" do
6
- ThinkingSphinx.should_receive(:search).with(
7
- hash_including(:group_by => 'city_facet')
8
- ).and_return([])
9
- ThinkingSphinx.should_receive(:search).with(
10
- hash_including(:group_by => 'state_facet')
11
- ).and_return([])
12
- ThinkingSphinx.should_receive(:search).with(
13
- hash_including(:group_by => 'birthday')
14
- ).and_return([])
15
-
16
- ThinkingSphinx::FacetSearch.new(:classes => [Person])
13
+ before :each do
14
+ config.configuration.searchd.max_matches = 10_000
17
15
  end
18
-
16
+
19
17
  it "should request all shared facets in a multi-model request by default" do
20
- ThinkingSphinx.stub!(:search => [])
18
+ ThinkingSphinx.stub!(:search => search)
21
19
  ThinkingSphinx::FacetSearch.new.facet_names.should == ['class_crc']
22
20
  end
23
21
 
24
22
  it "should request all facets in a multi-model request if specified" do
25
- ThinkingSphinx.stub!(:search => [])
23
+ ThinkingSphinx.stub!(:search => search)
26
24
  ThinkingSphinx::FacetSearch.new(
27
25
  :all_facets => true
28
26
  ).facet_names.should == [
@@ -30,80 +28,22 @@ describe ThinkingSphinx::FacetSearch do
30
28
  ]
31
29
  end
32
30
 
33
- describe ':facets option' do
34
- it "should limit facets to the requested set" do
35
- ThinkingSphinx.should_receive(:search).once.and_return([])
36
-
37
- ThinkingSphinx::FacetSearch.new(
38
- :classes => [Person], :facets => :state
39
- )
40
- end
41
- end
42
-
43
- describe "empty result set for attributes" do
44
- before :each do
45
- ThinkingSphinx.stub!(:search => [])
46
- @facets = ThinkingSphinx::FacetSearch.new(
47
- :classes => [Person], :facets => :state
48
- )
49
- end
50
-
51
- it "should add key as attribute" do
52
- @facets.should have_key(:state)
53
- end
54
-
55
- it "should return an empty hash for the facet results" do
56
- @facets[:state].should be_empty
57
- end
58
- end
59
-
60
- describe "non-empty result set" do
61
- before :each do
62
- @person = Person.find(:first)
63
- @people = [@person]
64
- @people.stub!(:each_with_groupby_and_count).
65
- and_yield(@person, @person.city.to_crc32, 1)
66
- ThinkingSphinx.stub!(:search => @people)
67
-
68
- @facets = ThinkingSphinx::FacetSearch.new(
69
- :classes => [Person], :facets => :city
70
- )
71
- end
72
-
73
- it "should return a hash" do
74
- @facets.should be_a_kind_of(Hash)
75
- end
76
-
77
- it "should add key as attribute" do
78
- @facets.keys.should include(:city)
79
- end
80
-
81
- it "should return a hash" do
82
- @facets[:city].should == {@person.city => 1}
83
- end
84
- end
85
-
86
- before :each do
87
- @config = ThinkingSphinx::Configuration.instance
88
- @config.configuration.searchd.max_matches = 10_000
89
- end
90
-
91
31
  it "should use the system-set max_matches for limit on facet calls" do
92
32
  ThinkingSphinx.should_receive(:search) do |options|
93
33
  options[:max_matches].should == 10_000
94
34
  options[:limit].should == 10_000
95
- []
35
+ search
96
36
  end
97
37
 
98
38
  ThinkingSphinx::FacetSearch.new
99
39
  end
100
40
 
101
41
  it "should use the default max-matches if there is no explicit setting" do
102
- @config.configuration.searchd.max_matches = nil
42
+ config.configuration.searchd.max_matches = nil
103
43
  ThinkingSphinx.should_receive(:search) do |options|
104
44
  options[:max_matches].should == 1000
105
45
  options[:limit].should == 1000
106
- []
46
+ search
107
47
  end
108
48
 
109
49
  ThinkingSphinx::FacetSearch.new
@@ -113,7 +53,7 @@ describe ThinkingSphinx::FacetSearch do
113
53
  ThinkingSphinx.should_receive(:search) do |options|
114
54
  options[:max_matches].should == 10_000
115
55
  options[:limit].should == 10_000
116
- []
56
+ search
117
57
  end
118
58
 
119
59
  ThinkingSphinx::FacetSearch.new(
@@ -125,7 +65,7 @@ describe ThinkingSphinx::FacetSearch do
125
65
  it "should not use an explicit :page" do
126
66
  ThinkingSphinx.should_receive(:search) do |options|
127
67
  options[:page].should == 1
128
- []
68
+ search
129
69
  end
130
70
 
131
71
  ThinkingSphinx::FacetSearch.new(:page => 3)
@@ -149,15 +89,69 @@ describe ThinkingSphinx::FacetSearch do
149
89
  }.should raise_error
150
90
  end
151
91
  end
92
+
93
+ describe ':facets option' do
94
+ it "should limit facets to the requested set" do
95
+ ThinkingSphinx.should_receive(:search).once.and_return(search)
96
+
97
+ ThinkingSphinx::FacetSearch.new(
98
+ :classes => [Person], :facets => :state
99
+ )
100
+ end
101
+ end
102
+
103
+ describe "empty result set for attributes" do
104
+ before :each do
105
+ ThinkingSphinx.stub!(:search => search)
106
+ @facets = ThinkingSphinx::FacetSearch.new(
107
+ :classes => [Person], :facets => :state
108
+ )
109
+ end
110
+
111
+ it "should add key as attribute" do
112
+ @facets.should have_key(:state)
113
+ end
114
+
115
+ it "should return an empty hash for the facet results" do
116
+ @facets[:state].should be_empty
117
+ end
118
+ end
119
+
120
+ describe "non-empty result set" do
121
+ before :each do
122
+ @person = Person.find(:first)
123
+ @people = [@person]
124
+ search.stub!(:empty? => false)
125
+ search.stub!(:each_with_match).
126
+ and_yield(@person, {:attributes => {'@groupby' => @person.city.to_crc32, '@count' => 1}})
127
+ ThinkingSphinx::Search.stub!(:bundle_searches => [search])
128
+
129
+ @facets = ThinkingSphinx::FacetSearch.new(
130
+ :classes => [Person], :facets => :city
131
+ )
132
+ end
133
+
134
+ it "should return a hash" do
135
+ @facets.should be_a_kind_of(Hash)
136
+ end
137
+
138
+ it "should add key as attribute" do
139
+ @facets.keys.should include(:city)
140
+ end
141
+
142
+ it "should return a hash" do
143
+ @facets[:city].should == {@person.city => 1}
144
+ end
145
+ end
152
146
  end
153
147
 
154
148
  describe "#for" do
155
149
  before do
156
150
  @person = Person.find(:first)
157
151
  @people = [@person]
158
- @people.stub!(:each_with_groupby_and_count).
159
- and_yield(@person, @person.city.to_crc32, 1)
160
- ThinkingSphinx.stub!(:search => @people)
152
+ search.stub!(:each_with_match).
153
+ and_yield(@person, {:attributes => {'@groupby' => @person.city.to_crc32, '@count' => 1}})
154
+ ThinkingSphinx::Search.stub!(:bundle_searches => [search])
161
155
 
162
156
  @facets = ThinkingSphinx::FacetSearch.new(
163
157
  :classes => [Person], :facets => :city
@@ -291,13 +291,13 @@ describe ThinkingSphinx::Facet do
291
291
  person = Person.find(:first)
292
292
  friendship = Friendship.new(:person => person)
293
293
 
294
- @facet.value(friendship, 1).should == person.first_name
294
+ @facet.value(friendship, {'first_name_facet' => 1}).should == person.first_name
295
295
  end
296
296
 
297
297
  it "should return nil if the association is nil" do
298
298
  friendship = Friendship.new(:person => nil)
299
299
 
300
- @facet.value(friendship, 1).should be_nil
300
+ @facet.value(friendship, {'first_name_facet' => 1}).should be_nil
301
301
  end
302
302
 
303
303
  it "should return multi-level association values" do
@@ -308,7 +308,7 @@ describe ThinkingSphinx::Facet do
308
308
  field = ThinkingSphinx::Field.new(
309
309
  @source, ThinkingSphinx::Index::FauxColumn.new(:person, :tags, :name)
310
310
  )
311
- ThinkingSphinx::Facet.new(field).value(friendship, 'buried'.to_crc32).
311
+ ThinkingSphinx::Facet.new(field).value(friendship, {'name_facet' => 'buried'.to_crc32}).
312
312
  should == 'buried'
313
313
  end
314
314
  end
@@ -326,7 +326,7 @@ describe ThinkingSphinx::Facet do
326
326
  it "should translate using the given model" do
327
327
  alpha = Alpha.new(:cost => 10.5)
328
328
 
329
- @facet.value(alpha, 1093140480).should == 10.5
329
+ @facet.value(alpha, {'cost' => 1093140480}).should == 10.5
330
330
  end
331
331
  end
332
332
  end
@@ -135,6 +135,10 @@ describe ThinkingSphinx::SearchMethods do
135
135
  end
136
136
 
137
137
  describe '.facets' do
138
+ before :each do
139
+ ThinkingSphinx::Search.stub!(:bundle_searches => [])
140
+ end
141
+
138
142
  it "should return a FacetSearch instance" do
139
143
  Alpha.facets.should be_a(ThinkingSphinx::FacetSearch)
140
144
  end
@@ -785,9 +785,10 @@ describe ThinkingSphinx::Search do
785
785
  end
786
786
 
787
787
  it "should set up the excerpter with the instances and search" do
788
- ThinkingSphinx::Excerpter.should_receive(:new).with(@search, @alpha_a)
789
- ThinkingSphinx::Excerpter.should_receive(:new).with(@search, @alpha_b)
790
-
788
+ [@alpha_a, @beta_b, @alpha_b, @beta_a].each do |object|
789
+ ThinkingSphinx::Excerpter.should_receive(:new).with(@search, object)
790
+ end
791
+
791
792
  @search.first
792
793
  end
793
794
  end
@@ -822,11 +823,6 @@ describe ThinkingSphinx::Search do
822
823
  search.first.should respond_to(:matching_fields)
823
824
  end
824
825
 
825
- it "should not add matching_fields method if using a different ranking mode" do
826
- search = ThinkingSphinx::Search.new :rank_mode => :bm25
827
- search.first.should_not respond_to(:matching_fields)
828
- end
829
-
830
826
  it "should not add matching_fields method if object already have one" do
831
827
  search = ThinkingSphinx::Search.new :rank_mode => :fieldmask
832
828
  search.last.matching_fields.should_not be_an(Array)
@@ -1112,6 +1108,15 @@ describe ThinkingSphinx::Search do
1112
1108
  @search.excerpt_for('string')
1113
1109
  end
1114
1110
 
1111
+ it "should respect the provided index option" do
1112
+ @search = ThinkingSphinx::Search.new(:classes => [Alpha], :index => 'foo')
1113
+ @client.should_receive(:excerpts) do |options|
1114
+ options[:index].should == 'foo'
1115
+ end
1116
+
1117
+ @search.excerpt_for('string')
1118
+ end
1119
+
1115
1120
  it "should optionally take a second argument to allow for multi-model searches" do
1116
1121
  @client.should_receive(:excerpts) do |options|
1117
1122
  options[:index].should == 'beta_core'
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require "#{File.dirname(__FILE__)}/../../lib/thinking_sphinx/test"
3
+
4
+ describe ThinkingSphinx::Test do
5
+ describe ".run" do
6
+ before :each do
7
+ ThinkingSphinx::Test.stub!(:start)
8
+ end
9
+
10
+ it "should call stop when an exception is raised by passed block" do
11
+ ThinkingSphinx::Test.should_receive(:stop)
12
+
13
+ begin
14
+ ThinkingSphinx::Test.run { raise FakeError }
15
+ rescue => FakeError
16
+ # we raised it manually ourselves!
17
+ end
18
+ end
19
+ end
20
+ end
@@ -23,7 +23,9 @@ Jeweler::Tasks.new do |gem|
23
23
  "VERSION"
24
24
  ]
25
25
  gem.test_files = FileList[
26
- "features/**/*",
26
+ "features/**/*.rb",
27
+ "features/**/*.feature",
28
+ "features/**/*.example.yml",
27
29
  "spec/**/*_spec.rb"
28
30
  ]
29
31
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thinking-sphinx
3
3
  version: !ruby/object:Gem::Version
4
- hash: 63
4
+ hash: 61
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 3
9
- - 18
10
- version: 1.3.18
9
+ - 19
10
+ version: 1.3.19
11
11
  platform: ruby
12
12
  authors:
13
13
  - Pat Allan
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-29 00:00:00 +10:00
18
+ date: 2010-08-23 00:00:00 +08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -214,24 +214,6 @@ files:
214
214
  - tasks/distribution.rb
215
215
  - tasks/rails.rake
216
216
  - tasks/testing.rb
217
- - features/abstract_inheritance.feature
218
- - features/alternate_primary_key.feature
219
- - features/attribute_transformation.feature
220
- - features/attribute_updates.feature
221
- - features/deleting_instances.feature
222
- - features/direct_attributes.feature
223
- - features/excerpts.feature
224
- - features/extensible_delta_indexing.feature
225
- - features/facets.feature
226
- - features/facets_across_model.feature
227
- - features/handling_edits.feature
228
- - features/retry_stale_indexes.feature
229
- - features/searching_across_models.feature
230
- - features/searching_by_index.feature
231
- - features/searching_by_model.feature
232
- - features/searching_with_find_arguments.feature
233
- - features/sphinx_detection.feature
234
- - features/sphinx_scopes.feature
235
217
  - features/step_definitions/alpha_steps.rb
236
218
  - features/step_definitions/beta_steps.rb
237
219
  - features/step_definitions/common_steps.rb
@@ -242,11 +224,8 @@ files:
242
224
  - features/step_definitions/scope_steps.rb
243
225
  - features/step_definitions/search_steps.rb
244
226
  - features/step_definitions/sphinx_steps.rb
245
- - features/sti_searching.feature
246
227
  - features/support/env.rb
247
228
  - features/support/lib/generic_delta_handler.rb
248
- - features/thinking_sphinx/database.example.yml
249
- - features/thinking_sphinx/database.yml
250
229
  - features/thinking_sphinx/db/fixtures/alphas.rb
251
230
  - features/thinking_sphinx/db/fixtures/authors.rb
252
231
  - features/thinking_sphinx/db/fixtures/betas.rb
@@ -303,6 +282,26 @@ files:
303
282
  - features/thinking_sphinx/models/robot.rb
304
283
  - features/thinking_sphinx/models/tag.rb
305
284
  - features/thinking_sphinx/models/tagging.rb
285
+ - features/abstract_inheritance.feature
286
+ - features/alternate_primary_key.feature
287
+ - features/attribute_transformation.feature
288
+ - features/attribute_updates.feature
289
+ - features/deleting_instances.feature
290
+ - features/direct_attributes.feature
291
+ - features/excerpts.feature
292
+ - features/extensible_delta_indexing.feature
293
+ - features/facets.feature
294
+ - features/facets_across_model.feature
295
+ - features/handling_edits.feature
296
+ - features/retry_stale_indexes.feature
297
+ - features/searching_across_models.feature
298
+ - features/searching_by_index.feature
299
+ - features/searching_by_model.feature
300
+ - features/searching_with_find_arguments.feature
301
+ - features/sphinx_detection.feature
302
+ - features/sphinx_scopes.feature
303
+ - features/sti_searching.feature
304
+ - features/thinking_sphinx/database.example.yml
306
305
  - spec/thinking_sphinx/active_record/delta_spec.rb
307
306
  - spec/thinking_sphinx/active_record/has_many_association_spec.rb
308
307
  - spec/thinking_sphinx/active_record/scopes_spec.rb
@@ -325,6 +324,7 @@ files:
325
324
  - spec/thinking_sphinx/search_methods_spec.rb
326
325
  - spec/thinking_sphinx/search_spec.rb
327
326
  - spec/thinking_sphinx/source_spec.rb
327
+ - spec/thinking_sphinx/test_spec.rb
328
328
  - spec/thinking_sphinx_spec.rb
329
329
  has_rdoc: true
330
330
  homepage: http://ts.freelancing-gods.com
@@ -364,24 +364,6 @@ signing_key:
364
364
  specification_version: 3
365
365
  summary: ActiveRecord/Rails Sphinx library
366
366
  test_files:
367
- - features/abstract_inheritance.feature
368
- - features/alternate_primary_key.feature
369
- - features/attribute_transformation.feature
370
- - features/attribute_updates.feature
371
- - features/deleting_instances.feature
372
- - features/direct_attributes.feature
373
- - features/excerpts.feature
374
- - features/extensible_delta_indexing.feature
375
- - features/facets.feature
376
- - features/facets_across_model.feature
377
- - features/handling_edits.feature
378
- - features/retry_stale_indexes.feature
379
- - features/searching_across_models.feature
380
- - features/searching_by_index.feature
381
- - features/searching_by_model.feature
382
- - features/searching_with_find_arguments.feature
383
- - features/sphinx_detection.feature
384
- - features/sphinx_scopes.feature
385
367
  - features/step_definitions/alpha_steps.rb
386
368
  - features/step_definitions/beta_steps.rb
387
369
  - features/step_definitions/common_steps.rb
@@ -392,11 +374,8 @@ test_files:
392
374
  - features/step_definitions/scope_steps.rb
393
375
  - features/step_definitions/search_steps.rb
394
376
  - features/step_definitions/sphinx_steps.rb
395
- - features/sti_searching.feature
396
377
  - features/support/env.rb
397
378
  - features/support/lib/generic_delta_handler.rb
398
- - features/thinking_sphinx/database.example.yml
399
- - features/thinking_sphinx/database.yml
400
379
  - features/thinking_sphinx/db/fixtures/alphas.rb
401
380
  - features/thinking_sphinx/db/fixtures/authors.rb
402
381
  - features/thinking_sphinx/db/fixtures/betas.rb
@@ -453,6 +432,26 @@ test_files:
453
432
  - features/thinking_sphinx/models/robot.rb
454
433
  - features/thinking_sphinx/models/tag.rb
455
434
  - features/thinking_sphinx/models/tagging.rb
435
+ - features/abstract_inheritance.feature
436
+ - features/alternate_primary_key.feature
437
+ - features/attribute_transformation.feature
438
+ - features/attribute_updates.feature
439
+ - features/deleting_instances.feature
440
+ - features/direct_attributes.feature
441
+ - features/excerpts.feature
442
+ - features/extensible_delta_indexing.feature
443
+ - features/facets.feature
444
+ - features/facets_across_model.feature
445
+ - features/handling_edits.feature
446
+ - features/retry_stale_indexes.feature
447
+ - features/searching_across_models.feature
448
+ - features/searching_by_index.feature
449
+ - features/searching_by_model.feature
450
+ - features/searching_with_find_arguments.feature
451
+ - features/sphinx_detection.feature
452
+ - features/sphinx_scopes.feature
453
+ - features/sti_searching.feature
454
+ - features/thinking_sphinx/database.example.yml
456
455
  - spec/thinking_sphinx/active_record/delta_spec.rb
457
456
  - spec/thinking_sphinx/active_record/has_many_association_spec.rb
458
457
  - spec/thinking_sphinx/active_record/scopes_spec.rb
@@ -475,4 +474,5 @@ test_files:
475
474
  - spec/thinking_sphinx/search_methods_spec.rb
476
475
  - spec/thinking_sphinx/search_spec.rb
477
476
  - spec/thinking_sphinx/source_spec.rb
477
+ - spec/thinking_sphinx/test_spec.rb
478
478
  - spec/thinking_sphinx_spec.rb
@@ -1,3 +0,0 @@
1
- username: thinking_sphinx
2
- pool: 1
3
- min_messages: warning