outoftime-sunspot 0.8.5 → 0.8.8
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/README.rdoc +2 -1
- data/VERSION.yml +1 -1
- data/bin/sunspot-solr +11 -3
- data/lib/sunspot/adapters.rb +10 -3
- data/lib/sunspot/indexer.rb +1 -1
- data/lib/sunspot/query.rb +9 -2
- data/lib/sunspot.rb +2 -2
- data/spec/api/adapters_spec.rb +12 -0
- data/spec/api/build_search_spec.rb +14 -9
- data/spec/api/indexer_spec.rb +7 -2
- data/spec/api/sunspot_spec.rb +20 -0
- data/spec/integration/keyword_search_spec.rb +10 -0
- data/spec/mocks/comment.rb +23 -21
- metadata +4 -2
data/README.rdoc
CHANGED
|
@@ -29,7 +29,7 @@ objects such as the filesystem.
|
|
|
29
29
|
|
|
30
30
|
In order to start the packaged Solr installation, run:
|
|
31
31
|
|
|
32
|
-
sunspot-solr start -- [-d /path/to/data/directory] [-p port] [-s path/to/solr/home]
|
|
32
|
+
sunspot-solr start -- [-d /path/to/data/directory] [-p port] [-s path/to/solr/home] [--pid-dir=path/to/pid/dir]
|
|
33
33
|
|
|
34
34
|
If you don't specify a data directory, your Solr index will be stored in your operating system's temporary directory.
|
|
35
35
|
|
|
@@ -146,6 +146,7 @@ http://outoftime.lighthouseapp.com/projects/20339-sunspot
|
|
|
146
146
|
== Further Reading
|
|
147
147
|
|
|
148
148
|
* Sunspot Discussion: http://groups.google.com/group/ruby-sunspot
|
|
149
|
+
* IRC: #sunspot-ruby @ Freenode
|
|
149
150
|
* Posts about Sunspot from my tumblog: http://outofti.me/tagged/sunspot
|
|
150
151
|
* Read about it on Linux Magazine: http://www.linux-mag.com/id/7341
|
|
151
152
|
|
data/VERSION.yml
CHANGED
data/bin/sunspot-solr
CHANGED
|
@@ -24,14 +24,22 @@ module SolrFlags extend OptiFlagSet
|
|
|
24
24
|
description 'Solr home (should contain conf/ directory)'
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
optional_flag 'pd' do
|
|
28
|
+
long_form 'pid-dir'
|
|
29
|
+
description 'Directory for pid files'
|
|
30
|
+
end
|
|
31
|
+
|
|
27
32
|
and_process!
|
|
28
33
|
end
|
|
29
34
|
|
|
30
|
-
port
|
|
35
|
+
port = ARGV.flags.p || '8983'
|
|
31
36
|
data_dir = File.expand_path(ARGV.flags.d || File.join(Dir.tmpdir, 'solr_data'))
|
|
32
|
-
home
|
|
37
|
+
home = File.expand_path(ARGV.flags.s) if ARGV.flags.s
|
|
38
|
+
pid_dir = File.expand_path(ARGV.flags.pd || working_directory)
|
|
39
|
+
|
|
40
|
+
options = { :dir_mode => :normal, :dir => pid_dir }
|
|
33
41
|
|
|
34
|
-
Daemons.run_proc('sunspot-solr') do
|
|
42
|
+
Daemons.run_proc('sunspot-solr', options) do
|
|
35
43
|
FileUtils.cd(working_directory) do
|
|
36
44
|
FileUtils.cd(solr_home) do
|
|
37
45
|
args = ['java']
|
data/lib/sunspot/adapters.rb
CHANGED
|
@@ -118,7 +118,7 @@ module Sunspot
|
|
|
118
118
|
def for(clazz) #:nodoc:
|
|
119
119
|
original_class_name = clazz.name
|
|
120
120
|
clazz.ancestors.each do |ancestor_class|
|
|
121
|
-
next if ancestor_class.name.empty?
|
|
121
|
+
next if ancestor_class.name.nil? || ancestor_class.name.empty?
|
|
122
122
|
class_name = ancestor_class.name.to_sym
|
|
123
123
|
return instance_adapters[class_name] if instance_adapters[class_name]
|
|
124
124
|
end
|
|
@@ -227,14 +227,21 @@ module Sunspot
|
|
|
227
227
|
#
|
|
228
228
|
# ==== Returns
|
|
229
229
|
#
|
|
230
|
-
# Class:: Implementation of DataAccessor
|
|
230
|
+
# Class:: Implementation of DataAccessor
|
|
231
|
+
#
|
|
232
|
+
# ==== Raises
|
|
233
|
+
#
|
|
234
|
+
# Sunspot::NoAdapterError:: If no data accessor exists for the given class
|
|
231
235
|
#
|
|
232
236
|
def for(clazz) #:nodoc:
|
|
237
|
+
original_class_name = clazz.name
|
|
233
238
|
clazz.ancestors.each do |ancestor_class|
|
|
234
|
-
next if ancestor_class.name.empty?
|
|
239
|
+
next if ancestor_class.name.nil? || ancestor_class.name.empty?
|
|
235
240
|
class_name = ancestor_class.name.to_sym
|
|
236
241
|
return data_accessors[class_name] if data_accessors[class_name]
|
|
237
242
|
end
|
|
243
|
+
raise(Sunspot::NoAdapterError,
|
|
244
|
+
"No data accessor is configured for #{original_class_name} or its superclasses. See the documentation for Sunspot::Adapters")
|
|
238
245
|
end
|
|
239
246
|
|
|
240
247
|
protected
|
data/lib/sunspot/indexer.rb
CHANGED
|
@@ -33,7 +33,7 @@ module Sunspot
|
|
|
33
33
|
# Delete all documents of the class indexed by this indexer from Solr.
|
|
34
34
|
#
|
|
35
35
|
def remove_all
|
|
36
|
-
@connection.delete_by_query("type:#{@setup.clazz.name}")
|
|
36
|
+
@connection.delete_by_query("type:#{Solr::Util.query_parser_escape(@setup.clazz.name)}")
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
protected
|
data/lib/sunspot/query.rb
CHANGED
|
@@ -314,11 +314,18 @@ module Sunspot
|
|
|
314
314
|
#
|
|
315
315
|
def types_phrase
|
|
316
316
|
if @types.nil? || @types.empty? then "type:[* TO *]"
|
|
317
|
-
elsif @types.length == 1 then "type:#{
|
|
318
|
-
else "type:(#{
|
|
317
|
+
elsif @types.length == 1 then "type:#{escaped_types.first}"
|
|
318
|
+
else "type:(#{escaped_types * ' OR '})"
|
|
319
319
|
end
|
|
320
320
|
end
|
|
321
321
|
|
|
322
|
+
#
|
|
323
|
+
# Wraps each type in quotes to escape names of the form Namespace::Class
|
|
324
|
+
#
|
|
325
|
+
def escaped_types
|
|
326
|
+
@types.map { |t| Solr::Util.query_parser_escape(t.name)}
|
|
327
|
+
end
|
|
328
|
+
|
|
322
329
|
#
|
|
323
330
|
# Return a hash of field names to field objects, containing all fields
|
|
324
331
|
# that are common to all of the classes under search. In order for fields
|
data/lib/sunspot.rb
CHANGED
|
@@ -347,7 +347,7 @@ module Sunspot
|
|
|
347
347
|
# classes...<Class>::
|
|
348
348
|
# classes for which to remove all instances from the index
|
|
349
349
|
def remove_all!(*classes)
|
|
350
|
-
session.remove_all(*classes)
|
|
350
|
+
session.remove_all!(*classes)
|
|
351
351
|
end
|
|
352
352
|
|
|
353
353
|
#
|
|
@@ -385,7 +385,7 @@ module Sunspot
|
|
|
385
385
|
# static data between tests, but probably nowhere else.
|
|
386
386
|
#
|
|
387
387
|
def reset!
|
|
388
|
-
@session =
|
|
388
|
+
@session = Session.new(session.config)
|
|
389
389
|
end
|
|
390
390
|
|
|
391
391
|
private
|
data/spec/api/adapters_spec.rb
CHANGED
|
@@ -8,6 +8,12 @@ describe Sunspot::Adapters::InstanceAdapter do
|
|
|
8
8
|
it "finds adapter by mixin" do
|
|
9
9
|
Sunspot::Adapters::InstanceAdapter::for(MixModel).should be(MixInModelInstanceAdapter)
|
|
10
10
|
end
|
|
11
|
+
|
|
12
|
+
it 'throws NoAdapterError if anonymous module passed in' do
|
|
13
|
+
lambda do
|
|
14
|
+
Sunspot::Adapters::InstanceAdapter::for(Module.new)
|
|
15
|
+
end.should raise_error(Sunspot::NoAdapterError)
|
|
16
|
+
end
|
|
11
17
|
end
|
|
12
18
|
|
|
13
19
|
describe Sunspot::Adapters::DataAccessor do
|
|
@@ -18,4 +24,10 @@ describe Sunspot::Adapters::DataAccessor do
|
|
|
18
24
|
it "finds adapter by mixin" do
|
|
19
25
|
Sunspot::Adapters::DataAccessor::for(MixModel).should be(MixInModelDataAccessor)
|
|
20
26
|
end
|
|
27
|
+
|
|
28
|
+
it 'throws NoAdapterError if anonymous module passed in' do
|
|
29
|
+
lambda do
|
|
30
|
+
Sunspot::Adapters::DataAccessor::for(Module.new)
|
|
31
|
+
end.should raise_error(Sunspot::NoAdapterError)
|
|
32
|
+
end
|
|
21
33
|
end
|
|
@@ -320,23 +320,28 @@ describe 'Search' do
|
|
|
320
320
|
end
|
|
321
321
|
end
|
|
322
322
|
|
|
323
|
+
it 'should properly escape namespaced type names' do
|
|
324
|
+
connection.should_receive(:query).with('(type:Namespaced\:\:Comment)', hash_including)
|
|
325
|
+
session.search(Namespaced::Comment)
|
|
326
|
+
end
|
|
327
|
+
|
|
323
328
|
it 'should build search for multiple types' do
|
|
324
|
-
connection.should_receive(:query).with('(type:(Post OR Comment))', hash_including)
|
|
325
|
-
session.search(Post, Comment)
|
|
329
|
+
connection.should_receive(:query).with('(type:(Post OR Namespaced\:\:Comment))', hash_including)
|
|
330
|
+
session.search(Post, Namespaced::Comment)
|
|
326
331
|
end
|
|
327
332
|
|
|
328
333
|
it 'should allow search on fields common to all types' do
|
|
329
|
-
connection.should_receive(:query).with('(type:(Post OR Comment))', hash_including(:filter_queries => ['published_at_d:1983\-07\-08T09\:00\:00Z'])).twice
|
|
334
|
+
connection.should_receive(:query).with('(type:(Post OR Namespaced\:\:Comment))', hash_including(:filter_queries => ['published_at_d:1983\-07\-08T09\:00\:00Z'])).twice
|
|
330
335
|
time = Time.parse('1983-07-08 05:00:00 -0400')
|
|
331
|
-
session.search Post, Comment, :conditions => { :published_at => time }
|
|
332
|
-
session.search Post, Comment do
|
|
336
|
+
session.search Post, Namespaced::Comment, :conditions => { :published_at => time }
|
|
337
|
+
session.search Post, Namespaced::Comment do
|
|
333
338
|
with :published_at, time
|
|
334
339
|
end
|
|
335
340
|
end
|
|
336
341
|
|
|
337
342
|
it 'should raise Sunspot::UnrecognizedFieldError if search scoped to field not common to all types' do
|
|
338
343
|
lambda do
|
|
339
|
-
session.search Post, Comment do
|
|
344
|
+
session.search Post, Namespaced::Comment do
|
|
340
345
|
with :blog_id, 1
|
|
341
346
|
end
|
|
342
347
|
end.should raise_error(Sunspot::UnrecognizedFieldError)
|
|
@@ -344,15 +349,15 @@ describe 'Search' do
|
|
|
344
349
|
|
|
345
350
|
it 'should raise Sunspot::UnrecognizedFieldError if search scoped to field configured differently between types' do
|
|
346
351
|
lambda do
|
|
347
|
-
session.search Post, Comment do
|
|
352
|
+
session.search Post, Namespaced::Comment do
|
|
348
353
|
with :average_rating, 2.2 # this is a float in Post but an integer in Comment
|
|
349
354
|
end
|
|
350
355
|
end.should raise_error(Sunspot::UnrecognizedFieldError)
|
|
351
356
|
end
|
|
352
357
|
|
|
353
358
|
it 'should ignore condition if field is not common to all types' do
|
|
354
|
-
connection.should_receive(:query).with('(type:(Post OR Comment))', hash_not_including(:filter_queries))
|
|
355
|
-
session.search Post, Comment, :conditions => { :blog_id => 1 }
|
|
359
|
+
connection.should_receive(:query).with('(type:(Post OR Namespaced\:\:Comment))', hash_not_including(:filter_queries))
|
|
360
|
+
session.search Post, Namespaced::Comment, :conditions => { :blog_id => 1 }
|
|
356
361
|
end
|
|
357
362
|
|
|
358
363
|
it 'should allow building search using block argument rather than instance_eval' do
|
data/spec/api/indexer_spec.rb
CHANGED
|
@@ -15,10 +15,10 @@ describe 'indexer' do
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
it 'should index an array containing more than one type of object' do
|
|
18
|
-
post1, comment, post2 = objects = [Post.new, Comment.new, Post.new]
|
|
18
|
+
post1, comment, post2 = objects = [Post.new, Namespaced::Comment.new, Post.new]
|
|
19
19
|
connection.should_receive(:add).with([hash_including(:id => "Post #{post1.id}", :type => ['Post', 'BaseClass']),
|
|
20
20
|
hash_including(:id => "Post #{post2.id}", :type => ['Post', 'BaseClass'])])
|
|
21
|
-
connection.should_receive(:add).with([hash_including(:id => "Comment #{comment.id}", :type => ['Comment', 'BaseClass'])])
|
|
21
|
+
connection.should_receive(:add).with([hash_including(:id => "Namespaced::Comment #{comment.id}", :type => ['Namespaced::Comment', 'BaseClass'])])
|
|
22
22
|
session.index objects
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -134,6 +134,11 @@ describe 'indexer' do
|
|
|
134
134
|
connection.should_receive(:delete_by_query).with("type:Post")
|
|
135
135
|
session.remove_all(Post)
|
|
136
136
|
end
|
|
137
|
+
|
|
138
|
+
it 'should correctly escape namespaced classes when removing everything from the index' do
|
|
139
|
+
connection.should_receive(:delete_by_query).with('type:Namespaced\:\:Comment')
|
|
140
|
+
session.remove_all(Namespaced::Comment)
|
|
141
|
+
end
|
|
137
142
|
end
|
|
138
143
|
|
|
139
144
|
describe 'dynamic fields' do
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Sunspot do
|
|
4
|
+
describe "reset!" do
|
|
5
|
+
it "should reset current session" do
|
|
6
|
+
old_session = Sunspot.send(:session)
|
|
7
|
+
Sunspot.reset!
|
|
8
|
+
|
|
9
|
+
Sunspot.send(:session).should_not == old_session
|
|
10
|
+
end
|
|
11
|
+
it "should keep keep configuration" do
|
|
12
|
+
Sunspot.config.solr.url = "http://localhost:9999/path/solr"
|
|
13
|
+
|
|
14
|
+
config_before_reset = Sunspot.config
|
|
15
|
+
Sunspot.reset!
|
|
16
|
+
|
|
17
|
+
Sunspot.config.should == config_before_reset
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -11,6 +11,8 @@ describe 'keyword search' do
|
|
|
11
11
|
@posts << Post.new(:title => 'The toast abbreviates the recovering spirit',
|
|
12
12
|
:body => 'Does the wind interpret the buffer?')
|
|
13
13
|
Sunspot.index!(*@posts)
|
|
14
|
+
@comment = Namespaced::Comment.new(:body => 'Hey there where ya goin, not exactly knowin, who says you have to call just one place toast.')
|
|
15
|
+
Sunspot.index!(@comment)
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
it 'matches a single keyword out of a single field' do
|
|
@@ -29,4 +31,12 @@ describe 'keyword search' do
|
|
|
29
31
|
[0, 2].each { |i| results.should include(@posts[i]) }
|
|
30
32
|
[1].each { |i| results.should_not include(@posts[i]) }
|
|
31
33
|
end
|
|
34
|
+
|
|
35
|
+
it 'matches multiple types' do
|
|
36
|
+
results = Sunspot.search(Post, Namespaced::Comment) do
|
|
37
|
+
keywords 'toast'
|
|
38
|
+
end.results
|
|
39
|
+
[@posts[0], @posts[2], @comment].each { |obj| results.should include(obj) }
|
|
40
|
+
results.should_not include(@posts[1])
|
|
41
|
+
end
|
|
32
42
|
end
|
data/spec/mocks/comment.rb
CHANGED
|
@@ -1,28 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
module Namespaced
|
|
2
|
+
class Comment < BaseClass
|
|
3
|
+
@@id = 0
|
|
4
|
+
@@comments = [nil]
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
attr_reader :id
|
|
7
|
+
attr_accessor :author_name, :published_at, :body, :average_rating
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
def initialize(attrs = {})
|
|
10
|
+
@id = @@id += 1
|
|
11
|
+
@@comments << self
|
|
12
|
+
attrs.each_pair { |attribute, value| self.send("#{attribute}=", value) }
|
|
13
|
+
end
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
def self.get(id)
|
|
16
|
+
@@comments[id]
|
|
17
|
+
end
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
def self.get_all(ids)
|
|
20
|
+
ids.map { |id| get(id) }.sort_by { |post| post.id } # this is so that results are not ordered by coincidence
|
|
21
|
+
end
|
|
20
22
|
end
|
|
21
|
-
end
|
|
22
23
|
|
|
23
|
-
Sunspot.setup(Comment) do
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
Sunspot.setup(Comment) do
|
|
25
|
+
text :author_name, :body
|
|
26
|
+
string :author_name
|
|
27
|
+
time :published_at
|
|
28
|
+
integer :average_rating
|
|
29
|
+
end
|
|
28
30
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: outoftime-sunspot
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mat Brown
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2009-06-
|
|
12
|
+
date: 2009-06-15 00:00:00 -07:00
|
|
13
13
|
default_executable: sunspot-solr
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
@@ -127,6 +127,7 @@ files:
|
|
|
127
127
|
- spec/api/search_retrieval_spec.rb
|
|
128
128
|
- spec/api/session_spec.rb
|
|
129
129
|
- spec/api/spec_helper.rb
|
|
130
|
+
- spec/api/sunspot_spec.rb
|
|
130
131
|
- spec/integration/dynamic_fields_spec.rb
|
|
131
132
|
- spec/integration/faceting_spec.rb
|
|
132
133
|
- spec/integration/keyword_search_spec.rb
|
|
@@ -195,5 +196,6 @@ test_files:
|
|
|
195
196
|
- spec/api/session_spec.rb
|
|
196
197
|
- spec/api/adapters_spec.rb
|
|
197
198
|
- spec/api/build_search_spec.rb
|
|
199
|
+
- spec/api/sunspot_spec.rb
|
|
198
200
|
- spec/api/indexer_spec.rb
|
|
199
201
|
- spec/api/query_spec.rb
|