thinking-sphinx 1.3.3 → 1.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +3 -0
- data/VERSION.yml +1 -1
- data/lib/thinking_sphinx.rb +0 -4
- data/lib/thinking_sphinx/active_record/scopes.rb +37 -1
- data/lib/thinking_sphinx/configuration.rb +10 -6
- data/lib/thinking_sphinx/deploy/capistrano.rb +1 -1
- data/lib/thinking_sphinx/search.rb +20 -7
- data/lib/thinking_sphinx/source.rb +2 -1
- data/rails/init.rb +4 -0
- data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +46 -2
- data/spec/lib/thinking_sphinx/configuration_spec.rb +25 -3
- data/spec/lib/thinking_sphinx/index/builder_spec.rb +14 -0
- data/tasks/distribution.rb +1 -1
- metadata +3 -3
data/README.textile
CHANGED
data/VERSION.yml
CHANGED
data/lib/thinking_sphinx.rb
CHANGED
@@ -8,6 +8,40 @@ module ThinkingSphinx
|
|
8
8
|
end
|
9
9
|
|
10
10
|
module ClassMethods
|
11
|
+
|
12
|
+
# Similar to ActiveRecord's default_scope method Thinking Sphinx supports
|
13
|
+
# a default_sphinx_scope. For example:
|
14
|
+
#
|
15
|
+
# default_sphinx_scope :some_sphinx_named_scope
|
16
|
+
#
|
17
|
+
# The scope is automatically applied when the search method is called. It
|
18
|
+
# will only be applied if it is an existing sphinx_scope.
|
19
|
+
def default_sphinx_scope(sphinx_scope_name)
|
20
|
+
@default_sphinx_scope = sphinx_scope_name
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the default_sphinx_scope or nil if none is set.
|
24
|
+
def get_default_sphinx_scope
|
25
|
+
@default_sphinx_scope
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns true if the current Model has a default_sphinx_scope. Also checks if
|
29
|
+
# the default_sphinx_scope actually is a scope.
|
30
|
+
def has_default_sphinx_scope?
|
31
|
+
!@default_sphinx_scope.nil? && sphinx_scopes.include?(@default_sphinx_scope)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Similar to ActiveRecord's named_scope method Thinking Sphinx supports
|
35
|
+
# scopes. For example:
|
36
|
+
#
|
37
|
+
# sphinx_scope(:latest_first) {
|
38
|
+
# {:order => 'created_at DESC, @relevance DESC'}
|
39
|
+
# }
|
40
|
+
#
|
41
|
+
# Usage:
|
42
|
+
#
|
43
|
+
# @articles = Article.latest_first.search 'pancakes'
|
44
|
+
#
|
11
45
|
def sphinx_scope(method, &block)
|
12
46
|
@sphinx_scopes ||= []
|
13
47
|
@sphinx_scopes << method
|
@@ -21,7 +55,9 @@ module ThinkingSphinx
|
|
21
55
|
end
|
22
56
|
end
|
23
57
|
end
|
24
|
-
|
58
|
+
|
59
|
+
# This returns an Array of all defined scopes. The default
|
60
|
+
# scope shows as :default.
|
25
61
|
def sphinx_scopes
|
26
62
|
@sphinx_scopes || []
|
27
63
|
end
|
@@ -49,14 +49,18 @@ module ThinkingSphinx
|
|
49
49
|
class Configuration
|
50
50
|
include Singleton
|
51
51
|
|
52
|
-
SourceOptions = %w( mysql_connect_flags
|
53
|
-
|
52
|
+
SourceOptions = %w( mysql_connect_flags mysql_ssl_cert mysql_ssl_key
|
53
|
+
mysql_ssl_ca sql_range_step sql_query_pre sql_query_post
|
54
|
+
sql_query_killlist sql_ranged_throttle sql_query_post_index unpack_zlib
|
55
|
+
unpack_mysqlcompress unpack_mysqlcompress_maxsize )
|
54
56
|
|
55
57
|
IndexOptions = %w( charset_table charset_type docinfo enable_star
|
56
|
-
exceptions html_index_attrs html_remove_elements html_strip
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
exceptions html_index_attrs html_remove_elements html_strip
|
59
|
+
index_exact_words ignore_chars inplace_docinfo_gap inplace_enable
|
60
|
+
inplace_hit_gap inplace_reloc_factor inplace_write_factor min_infix_len
|
61
|
+
min_prefix_len min_stemming_len min_word_len mlock morphology ngram_chars
|
62
|
+
ngram_len ondisk_dict overshort_step phrase_boundary phrase_boundary_step
|
63
|
+
preopen stopwords stopwords_step wordforms )
|
60
64
|
|
61
65
|
CustomOptions = %w( disable_range )
|
62
66
|
|
@@ -93,7 +93,7 @@ DESC
|
|
93
93
|
rails_env = fetch(:rails_env, "production")
|
94
94
|
rake = fetch(:rake, "rake")
|
95
95
|
tasks.each do |t|
|
96
|
-
run "cd #{current_path}; #{rake} RAILS_ENV=#{rails_env} #{t}"
|
96
|
+
run "if [ -d #{release_path} ]; then cd #{release_path}; else cd #{current_path}; fi; #{rake} RAILS_ENV=#{rails_env} #{t}"
|
97
97
|
end
|
98
98
|
end
|
99
99
|
end
|
@@ -14,7 +14,7 @@ module ThinkingSphinx
|
|
14
14
|
kind_of? member? method methods nil? object_id respond_to? send should
|
15
15
|
type )
|
16
16
|
SafeMethods = %w( partition private_methods protected_methods
|
17
|
-
public_methods send )
|
17
|
+
public_methods send class )
|
18
18
|
|
19
19
|
instance_methods.select { |method|
|
20
20
|
method.to_s[/^__/].nil? && !CoreMethods.include?(method.to_s)
|
@@ -215,6 +215,7 @@ module ThinkingSphinx
|
|
215
215
|
end
|
216
216
|
|
217
217
|
def search(*args)
|
218
|
+
add_default_scope
|
218
219
|
merge_search ThinkingSphinx::Search.new(*args)
|
219
220
|
self
|
220
221
|
end
|
@@ -231,8 +232,12 @@ module ThinkingSphinx
|
|
231
232
|
|
232
233
|
retry_on_stale_index do
|
233
234
|
begin
|
234
|
-
log "Querying
|
235
|
-
|
235
|
+
log "Querying: '#{query}'"
|
236
|
+
runtime = Benchmark.realtime {
|
237
|
+
@results = client.query query, indexes, comment
|
238
|
+
}
|
239
|
+
log "Found #{@results[:total_found]} results", :debug,
|
240
|
+
"Sphinx (#{sprintf("%f", runtime)}s)"
|
236
241
|
rescue Errno::ECONNREFUSED => err
|
237
242
|
raise ThinkingSphinx::ConnectionError,
|
238
243
|
'Connection to Sphinx Daemon (searchd) failed.'
|
@@ -280,13 +285,16 @@ module ThinkingSphinx
|
|
280
285
|
end
|
281
286
|
end
|
282
287
|
|
283
|
-
def self.log(message, method = :debug)
|
288
|
+
def self.log(message, method = :debug, identifier = 'Sphinx')
|
284
289
|
return if ::ActiveRecord::Base.logger.nil?
|
285
|
-
|
290
|
+
identifier_color, message_color = "4;32;1", "0" # 0;1 = Bold
|
291
|
+
info = " \e[#{identifier_color}m#{identifier}\e[0m "
|
292
|
+
info << "\e[#{message_color}m#{message}\e[0m"
|
293
|
+
::ActiveRecord::Base.logger.send method, info
|
286
294
|
end
|
287
295
|
|
288
|
-
def log(
|
289
|
-
self.class.log(
|
296
|
+
def log(*args)
|
297
|
+
self.class.log(*args)
|
290
298
|
end
|
291
299
|
|
292
300
|
def client
|
@@ -684,6 +692,11 @@ MSG
|
|
684
692
|
one_class && one_class.sphinx_scopes.include?(method)
|
685
693
|
end
|
686
694
|
|
695
|
+
# Adds the default_sphinx_scope if set.
|
696
|
+
def add_default_scope
|
697
|
+
add_scope(one_class.get_default_sphinx_scope) if one_class && one_class.has_default_sphinx_scope?
|
698
|
+
end
|
699
|
+
|
687
700
|
def add_scope(method, *args, &block)
|
688
701
|
merge_search one_class.send(method, *args, &block)
|
689
702
|
end
|
@@ -43,8 +43,8 @@ module ThinkingSphinx
|
|
43
43
|
|
44
44
|
set_source_database_settings source
|
45
45
|
set_source_attributes source, offset
|
46
|
-
set_source_sql source, offset
|
47
46
|
set_source_settings source
|
47
|
+
set_source_sql source, offset
|
48
48
|
|
49
49
|
source
|
50
50
|
end
|
@@ -57,6 +57,7 @@ module ThinkingSphinx
|
|
57
57
|
|
58
58
|
set_source_database_settings source
|
59
59
|
set_source_attributes source, offset, true
|
60
|
+
set_source_settings source
|
60
61
|
set_source_sql source, offset, true
|
61
62
|
|
62
63
|
source
|
data/rails/init.rb
CHANGED
@@ -34,7 +34,22 @@ describe ThinkingSphinx::ActiveRecord::Scopes do
|
|
34
34
|
Alpha.sphinx_scopes.should == [:by_name]
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
|
+
describe '.default_sphinx_scope' do
|
39
|
+
before :each do
|
40
|
+
Alpha.sphinx_scope(:scope_used_as_default_scope) { {:conditions => {:name => 'name'}} }
|
41
|
+
Alpha.default_sphinx_scope :scope_used_as_default_scope
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return an array of defined scope names as symbols" do
|
45
|
+
Alpha.sphinx_scopes.should == [:scope_used_as_default_scope]
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should have a default_sphinx_scope" do
|
49
|
+
Alpha.has_default_sphinx_scope?.should be_true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
38
53
|
describe '.remove_sphinx_scopes' do
|
39
54
|
before :each do
|
40
55
|
Alpha.sphinx_scope(:by_name) { |name| {:conditions => {:name => name}} }
|
@@ -49,7 +64,36 @@ describe ThinkingSphinx::ActiveRecord::Scopes do
|
|
49
64
|
Alpha.sphinx_scopes.should be_empty
|
50
65
|
end
|
51
66
|
end
|
52
|
-
|
67
|
+
|
68
|
+
describe '.example_default_scope' do
|
69
|
+
before :each do
|
70
|
+
Alpha.sphinx_scope(:foo_scope){ {:conditions => {:name => 'foo'}} }
|
71
|
+
Alpha.default_sphinx_scope :foo_scope
|
72
|
+
Alpha.sphinx_scope(:by_name) { |name| {:conditions => {:name => name}} }
|
73
|
+
Alpha.sphinx_scope(:by_foo) { |foo| {:conditions => {:foo => foo}} }
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should return a ThinkingSphinx::Search object" do
|
77
|
+
Alpha.search.should be_a(ThinkingSphinx::Search)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should apply the default scope options to the underlying search object" do
|
81
|
+
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
82
|
+
search.search.options[:conditions].should == {:name => 'foo'}
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should apply the default scope options and scope options to the underlying search object" do
|
86
|
+
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
87
|
+
search.by_foo('foo').search.options[:conditions].should == {:foo => 'foo', :name => 'foo'}
|
88
|
+
end
|
89
|
+
|
90
|
+
# FIXME: Probably the other way around is more logical? How to do this?
|
91
|
+
it "should apply the default scope options after other scope options to the underlying search object" do
|
92
|
+
search = ThinkingSphinx::Search.new(:classes => [Alpha])
|
93
|
+
search.by_name('bar').search.options[:conditions].should == {:name => 'foo'}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
53
97
|
describe '.example_scope' do
|
54
98
|
before :each do
|
55
99
|
Alpha.sphinx_scope(:by_name) { |name| {:conditions => {:name => name}} }
|
@@ -50,7 +50,8 @@ describe ThinkingSphinx::Configuration do
|
|
50
50
|
"charset_table" => "table",
|
51
51
|
"ignore_chars" => "e",
|
52
52
|
"searchd_binary_name" => "sphinx-searchd",
|
53
|
-
"indexer_binary_name" => "sphinx-indexer"
|
53
|
+
"indexer_binary_name" => "sphinx-indexer",
|
54
|
+
"index_exact_words" => true
|
54
55
|
}
|
55
56
|
}
|
56
57
|
|
@@ -187,7 +188,9 @@ describe ThinkingSphinx::Configuration do
|
|
187
188
|
|
188
189
|
it "should insert set index options into the configuration file" do
|
189
190
|
config = ThinkingSphinx::Configuration.instance
|
191
|
+
|
190
192
|
ThinkingSphinx::Configuration::IndexOptions.each do |option|
|
193
|
+
config.reset
|
191
194
|
config.index_options[option.to_sym] = "something"
|
192
195
|
config.build
|
193
196
|
|
@@ -200,15 +203,34 @@ describe ThinkingSphinx::Configuration do
|
|
200
203
|
|
201
204
|
it "should insert set source options into the configuration file" do
|
202
205
|
config = ThinkingSphinx::Configuration.instance
|
206
|
+
config.reset
|
207
|
+
|
208
|
+
config.source_options[:sql_query_pre] = ["something"]
|
203
209
|
ThinkingSphinx::Configuration::SourceOptions.each do |option|
|
204
|
-
config.source_options[option.to_sym]
|
210
|
+
config.source_options[option.to_sym] ||= "something"
|
205
211
|
config.build
|
206
212
|
|
207
213
|
file = open(config.config_file) { |f| f.read }
|
208
214
|
file.should match(/#{option}\s+= something/)
|
209
215
|
|
210
|
-
config.source_options
|
216
|
+
config.source_options.delete option.to_sym
|
211
217
|
end
|
218
|
+
|
219
|
+
config.source_options[:sql_query_pre] = nil
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should not blow away delta or utf options if sql pre is specified in config" do
|
223
|
+
config = ThinkingSphinx::Configuration.instance
|
224
|
+
config.reset
|
225
|
+
|
226
|
+
config.source_options[:sql_query_pre] = ["a pre query"]
|
227
|
+
config.build
|
228
|
+
file = open(config.config_file) { |f| f.read }
|
229
|
+
|
230
|
+
file.should match(/sql_query_pre = a pre query\n\s*sql_query_pre = UPDATE `\w+` SET `delta` = 0 WHERE `delta` = 1/im)
|
231
|
+
file.should match(/sql_query_pre = a pre query\n\s*sql_query_pre = \n/im)
|
232
|
+
|
233
|
+
config.source_options[:sql_query_pre] = nil
|
212
234
|
end
|
213
235
|
|
214
236
|
it "should set any explicit prefixed or infixed fields" do
|
@@ -452,4 +452,18 @@ describe ThinkingSphinx::Index::Builder do
|
|
452
452
|
@index.delta_object.should be_a_kind_of(ThinkingSphinx::Deltas::DefaultDelta)
|
453
453
|
end
|
454
454
|
end
|
455
|
+
|
456
|
+
context 'index options' do
|
457
|
+
before :each do
|
458
|
+
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
459
|
+
indexes first_name
|
460
|
+
|
461
|
+
set_property :index_exact_words => true
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
it "should track the index_exact_words option to the index" do
|
466
|
+
@index.local_options[:index_exact_words].should be_true
|
467
|
+
end
|
468
|
+
end
|
455
469
|
end
|
data/tasks/distribution.rb
CHANGED
@@ -28,7 +28,7 @@ Jeweler::Tasks.new do |gem|
|
|
28
28
|
]
|
29
29
|
|
30
30
|
gem.add_dependency 'activerecord', '>= 1.15.6'
|
31
|
-
gem.add_dependency 'riddle', '>= 1.0.
|
31
|
+
gem.add_dependency 'riddle', '>= 1.0.1'
|
32
32
|
gem.add_dependency 'after_commit', '>= 1.0.2'
|
33
33
|
|
34
34
|
gem.post_install_message = <<-MESSAGE
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thinking-sphinx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.4
|
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-11-
|
12
|
+
date: 2009-11-16 00:00:00 +11:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.0.
|
33
|
+
version: 1.0.1
|
34
34
|
version:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: after_commit
|