substantial-sunspot_rails 2.0.0.pre.111215

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. data/.gitignore +7 -0
  2. data/.rspec +1 -0
  3. data/History.txt +66 -0
  4. data/LICENSE +18 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +265 -0
  7. data/Rakefile +12 -0
  8. data/TODO +8 -0
  9. data/dev_tasks/rdoc.rake +24 -0
  10. data/dev_tasks/release.rake +4 -0
  11. data/dev_tasks/spec.rake +107 -0
  12. data/dev_tasks/todo.rake +4 -0
  13. data/gemfiles/rails-2.3.14 +15 -0
  14. data/gemfiles/rails-3.0.11 +15 -0
  15. data/gemfiles/rails-3.1.3 +15 -0
  16. data/generators/sunspot/sunspot_generator.rb +9 -0
  17. data/generators/sunspot/templates/sunspot.yml +18 -0
  18. data/install.rb +1 -0
  19. data/lib/generators/sunspot_rails.rb +9 -0
  20. data/lib/generators/sunspot_rails/install/install_generator.rb +13 -0
  21. data/lib/generators/sunspot_rails/install/templates/config/sunspot.yml +17 -0
  22. data/lib/substantial-sunspot_rails.rb +1 -0
  23. data/lib/sunspot/rails.rb +65 -0
  24. data/lib/sunspot/rails/adapters.rb +83 -0
  25. data/lib/sunspot/rails/configuration.rb +340 -0
  26. data/lib/sunspot/rails/init.rb +5 -0
  27. data/lib/sunspot/rails/log_subscriber.rb +33 -0
  28. data/lib/sunspot/rails/railtie.rb +36 -0
  29. data/lib/sunspot/rails/railties/controller_runtime.rb +36 -0
  30. data/lib/sunspot/rails/request_lifecycle.rb +36 -0
  31. data/lib/sunspot/rails/searchable.rb +480 -0
  32. data/lib/sunspot/rails/server.rb +106 -0
  33. data/lib/sunspot/rails/solr_instrumentation.rb +18 -0
  34. data/lib/sunspot/rails/solr_logging.rb +62 -0
  35. data/lib/sunspot/rails/spec_helper.rb +26 -0
  36. data/lib/sunspot/rails/stub_session_proxy.rb +142 -0
  37. data/lib/sunspot/rails/tasks.rb +84 -0
  38. data/lib/sunspot_rails.rb +12 -0
  39. data/spec/configuration_spec.rb +195 -0
  40. data/spec/model_lifecycle_spec.rb +63 -0
  41. data/spec/model_spec.rb +595 -0
  42. data/spec/rails_template/app/controllers/application_controller.rb +10 -0
  43. data/spec/rails_template/app/controllers/posts_controller.rb +6 -0
  44. data/spec/rails_template/app/models/author.rb +8 -0
  45. data/spec/rails_template/app/models/blog.rb +12 -0
  46. data/spec/rails_template/app/models/location.rb +2 -0
  47. data/spec/rails_template/app/models/photo_post.rb +2 -0
  48. data/spec/rails_template/app/models/post.rb +11 -0
  49. data/spec/rails_template/app/models/post_with_auto.rb +10 -0
  50. data/spec/rails_template/app/models/post_with_default_scope.rb +11 -0
  51. data/spec/rails_template/config/boot.rb +127 -0
  52. data/spec/rails_template/config/preinitializer.rb +22 -0
  53. data/spec/rails_template/config/routes.rb +9 -0
  54. data/spec/rails_template/config/sunspot.yml +22 -0
  55. data/spec/rails_template/db/schema.rb +27 -0
  56. data/spec/request_lifecycle_spec.rb +61 -0
  57. data/spec/schema.rb +27 -0
  58. data/spec/searchable_spec.rb +12 -0
  59. data/spec/server_spec.rb +33 -0
  60. data/spec/session_spec.rb +57 -0
  61. data/spec/shared_examples/indexed_after_save.rb +8 -0
  62. data/spec/shared_examples/not_indexed_after_save.rb +8 -0
  63. data/spec/spec_helper.rb +48 -0
  64. data/spec/stub_session_proxy_spec.rb +122 -0
  65. data/substantial-sunspot_rails.gemspec +43 -0
  66. metadata +228 -0
@@ -0,0 +1,4 @@
1
+ desc 'Show all TODO and related tags'
2
+ task :todo do
3
+ FileList['lib/**/*.rb'].egrep(/#.*(TODO|FIXME|XXX)/)
4
+ end
@@ -0,0 +1,15 @@
1
+ source :rubygems
2
+
3
+ gem 'rails', '2.3.14'
4
+ gem 'sqlite3-ruby', '~> 1.3.1'
5
+
6
+ gem 'sunspot', :path => File.expand_path('../../../sunspot', __FILE__)
7
+ gem 'sunspot_solr', :path => File.expand_path('../../../sunspot_solr', __FILE__)
8
+ gem 'sunspot_rails', :path => File.expand_path('../..', __FILE__)
9
+
10
+ group :test do
11
+ gem 'rspec-rails', '~> 1.3.4'
12
+ gem 'ruby-debug19', :require => nil, :platforms => :mri_19
13
+ gem 'test-unit', '1.2.3', :platforms => :mri_19
14
+ gem 'ruby-debug', :require => nil, :platforms => :mri_18
15
+ end
@@ -0,0 +1,15 @@
1
+ source :rubygems
2
+
3
+ gem 'rails', '3.0.11'
4
+ gem 'sqlite3-ruby', '~> 1.3.1'
5
+
6
+ gem 'sunspot', :path => File.expand_path('../../../sunspot', __FILE__)
7
+ gem 'sunspot_solr', :path => File.expand_path('../../../sunspot_solr', __FILE__)
8
+ gem 'sunspot_rails', :path => File.expand_path('../..', __FILE__)
9
+
10
+ group :test do
11
+ gem 'rspec-rails', '~> 2.0.0'
12
+ gem 'ruby-debug19', :require => nil, :platforms => :mri_19
13
+ gem 'test-unit', '1.2.3', :platforms => :mri_19
14
+ gem 'ruby-debug', :require => nil, :platforms => :mri_18
15
+ end
@@ -0,0 +1,15 @@
1
+ source :rubygems
2
+
3
+ gem 'rails', '3.1.3'
4
+ gem 'sqlite3-ruby', '~> 1.3.1'
5
+
6
+ gem 'sunspot', :path => File.expand_path('../../../sunspot', __FILE__)
7
+ gem 'sunspot_solr', :path => File.expand_path('../../../sunspot_solr', __FILE__)
8
+ gem 'sunspot_rails', :path => File.expand_path('../..', __FILE__)
9
+
10
+ group :test do
11
+ gem 'rspec-rails', '~> 2.0.0'
12
+ gem 'ruby-debug19', :require => nil, :platforms => :mri_19
13
+ gem 'test-unit', '1.2.3', :platforms => :mri_19
14
+ gem 'ruby-debug', :require => nil, :platforms => :mri_18
15
+ end
@@ -0,0 +1,9 @@
1
+ class SunspotGenerator < Rails::Generator::Base
2
+
3
+ def manifest
4
+ record do |m|
5
+ m.template 'sunspot.yml', 'config/sunspot.yml'
6
+ end
7
+ end
8
+
9
+ end
@@ -0,0 +1,18 @@
1
+ production:
2
+ solr:
3
+ hostname: localhost
4
+ port: 8983
5
+ log_level: WARNING
6
+
7
+ development:
8
+ solr:
9
+ hostname: localhost
10
+ port: 8982
11
+ log_level: INFO
12
+
13
+ test:
14
+ solr:
15
+ hostname: localhost
16
+ port: 8981
17
+ log_level: WARNING
18
+
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,9 @@
1
+ module SunspotRails
2
+ module Generators
3
+ class Base < Rails::Generators::NamedBase
4
+ def self.source_root
5
+ @_sunspot_rails_source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'sunspot_rails', generator_name, 'templates'))
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module SunspotRails
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ def self.source_root
5
+ @source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
6
+ end
7
+ def copy_config_file
8
+ template 'config/sunspot.yml'
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,17 @@
1
+ production:
2
+ solr:
3
+ hostname: localhost
4
+ port: 8983
5
+ log_level: WARNING
6
+
7
+ development:
8
+ solr:
9
+ hostname: localhost
10
+ port: 8982
11
+ log_level: INFO
12
+
13
+ test:
14
+ solr:
15
+ hostname: localhost
16
+ port: 8981
17
+ log_level: WARNING
@@ -0,0 +1 @@
1
+ require 'sunspot_rails'
@@ -0,0 +1,65 @@
1
+ require 'sunspot'
2
+ require File.join(File.dirname(__FILE__), 'rails', 'configuration')
3
+ require File.join(File.dirname(__FILE__), 'rails', 'adapters')
4
+ require File.join(File.dirname(__FILE__), 'rails', 'request_lifecycle')
5
+ require File.join(File.dirname(__FILE__), 'rails', 'searchable')
6
+
7
+ module Sunspot #:nodoc:
8
+ module Rails #:nodoc:
9
+ autoload :SolrInstrumentation, File.join(File.dirname(__FILE__), 'rails', 'solr_instrumentation')
10
+ autoload :StubSessionProxy, File.join(File.dirname(__FILE__), 'rails', 'stub_session_proxy')
11
+ begin
12
+ require 'sunspot_solr'
13
+ autoload :Server, File.join(File.dirname(__FILE__), 'rails', 'server')
14
+ rescue LoadError => e
15
+ # We're fine
16
+ end
17
+
18
+ class <<self
19
+ attr_writer :configuration
20
+
21
+ def configuration
22
+ @configuration ||= Sunspot::Rails::Configuration.new
23
+ end
24
+
25
+ def reset
26
+ @configuration = nil
27
+ end
28
+
29
+ def build_session(configuration = self.configuration)
30
+ if configuration.disabled?
31
+ StubSessionProxy.new(Sunspot.session)
32
+ elsif configuration.has_master?
33
+ SessionProxy::MasterSlaveSessionProxy.new(
34
+ SessionProxy::ThreadLocalSessionProxy.new(master_config(configuration)),
35
+ SessionProxy::ThreadLocalSessionProxy.new(slave_config(configuration))
36
+ )
37
+ else
38
+ SessionProxy::ThreadLocalSessionProxy.new(slave_config(configuration))
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def master_config(sunspot_rails_configuration)
45
+ config = Sunspot::Configuration.build
46
+ config.solr.url = URI::HTTP.build(
47
+ :host => sunspot_rails_configuration.master_hostname,
48
+ :port => sunspot_rails_configuration.master_port,
49
+ :path => sunspot_rails_configuration.master_path
50
+ ).to_s
51
+ config
52
+ end
53
+
54
+ def slave_config(sunspot_rails_configuration)
55
+ config = Sunspot::Configuration.build
56
+ config.solr.url = URI::HTTP.build(
57
+ :host => sunspot_rails_configuration.hostname,
58
+ :port => sunspot_rails_configuration.port,
59
+ :path => sunspot_rails_configuration.path
60
+ ).to_s
61
+ config
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,83 @@
1
+ module Sunspot #:nodoc:
2
+ module Rails #:nodoc:
3
+ #
4
+ # This module provides Sunspot Adapter implementations for ActiveRecord
5
+ # models.
6
+ #
7
+ module Adapters
8
+ class ActiveRecordInstanceAdapter < Sunspot::Adapters::InstanceAdapter
9
+ #
10
+ # Return the primary key for the adapted instance
11
+ #
12
+ # ==== Returns
13
+ #
14
+ # Integer:: Database ID of model
15
+ #
16
+ def id
17
+ @instance.id
18
+ end
19
+ end
20
+
21
+ class ActiveRecordDataAccessor < Sunspot::Adapters::DataAccessor
22
+ # options for the find
23
+ attr_accessor :include, :select
24
+
25
+ #
26
+ # Set the fields to select from the database. This will be passed
27
+ # to ActiveRecord.
28
+ #
29
+ # ==== Parameters
30
+ #
31
+ # value<Mixed>:: String of comma-separated columns or array of columns
32
+ #
33
+ def select=(value)
34
+ value = value.join(', ') if value.respond_to?(:join)
35
+ @select = value
36
+ end
37
+
38
+ #
39
+ # Get one ActiveRecord instance out of the database by ID
40
+ #
41
+ # ==== Parameters
42
+ #
43
+ # id<String>:: Database ID of model to retreive
44
+ #
45
+ # ==== Returns
46
+ #
47
+ # ActiveRecord::Base:: ActiveRecord model
48
+ #
49
+ def load(id)
50
+ @clazz.first(options_for_find.merge(
51
+ :conditions => { @clazz.primary_key => id}
52
+ ))
53
+ end
54
+
55
+ #
56
+ # Get a collection of ActiveRecord instances out of the database by ID
57
+ #
58
+ # ==== Parameters
59
+ #
60
+ # ids<Array>:: Database IDs of models to retrieve
61
+ #
62
+ # ==== Returns
63
+ #
64
+ # Array:: Collection of ActiveRecord models
65
+ #
66
+ def load_all(ids)
67
+ @clazz.all(options_for_find.merge(
68
+ :conditions => { @clazz.primary_key => ids.map { |id| id }}
69
+ ))
70
+ end
71
+
72
+ private
73
+
74
+ def options_for_find
75
+ options = {}
76
+ options[:include] = @include unless @include.blank?
77
+ options[:select] = @select unless @select.blank?
78
+ options
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,340 @@
1
+ require 'erb'
2
+
3
+ module Sunspot #:nodoc:
4
+ module Rails #:nodoc:
5
+ #
6
+ # Sunspot::Rails is configured via the config/sunspot.yml file, which
7
+ # contains properties keyed by environment name. A sample sunspot.yml file
8
+ # would look like:
9
+ #
10
+ # development:
11
+ # solr:
12
+ # hostname: localhost
13
+ # port: 8982
14
+ # min_memory: 512M
15
+ # max_memory: 1G
16
+ # solr_jar: /some/path/solr15/start.jar
17
+ # bind_address: 0.0.0.0
18
+ # disabled: false
19
+ # test:
20
+ # solr:
21
+ # hostname: localhost
22
+ # port: 8983
23
+ # log_level: OFF
24
+ # production:
25
+ # solr:
26
+ # hostname: localhost
27
+ # port: 8983
28
+ # path: /solr/myindex
29
+ # log_level: WARNING
30
+ # solr_home: /some/path
31
+ # master_solr:
32
+ # hostname: localhost
33
+ # port: 8982
34
+ # path: /solr
35
+ # auto_commit_after_request: true
36
+ #
37
+ # Sunspot::Rails uses the configuration to set up the Solr connection, as
38
+ # well as for starting Solr with the appropriate port using the
39
+ # <code>rake sunspot:solr:start</code> task.
40
+ #
41
+ # If the <code>master_solr</code> configuration is present, Sunspot will use
42
+ # the Solr instance specified here for all write operations, and the Solr
43
+ # configured under <code>solr</code> for all read operations.
44
+ #
45
+ class Configuration
46
+ attr_writer :user_configuration
47
+ #
48
+ # The host name at which to connect to Solr. Default 'localhost'.
49
+ #
50
+ # ==== Returns
51
+ #
52
+ # String:: host name
53
+ #
54
+ def hostname
55
+ unless defined?(@hostname)
56
+ @hostname = solr_url.host if solr_url
57
+ @hostname ||= user_configuration_from_key('solr', 'hostname')
58
+ @hostname ||= default_hostname
59
+ end
60
+ @hostname
61
+ end
62
+
63
+ #
64
+ # The port at which to connect to Solr.
65
+ # Defaults to 8981 in test, 8982 in development and 8983 in production.
66
+ #
67
+ # ==== Returns
68
+ #
69
+ # Integer:: port
70
+ #
71
+ def port
72
+ unless defined?(@port)
73
+ @port = solr_url.port if solr_url
74
+ @port ||= user_configuration_from_key('solr', 'port')
75
+ @port ||= default_port
76
+ @port = @port.to_i
77
+ end
78
+ @port
79
+ end
80
+
81
+ #
82
+ # The url path to the Solr servlet (useful if you are running multicore).
83
+ # Default '/solr'.
84
+ #
85
+ # ==== Returns
86
+ #
87
+ # String:: path
88
+ #
89
+ def path
90
+ unless defined?(@path)
91
+ @path = solr_url.path if solr_url
92
+ @path ||= user_configuration_from_key('solr', 'path')
93
+ @path ||= default_path
94
+ end
95
+ @path
96
+ end
97
+
98
+ #
99
+ # The host name at which to connect to the master Solr instance. Defaults
100
+ # to the 'hostname' configuration option.
101
+ #
102
+ # ==== Returns
103
+ #
104
+ # String:: host name
105
+ #
106
+ def master_hostname
107
+ @master_hostname ||= (user_configuration_from_key('master_solr', 'hostname') || hostname)
108
+ end
109
+
110
+ #
111
+ # The port at which to connect to the master Solr instance. Defaults to
112
+ # the 'port' configuration option.
113
+ #
114
+ # ==== Returns
115
+ #
116
+ # Integer:: port
117
+ #
118
+ def master_port
119
+ @master_port ||= (user_configuration_from_key('master_solr', 'port') || port).to_i
120
+ end
121
+
122
+ #
123
+ # The path to the master Solr servlet (useful if you are running multicore).
124
+ # Defaults to the value of the 'path' configuration option.
125
+ #
126
+ # ==== Returns
127
+ #
128
+ # String:: path
129
+ #
130
+ def master_path
131
+ @master_path ||= (user_configuration_from_key('master_solr', 'path') || path)
132
+ end
133
+
134
+ #
135
+ # True if there is a master Solr instance configured, otherwise false.
136
+ #
137
+ # ==== Returns
138
+ #
139
+ # Boolean:: bool
140
+ #
141
+ def has_master?
142
+ @has_master = !!user_configuration_from_key('master_solr')
143
+ end
144
+
145
+ #
146
+ # The default log_level that should be passed to solr. You can
147
+ # change the individual log_levels in the solr admin interface.
148
+ # Default 'INFO'.
149
+ #
150
+ # ==== Returns
151
+ #
152
+ # String:: log_level
153
+ #
154
+ def log_level
155
+ @log_level ||= (user_configuration_from_key('solr', 'log_level') || 'INFO')
156
+ end
157
+
158
+ #
159
+ # Should the solr index receive a commit after each http-request.
160
+ # Default true
161
+ #
162
+ # ==== Returns
163
+ #
164
+ # Boolean: auto_commit_after_request?
165
+ #
166
+ def auto_commit_after_request?
167
+ @auto_commit_after_request ||=
168
+ user_configuration_from_key('auto_commit_after_request') != false
169
+ end
170
+
171
+ #
172
+ # As for #auto_commit_after_request? but only for deletes
173
+ # Default false
174
+ #
175
+ # ==== Returns
176
+ #
177
+ # Boolean: auto_commit_after_delete_request?
178
+ #
179
+ def auto_commit_after_delete_request?
180
+ @auto_commit_after_delete_request ||=
181
+ (user_configuration_from_key('auto_commit_after_delete_request') || false)
182
+ end
183
+
184
+
185
+ #
186
+ # The log directory for solr logfiles
187
+ #
188
+ # ==== Returns
189
+ #
190
+ # String:: log_dir
191
+ #
192
+ def log_file
193
+ @log_file ||= (user_configuration_from_key('solr', 'log_file') || default_log_file_location )
194
+ end
195
+
196
+ def data_path
197
+ @data_path ||= user_configuration_from_key('solr', 'data_path') || File.join(::Rails.root, 'solr', 'data', ::Rails.env)
198
+ end
199
+
200
+ def pid_dir
201
+ @pid_dir ||= user_configuration_from_key('solr', 'pid_dir') || File.join(::Rails.root, 'solr', 'pids', ::Rails.env)
202
+ end
203
+
204
+
205
+ #
206
+ # The solr home directory. Sunspot::Rails expects this directory
207
+ # to contain a config, data and pids directory. See
208
+ # Sunspot::Rails::Server.bootstrap for more information.
209
+ #
210
+ # ==== Returns
211
+ #
212
+ # String:: solr_home
213
+ #
214
+ def solr_home
215
+ @solr_home ||=
216
+ if user_configuration_from_key('solr', 'solr_home')
217
+ user_configuration_from_key('solr', 'solr_home')
218
+ else
219
+ File.join(::Rails.root, 'solr')
220
+ end
221
+ end
222
+
223
+ #
224
+ # Solr start jar
225
+ #
226
+ def solr_jar
227
+ @solr_jar ||= user_configuration_from_key('solr', 'solr_jar')
228
+ end
229
+
230
+ #
231
+ # Minimum java heap size for Solr instance
232
+ #
233
+ def min_memory
234
+ @min_memory ||= user_configuration_from_key('solr', 'min_memory')
235
+ end
236
+
237
+ #
238
+ # Maximum java heap size for Solr instance
239
+ #
240
+ def max_memory
241
+ @max_memory ||= user_configuration_from_key('solr', 'max_memory')
242
+ end
243
+
244
+ #
245
+ # Interface on which to run Solr
246
+ #
247
+ def bind_address
248
+ @bind_address ||= user_configuration_from_key('solr', 'bind_address')
249
+ end
250
+
251
+ #
252
+ # Whether or not to disable Solr.
253
+ # Defaults to false.
254
+ #
255
+ def disabled?
256
+ @disabled ||= (user_configuration_from_key('disabled') || false)
257
+ end
258
+
259
+ private
260
+
261
+ #
262
+ # Logging in rails_root/log as solr_<environment>.log as a
263
+ # default.
264
+ #
265
+ # ===== Returns
266
+ #
267
+ # String:: default_log_file_location
268
+ #
269
+ def default_log_file_location
270
+ File.join(::Rails.root, 'log', "solr_" + ::Rails.env + ".log")
271
+ end
272
+
273
+ #
274
+ # return a specific key from the user configuration in config/sunspot.yml
275
+ #
276
+ # ==== Returns
277
+ #
278
+ # Mixed:: requested_key or nil
279
+ #
280
+ def user_configuration_from_key( *keys )
281
+ keys.inject(user_configuration) do |hash, key|
282
+ hash[key] if hash
283
+ end
284
+ end
285
+
286
+ #
287
+ # Memoized hash of configuration options for the current Rails environment
288
+ # as specified in config/sunspot.yml
289
+ #
290
+ # ==== Returns
291
+ #
292
+ # Hash:: configuration options for current environment
293
+ #
294
+ def user_configuration
295
+ @user_configuration ||=
296
+ begin
297
+ path = File.join(::Rails.root, 'config', 'sunspot.yml')
298
+ if File.exist?(path)
299
+ File.open(path) do |file|
300
+ processed = ERB.new(file.read).result
301
+ YAML.load(processed)[::Rails.env]
302
+ end
303
+ else
304
+ {}
305
+ end
306
+ end
307
+ end
308
+
309
+ protected
310
+
311
+ #
312
+ # When a specific hostname, port and path aren't provided in the
313
+ # sunspot.yml file, look for a key named 'url', then check the
314
+ # environment, then fall back to a sensible localhost default.
315
+ #
316
+
317
+ def solr_url
318
+ if ENV['SOLR_URL'] || ENV['WEBSOLR_URL']
319
+ URI.parse(ENV['SOLR_URL'] || ENV['WEBSOLR_URL'])
320
+ end
321
+ end
322
+
323
+ def default_hostname
324
+ 'localhost'
325
+ end
326
+
327
+ def default_port
328
+ { 'test' => 8981,
329
+ 'development' => 8982,
330
+ 'production' => 8983
331
+ }[::Rails.env] || 8983
332
+ end
333
+
334
+ def default_path
335
+ '/solr'
336
+ end
337
+
338
+ end
339
+ end
340
+ end