thinking-sphinx 1.4.4 → 1.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)
|