sunspot_rails 0.11.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,15 @@
1
+ == 1.0.0
2
+ * Sunspot::Rails::Server subclasses Sunspot::Server; no longer needs to shell out
3
+ * Use Sunspot built-in session proxies in Sunspot::Rails
4
+ * Sunspot::Rails adapter compatible with assumed inconsistency
5
+ * Use session proxy for disconnecting Sunspot in specs
6
+ * Allow specification of first ID for reindex batches.
7
+ * Log Solr requests in Rails logger
8
+ * Use class_inheritable_hash for sunspot_options
9
+ * Add `index` class method, which is like `reindex` but doesn't clear first
10
+ * Rename sunspot:solr:reindex to sunspot:reindex
11
+ * Use Sunspot::Installer to bootstrap Rails Solr home
12
+
1
13
  == 0.10.7
2
14
  * Added Sunspot::Rails::Server class to start/stop/run/bootstrap the solr server
3
15
  * Added log_level key to sunspot.yml, see java docs for valid values (http://java.sun.com/j2se/1.5.0/docs/api/java/util/logging/Level.html)
data/README.rdoc CHANGED
@@ -206,31 +206,24 @@ used as intended.
206
206
 
207
207
  == Testing Solr integration using RSpec
208
208
 
209
- To disable the sunspot-solr integration for your active record models, add the
210
- following line to your spec_helper.rb
209
+ To disable the sunspot-solr integration for your active record models, require
210
+ the file `sunspot/rails/spec_helper`
211
211
 
212
- require 'sunspot/spec/extension'
212
+ Then, in your spec, use the #disconnect_sunspot method:
213
213
 
214
- This will disable all automatic after_save/after_destroy solr-requests generated
215
- via the #searchable method. This will not disable/mock explicit calls in your code.
214
+ require 'sunspot/rails/spec_helper'
216
215
 
217
- If you want to test the sunspot-solr integration with active record, you can
218
- reenable the after_save/after_destroy hooks by adding 'integrate_sunspot' in your
219
- examples.
220
-
221
- describe Searches do
222
- integrate_sunspot
223
-
224
- before(:each) do
225
- @movie = Factory.create :movie
226
- end
216
+ describe Post do
217
+ disconnect_sunspot
227
218
 
228
- it "should find a movie" do
229
- Movie.search { keywords @movie.title }.first.should == @movie
219
+ it 'should have some behavior'
220
+ # ...
230
221
  end
231
222
  end
232
223
 
233
-
224
+ In all of the examples in this group, all Sunspot calls will be stubbed out. The
225
+ Sunspot#search method will return a stub search object that mimics a search with
226
+ no results.
234
227
 
235
228
  == Further Reading
236
229
 
@@ -254,6 +247,7 @@ http://outoftime.lighthouseapp.com/projects/20339-sunspot
254
247
  - Benjamin Krause (bk@benjaminkrause.com)
255
248
  - Adam Salter (adam@codebright.net)
256
249
  - Brandon Keepers (brandon@opensoul.org)
250
+ - Paul Canavese (paul@canavese.org)
257
251
 
258
252
  == License
259
253
 
data/TODO CHANGED
@@ -1,4 +1,4 @@
1
- * Session proxy should give access to config
1
+ * Delegate new_search method
2
2
  =======
3
3
  * Fix final status output for reindex
4
4
  * Add batch-per-request option
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 4
3
+ :major: 0
4
+ :minor: 11
@@ -1,7 +1,8 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'sunspot', 'lib', 'sunspot', 'gem_tasks')
2
- require File.join(File.dirname(__FILE__), '..', 'lib', 'sunspot', 'rails', 'version')
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'tools', 'gem_tasks')
3
2
 
4
3
  Sunspot::GemTasks.new do |s|
4
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'sunspot', 'rails', 'version')
5
+
5
6
  s.name = 'sunspot_rails'
6
7
  s.version = Sunspot::Rails::VERSION
7
8
  s.summary = 'Rails integration for the Sunspot Solr search library'
@@ -15,21 +16,19 @@ running a Sunspot-compatible Solr instance for development and test
15
16
  environments, and automatically commit Solr index changes at the end of each
16
17
  Rails request.
17
18
  TEXT
18
- s.authors = ['Mat Brown', 'Peer Allan', 'Michael Moen', 'Benjamin Krause']
19
+ s.authors = ['Mat Brown', 'Peer Allan', 'Michael Moen', 'Benjamin Krause', 'Adam Salter', 'Brandon Keepers', 'Paul Canavese']
19
20
  s.rubyforge_project = 'sunspot'
20
21
  s.files = FileList['[A-Z]*',
21
- '{lib,tasks,dev_tasks}/**/*',
22
- 'generators/**/*',
23
- 'install.rb',
24
- 'MIT-LICENSE',
25
- 'rails/*',
26
- 'spec/*.rb',
27
- 'spec/mock_app/{app,lib,db,vendor,config}/**/*',
28
- 'spec/mock_app/{tmp,log,solr}']
22
+ '{lib,tasks,dev_tasks}/**/*',
23
+ 'generators/**/*',
24
+ 'install.rb',
25
+ 'MIT-LICENSE',
26
+ 'rails/*',
27
+ 'spec/*.rb',
28
+ 'spec/mock_app/{app,lib,db,vendor,config}/**/*',
29
+ 'spec/mock_app/{tmp,log,solr}']
29
30
  s.add_dependency 'escape', '>= 0.0.4'
30
- s.add_dependency 'sunspot', '>= 0.10.6', '<= 0.10.8'
31
+ s.add_dependency 'sunspot', Sunspot::Rails::VERSION
31
32
  s.add_development_dependency 'rspec', '~> 1.2'
32
33
  s.add_development_dependency 'rspec-rails', '~> 1.2'
33
- s.add_development_dependency 'ruby-debug', '~> 0.10'
34
- s.add_development_dependency 'technicalpickles-jeweler', '~> 1.0'
35
34
  end
@@ -47,7 +47,7 @@ module Sunspot #:nodoc:
47
47
  # ActiveRecord::Base:: ActiveRecord model
48
48
  #
49
49
  def load(id)
50
- @clazz.find(id.to_i, options_for_find)
50
+ @clazz.find_by_id(id.to_i, options_for_find)
51
51
  end
52
52
 
53
53
  #
@@ -62,7 +62,7 @@ module Sunspot #:nodoc:
62
62
  # Array:: Collection of ActiveRecord models
63
63
  #
64
64
  def load_all(ids)
65
- @clazz.find(ids.map { |id| id.to_i }, options_for_find)
65
+ @clazz.find_all_by_id(ids.map { |id| id.to_i }, options_for_find)
66
66
  end
67
67
 
68
68
  private
@@ -36,7 +36,7 @@ module Sunspot #:nodoc:
36
36
  # </b>(see the README).
37
37
  # :ignore_attribute_changes_of<Array>::
38
38
  # Define attributes, that should not trigger a reindex of that
39
- # object. Usual suspects are update_at or counters.
39
+ # object. Usual suspects are updated_at or counters.
40
40
  #
41
41
  # ==== Example
42
42
  #
@@ -57,13 +57,12 @@ module Sunspot #:nodoc:
57
57
  unless searchable?
58
58
  extend ClassMethods
59
59
  include InstanceMethods
60
-
61
- Sunspot::Rails::Util.sunspot_options[self.to_s.underscore.to_sym] = options
60
+
61
+ class_inheritable_hash :sunspot_options
62
62
 
63
63
  unless options[:auto_index] == false
64
- after_save do |searchable|
65
- searchable.index if Sunspot::Rails::Util.index_relevant_attribute_changed?( searchable )
66
- end
64
+ before_save :maybe_mark_for_auto_indexing
65
+ after_save :maybe_auto_index
67
66
  end
68
67
 
69
68
  unless options[:auto_remove] == false
@@ -72,6 +71,7 @@ module Sunspot #:nodoc:
72
71
  end
73
72
  end
74
73
  end
74
+ self.sunspot_options = options
75
75
  end
76
76
 
77
77
  #
@@ -137,17 +137,24 @@ module Sunspot #:nodoc:
137
137
  # Remove all instances of this class from the Solr index and immediately
138
138
  # commit.
139
139
  #
140
- #---
141
- # XXX Sunspot should implement remove_all!()
142
140
  #
143
141
  def remove_all_from_index!
144
- remove_all_from_index
145
- Sunspot.commit
142
+ Sunspot.remove_all!(self)
146
143
  end
147
144
 
148
145
  #
149
146
  # Completely rebuild the index for this class. First removes all
150
- # instances from the index, then loads records and save them. The
147
+ # instances from the index, then loads records and indexes them.
148
+ #
149
+ # See #index for information on options, etc.
150
+ #
151
+ def reindex(options = {})
152
+ remove_all_from_index
153
+ index(options)
154
+ end
155
+
156
+ #
157
+ # Add/update all existing records in the Solr index. The
151
158
  # +batch_size+ argument specifies how many records to load out of the
152
159
  # database at a time. The default batch size is 500; if nil is passed,
153
160
  # records will not be indexed in batches. By default, a commit is issued
@@ -166,31 +173,33 @@ module Sunspot #:nodoc:
166
173
  # used for including associated objects that need to be
167
174
  # indexed with the parent object, accepts all formats
168
175
  # ActiveRecord::Base.find does
176
+ # first_id:: The lowest possible ID for this class. Defaults to 0, which
177
+ # is fine for integer IDs; string primary keys will need to
178
+ # specify something reasonable here.
169
179
  #
170
180
  # ==== Examples
171
181
  #
172
- # # reindex in batches of 500, commit after each
173
- # Post.reindex
182
+ # # index in batches of 500, commit after each
183
+ # Post.index
174
184
  #
175
185
  # # index all rows at once, then commit
176
- # Post.reindex(:batch_size => nil)
186
+ # Post.index(:batch_size => nil)
177
187
  #
178
- # # reindex in batches of 500, commit when all batches complete
179
- # Post.reindex(:batch_commit => false)
188
+ # # index in batches of 500, commit when all batches complete
189
+ # Post.index(:batch_commit => false)
180
190
  #
181
191
  # # include the associated +author+ object when loading to index
182
- # Post.reindex(:include => :author)
192
+ # Post.index(:include => :author)
183
193
  #
184
- def reindex(opts={})
185
- options = { :batch_size => 500, :batch_commit => true, :include => []}.merge(opts)
186
- remove_all_from_index
194
+ def index(opts={})
195
+ options = { :batch_size => 500, :batch_commit => true, :include => [], :first_id => 0}.merge(opts)
187
196
  unless options[:batch_size]
188
197
  Sunspot.index!(all(:include => options[:include]))
189
198
  else
190
199
  offset = 0
191
200
  counter = 1
192
201
  record_count = count
193
- last_id = 0
202
+ last_id = options[:first_id]
194
203
  while(offset < record_count)
195
204
  benchmark options[:batch_size], counter do
196
205
  records = all(:include => options[:include], :conditions => ["#{table_name}.#{primary_key} > ?", last_id], :limit => options[:batch_size], :order => primary_key)
@@ -303,6 +312,25 @@ module Sunspot #:nodoc:
303
312
  def remove_from_index!
304
313
  Sunspot.remove!(self)
305
314
  end
315
+
316
+ private
317
+
318
+ def maybe_mark_for_auto_indexing
319
+ @marked_for_auto_indexing =
320
+ if !new_record? && ignore_attributes = self.class.sunspot_options[:ignore_attribute_changes_of]
321
+ @marked_for_auto_indexing = !(changed.map { |attr| attr.to_sym } - ignore_attributes).blank?
322
+ else
323
+ true
324
+ end
325
+ true
326
+ end
327
+
328
+ def maybe_auto_index
329
+ if @marked_for_auto_indexing
330
+ index
331
+ remove_instance_variable(:@marked_for_auto_indexing)
332
+ end
333
+ end
306
334
  end
307
335
  end
308
336
  end
@@ -1,229 +1,152 @@
1
- require 'escape'
2
-
3
- module Sunspot #:nodoc:
4
- module Rails #:nodoc:
5
- # The Sunspot::Rails::Server class is a simple wrapper around
6
- # the start/stop scripts for solr.
7
- class Server
8
-
9
- class << self
10
- delegate :log_file, :log_level, :port, :solr_home, :to => :configuration
11
-
12
- # Name of the sunspot executable (shell script)
13
- SUNSPOT_EXECUTABLE = (RUBY_PLATFORM =~ /w(in)?32$/ ? 'sunspot-solr.bat' : 'sunspot-solr')
14
-
15
- #
16
- # Start the sunspot-solr server. Bootstrap solr_home first,
17
- # if neccessary.
18
- #
19
- # ==== Returns
20
- #
21
- # Boolean:: success
22
- #
23
- def start
24
- bootstrap if bootstrap_neccessary?
25
- execute( start_command )
26
- end
27
-
28
- #
29
- # Run the sunspot-solr server in the foreground. Boostrap
30
- # solr_home first, if neccessary.
31
- #
32
- # ==== Returns
33
- #
34
- # Boolean:: success
35
- #
36
- def run
37
- bootstrap if bootstrap_neccessary?
38
- execute( run_command )
39
- end
40
-
41
- #
42
- # Stop the sunspot-solr server.
43
- #
44
- # ==== Returns
45
- #
46
- # Boolean:: success
47
- #
48
- def stop
49
- execute( stop_command )
50
- end
51
-
52
- #
53
- # Directory to store solr config files
54
- #
55
- # ==== Returns
56
- #
57
- # String:: config_path
58
- #
59
- def config_path
60
- File.join( solr_home, 'conf' )
61
- end
62
-
63
- #
64
- # Directory to store lucene index data files
65
- #
66
- # ==== Returns
67
- #
68
- # String:: data_path
69
- #
70
- def data_path
71
- File.join( solr_home, 'data', ::Rails.env )
72
- end
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)
73
7
 
74
- #
75
- # Directory to store custom libraries for solr
76
- #
77
- # ==== Returns
78
- #
79
- # String:: lib_path
80
- #
81
- def lib_path
82
- File.join( solr_home, 'lib' )
83
- end
84
-
85
- #
86
- # Directory to store pid files
87
- #
88
- # ==== Returns
89
- #
90
- # String:: pid_path
91
- #
92
- def pid_path
93
- File.join( solr_home, 'pids', ::Rails.env )
94
- end
95
-
96
- #
97
- # Bootstrap a new solr_home by creating all required
98
- # directories.
99
- #
100
- # ==== Returns
101
- #
102
- # Boolean:: success
103
- #
104
- def bootstrap
105
- create_solr_directories and create_solr_configuration_files and copy_custom_solr_libraries
106
- end
107
-
108
- #
109
- # Check for bootstrap necessity
110
- #
111
- # ==== Returns
112
- #
113
- # Boolean:: neccessary
114
- #
115
- def bootstrap_neccessary?
116
- !File.directory?( solr_home ) or !File.exists?( File.join( config_path, 'solrconfig.xml' ) )
117
- end
118
-
119
-
120
- protected
121
-
122
- #
123
- # Generate the start command for the sunspot-solr executable
124
- #
125
- # ==== Returns
126
- #
127
- # Array:: sunspot_start_command
128
- #
129
- def start_command
130
- [ SUNSPOT_EXECUTABLE, 'start', '-p', port.to_s, '-d', data_path, '-s', solr_home, '-l', log_level, '--log-file', log_file ]
131
- end
8
+ def start
9
+ bootstrap
10
+ super
11
+ end
132
12
 
133
- #
134
- # Generate the stop command for the sunspot-solr executable
135
- #
136
- # ==== Returns
137
- #
138
- # Array:: sunspot_stop_command
139
- #
140
- def stop_command
141
- [ SUNSPOT_EXECUTABLE, 'stop' ]
142
- end
13
+ def run
14
+ bootstrap
15
+ super
16
+ end
143
17
 
144
- #
145
- # Generate the run command for the sunspot-solr executable
146
- #
147
- # ==== Returns
148
- #
149
- # Array:: run_command
150
- #
151
- def run_command
152
- [ SUNSPOT_EXECUTABLE, 'run', '-p', port.to_s, '-d', data_path, '-s', solr_home, '-l', log_level, '-lf', log_file ]
153
- end
154
-
155
- #
156
- # access to the Sunspot::Rails::Configuration, defined in
157
- # sunspot.yml. Use Sunspot::Rails.configuration if you want
158
- # to access the configuration directly.
159
- #
160
- # ==== returns
161
- #
162
- # Sunspot::Rails::Configuration:: configuration
163
- #
164
- def configuration
165
- Sunspot::Rails.configuration
166
- end
167
-
168
- private
169
-
170
- #
171
- # Change directory to the pid file path and execute a
172
- # command on a subshell.
173
- #
174
- # ==== Returns
175
- #
176
- # Boolean:: success
177
- #
178
- def execute( command )
179
- success = false
180
- FileUtils.cd( pid_path ) do
181
- success = Kernel.system(Escape.shell_command( command ))
182
- end
183
- success
184
- end
185
-
186
- #
187
- # Create new solr_home, config, log and pid directories
188
- #
189
- # ==== Returns
190
- #
191
- # Boolean:: success
192
- #
193
- def create_solr_directories
194
- [ solr_home, config_path, data_path, pid_path, lib_path ].each do |path|
195
- FileUtils.mkdir_p( path )
196
- end
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
197
30
  end
198
-
199
- #
200
- # Copy custom solr libraries (like localsolr) to the
201
- # lib directory
202
- #
203
- # ==== Returns
204
- #
205
- # Boolean:: success
206
- #
207
- def copy_custom_solr_libraries
208
- Dir.glob( File.join( Sunspot::Configuration.solr_default_configuration_location, '..', 'lib', '*.jar') ).each do |jar_file|
209
- FileUtils.cp( jar_file, lib_path )
210
- 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
+ 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(::Rails.root, 'solr')
70
+ end
71
+
72
+ #
73
+ # Port on which to run Solr
74
+ #
75
+ def port
76
+ configuration.port
77
+ end
78
+
79
+ #
80
+ # Severity level for logging. This is based on the severity level for the
81
+ # Rails logger.
82
+ #
83
+ def log_level
84
+ LOG_LEVELS[::Rails.logger.level]
85
+ end
86
+
87
+ #
88
+ # Log file for Solr. File is in the rails log/ directory.
89
+ #
90
+ def log_file
91
+ File.join(::Rails.root, 'log', "sunspot-solr-#{::Rails.env}.log")
92
+ end
93
+
94
+ private
95
+
96
+ #
97
+ # access to the Sunspot::Rails::Configuration, defined in
98
+ # sunspot.yml. Use Sunspot::Rails.configuration if you want
99
+ # to access the configuration directly.
100
+ #
101
+ # ==== returns
102
+ #
103
+ # Sunspot::Rails::Configuration:: configuration
104
+ #
105
+ def configuration
106
+ Sunspot::Rails.configuration
107
+ end
108
+
109
+ #
110
+ # Directory to store solr config files
111
+ #
112
+ # ==== Returns
113
+ #
114
+ # String:: config_path
115
+ #
116
+ def config_path
117
+ File.join(solr_home, 'conf')
118
+ end
119
+
120
+ #
121
+ # Copy default solr configuration files from sunspot
122
+ # gem to the new solr_home/config directory
123
+ #
124
+ # ==== Returns
125
+ #
126
+ # Boolean:: success
127
+ #
128
+ def install_solr_home
129
+ unless File.exists?(solr_home)
130
+ Sunspot::Installer.execute(
131
+ solr_home,
132
+ :force => true,
133
+ :verbose => true
134
+ )
211
135
  end
212
-
213
- #
214
- # Copy default solr configuration files from sunspot
215
- # gem to the new solr_home/config directory
216
- #
217
- # ==== Returns
218
- #
219
- # Boolean:: success
220
- #
221
- def create_solr_configuration_files
222
- Dir.glob( File.join( Sunspot::Configuration.solr_default_configuration_location, '*') ).each do |config_file|
223
- FileUtils.cp( config_file, config_path )
224
- end
136
+ end
137
+
138
+ #
139
+ # Create new solr_home, config, log and pid directories
140
+ #
141
+ # ==== Returns
142
+ #
143
+ # Boolean:: success
144
+ #
145
+ def create_solr_directories
146
+ [solr_data_dir, pid_dir].each do |path|
147
+ FileUtils.mkdir_p( path )
225
148
  end
226
149
  end
227
150
  end
228
151
  end
229
- end
152
+ end