freelancing-god-thinking-sphinx 1.2.4 → 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +1 -0
- data/lib/thinking_sphinx.rb +47 -57
- data/lib/thinking_sphinx/active_record.rb +9 -4
- data/lib/thinking_sphinx/active_record/scopes.rb +3 -1
- data/lib/thinking_sphinx/rails_additions.rb +14 -0
- data/lib/thinking_sphinx/search.rb +16 -1
- data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +5 -1
- data/spec/lib/thinking_sphinx/active_record_spec.rb +25 -0
- data/spec/lib/thinking_sphinx/configuration_spec.rb +47 -41
- data/spec/lib/thinking_sphinx/rails_additions_spec.rb +12 -0
- data/spec/lib/thinking_sphinx/search_spec.rb +69 -7
- data/vendor/riddle/lib/riddle/controller.rb +12 -6
- metadata +2 -2
data/README.textile
CHANGED
data/lib/thinking_sphinx.rb
CHANGED
@@ -38,16 +38,16 @@ module ThinkingSphinx
|
|
38
38
|
module Version #:nodoc:
|
39
39
|
Major = 1
|
40
40
|
Minor = 2
|
41
|
-
Tiny =
|
41
|
+
Tiny = 5
|
42
42
|
|
43
43
|
String = [Major, Minor, Tiny].join('.')
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
# A ConnectionError will get thrown when a connection to Sphinx can't be
|
47
47
|
# made.
|
48
48
|
class ConnectionError < StandardError
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
# A StaleIdsException is thrown by Collection.instances_from_matches if there
|
52
52
|
# are records in Sphinx but not in the database, so the search can be retried.
|
53
53
|
class StaleIdsException < StandardError
|
@@ -56,42 +56,42 @@ module ThinkingSphinx
|
|
56
56
|
self.ids = ids
|
57
57
|
end
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
# The collection of indexed models. Keep in mind that Rails lazily loads
|
61
61
|
# its classes, so this may not actually be populated with _all_ the models
|
62
62
|
# that have Sphinx indexes.
|
63
63
|
def self.indexed_models
|
64
64
|
@@indexed_models ||= []
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
def self.unique_id_expression(offset = nil)
|
68
68
|
"* #{ThinkingSphinx.indexed_models.size} + #{offset || 0}"
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
# Check if index definition is disabled.
|
72
|
-
#
|
72
|
+
#
|
73
73
|
def self.define_indexes?
|
74
74
|
@@define_indexes = true unless defined?(@@define_indexes)
|
75
75
|
@@define_indexes == true
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
# Enable/disable indexes - you may want to do this while migrating data.
|
79
|
-
#
|
79
|
+
#
|
80
80
|
# ThinkingSphinx.define_indexes = false
|
81
|
-
#
|
81
|
+
#
|
82
82
|
def self.define_indexes=(value)
|
83
83
|
@@define_indexes = value
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
@@deltas_enabled = nil
|
87
87
|
|
88
88
|
# Check if delta indexing is enabled.
|
89
|
-
#
|
89
|
+
#
|
90
90
|
def self.deltas_enabled?
|
91
91
|
@@deltas_enabled = (ThinkingSphinx::Configuration.environment != 'test') if @@deltas_enabled.nil?
|
92
92
|
@@deltas_enabled
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
# Enable/disable all delta indexing.
|
96
96
|
#
|
97
97
|
# ThinkingSphinx.deltas_enabled = false
|
@@ -99,38 +99,38 @@ module ThinkingSphinx
|
|
99
99
|
def self.deltas_enabled=(value)
|
100
100
|
@@deltas_enabled = value
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
@@updates_enabled = nil
|
104
|
-
|
104
|
+
|
105
105
|
# Check if updates are enabled. True by default, unless within the test
|
106
106
|
# environment.
|
107
|
-
#
|
107
|
+
#
|
108
108
|
def self.updates_enabled?
|
109
109
|
@@updates_enabled = (ThinkingSphinx::Configuration.environment != 'test') if @@updates_enabled.nil?
|
110
110
|
@@updates_enabled
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
# Enable/disable updates to Sphinx
|
114
|
-
#
|
114
|
+
#
|
115
115
|
# ThinkingSphinx.updates_enabled = false
|
116
116
|
#
|
117
117
|
def self.updates_enabled=(value)
|
118
118
|
@@updates_enabled = value
|
119
119
|
end
|
120
|
-
|
120
|
+
|
121
121
|
@@suppress_delta_output = false
|
122
|
-
|
122
|
+
|
123
123
|
def self.suppress_delta_output?
|
124
124
|
@@suppress_delta_output
|
125
125
|
end
|
126
|
-
|
126
|
+
|
127
127
|
def self.suppress_delta_output=(value)
|
128
128
|
@@suppress_delta_output = value
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
# Checks to see if MySQL will allow simplistic GROUP BY statements. If not,
|
132
132
|
# or if not using MySQL, this will return false.
|
133
|
-
#
|
133
|
+
#
|
134
134
|
def self.use_group_by_shortcut?
|
135
135
|
!!(
|
136
136
|
mysql? && ::ActiveRecord::Base.connection.select_all(
|
@@ -138,75 +138,65 @@ module ThinkingSphinx
|
|
138
138
|
).all? { |key,value| value.nil? || value[/ONLY_FULL_GROUP_BY/].nil? }
|
139
139
|
)
|
140
140
|
end
|
141
|
-
|
141
|
+
|
142
142
|
@@remote_sphinx = false
|
143
|
-
|
143
|
+
|
144
144
|
# An indication of whether Sphinx is running on a remote machine instead of
|
145
145
|
# the same machine.
|
146
|
-
#
|
146
|
+
#
|
147
147
|
def self.remote_sphinx?
|
148
148
|
@@remote_sphinx
|
149
149
|
end
|
150
|
-
|
150
|
+
|
151
151
|
# Tells Thinking Sphinx that Sphinx is running on a different machine, and
|
152
|
-
# thus it can't reliably guess whether it is running or not (ie: the
|
152
|
+
# thus it can't reliably guess whether it is running or not (ie: the
|
153
153
|
# #sphinx_running? method), and so just assumes it is.
|
154
|
-
#
|
154
|
+
#
|
155
155
|
# Useful for multi-machine deployments. Set it in your production.rb file.
|
156
|
-
#
|
156
|
+
#
|
157
157
|
# ThinkingSphinx.remote_sphinx = true
|
158
|
-
#
|
158
|
+
#
|
159
159
|
def self.remote_sphinx=(value)
|
160
160
|
@@remote_sphinx = value
|
161
161
|
end
|
162
|
-
|
162
|
+
|
163
163
|
# Check if Sphinx is running. If remote_sphinx is set to true (indicating
|
164
164
|
# Sphinx is on a different machine), this will always return true, and you
|
165
165
|
# will have to handle any connection errors yourself.
|
166
|
-
#
|
166
|
+
#
|
167
167
|
def self.sphinx_running?
|
168
168
|
remote_sphinx? || sphinx_running_by_pid?
|
169
169
|
end
|
170
|
-
|
170
|
+
|
171
171
|
# Check if Sphinx is actually running, provided the pid is on the same
|
172
172
|
# machine as this code.
|
173
|
-
#
|
173
|
+
#
|
174
174
|
def self.sphinx_running_by_pid?
|
175
175
|
!!sphinx_pid && pid_active?(sphinx_pid)
|
176
176
|
end
|
177
|
-
|
177
|
+
|
178
178
|
def self.sphinx_pid
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
if microsoft?
|
184
|
-
pid_file.gsub!('/', '\\')
|
185
|
-
cat_command = 'type'
|
179
|
+
if File.exists?(ThinkingSphinx::Configuration.instance.pid_file)
|
180
|
+
File.read(ThinkingSphinx::Configuration.instance.pid_file)[/\d+/]
|
181
|
+
else
|
182
|
+
nil
|
186
183
|
end
|
187
|
-
|
188
|
-
`#{cat_command} \"#{pid_file}\"`[/\d+/]
|
189
184
|
end
|
190
|
-
|
185
|
+
|
191
186
|
def self.pid_active?(pid)
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
# In JRuby this returns -1 if the process doesn't exist
|
196
|
-
Process.getpgid(pid.to_i) != -1
|
197
|
-
rescue Exception => e
|
198
|
-
false
|
199
|
-
end
|
187
|
+
!!Process.kill(0, pid.to_i)
|
188
|
+
rescue Exception => e
|
189
|
+
false
|
200
190
|
end
|
201
|
-
|
191
|
+
|
202
192
|
def self.microsoft?
|
203
193
|
RUBY_PLATFORM =~ /mswin/
|
204
194
|
end
|
205
|
-
|
195
|
+
|
206
196
|
def self.jruby?
|
207
197
|
defined?(JRUBY_VERSION)
|
208
198
|
end
|
209
|
-
|
199
|
+
|
210
200
|
def self.mysql?
|
211
201
|
::ActiveRecord::Base.connection.class.name.demodulize == "MysqlAdapter" ||
|
212
202
|
::ActiveRecord::Base.connection.class.name.demodulize == "MysqlplusAdapter" || (
|
@@ -274,13 +274,18 @@ module ThinkingSphinx
|
|
274
274
|
# nothing
|
275
275
|
end
|
276
276
|
|
277
|
+
# Returns the unique integer id for the object. This method uses the
|
278
|
+
# attribute hash to get around ActiveRecord always mapping the #id method
|
279
|
+
# to whatever the real primary key is (which may be a unique string hash).
|
280
|
+
#
|
281
|
+
# @return [Integer] Unique record id for the purposes of Sphinx.
|
282
|
+
#
|
277
283
|
def primary_key_for_sphinx
|
278
|
-
self.
|
284
|
+
attributes[self.class.primary_key_for_sphinx.to_s]
|
279
285
|
end
|
280
|
-
|
286
|
+
|
281
287
|
def sphinx_document_id
|
282
|
-
|
283
|
-
self.attributes[key] * ThinkingSphinx.indexed_models.size +
|
288
|
+
primary_key_for_sphinx * ThinkingSphinx.indexed_models.size +
|
284
289
|
ThinkingSphinx.indexed_models.index(self.class.source_of_sphinx_index.name)
|
285
290
|
end
|
286
291
|
|
@@ -134,3 +134,17 @@ end
|
|
134
134
|
Class.extend(
|
135
135
|
ThinkingSphinx::ClassAttributeMethods
|
136
136
|
) unless Class.respond_to?(:cattr_reader)
|
137
|
+
|
138
|
+
module ThinkingSphinx
|
139
|
+
module MetaClass
|
140
|
+
def metaclass
|
141
|
+
class << self
|
142
|
+
self
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
unless Object.new.respond_to?(:metaclass)
|
149
|
+
Object.send(:include, ThinkingSphinx::MetaClass)
|
150
|
+
end
|
@@ -187,6 +187,11 @@ module ThinkingSphinx
|
|
187
187
|
).first
|
188
188
|
end
|
189
189
|
|
190
|
+
def search(*args)
|
191
|
+
merge_search ThinkingSphinx::Search.new(*args)
|
192
|
+
self
|
193
|
+
end
|
194
|
+
|
190
195
|
private
|
191
196
|
|
192
197
|
def config
|
@@ -444,6 +449,11 @@ module ThinkingSphinx
|
|
444
449
|
def condition_filters
|
445
450
|
(options[:conditions] || {}).collect { |attrib, value|
|
446
451
|
if attributes.include?(attrib)
|
452
|
+
puts <<-MSG
|
453
|
+
Deprecation Warning: filters on attributes should be done using the :with
|
454
|
+
option, not :conditions. For example:
|
455
|
+
:with => {:#{attrib} => #{value.inspect}}
|
456
|
+
MSG
|
447
457
|
Riddle::Client::Filter.new attrib.to_s, filter_value(value)
|
448
458
|
else
|
449
459
|
nil
|
@@ -619,7 +629,11 @@ module ThinkingSphinx
|
|
619
629
|
end
|
620
630
|
|
621
631
|
def add_scope(method, *args, &block)
|
622
|
-
|
632
|
+
merge_search options[:classes].first.send(method, *args, &block)
|
633
|
+
end
|
634
|
+
|
635
|
+
def merge_search(search)
|
636
|
+
search.args.each { |arg| args << arg }
|
623
637
|
|
624
638
|
search.options.keys.each do |key|
|
625
639
|
if HashOptions.include?(key)
|
@@ -628,6 +642,7 @@ module ThinkingSphinx
|
|
628
642
|
elsif ArrayOptions.include?(key)
|
629
643
|
options[key] ||= []
|
630
644
|
options[key] += search.options[key]
|
645
|
+
options[key].uniq!
|
631
646
|
else
|
632
647
|
options[key] = search.options[key]
|
633
648
|
end
|
@@ -57,10 +57,14 @@ describe ThinkingSphinx::ActiveRecord::Scopes do
|
|
57
57
|
Alpha.sphinx_scope(:with_betas) { {:classes => [Beta]} }
|
58
58
|
end
|
59
59
|
|
60
|
-
it "should return a ThinkingSphinx object" do
|
60
|
+
it "should return a ThinkingSphinx::Search object" do
|
61
61
|
Alpha.by_name('foo').should be_a(ThinkingSphinx::Search)
|
62
62
|
end
|
63
63
|
|
64
|
+
it "should set the classes option" do
|
65
|
+
Alpha.by_name('foo').options[:classes].should == [Alpha]
|
66
|
+
end
|
67
|
+
|
64
68
|
it "should be able to be called on a ThinkingSphinx::Search object" do
|
65
69
|
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
66
70
|
lambda {
|
@@ -326,4 +326,29 @@ describe "ThinkingSphinx::ActiveRecord" do
|
|
326
326
|
|
327
327
|
(beta.id * model_count + offset).should == beta.sphinx_document_id
|
328
328
|
end
|
329
|
+
|
330
|
+
describe '#primary_key_for_sphinx' do
|
331
|
+
before :each do
|
332
|
+
@person = Person.find(:first)
|
333
|
+
end
|
334
|
+
|
335
|
+
after :each do
|
336
|
+
Person.set_sphinx_primary_key nil
|
337
|
+
end
|
338
|
+
|
339
|
+
it "should return the id by default" do
|
340
|
+
@person.primary_key_for_sphinx.should == @person.id
|
341
|
+
end
|
342
|
+
|
343
|
+
it "should use the sphinx primary key to determine the value" do
|
344
|
+
Person.set_sphinx_primary_key :first_name
|
345
|
+
@person.primary_key_for_sphinx.should == @person.first_name
|
346
|
+
end
|
347
|
+
|
348
|
+
it "should not use accessor methods but the attributes hash" do
|
349
|
+
id = @person.id
|
350
|
+
@person.stub!(:id => 'unique_hash')
|
351
|
+
@person.primary_key_for_sphinx.should == id
|
352
|
+
end
|
353
|
+
end
|
329
354
|
end
|
@@ -4,32 +4,32 @@ describe ThinkingSphinx::Configuration do
|
|
4
4
|
describe "environment class method" do
|
5
5
|
before :each do
|
6
6
|
ThinkingSphinx::Configuration.send(:class_variable_set, :@@environment, nil)
|
7
|
-
|
7
|
+
|
8
8
|
ENV["RAILS_ENV"] = nil
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
it "should use the Merb environment value if set" do
|
12
12
|
unless defined?(Merb)
|
13
13
|
module ::Merb; end
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
ThinkingSphinx::Configuration.stub_method(:defined? => true)
|
17
17
|
Merb.stub!(:environment => "merb_production")
|
18
18
|
ThinkingSphinx::Configuration.environment.should == "merb_production"
|
19
|
-
|
19
|
+
|
20
20
|
Object.send(:remove_const, :Merb)
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
it "should use the Rails environment value if set" do
|
24
24
|
ENV["RAILS_ENV"] = "rails_production"
|
25
25
|
ThinkingSphinx::Configuration.environment.should == "rails_production"
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
it "should default to development" do
|
29
29
|
ThinkingSphinx::Configuration.environment.should == "development"
|
30
30
|
end
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
describe "parse_config method" do
|
34
34
|
before :each do
|
35
35
|
@settings = {
|
@@ -53,22 +53,22 @@ describe ThinkingSphinx::Configuration do
|
|
53
53
|
"indexer_binary_name" => "sphinx-indexer"
|
54
54
|
}
|
55
55
|
}
|
56
|
-
|
56
|
+
|
57
57
|
open("#{RAILS_ROOT}/config/sphinx.yml", "w") do |f|
|
58
58
|
f.write YAML.dump(@settings)
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
it "should use the accessors to set the configuration values" do
|
63
63
|
config = ThinkingSphinx::Configuration.instance
|
64
64
|
config.send(:parse_config)
|
65
|
-
|
65
|
+
|
66
66
|
%w(config_file searchd_log_file query_log_file pid_file searchd_file_path
|
67
67
|
address port searchd_binary_name indexer_binary_name).each do |key|
|
68
68
|
config.send(key).should == @settings["development"][key]
|
69
69
|
end
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
after :each do
|
73
73
|
FileUtils.rm "#{RAILS_ROOT}/config/sphinx.yml"
|
74
74
|
end
|
@@ -82,137 +82,143 @@ describe ThinkingSphinx::Configuration do
|
|
82
82
|
ThinkingSphinx::Configuration.instance.app_root.should == "/here/somewhere"
|
83
83
|
end
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
describe "initialisation" do
|
87
87
|
it "should have a default bin_path of nothing" do
|
88
88
|
ThinkingSphinx::Configuration.instance.bin_path.should == ""
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
it "should append a / to bin_path if one is supplied" do
|
92
92
|
@settings = {
|
93
93
|
"development" => {
|
94
94
|
"bin_path" => "path/to/somewhere"
|
95
95
|
}
|
96
96
|
}
|
97
|
-
|
97
|
+
|
98
98
|
open("#{RAILS_ROOT}/config/sphinx.yml", "w") do |f|
|
99
99
|
f.write YAML.dump(@settings)
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
ThinkingSphinx::Configuration.instance.send(:parse_config)
|
103
103
|
ThinkingSphinx::Configuration.instance.bin_path.should match(/\/$/)
|
104
|
+
|
105
|
+
FileUtils.rm "#{RAILS_ROOT}/config/sphinx.yml"
|
104
106
|
end
|
105
107
|
end
|
106
|
-
|
108
|
+
|
107
109
|
describe "index options" do
|
108
110
|
before :each do
|
109
111
|
@settings = {
|
110
112
|
"development" => {"disable_range" => true}
|
111
113
|
}
|
112
|
-
|
114
|
+
|
113
115
|
open("#{RAILS_ROOT}/config/sphinx.yml", "w") do |f|
|
114
116
|
f.write YAML.dump(@settings)
|
115
117
|
end
|
116
|
-
|
118
|
+
|
117
119
|
@config = ThinkingSphinx::Configuration.instance
|
118
120
|
@config.send(:parse_config)
|
119
121
|
end
|
120
|
-
|
122
|
+
|
121
123
|
it "should collect disable_range" do
|
122
124
|
@config.index_options[:disable_range].should be_true
|
123
125
|
end
|
126
|
+
|
127
|
+
after :each do
|
128
|
+
FileUtils.rm "#{RAILS_ROOT}/config/sphinx.yml"
|
129
|
+
end
|
124
130
|
end
|
125
|
-
|
131
|
+
|
126
132
|
describe "#load_models" do
|
127
133
|
before :each do
|
128
134
|
@config = ThinkingSphinx::Configuration.instance
|
129
135
|
@config.model_directories = ['']
|
130
|
-
|
136
|
+
|
131
137
|
@file_name = 'a.rb'
|
132
138
|
@model_name_lower = 'a'
|
133
139
|
@class_name = 'A'
|
134
|
-
|
140
|
+
|
135
141
|
@file_name.stub!(:gsub).and_return(@model_name_lower)
|
136
142
|
@model_name_lower.stub!(:camelize).and_return(@class_name)
|
137
143
|
Dir.stub(:[]).and_return([@file_name])
|
138
144
|
end
|
139
|
-
|
145
|
+
|
140
146
|
it "should load the files by guessing the file name" do
|
141
147
|
@class_name.should_receive(:constantize).and_return(true)
|
142
|
-
|
148
|
+
|
143
149
|
@config.load_models
|
144
150
|
end
|
145
|
-
|
151
|
+
|
146
152
|
it "should not raise errors if the model name is nil" do
|
147
153
|
@file_name.stub!(:gsub).and_return(nil)
|
148
|
-
|
154
|
+
|
149
155
|
lambda {
|
150
156
|
@config.load_models
|
151
157
|
}.should_not raise_error
|
152
158
|
end
|
153
|
-
|
159
|
+
|
154
160
|
it "should not raise errors if the file name does not represent a class name" do
|
155
161
|
@class_name.should_receive(:constantize).and_raise(NameError)
|
156
|
-
|
162
|
+
|
157
163
|
lambda {
|
158
164
|
@config.load_models
|
159
165
|
}.should_not raise_error
|
160
166
|
end
|
161
|
-
|
167
|
+
|
162
168
|
it "should retry if the first pass fails and contains a directory" do
|
163
169
|
@model_name_lower.stub!(:gsub!).and_return(true, nil)
|
164
170
|
@class_name.stub(:constantize).and_raise(LoadError)
|
165
171
|
@model_name_lower.should_receive(:camelize).twice
|
166
|
-
|
172
|
+
|
167
173
|
lambda {
|
168
174
|
@config.load_models
|
169
175
|
}.should_not raise_error
|
170
176
|
end
|
171
|
-
|
177
|
+
|
172
178
|
it "should catch database errors with a warning" do
|
173
179
|
@class_name.should_receive(:constantize).and_raise(Mysql::Error)
|
174
180
|
@config.should_receive(:puts).with('Warning: Error loading a.rb')
|
175
|
-
|
181
|
+
|
176
182
|
lambda {
|
177
183
|
@config.load_models
|
178
184
|
}.should_not raise_error
|
179
185
|
end
|
180
186
|
end
|
181
|
-
|
187
|
+
|
182
188
|
it "should insert set index options into the configuration file" do
|
183
189
|
config = ThinkingSphinx::Configuration.instance
|
184
190
|
ThinkingSphinx::Configuration::IndexOptions.each do |option|
|
185
191
|
config.index_options[option.to_sym] = "something"
|
186
192
|
config.build
|
187
|
-
|
193
|
+
|
188
194
|
file = open(config.config_file) { |f| f.read }
|
189
195
|
file.should match(/#{option}\s+= something/)
|
190
|
-
|
196
|
+
|
191
197
|
config.index_options[option.to_sym] = nil
|
192
198
|
end
|
193
199
|
end
|
194
|
-
|
200
|
+
|
195
201
|
it "should insert set source options into the configuration file" do
|
196
202
|
config = ThinkingSphinx::Configuration.instance
|
197
203
|
ThinkingSphinx::Configuration::SourceOptions.each do |option|
|
198
204
|
config.source_options[option.to_sym] = "something"
|
199
205
|
config.build
|
200
|
-
|
206
|
+
|
201
207
|
file = open(config.config_file) { |f| f.read }
|
202
208
|
file.should match(/#{option}\s+= something/)
|
203
|
-
|
209
|
+
|
204
210
|
config.source_options[option.to_sym] = nil
|
205
211
|
end
|
206
212
|
end
|
207
|
-
|
213
|
+
|
208
214
|
it "should set any explicit prefixed or infixed fields" do
|
209
215
|
file = open(ThinkingSphinx::Configuration.instance.config_file) { |f|
|
210
216
|
f.read
|
211
217
|
}
|
212
218
|
file.should match(/prefix_fields\s+= city/)
|
213
|
-
file.should match(/infix_fields\s+= state/)
|
219
|
+
file.should match(/infix_fields\s+= state/)
|
214
220
|
end
|
215
|
-
|
221
|
+
|
216
222
|
it "should not have prefix fields in indexes where nothing is set" do
|
217
223
|
file = open(ThinkingSphinx::Configuration.instance.config_file) { |f|
|
218
224
|
f.read
|
@@ -118,6 +118,18 @@ describe ThinkingSphinx::ActiveRecordStoreFullSTIClass do
|
|
118
118
|
end
|
119
119
|
end
|
120
120
|
|
121
|
+
describe ThinkingSphinx::MetaClass do
|
122
|
+
describe 'metaclass' do
|
123
|
+
it "should exist as an instance method in Object" do
|
124
|
+
Object.new.should respond_to('metaclass')
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should return the meta/eigen/singleton class" do
|
128
|
+
Object.new.metaclass.should be_a(Class)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
121
133
|
class TestModel
|
122
134
|
@@squares = 89
|
123
135
|
@@circles = 43
|
@@ -50,6 +50,24 @@ describe ThinkingSphinx::Search do
|
|
50
50
|
ThinkingSphinx::Search.new.foo
|
51
51
|
}.should raise_error(NoMethodError)
|
52
52
|
end
|
53
|
+
|
54
|
+
it "should accept sphinx scopes" do
|
55
|
+
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
56
|
+
|
57
|
+
lambda {
|
58
|
+
search.by_name('Pat')
|
59
|
+
}.should_not raise_error(NoMethodError)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should return itself when using a sphinx scope" do
|
63
|
+
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
64
|
+
search.by_name('Pat').object_id.should == search.object_id
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should keep the same search object when chaining multiple scopes" do
|
68
|
+
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
69
|
+
search.by_name('Pat').ids_only.object_id.should == search.object_id
|
70
|
+
end
|
53
71
|
end
|
54
72
|
|
55
73
|
describe '.search' do
|
@@ -104,13 +122,16 @@ describe ThinkingSphinx::Search do
|
|
104
122
|
@alpha_a, @alpha_b = Alpha.new, Alpha.new
|
105
123
|
@beta_a, @beta_b = Beta.new, Beta.new
|
106
124
|
|
107
|
-
@alpha_a.stub!
|
108
|
-
@
|
125
|
+
@alpha_a.stub! :id => 1, :attributes => {'id' => 1}
|
126
|
+
@alpha_b.stub! :id => 2, :attributes => {'id' => 2}
|
127
|
+
@beta_a.stub! :id => 1, :attributes => {'id' => 1}
|
128
|
+
@beta_b.stub! :id => 2, :attributes => {'id' => 2}
|
129
|
+
|
109
130
|
@client.stub! :query => {
|
110
131
|
:matches => minimal_result_hashes(@alpha_a, @beta_b, @alpha_b, @beta_a)
|
111
132
|
}
|
112
|
-
Alpha.stub!
|
113
|
-
Beta.stub!
|
133
|
+
Alpha.stub! :find => [@alpha_a, @alpha_b]
|
134
|
+
Beta.stub! :find => [@beta_a, @beta_b]
|
114
135
|
end
|
115
136
|
|
116
137
|
it "should issue only one select per model" do
|
@@ -740,7 +761,7 @@ describe ThinkingSphinx::Search do
|
|
740
761
|
describe '.each_with_groupby_and_count' do
|
741
762
|
before :each do
|
742
763
|
@alpha = Alpha.new
|
743
|
-
@alpha.stub!(:id => 1)
|
764
|
+
@alpha.stub!(:id => 1, :attributes => {'id' => 1})
|
744
765
|
|
745
766
|
@client.stub! :query => {
|
746
767
|
:matches => [{
|
@@ -768,7 +789,7 @@ describe ThinkingSphinx::Search do
|
|
768
789
|
describe '.each_with_weighting' do
|
769
790
|
before :each do
|
770
791
|
@alpha = Alpha.new
|
771
|
-
@alpha.stub!(:id => 1)
|
792
|
+
@alpha.stub!(:id => 1, :attributes => {'id' => 1})
|
772
793
|
|
773
794
|
@client.stub! :query => {
|
774
795
|
:matches => [{
|
@@ -793,7 +814,7 @@ describe ThinkingSphinx::Search do
|
|
793
814
|
describe '.each_with_*' do
|
794
815
|
before :each do
|
795
816
|
@alpha = Alpha.new
|
796
|
-
@alpha.stub!(:id => 1)
|
817
|
+
@alpha.stub!(:id => 1, :attributes => {'id' => 1})
|
797
818
|
|
798
819
|
@client.stub! :query => {
|
799
820
|
:matches => [{
|
@@ -878,6 +899,47 @@ describe ThinkingSphinx::Search do
|
|
878
899
|
@search.excerpt_for('string', Beta)
|
879
900
|
end
|
880
901
|
end
|
902
|
+
|
903
|
+
describe '#search' do
|
904
|
+
before :each do
|
905
|
+
@search = ThinkingSphinx::Search.new('word',
|
906
|
+
:conditions => {:field => 'field'},
|
907
|
+
:with => {:int => 5}
|
908
|
+
)
|
909
|
+
end
|
910
|
+
|
911
|
+
it "should return itself" do
|
912
|
+
@search.search.object_id.should == @search.object_id
|
913
|
+
end
|
914
|
+
|
915
|
+
it "should merge in arguments" do
|
916
|
+
@client.should_receive(:query) do |query, index, comments|
|
917
|
+
query.should == 'word more @field field'
|
918
|
+
end
|
919
|
+
|
920
|
+
@search.search('more').first
|
921
|
+
end
|
922
|
+
|
923
|
+
it "should merge conditions" do
|
924
|
+
@client.should_receive(:query) do |query, index, comments|
|
925
|
+
query.should match(/@name plato/)
|
926
|
+
query.should match(/@field field/)
|
927
|
+
end
|
928
|
+
|
929
|
+
@search.search(:conditions => {:name => 'plato'}).first
|
930
|
+
end
|
931
|
+
|
932
|
+
it "should merge filters" do
|
933
|
+
@search.search(:with => {:float => 1.5}).first
|
934
|
+
|
935
|
+
@client.filters.detect { |filter|
|
936
|
+
filter.attribute == 'float'
|
937
|
+
}.should_not be_nil
|
938
|
+
@client.filters.detect { |filter|
|
939
|
+
filter.attribute == 'int'
|
940
|
+
}.should_not be_nil
|
941
|
+
end
|
942
|
+
end
|
881
943
|
end
|
882
944
|
|
883
945
|
describe ThinkingSphinx::Search, "playing nice with Search model" do
|
@@ -4,7 +4,7 @@ module Riddle
|
|
4
4
|
@configuration = configuration
|
5
5
|
@path = path
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def index
|
9
9
|
cmd = "indexer --config #{@path} --all"
|
10
10
|
cmd << " --rotate" if running?
|
@@ -15,7 +15,8 @@ module Riddle
|
|
15
15
|
return if running?
|
16
16
|
|
17
17
|
cmd = "searchd --pidfile --config #{@path}"
|
18
|
-
|
18
|
+
cmd = "start /B #{cmd}" if RUBY_PLATFORM =~ /mswin/
|
19
|
+
`#{cmd}`
|
19
20
|
|
20
21
|
sleep(1)
|
21
22
|
|
@@ -26,19 +27,24 @@ module Riddle
|
|
26
27
|
|
27
28
|
def stop
|
28
29
|
return unless running?
|
29
|
-
|
30
|
+
Process.kill('SIGTERM', pid.to_i)
|
31
|
+
rescue Errno::EINVAL
|
32
|
+
Process.kill('SIGKILL', pid.to_i)
|
30
33
|
end
|
31
34
|
|
32
35
|
def pid
|
33
|
-
if File.exists?(
|
34
|
-
|
36
|
+
if File.exists?(@configuration.searchd.pid_file)
|
37
|
+
File.read(@configuration.searchd.pid_file)[/\d+/]
|
35
38
|
else
|
36
39
|
nil
|
37
40
|
end
|
38
41
|
end
|
39
42
|
|
40
43
|
def running?
|
41
|
-
pid &&
|
44
|
+
!!pid && !!Process.kill(0, pid.to_i)
|
45
|
+
rescue
|
46
|
+
false
|
42
47
|
end
|
48
|
+
|
43
49
|
end
|
44
50
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: freelancing-god-thinking-sphinx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pat Allan
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-08-02 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|