rsolr 1.0.0.beta → 1.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rsolr/http.rb CHANGED
@@ -1,106 +1,99 @@
1
- module RSolr
2
-
3
- class Http
4
-
5
- attr_reader :uri, :proxy, :options
6
-
7
- def initialize base_url, options = {}
8
- @options = options
9
- @uri = base_url
10
- @proxy = options[:proxy]
11
- end
12
-
13
- def base_uri
14
- @proxy ? @proxy.request_uri : @uri.request_uri
15
- end
16
-
17
- def http
18
- @http ||= (
19
- http = if proxy
20
- proxy_user, proxy_pass = proxy.userinfo.split(/:/) if proxy.userinfo
21
- Net::HTTP.Proxy(proxy.host, proxy.port, proxy_user, proxy_pass).new uri.host, uri.port
22
- else
23
- Net::HTTP.new uri.host, uri.port
24
- end
25
-
26
- http.use_ssl = uri.port == 443 || uri.instance_of?(URI::HTTPS)
1
+ require 'net/http'
2
+ require 'net/https'
3
+
4
+ class RSolr::Http
27
5
 
28
- if options[:timeout] && options[:timeout].is_a?(Integer)
29
- http.open_timeout = options[:timeout]
30
- http.read_timeout = options[:timeout]
31
- end
6
+ include RSolr::Connectable
32
7
 
33
- if options[:pem] && http.use_ssl?
34
- http.cert = OpenSSL::X509::Certificate.new(options[:pem])
35
- http.key = OpenSSL::PKey::RSA.new(options[:pem])
36
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
37
- else
38
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
39
- end
40
-
41
- if options[:debug_output]
42
- http.set_debug_output(options[:debug_output])
43
- end
44
-
45
- http
46
- )
47
- end
8
+ def initialize *args, &block
9
+ # call the initialize method from RSolr::Connectable
10
+ super
11
+ end
48
12
 
49
- # send in path w/query
50
- def get request_uri, headers = {}
51
- req = setup_raw_request Net::HTTP::Get, request_uri, headers
52
- perform_request http, req
13
+ # using the request_context hash,
14
+ # issue a request,
15
+ # then return the standard rsolr response hash {:status, :body, :headers}
16
+ def execute request_context
17
+ request = setup_raw_request request_context
18
+ request.body = request_context[:data] if request_context[:method] == :post and request_context[:data]
19
+ begin
20
+ response = http.request request
21
+ {:status => response.code.to_i, :headers => response.to_hash, :body => response.body}
22
+ rescue NoMethodError
23
+ $!.message == "undefined method `closed?' for nil:NilClass" ?
24
+ raise(Errno::ECONNREFUSED.new) :
25
+ raise($!)
53
26
  end
27
+ end
54
28
 
55
- # send in path w/query
56
- def head request_uri, headers = {}
57
- req = setup_raw_request Net::HTTP::Head, request_uri, headers
58
- perform_request http, req
59
- end
29
+ protected
60
30
 
61
- # send in path w/query
62
- def post request_uri, data, headers = {}
63
- req = setup_raw_request Net::HTTP::Post, request_uri, headers
64
- req.body = data if data
65
- perform_request http, req
66
- end
31
+ def http
32
+ @http ||= (
33
+ http = if proxy
34
+ proxy_user, proxy_pass = proxy.userinfo.split(/:/) if proxy.userinfo
35
+ Net::HTTP.Proxy(proxy.host, proxy.port, proxy_user, proxy_pass).new uri.host, uri.port
36
+ else
37
+ Net::HTTP.new uri.host, uri.port
38
+ end
67
39
 
68
- def perform_request http, request
69
- begin
70
- response = http.request request
71
- {:status => response.code.to_i, :headers => response.to_hash, :body => response.body}
72
- rescue NoMethodError
73
- $!.message == "undefined method `closed?' for nil:NilClass" ?
74
- raise(Errno::ECONNREFUSED.new) :
75
- raise($!)
40
+ http.use_ssl = uri.port == 443 || uri.instance_of?(URI::HTTPS)
41
+
42
+ if options[:timeout] && options[:timeout].is_a?(Integer)
43
+ http.open_timeout = options[:timeout]
44
+ http.read_timeout = options[:timeout]
45
+ end
46
+
47
+ if options[:pem] && http.use_ssl?
48
+ http.cert = OpenSSL::X509::Certificate.new(options[:pem])
49
+ http.key = OpenSSL::PKey::RSA.new(options[:pem])
50
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
51
+ else
52
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
53
+ end
54
+
55
+ if options[:debug_output]
56
+ http.set_debug_output(options[:debug_output])
76
57
  end
58
+
59
+ http
60
+ )
61
+ end
62
+
63
+ def setup_raw_request request_context
64
+ http_method = case request_context[:method]
65
+ when :get
66
+ Net::HTTP::Get
67
+ when :post
68
+ Net::HTTP::Post
69
+ when :head
70
+ Net::HTTP::Head
71
+ else
72
+ raise "Only :get, :post and :head http method types are allowed."
77
73
  end
78
-
79
- def setup_raw_request http_method, request_uri, headers = {}
80
- raw_request = http_method.new "#{base_uri}#{request_uri}"
81
- raw_request.initialize_http_header headers
82
- raw_request.basic_auth username, password if options[:basic_auth]
83
- if options[:digest_auth]
84
- res = http.head(request_uri, headers)
85
- if res['www-authenticate'] != nil && res['www-authenticate'].length > 0
86
- raw_request.digest_auth username, password, res
87
- end
74
+ headers = request_context[:headers] || {}
75
+ raw_request = http_method.new request_context[:uri].to_s
76
+ raw_request.initialize_http_header headers
77
+ raw_request.basic_auth username, password if options[:basic_auth]
78
+ if options[:digest_auth]
79
+ res = http.head(request_context[:uri].to_s, headers)
80
+ if res['www-authenticate'] != nil && res['www-authenticate'].length > 0
81
+ raw_request.digest_auth username, password, res
88
82
  end
89
- raw_request
90
83
  end
84
+ raw_request
85
+ end
91
86
 
92
- def credentials
93
- options[:basic_auth] || options[:digest_auth]
94
- end
87
+ def credentials
88
+ options[:basic_auth] || options[:digest_auth]
89
+ end
95
90
 
96
- def username
97
- credentials[:username]
98
- end
91
+ def username
92
+ credentials[:username]
93
+ end
99
94
 
100
- def password
101
- credentials[:password]
102
- end
103
-
95
+ def password
96
+ credentials[:password]
104
97
  end
105
98
 
106
99
  end
data/lib/rsolr/uri.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'uri'
2
+
1
3
  module RSolr::Uri
2
4
 
3
5
  def self.create url
data/lib/rsolr/xml.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'builder'
2
+
1
3
  module RSolr::Xml
2
4
 
3
5
  class Document
@@ -102,7 +104,8 @@ module RSolr::Xml
102
104
  # The "nickname" field would have a boost="20.0"
103
105
  # if the doc had a "nickname" field with the value of "Tim".
104
106
  #
105
- def add data, add_attrs={}, &block
107
+ def add data, add_attrs = nil, &block
108
+ add_attrs ||= {}
106
109
  data = [data] unless data.is_a?(Array)
107
110
  build do |xml|
108
111
  xml.add(add_attrs) do |add_node|
@@ -118,25 +121,27 @@ module RSolr::Xml
118
121
  end
119
122
  end
120
123
  end
121
-
124
+
122
125
  # generates a <commit/> message
123
- def commit(opts={})
124
- build {|xml| xml.commit opts}
126
+ def commit opts = nil
127
+ opts ||= {}
128
+ build {|xml| xml.commit(opts) }
125
129
  end
126
-
130
+
127
131
  # generates a <optimize/> message
128
- def optimize(opts={})
129
- build {|xml| xml.optimize opts}
132
+ def optimize opts = nil
133
+ opts ||= {}
134
+ build {|xml| xml.optimize(opts) }
130
135
  end
131
-
136
+
132
137
  # generates a <rollback/> message
133
- def rollback opts={}
134
- build {|xml| xml.rollback opts}
138
+ def rollback
139
+ build {|xml| xml.rollback({}) }
135
140
  end
136
141
 
137
142
  # generates a <delete><id>ID</id></delete> message
138
143
  # "ids" can be a single value or array of values
139
- def delete_by_id(ids)
144
+ def delete_by_id ids
140
145
  ids = [ids] unless ids.is_a?(Array)
141
146
  build do |xml|
142
147
  xml.delete do |delete_node|
@@ -151,7 +156,7 @@ module RSolr::Xml
151
156
  queries = [queries] unless queries.is_a?(Array)
152
157
  build do |xml|
153
158
  xml.delete do |delete_node|
154
- queries.each { |query| delete_node.query query }
159
+ queries.each { |query| delete_node.query(query) }
155
160
  end
156
161
  end
157
162
  end
data/lib/rsolr.rb CHANGED
@@ -1,14 +1,10 @@
1
- require 'uri'
2
- require 'net/http'
3
- require 'net/https'
4
- require 'rubygems'
5
- require 'builder'
1
+ $: << "#{File.dirname(__FILE__)}" unless $:.include? File.dirname(__FILE__)
6
2
 
7
- $: << "#{File.dirname(__FILE__)}"
3
+ require 'rubygems'
8
4
 
9
5
  module RSolr
10
6
 
11
- %W(Char Client Error Http Uri Xml).each{|n|autoload n.to_sym, "rsolr/#{n.downcase}"}
7
+ %W(Char Client Connectable Error Http Uri Xml).each{|n|autoload n.to_sym, "rsolr/#{n.downcase}"}
12
8
 
13
9
  def self.version
14
10
  @version ||= File.read(File.join(File.dirname(__FILE__), '..', 'VERSION')).chomp
@@ -17,16 +13,10 @@ module RSolr
17
13
  VERSION = self.version
18
14
 
19
15
  def self.connect *args
20
- opts = parse_options *args
21
- Client.new Http.new(opts[0], opts[1])
16
+ Client.new Http.new(*args)
22
17
  end
23
18
 
24
- def self.parse_options *args
25
- opts = args[-1].kind_of?(Hash) ? args.pop : {}
26
- url = args.empty? ? 'http://127.0.0.1:8983/solr/' : args[0]
27
- uri = Uri.create url
28
- proxy = Uri.create opts[:proxy] if opts[:proxy]
29
- [uri, {:proxy => proxy}]
30
- end
19
+ # RSolr.escape
20
+ extend Char
31
21
 
32
22
  end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ describe "RSolr::Char" do
3
+
4
+ let(:char){Object.new.extend RSolr::Char}
5
+
6
+ it 'should escape everything that is not a word with \\' do
7
+ (0..255).each do |ascii|
8
+ chr = ascii.chr
9
+ esc = char.escape(chr)
10
+ if chr =~ /\W/
11
+ esc.to_s.should == "\\#{chr}"
12
+ else
13
+ esc.to_s.should == chr
14
+ end
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,158 @@
1
+ require 'spec_helper'
2
+ describe "RSolr::Client" do
3
+
4
+ module ClientHelper
5
+ def client
6
+ @client ||= (
7
+ connection = RSolr::Http.new :url => "http://localhost:9999/solr"
8
+ RSolr::Client.new connection
9
+ )
10
+ end
11
+ end
12
+
13
+ context "initialize" do
14
+ it "should accept whatevs and set it as the @connection" do
15
+ RSolr::Client.new(:whatevs).connection.should == :whatevs
16
+ end
17
+ end
18
+
19
+ context "send_request" do
20
+ include ClientHelper
21
+ it "should forward these method calls the #connection object" do
22
+ [:get, :post, :head].each do |meth|
23
+ client.connection.should_receive(:send_request).
24
+ and_return({:status => 200, :body => "{}", :headers => {}})
25
+ client.send_request '', :method => meth, :params => {}, :data => nil, :headers => {}
26
+ end
27
+ end
28
+ end
29
+
30
+ context "post" do
31
+ include ClientHelper
32
+ it "should pass the expected params to the connection's #post method" do
33
+ client.connection.should_receive(:send_request).
34
+ with(
35
+ "update", {:headers=>{"Content-Type"=>"text/plain"}, :method=>:post, :data=>"the data"}
36
+ ).
37
+ and_return(
38
+ :params=>{:wt=>:ruby},
39
+ :query=>"wt=ruby",
40
+ :path => "update",
41
+ :data=>"the data",
42
+ :method=>:post,
43
+ :headers=>{"Content-Type"=>"text/plain"}
44
+ )
45
+ client.post "update", :data => "the data", :headers => {"Content-Type" => "text/plain"}
46
+ end
47
+ end
48
+
49
+ context "xml" do
50
+ include ClientHelper
51
+ it "should return an instance of RSolr::Xml::Generator" do
52
+ client.xml.should be_a RSolr::Xml::Generator
53
+ end
54
+ end
55
+
56
+ context "add" do
57
+ include ClientHelper
58
+ it "should send xml to the connection's #post method" do
59
+ client.connection.should_receive(:send_request).
60
+ with(
61
+ "update", {:headers=>{"Content-Type"=>"text/xml"}, :method=>:post, :data=>"<xml/>"}
62
+ ).
63
+ and_return(
64
+ :path => "update",
65
+ :data => "<xml/>",
66
+ :headers => {"Content-Type"=>"text/xml"},
67
+ :method => :post,
68
+ :query => "wt=ruby",
69
+ :params => {:wt=>:ruby}
70
+ )
71
+ # the :xml attr is lazy loaded... so load it up first
72
+ client.xml
73
+ client.xml.should_receive(:add).
74
+ with({:id=>1}, {:commitWith=>10}).
75
+ and_return("<xml/>")
76
+ client.add({:id=>1}, :add_attributes => {:commitWith=>10})
77
+ end
78
+ end
79
+
80
+ context "update" do
81
+ include ClientHelper
82
+ it "should send data to the connection's #post method" do
83
+ client.connection.should_receive(:send_request).
84
+ with(
85
+ "update", {:headers=>{"Content-Type"=>"text/xml"}, :method=>:post, :data=>"<optimize/>"}
86
+ ).
87
+ and_return(
88
+ :path => "update",
89
+ :data => "<optimize/>",
90
+ :headers => {"Content-Type"=>"text/xml"},
91
+ :method => :post,
92
+ :query => "wt=ruby",
93
+ :params => {:wt=>:ruby}
94
+ )
95
+ client.update(:data => "<optimize/>")
96
+ end
97
+ end
98
+
99
+ context "post based helper methods:" do
100
+ include ClientHelper
101
+ [:commit, :optimize, :rollback].each do |meth|
102
+ it "should send a #{meth} message to the connection's #post method" do
103
+ client.connection.should_receive(:send_request).
104
+ with(
105
+ "update", {:headers=>{"Content-Type"=>"text/xml"}, :method=>:post, :data=>"<?xml version=\"1.0\" encoding=\"UTF-8\"?><#{meth}/>"}
106
+ ).
107
+ and_return(
108
+ :path => "update",
109
+ :data => "<?xml version=\"1.0\" encoding=\"UTF-8\"?><#{meth}/>",
110
+ :headers => {"Content-Type"=>"text/xml"},
111
+ :method => :post,
112
+ :query => "wt=ruby",
113
+ :params => {:wt=>:ruby}
114
+ )
115
+ client.send meth
116
+ end
117
+ end
118
+ end
119
+
120
+ context "delete_by_id" do
121
+ include ClientHelper
122
+ it "should send data to the connection's #post method" do
123
+ client.connection.should_receive(:send_request).
124
+ with(
125
+ "update", {:headers=>{"Content-Type"=>"text/xml"}, :method=>:post, :data=>"<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><id>1</id></delete>"}
126
+ ).
127
+ and_return(
128
+ :path => "update",
129
+ :data => "<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><id>1</id></delete>",
130
+ :headers => {"Content-Type"=>"text/xml"},
131
+ :method => :post,
132
+ :query => "wt=ruby",
133
+ :params => {:wt=>:ruby}
134
+ )
135
+ client.delete_by_id 1
136
+ end
137
+ end
138
+
139
+ context "delete_by_query" do
140
+ include ClientHelper
141
+ it "should send data to the connection's #post method" do
142
+ client.connection.should_receive(:send_request).
143
+ with(
144
+ "update", {:headers=>{"Content-Type"=>"text/xml"}, :method=>:post, :data=>"<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><query fq=\"category:&quot;trash&quot;\"/></delete>"}
145
+ ).
146
+ and_return(
147
+ :path => "update",
148
+ :data => "<?xml version=\"1.0\" encoding=\"UTF-8\"?><delete><query fq=\"category:&quot;trash&quot;\"/></delete>",
149
+ :headers => {"Content-Type"=>"text/xml"},
150
+ :method => :post,
151
+ :query => "wt=ruby",
152
+ :params => {:wt=>:ruby}
153
+ )
154
+ client.delete_by_query :fq => "category:\"trash\""
155
+ end
156
+ end
157
+
158
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe "RSolr::Connectable" do
4
+
5
+ def connectable
6
+ Object.new.extend RSolr::Connectable
7
+ end
8
+
9
+ context "adapt_response" do
10
+
11
+ it 'should not try to evaluate ruby when the :qt is not :ruby' do
12
+ body = '{:time=>"NOW"}'
13
+ result = connectable.adapt_response({:params=>{}}, {:status => 200, :body => body, :headers => {}})
14
+ result.should be_a(String)
15
+ result.should == body
16
+ end
17
+
18
+ it 'should evaluate ruby responses when the :wt is :ruby' do
19
+ body = '{:time=>"NOW"}'
20
+ result = connectable.adapt_response({:params=>{:wt=>:ruby}}, {:status => 200, :body => body, :headers => {}})
21
+ result.should be_a(Hash)
22
+ result.should == {:time=>"NOW"}
23
+ end
24
+
25
+ it "ought raise a RSolr::Error::InvalidRubyResponse when the ruby is indeed frugged" do
26
+ lambda {
27
+ connectable.adapt_response({:params=>{:wt => :ruby}}, {:status => 200, :body => "<woops/>", :headers => {}})
28
+ }.should raise_error RSolr::Error::InvalidRubyResponse
29
+ end
30
+
31
+ end
32
+
33
+ context "build_request" do
34
+
35
+ it 'should return a request context array' do
36
+ result = connectable.build_request 'select', :method => :post, :params => {:q=>'test', :fq=>[0,1]}, :data => "data", :headers => {}
37
+ [/fq=0/, /fq=1/, /q=test/, /wt=ruby/].each do |pattern|
38
+ result[:query].should match pattern
39
+ end
40
+ result[:data].should == "data"
41
+ result[:headers].should == {}
42
+ end
43
+
44
+ it "should set the Content-Type header to application/x-www-form-urlencoded if a hash is passed in to the data arg" do
45
+ result = connectable.build_request 'select', :method => :post, :data => {:q=>'test', :fq=>[0,1]}, :headers => {}
46
+ result[:query].should == "wt=ruby"
47
+ [/fq=0/, /fq=1/, /q=test/].each do |pattern|
48
+ result[:data].should match pattern
49
+ end
50
+ result[:data].should_not match /wt=ruby/
51
+ result[:headers].should == {"Content-Type" => "application/x-www-form-urlencoded"}
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+ describe "RSolr::Http" do
3
+ # it "should raise an Http error if the response status code aint right" do
4
+ # client.connection.should_receive(:get).
5
+ # and_return({:status => 400, :body => "", :headers => {}})
6
+ # lambda{
7
+ # client.send_request '', :method => :get
8
+ # }.should raise_error(RSolr::Error::Http) {|error|
9
+ # error.should be_a(RSolr::Error::Http)
10
+ # error.should respond_to(:request)
11
+ # error.should respond_to(:response)
12
+ # }
13
+ # end
14
+ end
File without changes
@@ -9,7 +9,7 @@ describe "RSolr::Xml" do
9
9
  [:optimize, :rollback, :commit].each do |meth|
10
10
  it "#{meth} should generator xml" do
11
11
  result = generator.send(meth)
12
- result.should match(Regexp.escape("<#{meth}/>"))
12
+ result.should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?><#{meth}/>"
13
13
  end
14
14
  end
15
15
 
metadata CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
6
6
  - 1
7
7
  - 0
8
8
  - 0
9
- - beta
10
- version: 1.0.0.beta
9
+ - beta2
10
+ version: 1.0.0.beta2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matt Mitchell
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-29 00:00:00 -04:00
18
+ date: 2010-07-12 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -48,6 +48,7 @@ files:
48
48
  - lib/rsolr.rb
49
49
  - lib/rsolr/char.rb
50
50
  - lib/rsolr/client.rb
51
+ - lib/rsolr/connectable.rb
51
52
  - lib/rsolr/error.rb
52
53
  - lib/rsolr/http.rb
53
54
  - lib/rsolr/uri.rb
@@ -85,12 +86,12 @@ signing_key:
85
86
  specification_version: 3
86
87
  summary: A Ruby client for Apache Solr
87
88
  test_files:
88
- - spec/api/rsolr_client_spec.rb
89
- - spec/api/rsolr_error_spec.rb
90
- - spec/api/rsolr_http_spec.rb
91
- - spec/api/rsolr_spec.rb
92
- - spec/api/rsolr_uri_spec.rb
93
- - spec/api/rsolr_xml_spec.rb
89
+ - spec/api/char_spec.rb
90
+ - spec/api/client_spec.rb
91
+ - spec/api/connectable_spec.rb
92
+ - spec/api/http_spec.rb
93
+ - spec/api/uri_spec.rb
94
+ - spec/api/xml_spec.rb
94
95
  - spec/spec_helper.rb
95
96
  - Rakefile
96
97
  - tasks/spec.rake