thinking-sphinx 1.3.3 → 1.3.4

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 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