Sphincter 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,5 @@
1
+ == 1.0.0 / 2007-07-26
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
5
+
data/LICENSE.txt ADDED
@@ -0,0 +1,27 @@
1
+ Copyright 2007 Eric Hodel. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ 3. Neither the names of the authors nor the names of their contributors
13
+ may be used to endorse or promote products derived from this software
14
+ without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
17
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
20
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
data/Manifest.txt ADDED
@@ -0,0 +1,16 @@
1
+ History.txt
2
+ LICENSE.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ lib/sphincter.rb
7
+ lib/sphincter/association_searcher.rb
8
+ lib/sphincter/configure.rb
9
+ lib/sphincter/search.rb
10
+ lib/sphincter/search_stub.rb
11
+ lib/sphincter/tasks.rb
12
+ test/sphincter_test_case.rb
13
+ test/test_sphincter_association_searcher.rb
14
+ test/test_sphincter_configure.rb
15
+ test/test_sphincter_search.rb
16
+ test/test_sphincter_search_stub.rb
data/README.txt ADDED
@@ -0,0 +1,132 @@
1
+ Sphincter
2
+
3
+ Eric Hodel <drbrain@segment7.net>
4
+
5
+ http://seattlerb.org/Sphincter
6
+
7
+ Sphincter was named by David Yeu.
8
+
9
+ == DESCRIPTION:
10
+
11
+ Sphincter is an ActiveRecord extension for full-text searching with Sphinx.
12
+
13
+ Sphincter uses Dmytro Shteflyuk's sphinx Ruby API and automatic
14
+ configuration to make totally rad ActiveRecord searching. Well, you
15
+ still have to tell Sphincter what models you want to search. It
16
+ doesn't read your mind.
17
+
18
+ For complete documentation:
19
+
20
+ ri Sphincter
21
+
22
+ == FEATURES:
23
+
24
+ * Automatically configures itself.
25
+ * Handy set of rake tasks for easy, automatic management.
26
+ * Automatically adds has_many metadata for searching across the
27
+ association.
28
+ * Stub for testing without connecting to searchd, Sphincter::SearchStub.
29
+ * Easy pagination support.
30
+ * Filtering by index metadata and ranges, including dates.
31
+
32
+ == PROBLEMS:
33
+
34
+ * Setting match mode not supported.
35
+ * Setting sort mode not supported.
36
+ * Setting per-field weights not supported.
37
+ * Setting id range not supported.
38
+ * Setting group-by not supported.
39
+
40
+ == QUICK-START:
41
+
42
+ Download and install Sphinx from http://www.sphinxsearch.com/downloads.html
43
+
44
+ Download Sphinx Ruby API from http://rubyforge.org/frs/?group_id=2604&release_id=11049
45
+
46
+ Unpack Sphinx Ruby API into vendor/plugins/.
47
+
48
+ Install Sphincter:
49
+
50
+ $ gem install Sphincter
51
+
52
+ Load Sphincter in config/environment.rb:
53
+
54
+ require 'sphincter'
55
+
56
+ By default, Sphincter will run searchd on the same port for all
57
+ environments. See Sphincter::Configure for how to configure different
58
+ environments to use different ports.
59
+
60
+ Add indexes to models:
61
+
62
+ class Post < ActiveRecord::Base
63
+ belongs_to :blog
64
+ add_index :fields => %w[title body published]
65
+ end
66
+
67
+ Add searching UI:
68
+
69
+ class BlogController < ApplicationController
70
+ def search
71
+ @blog = Blog.find params[:id]
72
+
73
+ @results = @blog.posts.search params[:q]
74
+ end
75
+ end
76
+
77
+ Start searchd:
78
+
79
+ $ rake sphincter:start_searchd
80
+
81
+ Then test it out in your browser.
82
+
83
+ == TESTING QUICK-START:
84
+
85
+ See Sphinx::SearchStub.
86
+
87
+ == EXAMPLES:
88
+
89
+ See Sphincter::Search#search for full documentation.
90
+
91
+ Example ActiveRecord model:
92
+
93
+ class Post < ActiveRecord::Base
94
+ belongs_to :blog
95
+
96
+ # published is a boolean and title and body are string or text fields
97
+ add_index :fields => %w[title body published]
98
+ end
99
+
100
+ Simple search:
101
+
102
+ Post.search 'words'
103
+
104
+ Only search published posts:
105
+
106
+ Post.search 'words', :conditions => { :published => 1 }
107
+
108
+ Only search posts created in the last week:
109
+
110
+ now = Time.now
111
+ ago = now - 1.weeks
112
+ Post.search 'words', :between => { :created_on => [ago, now] }
113
+
114
+ Pagination (defaults to ten records/page):
115
+
116
+ Post.search 'words', :page => 2
117
+
118
+ Pagination with custom page size:
119
+
120
+ Post.search 'words', :page => 2, :per_page => 20
121
+
122
+ Pagination with custom page size (better):
123
+
124
+ Add to config/sphincter.yml:
125
+
126
+ sphincter:
127
+ per_page: 20
128
+
129
+ Then search:
130
+
131
+ Post.search 'words', :page => 2
132
+
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ $:.unshift 'lib'
6
+ require 'sphincter'
7
+
8
+ Hoe.new('Sphincter', Sphincter::VERSION) do |p|
9
+ p.rubyforge_name = 'seattlerb'
10
+ p.author = 'Eric Hodel'
11
+ p.email = 'drbrain@segment7.net'
12
+ p.summary = p.paragraphs_of('README.txt', 5).first
13
+ p.description = p.paragraphs_of('README.txt', 6).first
14
+ p.url = p.paragraphs_of('README.txt', 2).first
15
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
16
+
17
+ p.extra_deps << ['rake', '>= 0.7.3']
18
+ p.extra_deps << ['rails', '>= 1.2.3']
19
+ end
20
+
21
+ # vim: syntax=Ruby
data/lib/sphincter.rb ADDED
@@ -0,0 +1,102 @@
1
+ $TESTING = defined?($TESTING) && $TESTING
2
+
3
+ ##
4
+ # Sphincter is a ActiveRecord extension for full-text searching using the
5
+ # Sphinx library.
6
+ #
7
+ # For the quick-start guide and some examples, see README.txt.
8
+ #
9
+ # == Installing
10
+ #
11
+ # Download and install Sphinx from http://www.sphinxsearch.com/downloads.html
12
+ #
13
+ # Download Sphinx Ruby API from
14
+ # http://rubyforge.org/frs/?group_id=2604&release_id=11049
15
+ #
16
+ # Unpack Sphinx Ruby API into vendor/plugins/.
17
+ #
18
+ # Install the gem:
19
+ #
20
+ # gem install Sphincter
21
+ #
22
+ # Require Sphincter in config/environment.rb:
23
+ #
24
+ # require 'sphincter'
25
+ #
26
+ # Require the Sphincter rake tasks in Rakefile:
27
+ #
28
+ # require 'sphincter/tasks'
29
+ #
30
+ # == Setup
31
+ #
32
+ # At best, you don't do anything to setup Sphincter. It has sensible built-in
33
+ # defaults.
34
+ #
35
+ # If you're running Sphinx's searchd for multiple environments on the same
36
+ # machine, you'll want to add a config file to change the port that searchd
37
+ # and the RAILS_ENV will comminicate across. Do that in a per-environment
38
+ # configuration file.
39
+ #
40
+ # If you have multiple machines, you'll want to change which address searchd
41
+ # will run on. Do that in the global configuration file.
42
+ #
43
+ # See Sphincter::Configure for full information on how to setup these and
44
+ # other options for Sphincter.
45
+ #
46
+ # When you're done, run:
47
+ #
48
+ # $ rake sphincter:configure
49
+ #
50
+ # == Indexing
51
+ #
52
+ # Sphincter automatically extends ActiveRecord::Base with Sphincter::Search, so
53
+ # you only have to call add_index in the models you want indexed:
54
+ #
55
+ # class Model < ActiveRecord::Base
56
+ # belongs_to :other
57
+ #
58
+ # add_index :fields => %w[title body]
59
+ # end
60
+ #
61
+ # class Other < ActiveRecord::Base
62
+ # has_many :models
63
+ # end
64
+ #
65
+ # add_index automatically adds a #search method to has_many associations
66
+ # referencing this model, so you could:
67
+ #
68
+ # Other.find(id).models.search 'some query'
69
+ #
70
+ # See Sphincter::Search for details.
71
+ #
72
+ # When you're done, run:
73
+ #
74
+ # rake sphincter:index
75
+ #
76
+ # == Tasks
77
+ #
78
+ # You can get a set of Sphincter tasks by requiring 'sphincter/tasks' in your
79
+ # Rakefile. These tasks are all in the 'sphincter' namespace:
80
+ #
81
+ # configure:: Creates sphinx.conf if it doesn't exist
82
+ # reconfigure:: Creates sphinx.conf, replacing the existing one.
83
+ # index:: Runs the sphinx indexer if the index doesn't exist.
84
+ # reindex:: Runs the sphinx indexer. Rotates the index if searchd is running.
85
+ # reset:: Stops searchd, reconfigures and reindexes
86
+ # restart_searchd:: Restarts the searchd sphinx daemon
87
+ # start_searchd:: Starts the searchd sphinx daemon
88
+ # stop_searchd:: Stops the searchd daemon
89
+
90
+ module Sphincter
91
+
92
+ ##
93
+ # This is the version of Sphincter you are using.
94
+
95
+ VERSION = '1.0.0'
96
+
97
+ end
98
+
99
+ require 'sphincter/configure'
100
+ require 'sphincter/association_searcher'
101
+ require 'sphincter/search'
102
+
@@ -0,0 +1,22 @@
1
+ require 'sphincter'
2
+
3
+ ##
4
+ # ActiveRecord::Associations::ClassMethods#has_many extension for searching
5
+ # the items of an ActiveRecord::Associations::AssociationProxy.
6
+
7
+ module Sphincter::AssociationSearcher
8
+
9
+ ##
10
+ # Searches for +query+ with +options+. Adds a condition so only the
11
+ # proxy_owner's records are matched.
12
+
13
+ def search(query, options = {})
14
+ pkey = proxy_reflection.primary_key_name
15
+ options[:conditions] ||= {}
16
+ options[:conditions][pkey] = proxy_owner.id
17
+
18
+ proxy_reflection.klass.search query, options
19
+ end
20
+
21
+ end
22
+
@@ -0,0 +1,380 @@
1
+ require 'fileutils'
2
+ require 'yaml'
3
+
4
+ require 'sphincter'
5
+
6
+ ##
7
+ # Configuration module for Sphincter.
8
+ #
9
+ # DEFAULT_CONF contains the default options. They can be overridden in both a
10
+ # global config/sphincter.yml and in a per-environment
11
+ # config/environments/sphincter.RAILS_ENV.yml.
12
+ #
13
+ # The only option you should need to override is the port option of
14
+ # sphincter, so a config file for separate test and development indexes would
15
+ # look like:
16
+ #
17
+ # config/environments/sphincter.development.yml:
18
+ #
19
+ # sphincter:
20
+ # port: 3313
21
+ #
22
+ # config/environments/sphincter.test.yml:
23
+ #
24
+ # sphincter:
25
+ # port: 3314
26
+ #
27
+ # Configuration options:
28
+ #
29
+ # sphincter:: Options for serachd's and Sphinx's port and address, and
30
+ # paths for index files.
31
+ # index:: Options for a sphinx index conf section
32
+ # indexer:: Options for the sphinx indexer
33
+ # mysql:: Options for the sphinx indexer's mysql database connection. The
34
+ # important ones are filled from config/database.yml
35
+ # searchd:: Options for a sphinx searchd conf section
36
+ # source:: Options for a sphinx source conf section
37
+ #
38
+ # The sphincter entry contains:
39
+ #
40
+ # address:: Which host searchd will run on, and which host Sphincter will
41
+ # connect to.
42
+ # port:: Which port searchd and Sphincter will connect to.
43
+ # path:: Location of searchd indexes, relative to RAILS_ROOT.
44
+ # per_page:: How many items to include in a search by default.
45
+ #
46
+ # All other entries are from Sphinx.
47
+ #
48
+ # See http://www.sphinxsearch.com/doc.html#reference for details on sphinx
49
+ # conf file settings.
50
+
51
+ module Sphincter::Configure
52
+
53
+ @env_conf = nil
54
+ @index_count = nil
55
+
56
+ rails_env = defined?(RAILS_ENV) ? RAILS_ENV : 'RAILS_ENV'
57
+
58
+ ##
59
+ # Default Sphincter configuration.
60
+
61
+ DEFAULT_CONF = {
62
+ 'sphincter' => {
63
+ 'address' => '127.0.0.1',
64
+ 'path' => "sphinx/#{rails_env}",
65
+ 'per_page' => 10,
66
+ 'port' => 3312,
67
+ },
68
+
69
+ 'index' => {
70
+ 'charset_type' => 'utf-8',
71
+ 'docinfo' => 'extern',
72
+ 'min_word_len' => 1,
73
+ 'morphology' => 'stem_en',
74
+ 'stopwords' => '',
75
+ },
76
+
77
+ 'indexer' => {
78
+ 'mem_limit' => '32M',
79
+ },
80
+
81
+ 'mysql' => {
82
+ 'sql_query_pre' => [
83
+ 'SET SESSION group_concat_max_len = 65535',
84
+ 'SET NAMES utf8',
85
+ ],
86
+ },
87
+
88
+ 'searchd' => {
89
+ 'log' => "log/sphinx/searchd.#{rails_env}.log",
90
+ 'max_children' => 30,
91
+ 'max_matches' => 1000,
92
+ 'query_log' => "log/sphinx/query.#{rails_env}.log",
93
+ 'read_timeout' => 5,
94
+ },
95
+
96
+ 'source' => {
97
+ 'index_html_attrs' => '',
98
+ 'sql_query_post' => '',
99
+ 'sql_range_step' => 20000,
100
+ 'strip_html' => 0,
101
+ },
102
+ }
103
+
104
+ ##
105
+ # Builds and writes out a sphinx.conf file.
106
+
107
+ def self.configure
108
+ conf = get_conf
109
+ db_conf = get_db_conf
110
+
111
+ db_conf = conf[db_conf['type']].merge db_conf
112
+
113
+ sources = get_sources
114
+
115
+ sources.each do |name, source_conf|
116
+ sources[name] = db_conf.merge source_conf
117
+ end
118
+
119
+ write_configuration conf, sources
120
+ end
121
+
122
+ ##
123
+ # Merges Hashes of Hashes +mergee+ and +hash+.
124
+
125
+ def self.deep_merge(mergee, hash)
126
+ mergee = mergee.dup
127
+ hash.keys.each do |key| mergee[key] ||= hash[key] end
128
+ mergee.each do |key, value|
129
+ next unless hash[key]
130
+ mergee[key] = value.merge hash[key]
131
+ end
132
+ end
133
+
134
+ ##
135
+ # Builds the Sphincter configuration.
136
+ #
137
+ # Automatically fills in searchd address, port and pid_file from 'sphincter'
138
+ # section.
139
+
140
+ def self.get_conf
141
+ return @env_conf unless @env_conf.nil?
142
+
143
+ base_file = File.expand_path File.join(RAILS_ROOT, 'config', 'sphincter.yml')
144
+ base_conf = deep_merge DEFAULT_CONF, get_conf_from(base_file)
145
+
146
+ env_file = File.expand_path File.join(RAILS_ROOT, 'config', 'environments',
147
+ "sphincter.#{RAILS_ENV}.yml")
148
+ env_conf = deep_merge base_conf, get_conf_from(env_file)
149
+
150
+ env_conf['searchd']['address'] = env_conf['sphincter']['address']
151
+ env_conf['searchd']['port'] = env_conf['sphincter']['port']
152
+ env_conf['searchd']['pid_file'] = File.join(env_conf['sphincter']['path'],
153
+ 'searchd.pid')
154
+
155
+ @env_conf = env_conf
156
+ end
157
+
158
+ ##
159
+ # Reads configuration file +file+. Returns {} if the file does not exist.
160
+
161
+ def self.get_conf_from(file)
162
+ if File.exist? file then
163
+ YAML.load File.read(file)
164
+ else
165
+ {}
166
+ end
167
+ end
168
+
169
+ ##
170
+ # Builds a sphinx.conf source configuration for each index.
171
+
172
+ def self.get_sources
173
+ load_models
174
+
175
+ indexes = Sphincter::Search.indexes
176
+ index_count # HACK necessary to set options[:index_id] per-index
177
+
178
+ sources = {}
179
+
180
+ indexes.each do |klass, model_indexes|
181
+ model_indexes.each do |options|
182
+ conn = klass.connection
183
+ table = klass.table_name
184
+ pk = conn.quote_column_name klass.primary_key
185
+ index_id = options[:index_id]
186
+
187
+ source_conf = {}
188
+ source_conf['sql_date_column'] = []
189
+ source_conf['sql_group_column'] = %w[sphincter_index_id]
190
+
191
+ fields = []
192
+ fields << "(#{table}.#{pk} * #{index_count} + #{index_id}) AS #{pk}"
193
+ fields << "#{index_id} AS sphincter_index_id"
194
+ fields << "#{conn.quote table} AS klass"
195
+
196
+ options[:fields].each do |field|
197
+ fields << get_sources_field(source_conf, klass, field)
198
+ end
199
+
200
+ fields = fields.join ', '
201
+
202
+ where = []
203
+ where << "#{table}.#{pk} >= $start AND #{table}.#{pk} <= $end"
204
+ where << options[:conditions]
205
+ where = where.compact.join ' AND '
206
+
207
+ source_conf['sql_query'] =
208
+ "SELECT #{fields} FROM #{table} WHERE #{where}"
209
+ source_conf['sql_query_info'] =
210
+ "SELECT * FROM #{table} " \
211
+ "WHERE #{table}.#{pk} = (($id - #{index_id}) / #{index_count})"
212
+ source_conf['sql_query_range'] =
213
+ "SELECT MIN(#{pk}), MAX(#{pk}) FROM #{table}"
214
+ source_conf['strip_html'] = options[:strip_html] ? 1 : 0
215
+
216
+ name = options[:name] || table
217
+ sources[name] = source_conf
218
+ end
219
+ end
220
+
221
+ sources
222
+ end
223
+
224
+ ##
225
+ # Builds a field for a source's sql_query sphinx.conf setting.
226
+ #
227
+ # get_sources_field only understands :datetime, :boolean, :integer, :string
228
+ # and :text column types.
229
+
230
+ def self.get_sources_field(source_conf, klass, field)
231
+ conn = klass.connection
232
+ table = klass.table_name
233
+
234
+ quoted_field = conn.quote_column_name field
235
+ case klass.columns_hash[field].type
236
+ when :date, :datetime, :time, :timestamp then
237
+ source_conf['sql_date_column'] << field
238
+ "UNIX_TIMESTAMP(#{table}.#{quoted_field}) AS #{quoted_field}"
239
+ when :boolean, :integer then
240
+ source_conf['sql_group_column'] << field
241
+ "#{table}.#{quoted_field} AS #{quoted_field}"
242
+ when :string, :text then
243
+ "#{table}.#{quoted_field} AS #{quoted_field}"
244
+ end
245
+ end
246
+
247
+ ##
248
+ # Retrieves the database configuration for ActiveRecord::Base and adapts it
249
+ # for a sphinx.conf file.
250
+
251
+ def self.get_db_conf
252
+ conf = {}
253
+ ar_conf = ActiveRecord::Base.configurations[::RAILS_ENV]
254
+
255
+ conf['type'] = ar_conf['adapter']
256
+ conf['sql_host'] = ar_conf['host'] if ar_conf.include? 'host'
257
+ conf['sql_user'] = ar_conf['username'] if ar_conf.include? 'username'
258
+ conf['sql_pass'] = ar_conf['password'] if ar_conf.include? 'password'
259
+ conf['sql_db'] = ar_conf['database'] if ar_conf.include? 'database'
260
+ conf['sql_sock'] = ar_conf['socket'] if ar_conf.include? 'socket'
261
+
262
+ conf
263
+ end
264
+
265
+ ##
266
+ # Iterates over the searchable ActiveRecord::Base classes and assigns an
267
+ # index to each one. Returns the total number of indexes found.
268
+
269
+ def self.index_count
270
+ return @index_count unless @index_count.nil?
271
+
272
+ @index_count = 0
273
+
274
+ load_models
275
+
276
+ Sphincter::Search.indexes.each do |model, model_indexes|
277
+ model_indexes.each do |options|
278
+ options[:index_id] = @index_count
279
+ @index_count += 1
280
+ end
281
+ end
282
+ @index_count
283
+ end
284
+
285
+ ##
286
+ # Loads ActiveRecord::Base models from app/models.
287
+
288
+ def self.load_models
289
+ model_files = Dir[File.join(RAILS_ROOT, 'app', 'models', '*.rb')]
290
+ model_names = model_files.map { |name| File.basename name, '.rb' }
291
+ model_names.each { |name| name.camelize.constantize }
292
+ end
293
+
294
+ ##
295
+ # Returns the pid of searchd if searchd is running, otherwise false.
296
+
297
+ def self.searchd_running?
298
+ pid_file = Sphincter::Configure.get_conf['searchd']['pid_file']
299
+ return false unless File.exist? pid_file
300
+
301
+ pid = File.read pid_file
302
+ return false if pid.empty?
303
+
304
+ running = `ps -p #{pid}` =~ /#{pid}.*searchd/
305
+ running ? pid : false
306
+ end
307
+
308
+ ##
309
+ # Outputs a sphinx.conf configuration section titled +heading+ using the
310
+ # Hash +data+. Values in +data+ may be a String or Array. For an Array,
311
+ # the Hash key is printed multiple times.
312
+
313
+ def self.section(heading, data)
314
+ section = []
315
+ section << heading
316
+ section << '{'
317
+ data.sort_by { |k,| k }.each do |key, value|
318
+ case value
319
+ when Array then
320
+ next if value.empty?
321
+ value.each do |v|
322
+ section << " #{key} = #{v}"
323
+ end
324
+ else
325
+ section << " #{key} = #{value}"
326
+ end
327
+ end
328
+ section << '}'
329
+ section.join "\n"
330
+ end
331
+
332
+ ##
333
+ # The path to sphinx.conf.
334
+
335
+ def self.sphinx_conf
336
+ @sphinx_conf ||= File.join sphinx_dir, 'sphinx.conf'
337
+ end
338
+
339
+ ##
340
+ # The directory where sphinx's files live.
341
+
342
+ def self.sphinx_dir
343
+ @sphinx_dir ||= File.join(RAILS_ROOT,
344
+ Sphincter::Configure.get_conf['sphincter']['path'])
345
+ end
346
+
347
+ ##
348
+ # Writes out a sphinx.conf configuration using +conf+ and +sources+.
349
+
350
+ def self.write_configuration(conf, sources)
351
+ FileUtils.mkdir_p sphinx_dir
352
+
353
+ out = []
354
+
355
+ out << section('indexer', conf['indexer'])
356
+ out << nil
357
+
358
+ out << section('searchd', conf['searchd'])
359
+ out << nil
360
+
361
+ sources.each do |index_name, values|
362
+ source_data = conf['source'].merge values
363
+ out << section("source #{index_name}", source_data)
364
+ out << nil
365
+
366
+ index_path = File.join sphinx_dir, index_name
367
+ index_data = conf['index'].merge 'source' => index_name,
368
+ 'path' => index_path
369
+
370
+ out << section("index #{index_name}", index_data)
371
+ out << nil
372
+ end
373
+
374
+ File.open sphinx_conf, 'w' do |fp|
375
+ fp.write out.join("\n")
376
+ end
377
+ end
378
+
379
+ end
380
+