outoftime-sunspot 0.8.5 → 0.8.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|