rsolr 0.12.0 → 0.12.1

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