rsolr 0.12.1 → 0.13.0.pre

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
@@ -9,16 +9,21 @@ A simple, extensible Ruby client for Apache Solr.
9
9
  == Example:
10
10
  require 'rubygems'
11
11
  require 'rsolr'
12
+
13
+ # Direct connection
12
14
  solr = RSolr.connect :url=>'http://solrserver.com'
13
15
 
16
+ # Connecting over a proxy server
17
+ solr = RSolr.connect :url=>'http://solrserver.com', :proxy=>'http://user:pass@proxy.example.com:8080'
18
+
14
19
  # send a request to /select
15
- response = rsolr.select :q=>'*:*'
20
+ response = solr.select :q=>'*:*'
16
21
 
17
22
  # send a request to a custom request handler; /catalog
18
- response = rsolr.request '/catalog', :q=>'*:*'
23
+ response = solr.request '/catalog', :q=>'*:*'
19
24
 
20
25
  # alternative to above:
21
- response = rsolr.catalog :q=>'*:*'
26
+ response = solr.catalog :q=>'*:*'
22
27
 
23
28
  == Querying
24
29
  Use the #select method to send requests to the /select handler:
@@ -107,6 +112,7 @@ The raw is a hash that contains the generated params, url, path, post data, head
107
112
  * {RSolr Google Group}[http://groups.google.com/group/rsolr] -- The RSolr discussion group
108
113
  * {rsolr-ext}[http://github.com/mwmitchell/rsolr-ext] -- An extension kit for RSolr
109
114
  * {rsolr-direct}[http://github.com/mwmitchell/rsolr-direct] -- JRuby direct connection for RSolr
115
+ * {rsolr-nokogiri}[http://github.com/mwmitchell/rsolr-nokogiri] -- Gives RSolr Nokogiri for XML generation.
110
116
  * {SunSpot}[http://github.com/outoftime/sunspot] -- An awesome Solr DSL, built with RSolr
111
117
  * {Blacklight}[http://blacklightopac.org] -- A "next generation" Library OPAC, built with RSolr
112
118
  * {java_bin}[http://github.com/kennyj/java_bin] -- Provides javabin/binary parsing for RSolr
@@ -122,8 +128,12 @@ The raw is a hash that contains the generated params, url, path, post data, head
122
128
  * Send me a pull request. Bonus points for topic branches.
123
129
 
124
130
  ==Contributors
125
- * mperham
131
+ * Lorenzo Riccucci
132
+ * Mike Perham
126
133
  * Mat Brown
127
- * shairontoledo
134
+ * Shairon Toledo
128
135
  * Matthew Rudy
129
- * Fouad Mardini
136
+ * Fouad Mardini
137
+ * Jeremy Hinegardner
138
+ * Nathan Witmer
139
+ * Craig Smith
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.12.1
1
+ 0.13.0.pre
data/lib/rsolr.rb CHANGED
@@ -47,4 +47,7 @@ module RSolr
47
47
  # RequestError is a common/generic exception class used by the adapters
48
48
  class RequestError < RuntimeError; end
49
49
 
50
+ # TODO: The connection drivers need to start raising this...
51
+ class ConnectionError < RuntimeError; end
52
+
50
53
  end
data/lib/rsolr/client.rb CHANGED
@@ -42,18 +42,38 @@ class RSolr::Client
42
42
  # update using an array
43
43
  # solr.update([{:id=>1, :name=>'one'}, {:id=>2, :name=>'two'}])
44
44
  #
45
- def add(doc, &block)
46
- update message.add(doc, &block)
45
+ def add(doc, params={}, &block)
46
+ update message.add(doc, params, &block)
47
47
  end
48
48
 
49
- # send </commit>
50
- def commit
51
- update message.commit
49
+ # send "commit" message with options
50
+ #
51
+ # Options recognized by solr
52
+ #
53
+ # :maxSegments => N - optimizes down to at most N number of segments
54
+ # :waitFlush => true|false - do not return until changes are flushed to disk
55
+ # :waitSearcher => true|false - do not return until a new searcher is opened and registered
56
+ # :expungeDeletes => true|false - merge segments with deletes into other segments #NOT
57
+ #
58
+ # *NOTE* :expungeDeletes is Solr 1.4 only
59
+ #
60
+ def commit( options = {} )
61
+ update message.commit( options )
52
62
  end
53
63
 
54
- # send </optimize>
55
- def optimize
56
- update message.optimize
64
+ # send "optimize" message with options.
65
+ #
66
+ # Options recognized by solr
67
+ #
68
+ # :maxSegments => N - optimizes down to at most N number of segments
69
+ # :waitFlush => true|false - do not return until changes are flushed to disk
70
+ # :waitSearcher => true|false - do not return until a new searcher is opened and registered
71
+ # :expungeDeletes => true|false - merge segments with deletes into other segments
72
+ #
73
+ # *NOTE* :expungeDeletes is Solr 1.4 only
74
+ #
75
+ def optimize( options = {} )
76
+ update message.optimize( options )
57
77
  end
58
78
 
59
79
  # send </rollback>
@@ -77,7 +97,7 @@ class RSolr::Client
77
97
  end
78
98
 
79
99
  # shortcut to RSolr::Message::Generator
80
- def message *opts
100
+ def message
81
101
  @message ||= RSolr::Message::Generator.new
82
102
  end
83
103
 
@@ -4,6 +4,6 @@ module RSolr::Connection
4
4
 
5
5
  autoload :NetHttp, 'rsolr/connection/net_http'
6
6
  autoload :Utils, 'rsolr/connection/utils'
7
- autoload :Requestable, 'rsolr/connection/requestable'
7
+ autoload :Httpable, 'rsolr/connection/httpable'
8
8
 
9
9
  end
@@ -0,0 +1,101 @@
1
+ # A module that defines the interface and top-level logic for http based connection classes.
2
+ # Httpable provides URL parsing and handles proxy logic.
3
+
4
+ module RSolr::Connection::Httpable
5
+
6
+ include RSolr::Connection::Utils
7
+
8
+ attr_reader :opts, :uri, :proxy
9
+
10
+ # opts can have:
11
+ # :url => 'http://localhost:8080/solr'
12
+ def initialize opts={}
13
+ opts[:url] ||= 'http://127.0.0.1:8983/solr'
14
+ @opts = opts
15
+ @uri = URI.parse opts[:url]
16
+ @proxy = URI.parse opts[:proxy] if opts[:proxy]
17
+ end
18
+
19
+ # send a request to the connection
20
+ # request '/select', :q=>'*:*'
21
+ #
22
+ # request '/update', {:wt=>:xml}, '</commit>'
23
+ #
24
+ # force a post where the post body is the param query
25
+ # request '/update', "<optimize/>", :method=>:post
26
+ #
27
+ def request path, params={}, *extra
28
+ extra = extra.dup
29
+ opts = extra[-1].kind_of?(Hash) ? extra.pop : {}
30
+ data = extra[0]
31
+
32
+ context = create_http_context path, params, data, opts
33
+
34
+ error = nil
35
+
36
+ begin
37
+
38
+ # if data is being sent, this is a POST
39
+ if context[:data]
40
+ response = self.post context[:path], context[:data], context[:headers]
41
+ # use POST if :method => :post
42
+ elsif opts[:method] == :post
43
+ response = self.post context[:path], context[:query], context[:headers]
44
+ # GET
45
+ else
46
+ response = self.get context[:path]
47
+ end
48
+
49
+ # spray out our response into variables...
50
+ body, status_code, message = response
51
+
52
+ # merge the response into the http context
53
+ context.merge!(:body => body, :status_code => status_code, :message => message)
54
+
55
+ rescue
56
+ # throw RequestError?
57
+ context[:message] = $!.to_s
58
+ end
59
+
60
+ # if no :message but a non-200, throw a "SolrRequestError" ?
61
+ unless context[:status_code] == 200
62
+ error = context[:message] || "Non-200 Response Status Code"
63
+ raise RSolr::RequestError.new("#{error} -> #{context.inspect}")
64
+ end
65
+
66
+ context
67
+ end
68
+
69
+ # -> should this stuff be in a "ReqResContext" class? ->
70
+
71
+ # creates a Hash based "context"
72
+ # that contains all of the information sent to Solr
73
+ # The keys are:
74
+ # :host, :path, :params, :query, :data, :headers
75
+ def create_http_context path, params, data=nil, opts={}
76
+ context = {:host => base_url, :path => build_url(path), :params => params, :query => hash_to_query(params), :data => data}
77
+ if opts[:method] == :post
78
+ raise "Don't send POST data when using :method => :post" unless data.to_s.empty?
79
+ # force a POST, use the query string as the POST body
80
+ context.merge! :data => hash_to_query(params), :headers => {'Content-Type' => 'application/x-www-form-urlencoded'}
81
+ elsif data
82
+ # standard POST, using "data" as the POST body
83
+ context.merge! :headers => {'Content-Type' => 'text/xml; charset=utf-8'}
84
+ else
85
+ context.merge! :path => build_url(path, params)
86
+ end
87
+ context
88
+ end
89
+
90
+ # accepts a path/string and optional hash of query params
91
+ # returns a string that represents the full url
92
+ def build_url path, params={}
93
+ full_path = @uri.path + path
94
+ super full_path, params, @uri.query
95
+ end
96
+
97
+ def base_url
98
+ "#{@uri.scheme}://#{@uri.host}" + (@uri.port ? ":#{@uri.port}" : "")
99
+ end
100
+
101
+ end
@@ -5,44 +5,26 @@ require 'net/http'
5
5
  #
6
6
  class RSolr::Connection::NetHttp
7
7
 
8
- include RSolr::Connection::Requestable
8
+ include RSolr::Connection::Httpable
9
9
 
10
10
  def connection
11
- @connection ||= Net::HTTP.new(@uri.host, @uri.port)
11
+ if @proxy
12
+ proxy_user, proxy_pass = @proxy.userinfo.split(/:/) if @proxy.userinfo
13
+ @connection ||= Net::HTTP.Proxy(@proxy.host, @proxy.port, proxy_user, proxy_pass).new(@uri.host, @uri.port)
14
+ else
15
+ @connection ||= Net::HTTP.new(@uri.host, @uri.port)
16
+ end
12
17
  end
13
18
 
14
- def get path, params={}
15
- url = self.build_url path, params
19
+ # maybe follow Rack and do [status, headers, body]
20
+ def get url
16
21
  net_http_response = self.connection.get url
17
- create_http_context net_http_response, url, path, params
22
+ [net_http_response.code.to_i, net_http_response.message, net_http_response.body]
18
23
  end
19
24
 
20
- def post path, data, params={}, headers={}
21
- url = self.build_url path, params
25
+ def post url, data, headers={}
22
26
  net_http_response = self.connection.post url, data, headers
23
- create_http_context net_http_response, url, path, params, data, headers
24
- end
25
-
26
- def create_http_context net_http_response, url, path, params, data=nil, headers={}
27
- full_url = "#{@uri.scheme}://#{@uri.host}"
28
- full_url += @uri.port ? ":#{@uri.port}" : ''
29
- full_url += url
30
- {
31
- :status_code=>net_http_response.code.to_i,
32
- :url=>full_url,
33
- :body=> encode_utf8(net_http_response.body),
34
- :path=>path,
35
- :params=>params,
36
- :data=>data,
37
- :headers=>headers,
38
- :message => net_http_response.message
39
- }
40
- end
41
-
42
- # accepts a path/string and optional hash of query params
43
- def build_url path, params={}
44
- full_path = @uri.path + path
45
- super full_path, params, @uri.query
27
+ [net_http_response.code.to_i, net_http_response.message, net_http_response.body]
46
28
  end
47
29
 
48
30
  end
@@ -1,5 +1,5 @@
1
1
  # Helpful utility methods for building queries to a Solr server
2
- # This includes helpers that the Direct connection can use.
2
+ # This includes helpers that the Direct connection can use -- not specific to http, for example
3
3
  module RSolr::Connection::Utils
4
4
 
5
5
  # Performs URI escaping so that you can construct proper
@@ -19,7 +19,7 @@ module RSolr::Connection::Utils
19
19
  string.force_encoding(Encoding::UTF_8) : string
20
20
  end
21
21
 
22
- # Return the bytesize of String; uses String#length under Ruby 1.8 and
22
+ # Return the bytesize of String; uses String#size under Ruby 1.8 and
23
23
  # String#bytesize under 1.9.
24
24
  if ''.respond_to?(:bytesize)
25
25
  def bytesize(string)
@@ -53,11 +53,12 @@ module RSolr::Connection::Utils
53
53
  #
54
54
  # converts hash into URL query string, keys get an alpha sort
55
55
  # if a value is an array, the array values get mapped to the same key:
56
- # hash_to_query(:q=>'blah', :fq=>['blah', 'blah'], :facet=>{:field=>['location_facet', 'format_facet']})
56
+ # hash_to_query(:q=>'blah-query', :fq=>['f1', 'f1'], :facet=>true, 'facet.field'=>['location_facet', 'format_facet'])
57
57
  # returns:
58
- # ?q=blah&fq=blah&fq=blah&facet.field=location_facet&facet.field=format.facet
58
+ # ?q=blah-query&fq=f1&fq=f2&facet=true&facet.field=location_facet&facet.field=format.facet
59
+ #
60
+ # if a value is empty/nil etc., it is tossed out
59
61
  #
60
- # if a value is empty/nil etc., it is not added
61
62
  def hash_to_query(params)
62
63
  mapped = params.map do |k, v|
63
64
  next if v.to_s.empty?
@@ -69,5 +70,5 @@ module RSolr::Connection::Utils
69
70
  end
70
71
  mapped.compact.join("&")
71
72
  end
72
-
73
+
73
74
  end
@@ -26,18 +26,40 @@ describe RSolr::Client do
26
26
  }
27
27
  client.add(:id=>1)
28
28
  end
29
-
29
+
30
30
  it 'should forward #commit calls to #update' do
31
31
  client.should_receive(:update).
32
32
  with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><commit/>")
33
33
  client.commit
34
34
  end
35
+
36
+ it 'should forward #commit calls with options to #update' do
37
+ opts = {:waitFlush => false, :waitSearcher => false, :expungeDeletes => true}
38
+ # when client.commit is called, it eventually calls update
39
+ client.should_receive(:update).
40
+ with(opts)
41
+ # client.message is calls to create the xml
42
+ client.message.should_receive(:commit).
43
+ and_return(opts)
44
+ client.commit(opts)
45
+ end
35
46
 
36
47
  it 'should forward #optimize calls to #update' do
37
48
  client.should_receive(:update).
38
49
  with("<?xml version=\"1.0\" encoding=\"UTF-8\"?><optimize/>")
39
50
  client.optimize
40
51
  end
52
+
53
+ it 'should forward #optimize calls with options to #update' do
54
+ opts = {:maxSegments => 5, :waitFlush => false}
55
+ # when client.commit is called, it eventually calls update
56
+ client.should_receive(:update).
57
+ with(opts)
58
+ # client.message is calls to create the xml
59
+ client.message.should_receive(:optimize).
60
+ and_return(opts)
61
+ client.optimize(opts)
62
+ end
41
63
 
42
64
  it 'should forward #rollback calls to #update' do
43
65
  client.should_receive(:update).
@@ -69,9 +91,9 @@ describe RSolr::Client do
69
91
  and_return(:params=>{})
70
92
  client.request '/music', :q=>'Coltrane'
71
93
  end
72
-
94
+
73
95
  end
74
-
96
+
75
97
  context :adapt_response do
76
98
 
77
99
  it 'should not try to evaluate ruby when the :qt is not :ruby' do
@@ -90,4 +112,4 @@ describe RSolr::Client do
90
112
 
91
113
  end
92
114
 
93
- end
115
+ end
@@ -0,0 +1,157 @@
1
+ describe RSolr::Connection::Httpable do
2
+
3
+ # calls #let to set "net_http" as method accessor
4
+ class R
5
+ include RSolr::Connection::Httpable
6
+ end
7
+
8
+ module HttpableHelper
9
+ def self.included base
10
+ base.let(:httpable){R.new}
11
+ end
12
+ end
13
+
14
+ context 'new' do
15
+
16
+ include HttpableHelper
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
+ httpable.should respond_to(:opts)
24
+ end
25
+
26
+ it 'should have an #uri attribute after creation' do
27
+ httpable.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 :build_url do
50
+
51
+ include HttpableHelper
52
+
53
+ it 'should build a full path and create a query string' do
54
+ r = httpable
55
+ r.build_url("/select", :q=>1).should == '/solr/select?q=1'
56
+ end
57
+
58
+ it 'should build a full path without a query string' do
59
+ r = httpable
60
+ r.build_url("/select").should == '/solr/select'
61
+ end
62
+
63
+ end
64
+
65
+ context :create_http_context do
66
+
67
+ include HttpableHelper
68
+
69
+ it "should build a simple GET context" do
70
+ r = httpable
71
+ result = r.create_http_context('/select', :q=>'a', :fq=>'b')
72
+ expected = {:path=>"/solr/select?q=a&fq=b", :params=>{:q=>"a", :fq=>"b"}, :data=>nil, :query=>"q=a&fq=b", :host=>"http://127.0.0.1:8983"}
73
+
74
+ result.keys.all? {|v| expected.keys.include?(v) }
75
+ result.values.all? {|v| expected.values.include?(v) }
76
+ end
77
+
78
+ it "should build a POST context" do
79
+ r = httpable
80
+ result = r.create_http_context('/select', {:wt => :xml}, '<commit/>')
81
+ expected = {:path=>"/solr/select", :params=>{:wt=>:xml}, :headers=>{"Content-Type"=>"text/xml; charset=utf-8"}, :data=>"<commit/>", :query=>"wt=xml", :host=>"http://127.0.0.1:8983"}
82
+ result.should == expected
83
+ end
84
+
85
+ it "should raise an exception when trying to use POST data AND :method => :post" do
86
+ r = httpable
87
+ lambda{
88
+ r.create_http_context('/select', {:wt => :xml}, '<commit/>', :method => :post)
89
+ }.should raise_error("Don't send POST data when using :method => :post")
90
+ end
91
+
92
+ it "should form-encoded POST context" do
93
+ r = httpable
94
+ result = r.create_http_context('/select', {:q => 'some gigantic query string that is too big for GET (for example)'}, nil, :method => :post)
95
+ result.should == {:path=>"/solr/select", :params=>{:q=>"some gigantic query string that is too big for GET (for example)"}, :headers=>{"Content-Type"=>"application/x-www-form-urlencoded"}, :data=>"q=some+gigantic+query+string+that+is+too+big+for+GET+%28for+example%29", :query=>"q=some+gigantic+query+string+that+is+too+big+for+GET+%28for+example%29", :host=>"http://127.0.0.1:8983"}
96
+ end
97
+
98
+ end
99
+
100
+ context :request do
101
+
102
+ include HttpableHelper
103
+
104
+ it "should be able to build a request context, pass the url to #get and return a full context" do
105
+ httpable.should_receive(:create_http_context).
106
+ with("/admin/ping", {}, nil, {}).
107
+ and_return({:path => '/solr/admin/ping'})
108
+ httpable.should_receive(:get).
109
+ with('/solr/admin/ping').
110
+ and_return(["asdfasdf", 200, "OK"])
111
+ response = httpable.request '/admin/ping'
112
+ response.should == {:status_code=>200, :message=>"OK", :path=>"/solr/admin/ping", :body=>"asdfasdf"}
113
+ end
114
+
115
+ it 'should send a get to itself with params' do
116
+ httpable.should_receive(:get).
117
+ with("/solr/blahasdf?id=1").
118
+ and_return(["", 200, "OK"])
119
+ r = httpable.request('/blahasdf', :id=>1)
120
+ r.should == {:status_code=>200, :path=>"/solr/blahasdf?id=1", :params=>{:id=>1}, :message=>"OK", :data=>nil, :query=>"id=1", :host=>"http://127.0.0.1:8983", :body=>""}
121
+ end
122
+
123
+ it 'should raise an error if the status_code is not 200' do
124
+ httpable.should_receive(:get).
125
+ with("/solr/blah?id=1").
126
+ and_return( ["", 404, "Not Found"] )
127
+ lambda{
128
+ httpable.request('/blah', :id=>1).should == true
129
+ }.should raise_error(/Not Found/)
130
+ end
131
+
132
+ it 'should send a post to itself if data is supplied' do
133
+ httpable.should_receive(:post).
134
+ with("/solr/blah", "<commit/>", {"Content-Type"=>"text/xml; charset=utf-8"}).
135
+ and_return(["", 200, "OK"])
136
+ httpable.request('/blah', {:id=>1}, "<commit/>")#.should == expected_response
137
+ end
138
+
139
+ it 'should send a post to itself when :method=>:post is set even if no POST data is supplied' do
140
+ httpable.should_receive(:post).
141
+ with("/solr/blah", "q=testing", {"Content-Type"=>"application/x-www-form-urlencoded"}).
142
+ and_return(["", 200, "OK"])
143
+ response = httpable.request('/blah', {:q => "testing"}, :method => :post)#.should == expected_response
144
+ response[:body].should == ""
145
+ response[:path].should == "/solr/blah"
146
+ response[:message].should == "OK"
147
+ response[:status_code].should == 200
148
+ response[:params].should == {:q=>"testing"}
149
+ response[:headers].should == {"Content-Type"=>"application/x-www-form-urlencoded"}
150
+ response[:data].should == "q=testing"
151
+ response[:query].should == "q=testing"
152
+ response[:host].should == "http://127.0.0.1:8983"
153
+ end
154
+
155
+ end
156
+
157
+ end
@@ -12,23 +12,26 @@ describe RSolr::Connection::NetHttp do
12
12
  include NetHttpHelper
13
13
 
14
14
  it 'should forward simple, non-data calls to #get' do
15
+ net_http.should_receive(:create_http_context).
16
+ with("/select", {:q=>"a"}, nil, {}).
17
+ and_return(:path=>"/solr/select?q=a", :params=>{:q=>"a"}, :data=>nil, :query=>"q=a", :host=>"http://127.0.0.1:8983")
15
18
  net_http.should_receive(:get).
16
- with('/select', :q=>'a').
17
- and_return({:status_code=>200})
18
- net_http.request('/select', :q=>'a')
19
+ with("/solr/select?q=a").
20
+ and_return(['', 200, 'OK'])
21
+ net_http.request('/select', :q=>'a')
19
22
  end
20
23
 
21
24
  it 'should forward :method=>:post calls to #post with a special header' do
22
25
  net_http.should_receive(:post).
23
- with('/select', 'q=a', {}, {"Content-Type"=>"application/x-www-form-urlencoded"}).
24
- and_return({:status_code=>200})
26
+ with("/solr/select", "q=a", {"Content-Type"=>"application/x-www-form-urlencoded"}).
27
+ and_return(["", 200, "OK"])
25
28
  net_http.request('/select', {:q=>'a'}, :method=>:post)
26
29
  end
27
30
 
28
31
  it 'should forward data calls to #post' do
29
32
  net_http.should_receive(:post).
30
- with("/update", "<optimize/>", {}, {"Content-Type"=>"text/xml; charset=utf-8"}).
31
- and_return({:status_code=>200})
33
+ with("/solr/update", "<optimize/>", {"Content-Type"=>"text/xml; charset=utf-8"}).
34
+ and_return(["", 200, "OK"])
32
35
  net_http.request('/update', {}, '<optimize/>')
33
36
  end
34
37
 
@@ -61,21 +64,14 @@ describe RSolr::Connection::NetHttp do
61
64
  with('/solr/select?q=1').
62
65
  and_return(net_http_response)
63
66
 
64
- context = net_http.send(:get, '/select', :q=>1)
65
- context.should be_a(Hash)
67
+ context = net_http.send(:get, '/solr/select?q=1')
68
+ context.should be_a(Array)
66
69
 
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
+ context.size.should == 3
70
71
 
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'
72
+ context[0].should == 200
73
+ context[1].should == 'OK'
74
+ context[2].should == 'The Response'
79
75
  end
80
76
 
81
77
  it 'should make a POST request as expected' do
@@ -90,21 +86,14 @@ describe RSolr::Connection::NetHttp do
90
86
  c.should_receive(:post).
91
87
  with('/solr/update', '<rollback/>', {}).
92
88
  and_return(net_http_response)
93
- context = net_http.send(:post, '/update', '<rollback/>')
94
- context.should be_a(Hash)
89
+ context = net_http.send(:post, '/solr/update', '<rollback/>')
90
+ context.should be_a(Array)
95
91
 
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
92
+ context.size.should == 3
99
93
 
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'
94
+ context[0].should == 200
95
+ context[1].should == 'OK'
96
+ context[2].should == 'The Response'
108
97
  end
109
98
 
110
99
  end
@@ -145,4 +134,4 @@ describe RSolr::Connection::NetHttp do
145
134
 
146
135
  end
147
136
 
148
- end
137
+ end
@@ -39,12 +39,12 @@ describe RSolr::Connection::Utils do
39
39
  utils.hash_to_query(my_params).should == expected
40
40
  end
41
41
 
42
- it 'should escape comlex queries, part 2' do
42
+ it 'should escape complex queries, part 2' do
43
43
  my_params = {'q' => '+popularity:[10 TO *] +section:0'}
44
44
  expected = 'q=%2Bpopularity%3A%5B10+TO+%2A%5D+%2Bsection%3A0'
45
45
  utils.hash_to_query(my_params).should == expected
46
46
  end
47
-
47
+
48
48
  end
49
49
 
50
50
  context 'escape method' do
@@ -81,4 +81,4 @@ describe RSolr::Connection::Utils do
81
81
 
82
82
  end
83
83
 
84
- end
84
+ end
@@ -0,0 +1,12 @@
1
+ describe "Solr servlet error handling" do
2
+
3
+ it "should raise a RSolr::Request which contains the http request context" do
4
+ s = RSolr.connect
5
+ begin
6
+ s.select :qt => 'standard'
7
+ rescue RSolr::RequestError
8
+
9
+ end
10
+ end
11
+
12
+ end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsolr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ prerelease: true
5
+ segments:
6
+ - 0
7
+ - 13
8
+ - 0
9
+ - pre
10
+ version: 0.13.0.pre
5
11
  platform: ruby
6
12
  authors:
7
13
  - Matt Mitchell
@@ -9,19 +15,23 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-02-04 00:00:00 -05:00
18
+ date: 2010-04-04 00:00:00 -04:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: builder
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
20
25
  requirements:
21
26
  - - ">="
22
27
  - !ruby/object:Gem::Version
28
+ segments:
29
+ - 2
30
+ - 1
31
+ - 2
23
32
  version: 2.1.2
24
- version:
33
+ type: :runtime
34
+ version_requirements: *id001
25
35
  description: RSolr aims to provide a simple and extensible library for working with Solr
26
36
  email: goodieboy@gmail.com
27
37
  executables: []
@@ -38,8 +48,8 @@ files:
38
48
  - lib/rsolr.rb
39
49
  - lib/rsolr/client.rb
40
50
  - lib/rsolr/connection.rb
51
+ - lib/rsolr/connection/httpable.rb
41
52
  - lib/rsolr/connection/net_http.rb
42
- - lib/rsolr/connection/requestable.rb
43
53
  - lib/rsolr/connection/utils.rb
44
54
  - lib/rsolr/message.rb
45
55
  - lib/rsolr/message/document.rb
@@ -58,28 +68,33 @@ required_ruby_version: !ruby/object:Gem::Requirement
58
68
  requirements:
59
69
  - - ">="
60
70
  - !ruby/object:Gem::Version
71
+ segments:
72
+ - 0
61
73
  version: "0"
62
- version:
63
74
  required_rubygems_version: !ruby/object:Gem::Requirement
64
75
  requirements:
65
- - - ">="
76
+ - - ">"
66
77
  - !ruby/object:Gem::Version
67
- version: "0"
68
- version:
78
+ segments:
79
+ - 1
80
+ - 3
81
+ - 1
82
+ version: 1.3.1
69
83
  requirements: []
70
84
 
71
85
  rubyforge_project:
72
- rubygems_version: 1.3.5
86
+ rubygems_version: 1.3.6
73
87
  signing_key:
74
88
  specification_version: 3
75
89
  summary: A Ruby client for Apache Solr
76
90
  test_files:
77
91
  - spec/api/client_spec.rb
92
+ - spec/api/connection/httpable_spec.rb
78
93
  - spec/api/connection/net_http_spec.rb
79
- - spec/api/connection/requestable_spec.rb
80
94
  - spec/api/connection/utils_spec.rb
81
95
  - spec/api/message_spec.rb
82
96
  - spec/api/rsolr_spec.rb
97
+ - spec/integration/http_errors_spec.rb
83
98
  - spec/spec_helper.rb
84
99
  - Rakefile
85
100
  - tasks/spec.rake
@@ -1,43 +0,0 @@
1
- # A module that defines the interface and top-level logic for http based connection classes.
2
- module RSolr::Connection::Requestable
3
-
4
- include RSolr::Connection::Utils
5
-
6
- attr_reader :opts, :uri
7
-
8
- # opts can have:
9
- # :url => 'http://localhost:8080/solr'
10
- def initialize opts={}
11
- opts[:url] ||= 'http://127.0.0.1:8983/solr'
12
- @opts = opts
13
- @uri = URI.parse opts[:url]
14
- end
15
-
16
- # send a request to the connection
17
- # request '/select', :q=>'*:*'
18
- #
19
- # request '/update', {:wt=>:xml}, '</commit>'
20
- #
21
- # force a post where the post body is the param query
22
- # request '/update', "<optimize/>", :method=>:post
23
- #
24
- def request path, params={}, *extra
25
- opts = extra[-1].kind_of?(Hash) ? extra.pop : {}
26
- data = extra[0]
27
- # force a POST, use the query string as the POST body
28
- if opts[:method] == :post and data.to_s.empty?
29
- http_context = self.post(path, hash_to_query(params), {}, {'Content-Type' => 'application/x-www-form-urlencoded'})
30
- else
31
- if data
32
- # standard POST, using "data" as the POST body
33
- http_context = self.post(path, data, params, {"Content-Type" => 'text/xml; charset=utf-8'})
34
- else
35
- # standard GET
36
- http_context = self.get(path, params)
37
- end
38
- end
39
- raise RSolr::RequestError.new("Solr Response: #{http_context[:message]}") unless http_context[:status_code] == 200
40
- http_context
41
- end
42
-
43
- end
@@ -1,92 +0,0 @@
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