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 CHANGED
@@ -142,3 +142,6 @@ Since I first released this library, there's been quite a few people who have su
142
142
  * Christian Aust
143
143
  * Martin Sarasale
144
144
  * Édouard Brière
145
+ * Steve Madsen
146
+ * Justin DeWind
147
+ * Chris Z
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- :patch: 3
2
+ :patch: 4
3
3
  :major: 1
4
4
  :build:
5
5
  :minor: 3
@@ -1,7 +1,3 @@
1
- Dir[File.join(File.dirname(__FILE__), '../vendor/*/lib')].each do |path|
2
- $LOAD_PATH.unshift path
3
- end
4
-
5
1
  require 'active_record'
6
2
  require 'after_commit'
7
3
  require 'yaml'
@@ -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 sql_range_step sql_query_pre
53
- sql_query_post sql_ranged_throttle sql_query_post_index )
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 ignore_chars
57
- min_infix_len min_prefix_len min_word_len mlock morphology ngram_chars
58
- ngram_len phrase_boundary phrase_boundary_step preopen stopwords
59
- wordforms )
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 Sphinx: #{query}"
235
- @results = client.query query, indexes, comment
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
- ::ActiveRecord::Base.logger.send method, message
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(message, method = :debug)
289
- self.class.log(message, method)
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
@@ -1,3 +1,7 @@
1
+ Dir[File.join(File.dirname(__FILE__), '../vendor/*/lib')].each do |path|
2
+ $LOAD_PATH.unshift path
3
+ end
4
+
1
5
  require 'thinking_sphinx/0.9.8'
2
6
  require 'action_controller/dispatcher'
3
7
 
@@ -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] = "something"
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[option.to_sym] = nil
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
@@ -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.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.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-11 00:00:00 +11:00
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.0
33
+ version: 1.0.1
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: after_commit