erichummel-sunspot_rails 1.2.1a

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 (45) hide show
  1. data/History.txt +51 -0
  2. data/LICENSE +18 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +258 -0
  5. data/Rakefile +18 -0
  6. data/TESTING.md +35 -0
  7. data/TODO +8 -0
  8. data/VERSION.yml +4 -0
  9. data/dev_tasks/rdoc.rake +24 -0
  10. data/dev_tasks/release.rake +4 -0
  11. data/dev_tasks/spec.rake +22 -0
  12. data/dev_tasks/todo.rake +4 -0
  13. data/generators/sunspot/sunspot_generator.rb +9 -0
  14. data/generators/sunspot/templates/sunspot.yml +18 -0
  15. data/install.rb +1 -0
  16. data/lib/generators/sunspot_rails/install/install_generator.rb +13 -0
  17. data/lib/generators/sunspot_rails/install/templates/config/sunspot.yml +17 -0
  18. data/lib/generators/sunspot_rails.rb +9 -0
  19. data/lib/sunspot/rails/adapters.rb +83 -0
  20. data/lib/sunspot/rails/configuration.rb +323 -0
  21. data/lib/sunspot/rails/init.rb +5 -0
  22. data/lib/sunspot/rails/log_subscriber.rb +33 -0
  23. data/lib/sunspot/rails/railtie.rb +36 -0
  24. data/lib/sunspot/rails/railties/controller_runtime.rb +36 -0
  25. data/lib/sunspot/rails/request_lifecycle.rb +36 -0
  26. data/lib/sunspot/rails/searchable.rb +412 -0
  27. data/lib/sunspot/rails/server.rb +173 -0
  28. data/lib/sunspot/rails/solr_instrumentation.rb +21 -0
  29. data/lib/sunspot/rails/solr_logging.rb +63 -0
  30. data/lib/sunspot/rails/spec_helper.rb +26 -0
  31. data/lib/sunspot/rails/stub_session_proxy.rb +88 -0
  32. data/lib/sunspot/rails/tasks.rb +62 -0
  33. data/lib/sunspot/rails/version.rb +5 -0
  34. data/lib/sunspot/rails.rb +59 -0
  35. data/lib/sunspot_rails.rb +12 -0
  36. data/spec/configuration_spec.rb +173 -0
  37. data/spec/model_lifecycle_spec.rb +63 -0
  38. data/spec/model_spec.rb +356 -0
  39. data/spec/request_lifecycle_spec.rb +61 -0
  40. data/spec/schema.rb +27 -0
  41. data/spec/server_spec.rb +37 -0
  42. data/spec/session_spec.rb +24 -0
  43. data/spec/spec_helper.rb +46 -0
  44. data/spec/stub_session_proxy_spec.rb +122 -0
  45. metadata +155 -0
@@ -0,0 +1,412 @@
1
+ module Sunspot #:nodoc:
2
+ module Rails #:nodoc:
3
+ #
4
+ # This module adds Sunspot functionality to ActiveRecord models. As well as
5
+ # providing class and instance methods, it optionally adds lifecycle hooks
6
+ # to automatically add and remove models from the Solr index as they are
7
+ # created and destroyed.
8
+ #
9
+ module Searchable
10
+ class <<self
11
+ def included(base) #:nodoc:
12
+ base.module_eval do
13
+ extend(ActsAsMethods)
14
+ end
15
+ end
16
+ end
17
+
18
+ module ActsAsMethods
19
+ #
20
+ # Makes a class searchable if it is not already, or adds search
21
+ # configuration if it is. Note that the options passed in are only used
22
+ # the first time this method is called for a particular class; so,
23
+ # search should be defined before activating any mixins that extend
24
+ # search configuration.
25
+ #
26
+ # The block passed into this method is evaluated by the
27
+ # <code>Sunspot.setup</code> method. See the Sunspot documentation for
28
+ # complete information on the functionality provided by that method.
29
+ #
30
+ # ==== Options (+options+)
31
+ #
32
+ # :auto_index<Boolean>::
33
+ # Automatically index models in Solr when they are saved.
34
+ # Default: true
35
+ # :auto_remove<Boolean>::
36
+ # Automatically remove models from the Solr index when they are
37
+ # destroyed. <b>Setting this option to +false+ is not recommended
38
+ # </b>(see the README).
39
+ # :ignore_attribute_changes_of<Array>::
40
+ # Define attributes, that should not trigger a reindex of that
41
+ # object. Usual suspects are updated_at or counters.
42
+ # :include<Mixed>::
43
+ # Define default ActiveRecord includes, set this to allow ActiveRecord
44
+ # to load required associations when indexing. See ActiveRecord's
45
+ # documentation on eager-loading for examples on how to set this
46
+ # Default: []
47
+ #
48
+ # ==== Example
49
+ #
50
+ # class Post < ActiveRecord::Base
51
+ # searchable do
52
+ # text :title, :body
53
+ # string :sort_title do
54
+ # title.downcase.sub(/^(an?|the)/, '')
55
+ # end
56
+ # integer :blog_id
57
+ # time :updated_at
58
+ # end
59
+ # end
60
+ #
61
+ def searchable(options = {}, &block)
62
+ Sunspot.setup(self, &block)
63
+
64
+ if searchable?
65
+ sunspot_options[:include].concat(Util::Array(options[:include]))
66
+ else
67
+ extend ClassMethods
68
+ include InstanceMethods
69
+
70
+ class_attribute :sunspot_options
71
+
72
+ unless options[:auto_index] == false
73
+ before_save :maybe_mark_for_auto_indexing
74
+ after_save :maybe_auto_index
75
+ end
76
+
77
+ unless options[:auto_remove] == false
78
+ after_destroy do |searchable|
79
+ searchable.remove_from_index
80
+ end
81
+ end
82
+ options[:include] = Util::Array(options[:include])
83
+
84
+ self.sunspot_options = options
85
+ end
86
+ end
87
+
88
+ #
89
+ # This method is defined on all ActiveRecord::Base subclasses. It
90
+ # is false for classes on which #searchable has not been called, and
91
+ # true for classes on which #searchable has been called.
92
+ #
93
+ # ==== Returns
94
+ #
95
+ # +false+
96
+ #
97
+ def searchable?
98
+ false
99
+ end
100
+ end
101
+
102
+ module ClassMethods
103
+ def self.extended(base) #:nodoc:
104
+ class <<base
105
+ alias_method :search, :solr_search unless method_defined? :search
106
+ alias_method :search_ids, :solr_search_ids unless method_defined? :search_ids
107
+ alias_method :remove_all_from_index, :solr_remove_all_from_index unless method_defined? :remove_all_from_index
108
+ alias_method :remove_all_from_index!, :solr_remove_all_from_index! unless method_defined? :remove_all_from_index!
109
+ alias_method :reindex, :solr_reindex unless method_defined? :reindex
110
+ alias_method :index, :solr_index unless method_defined? :index
111
+ alias_method :index_orphans, :solr_index_orphans unless method_defined? :index_orphans
112
+ alias_method :clean_index_orphans, :solr_clean_index_orphans unless method_defined? :clean_index_orphans
113
+ end
114
+ end
115
+ #
116
+ # Search for instances of this class in Solr. The block is delegated to
117
+ # the Sunspot.search method - see the Sunspot documentation for the full
118
+ # API.
119
+ #
120
+ # ==== Example
121
+ #
122
+ # Post.search(:include => [:blog]) do
123
+ # keywords 'best pizza'
124
+ # with :blog_id, 1
125
+ # order :updated_at, :desc
126
+ # facet :category_ids
127
+ # end
128
+ #
129
+ # ==== Options
130
+ #
131
+ # :include:: Specify associations to eager load
132
+ # :select:: Specify columns to select from database when loading results
133
+ #
134
+ # ==== Returns
135
+ #
136
+ # Sunspot::Search:: Object containing results, totals, facets, etc.
137
+ #
138
+ def solr_search(options = {}, &block)
139
+ solr_execute_search(options) do
140
+ Sunspot.new_search(self, &block)
141
+ end
142
+ end
143
+
144
+ #
145
+ # Get IDs of matching results without loading the result objects from
146
+ # the database. This method may be useful if search is used as an
147
+ # intermediate step in a larger find operation. The block is the same
148
+ # as the block provided to the #search method.
149
+ #
150
+ # ==== Returns
151
+ #
152
+ # Array:: Array of IDs, in the order returned by the search
153
+ #
154
+ def solr_search_ids(&block)
155
+ solr_execute_search_ids do
156
+ solr_search(&block)
157
+ end
158
+ end
159
+
160
+ #
161
+ # Remove instances of this class from the Solr index.
162
+ #
163
+ def solr_remove_all_from_index
164
+ Sunspot.remove_all(self)
165
+ end
166
+
167
+ #
168
+ # Remove all instances of this class from the Solr index and immediately
169
+ # commit.
170
+ #
171
+ #
172
+ def solr_remove_all_from_index!
173
+ Sunspot.remove_all!(self)
174
+ end
175
+
176
+ #
177
+ # Completely rebuild the index for this class. First removes all
178
+ # instances from the index, then loads records and indexes them.
179
+ #
180
+ # See #index for information on options, etc.
181
+ #
182
+ def solr_reindex(options = {})
183
+ solr_remove_all_from_index
184
+ solr_index(options)
185
+ end
186
+
187
+ #
188
+ # Add/update all existing records in the Solr index. The
189
+ # +batch_size+ argument specifies how many records to load out of the
190
+ # database at a time. The default batch size is 50; if nil is passed,
191
+ # records will not be indexed in batches. By default, a commit is issued
192
+ # after each batch; passing +false+ for +batch_commit+ will disable
193
+ # this, and only issue a commit at the end of the process. If associated
194
+ # objects need to indexed also, you can specify +include+ in format
195
+ # accepted by ActiveRecord to improve your sql select performance
196
+ #
197
+ # ==== Options (passed as a hash)
198
+ #
199
+ # batch_size<Integer>:: Batch size with which to load records. Passing
200
+ # 'nil' will skip batches. Default is 50.
201
+ # batch_commit<Boolean>:: Flag signalling if a commit should be done after
202
+ # after each batch is indexed, default is 'true'
203
+ # include<Mixed>:: include option to be passed to the ActiveRecord find,
204
+ # used for including associated objects that need to be
205
+ # indexed with the parent object, accepts all formats
206
+ # ActiveRecord::Base.find does
207
+ # first_id:: The lowest possible ID for this class. Defaults to 0, which
208
+ # is fine for integer IDs; string primary keys will need to
209
+ # specify something reasonable here.
210
+ #
211
+ # ==== Examples
212
+ #
213
+ # # index in batches of 50, commit after each
214
+ # Post.index
215
+ #
216
+ # # index all rows at once, then commit
217
+ # Post.index(:batch_size => nil)
218
+ #
219
+ # # index in batches of 50, commit when all batches complete
220
+ # Post.index(:batch_commit => false)
221
+ #
222
+ # # include the associated +author+ object when loading to index
223
+ # Post.index(:include => :author)
224
+ #
225
+ def solr_index(opts={})
226
+ options = {
227
+ :batch_size => 50,
228
+ :batch_commit => true,
229
+ :include => self.sunspot_options[:include],
230
+ :first_id => 0
231
+ }.merge(opts)
232
+
233
+ if options[:batch_size]
234
+ counter = 0
235
+ find_in_batches(:include => options[:include], :batch_size => options[:batch_size]) do |records|
236
+ solr_benchmark options[:batch_size], counter do
237
+ Sunspot.index(records)
238
+ end
239
+ Sunspot.commit if options[:batch_commit]
240
+ counter += 1
241
+ end
242
+ Sunspot.commit unless options[:batch_commit]
243
+ else
244
+ Sunspot.index!(all(:include => options[:include]))
245
+ end
246
+ end
247
+
248
+ #
249
+ # Return the IDs of records of this class that are indexed in Solr but
250
+ # do not exist in the database. Under normal circumstances, this should
251
+ # never happen, but this method is provided in case something goes
252
+ # wrong. Usually you will want to rectify the situation by calling
253
+ # #clean_index_orphans or #reindex
254
+ #
255
+ # ==== Returns
256
+ #
257
+ # Array:: Collection of IDs that exist in Solr but not in the database
258
+ def solr_index_orphans
259
+ count = self.count
260
+ indexed_ids = solr_search_ids { paginate(:page => 1, :per_page => count) }.to_set
261
+ all(:select => 'id').each do |object|
262
+ indexed_ids.delete(object.id)
263
+ end
264
+ indexed_ids.to_a
265
+ end
266
+
267
+ #
268
+ # Find IDs of records of this class that are indexed in Solr but do not
269
+ # exist in the database, and remove them from Solr. Under normal
270
+ # circumstances, this should not be necessary; this method is provided
271
+ # in case something goes wrong.
272
+ #
273
+ def solr_clean_index_orphans
274
+ solr_index_orphans.each do |id|
275
+ new do |fake_instance|
276
+ fake_instance.id = id
277
+ end.solr_remove_from_index
278
+ end
279
+ end
280
+
281
+ #
282
+ # Classes that have been defined as searchable return +true+ for this
283
+ # method.
284
+ #
285
+ # ==== Returns
286
+ #
287
+ # +true+
288
+ #
289
+ def searchable?
290
+ true
291
+ end
292
+
293
+ def solr_execute_search(options = {})
294
+ options.assert_valid_keys(:include, :select)
295
+ search = yield
296
+ unless options.empty?
297
+ search.build do |query|
298
+ if options[:include]
299
+ query.data_accessor_for(self).include = options[:include]
300
+ end
301
+ if options[:select]
302
+ query.data_accessor_for(self).select = options[:select]
303
+ end
304
+ end
305
+ end
306
+ search.execute
307
+ end
308
+
309
+ def solr_execute_search_ids(options = {})
310
+ search = yield
311
+ search.raw_results.map { |raw_result| raw_result.primary_key.to_i }
312
+ end
313
+
314
+ protected
315
+
316
+ #
317
+ # Does some logging for benchmarking indexing performance
318
+ #
319
+ def solr_benchmark(batch_size, counter, &block)
320
+ start = Time.now
321
+ logger.info("[#{Time.now}] Start Indexing")
322
+ yield
323
+ elapsed = Time.now-start
324
+ logger.info("[#{Time.now}] Completed Indexing. Rows indexed #{counter * batch_size}. Rows/sec: #{batch_size/elapsed.to_f} (Elapsed: #{elapsed} sec.)")
325
+ end
326
+
327
+ end
328
+
329
+ module InstanceMethods
330
+ def self.included(base) #:nodoc:
331
+ base.module_eval do
332
+ alias_method :index, :solr_index unless method_defined? :index
333
+ alias_method :index!, :solr_index! unless method_defined? :index!
334
+ alias_method :remove_from_index, :solr_remove_from_index unless method_defined? :remove_from_index
335
+ alias_method :remove_from_index!, :solr_remove_from_index! unless method_defined? :remove_from_index!
336
+ alias_method :more_like_this, :solr_more_like_this unless method_defined? :more_like_this
337
+ alias_method :more_like_this_ids, :solr_more_like_this_ids unless method_defined? :more_like_this_ids
338
+ end
339
+ end
340
+ #
341
+ # Index the model in Solr. If the model is already indexed, it will be
342
+ # updated. Using the defaults, you will usually not need to call this
343
+ # method, as models are indexed automatically when they are created or
344
+ # updated. If you have disabled automatic indexing (see
345
+ # ClassMethods#searchable), this method allows you to manage indexing
346
+ # manually.
347
+ #
348
+ def solr_index
349
+ Sunspot.index(self)
350
+ end
351
+
352
+ #
353
+ # Index the model in Solr and immediately commit. See #index
354
+ #
355
+ def solr_index!
356
+ Sunspot.index!(self)
357
+ end
358
+
359
+ #
360
+ # Remove the model from the Solr index. Using the defaults, this should
361
+ # not be necessary, as models will automatically be removed from the
362
+ # index when they are destroyed. If you disable automatic removal
363
+ # (which is not recommended!), you can use this method to manage removal
364
+ # manually.
365
+ #
366
+ def solr_remove_from_index
367
+ Sunspot.remove(self)
368
+ end
369
+
370
+ #
371
+ # Remove the model from the Solr index and commit immediately. See
372
+ # #remove_from_index
373
+ #
374
+ def solr_remove_from_index!
375
+ Sunspot.remove!(self)
376
+ end
377
+
378
+ def solr_more_like_this(*args, &block)
379
+ options = args.extract_options!
380
+ self.class.solr_execute_search(options) do
381
+ Sunspot.new_more_like_this(self, *args, &block)
382
+ end
383
+ end
384
+
385
+ def solr_more_like_this_ids(&block)
386
+ self.class.solr_execute_search_ids do
387
+ solr_more_like_this(&block)
388
+ end
389
+ end
390
+
391
+ private
392
+
393
+ def maybe_mark_for_auto_indexing
394
+ @marked_for_auto_indexing =
395
+ if !new_record? && ignore_attributes = self.class.sunspot_options[:ignore_attribute_changes_of]
396
+ @marked_for_auto_indexing = !(changed.map { |attr| attr.to_sym } - ignore_attributes).blank?
397
+ else
398
+ true
399
+ end
400
+ true
401
+ end
402
+
403
+ def maybe_auto_index
404
+ if @marked_for_auto_indexing
405
+ solr_index
406
+ remove_instance_variable(:@marked_for_auto_indexing)
407
+ end
408
+ end
409
+ end
410
+ end
411
+ end
412
+ end
@@ -0,0 +1,173 @@
1
+ module Sunspot
2
+ module Rails
3
+ class Server < Sunspot::Server
4
+ # ActiveSupport log levels are integers; this array maps them to the
5
+ # appropriate java.util.logging.Level constant
6
+ LOG_LEVELS = %w(FINE INFO WARNING SEVERE SEVERE INFO)
7
+
8
+ def start
9
+ bootstrap
10
+ super
11
+ end
12
+
13
+ def run
14
+ bootstrap
15
+ super
16
+ end
17
+
18
+ #
19
+ # Bootstrap a new solr_home by creating all required
20
+ # directories.
21
+ #
22
+ # ==== Returns
23
+ #
24
+ # Boolean:: success
25
+ #
26
+ def bootstrap
27
+ unless @bootstrapped
28
+ install_solr_home
29
+ @bootstrapped = true
30
+ end
31
+ end
32
+
33
+ #
34
+ # Directory to store custom libraries for solr
35
+ #
36
+ def lib_path
37
+ File.join( solr_home, 'lib' )
38
+ end
39
+
40
+ #
41
+ # Directory in which to store PID files
42
+ #
43
+ def pid_dir
44
+ configuration.pid_dir || File.join(::Rails.root, 'tmp', 'pids')
45
+ end
46
+
47
+ #
48
+ # Name of the PID file
49
+ #
50
+ def pid_file
51
+ "sunspot-solr-#{::Rails.env}.pid"
52
+ end
53
+
54
+ #
55
+ # Directory to store lucene index data files
56
+ #
57
+ # ==== Returns
58
+ #
59
+ # String:: data_path
60
+ #
61
+ def solr_data_dir
62
+ File.join(solr_home, 'data', ::Rails.env)
63
+ end
64
+
65
+ #
66
+ # Directory to use for Solr home.
67
+ #
68
+ def solr_home
69
+ File.join(configuration.solr_home)
70
+ end
71
+
72
+ #
73
+ # Solr start jar
74
+ #
75
+ def solr_jar
76
+ configuration.solr_jar || super
77
+ end
78
+
79
+ #
80
+ # Port on which to run Solr
81
+ #
82
+ def port
83
+ configuration.port
84
+ end
85
+
86
+ #
87
+ # Severity level for logging. This is based on the severity level for the
88
+ # Rails logger.
89
+ #
90
+ def log_level
91
+ LOG_LEVELS[::Rails.logger.level]
92
+ end
93
+
94
+ #
95
+ # Log file for Solr. File is in the rails log/ directory.
96
+ #
97
+ def log_file
98
+ File.join(::Rails.root, 'log', "sunspot-solr-#{::Rails.env}.log")
99
+ end
100
+
101
+ #
102
+ # Minimum Java heap size for Solr
103
+ #
104
+ def min_memory
105
+ configuration.min_memory
106
+ end
107
+
108
+ #
109
+ # Maximum Java heap size for Solr
110
+ #
111
+ def max_memory
112
+ configuration.max_memory
113
+ end
114
+
115
+ private
116
+
117
+ #
118
+ # access to the Sunspot::Rails::Configuration, defined in
119
+ # sunspot.yml. Use Sunspot::Rails.configuration if you want
120
+ # to access the configuration directly.
121
+ #
122
+ # ==== returns
123
+ #
124
+ # Sunspot::Rails::Configuration:: configuration
125
+ #
126
+ def configuration
127
+ Sunspot::Rails.configuration
128
+ end
129
+
130
+ #
131
+ # Directory to store solr config files
132
+ #
133
+ # ==== Returns
134
+ #
135
+ # String:: config_path
136
+ #
137
+ def config_path
138
+ File.join(solr_home, 'conf')
139
+ end
140
+
141
+ #
142
+ # Copy default solr configuration files from sunspot
143
+ # gem to the new solr_home/config directory
144
+ #
145
+ # ==== Returns
146
+ #
147
+ # Boolean:: success
148
+ #
149
+ def install_solr_home
150
+ unless File.exists?(solr_home)
151
+ Sunspot::Installer.execute(
152
+ solr_home,
153
+ :force => true,
154
+ :verbose => true
155
+ )
156
+ end
157
+ end
158
+
159
+ #
160
+ # Create new solr_home, config, log and pid directories
161
+ #
162
+ # ==== Returns
163
+ #
164
+ # Boolean:: success
165
+ #
166
+ def create_solr_directories
167
+ [solr_data_dir, pid_dir].each do |path|
168
+ FileUtils.mkdir_p( path )
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,21 @@
1
+ module Sunspot
2
+ module Rails
3
+ module SolrInstrumentation
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ alias_method :request_without_as_instrumentation, :request
8
+ alias_method :request, :request_with_as_instrumentation
9
+ end
10
+
11
+ module InstanceMethods
12
+ def request_with_as_instrumentation(path, params={}, *extra)
13
+ ActiveSupport::Notifications.instrument("request.rsolr",
14
+ {:path => path, :parameters => params}) do
15
+ request_without_as_instrumentation(path, params, *extra)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,63 @@
1
+ module Sunspot
2
+ module Rails
3
+ module SolrLogging
4
+ class <<self
5
+ def included(base)
6
+ base.module_eval { alias_method_chain(:request, :rails_logging) }
7
+ end
8
+ end
9
+
10
+ def request_with_rails_logging(path, params={}, *extra)
11
+
12
+ # Set up logging text.
13
+ body = (params.nil? || params.empty?) ? extra.first : params.inspect
14
+ action = path[1..-1].capitalize
15
+ if body == "<commit/>"
16
+ action = 'Commit'
17
+ body = ''
18
+ end
19
+ body = body[0, 800] + '...' if body.length > 800
20
+
21
+ # Make request and log.
22
+ response = nil
23
+ begin
24
+ ms = Benchmark.ms do
25
+ response = request_without_rails_logging(path, params, *extra)
26
+ end
27
+ log_name = 'Solr %s (%.1fms)' % [action, ms]
28
+ ::Rails.logger.debug(format_log_entry(log_name, body))
29
+ rescue Exception => e
30
+ log_name = 'Solr %s (Error)' % [action]
31
+ ::Rails.logger.error(format_log_entry(log_name, body))
32
+ raise e
33
+ end
34
+
35
+ response
36
+ end
37
+
38
+ private
39
+
40
+ def format_log_entry(message, dump = nil)
41
+ @colorize_logging ||= begin
42
+ ::Rails.application.config.colorize_logging # Rails 3
43
+ rescue NoMethodError
44
+ ActiveRecord::Base.colorize_logging # Rails 2
45
+ end
46
+ if @colorize_logging
47
+ message_color, dump_color = "4;32;1", "0;1"
48
+ log_entry = " \e[#{message_color}m#{message}\e[0m "
49
+ log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
50
+ log_entry
51
+ else
52
+ "%s %s" % [message, dump]
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ begin
60
+ RSolr::Client.module_eval { include(Sunspot::Rails::SolrLogging) }
61
+ rescue NameError # RSolr 0.9.6
62
+ RSolr::Connection::Base.module_eval { include(Sunspot::Rails::SolrLogging) }
63
+ end
@@ -0,0 +1,26 @@
1
+ module Sunspot
2
+ module Rails
3
+ module SpecHelper
4
+ def disconnect_sunspot
5
+ before(:each) do
6
+ Sunspot.session = StubSessionProxy.new(Sunspot.session)
7
+ end
8
+
9
+ after(:each) do
10
+ Sunspot.session = Sunspot.session.original_session
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ rspec =
18
+ begin
19
+ RSpec
20
+ rescue NameError, ArgumentError
21
+ Spec::Runner
22
+ end
23
+
24
+ rspec.configure do |config|
25
+ config.extend(Sunspot::Rails::SpecHelper)
26
+ end