gojee-sunspot-rails 2.0.3 → 2.0.4

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 (67) hide show
  1. data/.gitignore +7 -0
  2. data/.rspec +1 -0
  3. data/History.txt +74 -0
  4. data/LICENSE +18 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +265 -0
  7. data/Rakefile +17 -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 +12 -0
  14. data/gemfiles/rails-3.0.11 +12 -0
  15. data/gemfiles/rails-3.1.3 +12 -0
  16. data/gemfiles/rails-3.2.1 +12 -0
  17. data/generators/sunspot/sunspot_generator.rb +9 -0
  18. data/generators/sunspot/templates/sunspot.yml +20 -0
  19. data/install.rb +1 -0
  20. data/lib/generators/sunspot_rails/install/install_generator.rb +13 -0
  21. data/lib/generators/sunspot_rails/install/templates/config/sunspot.yml +19 -0
  22. data/lib/generators/sunspot_rails.rb +9 -0
  23. data/lib/sunspot/rails/adapters.rb +83 -0
  24. data/lib/sunspot/rails/configuration.rb +376 -0
  25. data/lib/sunspot/rails/init.rb +5 -0
  26. data/lib/sunspot/rails/log_subscriber.rb +33 -0
  27. data/lib/sunspot/rails/railtie.rb +36 -0
  28. data/lib/sunspot/rails/railties/controller_runtime.rb +36 -0
  29. data/lib/sunspot/rails/request_lifecycle.rb +36 -0
  30. data/lib/sunspot/rails/searchable.rb +491 -0
  31. data/lib/sunspot/rails/server.rb +114 -0
  32. data/lib/sunspot/rails/solr_instrumentation.rb +19 -0
  33. data/lib/sunspot/rails/solr_logging.rb +62 -0
  34. data/lib/sunspot/rails/spec_helper.rb +26 -0
  35. data/lib/sunspot/rails/stub_session_proxy.rb +142 -0
  36. data/lib/sunspot/rails/tasks.rb +84 -0
  37. data/lib/sunspot/rails.rb +69 -0
  38. data/lib/sunspot_rails.rb +12 -0
  39. data/spec/configuration_spec.rb +209 -0
  40. data/spec/model_lifecycle_spec.rb +63 -0
  41. data/spec/model_spec.rb +601 -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 +24 -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/sunspot_rails.gemspec +43 -0
  66. data/tmp/.gitkeep +0 -0
  67. metadata +97 -5
@@ -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
@@ -0,0 +1,142 @@
1
+ module Sunspot
2
+ module Rails
3
+ class StubSessionProxy
4
+ attr_reader :original_session
5
+
6
+ def initialize(original_session)
7
+ @original_session = original_session
8
+ end
9
+
10
+ def index(*objects)
11
+ end
12
+
13
+ def index!(*objects)
14
+ end
15
+
16
+ def remove(*objects)
17
+ end
18
+
19
+ def remove!(*objects)
20
+ end
21
+
22
+ def remove_by_id(clazz, id)
23
+ end
24
+
25
+ def remove_by_id!(clazz, id)
26
+ end
27
+
28
+ def remove_all(clazz = nil)
29
+ end
30
+
31
+ def remove_all!(clazz = nil)
32
+ end
33
+
34
+ def dirty?
35
+ false
36
+ end
37
+
38
+ def delete_dirty?
39
+ false
40
+ end
41
+
42
+ def commit_if_dirty
43
+ end
44
+
45
+ def commit_if_delete_dirty
46
+ end
47
+
48
+ def commit
49
+ end
50
+
51
+ def search(*types)
52
+ Search.new
53
+ end
54
+
55
+ def new_search(*types)
56
+ Search.new
57
+ end
58
+
59
+ def new_more_like_this(*args)
60
+ Search.new
61
+ end
62
+
63
+ class Search
64
+
65
+ def build
66
+ self
67
+ end
68
+
69
+ def results
70
+ PaginatedCollection.new
71
+ end
72
+
73
+ def hits(options = {})
74
+ PaginatedCollection.new
75
+ end
76
+
77
+ def total
78
+ 0
79
+ end
80
+
81
+ def facet(name)
82
+ end
83
+
84
+ def dynamic_facet(name)
85
+ end
86
+
87
+ def execute
88
+ self
89
+ end
90
+ end
91
+
92
+
93
+ class PaginatedCollection < Array
94
+
95
+ def total_count
96
+ 0
97
+ end
98
+ alias :total_entries :total_count
99
+
100
+ def current_page
101
+ 1
102
+ end
103
+
104
+ def per_page
105
+ 30
106
+ end
107
+ alias :limit_value :per_page
108
+
109
+ def total_pages
110
+ 1
111
+ end
112
+ alias :num_pages :total_pages
113
+
114
+ def first_page?
115
+ true
116
+ end
117
+
118
+ def last_page?
119
+ true
120
+ end
121
+
122
+ def previous_page
123
+ nil
124
+ end
125
+
126
+ def next_page
127
+ nil
128
+ end
129
+
130
+ def out_of_bounds?
131
+ false
132
+ end
133
+
134
+ def offset
135
+ 0
136
+ end
137
+
138
+ end
139
+
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,84 @@
1
+ namespace :sunspot do
2
+
3
+ desc "Reindex all solr models that are located in your application's models directory."
4
+ # This task depends on the standard Rails file naming \
5
+ # conventions, in that the file name matches the defined class name. \
6
+ # By default the indexing system works in batches of 50 records, you can \
7
+ # set your own value for this by using the batch_size argument. You can \
8
+ # also optionally define a list of models to separated by a forward slash '/'
9
+ #
10
+ # $ rake sunspot:reindex # reindex all models
11
+ # $ rake sunspot:reindex[1000] # reindex in batches of 1000
12
+ # $ rake sunspot:reindex[false] # reindex without batching
13
+ # $ rake sunspot:reindex[,Post] # reindex only the Post model
14
+ # $ rake sunspot:reindex[1000,Post] # reindex only the Post model in
15
+ # # batchs of 1000
16
+ # $ rake sunspot:reindex[,Post+Author] # reindex Post and Author model
17
+ task :reindex, [:batch_size, :models] => [:environment] do |t, args|
18
+ # Set up general options for reindexing
19
+ reindex_options = { :batch_commit => false }
20
+
21
+ case args[:batch_size]
22
+ when 'false'
23
+ reindex_options[:batch_size] = nil
24
+ when /^\d+$/
25
+ reindex_options[:batch_size] = args[:batch_size].to_i if args[:batch_size].to_i > 0
26
+ end
27
+
28
+ # Load all the application's models. Models which invoke 'searchable' will register themselves
29
+ # in Sunspot.searchable.
30
+ Dir.glob(Rails.root.join('app/models/**/*.rb')).each { |path| require path }
31
+
32
+ # By default, reindex all searchable models
33
+ sunspot_models = Sunspot.searchable
34
+
35
+ # Choose a specific subset of models, if requested
36
+ if args[:models]
37
+ model_names = args[:models].split('+')
38
+ sunspot_models = model_names.map{ |m| m.constantize }
39
+ end
40
+
41
+ # Set up progress_bar to, ah, report progress
42
+ begin
43
+ require 'progress_bar'
44
+ total_documents = sunspot_models.map { | m | m.count }.sum
45
+ reindex_options[:progress_bar] = ProgressBar.new(total_documents)
46
+ rescue LoadError => e
47
+ $stdout.puts "Skipping progress bar: for progress reporting, add gem 'progress_bar' to your Gemfile"
48
+ rescue Exception => e
49
+ $stderr.puts "Error using progress bar: #{e.message}"
50
+ end
51
+
52
+ # Finally, invoke the class-level solr_reindex on each model
53
+ sunspot_models.each do |model|
54
+ model.solr_reindex(reindex_options)
55
+ end
56
+ end
57
+
58
+
59
+ unless defined?(Sunspot::Solr)
60
+ namespace :solr do
61
+ task :moved_to_sunspot_solr do
62
+ abort %(
63
+ Note: This task has been moved to the sunspot_solr gem. To install, start and
64
+ stop a local Solr instance, please add sunspot_solr to your Gemfile:
65
+
66
+ group :development do
67
+ gem 'sunspot_solr'
68
+ end
69
+
70
+ )
71
+ end
72
+
73
+ desc 'Start the Solr instance'
74
+ task :start => :moved_to_sunspot_solr
75
+ desc 'Run the Solr instance in the foreground'
76
+ task :run => :moved_to_sunspot_solr
77
+ desc 'Stop the Solr instance'
78
+ task :stop => :moved_to_sunspot_solr
79
+ # for backwards compatibility
80
+ task :reindex => :"sunspot:reindex"
81
+ end
82
+ end
83
+
84
+ end
@@ -0,0 +1,69 @@
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.solr.read_timeout = sunspot_rails_configuration.read_timeout
52
+ config.solr.open_timeout = sunspot_rails_configuration.open_timeout
53
+ config
54
+ end
55
+
56
+ def slave_config(sunspot_rails_configuration)
57
+ config = Sunspot::Configuration.build
58
+ config.solr.url = URI::HTTP.build(
59
+ :host => sunspot_rails_configuration.hostname,
60
+ :port => sunspot_rails_configuration.port,
61
+ :path => sunspot_rails_configuration.path
62
+ ).to_s
63
+ config.solr.read_timeout = sunspot_rails_configuration.read_timeout
64
+ config.solr.open_timeout = sunspot_rails_configuration.open_timeout
65
+ config
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,12 @@
1
+ # This needs to be loaded before sunspot/search/paginated_collection
2
+ # or #to_json gets defined in Object breaking delegation to Array via
3
+ # method_missing
4
+ require 'active_support/core_ext/object/to_json' if Rails::VERSION::MAJOR == 3
5
+
6
+ require 'sunspot/rails'
7
+
8
+ if Rails::VERSION::MAJOR == 3
9
+ require 'sunspot/rails/railtie'
10
+ else
11
+ require 'sunspot/rails/init'
12
+ end
@@ -0,0 +1,209 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe Sunspot::Rails::Configuration, "default values without a sunspot.yml" do
4
+ before(:each) do
5
+ File.stub!(:exist?).and_return(false) # simulate sunspot.yml not existing
6
+ @config = Sunspot::Rails::Configuration.new
7
+ end
8
+
9
+ it "should handle the 'hostname' property when not set" do
10
+ @config.hostname.should == 'localhost'
11
+ end
12
+
13
+ it "should handle the 'path' property when not set" do
14
+ @config.path.should == '/solr'
15
+ end
16
+
17
+ describe "port" do
18
+ it "should default to port 8981 in test" do
19
+ ::Rails.stub!(:env => 'test')
20
+ @config = Sunspot::Rails::Configuration.new
21
+ @config.port.should == 8981
22
+ end
23
+ it "should default to port 8982 in development" do
24
+ ::Rails.stub!(:env => 'development')
25
+ @config = Sunspot::Rails::Configuration.new
26
+ @config.port.should == 8982
27
+ end
28
+ it "should default to 8983 in production" do
29
+ ::Rails.stub!(:env => 'production')
30
+ @config = Sunspot::Rails::Configuration.new
31
+ @config.port.should == 8983
32
+ end
33
+ it "should generally default to 8983" do
34
+ ::Rails.stub!(:env => 'staging')
35
+ @config = Sunspot::Rails::Configuration.new
36
+ @config.port.should == 8983
37
+ end
38
+ end
39
+
40
+ it "should set the read timeout to nil when not set" do
41
+ @config.read_timeout == nil
42
+ end
43
+
44
+ it "should set the open timeout to nil when not set" do
45
+ @config.open_timeout == nil
46
+ end
47
+
48
+ it "should handle the 'log_level' property when not set" do
49
+ @config.log_level.should == 'INFO'
50
+ end
51
+
52
+ it "should handle the 'log_file' property" do
53
+ @config.log_file.should =~ /log\/solr_test.log/
54
+ end
55
+
56
+ it "should handle the 'solr_home' property when not set" do
57
+ Rails.should_receive(:root).at_least(1).and_return('/some/path')
58
+ @config.solr_home.should == '/some/path/solr'
59
+ end
60
+
61
+ it "should handle the 'data_path' property when not set" do
62
+ Rails.should_receive(:root).at_least(1).and_return('/some/path')
63
+ @config.data_path.should == '/some/path/solr/data/test'
64
+ end
65
+
66
+ it "should handle the 'pid_dir' property when not set" do
67
+ Rails.should_receive(:root).at_least(1).and_return('/some/path')
68
+ @config.pid_dir.should == '/some/path/solr/pids/test'
69
+ end
70
+
71
+ it "should handle the 'auto_commit_after_request' propery when not set" do
72
+ @config.auto_commit_after_request?.should == true
73
+ end
74
+
75
+ it "should handle the 'auto_commit_after_delete_request' propery when not set" do
76
+ @config.auto_commit_after_delete_request?.should == false
77
+ end
78
+
79
+ it "should handle the 'bind_address' property when not set" do
80
+ @config.bind_address.should be_nil
81
+ end
82
+
83
+ it "should handle the 'disabled' property when not set" do
84
+ @config.disabled?.should be_false
85
+ end
86
+ end
87
+
88
+ describe Sunspot::Rails::Configuration, "user provided sunspot.yml" do
89
+ before(:each) do
90
+ ::Rails.stub!(:env => 'config_test')
91
+ @config = Sunspot::Rails::Configuration.new
92
+ end
93
+
94
+ it "should handle the 'hostname' property when set" do
95
+ @config.hostname.should == 'some.host'
96
+ end
97
+
98
+ it "should handle the 'port' property when set" do
99
+ @config.port.should == 1234
100
+ end
101
+
102
+ it "should handle the 'path' property when set" do
103
+ @config.path.should == '/solr/idx'
104
+ end
105
+
106
+ it "should handle the 'log_level' propery when set" do
107
+ @config.log_level.should == 'WARNING'
108
+ end
109
+
110
+ it "should handle the 'solr_home' propery when set" do
111
+ @config.solr_home.should == '/my_superior_path'
112
+ end
113
+
114
+ it "should handle the 'data_path' property when set" do
115
+ @config.data_path.should == '/my_superior_path/data'
116
+ end
117
+
118
+ it "should handle the 'pid_dir' property when set" do
119
+ @config.pid_dir.should == '/my_superior_path/pids'
120
+ end
121
+
122
+ it "should handle the 'solr_home' property when set" do
123
+ @config.solr_home.should == '/my_superior_path'
124
+ end
125
+
126
+ it "should handle the 'auto_commit_after_request' propery when set" do
127
+ @config.auto_commit_after_request?.should == false
128
+ end
129
+
130
+ it "should handle the 'auto_commit_after_delete_request' propery when set" do
131
+ @config.auto_commit_after_delete_request?.should == true
132
+ end
133
+
134
+ it "should handle the 'bind_address' property when set" do
135
+ @config.bind_address.should == "127.0.0.1"
136
+ end
137
+ it "should handle the 'read_timeout' property when set" do
138
+ @config.read_timeout.should == 2
139
+ end
140
+ it "should handle the 'open_timeout' property when set" do
141
+ @config.open_timeout.should == 0.5
142
+ end
143
+ end
144
+
145
+ describe Sunspot::Rails::Configuration, "with disabled: true in sunspot.yml" do
146
+ before(:each) do
147
+ ::Rails.stub!(:env => 'config_disabled_test')
148
+ @config = Sunspot::Rails::Configuration.new
149
+ end
150
+
151
+ it "should handle the 'disabled' property when set" do
152
+ @config.disabled?.should be_true
153
+ end
154
+ end
155
+
156
+ describe Sunspot::Rails::Configuration, "with ENV['SOLR_URL'] overriding sunspot.yml" do
157
+ before(:all) do
158
+ ENV['SOLR_URL'] = 'http://environment.host:5432/solr/env'
159
+ end
160
+
161
+ before(:each) do
162
+ ::Rails.stub!(:env => 'config_test')
163
+ @config = Sunspot::Rails::Configuration.new
164
+ end
165
+
166
+ after(:all) do
167
+ ENV.delete('SOLR_URL')
168
+ end
169
+
170
+ it "should handle the 'hostname' property when set" do
171
+ @config.hostname.should == 'environment.host'
172
+ end
173
+
174
+ it "should handle the 'port' property when set" do
175
+ @config.port.should == 5432
176
+ end
177
+
178
+ it "should handle the 'path' property when set" do
179
+ @config.path.should == '/solr/env'
180
+ end
181
+ end
182
+
183
+ describe Sunspot::Rails::Configuration, "with ENV['WEBSOLR_URL'] overriding sunspot.yml" do
184
+ before(:all) do
185
+ ENV['WEBSOLR_URL'] = 'http://index.websolr.test/solr/a1b2c3d4e5f'
186
+ end
187
+
188
+ before(:each) do
189
+ ::Rails.stub!(:env => 'config_test')
190
+ @config = Sunspot::Rails::Configuration.new
191
+ end
192
+
193
+ after(:all) do
194
+ ENV.delete('WEBSOLR_URL')
195
+ end
196
+
197
+ it "should handle the 'hostname' property when set" do
198
+ @config.hostname.should == 'index.websolr.test'
199
+ end
200
+
201
+ it "should handle the 'port' property when set" do
202
+ @config.port.should == 80
203
+ end
204
+
205
+ it "should handle the 'path' property when set" do
206
+ @config.path.should == '/solr/a1b2c3d4e5f'
207
+ end
208
+ end
209
+
@@ -0,0 +1,63 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe 'searchable with lifecycle' do
4
+ describe 'on create' do
5
+ before :each do
6
+ @post = PostWithAuto.create
7
+ Sunspot.commit
8
+ end
9
+
10
+ it 'should automatically index' do
11
+ PostWithAuto.search.results.should == [@post]
12
+ end
13
+ end
14
+
15
+ describe 'on update' do
16
+ before :each do
17
+ @post = PostWithAuto.create
18
+ @post.update_attributes(:title => 'Test 1')
19
+ Sunspot.commit
20
+ end
21
+
22
+ it 'should automatically update index' do
23
+ PostWithAuto.search { with :title, 'Test 1' }.results.should == [@post]
24
+ end
25
+
26
+ it "should index model if relevant attribute changed" do
27
+ @post = PostWithAuto.create!
28
+ @post.title = 'new title'
29
+ @post.should_receive :solr_index
30
+ @post.save!
31
+ end
32
+
33
+ it "should not index model if relevant attribute not changed" do
34
+ @post = PostWithAuto.create!
35
+ @post.updated_at = Date.tomorrow
36
+ @post.should_not_receive :solr_index
37
+ @post.save!
38
+ end
39
+ end
40
+
41
+ describe 'on destroy' do
42
+ before :each do
43
+ @post = PostWithAuto.create
44
+ @post.destroy
45
+ Sunspot.commit
46
+ end
47
+
48
+ it 'should automatically remove it from the index' do
49
+ PostWithAuto.search_ids.should be_empty
50
+ end
51
+ end
52
+ end
53
+
54
+ describe 'searchable with lifecycle - ignoring specific attributes' do
55
+ before(:each) do
56
+ @post = PostWithAuto.create
57
+ end
58
+
59
+ it "should not reindex the object on an update_at change, because it is marked as to-ignore" do
60
+ Sunspot.should_not_receive(:index).with(@post)
61
+ @post.update_attribute :updated_at, 123.seconds.from_now
62
+ end
63
+ end