robsharp-sunspot_rails 1.1.0.2

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 (55) hide show
  1. data/History.txt +40 -0
  2. data/LICENSE +18 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +256 -0
  5. data/Rakefile +27 -0
  6. data/TODO +8 -0
  7. data/VERSION.yml +4 -0
  8. data/dev_tasks/gemspec.rake +33 -0
  9. data/dev_tasks/rdoc.rake +24 -0
  10. data/dev_tasks/release.rake +4 -0
  11. data/dev_tasks/todo.rake +4 -0
  12. data/generators/sunspot/sunspot_generator.rb +9 -0
  13. data/generators/sunspot/templates/sunspot.yml +18 -0
  14. data/install.rb +1 -0
  15. data/lib/sunspot/rails.rb +58 -0
  16. data/lib/sunspot/rails/adapters.rb +160 -0
  17. data/lib/sunspot/rails/configuration.rb +272 -0
  18. data/lib/sunspot/rails/request_lifecycle.rb +31 -0
  19. data/lib/sunspot/rails/searchable.rb +464 -0
  20. data/lib/sunspot/rails/server.rb +173 -0
  21. data/lib/sunspot/rails/solr_logging.rb +58 -0
  22. data/lib/sunspot/rails/spec_helper.rb +19 -0
  23. data/lib/sunspot/rails/stub_session_proxy.rb +88 -0
  24. data/lib/sunspot/rails/tasks.rb +62 -0
  25. data/lib/sunspot/rails/version.rb +5 -0
  26. data/rails/init.rb +10 -0
  27. data/spec/configuration_spec.rb +102 -0
  28. data/spec/mock_app/app/controllers/application.rb +10 -0
  29. data/spec/mock_app/app/controllers/application_controller.rb +10 -0
  30. data/spec/mock_app/app/controllers/posts_controller.rb +6 -0
  31. data/spec/mock_app/app/models/author.rb +8 -0
  32. data/spec/mock_app/app/models/blog.rb +12 -0
  33. data/spec/mock_app/app/models/location.rb +2 -0
  34. data/spec/mock_app/app/models/photo_post.rb +2 -0
  35. data/spec/mock_app/app/models/post.rb +10 -0
  36. data/spec/mock_app/app/models/post_with_auto.rb +10 -0
  37. data/spec/mock_app/config/boot.rb +110 -0
  38. data/spec/mock_app/config/database.yml +4 -0
  39. data/spec/mock_app/config/environment.rb +42 -0
  40. data/spec/mock_app/config/environments/development.rb +27 -0
  41. data/spec/mock_app/config/environments/test.rb +27 -0
  42. data/spec/mock_app/config/initializers/new_rails_defaults.rb +19 -0
  43. data/spec/mock_app/config/initializers/session_store.rb +15 -0
  44. data/spec/mock_app/config/routes.rb +43 -0
  45. data/spec/mock_app/config/sunspot.yml +19 -0
  46. data/spec/mock_app/db/schema.rb +27 -0
  47. data/spec/model_lifecycle_spec.rb +63 -0
  48. data/spec/model_spec.rb +409 -0
  49. data/spec/request_lifecycle_spec.rb +52 -0
  50. data/spec/schema.rb +27 -0
  51. data/spec/server_spec.rb +36 -0
  52. data/spec/session_spec.rb +24 -0
  53. data/spec/spec_helper.rb +51 -0
  54. data/spec/stub_session_proxy_spec.rb +122 -0
  55. metadata +170 -0
@@ -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
+ 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
+ # 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,58 @@
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
+ if ActiveRecord::Base.colorize_logging
42
+ message_color, dump_color = "4;32;1", "0;1"
43
+ log_entry = " \e[#{message_color}m#{message}\e[0m "
44
+ log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
45
+ log_entry
46
+ else
47
+ "%s %s" % [message, dump]
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ begin
55
+ RSolr::Client.module_eval { include(Sunspot::Rails::SolrLogging) }
56
+ rescue NameError # RSolr 0.9.6
57
+ RSolr::Connection::Base.module_eval { include(Sunspot::Rails::SolrLogging) }
58
+ end
@@ -0,0 +1,19 @@
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
+ Spec::Runner.configure do |config|
18
+ config.extend(Sunspot::Rails::SpecHelper)
19
+ end
@@ -0,0 +1,88 @@
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
+ class Search
60
+ def build
61
+ self
62
+ end
63
+
64
+ def results
65
+ []
66
+ end
67
+
68
+ def hits(options = {})
69
+ []
70
+ end
71
+
72
+ def total
73
+ 0
74
+ end
75
+
76
+ def facet(name)
77
+ end
78
+
79
+ def dynamic_facet(name)
80
+ end
81
+
82
+ def execute
83
+ self
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,62 @@
1
+ namespace :sunspot do
2
+ namespace :solr do
3
+ desc 'Start the Solr instance'
4
+ task :start => :environment do
5
+ if RUBY_PLATFORM =~ /w(in)?32$/
6
+ abort('This command does not work on Windows. Please use rake sunspot:solr:run to run Solr in the foreground.')
7
+ end
8
+ Sunspot::Rails::Server.new.start
9
+ end
10
+
11
+ desc 'Run the Solr instance in the foreground'
12
+ task :run => :environment do
13
+ Sunspot::Rails::Server.new.run
14
+ end
15
+
16
+ desc 'Stop the Solr instance'
17
+ task :stop => :environment do
18
+ if RUBY_PLATFORM =~ /w(in)?32$/
19
+ abort('This command does not work on Windows.')
20
+ end
21
+ Sunspot::Rails::Server.new.stop
22
+ end
23
+
24
+ task :reindex => :"sunspot:reindex"
25
+ end
26
+
27
+ desc "Reindex all solr models that are located in your application's models directory."
28
+ # This task depends on the standard Rails file naming \
29
+ # conventions, in that the file name matches the defined class name. \
30
+ # By default the indexing system works in batches of 500 records, you can \
31
+ # set your own value for this by using the batch_size argument. You can \
32
+ # also optionally define a list of models to separated by a forward slash '/'
33
+ #
34
+ # $ rake sunspot:reindex # reindex all models
35
+ # $ rake sunspot:reindex[1000] # reindex in batches of 1000
36
+ # $ rake sunspot:reindex[false] # reindex without batching
37
+ # $ rake sunspot:reindex[,Post] # reindex only the Post model
38
+ # $ rake sunspot:reindex[1000,Post] # reindex only the Post model in
39
+ # # batchs of 1000
40
+ # $ rake sunspot:reindex[,Post+Author] # reindex Post and Author model
41
+ task :reindex, :batch_size, :models, :needs => :environment do |t, args|
42
+ reindex_options = {:batch_commit => false}
43
+ case args[:batch_size]
44
+ when 'false'
45
+ reindex_options[:batch_size] = nil
46
+ when /^\d+$/
47
+ reindex_options[:batch_size] = args[:batch_size].to_i if args[:batch_size].to_i > 0
48
+ end
49
+ unless args[:models]
50
+ all_files = Dir.glob(File.join(RAILS_ROOT, 'app', 'models', '*.rb'))
51
+ all_models = all_files.map { |path| File.basename(path, '.rb').camelize.constantize }
52
+ # FIXME: Workaround the hack
53
+ sunspot_models = all_models #.select { |m| m < ActiveRecord::Base and m.searchable? }
54
+ else
55
+ sunspot_models = args[:models].split('+').map{|m| m.constantize}
56
+ end
57
+ sunspot_models.each do |model|
58
+ model.solr_reindex reindex_options
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,5 @@
1
+ module Sunspot
2
+ module Rails
3
+ VERSION = '1.1.0'
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ require 'sunspot'
2
+
3
+ Sunspot.session = Sunspot::Rails.build_session
4
+ Sunspot::Adapters::InstanceAdapter.register(Sunspot::Rails::Adapters::ActiveRecordInstanceAdapter, ActiveRecord::Base)
5
+ Sunspot::Adapters::InstanceAdapter.register(Sunspot::Rails::Adapters::ActiveResourceInstanceAdapter, ActiveResource::Base)
6
+ Sunspot::Adapters::DataAccessor.register(Sunspot::Rails::Adapters::ActiveRecordDataAccessor, ActiveRecord::Base)
7
+ Sunspot::Adapters::DataAccessor.register(Sunspot::Rails::Adapters::ActiveResourceDataAccessor, ActiveResource::Base)
8
+ ActiveRecord::Base.module_eval { include(Sunspot::Rails::Searchable) }
9
+ ActiveResource::Base.module_eval { include(Sunspot::Rails::Searchable) }
10
+ ActionController::Base.module_eval { include(Sunspot::Rails::RequestLifecycle) }
@@ -0,0 +1,102 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Sunspot::Rails::Configuration, "default values" do
4
+ before(:each) do
5
+ File.should_receive(:exist?).at_least(:once).and_return(false)
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
+ it "should handle the 'port' property when not set" do
18
+ @config.port.should == 8983
19
+ end
20
+
21
+ it "should handle the 'log_level' property when not set" do
22
+ @config.log_level.should == 'INFO'
23
+ end
24
+
25
+ it "should handle the 'log_file' property" do
26
+ @config.log_file.should =~ /log\/solr_test.log/
27
+ end
28
+
29
+ it "should handle the 'solr_home' property when not set" do
30
+ Rails.should_receive(:root).at_least(1).and_return('/some/path')
31
+ @config.solr_home.should == '/some/path/solr'
32
+ end
33
+
34
+ it "should handle the 'data_path' property when not set" do
35
+ Rails.should_receive(:root).at_least(1).and_return('/some/path')
36
+ @config.data_path.should == '/some/path/solr/data/test'
37
+ end
38
+
39
+ it "should handle the 'pid_path' property when not set" do
40
+ Rails.should_receive(:root).at_least(1).and_return('/some/path')
41
+ @config.pid_path.should == '/some/path/solr/pids/test'
42
+ end
43
+
44
+ it "should handle the 'solr_home' property when not set" do
45
+ @config.solr_home.should_not == nil
46
+ end
47
+
48
+ it "should handle the 'auto_commit_after_request' propery when not set" do
49
+ @config.auto_commit_after_request?.should == true
50
+ end
51
+
52
+ it "should handle the 'auto_commit_after_delete_request' propery when not set" do
53
+ @config.auto_commit_after_delete_request?.should == false
54
+ end
55
+ end
56
+
57
+ describe Sunspot::Rails::Configuration, "user settings" do
58
+ before(:each) do
59
+ ::Rails.stub!(:env => 'config_test')
60
+ @config = Sunspot::Rails::Configuration.new
61
+ end
62
+
63
+ it "should handle the 'hostname' property when set" do
64
+ @config.hostname.should == 'some.host'
65
+ end
66
+
67
+ it "should handle the 'port' property when set" do
68
+ @config.port.should == 1234
69
+ end
70
+
71
+ it "should handle the 'path' property when set" do
72
+ @config.path.should == '/solr/idx'
73
+ end
74
+
75
+ it "should handle the 'log_level' propery when set" do
76
+ @config.log_level.should == 'WARNING'
77
+ end
78
+
79
+ it "should handle the 'solr_home' propery when set" do
80
+ @config.solr_home.should == '/my_superior_path'
81
+ end
82
+
83
+ it "should handle the 'data_path' property when set" do
84
+ @config.data_path.should == '/my_superior_path/data'
85
+ end
86
+
87
+ it "should handle the 'pid_path' property when set" do
88
+ @config.pid_path.should == '/my_superior_path/pids'
89
+ end
90
+
91
+ it "should handle the 'solr_home' property when set" do
92
+ @config.solr_home.should == '/my_superior_path'
93
+ end
94
+
95
+ it "should handle the 'auto_commit_after_request' propery when set" do
96
+ @config.auto_commit_after_request?.should == false
97
+ end
98
+
99
+ it "should handle the 'auto_commit_after_delete_request' propery when set" do
100
+ @config.auto_commit_after_delete_request?.should == true
101
+ end
102
+ end