sunspot 2.0.0 → 2.1.0
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.
- data/lib/sunspot/adapters.rb +64 -17
- data/lib/sunspot/configuration.rb +1 -1
- data/lib/sunspot/query/dismax.rb +4 -4
- data/lib/sunspot/query/restriction.rb +27 -2
- data/lib/sunspot/version.rb +1 -1
- data/spec/api/adapters_spec.rb +12 -0
- data/spec/api/query/fulltext_examples.rb +4 -4
- data/spec/api/query/geo_examples.rb +4 -4
- data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +1 -1
- data/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +1 -1
- data/spec/api/session_proxy/sharding_session_proxy_spec.rb +1 -1
- data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +1 -1
- data/spec/api/session_spec.rb +2 -2
- data/spec/helpers/integration_helper.rb +1 -1
- data/spec/helpers/query_helper.rb +1 -1
- data/spec/integration/keyword_search_spec.rb +28 -0
- data/spec/integration/scoped_search_spec.rb +39 -1
- data/spec/mocks/adapters.rb +3 -0
- metadata +11 -12
data/lib/sunspot/adapters.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
1
3
|
module Sunspot
|
2
4
|
#
|
3
5
|
# Sunspot works by saving references to the primary key (or natural ID) of
|
@@ -46,7 +48,7 @@ module Sunspot
|
|
46
48
|
# end
|
47
49
|
#
|
48
50
|
# # then in your initializer
|
49
|
-
# Sunspot::Adapters::InstanceAdapter.register(
|
51
|
+
# Sunspot::Adapters::InstanceAdapter.register(FileAdapter, File)
|
50
52
|
#
|
51
53
|
class InstanceAdapter
|
52
54
|
def initialize(instance) #:nodoc:
|
@@ -119,16 +121,28 @@ module Sunspot
|
|
119
121
|
#
|
120
122
|
# Sunspot::NoAdapterError:: If no adapter is registered for this class
|
121
123
|
#
|
122
|
-
def for(clazz)
|
123
|
-
|
124
|
-
|
125
|
-
next if ancestor_class.name.nil? || ancestor_class.name.empty?
|
126
|
-
class_name = ancestor_class.name.to_sym
|
127
|
-
return instance_adapters[class_name] if instance_adapters[class_name]
|
128
|
-
end
|
129
|
-
|
124
|
+
def for(clazz)
|
125
|
+
adapter = registered_adapter_for(clazz) || registered_adapter_for_ancestors_of(clazz)
|
126
|
+
return adapter if adapter
|
130
127
|
raise(Sunspot::NoAdapterError,
|
131
|
-
"No adapter is configured for #{
|
128
|
+
"No adapter is configured for #{clazz.name} or its superclasses. See the documentation for Sunspot::Adapters")
|
129
|
+
end
|
130
|
+
|
131
|
+
# Returns the directly-registered adapter for the specified class,
|
132
|
+
# if one exists, without searching the class's ancestors.
|
133
|
+
#
|
134
|
+
# === Parameters
|
135
|
+
#
|
136
|
+
# clazz<Class>:: The model class to be checked for the registered
|
137
|
+
# adapter
|
138
|
+
#
|
139
|
+
# === Returns
|
140
|
+
#
|
141
|
+
# Class:: Subclass of InstanceAdapter, or nil if none found
|
142
|
+
#
|
143
|
+
def registered_adapter_for(clazz)
|
144
|
+
return nil if clazz.name.nil? || clazz.name.empty?
|
145
|
+
instance_adapters[clazz.name.to_sym]
|
132
146
|
end
|
133
147
|
|
134
148
|
def index_id_for(class_name, id) #:nodoc:
|
@@ -146,6 +160,16 @@ module Sunspot
|
|
146
160
|
def instance_adapters #:nodoc:
|
147
161
|
@instance_adapters ||= {}
|
148
162
|
end
|
163
|
+
|
164
|
+
def registered_adapter_for_ancestors_of(clazz) # :nodoc:
|
165
|
+
clazz.ancestors.each do |ancestor_class|
|
166
|
+
if adapter = registered_adapter_for(ancestor_class)
|
167
|
+
register(adapter, clazz)
|
168
|
+
return adapter
|
169
|
+
end
|
170
|
+
end
|
171
|
+
nil
|
172
|
+
end
|
149
173
|
end
|
150
174
|
end
|
151
175
|
|
@@ -247,14 +271,27 @@ module Sunspot
|
|
247
271
|
# Sunspot::NoAdapterError:: If no data accessor exists for the given class
|
248
272
|
#
|
249
273
|
def for(clazz) #:nodoc:
|
250
|
-
|
251
|
-
|
252
|
-
next if ancestor_class.name.nil? || ancestor_class.name.empty?
|
253
|
-
class_name = ancestor_class.name.to_sym
|
254
|
-
return data_accessors[class_name] if data_accessors[class_name]
|
255
|
-
end
|
274
|
+
accessor = registered_accessor_for(clazz) || registered_accessor_for_ancestors_of(clazz)
|
275
|
+
return accessor if accessor
|
256
276
|
raise(Sunspot::NoAdapterError,
|
257
|
-
"No data accessor is configured for #{
|
277
|
+
"No data accessor is configured for #{clazz.name} or its superclasses. See the documentation for Sunspot::Adapters")
|
278
|
+
end
|
279
|
+
|
280
|
+
# Returns the directly-registered accessor for the specified class, if
|
281
|
+
# one exists, without searching the class's ancestors.
|
282
|
+
#
|
283
|
+
# === Parameters
|
284
|
+
#
|
285
|
+
# clazz<Class>:: The model class to be checked for the registered
|
286
|
+
# data accessor
|
287
|
+
#
|
288
|
+
# === Returns
|
289
|
+
#
|
290
|
+
# Class:: Subclass of DataAccessor, or nil if none found
|
291
|
+
#
|
292
|
+
def registered_accessor_for(clazz)
|
293
|
+
return nil if clazz.name.nil? || clazz.name.empty?
|
294
|
+
data_accessors[clazz.name.to_sym]
|
258
295
|
end
|
259
296
|
|
260
297
|
protected
|
@@ -268,6 +305,16 @@ module Sunspot
|
|
268
305
|
def data_accessors #:nodoc:
|
269
306
|
@adapters ||= {}
|
270
307
|
end
|
308
|
+
|
309
|
+
def registered_accessor_for_ancestors_of(clazz) # :nodoc:
|
310
|
+
clazz.ancestors.each do |ancestor_class|
|
311
|
+
if accessor = registered_accessor_for(ancestor_class)
|
312
|
+
register(accessor, clazz)
|
313
|
+
return accessor
|
314
|
+
end
|
315
|
+
end
|
316
|
+
nil
|
317
|
+
end
|
271
318
|
end
|
272
319
|
end
|
273
320
|
|
data/lib/sunspot/query/dismax.rb
CHANGED
@@ -30,7 +30,7 @@ module Sunspot
|
|
30
30
|
params = { :q => @keywords }
|
31
31
|
params[:fl] = '* score'
|
32
32
|
params[:qf] = @fulltext_fields.values.map { |field| field.to_boosted_field }.join(' ')
|
33
|
-
params[:defType] = '
|
33
|
+
params[:defType] = 'edismax'
|
34
34
|
if @phrase_fields
|
35
35
|
params[:pf] = @phrase_fields.map { |field| field.to_boosted_field }.join(' ')
|
36
36
|
end
|
@@ -71,7 +71,7 @@ module Sunspot
|
|
71
71
|
params.delete :fl
|
72
72
|
keywords = params.delete(:q)
|
73
73
|
options = params.map { |key, value| escape_param(key, value) }.join(' ')
|
74
|
-
"_query_:\"{!
|
74
|
+
"_query_:\"{!edismax #{options}}#{escape_quotes(keywords)}\""
|
75
75
|
end
|
76
76
|
|
77
77
|
#
|
@@ -82,7 +82,7 @@ module Sunspot
|
|
82
82
|
boost_query
|
83
83
|
end
|
84
84
|
|
85
|
-
#
|
85
|
+
#
|
86
86
|
# Add a boost function
|
87
87
|
#
|
88
88
|
def add_boost_function(function_query)
|
@@ -123,7 +123,7 @@ module Sunspot
|
|
123
123
|
|
124
124
|
|
125
125
|
private
|
126
|
-
|
126
|
+
|
127
127
|
def escape_param(key, value)
|
128
128
|
"#{key}='#{escape_quotes(Array(value).join(" "))}'"
|
129
129
|
end
|
@@ -273,10 +273,23 @@ module Sunspot
|
|
273
273
|
# Results must have field with value included in given collection
|
274
274
|
#
|
275
275
|
class AnyOf < Base
|
276
|
+
|
277
|
+
def negated?
|
278
|
+
if @value.empty?
|
279
|
+
false
|
280
|
+
else
|
281
|
+
super
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
276
285
|
private
|
277
286
|
|
278
287
|
def to_solr_conditional
|
279
|
-
|
288
|
+
if @value.empty?
|
289
|
+
"[* TO *]"
|
290
|
+
else
|
291
|
+
"(#{@value.map { |v| solr_value v } * ' OR '})"
|
292
|
+
end
|
280
293
|
end
|
281
294
|
end
|
282
295
|
|
@@ -285,10 +298,22 @@ module Sunspot
|
|
285
298
|
# collection (only makes sense for fields with multiple values)
|
286
299
|
#
|
287
300
|
class AllOf < Base
|
301
|
+
def negated?
|
302
|
+
if @value.empty?
|
303
|
+
false
|
304
|
+
else
|
305
|
+
super
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
288
309
|
private
|
289
310
|
|
290
311
|
def to_solr_conditional
|
291
|
-
|
312
|
+
if @value.empty?
|
313
|
+
"[* TO *]"
|
314
|
+
else
|
315
|
+
"(#{@value.map { |v| solr_value v } * ' AND '})"
|
316
|
+
end
|
292
317
|
end
|
293
318
|
end
|
294
319
|
|
data/lib/sunspot/version.rb
CHANGED
data/spec/api/adapters_spec.rb
CHANGED
@@ -14,6 +14,12 @@ describe Sunspot::Adapters::InstanceAdapter do
|
|
14
14
|
Sunspot::Adapters::InstanceAdapter::for(Module.new)
|
15
15
|
end.should raise_error(Sunspot::NoAdapterError)
|
16
16
|
end
|
17
|
+
|
18
|
+
it "registers adapters found by ancestor lookup with the descendant class" do
|
19
|
+
Sunspot::Adapters::InstanceAdapter::registered_adapter_for(UnseenModel).should be(nil)
|
20
|
+
Sunspot::Adapters::InstanceAdapter::for(UnseenModel)
|
21
|
+
Sunspot::Adapters::InstanceAdapter::registered_adapter_for(UnseenModel).should be(AbstractModelInstanceAdapter)
|
22
|
+
end
|
17
23
|
end
|
18
24
|
|
19
25
|
describe Sunspot::Adapters::DataAccessor do
|
@@ -30,6 +36,12 @@ describe Sunspot::Adapters::DataAccessor do
|
|
30
36
|
Sunspot::Adapters::DataAccessor::for(Module.new)
|
31
37
|
end.should raise_error(Sunspot::NoAdapterError)
|
32
38
|
end
|
39
|
+
|
40
|
+
it "registers adapters found by ancestor lookup with the descendant class" do
|
41
|
+
Sunspot::Adapters::DataAccessor::registered_accessor_for(UnseenModel).should be(nil)
|
42
|
+
Sunspot::Adapters::DataAccessor::for(UnseenModel)
|
43
|
+
Sunspot::Adapters::DataAccessor::registered_accessor_for(UnseenModel).should be(AbstractModelDataAccessor)
|
44
|
+
end
|
33
45
|
end
|
34
46
|
|
35
47
|
describe Sunspot::Adapters::Registry do
|
@@ -10,21 +10,21 @@ shared_examples_for 'fulltext query' do
|
|
10
10
|
search do
|
11
11
|
keywords ''
|
12
12
|
end
|
13
|
-
connection.should_not have_last_search_with(:defType => '
|
13
|
+
connection.should_not have_last_search_with(:defType => 'edismax')
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'ignores keywords if nil' do
|
17
17
|
search do
|
18
18
|
keywords nil
|
19
19
|
end
|
20
|
-
connection.should_not have_last_search_with(:defType => '
|
20
|
+
connection.should_not have_last_search_with(:defType => 'edismax')
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'ignores keywords with only whitespace' do
|
24
24
|
search do
|
25
25
|
keywords " \t"
|
26
26
|
end
|
27
|
-
connection.should_not have_last_search_with(:defType => '
|
27
|
+
connection.should_not have_last_search_with(:defType => 'edismax')
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'gracefully ignores keywords block if keywords ignored' do
|
@@ -37,7 +37,7 @@ shared_examples_for 'fulltext query' do
|
|
37
37
|
search do
|
38
38
|
keywords 'keyword search'
|
39
39
|
end
|
40
|
-
connection.should have_last_search_with(:defType => '
|
40
|
+
connection.should have_last_search_with(:defType => 'edismax')
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'searches types in filter query if keywords used' do
|
@@ -41,11 +41,11 @@ shared_examples_for 'geohash query' do
|
|
41
41
|
fulltext 'pizza', :fields => :title
|
42
42
|
with(:coordinates).near(40.7, -73.5)
|
43
43
|
end
|
44
|
-
expected =
|
45
|
-
"{!
|
44
|
+
expected =
|
45
|
+
"{!edismax fl='* score' qf='title_text'}pizza (#{build_geo_query})"
|
46
46
|
connection.should have_last_search_including(
|
47
47
|
:q,
|
48
|
-
%Q(_query_:"{!
|
48
|
+
%Q(_query_:"{!edismax qf='title_text'}pizza" (#{build_geo_query}))
|
49
49
|
)
|
50
50
|
end
|
51
51
|
|
@@ -57,7 +57,7 @@ shared_examples_for 'geohash query' do
|
|
57
57
|
boost = options[:boost] || 1.0
|
58
58
|
hash = 'dr5xx3nytvgs'
|
59
59
|
(precision..12).map do |i|
|
60
|
-
phrase =
|
60
|
+
phrase =
|
61
61
|
if i == 12 then hash
|
62
62
|
else "#{hash[0, i]}*"
|
63
63
|
end
|
@@ -68,7 +68,7 @@ describe Sunspot::SessionProxy::ClassShardingSessionProxy do
|
|
68
68
|
|
69
69
|
[:dirty, :delete_dirty].each do |method|
|
70
70
|
it "should be dirty if any of the sessions are dirty" do
|
71
|
-
@proxy.post_session.stub
|
71
|
+
@proxy.post_session.stub(:"#{method}?").and_return(true)
|
72
72
|
@proxy.should send("be_#{method}")
|
73
73
|
end
|
74
74
|
|
@@ -53,7 +53,7 @@ describe Sunspot::SessionProxy::Retry5xxSessionProxy do
|
|
53
53
|
|
54
54
|
@sunspot_session.should_receive(:index).and_return do
|
55
55
|
@sunspot_session.should_receive(:index).and_return do
|
56
|
-
@sunspot_session.stub
|
56
|
+
@sunspot_session.stub(:index).and_return(fake_success)
|
57
57
|
raise e
|
58
58
|
end
|
59
59
|
raise e
|
@@ -60,7 +60,7 @@ describe Sunspot::SessionProxy::ShardingSessionProxy do
|
|
60
60
|
|
61
61
|
[:dirty, :delete_dirty].each do |method|
|
62
62
|
it "should be dirty if any of the sessions are dirty" do
|
63
|
-
@proxy.sessions[0].stub
|
63
|
+
@proxy.sessions[0].stub(:"#{method}?").and_return(true)
|
64
64
|
@proxy.should send("be_#{method}")
|
65
65
|
end
|
66
66
|
|
@@ -13,7 +13,7 @@ describe Sunspot::SessionProxy::ShardingSessionProxy do
|
|
13
13
|
it "should call rescued_exception when an exception is caught" do
|
14
14
|
SUPPORTED_METHODS.each do |method|
|
15
15
|
e = FakeException.new(method)
|
16
|
-
@search_session.stub
|
16
|
+
@search_session.stub(method).and_raise(e)
|
17
17
|
@proxy.should_receive(:rescued_exception).with(method, e)
|
18
18
|
@proxy.send(method)
|
19
19
|
end
|
data/spec/api/session_spec.rb
CHANGED
@@ -77,7 +77,7 @@ describe 'Session' do
|
|
77
77
|
|
78
78
|
it 'should open connection with defaults if nothing specified' do
|
79
79
|
Sunspot.commit
|
80
|
-
connection.opts[:url].should == 'http://127.0.0.1:8983/solr'
|
80
|
+
connection.opts[:url].should == 'http://127.0.0.1:8983/solr/default'
|
81
81
|
end
|
82
82
|
|
83
83
|
it 'should open a connection with custom host' do
|
@@ -217,7 +217,7 @@ describe 'Session' do
|
|
217
217
|
|
218
218
|
context 'session proxy' do
|
219
219
|
it 'should send messages to manually assigned session proxy' do
|
220
|
-
stub_session = stub
|
220
|
+
stub_session = stub('session')
|
221
221
|
Sunspot.session = stub_session
|
222
222
|
post = Post.new
|
223
223
|
stub_session.should_receive(:index).with(post)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module IntegrationHelper
|
2
2
|
def self.included(base)
|
3
3
|
base.before(:all) do
|
4
|
-
Sunspot.config.solr.url = ENV['SOLR_URL'] || 'http://localhost:8983/solr'
|
4
|
+
Sunspot.config.solr.url = ENV['SOLR_URL'] || 'http://localhost:8983/solr/default'
|
5
5
|
Sunspot.reset!(true)
|
6
6
|
end
|
7
7
|
end
|
@@ -11,7 +11,7 @@ module QueryHelper
|
|
11
11
|
def subqueries(param)
|
12
12
|
q = connection.searches.last[:q]
|
13
13
|
subqueries = []
|
14
|
-
subqueries = q.scan(%r(_query_:"\{!
|
14
|
+
subqueries = q.scan(%r(_query_:"\{!edismax (.*?)\}(.*?)"))
|
15
15
|
subqueries.map do |subquery|
|
16
16
|
params = {}
|
17
17
|
subquery[0].scan(%r((\S+?)='(.+?)')) do |key, value|
|
@@ -16,6 +16,34 @@ describe 'keyword search' do
|
|
16
16
|
Sunspot.index!(@comment)
|
17
17
|
end
|
18
18
|
|
19
|
+
context 'edismax' do
|
20
|
+
it 'matches with wildcards' do
|
21
|
+
results = Sunspot.search(Post) { keywords '*oas*' }.results
|
22
|
+
[0,2].each { |i| results.should include(@posts[i])}
|
23
|
+
[1].each { |i| results.should_not include(@posts[i])}
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'matches multiple keywords on different fields with wildcards using subqueries' do
|
27
|
+
results = Sunspot.search(Post) do
|
28
|
+
keywords 'insuffic*',:fields=>[:title]
|
29
|
+
keywords 'win*',:fields=>[:body]
|
30
|
+
end.results
|
31
|
+
[0].each {|i| results.should include(@posts[i])}
|
32
|
+
[1,2].each {|i| results.should_not include(@posts[i])}
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'matches with proximity' do
|
36
|
+
results = Sunspot.search(Post) { keywords '"wind buffer"~4' }.results
|
37
|
+
[0,1].each {|i| results.should_not include(@posts[i])}
|
38
|
+
[2].each {|i| results.should include(@posts[i])}
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'does not match if not within proximity' do
|
42
|
+
results = Sunspot.search(Post) { keywords '"wind buffer"~1' }.results
|
43
|
+
results.should == []
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
19
47
|
it 'matches a single keyword out of a single field' do
|
20
48
|
results = Sunspot.search(Post) { keywords 'toast' }.results
|
21
49
|
[0, 2].each { |i| results.should include(@posts[i]) }
|
@@ -266,6 +266,44 @@ describe 'scoped_search' do
|
|
266
266
|
end.results.should == posts[0..1]
|
267
267
|
end
|
268
268
|
|
269
|
+
it 'should return results, ignoring any restriction in a disjunction that has been passed an empty array' do
|
270
|
+
posts = (1..3).map { |i| Post.new(:blog_id => i)}
|
271
|
+
Sunspot.index!(posts)
|
272
|
+
Sunspot.search(Post) do
|
273
|
+
with(:blog_id, [])
|
274
|
+
end.results.should == posts
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'should return results, ignoring any restriction in a negative disjunction that has been passed an empty array' do
|
278
|
+
posts = (1..3).map { |i| Post.new(:blog_id => i)}
|
279
|
+
Sunspot.index!(posts)
|
280
|
+
Sunspot.search(Post) do
|
281
|
+
without(:blog_id, [])
|
282
|
+
end.results.should == posts
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'should return results, ignoring any restriction in a conjunction that has been passed an empty array' do
|
286
|
+
posts = (1..3).map { |i| Post.new(:blog_id => i)}
|
287
|
+
Sunspot.index!(posts)
|
288
|
+
Sunspot.search(Post) do
|
289
|
+
all_of do
|
290
|
+
with(:blog_id, 1)
|
291
|
+
with(:blog_id, [])
|
292
|
+
end
|
293
|
+
end.results.should == posts[0..0]
|
294
|
+
end
|
295
|
+
|
296
|
+
it 'should return results, ignoring any restriction in a negative conjunction that has been passed an empty array' do
|
297
|
+
posts = (1..3).map { |i| Post.new(:blog_id => i)}
|
298
|
+
Sunspot.index!(posts)
|
299
|
+
Sunspot.search(Post) do
|
300
|
+
all_of do
|
301
|
+
with(:blog_id, 1)
|
302
|
+
without(:blog_id, [])
|
303
|
+
end
|
304
|
+
end.results.should == posts[0..0]
|
305
|
+
end
|
306
|
+
|
269
307
|
it 'should return results that match a nested conjunction in a disjunction' do
|
270
308
|
posts = [
|
271
309
|
Post.new(:title => 'No', :blog_id => 1),
|
@@ -379,7 +417,7 @@ describe 'scoped_search' do
|
|
379
417
|
|
380
418
|
it 'should order randomly (run this test again if it fails)' do
|
381
419
|
result_sets = Array.new(2) do
|
382
|
-
Sunspot.search(Post) {
|
420
|
+
Sunspot.search(Post) { order_by(:random) }.results.map do |result|
|
383
421
|
result.id
|
384
422
|
end
|
385
423
|
end
|
data/spec/mocks/adapters.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sunspot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -27,7 +27,7 @@ authors:
|
|
27
27
|
autorequire:
|
28
28
|
bindir: bin
|
29
29
|
cert_chain: []
|
30
|
-
date: 2013-
|
30
|
+
date: 2013-10-25 00:00:00.000000000 Z
|
31
31
|
dependencies:
|
32
32
|
- !ruby/object:Gem::Dependency
|
33
33
|
name: rsolr
|
@@ -82,7 +82,7 @@ dependencies:
|
|
82
82
|
requirement: !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
|
-
- -
|
85
|
+
- - '>='
|
86
86
|
- !ruby/object:Gem::Version
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
@@ -90,14 +90,13 @@ dependencies:
|
|
90
90
|
version_requirements: !ruby/object:Gem::Requirement
|
91
91
|
none: false
|
92
92
|
requirements:
|
93
|
-
- -
|
93
|
+
- - '>='
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: '0'
|
96
|
-
description:
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
boolean queries or building Solr parameters by hand.\n"
|
96
|
+
description: |2
|
97
|
+
Sunspot is a library providing a powerful, all-ruby API for the Solr search engine. Sunspot manages the configuration of persistent
|
98
|
+
Ruby classes for search and indexing and exposes Solr's most powerful features through a collection of DSLs. Complex search operations
|
99
|
+
can be performed without hand-writing any boolean queries or building Solr parameters by hand.
|
101
100
|
email:
|
102
101
|
- mat@patch.com
|
103
102
|
executables: []
|
@@ -299,18 +298,18 @@ require_paths:
|
|
299
298
|
required_ruby_version: !ruby/object:Gem::Requirement
|
300
299
|
none: false
|
301
300
|
requirements:
|
302
|
-
- -
|
301
|
+
- - '>='
|
303
302
|
- !ruby/object:Gem::Version
|
304
303
|
version: '0'
|
305
304
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
306
305
|
none: false
|
307
306
|
requirements:
|
308
|
-
- -
|
307
|
+
- - '>='
|
309
308
|
- !ruby/object:Gem::Version
|
310
309
|
version: '0'
|
311
310
|
requirements: []
|
312
311
|
rubyforge_project: sunspot
|
313
|
-
rubygems_version: 1.8.
|
312
|
+
rubygems_version: 1.8.25
|
314
313
|
signing_key:
|
315
314
|
specification_version: 3
|
316
315
|
summary: Library for expressive, powerful interaction with the Solr search engine
|