thinking-sphinx 2.0.6 → 2.0.7

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 (50) hide show
  1. data/HISTORY +157 -0
  2. data/lib/cucumber/thinking_sphinx/external_world.rb +12 -0
  3. data/lib/cucumber/thinking_sphinx/internal_world.rb +127 -0
  4. data/lib/cucumber/thinking_sphinx/sql_logger.rb +20 -0
  5. data/lib/thinking-sphinx.rb +1 -0
  6. data/lib/thinking_sphinx/action_controller.rb +31 -0
  7. data/lib/thinking_sphinx/active_record/attribute_updates.rb +53 -0
  8. data/lib/thinking_sphinx/active_record/collection_proxy.rb +40 -0
  9. data/lib/thinking_sphinx/active_record/collection_proxy_with_scopes.rb +27 -0
  10. data/lib/thinking_sphinx/active_record/delta.rb +65 -0
  11. data/lib/thinking_sphinx/active_record/has_many_association.rb +37 -0
  12. data/lib/thinking_sphinx/active_record/has_many_association_with_scopes.rb +21 -0
  13. data/lib/thinking_sphinx/active_record/log_subscriber.rb +61 -0
  14. data/lib/thinking_sphinx/active_record/scopes.rb +110 -0
  15. data/lib/thinking_sphinx/active_record.rb +383 -0
  16. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +87 -0
  17. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +62 -0
  18. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +171 -0
  19. data/lib/thinking_sphinx/association.rb +229 -0
  20. data/lib/thinking_sphinx/attribute.rb +407 -0
  21. data/lib/thinking_sphinx/auto_version.rb +38 -0
  22. data/lib/thinking_sphinx/bundled_search.rb +44 -0
  23. data/lib/thinking_sphinx/class_facet.rb +20 -0
  24. data/lib/thinking_sphinx/configuration.rb +335 -0
  25. data/lib/thinking_sphinx/context.rb +77 -0
  26. data/lib/thinking_sphinx/core/string.rb +15 -0
  27. data/lib/thinking_sphinx/deltas/default_delta.rb +62 -0
  28. data/lib/thinking_sphinx/deltas.rb +28 -0
  29. data/lib/thinking_sphinx/deploy/capistrano.rb +99 -0
  30. data/lib/thinking_sphinx/excerpter.rb +23 -0
  31. data/lib/thinking_sphinx/facet.rb +128 -0
  32. data/lib/thinking_sphinx/facet_search.rb +170 -0
  33. data/lib/thinking_sphinx/field.rb +98 -0
  34. data/lib/thinking_sphinx/index/builder.rb +312 -0
  35. data/lib/thinking_sphinx/index/faux_column.rb +118 -0
  36. data/lib/thinking_sphinx/index.rb +157 -0
  37. data/lib/thinking_sphinx/join.rb +37 -0
  38. data/lib/thinking_sphinx/property.rb +185 -0
  39. data/lib/thinking_sphinx/railtie.rb +46 -0
  40. data/lib/thinking_sphinx/search.rb +995 -0
  41. data/lib/thinking_sphinx/search_methods.rb +439 -0
  42. data/lib/thinking_sphinx/sinatra.rb +7 -0
  43. data/lib/thinking_sphinx/source/internal_properties.rb +51 -0
  44. data/lib/thinking_sphinx/source/sql.rb +157 -0
  45. data/lib/thinking_sphinx/source.rb +194 -0
  46. data/lib/thinking_sphinx/tasks.rb +132 -0
  47. data/lib/thinking_sphinx/test.rb +55 -0
  48. data/lib/thinking_sphinx/version.rb +3 -0
  49. data/lib/thinking_sphinx.rb +296 -0
  50. metadata +53 -4
@@ -0,0 +1,335 @@
1
+ require 'erb'
2
+ require 'singleton'
3
+
4
+ module ThinkingSphinx
5
+ # This class both keeps track of the configuration settings for Sphinx and
6
+ # also generates the resulting file for Sphinx to use.
7
+ #
8
+ # Here are the default settings, relative to Rails.root where relevant:
9
+ #
10
+ # config file:: config/#{environment}.sphinx.conf
11
+ # searchd log file:: log/searchd.log
12
+ # query log file:: log/searchd.query.log
13
+ # pid file:: log/searchd.#{environment}.pid
14
+ # searchd files:: db/sphinx/#{environment}/
15
+ # address:: 127.0.0.1
16
+ # port:: 9312
17
+ # allow star:: false
18
+ # stop timeout:: 5
19
+ # min prefix length:: 1
20
+ # min infix length:: 1
21
+ # mem limit:: 64M
22
+ # max matches:: 1000
23
+ # morphology:: nil
24
+ # charset type:: utf-8
25
+ # charset table:: nil
26
+ # ignore chars:: nil
27
+ # html strip:: false
28
+ # html remove elements:: ''
29
+ # searchd_binary_name:: searchd
30
+ # indexer_binary_name:: indexer
31
+ #
32
+ # If you want to change these settings, create a YAML file at
33
+ # config/sphinx.yml with settings for each environment, in a similar
34
+ # fashion to database.yml - using the following keys: config_file,
35
+ # searchd_log_file, query_log_file, pid_file, searchd_file_path, port,
36
+ # allow_star, enable_star, min_prefix_len, min_infix_len, mem_limit,
37
+ # max_matches, morphology, charset_type, charset_table, ignore_chars,
38
+ # html_strip, html_remove_elements, delayed_job_priority,
39
+ # searchd_binary_name, indexer_binary_name.
40
+ #
41
+ # I think you've got the idea.
42
+ #
43
+ # Each setting in the YAML file is optional - so only put in the ones you
44
+ # want to change.
45
+ #
46
+ # Keep in mind, if for some particular reason you're using a version of
47
+ # Sphinx older than 0.9.8 r871 (that's prior to the proper 0.9.8 release),
48
+ # don't set allow_star to true.
49
+ #
50
+ class Configuration
51
+ include Singleton
52
+
53
+ SourceOptions = Riddle::Configuration::SQLSource.settings.map { |setting|
54
+ setting.to_s
55
+ } - %w( type sql_query_pre sql_query sql_joined_field sql_file_field
56
+ sql_query_range sql_attr_uint sql_attr_bool sql_attr_bigint sql_query_info
57
+ sql_attr_timestamp sql_attr_str2ordinal sql_attr_float sql_attr_multi
58
+ sql_attr_string sql_attr_str2wordcount sql_column_buffers sql_field_string
59
+ sql_field_str2wordcount )
60
+ IndexOptions = Riddle::Configuration::Index.settings.map { |setting|
61
+ setting.to_s
62
+ } - %w( source prefix_fields infix_fields )
63
+ CustomOptions = %w( disable_range use_64_bit )
64
+
65
+ attr_accessor :searchd_file_path, :allow_star, :app_root,
66
+ :model_directories, :delayed_job_priority, :indexed_models, :use_64_bit,
67
+ :touched_reindex_file, :stop_timeout, :version
68
+
69
+ attr_accessor :source_options, :index_options
70
+
71
+ attr_reader :configuration, :controller
72
+
73
+ @@environment = nil
74
+
75
+ # Load in the configuration settings - this will look for config/sphinx.yml
76
+ # and parse it according to the current environment.
77
+ #
78
+ def initialize(app_root = Dir.pwd)
79
+ self.reset
80
+ end
81
+
82
+ def self.configure(&block)
83
+ yield instance
84
+ instance.reset(instance.app_root)
85
+ end
86
+
87
+ def reset(custom_app_root=nil)
88
+ if custom_app_root
89
+ self.app_root = custom_app_root
90
+ else
91
+ self.app_root = Merb.root if defined?(Merb)
92
+ self.app_root = Sinatra::Application.root if defined?(Sinatra)
93
+ self.app_root = Rails.root if defined?(Rails)
94
+ self.app_root ||= app_root
95
+ end
96
+
97
+ @configuration = Riddle::Configuration.new
98
+ @configuration.searchd.pid_file = "#{self.app_root}/log/searchd.#{environment}.pid"
99
+ @configuration.searchd.log = "#{self.app_root}/log/searchd.log"
100
+ @configuration.searchd.query_log = "#{self.app_root}/log/searchd.query.log"
101
+
102
+ @controller = Riddle::Controller.new @configuration,
103
+ "#{self.app_root}/config/#{environment}.sphinx.conf"
104
+
105
+ self.address = "127.0.0.1"
106
+ self.port = 9312
107
+ self.searchd_file_path = "#{self.app_root}/db/sphinx/#{environment}"
108
+ self.allow_star = false
109
+ self.stop_timeout = 5
110
+ self.model_directories = ["#{app_root}/app/models/"] +
111
+ Dir.glob("#{app_root}/vendor/plugins/*/app/models/")
112
+ self.delayed_job_priority = 0
113
+ self.indexed_models = []
114
+
115
+ self.source_options = {}
116
+ self.index_options = {
117
+ :charset_type => "utf-8"
118
+ }
119
+
120
+ self.version = nil
121
+ parse_config
122
+ self.version ||= @controller.sphinx_version
123
+
124
+ self
125
+ end
126
+
127
+ def self.environment
128
+ @@environment ||= if defined?(Merb)
129
+ Merb.environment
130
+ elsif defined?(Rails)
131
+ Rails.env
132
+ elsif defined?(Sinatra)
133
+ Sinatra::Application.environment.to_s
134
+ else
135
+ ENV['RAILS_ENV'] || 'development'
136
+ end
137
+ end
138
+
139
+ def self.reset_environment
140
+ ThinkingSphinx.mutex.synchronize do
141
+ @@environment = nil
142
+ end
143
+ end
144
+
145
+ def environment
146
+ self.class.environment
147
+ end
148
+
149
+ def generate
150
+ @configuration.indexes.clear
151
+
152
+ ThinkingSphinx.context.indexed_models.each do |model|
153
+ model = model.constantize
154
+ model.define_indexes
155
+ @configuration.indexes.concat model.to_riddle
156
+
157
+ enforce_common_attribute_types
158
+ end
159
+ end
160
+
161
+ # Generate the config file for Sphinx by using all the settings defined and
162
+ # looping through all the models with indexes to build the relevant
163
+ # indexer and searchd configuration, and sources and indexes details.
164
+ #
165
+ def build(file_path=nil)
166
+ file_path ||= "#{self.config_file}"
167
+
168
+ generate
169
+
170
+ open(file_path, "w") do |file|
171
+ file.write @configuration.render
172
+ end
173
+ end
174
+
175
+ def address
176
+ @address
177
+ end
178
+
179
+ def address=(address)
180
+ @address = address
181
+ @configuration.searchd.address = address
182
+ end
183
+
184
+ def port
185
+ @port
186
+ end
187
+
188
+ def port=(port)
189
+ @port = port
190
+ @configuration.searchd.port = port
191
+ end
192
+
193
+ def pid_file
194
+ @configuration.searchd.pid_file
195
+ end
196
+
197
+ def pid_file=(pid_file)
198
+ @configuration.searchd.pid_file = pid_file
199
+ end
200
+
201
+ def searchd_log_file
202
+ @configuration.searchd.log
203
+ end
204
+
205
+ def searchd_log_file=(file)
206
+ @configuration.searchd.log = file
207
+ end
208
+
209
+ def query_log_file
210
+ @configuration.searchd.query_log
211
+ end
212
+
213
+ def query_log_file=(file)
214
+ @configuration.searchd.query_log = file
215
+ end
216
+
217
+ def config_file
218
+ @controller.path
219
+ end
220
+
221
+ def config_file=(file)
222
+ @controller.path = file
223
+ end
224
+
225
+ def bin_path
226
+ @controller.bin_path
227
+ end
228
+
229
+ def bin_path=(path)
230
+ @controller.bin_path = path
231
+ end
232
+
233
+ def searchd_binary_name
234
+ @controller.searchd_binary_name
235
+ end
236
+
237
+ def searchd_binary_name=(name)
238
+ @controller.searchd_binary_name = name
239
+ end
240
+
241
+ def indexer_binary_name
242
+ @controller.indexer_binary_name
243
+ end
244
+
245
+ def indexer_binary_name=(name)
246
+ @controller.indexer_binary_name = name
247
+ end
248
+
249
+ attr_accessor :timeout
250
+
251
+ def client
252
+ client = Riddle::Client.new address, port,
253
+ configuration.searchd.client_key
254
+ client.max_matches = configuration.searchd.max_matches || 1000
255
+ client.timeout = timeout || 0
256
+ client
257
+ end
258
+
259
+ def models_by_crc
260
+ @models_by_crc ||= begin
261
+ ThinkingSphinx.context.indexed_models.inject({}) do |hash, model|
262
+ hash[model.constantize.to_crc32] = model
263
+ model.constantize.descendants.each { |subclass|
264
+ hash[subclass.to_crc32] = subclass.name
265
+ }
266
+ hash
267
+ end
268
+ end
269
+ end
270
+
271
+ def touch_reindex_file(output)
272
+ return FileUtils.touch(@touched_reindex_file) if @touched_reindex_file and output =~ /succesfully sent SIGHUP to searchd/
273
+ false
274
+ end
275
+
276
+ private
277
+
278
+ # Parse the config/sphinx.yml file - if it exists - then use the attribute
279
+ # accessors to set the appropriate values. Nothing too clever.
280
+ #
281
+ def parse_config
282
+ path = "#{app_root}/config/sphinx.yml"
283
+ return unless File.exists?(path)
284
+
285
+ conf = YAML::load(ERB.new(IO.read(path)).result)[environment]
286
+
287
+ conf.each do |key,value|
288
+ self.send("#{key}=", value) if self.respond_to?("#{key}=")
289
+
290
+ set_sphinx_setting self.source_options, key, value, SourceOptions
291
+ set_sphinx_setting self.index_options, key, value, IndexOptions
292
+ set_sphinx_setting self.index_options, key, value, CustomOptions
293
+ set_sphinx_setting @configuration.searchd, key, value
294
+ set_sphinx_setting @configuration.indexer, key, value
295
+ end unless conf.nil?
296
+
297
+ self.bin_path += '/' unless self.bin_path.blank?
298
+
299
+ if self.allow_star
300
+ self.index_options[:enable_star] = true
301
+ self.index_options[:min_prefix_len] = 1
302
+ end
303
+ end
304
+
305
+ def set_sphinx_setting(object, key, value, allowed = {})
306
+ if object.is_a?(Hash)
307
+ object[key.to_sym] = value if allowed.include?(key.to_s)
308
+ else
309
+ object.send("#{key}=", value) if object.respond_to?("#{key}")
310
+ send("#{key}=", value) if self.respond_to?("#{key}")
311
+ end
312
+ end
313
+
314
+ def enforce_common_attribute_types
315
+ sql_indexes = configuration.indexes.reject { |index|
316
+ index.is_a? Riddle::Configuration::DistributedIndex
317
+ }
318
+
319
+ return unless sql_indexes.any? { |index|
320
+ index.sources.any? { |source|
321
+ source.sql_attr_bigint.include? :sphinx_internal_id
322
+ }
323
+ }
324
+
325
+ sql_indexes.each { |index|
326
+ index.sources.each { |source|
327
+ next if source.sql_attr_bigint.include? :sphinx_internal_id
328
+
329
+ source.sql_attr_bigint << :sphinx_internal_id
330
+ source.sql_attr_uint.delete :sphinx_internal_id
331
+ }
332
+ }
333
+ end
334
+ end
335
+ end
@@ -0,0 +1,77 @@
1
+ class ThinkingSphinx::Context
2
+ attr_reader :indexed_models
3
+
4
+ def initialize(*models)
5
+ @indexed_models = []
6
+ end
7
+
8
+ def prepare
9
+ ThinkingSphinx::Configuration.instance.indexed_models.each do |model|
10
+ add_indexed_model model
11
+ end
12
+
13
+ return unless indexed_models.empty?
14
+
15
+ load_models
16
+ add_indexed_models
17
+ end
18
+
19
+ def define_indexes
20
+ indexed_models.each { |model|
21
+ model.constantize.define_indexes
22
+ }
23
+ end
24
+
25
+ def add_indexed_model(model)
26
+ model = model.name if model.is_a?(Class)
27
+
28
+ indexed_models << model
29
+ indexed_models.uniq!
30
+ indexed_models.sort!
31
+ end
32
+
33
+ def superclass_indexed_models
34
+ klasses = indexed_models.collect { |name| name.constantize }
35
+ klasses.reject { |klass|
36
+ klass.superclass.ancestors.any? { |ancestor| klasses.include?(ancestor) }
37
+ }.collect { |klass| klass.name }
38
+ end
39
+
40
+ private
41
+
42
+ def add_indexed_models
43
+ ActiveRecord::Base.descendants.each do |klass|
44
+ add_indexed_model klass if klass.has_sphinx_indexes?
45
+ end
46
+ end
47
+
48
+ # Make sure all models are loaded - without reloading any that
49
+ # ActiveRecord::Base is already aware of (otherwise we start to hit some
50
+ # messy dependencies issues).
51
+ #
52
+ def load_models
53
+ ThinkingSphinx::Configuration.instance.model_directories.each do |base|
54
+ Dir["#{base}**/*.rb"].each do |file|
55
+ model_name = file.gsub(/^#{base}([\w_\/\\]+)\.rb/, '\1')
56
+
57
+ next if model_name.nil?
58
+ camelized_model = model_name.camelize
59
+ next if ::ActiveRecord::Base.descendants.detect { |model|
60
+ model.name == camelized_model
61
+ }
62
+
63
+ begin
64
+ camelized_model.constantize
65
+ rescue LoadError
66
+ model_name.gsub!(/.*[\/\\]/, '').nil? ? next : retry
67
+ rescue NameError
68
+ next
69
+ rescue StandardError => err
70
+ STDERR.puts "Warning: Error loading #{file}:"
71
+ STDERR.puts err.message
72
+ STDERR.puts err.backtrace.join("\n"), ''
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,15 @@
1
+ require 'zlib'
2
+
3
+ module ThinkingSphinx
4
+ module Core
5
+ module String
6
+ def to_crc32
7
+ Zlib.crc32 self
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ class String
14
+ include ThinkingSphinx::Core::String
15
+ end
@@ -0,0 +1,62 @@
1
+ module ThinkingSphinx
2
+ module Deltas
3
+ class DefaultDelta
4
+ attr_accessor :column
5
+
6
+ def initialize(index, options)
7
+ @index = index
8
+ @column = options.delete(:delta_column) || :delta
9
+ end
10
+
11
+ def index(model, instance = nil)
12
+ return true unless ThinkingSphinx.updates_enabled? &&
13
+ ThinkingSphinx.deltas_enabled?
14
+ return true if instance && !toggled(instance)
15
+
16
+ update_delta_indexes model
17
+ delete_from_core model, instance if instance
18
+
19
+ true
20
+ end
21
+
22
+ def toggle(instance)
23
+ instance.send "#{@column}=", true
24
+ end
25
+
26
+ def toggled(instance)
27
+ instance.send "#{@column}"
28
+ end
29
+
30
+ def reset_query(model)
31
+ "UPDATE #{model.quoted_table_name} SET " +
32
+ "#{model.connection.quote_column_name(@column.to_s)} = #{adapter.boolean(false)} " +
33
+ "WHERE #{model.connection.quote_column_name(@column.to_s)} = #{adapter.boolean(true)}"
34
+ end
35
+
36
+ def clause(model, toggled)
37
+ "#{model.quoted_table_name}.#{model.connection.quote_column_name(@column.to_s)}" +
38
+ " = #{adapter.boolean(toggled)}"
39
+ end
40
+
41
+ private
42
+
43
+ def update_delta_indexes(model)
44
+ config = ThinkingSphinx::Configuration.instance
45
+ rotate = ThinkingSphinx.sphinx_running? ? "--rotate" : ""
46
+
47
+ output = `#{config.bin_path}#{config.indexer_binary_name} --config "#{config.config_file}" #{rotate} #{model.delta_index_names.join(' ')}`
48
+ puts(output) unless ThinkingSphinx.suppress_delta_output?
49
+ end
50
+
51
+ def delete_from_core(model, instance)
52
+ model.core_index_names.each do |index_name|
53
+ model.delete_in_index index_name, instance.sphinx_document_id
54
+ end
55
+ end
56
+
57
+ def adapter
58
+ @adapter = @index.model.sphinx_database_adapter
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,28 @@
1
+ require 'thinking_sphinx/deltas/default_delta'
2
+
3
+ module ThinkingSphinx
4
+ module Deltas
5
+ def self.parse(index)
6
+ delta_option = index.local_options.delete(:delta)
7
+ case delta_option
8
+ when TrueClass, :default
9
+ DefaultDelta.new index, index.local_options
10
+ when :delayed
11
+ DelayedDelta.new index, index.local_options
12
+ when :datetime
13
+ DatetimeDelta.new index, index.local_options
14
+ when FalseClass, nil
15
+ nil
16
+ else
17
+ if delta_option.is_a?(String)
18
+ delta_option = Kernel.const_get(delta_option)
19
+ end
20
+ if delta_option.ancestors.include?(ThinkingSphinx::Deltas::DefaultDelta)
21
+ delta_option.new index, index.local_options
22
+ else
23
+ raise "Unknown delta type"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,99 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ namespace :thinking_sphinx do
3
+ namespace :install do
4
+ desc <<-DESC
5
+ Install Sphinx by source
6
+
7
+ If Postgres is available, Sphinx will use it.
8
+
9
+ If the variable :thinking_sphinx_configure_args is set, it will
10
+ be passed to the Sphinx configure script. You can use this to
11
+ install Sphinx in a non-standard location:
12
+
13
+ set :thinking_sphinx_configure_args, "--prefix=$HOME/software"
14
+ DESC
15
+
16
+ task :sphinx do
17
+ with_postgres = false
18
+ begin
19
+ run "which pg_config" do |channel, stream, data|
20
+ with_postgres = !(data.nil? || data == "")
21
+ end
22
+ rescue Capistrano::CommandError => e
23
+ puts "Continuing despite error: #{e.message}"
24
+ end
25
+
26
+ args = []
27
+ if with_postgres
28
+ run "pg_config --pkgincludedir" do |channel, stream, data|
29
+ args << "--with-pgsql=#{data}"
30
+ end
31
+ end
32
+ args << fetch(:thinking_sphinx_configure_args, '')
33
+
34
+ commands = <<-CMD
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
+ ./configure #{args.join(" ")}
39
+ make
40
+ #{try_sudo} make install
41
+ rm -rf sphinx-0.9.9 sphinx-0.9.9.tar.gz
42
+ CMD
43
+ run commands.split(/\n\s+/).join(" && ")
44
+ end
45
+
46
+ desc "Install Thinking Sphinx as a gem"
47
+ task :ts do
48
+ run "#{try_sudo} gem install thinking-sphinx"
49
+ end
50
+ end
51
+
52
+ desc "Generate the Sphinx configuration file"
53
+ task :configure do
54
+ rake "thinking_sphinx:configure"
55
+ end
56
+
57
+ desc "Index data"
58
+ task :index do
59
+ rake "thinking_sphinx:index"
60
+ end
61
+
62
+ desc "Start the Sphinx daemon"
63
+ task :start do
64
+ rake "thinking_sphinx:configure thinking_sphinx:start"
65
+ end
66
+
67
+ desc "Stop the Sphinx daemon"
68
+ task :stop do
69
+ rake "thinking_sphinx:configure thinking_sphinx:stop"
70
+ end
71
+
72
+ desc "Stop and then start the Sphinx daemon"
73
+ task :restart do
74
+ rake "thinking_sphinx:configure thinking_sphinx:stop \
75
+ thinking_sphinx:start"
76
+ end
77
+
78
+ desc "Stop, re-index and then start the Sphinx daemon"
79
+ task :rebuild do
80
+ rake "thinking_sphinx:configure thinking_sphinx:stop \
81
+ thinking_sphinx:reindex \
82
+ thinking_sphinx:start"
83
+ end
84
+
85
+ desc "Add the shared folder for sphinx files"
86
+ task :shared_sphinx_folder, :roles => :web do
87
+ rails_env = fetch(:rails_env, "production")
88
+ run "mkdir -p #{shared_path}/sphinx/#{rails_env}"
89
+ end
90
+
91
+ def rake(*tasks)
92
+ rails_env = fetch(:rails_env, "production")
93
+ rake = fetch(:rake, "rake")
94
+ tasks.each do |t|
95
+ run "if [ -d #{release_path} ]; then cd #{release_path}; else cd #{current_path}; fi; #{rake} RAILS_ENV=#{rails_env} #{t}"
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,23 @@
1
+ module ThinkingSphinx
2
+ class Excerpter
3
+ CoreMethods = %w( kind_of? object_id respond_to? respond_to_missing? should
4
+ should_not stub! )
5
+ # Hide most methods, to allow them to be passed through to the instance.
6
+ instance_methods.select { |method|
7
+ method.to_s[/^__/].nil? && !CoreMethods.include?(method.to_s)
8
+ }.each { |method|
9
+ undef_method method
10
+ }
11
+
12
+ def initialize(search, instance)
13
+ @search = search
14
+ @instance = instance
15
+ end
16
+
17
+ def method_missing(method, *args, &block)
18
+ string = @instance.send(method, *args, &block).to_s
19
+
20
+ @search.excerpt_for(string, @instance.class)
21
+ end
22
+ end
23
+ end