rsolr 0.12.0 → 0.12.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.
data/README.rdoc CHANGED
@@ -1,21 +1,12 @@
1
1
  =RSolr
2
2
 
3
- A Ruby client for Apache Solr. RSolr has been developed to be simple and extendable. It features transparent JRuby DirectSolrConnection support and a simple Hash-in, Hash-out architecture.
3
+ A simple, extensible Ruby client for Apache Solr.
4
4
 
5
5
  == Installation:
6
6
  gem sources -a http://gemcutter.org
7
7
  sudo gem install rsolr
8
8
 
9
- ==Related Resources & Projects
10
- * {Solr}[http://lucene.apache.org/solr/]
11
- * {RSolr Google Group}[http://groups.google.com/group/rsolr]
12
- * {RSolr::Ext}[http://github.com/mwmitchell/rsolr-ext] -- an extension kit for RSolr
13
- * {Sunspot}[http://github.com/outoftime/sunspot] -- an awesome Solr DSL, built with RSolr
14
- * {Blacklight}[http://blacklightopac.org] -- a next generation Library OPAC, built with RSolr
15
- * {solr-ruby}[http://wiki.apache.org/solr/solr-ruby] -- the original Solr Ruby Gem
16
- * {java_bin}[http://github.com/kennyj/java_bin] -- Provides javabin/binary parsing for Ruby
17
-
18
- == Simple usage:
9
+ == Example:
19
10
  require 'rubygems'
20
11
  require 'rsolr'
21
12
  solr = RSolr.connect :url=>'http://solrserver.com'
@@ -37,7 +28,7 @@ Use the #select method to send requests to the /select handler:
37
28
  :rows=>10
38
29
  })
39
30
 
40
- The params sent into the method are sent to Solr as-is. The one exception is if a value is an array. When an array is used, multiple parameters are generated for the Solr query. Example:
31
+ The params sent into the method are sent to Solr as-is. The one exception is if a value is an array. When an array is used, multiple parameters *with the same name* are generated for the Solr query. Example:
41
32
 
42
33
  solr.select :q=>'roses', :fq=>['red', 'violet']
43
34
 
@@ -48,12 +39,12 @@ The above statement generates this Solr query:
48
39
  Use the #request method for a custom request handler path:
49
40
  response = solr.request '/documents', :q=>'test'
50
41
 
51
- A shortcut for the above example:
42
+ A shortcut for the above example use a method call instead:
52
43
  response = solr.documents :q=>'test'
53
44
 
54
45
 
55
46
  == Updating Solr
56
- Updating can be done using native Ruby structures. Hashes are used for single documents and arrays are used for a collection of documents (hashes). These structures get turned into simple XML "messages". Raw XML strings can also be used.
47
+ Updating uses native Ruby structures. Hashes are used for single documents and arrays are used for a collection of documents (hashes). These structures get turned into simple XML "messages". Raw XML strings can also be used.
57
48
 
58
49
  Raw XML via #update
59
50
  solr.update '</commit>'
@@ -110,4 +101,29 @@ You can access the original request context (path, params, url etc.) by calling
110
101
  response.raw[:body]
111
102
  response.raw[:url]
112
103
 
113
- The raw is a hash that contains the generated params, url, path, post data, headers etc., very useful for debugging and testing.
104
+ The raw is a hash that contains the generated params, url, path, post data, headers etc., very useful for debugging and testing.
105
+
106
+ ==Related Resources & Projects
107
+ * {RSolr Google Group}[http://groups.google.com/group/rsolr] -- The RSolr discussion group
108
+ * {rsolr-ext}[http://github.com/mwmitchell/rsolr-ext] -- An extension kit for RSolr
109
+ * {rsolr-direct}[http://github.com/mwmitchell/rsolr-direct] -- JRuby direct connection for RSolr
110
+ * {SunSpot}[http://github.com/outoftime/sunspot] -- An awesome Solr DSL, built with RSolr
111
+ * {Blacklight}[http://blacklightopac.org] -- A "next generation" Library OPAC, built with RSolr
112
+ * {java_bin}[http://github.com/kennyj/java_bin] -- Provides javabin/binary parsing for RSolr
113
+ * {Solr}[http://lucene.apache.org/solr/] -- The Apache Solr project
114
+ * {solr-ruby}[http://wiki.apache.org/solr/solr-ruby] -- The original Solr Ruby Gem!
115
+
116
+ == Note on Patches/Pull Requests
117
+ * Fork the project.
118
+ * Make your feature addition or bug fix.
119
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
120
+ * Commit, do not mess with rakefile, version, or history
121
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
122
+ * Send me a pull request. Bonus points for topic branches.
123
+
124
+ ==Contributors
125
+ * mperham
126
+ * Mat Brown
127
+ * shairontoledo
128
+ * Matthew Rudy
129
+ * Fouad Mardini
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+
6
+ ENV['RUBYOPT'] = '-W1'
7
+
8
+ task :environment do
9
+ require File.dirname(__FILE__) + '/lib/rsolr'
10
+ end
11
+
12
+ Dir['tasks/**/*.rake'].each { |t| load t }
13
+
14
+ task :default => ['spec:api']
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.12.1
data/lib/rsolr.rb CHANGED
@@ -4,16 +4,26 @@ $:.unshift File.dirname(__FILE__) unless $:.include?(File.dirname(__FILE__))
4
4
 
5
5
  module RSolr
6
6
 
7
- VERSION = '0.12.0'
7
+ def self.version
8
+ @version ||= File.read(File.join(File.dirname(__FILE__), '..', 'VERSION'))
9
+ end
10
+
11
+ VERSION = self.version
8
12
 
9
13
  autoload :Message, 'rsolr/message'
10
14
  autoload :Client, 'rsolr/client'
11
15
  autoload :Connection, 'rsolr/connection'
12
16
 
13
- def self.connect opts={}
14
- Client.new Connection::NetHttp.new(opts)
17
+ module Connectable
18
+
19
+ def connect opts={}
20
+ Client.new Connection::NetHttp.new(opts)
21
+ end
22
+
15
23
  end
16
24
 
25
+ extend Connectable
26
+
17
27
  # A module that contains string related methods
18
28
  module Char
19
29
 
@@ -0,0 +1,93 @@
1
+ describe RSolr::Client do
2
+
3
+ let(:client){ RSolr::Client.new('') }
4
+
5
+ context :method_missing do
6
+
7
+ it 'a non-existent method should be forwarded to #method_missing and then to #request' do
8
+ client.should_receive(:request).
9
+ with('/music', :q=>'Coltrane')
10
+ client.music :q=>'Coltrane'
11
+ end
12
+
13
+ end
14
+
15
+ context :update do
16
+
17
+ it 'should forward /update to #request("/update")' do
18
+ client.should_receive(:request)#.
19
+ # with('/update', {:wt=>:ruby}, "my xml message")
20
+ client.update "my xml message"
21
+ end
22
+
23
+ it 'should forward #add calls to #update' do
24
+ client.should_receive(:update) {|value,params|
25
+ value.should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?><add><doc><field name=\"id\">1</field></doc></add>"
26
+ }
27
+ client.add(:id=>1)
28
+ end
29
+
30
+ it 'should forward #commit calls to #update' do
31
+ client.should_receive(:update).
32
+ with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><commit/>")
33
+ client.commit
34
+ end
35
+
36
+ it 'should forward #optimize calls to #update' do
37
+ client.should_receive(:update).
38
+ with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><optimize/>")
39
+ client.optimize
40
+ end
41
+
42
+ it 'should forward #rollback calls to #update' do
43
+ client.should_receive(:update).
44
+ with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><rollback/>")
45
+ client.rollback
46
+ end
47
+
48
+ it 'should forward #delete_by_id calls to #update' do
49
+ client.should_receive(:update).
50
+ with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><id>1</id></delete>")
51
+ client.delete_by_id 1
52
+ end
53
+
54
+ it 'should forward #delete_by_query calls to #update' do
55
+ client.should_receive(:update).
56
+ with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><query>blah</query></delete>")
57
+ client.delete_by_query 'blah'
58
+ end
59
+
60
+ end
61
+
62
+ context :request do
63
+
64
+ it 'should forward #request calls to the connection' do
65
+ client.connection.should_receive(:request).
66
+ with('/music', :q=>'Coltrane', :wt=>:ruby).
67
+ # empty params so that Client doesn't try to evalulate to Ruby;
68
+ # -- this happens if the :wt equal :ruby
69
+ and_return(:params=>{})
70
+ client.request '/music', :q=>'Coltrane'
71
+ end
72
+
73
+ end
74
+
75
+ context :adapt_response do
76
+
77
+ it 'should not try to evaluate ruby when the :qt is not :ruby' do
78
+ body = '{:time=>"NOW"}'
79
+ result = client.send(:adapt_response, {:body=>body, :params=>{}})
80
+ result.should be_a(String)
81
+ result.should == body
82
+ end
83
+
84
+ it 'should evaluate ruby responses when the :wt is :ruby' do
85
+ body = '{:time=>"NOW"}'
86
+ result = client.send(:adapt_response, {:body=>body, :params=>{:wt=>:ruby}})
87
+ result.should be_a(Hash)
88
+ result.should == {:time=>"NOW"}
89
+ end
90
+
91
+ end
92
+
93
+ end
@@ -0,0 +1,148 @@
1
+ describe RSolr::Connection::NetHttp do
2
+
3
+ # calls #let to set "net_http" as method accessor
4
+ module NetHttpHelper
5
+ def self.included base
6
+ base.let(:net_http){ RSolr::Connection::NetHttp.new }
7
+ end
8
+ end
9
+
10
+ context '#request' do
11
+
12
+ include NetHttpHelper
13
+
14
+ it 'should forward simple, non-data calls to #get' do
15
+ net_http.should_receive(:get).
16
+ with('/select', :q=>'a').
17
+ and_return({:status_code=>200})
18
+ net_http.request('/select', :q=>'a')
19
+ end
20
+
21
+ it 'should forward :method=>:post calls to #post with a special header' do
22
+ net_http.should_receive(:post).
23
+ with('/select', 'q=a', {}, {"Content-Type"=>"application/x-www-form-urlencoded"}).
24
+ and_return({:status_code=>200})
25
+ net_http.request('/select', {:q=>'a'}, :method=>:post)
26
+ end
27
+
28
+ it 'should forward data calls to #post' do
29
+ net_http.should_receive(:post).
30
+ with("/update", "<optimize/>", {}, {"Content-Type"=>"text/xml; charset=utf-8"}).
31
+ and_return({:status_code=>200})
32
+ net_http.request('/update', {}, '<optimize/>')
33
+ end
34
+
35
+ end
36
+
37
+ context 'connection' do
38
+
39
+ include NetHttpHelper
40
+
41
+ it 'will create an instance of Net::HTTP' do
42
+ net_http.send(:connection).should be_a(Net::HTTP)
43
+ end
44
+
45
+ end
46
+
47
+ context 'get/post' do
48
+
49
+ include NetHttpHelper
50
+
51
+ it 'should make a GET request as expected' do
52
+ net_http_response = mock('net_http_response')
53
+ net_http_response.should_receive(:code).
54
+ and_return(200)
55
+ net_http_response.should_receive(:body).
56
+ and_return('The Response')
57
+ net_http_response.should_receive(:message).
58
+ and_return('OK')
59
+ c = net_http.send(:connection)
60
+ c.should_receive(:get).
61
+ with('/solr/select?q=1').
62
+ and_return(net_http_response)
63
+
64
+ context = net_http.send(:get, '/select', :q=>1)
65
+ context.should be_a(Hash)
66
+
67
+ keys = [:data, :body, :status_code, :path, :url, :headers, :params, :message]
68
+ context.keys.size.should == keys.size
69
+ context.keys.all?{|key| keys.include?(key) }.should == true
70
+
71
+ context[:data].should == nil
72
+ context[:body].should == 'The Response'
73
+ context[:status_code].should == 200
74
+ context[:path].should == '/select'
75
+ context[:url].should == 'http://127.0.0.1:8983/solr/select?q=1'
76
+ context[:headers].should == {}
77
+ context[:params].should == {:q=>1}
78
+ context[:message].should == 'OK'
79
+ end
80
+
81
+ it 'should make a POST request as expected' do
82
+ net_http_response = mock('net_http_response')
83
+ net_http_response.should_receive(:code).
84
+ and_return(200)
85
+ net_http_response.should_receive(:body).
86
+ and_return('The Response')
87
+ net_http_response.should_receive(:message).
88
+ and_return('OK')
89
+ c = net_http.send(:connection)
90
+ c.should_receive(:post).
91
+ with('/solr/update', '<rollback/>', {}).
92
+ and_return(net_http_response)
93
+ context = net_http.send(:post, '/update', '<rollback/>')
94
+ context.should be_a(Hash)
95
+
96
+ keys = [:data, :body, :status_code, :path, :url, :headers, :params, :message]
97
+ context.keys.size.should == keys.size
98
+ context.keys.all?{|key| keys.include?(key) }.should == true
99
+
100
+ context[:data].should == '<rollback/>'
101
+ context[:body].should == 'The Response'
102
+ context[:status_code].should == 200
103
+ context[:path].should == '/update'
104
+ context[:url].should == 'http://127.0.0.1:8983/solr/update'
105
+ context[:headers].should == {}
106
+ context[:params].should == {}
107
+ context[:message].should == 'OK'
108
+ end
109
+
110
+ end
111
+
112
+ context 'build_url' do
113
+
114
+ include NetHttpHelper
115
+
116
+ it 'should incude the base path to solr' do
117
+ result = net_http.send(:build_url, '/select', :q=>'*:*', :check=>'{!}')
118
+ # this is a non-ordered hash work around,
119
+ # -- the order of the parameters in the resulting url will be different depending on the ruby distribution/platform
120
+ # yuk.
121
+ begin
122
+ result.should == '/solr/select?check=%7B%21%7D&q=%2A%3A%2A'
123
+ rescue
124
+ result.should == '/solr/select?q=%2A%3A%2A&check=%7B%21%7D'
125
+ end
126
+ end
127
+
128
+ end
129
+
130
+ context 'encode_utf8' do
131
+
132
+ include NetHttpHelper
133
+
134
+ it 'should encode response body as utf-8' do
135
+ string = 'testing'
136
+ if RUBY_VERSION =~ /1\.9/
137
+ string.encoding.should == Encoding::US_ASCII
138
+ encoded_string = net_http.send(:encode_utf8, string)
139
+ string.encoding.should == Encoding::UTF_8
140
+ else
141
+ encoded_string = net_http.send(:encode_utf8, string)
142
+ encoded_string.should == string
143
+ end
144
+ end
145
+
146
+ end
147
+
148
+ end
@@ -0,0 +1,92 @@
1
+ describe RSolr::Connection::Requestable do
2
+
3
+ # calls #let to set "net_http" as method accessor
4
+ class R
5
+ include RSolr::Connection::Requestable
6
+ end
7
+
8
+ module RequestableHelper
9
+ def self.included base
10
+ base.let(:requestable){R.new}
11
+ end
12
+ end
13
+
14
+ context 'new' do
15
+
16
+ include RequestableHelper
17
+
18
+ it 'should define an intialize method that accepts a hash argument' do
19
+ lambda{R.new({})}.should_not raise_error
20
+ end
21
+
22
+ it 'should have an #opts attribute after creation' do
23
+ requestable.should respond_to(:opts)
24
+ end
25
+
26
+ it 'should have an #uri attribute after creation' do
27
+ requestable.should respond_to(:uri)
28
+ end
29
+
30
+ end
31
+
32
+ context 'opts and uri' do
33
+
34
+ it 'should allow setting the opts' do
35
+ opts = {:url=>'blah'}
36
+ r = R.new(opts)
37
+ r.opts.should == opts
38
+ end
39
+
40
+ it 'should parser the url option into a URI object' do
41
+ opts = {:url => 'http://xyz:1010/solr'}
42
+ r = R.new(opts)
43
+ r.uri.should be_a(URI)
44
+ r.uri.host.should == 'xyz'
45
+ end
46
+
47
+ end
48
+
49
+ context :request do
50
+
51
+ include RequestableHelper
52
+
53
+ it 'should send a get to itself' do
54
+ expected_response = {:status_code => 200}
55
+ requestable.should_receive(:get).
56
+ with('/blah', {:id=>1}).
57
+ and_return(expected_response)
58
+ requestable.request('/blah', :id=>1).should == expected_response
59
+ end
60
+
61
+ it 'should raise an error if the status_code is not 200' do
62
+ expected_response = {:status_code => 503}
63
+ requestable.should_receive(:get).
64
+ with('/blah', {:id=>1}).
65
+ and_return(expected_response)
66
+ lambda{
67
+ requestable.request('/blah', :id=>1)
68
+ }.should raise_error
69
+ end
70
+
71
+ it 'should send a post to itself if data is supplied' do
72
+ expected_response = {:status_code => 200}
73
+ my_data = "<commit/>"
74
+ post_headers = {"Content-Type"=>"text/xml; charset=utf-8"}
75
+ requestable.should_receive(:post).
76
+ with('/blah', my_data, {:id=>1}, post_headers).
77
+ and_return(expected_response)
78
+ requestable.request('/blah', {:id=>1}, my_data).should == expected_response
79
+ end
80
+
81
+ it 'should send a post to itself when :method=>:post is set even if no POST data is supplied' do
82
+ expected_response = {:status_code => 200}
83
+ post_headers = {"Content-Type"=>"application/x-www-form-urlencoded"}
84
+ requestable.should_receive(:post).
85
+ with('/blah', "", {}, post_headers).
86
+ and_return(expected_response)
87
+ requestable.request('/blah', {}, :method => :post).should == expected_response
88
+ end
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,84 @@
1
+ describe RSolr::Connection::Utils do
2
+
3
+ # calls #let to set "utils" as a method accessor
4
+ module UtilsHelper
5
+ def self.included base
6
+ base.let(:utils){ nil.extend RSolr::Connection::Utils }
7
+ end
8
+ end
9
+
10
+ context 'hash_to_query method' do
11
+
12
+ include UtilsHelper
13
+
14
+ it "should build a query string from a hash, converting arrays to multi-params and removing nils/emptys" do
15
+ test_params = {
16
+ :z=>'should be whatever',
17
+ :q=>'test',
18
+ :item => [1, 2, 3, nil],
19
+ :nil=>nil
20
+ }
21
+ result = utils.hash_to_query(test_params)
22
+ [/z=should\+be\+whatever/, /q=test/, /item=1/, /item=2/, /item=3/].each do |regexp|
23
+ result.should match(regexp)
24
+ end
25
+ result.split('&').size.should == 5
26
+ end
27
+
28
+ it 'should escape &' do
29
+ utils.hash_to_query(:fq => "&").should == 'fq=%26'
30
+ end
31
+
32
+ it 'should convert spaces to +' do
33
+ utils.hash_to_query(:fq => "me and you").should == 'fq=me+and+you'
34
+ end
35
+
36
+ it 'should escape comlex queries, part 1' do
37
+ my_params = {'fq' => '{!raw f=field_name}crazy+\"field+value'}
38
+ expected = 'fq=%7B%21raw+f%3Dfield_name%7Dcrazy%2B%5C%22field%2Bvalue'
39
+ utils.hash_to_query(my_params).should == expected
40
+ end
41
+
42
+ it 'should escape comlex queries, part 2' do
43
+ my_params = {'q' => '+popularity:[10 TO *] +section:0'}
44
+ expected = 'q=%2Bpopularity%3A%5B10+TO+%2A%5D+%2Bsection%3A0'
45
+ utils.hash_to_query(my_params).should == expected
46
+ end
47
+
48
+ end
49
+
50
+ context 'escape method' do
51
+
52
+ include UtilsHelper
53
+
54
+ it 'should escape properly' do
55
+ utils.escape('+').should == '%2B'
56
+ utils.escape('This is a test').should == 'This+is+a+test'
57
+ utils.escape('<>/\\').should == '%3C%3E%2F%5C'
58
+ utils.escape('"').should == '%22'
59
+ utils.escape(':').should == '%3A'
60
+ end
61
+
62
+ it 'should escape brackets' do
63
+ utils.escape('{').should == '%7B'
64
+ utils.escape('}').should == '%7D'
65
+ end
66
+
67
+ it 'should escape exclamation marks!' do
68
+ utils.escape('!').should == '%21'
69
+ end
70
+
71
+ end
72
+
73
+ context 'build_url method' do
74
+
75
+ include UtilsHelper
76
+
77
+ it 'should build correctly' do
78
+ url = utils.build_url '/solr/select', {:q=>'test'}, 'blah=blah'
79
+ url.should == '/solr/select?blah=blah&q=test'
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,120 @@
1
+ describe RSolr::Message do
2
+
3
+ let(:generator){ RSolr::Message::Generator.new }
4
+
5
+ # call all of the simple methods...
6
+ # make sure the xml string is valid
7
+ # ensure the class is actually Solr::XML
8
+ [:optimize, :rollback, :commit].each do |meth|
9
+ it "#{meth} should generator xml" do
10
+ result = generator.send(meth)
11
+ result.should match(Regexp.escape("<#{meth}/>"))
12
+ end
13
+ end
14
+
15
+ context :add do
16
+
17
+ it 'should yield a Message::Document object when #add is called with a block' do
18
+ documents = [{:id=>1, :name=>'sam', :cat=>['cat 1', 'cat 2']}]
19
+ add_attrs = {:boost=>200.00}
20
+ result = generator.add(documents, add_attrs) do |doc|
21
+ doc.field_by_name(:name).attrs[:boost] = 10
22
+ doc.fields.size.should == 4
23
+ doc.fields_by_name(:cat).size.should == 2
24
+ end
25
+ result.should match(%r(name="cat">cat 1</field>))
26
+ result.should match(%r(name="cat">cat 2</field>))
27
+ result.should match(%r(<add boost="200.0">))
28
+ result.should match(%r(boost="10"))
29
+ result.should match(%r(<field name="id">1</field>))
30
+ end
31
+
32
+ # add a single hash ("doc")
33
+ it 'should create an add from a hash' do
34
+ data = {
35
+ :id=>1,
36
+ :name=>'matt'
37
+ }
38
+ result = generator.add(data)
39
+ result.should match(/<field name="name">matt<\/field>/)
40
+ result.should match(/<field name="id">1<\/field>/)
41
+ end
42
+
43
+ # add an array of hashes
44
+ it 'should create many adds from an array of hashes' do
45
+ data = [
46
+ {
47
+ :id=>1,
48
+ :name=>'matt'
49
+ },
50
+ {
51
+ :id=>2,
52
+ :name=>'sam'
53
+ }
54
+ ]
55
+ message = generator.add(data)
56
+ expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><add><doc><field name=\"id\">1</field><field name=\"name\">matt</field></doc><doc><field name=\"id\">2</field><field name=\"name\">sam</field></doc></add>"
57
+ message.should match(/<field name="name">matt<\/field>/)
58
+ message.should match(/<field name="name">sam<\/field>/)
59
+ end
60
+
61
+ # multiValue field support test, thanks to Fouad Mardini!
62
+ it 'should create multiple fields from array values' do
63
+ data = {
64
+ :id => 1,
65
+ :name => ['matt1', 'matt2']
66
+ }
67
+ result = generator.add(data)
68
+ result.should match(/<field name="name">matt1<\/field>/)
69
+ result.should match(/<field name="name">matt2<\/field>/)
70
+ end
71
+
72
+ it 'should create an add from a single Message::Document' do
73
+ document = RSolr::Message::Document.new
74
+ document.add_field('id', 1)
75
+ document.add_field('name', 'matt', :boost => 2.0)
76
+ result = generator.add(document)
77
+ result.should match(Regexp.escape('<?xml version="1.0" encoding="UTF-8"?>'))
78
+ result.should match(/<field name="id">1<\/field>/)
79
+ result.should match Regexp.escape('boost="2.0"')
80
+ result.should match Regexp.escape('name="name"')
81
+ result.should match Regexp.escape('matt</field>')
82
+ end
83
+
84
+ it 'should create adds from multiple Message::Documents' do
85
+ documents = (1..2).map do |i|
86
+ doc = RSolr::Message::Document.new
87
+ doc.add_field('id', i)
88
+ doc.add_field('name', "matt#{i}")
89
+ doc
90
+ end
91
+ result = generator.add(documents)
92
+ result.should match(/<field name="name">matt1<\/field>/)
93
+ result.should match(/<field name="name">matt2<\/field>/)
94
+ end
95
+
96
+ end
97
+
98
+ context :delete_by_id do
99
+
100
+ it 'should create a doc id delete' do
101
+ generator.delete_by_id(10).should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><id>10</id></delete>"
102
+ end
103
+
104
+ it 'should create many doc id deletes' do
105
+ generator.delete_by_id([1, 2, 3]).should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><id>1</id><id>2</id><id>3</id></delete>"
106
+ end
107
+
108
+ end
109
+
110
+ context :delete_by_query do
111
+ it 'should create a query delete' do
112
+ generator.delete_by_query('status:"LOST"').should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><query>status:\"LOST\"</query></delete>"
113
+ end
114
+
115
+ it 'should create many query deletes' do
116
+ generator.delete_by_query(['status:"LOST"', 'quantity:0']).should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><query>status:\"LOST\"</query><query>quantity:0</query></delete>"
117
+ end
118
+ end
119
+
120
+ end
@@ -0,0 +1,29 @@
1
+ describe RSolr do
2
+
3
+ context :connect do
4
+
5
+ it 'does not care about valid/live URLs yet' do
6
+ lambda{RSolr.connect :url=>'http://blah.blah.blah:666/solr'}.should_not raise_error
7
+ end
8
+
9
+ it 'should create an instance of RSolr::Connection::NetHttp as the #connection' do
10
+ expected_class = RSolr::Connection::NetHttp
11
+ RSolr.connect.connection.should be_a(expected_class)
12
+ RSolr.connect(:url=>'blah').connection.should be_a(expected_class)
13
+ end
14
+
15
+ end
16
+
17
+ context :escape do
18
+
19
+ it "should escape properly" do
20
+ RSolr.escape('Trying & % different "characters" here!').should == "Trying\\ \\&\\ \\%\\ different\\ \\\"characters\\\"\\ here\\!"
21
+ end
22
+
23
+ it 'should escape' do
24
+ expected = "http\\:\\/\\/lucene\\.apache\\.org\\/solr"
25
+ RSolr.escape("http://lucene.apache.org/solr").should == expected
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'rsolr')
data/tasks/rdoc.rake ADDED
@@ -0,0 +1,9 @@
1
+ # Rdoc
2
+ desc 'Generate documentation for the rsolr gem.'
3
+ Rake::RDocTask.new(:doc) do |rdoc|
4
+ rdoc.rdoc_dir = 'doc'
5
+ rdoc.title = 'RSolr'
6
+ rdoc.options << '--line-numbers' << '--inline-source'
7
+ rdoc.rdoc_files.include('README.rdoc')
8
+ rdoc.rdoc_files.include('lib/**/*.rb')
9
+ end
data/tasks/spec.rake ADDED
@@ -0,0 +1,42 @@
1
+ gem 'rspec'
2
+
3
+ # $stderr.puts `gem list`
4
+
5
+ require 'spec'
6
+ require 'spec/rake/spectask'
7
+
8
+ namespace :spec do
9
+
10
+ namespace :ruby do
11
+ desc 'run api specs through the Ruby implementations'
12
+ task :api do
13
+ puts "Ruby 1.8.7"
14
+ puts `rake spec:api`
15
+ puts "Ruby 1.9"
16
+ puts `rake1.9 spec:api`
17
+ puts "JRuby"
18
+ puts `jruby -S rake spec:api`
19
+ end
20
+ end
21
+
22
+ desc 'run api specs (mock out Solr dependency)'
23
+ Spec::Rake::SpecTask.new(:api) do |t|
24
+
25
+ t.spec_files = [File.join('spec', 'spec_helper.rb')]
26
+ t.spec_files += FileList[File.join('spec', 'api', '**', '*_spec.rb')]
27
+
28
+ t.verbose = true
29
+ t.spec_opts = ['--color']
30
+ end
31
+
32
+ desc 'run integration specs'
33
+ Spec::Rake::SpecTask.new(:integration) do |t|
34
+
35
+ t.spec_files = [File.join('spec', 'spec_helper.rb')]
36
+ t.spec_files += FileList[File.join('spec', 'integration', '**', '*_spec.rb')]
37
+
38
+ t.verbose = true
39
+ t.spec_opts = ['--color']
40
+ end
41
+
42
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsolr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Mitchell
@@ -9,11 +9,20 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-03 00:00:00 -05:00
12
+ date: 2010-02-04 00:00:00 -05:00
13
13
  default_executable:
14
- dependencies: []
15
-
16
- description: RSolr is a Ruby gem for working with Apache Solr!
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: builder
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.1.2
24
+ version:
25
+ description: RSolr aims to provide a simple and extensible library for working with Solr
17
26
  email: goodieboy@gmail.com
18
27
  executables: []
19
28
 
@@ -22,29 +31,27 @@ extensions: []
22
31
  extra_rdoc_files:
23
32
  - LICENSE
24
33
  - README.rdoc
25
- - CHANGES.txt
26
34
  files:
27
- - CHANGES.txt
35
+ - LICENSE
36
+ - README.rdoc
37
+ - VERSION
38
+ - lib/rsolr.rb
28
39
  - lib/rsolr/client.rb
40
+ - lib/rsolr/connection.rb
29
41
  - lib/rsolr/connection/net_http.rb
30
42
  - lib/rsolr/connection/requestable.rb
31
43
  - lib/rsolr/connection/utils.rb
32
- - lib/rsolr/connection.rb
44
+ - lib/rsolr/message.rb
33
45
  - lib/rsolr/message/document.rb
34
46
  - lib/rsolr/message/field.rb
35
47
  - lib/rsolr/message/generator.rb
36
- - lib/rsolr/message.rb
37
- - lib/rsolr.rb
38
- - LICENSE
39
- - README.rdoc
40
- - rsolr.gemspec
41
48
  has_rdoc: true
42
49
  homepage: http://github.com/mwmitchell/rsolr
43
50
  licenses: []
44
51
 
45
52
  post_install_message:
46
- rdoc_options: []
47
-
53
+ rdoc_options:
54
+ - --charset=UTF-8
48
55
  require_paths:
49
56
  - lib
50
57
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -66,5 +73,14 @@ rubygems_version: 1.3.5
66
73
  signing_key:
67
74
  specification_version: 3
68
75
  summary: A Ruby client for Apache Solr
69
- test_files: []
70
-
76
+ test_files:
77
+ - spec/api/client_spec.rb
78
+ - spec/api/connection/net_http_spec.rb
79
+ - spec/api/connection/requestable_spec.rb
80
+ - spec/api/connection/utils_spec.rb
81
+ - spec/api/message_spec.rb
82
+ - spec/api/rsolr_spec.rb
83
+ - spec/spec_helper.rb
84
+ - Rakefile
85
+ - tasks/spec.rake
86
+ - tasks/rdoc.rake
data/CHANGES.txt DELETED
@@ -1,282 +0,0 @@
1
- 0.12.0 - February 3, 2010
2
- Removed adapters for xml and connections (these will be provided via separate gems)
3
- - default xml generator is Builder
4
- - default http connection is Net::Http
5
- Removed JRuby/Direct connection stuff (this will be in a new library)
6
- Updated specs
7
-
8
- 0.11.0 - November 17, 2009
9
- Removed pagination feature yet again... keeping it in RSolr::Ext until a better API can be thought up.
10
- Updated Xout with fixed version - thanks to Mat Brown
11
- - bug in escaping consecutive special characters
12
- - moved regexp patterns out of loop, into "static" variables instead
13
-
14
- 0.10.1 - November 13, 2009
15
- Same changes as 0.10.0 -- but fixing version number problems
16
-
17
- 0.10.0 - November 13, 2009
18
- Changed RSolr.connect to return Http connection only:
19
- RSolr.connect :url=>'xxx'
20
- Added RSolr.direct_connect to handle the creation of SolrDirectConnections
21
- rsolr = RSolr.direct_connect :home_dir=>''
22
-
23
- # can also use a block so the connection will get closed automatically:
24
- RSolr.direct_connect :home_dir=>'' do |rsolr|
25
- # query...
26
- end
27
- Added paginate method to RSolr::Client
28
- - This method requires 2 new arguments: current page and per page:
29
- solr.paginate 1, 10, :q=>''
30
- - handler paths can be set:
31
- solr.paginate 1, 10, '/music', :q=>''
32
- - handler paths can also be set by method names:
33
- solr.paginate_music 1, 10
34
- Removed :dist_dir option from Direct connection options -- you gotta load your own java libs. See examples/direct.rb
35
- Updated specs
36
-
37
- 0.9.7.2 - November 6, 2009
38
- fixed gem spec, added client.rb
39
-
40
- 0.9.7.1 - November 5, 2009
41
- added support for multibyte url characters in RSolr::Connection::Utils
42
- - this is because Ruby 1.9's String size method is different than 1.8
43
-
44
- 0.9.7 - October 23, 2009
45
- Removed XML message builders - using pure Ruby generator instead
46
- - benchmarks show generation speed is a little faster than libxml
47
- - minimal xml escaping so binary posting to Solr should no longer be a problem.
48
- Changed response.adapter_resonse to response.raw
49
- Removed HTTP adapters - sticking with NetHTTP
50
- Removed builder dependency in gemspec
51
- Removed Adapter and HTTPClient modules
52
- Moved HTTPCLient::Util to Connection::Utils
53
- Updated all tests
54
-
55
- 0.9.6 - September 9, 2009
56
- Added ability to create direct connections from existing Java::OrgApacheSolrCore::SolrCore
57
- Added ability to send queries using POST
58
- - solr.request '/select', :q=>'*:*', :method=>:post
59
-
60
- 0.9.5 - September 4, 2009
61
- Removed Array #extract_options!
62
- Removed the Connection #send_request method (now #request)
63
- Removed the Connection #select method -- still works, but this now ends up calling Connection #method_missing
64
- Removed HTTPClient::Connector
65
- - HTTPClient now uses a method called #connect (like RSolr.connect)
66
- - This method accepts 1 or 2 args, see the #connect method comments
67
- Changed the way the HTTP client adapter is set. Now just pass in when connecting:
68
- - RSolr.connect(:http, :adapter=>curb, :url=>'http://solr.com')
69
- Moved Message::Builders to Message::Adapter
70
- Made Connection a module and moved class methods to "Base" class
71
- Made HTTPClient a module and moved class methods to "Base" class
72
- Removed the "adapter.rb" files -- Adapter modules are defined in the parent module file.
73
- Moved Message module/singleton functionality to Message::Builder class
74
- XML message adapter API change: no longer a singleton, must instantiate Message::Builder
75
- Made RSolr::Connection #message public -- can change the adapter as needed; connection.message.adapter = RSolr::Message::Adapter::LibXML.new
76
- More tests for HTTPClient::Util
77
- Simplified url/query building in HTTPClient::Util
78
- Updated tests accordingly
79
-
80
- 0.9.1 - July 22, 2009
81
- Added LibXml builder support (Thanks to Mat Brown - github.com/outoftime)
82
-
83
- 0.9.0 - July 17, 2009
84
- Added ability to use DirectSolrConnection instance when connecting
85
- Loading Java classes using full package name
86
-
87
- 0.8.9 - June 30, 2009
88
- Deprecated hash syntax fix from outoftime/rsolr (Mat Brown)
89
-
90
- 0.8.8 - May 6, 2009
91
- Added method :request to RSolr::Connection
92
- - this method is an alias for send_request
93
-
94
- 0.8.7 - May 6, 2009
95
- Added method_missing to RSolr::Connection, which sets the request handler path,
96
- based on the method name:
97
- # this sends a request like: /music_library?q=>coltrane
98
- solr.music_library :q=>'coltrane'
99
- Removed the core_ext file, put the Array extension code directly into rsolr.rb
100
-
101
- 0.8.6 - April 25, 2009
102
- Removed the Mash stuff -- which means the response keys from solr are only accessable using String based keys.
103
- Use RSolr::Ext if you want more magic.
104
-
105
- 0.8.5 - April 7, 2009
106
- The RSolr::Message #add method now accepts a single Message::Document or an array of Message::Document objects
107
- The Message::Document class has a new method: #add_field
108
- Tests added for both changes
109
- Permissions of files changed to non-executable
110
- -- the above changes were made by Mat Brown, thank you Mat!
111
- Added CannedSolrResponse module for mocks in the specs... not used yet
112
-
113
- 0.8.4 - April 3, 2009
114
- New test suite using RSpec and mocks coming. Run "rake spec"
115
- - added specs for RSolr and RSolr::Connection
116
-
117
- 0.8.3 - April 3, 2009
118
- RSolr::Connection
119
- - removed the block functionality of send_request and related methods
120
- - this was used to gain access to the raw adapter response
121
- - added #adapter_response method to all response objects
122
- - this is used to get access to the original adapter response:
123
- response = rsolr.select(:q=>'test')
124
- response.adapter_response[:status_code]
125
-
126
- 0.8.2 - March 24, 2009
127
- Changed RSolr.connect method to accept one options hash argument
128
- - This hash gets passed to the Connection object and the adapter
129
- Updated tests, examples and README.rdoc to reflect this change
130
- Bumped the version up in gemspec and the RSolr module
131
-
132
- 0.8.1 - March 12, 2009
133
- Added RSolr.escape and RSolr::Connection.new.escape
134
- - tests in rsolr_test
135
- Added ability to set doc and field attributes when adding documents via Message.add
136
-
137
- 0.8.0 - March 6, 2009
138
- Removed all response wrapper classes (now returning a simple hash for ruby responses)
139
- Removed RSolr::Query - this library needs an external partner lib, RSolrExt etc..
140
- changed query method to select
141
- added send_request method to Connection for custom requests:
142
- send_request '/my-handler', {:start=>0}, post_data=nil
143
- moved Connection::Base to Connection
144
- moved Connection::Adapter::* to Adapter::*
145
-
146
- 0.7.1 - February 27, 2009
147
- Added simple query helper module -> RSolr::Query
148
- Added tests for RSolr::Query
149
- Modified Test::Unit::TestCase in test/test_helpers.rb
150
-
151
- 0.7.0 - February 20, 2009
152
- Removed all param mapping behavior, code and tests
153
- - this stuff just gunks up rsolr and should be in an extension of some sort
154
- Can now specify the request handler in all RSolr::Connection::Base methods as the first argument:
155
- - solr.query 'select', :q=>'ipod'
156
- - solr.query 'catalog', :q=>'humphry'
157
- - solr.query :q=>'big' # defaults to the /select handler
158
-
159
- 0.6.9 - January 29, 2009
160
- Simplified facet response methods
161
- Main facet method is called #facets
162
- - returns an array of Response::Facet instances
163
- - each Facet instance has field and values attributes
164
- -- the values attribute is an array with FacetValue instances which have @value and @hits
165
- Added ability to set Connection::Base @param_adapters using :dismax or :standard
166
- instead of full class constant
167
- updated comments for #search method
168
- Updated tests
169
- Bumped up version
170
-
171
- 0.6.8 - January 28, 2009
172
- New method added to RSolr::Connection::Base - #find_values_for_facet
173
- This method searches for facet values only, and sets the :rows param to 0
174
- - returns an RSolr::Response::Query::Base instance
175
- Example:
176
- search_params[:facets][:offset]=0
177
- search_params[:facets][:limit]=5
178
- response = solr.search_facet_by_name(:language_facet, search_params)
179
-
180
- 0.6.7 - January 27, 2009
181
- The Symbol extension in core_ext.rb was cause for some REALLY painful debuging - so I removed it :(
182
- This means no more :q.alt or :facet.field until RSolr gets a really nice query-builder module happening.
183
-
184
- 0.6.6 - January 26, 2009
185
- Added #get method helper to RSolr::Response::Query::DocExt
186
- # doc.get(key, opts)
187
- # key is the name of the field
188
- # opts is a hash with the following valid keys:
189
- # - :sep - a string used for joining multivalued field values
190
- # - :default - a value to return when the key doesn't exist
191
- # if :sep is nil and the field is a multivalued field, the array is returned
192
-
193
- 0.6.5 - January 26, 2009
194
- Removed to_mash everywhere, except for usage in RSolr::Response
195
- Added a #close method to the Direct adapter
196
- - this closes the connection and sets the @connection variable to nil
197
- Removed to_mash in RSolr::Connection::Base
198
- Changed RSolr::Response::Query::Doc to DocExt
199
- - this no longer extends Mash
200
- - each doc in the response now uses the #extend method to mixin the new DocExt module
201
- Added #teardown method in direct connection test, this method closes the connection
202
- Updated the connection test methods a bit
203
-
204
- 0.6.4 - January 26, 2009
205
- Updated the mapping output for the :filters and :phrase_filters (when using the #search method)
206
- - now sending multiple fq's instead of one
207
- Updated mapping tests
208
-
209
- 0.6.3 - January 21, 2009
210
- Added a new param mapping module: RSolr::Connection::ParamMapping
211
- Mapping only for fields that need conversion/escaping or nested (facet.*) etc.
212
- This new module can be activated by using the #search method
213
- New tests for ParamMapping
214
-
215
- 0.6.2 - January 14, 2009
216
- Removed mapping and indexer modules -- seems to me that a general purpose mapping library
217
- would be more valuable than an embedded module in RSolr ( RMapper ?)
218
- This helps lighten RSolr a bit too
219
-
220
- 0.6.1 - January 13, 2009
221
- Removed SearchExt and mapping until this library gets some real use
222
- The only param mapping now is for :page and :per_page via the #search method
223
- The Connection::Base #query method does NO mapping now
224
-
225
- 0.6.0 - January 9, 2009
226
- Removed first argument from RSolr.connect, the "adapter_name"
227
- The adapter is now set using the :adapter key when passing in options to RSolr.connect:
228
- s = RSolr.connect(:adapter=>:direct)
229
-
230
- 0.5.9 - January 7, 2009
231
- Finally brought in the ExtLib Mash classes for incoming params and response hashes from solr
232
- - this gives the ability to access/set values for hashes using strings OR symbols (HashWithIndifferentAccess)
233
- Organized response tests
234
- Added more response tests
235
- Simplified the RSolr::Response::Base class by supporting only raw/string ruby input
236
- Added method to Response::IndexInfo for grabbing a Solr field list
237
-
238
- 0.5.7 - January 5, 2009
239
- Changed name from Solr to RSolr, changed all references to Solr to RSolr
240
- Added new tests for RSolr::Mapper and RSolr::Message
241
-
242
- 0.5.6 - December 30, 2008
243
- solr.gemspec cleanedup thanks to shairontoledo on github! :)
244
- Added Solr::Response::Query::Facet module with helpers from the delsolr project
245
- Also added test stub in test/connection/search_ext_test_methods.rb
246
- Fixed pagination math errors
247
- Added new SearchExt helper field: :phrase_filters
248
- This will add quoted values to the :filters (fq solr param) hash for doing easier facet requests
249
-
250
- Be sure to check out the new demo app: http://github.com/mwmitchell/consuminator/tree/master
251
-
252
- 0.5.5 - December 29, 2008
253
- Fixed bug where accessing a field by method name failed:
254
- docs.each do |doc|
255
- doc.timestamp
256
- end
257
- Fixed bug where using the #has? method on a doc failed:
258
- docs.each do |doc|
259
- doc.has?('timestamp')
260
- end
261
- Removed invalid autoload in Solr module
262
- Fixed spelling error in Solr::Connection::SearchExt (thanks to matthewrudy)
263
-
264
- 0.5.4 - December 29, 2008
265
- Re-organized the main Solr adapters, they're now in Solr::Connection::Adapter instead of Solr::Adapter
266
- All responses from HTTPClient and Connection::Adapter::Direct return a hash with the following keys:
267
- :status_code
268
- :body
269
- :params
270
- :url
271
- :path
272
- :headers
273
- :data
274
- This hash is now available in the solr response objects as #source - this will be useful in testing and debugging by allowing you to see the generated params and queries... example:
275
- response = Solr.query(:q=>'*:*')
276
- response.source[:params]
277
- response.source[:body]
278
- response.source[:url]
279
- Added MultiValue field support in Solr::Message, thanks to Fouad Mardini
280
- Bug in Solr::Connection::SearchExt where the :q params was not getting generated - fixed by Fouad Mardini
281
- Organized tests a bit, moved connection tests into test/connection
282
- Fixed a bug in Solr::Connection::Adapter::HTTP where invalid HTTP POST headers were being generated
data/rsolr.gemspec DELETED
@@ -1,32 +0,0 @@
1
- Gem::Specification.new do |s|
2
-
3
- s.name = "rsolr"
4
- s.version = "0.12.0"
5
- s.date = "2010-02-03"
6
- s.summary = "A Ruby client for Apache Solr"
7
- s.email = "goodieboy@gmail.com"
8
- s.homepage = "http://github.com/mwmitchell/rsolr"
9
- s.description = "RSolr is a Ruby gem for working with Apache Solr!"
10
- s.has_rdoc = true
11
- s.authors = ["Matt Mitchell"]
12
-
13
- s.files = [
14
- "CHANGES.txt",
15
- "lib/rsolr/client.rb",
16
- "lib/rsolr/connection/net_http.rb",
17
- "lib/rsolr/connection/requestable.rb",
18
- "lib/rsolr/connection/utils.rb",
19
- "lib/rsolr/connection.rb",
20
- "lib/rsolr/message/document.rb",
21
- "lib/rsolr/message/field.rb",
22
- "lib/rsolr/message/generator.rb",
23
- "lib/rsolr/message.rb",
24
- "lib/rsolr.rb",
25
- "LICENSE",
26
- "README.rdoc",
27
- "rsolr.gemspec"
28
- ]
29
-
30
- #s.rdoc_options = ["--main", "README.rdoc"]
31
- s.extra_rdoc_files = %w(LICENSE README.rdoc CHANGES.txt)
32
- end