rsolr 1.0.0.beta → 1.0.0.beta2

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/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