thinking-sphinx 1.4.4 → 1.4.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +5 -0
- data/VERSION +1 -1
- data/features/thinking_sphinx/models/developer.rb +0 -11
- data/lib/thinking_sphinx.rb +93 -40
- data/lib/thinking_sphinx/active_record.rb +11 -31
- data/lib/thinking_sphinx/active_record/delta.rb +27 -0
- data/lib/thinking_sphinx/auto_version.rb +18 -7
- data/lib/thinking_sphinx/configuration.rb +26 -10
- data/lib/thinking_sphinx/deploy/capistrano.rb +19 -19
- data/lib/thinking_sphinx/excerpter.rb +2 -1
- data/lib/thinking_sphinx/facet.rb +9 -10
- data/lib/thinking_sphinx/index/builder.rb +10 -0
- data/lib/thinking_sphinx/rails_additions.rb +31 -0
- data/lib/thinking_sphinx/search.rb +3 -3
- data/lib/thinking_sphinx/tasks.rb +4 -3
- data/spec/thinking_sphinx/active_record/delta_spec.rb +7 -7
- data/spec/thinking_sphinx/active_record_spec.rb +4 -0
- data/spec/thinking_sphinx/attribute_spec.rb +6 -3
- data/spec/thinking_sphinx/auto_version_spec.rb +12 -4
- data/spec/thinking_sphinx/configuration_spec.rb +1 -1
- data/spec/thinking_sphinx/context_spec.rb +1 -0
- data/spec/thinking_sphinx/facet_search_spec.rb +0 -8
- data/spec/thinking_sphinx/facet_spec.rb +12 -0
- data/spec/thinking_sphinx/field_spec.rb +6 -3
- data/spec/thinking_sphinx/index/builder_spec.rb +13 -0
- data/spec/thinking_sphinx/search_spec.rb +2 -1
- data/spec/thinking_sphinx_spec.rb +2 -3
- metadata +65 -159
- data/lib/thinking_sphinx/core/array.rb +0 -7
@@ -3,13 +3,13 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
3
3
|
namespace :install do
|
4
4
|
desc <<-DESC
|
5
5
|
Install Sphinx by source
|
6
|
-
|
6
|
+
|
7
7
|
If Postgres is available, Sphinx will use it.
|
8
|
-
|
8
|
+
|
9
9
|
If the variable :thinking_sphinx_configure_args is set, it will
|
10
10
|
be passed to the Sphinx configure script. You can use this to
|
11
11
|
install Sphinx in a non-standard location:
|
12
|
-
|
12
|
+
|
13
13
|
set :thinking_sphinx_configure_args, "--prefix=$HOME/software"
|
14
14
|
DESC
|
15
15
|
|
@@ -22,7 +22,7 @@ DESC
|
|
22
22
|
rescue Capistrano::CommandError => e
|
23
23
|
puts "Continuing despite error: #{e.message}"
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
args = []
|
27
27
|
if with_postgres
|
28
28
|
run "pg_config --pkgincludedir" do |channel, stream, data|
|
@@ -30,60 +30,60 @@ DESC
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
args << fetch(:thinking_sphinx_configure_args, '')
|
33
|
-
|
33
|
+
|
34
34
|
commands = <<-CMD
|
35
|
-
wget -q http://
|
36
|
-
tar xzvf sphinx-0.9.
|
37
|
-
cd sphinx-0.9.
|
35
|
+
wget -q http://sphinxsearch.com/downloads/sphinx-0.9.9.tar.gz >> sphinx.log
|
36
|
+
tar xzvf sphinx-0.9.9.tar.gz
|
37
|
+
cd sphinx-0.9.9
|
38
38
|
./configure #{args.join(" ")}
|
39
39
|
make
|
40
40
|
#{try_sudo} make install
|
41
|
-
rm -rf sphinx-0.9.
|
41
|
+
rm -rf sphinx-0.9.9 sphinx-0.9.9.tar.gz
|
42
42
|
CMD
|
43
43
|
run commands.split(/\n\s+/).join(" && ")
|
44
44
|
end
|
45
|
-
|
46
|
-
desc "Install Thinking Sphinx as a gem
|
45
|
+
|
46
|
+
desc "Install Thinking Sphinx as a gem"
|
47
47
|
task :ts do
|
48
|
-
run "#{try_sudo} gem install thinking-sphinx
|
48
|
+
run "#{try_sudo} gem install thinking-sphinx"
|
49
49
|
end
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
desc "Generate the Sphinx configuration file"
|
53
53
|
task :configure do
|
54
54
|
rake "thinking_sphinx:configure"
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
desc "Index data"
|
58
58
|
task :index do
|
59
59
|
rake "thinking_sphinx:index"
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
desc "Start the Sphinx daemon"
|
63
63
|
task :start do
|
64
64
|
configure
|
65
65
|
rake "thinking_sphinx:start"
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
desc "Stop the Sphinx daemon"
|
69
69
|
task :stop do
|
70
70
|
configure
|
71
71
|
rake "thinking_sphinx:stop"
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
desc "Stop and then start the Sphinx daemon"
|
75
75
|
task :restart do
|
76
76
|
stop
|
77
77
|
start
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
desc "Stop, re-index and then start the Sphinx daemon"
|
81
81
|
task :rebuild do
|
82
82
|
stop
|
83
83
|
index
|
84
84
|
start
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
desc "Add the shared folder for sphinx files"
|
88
88
|
task :shared_sphinx_folder, :roles => :web do
|
89
89
|
rails_env = fetch(:rails_env, "production")
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module ThinkingSphinx
|
2
2
|
class Excerpter
|
3
|
-
CoreMethods = %w( kind_of? object_id respond_to? should
|
3
|
+
CoreMethods = %w( kind_of? object_id respond_to? respond_to_missing? should
|
4
|
+
should_not stub! )
|
4
5
|
# Hide most methods, to allow them to be passed through to the instance.
|
5
6
|
instance_methods.select { |method|
|
6
7
|
method.to_s[/^__/].nil? && !CoreMethods.include?(method.to_s)
|
@@ -98,16 +98,15 @@ module ThinkingSphinx
|
|
98
98
|
|
99
99
|
def translate(object, attribute_value)
|
100
100
|
objects = source_objects(object)
|
101
|
-
return
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
end
|
101
|
+
return if objects.blank?
|
102
|
+
|
103
|
+
method = value_source || column.__name
|
104
|
+
object = objects.one? ? objects.first : objects.detect { |item|
|
105
|
+
result = item.send(method)
|
106
|
+
result && result.to_crc32 == attribute_value
|
107
|
+
}
|
108
|
+
|
109
|
+
object.try(method)
|
111
110
|
end
|
112
111
|
|
113
112
|
def source_objects(object)
|
@@ -251,6 +251,16 @@ module ThinkingSphinx
|
|
251
251
|
FauxColumn.new(assoc, *args)
|
252
252
|
end
|
253
253
|
|
254
|
+
# Use this method to generate SQL for your attributes, conditions, etc.
|
255
|
+
# You can pass in as whatever ActiveRecord::Base.sanitize_sql accepts.
|
256
|
+
#
|
257
|
+
# where sanitize_sql(["active = ?", true])
|
258
|
+
# #=> WHERE active = 1
|
259
|
+
#
|
260
|
+
def sanitize_sql(*args)
|
261
|
+
@index.model.send(:sanitize_sql, *args)
|
262
|
+
end
|
263
|
+
|
254
264
|
private
|
255
265
|
|
256
266
|
def source
|
@@ -148,3 +148,34 @@ end
|
|
148
148
|
unless Object.new.respond_to?(:singleton_class)
|
149
149
|
Object.send(:include, ThinkingSphinx::SingletonClass)
|
150
150
|
end
|
151
|
+
|
152
|
+
module ThinkingSphinx
|
153
|
+
module ObjectTry
|
154
|
+
def try(*a, &b)
|
155
|
+
if a.empty? && block_given?
|
156
|
+
yield self
|
157
|
+
else
|
158
|
+
__send__(*a, &b)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
module NilClassTry
|
164
|
+
def try(*args)
|
165
|
+
nil
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
Object.send(:include, ThinkingSphinx::ObjectTry) unless Object.new.respond_to?(:try)
|
171
|
+
NilClass.send(:include, ThinkingSphinx::NilClassTry) unless nil.respond_to?(:try)
|
172
|
+
|
173
|
+
module ThinkingSphinx
|
174
|
+
module EnumerableOne
|
175
|
+
def one?(&block)
|
176
|
+
select(&block).size == 1
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
Enumerable.send(:include, ThinkingSphinx::EnumerableOne) unless [].respond_to?(:one?)
|
@@ -7,12 +7,12 @@ module ThinkingSphinx
|
|
7
7
|
# search_for_ids methods will do the job in exactly the same manner when
|
8
8
|
# called from a model.
|
9
9
|
#
|
10
|
-
class Search
|
10
|
+
class Search < Array
|
11
11
|
CoreMethods = %w( == class class_eval extend frozen? id instance_eval
|
12
12
|
instance_of? instance_values instance_variable_defined?
|
13
13
|
instance_variable_get instance_variable_set instance_variables is_a?
|
14
|
-
kind_of? member? method methods nil? object_id respond_to?
|
15
|
-
type )
|
14
|
+
kind_of? member? method methods nil? object_id respond_to?
|
15
|
+
respond_to_missing? send should type )
|
16
16
|
SafeMethods = %w( partition private_methods protected_methods
|
17
17
|
public_methods send class )
|
18
18
|
|
@@ -5,15 +5,16 @@ namespace :thinking_sphinx do
|
|
5
5
|
task :app_env do
|
6
6
|
if defined?(RAILS_ROOT)
|
7
7
|
Rake::Task[:environment].invoke
|
8
|
-
|
9
8
|
if defined?(Rails.configuration)
|
10
9
|
Rails.configuration.cache_classes = false
|
11
10
|
else
|
12
11
|
Rails::Initializer.run { |config| config.cache_classes = false }
|
13
12
|
end
|
13
|
+
elsif defined?(Merb)
|
14
|
+
Rake::Task[:merb_env].invoke
|
15
|
+
elsif defined?(Sinatra)
|
16
|
+
Sinatra::Application.environment = ENV['RACK_ENV']
|
14
17
|
end
|
15
|
-
|
16
|
-
Rake::Task[:merb_env].invoke if defined?(Merb)
|
17
18
|
end
|
18
19
|
|
19
20
|
desc "Output the current Thinking Sphinx version"
|
@@ -17,27 +17,27 @@ describe "ThinkingSphinx::ActiveRecord::Delta" do
|
|
17
17
|
|
18
18
|
describe "suspended_delta method" do
|
19
19
|
before :each do
|
20
|
-
ThinkingSphinx.
|
20
|
+
ThinkingSphinx.deltas_suspended = false
|
21
21
|
Person.sphinx_indexes.first.delta_object.stub!(:` => "")
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should execute the argument block with deltas disabled" do
|
25
|
-
ThinkingSphinx.should_receive(:
|
26
|
-
ThinkingSphinx.should_receive(:
|
25
|
+
ThinkingSphinx.should_receive(:deltas_suspended=).once.with(true)
|
26
|
+
ThinkingSphinx.should_receive(:deltas_suspended=).once.with(false)
|
27
27
|
lambda { Person.suspended_delta { raise 'i was called' } }.should(
|
28
28
|
raise_error(Exception)
|
29
29
|
)
|
30
30
|
end
|
31
31
|
|
32
32
|
it "should restore deltas_enabled to its original setting" do
|
33
|
-
ThinkingSphinx.
|
34
|
-
ThinkingSphinx.should_receive(:
|
33
|
+
ThinkingSphinx.deltas_suspended = true
|
34
|
+
ThinkingSphinx.should_receive(:deltas_suspended=).twice.with(true)
|
35
35
|
Person.suspended_delta { 'no-op' }
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should restore deltas_enabled to its original setting even if there was an exception" do
|
39
|
-
ThinkingSphinx.
|
40
|
-
ThinkingSphinx.should_receive(:
|
39
|
+
ThinkingSphinx.deltas_suspended = true
|
40
|
+
ThinkingSphinx.should_receive(:deltas_suspended=).twice.with(true)
|
41
41
|
lambda { Person.suspended_delta { raise 'bad error' } }.should(
|
42
42
|
raise_error(Exception)
|
43
43
|
)
|
@@ -81,9 +81,9 @@ describe ThinkingSphinx::Attribute do
|
|
81
81
|
|
82
82
|
describe '#is_many?' do
|
83
83
|
before :each do
|
84
|
-
@assoc_a =
|
85
|
-
@assoc_b =
|
86
|
-
@assoc_c =
|
84
|
+
@assoc_a = ThinkingSphinx::Association.new(nil, nil)
|
85
|
+
@assoc_b = ThinkingSphinx::Association.new(nil, nil)
|
86
|
+
@assoc_c = ThinkingSphinx::Association.new(nil, nil)
|
87
87
|
|
88
88
|
@attribute = ThinkingSphinx::Attribute.new(
|
89
89
|
@source, [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
|
@@ -91,6 +91,9 @@ describe ThinkingSphinx::Attribute do
|
|
91
91
|
@attribute.associations = {
|
92
92
|
:a => @assoc_a, :b => @assoc_b, :c => @assoc_c
|
93
93
|
}
|
94
|
+
@attribute.associations.values.each { |assoc|
|
95
|
+
assoc.stub!(:is_many? => true)
|
96
|
+
}
|
94
97
|
end
|
95
98
|
|
96
99
|
it "should return true if all associations return true to is_many?" do
|
@@ -30,7 +30,7 @@ describe ThinkingSphinx::AutoVersion do
|
|
30
30
|
ThinkingSphinx::AutoVersion.detect
|
31
31
|
end
|
32
32
|
|
33
|
-
it "should require 1.10-beta if
|
33
|
+
it "should require 1.10-beta if using 1.10-beta compiled with id64 support" do
|
34
34
|
ThinkingSphinx::AutoVersion.should_receive(:require).
|
35
35
|
with('riddle/1.10')
|
36
36
|
|
@@ -38,15 +38,23 @@ describe ThinkingSphinx::AutoVersion do
|
|
38
38
|
ThinkingSphinx::AutoVersion.detect
|
39
39
|
end
|
40
40
|
|
41
|
-
it "should
|
42
|
-
|
41
|
+
it "should require 2.0.1 if using Sphinx 2.0.1 beta" do
|
42
|
+
ThinkingSphinx::AutoVersion.should_receive(:require).
|
43
|
+
with('riddle/2.0.1')
|
44
|
+
|
45
|
+
@config.stub!(:version => '2.0.1-beta')
|
46
|
+
ThinkingSphinx::AutoVersion.detect
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should output a warning if the detected version is unsupported" do
|
50
|
+
STDERR.should_receive(:puts).with(/unsupported/i)
|
43
51
|
|
44
52
|
@config.stub!(:version => '0.9.7')
|
45
53
|
ThinkingSphinx::AutoVersion.detect
|
46
54
|
end
|
47
55
|
|
48
56
|
it "should output a warning if the version cannot be determined" do
|
49
|
-
STDERR.should_receive(:puts)
|
57
|
+
STDERR.should_receive(:puts).at_least(:once)
|
50
58
|
|
51
59
|
@config.stub!(:version => nil)
|
52
60
|
ThinkingSphinx::AutoVersion.detect
|
@@ -41,6 +41,7 @@ describe ThinkingSphinx::Context do
|
|
41
41
|
}.should_not raise_error
|
42
42
|
end
|
43
43
|
|
44
|
+
# Fails in Ruby 1.9 (or maybe it's an RSpec update). Not sure why.
|
44
45
|
it "should retry if the first pass fails and contains a directory" do
|
45
46
|
@model_name_lower.stub!(:gsub!).and_return(true, nil)
|
46
47
|
@class_name.stub(:constantize).and_raise(LoadError)
|
@@ -98,14 +98,6 @@ describe ThinkingSphinx::FacetSearch do
|
|
98
98
|
:classes => [Person], :facets => :state
|
99
99
|
)
|
100
100
|
end
|
101
|
-
|
102
|
-
it "should handle multiple facets" do
|
103
|
-
ThinkingSphinx.should_receive(:search).twice.and_return(search)
|
104
|
-
|
105
|
-
ThinkingSphinx::FacetSearch.new(
|
106
|
-
:classes => [Person], :facets => [:state, :city]
|
107
|
-
)
|
108
|
-
end
|
109
101
|
end
|
110
102
|
|
111
103
|
describe "empty result set for attributes" do
|
@@ -311,6 +311,18 @@ describe ThinkingSphinx::Facet do
|
|
311
311
|
ThinkingSphinx::Facet.new(field).value(friendship, {'name_facet' => 'buried'.to_crc32}).
|
312
312
|
should == 'buried'
|
313
313
|
end
|
314
|
+
|
315
|
+
it "should not error with multi-level association values containing a nil value" do
|
316
|
+
person = Person.find(:first)
|
317
|
+
tag = person.tags.build(:name => nil)
|
318
|
+
tag = person.tags.build(:name => "buried")
|
319
|
+
friendship = Friendship.new(:person => person)
|
320
|
+
|
321
|
+
field = ThinkingSphinx::Field.new(
|
322
|
+
@source, ThinkingSphinx::Index::FauxColumn.new(:person, :tags, :name)
|
323
|
+
)
|
324
|
+
lambda{ThinkingSphinx::Facet.new(field).value(friendship, {'name_facet' => 'buried'.to_crc32})}.should_not raise_error
|
325
|
+
end
|
314
326
|
end
|
315
327
|
|
316
328
|
describe 'for float attributes' do
|
@@ -90,9 +90,9 @@ describe ThinkingSphinx::Field do
|
|
90
90
|
|
91
91
|
describe "is_many? method" do
|
92
92
|
before :each do
|
93
|
-
@assoc_a =
|
94
|
-
@assoc_b =
|
95
|
-
@assoc_c =
|
93
|
+
@assoc_a = ThinkingSphinx::Association.new(nil, nil)
|
94
|
+
@assoc_b = ThinkingSphinx::Association.new(nil, nil)
|
95
|
+
@assoc_c = ThinkingSphinx::Association.new(nil, nil)
|
96
96
|
|
97
97
|
@field = ThinkingSphinx::Field.new(
|
98
98
|
@source, [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
|
@@ -100,6 +100,9 @@ describe ThinkingSphinx::Field do
|
|
100
100
|
@field.associations = {
|
101
101
|
:a => @assoc_a, :b => @assoc_b, :c => @assoc_c
|
102
102
|
}
|
103
|
+
@field.associations.values.each { |assoc|
|
104
|
+
assoc.stub!(:is_many? => true)
|
105
|
+
}
|
103
106
|
end
|
104
107
|
|
105
108
|
it "should return true if all associations return true to is_many?" do
|
@@ -492,4 +492,17 @@ describe ThinkingSphinx::Index::Builder do
|
|
492
492
|
index.name.should == 'custom'
|
493
493
|
end
|
494
494
|
end
|
495
|
+
|
496
|
+
describe "sanitize_sql" do
|
497
|
+
def index
|
498
|
+
@index ||= ThinkingSphinx::Index::Builder.generate(Person) do
|
499
|
+
indexes first_name, last_name
|
500
|
+
where sanitize_sql(["gender = ?", "female"])
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
it "should be aliased to ActiveRecord::Base.sanitize_sql" do
|
505
|
+
index.sources.first.conditions.first.should == index.model.send(:sanitize_sql, ["gender = ?", "female"])
|
506
|
+
end
|
507
|
+
end
|
495
508
|
end
|
@@ -914,7 +914,8 @@ describe ThinkingSphinx::Search do
|
|
914
914
|
it "should not add excerpts method if objects already have one" do
|
915
915
|
@search.last.excerpts.should_not be_a(ThinkingSphinx::Excerpter)
|
916
916
|
end
|
917
|
-
|
917
|
+
|
918
|
+
# Fails in Ruby 1.9 (or maybe it's an RSpec update). Not sure why.
|
918
919
|
it "should set up the excerpter with the instances and search" do
|
919
920
|
[@alpha_a, @beta_b, @alpha_b, @beta_a].each do |object|
|
920
921
|
ThinkingSphinx::Excerpter.should_receive(:new).with(@search, object)
|