thinking-sphinx 3.0.3 → 3.0.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.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -1
  3. data/HISTORY +25 -0
  4. data/lib/thinking_sphinx.rb +1 -0
  5. data/lib/thinking_sphinx/active_record/association_proxy.rb +13 -55
  6. data/lib/thinking_sphinx/active_record/association_proxy/attribute_finder.rb +47 -0
  7. data/lib/thinking_sphinx/active_record/base.rb +16 -15
  8. data/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +1 -12
  9. data/lib/thinking_sphinx/active_record/database_adapters.rb +41 -42
  10. data/lib/thinking_sphinx/active_record/polymorpher.rb +7 -2
  11. data/lib/thinking_sphinx/active_record/property_query.rb +23 -19
  12. data/lib/thinking_sphinx/active_record/sql_builder.rb +108 -129
  13. data/lib/thinking_sphinx/active_record/sql_builder/clause_builder.rb +28 -0
  14. data/lib/thinking_sphinx/active_record/sql_builder/query.rb +43 -0
  15. data/lib/thinking_sphinx/active_record/sql_builder/statement.rb +110 -0
  16. data/lib/thinking_sphinx/active_record/sql_source.rb +143 -138
  17. data/lib/thinking_sphinx/capistrano.rb +11 -8
  18. data/lib/thinking_sphinx/configuration.rb +57 -35
  19. data/lib/thinking_sphinx/connection.rb +15 -6
  20. data/lib/thinking_sphinx/core.rb +1 -0
  21. data/lib/thinking_sphinx/core/index.rb +18 -10
  22. data/lib/thinking_sphinx/core/settings.rb +9 -0
  23. data/lib/thinking_sphinx/deletion.rb +48 -0
  24. data/lib/thinking_sphinx/errors.rb +7 -0
  25. data/lib/thinking_sphinx/excerpter.rb +1 -0
  26. data/lib/thinking_sphinx/facet_search.rb +42 -19
  27. data/lib/thinking_sphinx/masks/scopes_mask.rb +7 -0
  28. data/lib/thinking_sphinx/middlewares.rb +27 -33
  29. data/lib/thinking_sphinx/middlewares/active_record_translator.rb +18 -18
  30. data/lib/thinking_sphinx/middlewares/geographer.rb +49 -16
  31. data/lib/thinking_sphinx/middlewares/sphinxql.rb +128 -58
  32. data/lib/thinking_sphinx/panes/excerpts_pane.rb +7 -3
  33. data/lib/thinking_sphinx/rake_interface.rb +10 -0
  34. data/lib/thinking_sphinx/real_time.rb +7 -1
  35. data/lib/thinking_sphinx/real_time/attribute.rb +4 -0
  36. data/lib/thinking_sphinx/real_time/callbacks/real_time_callbacks.rb +14 -10
  37. data/lib/thinking_sphinx/real_time/index.rb +20 -12
  38. data/lib/thinking_sphinx/search/glaze.rb +5 -0
  39. data/lib/thinking_sphinx/search/query.rb +4 -8
  40. data/lib/thinking_sphinx/tasks.rb +8 -0
  41. data/spec/acceptance/excerpts_spec.rb +22 -0
  42. data/spec/acceptance/remove_deleted_records_spec.rb +10 -0
  43. data/spec/acceptance/searching_across_models_spec.rb +10 -0
  44. data/spec/acceptance/searching_with_filters_spec.rb +15 -0
  45. data/spec/acceptance/specifying_sql_spec.rb +3 -3
  46. data/spec/acceptance/sphinx_scopes_spec.rb +11 -0
  47. data/spec/internal/app/indices/product_index.rb +2 -0
  48. data/spec/internal/app/models/categorisation.rb +6 -0
  49. data/spec/internal/app/models/category.rb +3 -0
  50. data/spec/internal/app/models/product.rb +4 -1
  51. data/spec/internal/db/schema.rb +10 -0
  52. data/spec/thinking_sphinx/active_record/base_spec.rb +33 -0
  53. data/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb +4 -35
  54. data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +5 -10
  55. data/spec/thinking_sphinx/active_record/sql_source_spec.rb +4 -3
  56. data/spec/thinking_sphinx/configuration_spec.rb +26 -6
  57. data/spec/thinking_sphinx/connection_spec.rb +4 -1
  58. data/spec/thinking_sphinx/deletion_spec.rb +76 -0
  59. data/spec/thinking_sphinx/facet_search_spec.rb +54 -5
  60. data/spec/thinking_sphinx/panes/excerpts_pane_spec.rb +4 -6
  61. data/spec/thinking_sphinx/rake_interface_spec.rb +35 -0
  62. data/spec/thinking_sphinx/real_time/callbacks/real_time_callbacks_spec.rb +68 -28
  63. data/spec/thinking_sphinx/search/glaze_spec.rb +19 -0
  64. data/spec/thinking_sphinx/search/query_spec.rb +39 -2
  65. data/thinking-sphinx.gemspec +2 -2
  66. metadata +31 -45
@@ -15,6 +15,11 @@ class ThinkingSphinx::Search::Glaze < BasicObject
15
15
  @object.equal? object
16
16
  end
17
17
 
18
+ def respond_to?(method, include_private = false)
19
+ @object.respond_to?(method, include_private) ||
20
+ @panes.any? { |pane| pane.respond_to?(method, include_private) }
21
+ end
22
+
18
23
  def unglazed
19
24
  @object
20
25
  end
@@ -1,11 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  class ThinkingSphinx::Search::Query
4
- if Regexp.instance_methods.include?(:encoding)
5
- DefaultToken = Regexp.new('\p{Word}+')
6
- else
7
- DefaultToken = Regexp.new('\w+', nil, 'u')
8
- end
4
+ DEFAULT_TOKEN = /[\p{Word}\\][\p{Word}\\@]+/
9
5
 
10
6
  attr_reader :keywords, :conditions, :star
11
7
 
@@ -14,7 +10,7 @@ class ThinkingSphinx::Search::Query
14
10
  end
15
11
 
16
12
  def to_s
17
- (star_keyword(keywords) + ' ' + conditions.keys.collect { |key|
13
+ (star_keyword(keywords || '') + ' ' + conditions.keys.collect { |key|
18
14
  next if conditions[key].blank?
19
15
 
20
16
  "@#{key} #{star_keyword conditions[key], key}"
@@ -24,11 +20,11 @@ class ThinkingSphinx::Search::Query
24
20
  private
25
21
 
26
22
  def star_keyword(keyword, key = nil)
27
- unless star && (key.nil? || key.to_s != 'sphinx_internal_class')
23
+ unless star && (key.nil? || key.to_s != 'sphinx_internal_class_name')
28
24
  return keyword.to_s
29
25
  end
30
26
 
31
- token = star.is_a?(Regexp) ? star : DefaultToken
27
+ token = star.is_a?(Regexp) ? star : DEFAULT_TOKEN
32
28
  keyword.gsub(/("#{token}(.*?#{token})?"|(?![!-])#{token})/u) do
33
29
  pre, proper, post = $`, $&, $'
34
30
  # E.g. "@foo", "/2", "~3", but not as part of a token
@@ -9,6 +9,11 @@ namespace :ts do
9
9
  interface.index(ENV['INDEX_ONLY'] != 'true')
10
10
  end
11
11
 
12
+ desc 'Clear out Sphinx files'
13
+ task :clear => :environment do
14
+ interface.clear
15
+ end
16
+
12
17
  desc 'Generate fresh index files for real-time indices'
13
18
  task :generate => :environment do
14
19
  interface.generate
@@ -17,6 +22,9 @@ namespace :ts do
17
22
  desc 'Stop Sphinx, index and then restart Sphinx'
18
23
  task :rebuild => [:stop, :index, :start]
19
24
 
25
+ desc 'Stop Sphinx, clear files, reconfigure, start Sphinx, generate files'
26
+ task :regenerate => [:stop, :clear, :configure, :start, :generate]
27
+
20
28
  desc 'Restart the Sphinx daemon'
21
29
  task :restart => [:stop, :start]
22
30
 
@@ -24,4 +24,26 @@ describe 'Accessing excerpts for methods on a search result', :live => true do
24
24
  search.first.excerpts.title.
25
25
  should == 'Война и <span class="match">миръ</span>'
26
26
  end
27
+
28
+ it "does not include class names in excerpts" do
29
+ Book.create! :title => 'The Graveyard Book'
30
+ index
31
+
32
+ search = Book.search('graveyard')
33
+ search.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
34
+
35
+ search.first.excerpts.title.
36
+ should == 'The <span class="match">Graveyard</span> Book'
37
+ end
38
+
39
+ it "respects the star option with queries" do
40
+ Article.create! :title => 'Something'
41
+ index
42
+
43
+ search = Article.search('thin', :star => true)
44
+ search.context[:panes] << ThinkingSphinx::Panes::ExcerptsPane
45
+
46
+ search.first.excerpts.title.
47
+ should == '<span class="match">Something</span>'
48
+ end
27
49
  end
@@ -20,4 +20,14 @@ describe 'Hiding deleted records from search results', :live => true do
20
20
 
21
21
  Article.search('pancakes').should be_empty
22
22
  end
23
+
24
+ it "removes records from real-time index results" do
25
+ product = Product.create! :name => 'Shiny'
26
+
27
+ Product.search('Shiny').to_a.should == [product]
28
+
29
+ product.destroy
30
+
31
+ Product.search_for_ids('Shiny').should be_empty
32
+ end
23
33
  end
@@ -25,4 +25,14 @@ describe 'Searching across models', :live => true do
25
25
 
26
26
  ThinkingSphinx.search.to_a.should =~ [article, book]
27
27
  end
28
+
29
+ it "filters by multiple classes" do
30
+ article = Article.create! :title => 'Pancakes'
31
+ book = Book.create! :title => 'American Gods'
32
+ user = User.create! :name => 'Pat'
33
+ index
34
+
35
+ ThinkingSphinx.search(:classes => [User, Article]).to_a.
36
+ should =~ [article, user]
37
+ end
28
38
  end
@@ -106,4 +106,19 @@ describe 'Searching with filters', :live => true do
106
106
  articles = Article.search :without_all => {:tag_ids => [food.id, flat.id]}
107
107
  articles.to_a.should == [waffles]
108
108
  end
109
+
110
+ it "limits results on real-time indices with multi-value integer attributes" do
111
+ pancakes = Product.create :name => 'Pancakes'
112
+ waffles = Product.create :name => 'Waffles'
113
+
114
+ food = Category.create :name => 'food'
115
+ flat = Category.create :name => 'flat'
116
+
117
+ pancakes.categories << food
118
+ pancakes.categories << flat
119
+ waffles.categories << food
120
+
121
+ products = Product.search :with => {:category_ids => [flat.id]}
122
+ products.to_a.should == [pancakes]
123
+ end
109
124
  end
@@ -264,7 +264,7 @@ describe 'separate queries for MVAs' do
264
264
  declaration, query, range = attribute.split(/;\s+/)
265
265
 
266
266
  declaration.should == 'uint tag_ids from ranged-query'
267
- query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .taggings.\..tag_id. AS .tag_ids. FROM .taggings. \s?WHERE \(.taggings.\..article_id. >= \$start\) AND \(.taggings.\..article_id. <= \$end\)$/)
267
+ query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .taggings.\..tag_id. AS .tag_ids. FROM .taggings. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\)$/)
268
268
  range.should match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
269
269
  end
270
270
 
@@ -281,7 +281,7 @@ describe 'separate queries for MVAs' do
281
281
  declaration, query, range = attribute.split(/;\s+/)
282
282
 
283
283
  declaration.should == 'uint tag_ids from ranged-query'
284
- query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. >= \$start\) AND \(.taggings.\..article_id. <= \$end\)$/)
284
+ query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\)$/)
285
285
  range.should match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
286
286
  end
287
287
 
@@ -396,7 +396,7 @@ describe 'separate queries for field' do
396
396
  declaration, query, range = field.split(/;\s+/)
397
397
 
398
398
  declaration.should == 'tags from ranged-query'
399
- query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. >= \$start\) AND \(.taggings.\..article_id. <= \$end\)\s? ORDER BY .taggings.\..article_id. ASC$/)
399
+ query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\)\s? ORDER BY .taggings.\..article_id. ASC$/)
400
400
  range.should match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
401
401
  end
402
402
 
@@ -37,6 +37,17 @@ describe 'Sphinx scopes', :live => true do
37
37
  Book.by_query('Gods').search('Small').to_a.should == [pratchett]
38
38
  end
39
39
 
40
+ it "allows facet calls on scopes" do
41
+ Book.create! :title => 'American Gods', :author => 'Neil Gaiman'
42
+ Book.create! :title => 'Anansi Boys', :author => 'Neil Gaiman'
43
+ Book.create! :title => 'Small Gods', :author => 'Terry Pratchett'
44
+ index
45
+
46
+ Book.by_query('Gods').facets.to_hash[:author].should == {
47
+ 'Neil Gaiman' => 1, 'Terry Pratchett' => 1
48
+ }
49
+ end
50
+
40
51
  it "allows accessing counts on scopes" do
41
52
  Book.create! :title => 'American Gods'
42
53
  Book.create! :title => 'Anansi Boys'
@@ -1,3 +1,5 @@
1
1
  ThinkingSphinx::Index.define :product, :with => :real_time do
2
2
  indexes name
3
+
4
+ has category_ids, :type => :integer, :multi => true
3
5
  end
@@ -0,0 +1,6 @@
1
+ class Categorisation < ActiveRecord::Base
2
+ belongs_to :category
3
+ belongs_to :product
4
+
5
+ after_save ThinkingSphinx::RealTime.callback_for(:product, [:product])
6
+ end
@@ -0,0 +1,3 @@
1
+ class Category < ActiveRecord::Base
2
+ #
3
+ end
@@ -1,3 +1,6 @@
1
1
  class Product < ActiveRecord::Base
2
- #
2
+ has_many :categorisations
3
+ has_many :categories, :through => :categorisations
4
+
5
+ after_save ThinkingSphinx::RealTime.callback_for(:product)
3
6
  end
@@ -32,6 +32,16 @@ ActiveRecord::Schema.define do
32
32
  t.integer :genre_id
33
33
  end
34
34
 
35
+ create_table(:categories, :force => true) do |t|
36
+ t.integer :id
37
+ t.string :name
38
+ end
39
+
40
+ create_table(:categorisations, :force => true) do |t|
41
+ t.integer :category_id
42
+ t.integer :product_id
43
+ end
44
+
35
45
  create_table(:cities, :force => true) do |t|
36
46
  t.string :name
37
47
  t.float :lat
@@ -14,6 +14,39 @@ describe ThinkingSphinx::ActiveRecord::Base do
14
14
  end
15
15
  }
16
16
 
17
+ describe '.facets' do
18
+ it "returns a new search object" do
19
+ model.facets.should be_a(ThinkingSphinx::FacetSearch)
20
+ end
21
+
22
+ it "passes through arguments to the search object" do
23
+ model.facets('pancakes').query.should == 'pancakes'
24
+ end
25
+
26
+ it "scopes the search to a given model" do
27
+ model.facets('pancakes').options[:classes].should == [model]
28
+ end
29
+
30
+ it "merges the :classes option with the model" do
31
+ model.facets('pancakes', :classes => [sub_model]).
32
+ options[:classes].should == [sub_model, model]
33
+ end
34
+
35
+ it "applies the default scope if there is one" do
36
+ model.stub :default_sphinx_scope => :default,
37
+ :sphinx_scopes => {:default => Proc.new { {:order => :created_at} }}
38
+
39
+ model.facets.options[:order].should == :created_at
40
+ end
41
+
42
+ it "does not apply a default scope if one is not set" do
43
+ model.stub :default_sphinx_scope => nil,
44
+ :default => {:order => :created_at}
45
+
46
+ model.facets.options[:order].should be_nil
47
+ end
48
+ end
49
+
17
50
  describe '.search' do
18
51
  it "returns a new search object" do
19
52
  model.search.should be_a(ThinkingSphinx::Search)
@@ -33,49 +33,18 @@ describe ThinkingSphinx::ActiveRecord::Callbacks::DeleteCallbacks do
33
33
  describe '#after_destroy' do
34
34
  let(:config) { double('config', :indices_for_references => [index],
35
35
  :preload_indices => true) }
36
- let(:connection) { double('connection', :execute => nil) }
37
- let(:index) {
38
- double('index', :name => 'foo_core', :document_id_for_key => 14)
39
- }
36
+ let(:index) { double('index', :name => 'foo_core',
37
+ :document_id_for_key => 14, :type => 'plain') }
40
38
  let(:instance) { double('instance', :id => 7) }
41
39
 
42
40
  before :each do
43
41
  ThinkingSphinx::Configuration.stub :instance => config
44
- ThinkingSphinx::Connection.stub :new => connection
45
- Riddle::Query.stub :update => 'UPDATE STATEMENT'
46
42
  end
47
43
 
48
- it "updates the deleted flag to false" do
49
- connection.should_receive(:execute).with('UPDATE STATEMENT')
44
+ it "performs the deletion for the index and instance" do
45
+ ThinkingSphinx::Deletion.should_receive(:perform).with(index, instance)
50
46
 
51
47
  callbacks.after_destroy
52
48
  end
53
-
54
- it "builds the update query for the given index" do
55
- Riddle::Query.should_receive(:update).
56
- with('foo_core', anything, anything).and_return('')
57
-
58
- callbacks.after_destroy
59
- end
60
-
61
- it "builds the update query for the sphinx document id" do
62
- Riddle::Query.should_receive(:update).
63
- with(anything, 14, anything).and_return('')
64
-
65
- callbacks.after_destroy
66
- end
67
-
68
- it "builds the update query for setting sphinx_deleted to true" do
69
- Riddle::Query.should_receive(:update).
70
- with(anything, anything, :sphinx_deleted => true).and_return('')
71
-
72
- callbacks.after_destroy
73
- end
74
-
75
- it "doesn't care about Sphinx errors" do
76
- connection.stub(:execute).and_raise(Mysql2::Error.new(''))
77
-
78
- lambda { callbacks.after_destroy }.should_not raise_error
79
- end
80
49
  end
81
50
  end
@@ -105,8 +105,7 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
105
105
 
106
106
  it "limits results to a set range" do
107
107
  relation.should_receive(:where) do |string|
108
- string.should match(/`users`.`id` >= \$start/)
109
- string.should match(/`users`.`id` <= \$end/)
108
+ string.should match(/`users`.`id` BETWEEN \$start AND \$end/)
110
109
  relation
111
110
  end
112
111
 
@@ -117,8 +116,7 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
117
116
  source.stub! :disable_range? => true
118
117
 
119
118
  relation.should_receive(:where) do |string|
120
- string.should_not match(/`users`.`id` >= \$start/)
121
- string.should_not match(/`users`.`id` <= \$end/)
119
+ string.should_not match(/`users`.`id` BETWEEN \$start AND \$end/)
122
120
  relation
123
121
  end
124
122
 
@@ -318,8 +316,7 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
318
316
 
319
317
  it "limits results to a set range" do
320
318
  relation.should_receive(:where) do |string|
321
- string.should match(/"users"."id" >= \$start/)
322
- string.should match(/"users"."id" <= \$end/)
319
+ string.should match(/"users"."id" BETWEEN \$start AND \$end/)
323
320
  relation
324
321
  end
325
322
 
@@ -330,8 +327,7 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
330
327
  source.stub! :disable_range? => true
331
328
 
332
329
  relation.should_receive(:where) do |string|
333
- string.should_not match(/"users"."id" >= \$start/)
334
- string.should_not match(/"users"."id" <= \$end/)
330
+ string.should_not match(/"users"."id" BETWEEN \$start AND \$end/)
335
331
  relation
336
332
  end
337
333
 
@@ -590,8 +586,7 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
590
586
 
591
587
  it "shouldn't limit results to a range" do
592
588
  relation.should_receive(:where) do |string|
593
- string.should_not match(/`users`.`id` >= \$start/)
594
- string.should_not match(/`users`.`id` <= \$end/)
589
+ string.should_not match(/`users`.`id` BETWEEN \$start AND \$end/)
595
590
  relation
596
591
  end
597
592
 
@@ -1,9 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ThinkingSphinx::ActiveRecord::SQLSource do
4
- let(:model) { double('model', :connection => connection,
5
- :name => 'User', :column_names => [], :inheritance_column => 'type',
6
- :primary_key => :id) }
4
+ let(:model) { double('model', :name => 'User', :column_names => [],
5
+ :inheritance_column => 'type', :primary_key => :id) }
7
6
  let(:connection) {
8
7
  double('connection', :instance_variable_get => db_config) }
9
8
  let(:db_config) { {:host => 'localhost', :user => 'root',
@@ -13,6 +12,8 @@ describe ThinkingSphinx::ActiveRecord::SQLSource do
13
12
  let(:adapter) { double('adapter') }
14
13
 
15
14
  before :each do
15
+ stub_const 'ActiveRecord::Base', double(:connection => connection)
16
+
16
17
  ThinkingSphinx::ActiveRecord::DatabaseAdapters::MySQLAdapter.
17
18
  stub!(:=== => true)
18
19
  ThinkingSphinx::ActiveRecord::DatabaseAdapters.
@@ -23,6 +23,28 @@ describe ThinkingSphinx::Configuration do
23
23
  end
24
24
  end
25
25
 
26
+ describe '.reset' do
27
+ after :each do
28
+ config.framework = ThinkingSphinx::Frameworks.current
29
+ end
30
+
31
+ it 'does not cache settings after reset' do
32
+ File.stub :exists? => true
33
+ File.stub :read => {
34
+ 'test' => {'foo' => 'bugs'},
35
+ 'production' => {'foo' => 'bar'}
36
+ }.to_yaml
37
+
38
+ ThinkingSphinx::Configuration.reset
39
+ # Grab a new copy of the instance.
40
+ config = ThinkingSphinx::Configuration.instance
41
+ config.settings['foo'].should == 'bugs'
42
+
43
+ config.framework = double :environment => 'production', :root => '/tmp/'
44
+ config.settings['foo'].should == 'bar'
45
+ end
46
+ end
47
+
26
48
  describe '#configuration_file' do
27
49
  it "uses the Rails environment in the configuration file name" do
28
50
  config.configuration_file.
@@ -68,13 +90,11 @@ describe ThinkingSphinx::Configuration do
68
90
  end
69
91
 
70
92
  it "uses app/indices in the Rails engines" do
71
- engine =
72
- stub(:engine, { :paths => { 'app/indices' =>
73
- stub(:path, { :existent => '/engine/app/indices' } )
74
- } } )
93
+ engine = stub(:engine, { :paths => { 'app/indices' =>
94
+ stub(:path, { :existent => '/engine/app/indices' } )
95
+ } } )
75
96
 
76
- Rails::Engine::Railties.should_receive(:engines).
77
- and_return([ engine ])
97
+ Rails::Engine::Railties.should_receive(:engines).and_return([ engine ])
78
98
 
79
99
  config.index_paths.should include('/engine/app/indices')
80
100
  end