outoftime-sunspot 0.0.1

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 (100) hide show
  1. data/History.txt +7 -0
  2. data/Manifest.txt +104 -0
  3. data/PostInstall.txt +7 -0
  4. data/README.rdoc +115 -0
  5. data/Rakefile +27 -0
  6. data/config/hoe.rb +74 -0
  7. data/config/requirements.rb +15 -0
  8. data/lib/light_config.rb +40 -0
  9. data/lib/sunspot/adapters.rb +54 -0
  10. data/lib/sunspot/conditions.rb +50 -0
  11. data/lib/sunspot/conditions_builder.rb +37 -0
  12. data/lib/sunspot/configuration.rb +17 -0
  13. data/lib/sunspot/field.rb +108 -0
  14. data/lib/sunspot/field_builder.rb +37 -0
  15. data/lib/sunspot/indexer.rb +65 -0
  16. data/lib/sunspot/query.rb +115 -0
  17. data/lib/sunspot/query_builder.rb +30 -0
  18. data/lib/sunspot/restriction.rb +72 -0
  19. data/lib/sunspot/scope_builder.rb +33 -0
  20. data/lib/sunspot/search.rb +83 -0
  21. data/lib/sunspot/session.rb +43 -0
  22. data/lib/sunspot/type.rb +62 -0
  23. data/lib/sunspot/util.rb +13 -0
  24. data/lib/sunspot/version.rb +10 -0
  25. data/lib/sunspot.rb +50 -0
  26. data/setup.rb +1585 -0
  27. data/solr/README.txt +36 -0
  28. data/solr/etc/jetty.xml +206 -0
  29. data/solr/etc/webdefault.xml +379 -0
  30. data/solr/exampledocs/books.csv +11 -0
  31. data/solr/exampledocs/hd.xml +46 -0
  32. data/solr/exampledocs/ipod_other.xml +50 -0
  33. data/solr/exampledocs/ipod_video.xml +35 -0
  34. data/solr/exampledocs/mem.xml +58 -0
  35. data/solr/exampledocs/monitor.xml +31 -0
  36. data/solr/exampledocs/monitor2.xml +30 -0
  37. data/solr/exampledocs/mp500.xml +39 -0
  38. data/solr/exampledocs/post.jar +0 -0
  39. data/solr/exampledocs/post.sh +28 -0
  40. data/solr/exampledocs/sd500.xml +33 -0
  41. data/solr/exampledocs/solr.xml +38 -0
  42. data/solr/exampledocs/spellchecker.xml +58 -0
  43. data/solr/exampledocs/utf8-example.xml +42 -0
  44. data/solr/exampledocs/vidcard.xml +52 -0
  45. data/solr/lib/jetty-6.1.3.jar +0 -0
  46. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  47. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  48. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  49. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  50. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  51. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  52. data/solr/solr/README.txt +52 -0
  53. data/solr/solr/bin/abc +176 -0
  54. data/solr/solr/bin/abo +176 -0
  55. data/solr/solr/bin/backup +108 -0
  56. data/solr/solr/bin/backupcleaner +142 -0
  57. data/solr/solr/bin/commit +128 -0
  58. data/solr/solr/bin/optimize +129 -0
  59. data/solr/solr/bin/readercycle +129 -0
  60. data/solr/solr/bin/rsyncd-disable +77 -0
  61. data/solr/solr/bin/rsyncd-enable +76 -0
  62. data/solr/solr/bin/rsyncd-start +145 -0
  63. data/solr/solr/bin/rsyncd-stop +105 -0
  64. data/solr/solr/bin/scripts-util +83 -0
  65. data/solr/solr/bin/snapcleaner +148 -0
  66. data/solr/solr/bin/snapinstaller +168 -0
  67. data/solr/solr/bin/snappuller +248 -0
  68. data/solr/solr/bin/snappuller-disable +77 -0
  69. data/solr/solr/bin/snappuller-enable +77 -0
  70. data/solr/solr/bin/snapshooter +109 -0
  71. data/solr/solr/conf/admin-extra.html +31 -0
  72. data/solr/solr/conf/protwords.txt +21 -0
  73. data/solr/solr/conf/schema.xml +231 -0
  74. data/solr/solr/conf/scripts.conf +24 -0
  75. data/solr/solr/conf/solrconfig.xml +394 -0
  76. data/solr/solr/conf/stopwords.txt +57 -0
  77. data/solr/solr/conf/synonyms.txt +31 -0
  78. data/solr/start.jar +0 -0
  79. data/solr/webapps/solr.war +0 -0
  80. data/tasks/deployment.rake +34 -0
  81. data/tasks/environment.rake +7 -0
  82. data/tasks/rcov.rake +6 -0
  83. data/tasks/solr.rake +12 -0
  84. data/tasks/website.rake +17 -0
  85. data/test/api/test_build_search.rb +216 -0
  86. data/test/api/test_helper.rb +4 -0
  87. data/test/api/test_indexer.rb +110 -0
  88. data/test/api/test_retrieve_search.rb +114 -0
  89. data/test/api/test_session.rb +46 -0
  90. data/test/custom_expectation.rb +53 -0
  91. data/test/integration/test_field_types.rb +62 -0
  92. data/test/integration/test_helper.rb +1 -0
  93. data/test/integration/test_keyword_search.rb +32 -0
  94. data/test/integration/test_pagination.rb +32 -0
  95. data/test/mocks/base_class.rb +2 -0
  96. data/test/mocks/comment.rb +28 -0
  97. data/test/mocks/mock_adapter.rb +25 -0
  98. data/test/mocks/post.rb +41 -0
  99. data/test/test_helper.rb +31 -0
  100. metadata +191 -0
@@ -0,0 +1,37 @@
1
+ module Sunspot
2
+ class FieldBuilder
3
+ def initialize(clazz)
4
+ @clazz = clazz
5
+ end
6
+
7
+ def text(*names, &block)
8
+ for name in names
9
+ ::Sunspot::Field.register_text clazz, build_field(name, ::Sunspot::Type::TextType, &block)
10
+ end
11
+ end
12
+
13
+ def method_missing(method, *args, &block)
14
+ begin
15
+ type = ::Sunspot::Type.const_get "#{method.to_s.camel_case}Type"
16
+ rescue(NameError)
17
+ super(method.to_sym, *args, &block) and return
18
+ end
19
+ name = args.shift
20
+ ::Sunspot::Field.register clazz, build_field(name, type, *args, &block)
21
+ end
22
+
23
+ protected
24
+ attr_reader :clazz
25
+
26
+ private
27
+
28
+ def build_field(name, type, *args, &block)
29
+ options = args.shift if args.first.is_a?(Hash)
30
+ unless block
31
+ ::Sunspot::Field::AttributeField.new(name, type, options || {})
32
+ else
33
+ ::Sunspot::Field::VirtualField.new(name, type, options || {}, &block)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,65 @@
1
+ module Sunspot
2
+ class Indexer
3
+ def initialize(connection)
4
+ @connection = connection
5
+ end
6
+
7
+ def add(model)
8
+ hash = static_hash_for model
9
+ for field in fields
10
+ hash.merge! field.pair_for(model)
11
+ end
12
+ connection.add hash
13
+ end
14
+
15
+ def fields
16
+ @fields ||= []
17
+ end
18
+
19
+ def add_fields(fields)
20
+ self.fields.concat fields
21
+ end
22
+
23
+ def remove(model)
24
+ connection.delete(::Sunspot::Adapters.adapt_instance(model).index_id)
25
+ end
26
+
27
+ protected
28
+ attr_reader :connection
29
+
30
+ def static_hash_for(model)
31
+ { :id => ::Sunspot::Adapters.adapt_instance(model).index_id,
32
+ :type => Indexer.superclasses_for(model.class).map { |clazz| clazz.name }}
33
+ end
34
+ end
35
+
36
+ class <<Indexer
37
+ def add(connection, model)
38
+ self.for(model.class, connection).add(model)
39
+ end
40
+
41
+ def remove(connection, model)
42
+ self.for(model.class, connection).remove(model)
43
+ end
44
+
45
+ def remove_all(connection, clazz = nil)
46
+ connection.delete_by_query("type:#{clazz ? clazz.name : '[* TO *]'}")
47
+ end
48
+
49
+ def for(clazz, connection)
50
+ indexer = self.new(connection)
51
+ for superclass in superclasses_for(clazz)
52
+ indexer.add_fields ::Sunspot::Field.for(superclass)
53
+ indexer.add_fields ::Sunspot::Field.text_for(superclass)
54
+ end
55
+ raise ArgumentError, "Class #{clazz.name} has not been configured for indexing" if indexer.fields.empty?
56
+ indexer
57
+ end
58
+
59
+ def superclasses_for(clazz)
60
+ superclasses_for = [clazz]
61
+ superclasses_for << (clazz = clazz.superclass) while clazz.superclass != Object
62
+ superclasses_for
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,115 @@
1
+ module Sunspot
2
+ class Query
3
+ attr_accessor :keywords, :conditions, :rows, :start, :sort
4
+
5
+ def initialize(types, params, configuration)
6
+ @keywords, @types, @configuration = params[:keywords], types, configuration
7
+ @conditions = Sunspot::Conditions.new(self, params[:conditions] || {})
8
+ paginate(params[:page], params[:per_page])
9
+ self.order = params[:order] if params[:order]
10
+ attributes[:keywords] = @keywords
11
+ params[:conditions].each_pair do |field_name, value|
12
+ attributes[:conditions][field_name.to_sym] = value
13
+ end if params[:conditions]
14
+ end
15
+
16
+ def to_solr
17
+ query_components = []
18
+ query_components << keywords if keywords
19
+ query_components << types_query if types_query
20
+ query_components.map { |component| "(#{component})"} * ' AND '
21
+ end
22
+
23
+ def filter_queries
24
+ scope_queries + condition_queries
25
+ end
26
+
27
+ def add_scope(condition)
28
+ scope << condition
29
+ end
30
+
31
+ def build_condition(field_name, condition_clazz, value)
32
+ condition_clazz.new(field(field_name), value)
33
+ end
34
+
35
+ def paginate(page = nil, per_page = nil)
36
+ page ||= 1
37
+ per_page ||= configuration.pagination.default_per_page
38
+ @start = (page - 1) * per_page
39
+ @rows = per_page
40
+ attributes[:page], attributes[:per_page] = page, per_page
41
+ end
42
+
43
+ def order=(order)
44
+ order_by(*order.split(' '))
45
+ end
46
+
47
+ def order_by(field_name, direction = nil)
48
+ direction ||= :asc
49
+ @sort = [{ field(field_name).indexed_name.to_sym => (direction.to_s == 'asc' ? :ascending : :descending) }] #TODO should support multiple order columns
50
+ attributes[:order] = "#{field_name} #{direction}"
51
+ end
52
+
53
+ def page
54
+ return nil unless start && rows
55
+ start / rows + 1
56
+ end
57
+
58
+ def attributes
59
+ @attributes ||= {
60
+ :order => nil,
61
+ :conditions => fields_hash.keys.inject({}) { |conditions, key| conditions[key.to_sym] = nil; conditions }
62
+ }
63
+ end
64
+
65
+ alias_method :per_page, :rows
66
+
67
+ protected
68
+ attr_accessor :types, :configuration
69
+
70
+ private
71
+
72
+ def scope
73
+ @scope ||= []
74
+ end
75
+
76
+ def scope_queries
77
+ scope.map { |condition| condition.to_solr_query }
78
+ end
79
+
80
+ def condition_queries
81
+ conditions.restrictions.map { |condition| condition.to_solr_query }
82
+ end
83
+
84
+ def types_query
85
+ if types.nil? || types.empty? then "type:[* TO *]"
86
+ elsif types.length == 1 then "type:#{types.first}"
87
+ else "type:(#{types * ' OR '})"
88
+ end
89
+ end
90
+
91
+ def field(field_name)
92
+ fields_hash[field_name.to_s] || raise(ArgumentError, "No field configured for #{types * ', '} with name '#{field_name}'")
93
+ end
94
+
95
+ def fields_hash
96
+ @fields_hash ||= begin
97
+ fields_hash = types.inject({}) do |hash, type|
98
+ ::Sunspot::Field.for(type).each do |field|
99
+ (hash[field.name.to_s] ||= {})[type.name] = field
100
+ end
101
+ hash
102
+ end
103
+ fields_hash.each_pair do |field_name, field_configurations_hash|
104
+ if types.any? { |type| field_configurations_hash[type.name].nil? } # at least one type doesn't have this field configured
105
+ fields_hash.delete(field_name)
106
+ elsif field_configurations_hash.values.map { |configuration| configuration.indexed_name }.uniq.length != 1 # fields with this name have different configs
107
+ fields_hash.delete(field_name)
108
+ else
109
+ fields_hash[field_name] = field_configurations_hash.values.first
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,30 @@
1
+ module Sunspot
2
+ class QueryBuilder
3
+ def initialize(query)
4
+ @query = query
5
+ end
6
+
7
+ def keywords(keywords)
8
+ @query.keywords = keywords
9
+ end
10
+
11
+ def with
12
+ @conditions_builder ||= ::Sunspot::ScopeBuilder.new(@query)
13
+ end
14
+
15
+ def conditions
16
+ @query.conditions
17
+ end
18
+
19
+ def paginate(options = {})
20
+ page = options.delete(:page) || raise(ArgumentError, "paginate requires a :page argument")
21
+ per_page = options.delete(:per_page)
22
+ raise ArgumentError, "unknown argument #{options.keys.first.inspect} passed to paginate" unless options.empty?
23
+ @query.paginate(page, per_page)
24
+ end
25
+
26
+ def order_by(field_name, direction = nil)
27
+ @query.order_by(field_name, direction)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,72 @@
1
+ module Sunspot
2
+ module Restriction
3
+ class Base
4
+ def initialize(field, value)
5
+ @field, @value = field, value
6
+ end
7
+
8
+ def to_solr_query
9
+ "#{field.indexed_name}:#{to_solr_conditional}"
10
+ end
11
+
12
+ protected
13
+ attr_accessor :field, :value
14
+
15
+ def solr_value(value = self.value)
16
+ escape field.to_indexed(value)
17
+ end
18
+
19
+ def escape(value)
20
+ Solr::Util.query_parser_escape value
21
+ end
22
+ end
23
+
24
+ class EqualTo < Base
25
+ private
26
+
27
+ def to_solr_conditional
28
+ "#{solr_value}"
29
+ end
30
+ end
31
+
32
+ class LessThan < Base
33
+ private
34
+
35
+ def to_solr_conditional
36
+ "[* TO #{solr_value}]"
37
+ end
38
+ end
39
+
40
+ class GreaterThan < Base
41
+ private
42
+
43
+ def to_solr_conditional
44
+ "[#{solr_value} TO *]"
45
+ end
46
+ end
47
+
48
+ class Between < Base
49
+ private
50
+
51
+ def to_solr_conditional
52
+ "[#{solr_value value.first} TO #{solr_value value.last}]"
53
+ end
54
+ end
55
+
56
+ class AnyOf < Base
57
+ private
58
+
59
+ def to_solr_conditional
60
+ "(#{value.map { |v| solr_value v } * ' OR '})"
61
+ end
62
+ end
63
+
64
+ class AllOf < Base
65
+ private
66
+
67
+ def to_solr_conditional
68
+ "(#{value.map { |v| solr_value v } * ' AND '})"
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,33 @@
1
+ module Sunspot
2
+ class ScopeBuilder
3
+ def initialize(query)
4
+ @query = query
5
+ end
6
+
7
+ def method_missing(field_name, *args)
8
+ if args.length == 0 then RestrictionBuilder.new(field_name, @query)
9
+ elsif args.length == 1 then @query.add_scope @query.build_condition(field_name, ::Sunspot::Restriction::EqualTo, args.first)
10
+ else super(field_name.to_sym, *args)
11
+ end
12
+ end
13
+
14
+ class RestrictionBuilder
15
+ def initialize(field_name, query)
16
+ @field_name, @query = field_name, query
17
+ end
18
+
19
+ def method_missing(condition_name, *args)
20
+ clazz = begin
21
+ ::Sunspot::Restriction.const_get(condition_name.to_s.camel_case)
22
+ rescue(NameError)
23
+ super(condition_name.to_sym, *args)
24
+ end
25
+ if value = args.first
26
+ @query.add_scope @query.build_condition(@field_name, clazz, args.first)
27
+ else
28
+ @query.interpret_condition @field_name, clazz
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,83 @@
1
+ module Sunspot
2
+ class Search
3
+ def initialize(connection, configuration, *types, &block)
4
+ @connection = connection
5
+ params = types.last.is_a?(Hash) ? types.pop : {}
6
+ @query = Sunspot::Query.new(types, params, configuration)
7
+ QueryBuilder.new(@query).instance_eval(&block) if block
8
+ @types = types
9
+ end
10
+
11
+ def execute!
12
+ query_options = {}
13
+ query_options[:filter_queries] = query.filter_queries
14
+ query_options[:rows] = query.rows
15
+ query_options[:start] = query.start if query.start
16
+ query_options[:sort] = query.sort if query.sort
17
+ @solr_result = connection.query(query.to_solr, query_options)
18
+ self
19
+ end
20
+
21
+ def results
22
+ @results ||= if query.page && defined?(WillPaginate::Collection)
23
+ WillPaginate::Collection.create(query.page, query.per_page, @solr_result.total_hits) do |pager|
24
+ pager.replace(result_objects)
25
+ end
26
+ else
27
+ result_objects
28
+ end
29
+ end
30
+
31
+ def total
32
+ @total ||= @solr_result.total_hits
33
+ end
34
+
35
+ def attributes
36
+ @query.attributes
37
+ end
38
+
39
+ def order
40
+ @query.attributes[:order]
41
+ end
42
+
43
+ def page
44
+ @query.attributes[:page]
45
+ end
46
+
47
+ def per_page
48
+ @query.attributes[:per_page]
49
+ end
50
+
51
+ def keywords
52
+ @query.attributes[:keywords]
53
+ end
54
+
55
+ def conditions
56
+ ::Sunspot::Util::ClosedStruct.new(@query.attributes[:conditions])
57
+ end
58
+
59
+ protected
60
+ attr_reader :query, :types, :connection
61
+
62
+ private
63
+
64
+ def result_objects
65
+ hit_ids = @solr_result.hits.map { |hit| hit['id'] }
66
+ hit_ids.inject({}) do |type_id_hash, hit_id|
67
+ match = /([^ ]+) (.+)/.match hit_id
68
+ (type_id_hash[match[1]] ||= []) << match[2]
69
+ type_id_hash
70
+ end.inject([]) do |results, pair|
71
+ type_name, ids = pair
72
+ results.concat ::Sunspot::Adapters.adapt_class(type_with_name(type_name)).load_all(ids)
73
+ end.sort_by do |result|
74
+ hit_ids.index(::Sunspot::Adapters.adapt_instance(result).index_id)
75
+ end
76
+ end
77
+
78
+ def type_with_name(type_name)
79
+ @types_cache ||= {}
80
+ @types_cache[type_name] ||= type_name.split('::').inject(Module) { |namespace, name| namespace.const_get(name) }
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,43 @@
1
+ module Sunspot
2
+ class Session
3
+ attr_reader :config
4
+
5
+ def initialize(config = Sunspot::Configuration.build, connection = nil)
6
+ @config = config
7
+ yield(@config) if block_given?
8
+ @connection = connection
9
+ end
10
+
11
+ def search(*types, &block)
12
+ ::Sunspot::Search.new(connection, @config, *types, &block).execute!
13
+ end
14
+
15
+ def index(*objects)
16
+ for object in objects
17
+ ::Sunspot::Indexer.add(connection, object)
18
+ end
19
+ end
20
+
21
+ def remove(*objects)
22
+ for object in objects
23
+ ::Sunspot::Indexer.remove(connection, object)
24
+ end
25
+ end
26
+
27
+ def remove_all(*classes)
28
+ if classes.empty?
29
+ ::Sunspot::Indexer.remove_all(connection)
30
+ else
31
+ classes.each do |clazz|
32
+ ::Sunspot::Indexer.remove_all(connection, clazz)
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def connection
40
+ @connection ||= Solr::Connection.new(config.solr.url, :autocommit => :on)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,62 @@
1
+ module Sunspot
2
+ module Type
3
+ TextType = Module.new
4
+ StringType = Module.new
5
+ IntegerType = Module.new
6
+ FloatType = Module.new
7
+ TimeType = Module.new
8
+
9
+ class <<TextType
10
+ def indexed_name(name)
11
+ "#{name}_text"
12
+ end
13
+
14
+ def to_indexed(value)
15
+ value.to_s if value
16
+ end
17
+ end
18
+
19
+ class <<StringType
20
+ def indexed_name(name)
21
+ "#{name}_s"
22
+ end
23
+
24
+ def to_indexed(value)
25
+ value.to_s if value
26
+ end
27
+ end
28
+
29
+ class <<IntegerType
30
+ def indexed_name(name)
31
+ "#{name}_i"
32
+ end
33
+
34
+ def to_indexed(value)
35
+ value.to_i.to_s if value
36
+ end
37
+ end
38
+
39
+ class <<FloatType
40
+ def indexed_name(name)
41
+ "#{name}_f"
42
+ end
43
+
44
+ def to_indexed(value)
45
+ value.to_f.to_s if value
46
+ end
47
+ end
48
+
49
+ class <<TimeType
50
+ def indexed_name(name)
51
+ "#{name}_d"
52
+ end
53
+
54
+ def to_indexed(value)
55
+ if value
56
+ time = value.respond_to?(:to_time) ? value.to_time : Time.parse(value.to_s)
57
+ time.utc.strftime('%FT%TZ')
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,13 @@
1
+ module Sunspot
2
+ module Util
3
+ class ClosedStruct
4
+ def initialize(data)
5
+ (class <<self; self; end).module_eval do
6
+ data.each_pair do |attr_name, value|
7
+ define_method(attr_name.to_s) { value }
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module Sunspot
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ self
9
+ end
10
+ end
data/lib/sunspot.rb ADDED
@@ -0,0 +1,50 @@
1
+ require 'rubygems'
2
+ gem 'solr-ruby'
3
+ gem 'extlib'
4
+ require 'solr'
5
+ require 'extlib'
6
+ require File.join(File.dirname(__FILE__), 'light_config')
7
+
8
+ %w(adapters restriction conditions configuration field field_builder indexer query query_builder scope_builder search session type util).each do |filename|
9
+ require File.join(File.dirname(__FILE__), 'sunspot', filename)
10
+ end
11
+
12
+ module Sunspot
13
+ VERSION='0.0.1'
14
+ end
15
+
16
+ class <<Sunspot
17
+ def setup(clazz, &block)
18
+ ::Sunspot::FieldBuilder.new(clazz).instance_eval(&block) if block
19
+ end
20
+
21
+ def index(*objects)
22
+ session.index(*objects)
23
+ end
24
+
25
+ def search(*types, &block)
26
+ session.search(*types, &block)
27
+ end
28
+
29
+ def remove(*objects)
30
+ session.remove(*objects)
31
+ end
32
+
33
+ def remove_all(*classes)
34
+ session.remove_all(*classes)
35
+ end
36
+
37
+ def config
38
+ session.config
39
+ end
40
+
41
+ def reset!
42
+ @session = nil
43
+ end
44
+
45
+ private
46
+
47
+ def session
48
+ @session ||= ::Sunspot::Session.new
49
+ end
50
+ end