rsolr 0.9.6 → 0.9.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES.txt +15 -0
- data/README.rdoc +7 -33
- data/Rakefile +7 -69
- data/examples/http.rb +2 -3
- data/lib/rsolr/connection/{adapter/direct.rb → direct.rb} +2 -2
- data/lib/rsolr/connection/net_http.rb +79 -0
- data/lib/rsolr/connection.rb +57 -109
- data/lib/rsolr/message.rb +25 -24
- data/lib/rsolr.rb +9 -7
- data/lib/xout.rb +65 -0
- data/test/connection/direct_test.rb +2 -2
- data/test/connection/{http_test.rb → net_http_test.rb} +2 -2
- data/test/{http_client/util_test.rb → connection/utils_test.rb} +1 -1
- data/test/message_test.rb +2 -29
- metadata +12 -29
- data/lib/rsolr/connection/adapter/http.rb +0 -42
- data/lib/rsolr/http_client/adapter/curb.rb +0 -51
- data/lib/rsolr/http_client/adapter/net_http.rb +0 -48
- data/lib/rsolr/http_client.rb +0 -149
- data/lib/rsolr/message/adapter/builder.rb +0 -85
- data/lib/rsolr/message/adapter/libxml.rb +0 -59
- data/rsolr.gemspec +0 -46
- data/test/http_client/curb_test.rb +0 -18
- data/test/http_client/net_http_test.rb +0 -12
- data/test/http_client/test_methods.rb +0 -40
data/CHANGES.txt
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
0.9.7.1 - November 5, 2009
|
2
|
+
added support for multibyte url characters in RSolr::Connection::Utils
|
3
|
+
- this is because Ruby 1.9's String size method is different than 1.8
|
4
|
+
|
5
|
+
0.9.7 - October 23, 2009
|
6
|
+
Removed XML message builders - using pure Ruby generator instead
|
7
|
+
- benchmarks show generation speed is a little faster than libxml
|
8
|
+
- minimal xml escaping so binary posting to Solr should no longer be a problem.
|
9
|
+
Changed response.adapter_resonse to response.raw
|
10
|
+
Removed HTTP adapters - sticking with NetHTTP
|
11
|
+
Removed builder dependency in gemspec
|
12
|
+
Removed Adapter and HTTPClient modules
|
13
|
+
Moved HTTPCLient::Util to Connection::Utils
|
14
|
+
Updated all tests
|
15
|
+
|
1
16
|
0.9.6 - September 9, 2009
|
2
17
|
Added ability to create direct connections from existing Java::OrgApacheSolrCore::SolrCore
|
3
18
|
Added ability to send queries using POST
|
data/README.rdoc
CHANGED
@@ -3,8 +3,8 @@
|
|
3
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.
|
4
4
|
|
5
5
|
== Installation:
|
6
|
-
gem sources -a http://
|
7
|
-
sudo gem install
|
6
|
+
gem sources -a http://gemcutter.org
|
7
|
+
sudo gem install rsolr
|
8
8
|
|
9
9
|
==Related Resources & Projects
|
10
10
|
* {Solr}[http://lucene.apache.org/solr/]
|
@@ -100,12 +100,6 @@ Commit & optimize shortcuts
|
|
100
100
|
solr.commit
|
101
101
|
solr.optimize
|
102
102
|
|
103
|
-
===XML Builders for RSolr
|
104
|
-
As of version 0.9.1, RSolr can use LibXml to create the update messages sent to solr. To switch from Builder to LibXml, set the RSolr::Message.builder like:
|
105
|
-
solr = RSolr.connect
|
106
|
-
solr.message.adapter = RSolr::Message::Adapter::Libxml.new
|
107
|
-
|
108
|
-
|
109
103
|
== Response Formats
|
110
104
|
The default response format is Ruby. When the :wt param is set to :ruby, the response is eval'd resulting in a Hash. You can get a raw response by setting the :wt to "ruby" - notice, the string -- not a symbol. RSolr will eval the Ruby string ONLY if the :wt value is :ruby. All other response formats are available as expected, :wt=>'xml' etc..
|
111
105
|
|
@@ -119,30 +113,10 @@ The default response format is Ruby. When the :wt param is set to :ruby, the res
|
|
119
113
|
===JSON:
|
120
114
|
solr.select(:wt=>:json)
|
121
115
|
|
122
|
-
You can access the original request context (path, params, url etc.) by calling the #
|
116
|
+
You can access the original request context (path, params, url etc.) by calling the #raw method:
|
123
117
|
response = solr.select :q=>'*:*'
|
124
|
-
response.
|
125
|
-
response.
|
126
|
-
response.
|
127
|
-
|
128
|
-
The adapter_response is a hash that contains the generated params, url, path, post data, headers etc., very useful for debugging and testing.
|
129
|
-
|
130
|
-
|
131
|
-
== HTTP Client Adapter
|
132
|
-
You can specify the http client adapter:
|
133
|
-
:net_http uses the standard Net::HTTP library
|
134
|
-
:curb uses the C based "curl" library
|
118
|
+
response.raw[:status_code]
|
119
|
+
response.raw[:body]
|
120
|
+
response.raw[:url]
|
135
121
|
|
136
|
-
|
137
|
-
|
138
|
-
Example:
|
139
|
-
|
140
|
-
RSolr.connect(:adapter => :curb)
|
141
|
-
RSolr.connect(:adapter => :net_http)
|
142
|
-
|
143
|
-
Intereseting read about Ruby's Net::HTTP library:
|
144
|
-
http://apocryph.org/2008/11/09/more_indepth_analysis_ruby_http_client_performance
|
145
|
-
|
146
|
-
NOTE: You can't use the :curb adapter under jRuby. To install curb:
|
147
|
-
|
148
|
-
sudo gem install curb
|
122
|
+
The raw is a hash that contains the generated params, url, path, post data, headers etc., very useful for debugging and testing.
|
data/Rakefile
CHANGED
@@ -1,76 +1,14 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/testtask'
|
3
3
|
require 'rake/rdoctask'
|
4
|
-
|
5
|
-
namespace :rsolr do
|
6
|
-
|
7
|
-
desc "Starts the HTTP server used for running HTTP connection tests"
|
8
|
-
task :start_test_server do
|
9
|
-
system "cd apache-solr/example; java -jar start.jar"
|
10
|
-
end
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
task :default => [:test_units]
|
15
|
-
|
16
|
-
# rake package
|
17
|
-
|
18
|
-
require 'rubygems'
|
19
4
|
require 'rake/gempackagetask'
|
20
|
-
raw_spec = File.read 'rsolr.gemspec'
|
21
|
-
spec = eval(raw_spec)
|
22
|
-
Rake::GemPackageTask.new(spec) do |pkg|
|
23
|
-
pkg.need_tar = true
|
24
|
-
end
|
25
|
-
|
26
|
-
desc "Run basic tests"
|
27
|
-
Rake::TestTask.new("test_units") { |t|
|
28
|
-
t.pattern = 'test/**/*_test.rb'
|
29
|
-
t.verbose = true
|
30
|
-
t.warning = true
|
31
|
-
t.libs << "test"
|
32
|
-
}
|
33
|
-
|
34
|
-
require 'spec/rake/spectask'
|
35
|
-
|
36
|
-
desc "Run specs"
|
37
|
-
Spec::Rake::SpecTask.new('spec') do |t|
|
38
|
-
t.spec_files = FileList['spec/**/*_spec.rb']
|
39
|
-
t.libs += ["lib", "spec"]
|
40
|
-
end
|
41
|
-
|
42
|
-
desc 'Run specs' # this task runs each test in its own process
|
43
|
-
task :specs do
|
44
|
-
require 'rubygems'
|
45
|
-
require 'facets/more/filelist' unless defined?(FileList)
|
46
|
-
files = FileList["**/*_spec.rb"]
|
47
|
-
p files.to_a
|
48
|
-
files.each do |filename|
|
49
|
-
system "cd #{File.dirname(filename)} && ruby #{File.basename(filename)}"
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
desc "Run specs"
|
54
|
-
Rake::TestTask.new("specs") { |t|
|
55
|
-
t.pattern = 'spec/**/*_spec.rb'
|
56
|
-
t.verbose = true
|
57
|
-
t.warning = true
|
58
|
-
t.libs += ["lib", "spec"]
|
59
|
-
}
|
60
5
|
|
61
|
-
|
62
|
-
|
63
|
-
task :
|
64
|
-
|
65
|
-
FileUtils.rm_rf "pkg"
|
6
|
+
ENV['RUBYOPT'] = '-W1'
|
7
|
+
|
8
|
+
task :environment do
|
9
|
+
require File.dirname(__FILE__) + '/lib/rsolr'
|
66
10
|
end
|
11
|
+
|
12
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
67
13
|
|
68
|
-
|
69
|
-
desc 'Generate documentation for the rsolr gem.'
|
70
|
-
Rake::RDocTask.new(:doc) do |rdoc|
|
71
|
-
rdoc.rdoc_dir = 'doc'
|
72
|
-
rdoc.title = 'RSolr'
|
73
|
-
rdoc.options << '--line-numbers' << '--inline-source'
|
74
|
-
rdoc.rdoc_files.include('README.rdoc')
|
75
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
76
|
-
end
|
14
|
+
task :default => ['spec:api']
|
data/examples/http.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '..', 'lib', 'rsolr')
|
2
2
|
|
3
|
-
|
4
|
-
solr = RSolr.connect :adapter=>:curb
|
3
|
+
solr = RSolr.connect
|
5
4
|
|
6
5
|
Dir['../apache-solr/example/exampledocs/*.xml'].each do |xml_file|
|
7
6
|
puts "Updating with #{xml_file}"
|
@@ -14,7 +13,7 @@ puts
|
|
14
13
|
|
15
14
|
response = solr.select(:q=>'ipod', :fq=>['price:[0 TO 50]'], :rows=>2, :start=>0)
|
16
15
|
|
17
|
-
puts "URL : #{response.
|
16
|
+
puts "URL : #{response.raw[:url]} -> #{response.raw[:status_code]}"
|
18
17
|
|
19
18
|
puts
|
20
19
|
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
#
|
4
|
+
# Connection for standard HTTP Solr server
|
5
|
+
#
|
6
|
+
class RSolr::Connection::NetHttp
|
7
|
+
|
8
|
+
include RSolr::Connection::Utils
|
9
|
+
|
10
|
+
attr_reader :opts, :uri
|
11
|
+
|
12
|
+
# opts can have:
|
13
|
+
# :url => 'http://localhost:8080/solr'
|
14
|
+
def initialize opts={}
|
15
|
+
opts[:url] ||= 'http://127.0.0.1:8983/solr'
|
16
|
+
@opts = opts
|
17
|
+
@uri = URI.parse opts[:url]
|
18
|
+
end
|
19
|
+
|
20
|
+
# send a request to the connection
|
21
|
+
# request '/update', :wt=>:xml, '</commit>'
|
22
|
+
def request path, params={}, *extra
|
23
|
+
opts = extra[-1].kind_of?(Hash) ? extra.pop : {}
|
24
|
+
data = extra[0]
|
25
|
+
# force a POST, use the query string as the POST body
|
26
|
+
if opts[:method] == :post and data.to_s.empty?
|
27
|
+
http_context = self.post(path, hash_to_query(params), {}, {'Content-Type' => 'application/x-www-form-urlencoded'})
|
28
|
+
else
|
29
|
+
if data
|
30
|
+
# standard POST, using "data" as the POST body
|
31
|
+
http_context = self.post(path, data, params, {"Content-Type" => 'text/xml; charset=utf-8'})
|
32
|
+
else
|
33
|
+
# standard GET
|
34
|
+
http_context = self.get(path, params)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
raise RSolr::RequestError.new(http_context[:body]) unless http_context[:status_code] == 200
|
38
|
+
http_context
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def connection
|
44
|
+
@connection ||= Net::HTTP.new(@uri.host, @uri.port)
|
45
|
+
end
|
46
|
+
|
47
|
+
def get path, params={}
|
48
|
+
url = self.build_url path, params
|
49
|
+
net_http_response = self.connection.get url
|
50
|
+
create_http_context net_http_response, url, path, params
|
51
|
+
end
|
52
|
+
|
53
|
+
def post path, data, params={}, headers={}
|
54
|
+
url = self.build_url path, params
|
55
|
+
net_http_response = self.connection.post url, data, headers
|
56
|
+
create_http_context net_http_response, url, path, params, data, headers
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_http_context net_http_response, url, path, params, data=nil, headers={}
|
60
|
+
full_url = "#{@uri.scheme}://#{@uri.host}"
|
61
|
+
full_url += @uri.port ? ":#{@uri.port}" : ''
|
62
|
+
full_url += url
|
63
|
+
{
|
64
|
+
:status_code=>net_http_response.code.to_i,
|
65
|
+
:url=>full_url,
|
66
|
+
:body=>net_http_response.body,
|
67
|
+
:path=>path,
|
68
|
+
:params=>params,
|
69
|
+
:data=>data,
|
70
|
+
:headers=>headers
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def build_url path, params={}
|
75
|
+
full_path = @uri.path + path
|
76
|
+
super full_path, params, @uri.query
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
data/lib/rsolr/connection.rb
CHANGED
@@ -1,124 +1,72 @@
|
|
1
1
|
module RSolr::Connection
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
autoload :HTTP, 'rsolr/connection/adapter/http'
|
6
|
-
end
|
7
|
-
|
8
|
-
class Base
|
9
|
-
|
10
|
-
attr_reader :adapter
|
11
|
-
|
12
|
-
# "adapter" is instance of:
|
13
|
-
# RSolr::Adapter::HTTP
|
14
|
-
# RSolr::Adapter::Direct (jRuby only)
|
15
|
-
# or any other class that uses the connection "interface"
|
16
|
-
def initialize(adapter)
|
17
|
-
@adapter = adapter
|
18
|
-
end
|
3
|
+
autoload :Direct, 'rsolr/connection/direct'
|
4
|
+
autoload :NetHttp, 'rsolr/connection/net_http'
|
19
5
|
|
20
|
-
|
21
|
-
|
22
|
-
|
6
|
+
# Helpful utility methods for building queries to a Solr server
|
7
|
+
module Utils
|
8
|
+
|
9
|
+
# Performs URI escaping so that you can construct proper
|
10
|
+
# query strings faster. Use this rather than the cgi.rb
|
11
|
+
# version since it's faster. (Stolen from Rack).
|
12
|
+
def escape(s)
|
13
|
+
s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
|
14
|
+
#'%'+$1.unpack('H2'*$1.size).join('%').upcase
|
15
|
+
'%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
|
16
|
+
}.tr(' ', '+')
|
23
17
|
end
|
24
18
|
|
25
|
-
#
|
26
|
-
#
|
27
|
-
|
28
|
-
|
19
|
+
# Return the bytesize of String; uses String#length under Ruby 1.8 and
|
20
|
+
# String#bytesize under 1.9.
|
21
|
+
if ''.respond_to?(:bytesize)
|
22
|
+
def bytesize(string)
|
23
|
+
string.bytesize
|
24
|
+
end
|
25
|
+
else
|
26
|
+
def bytesize(string)
|
27
|
+
string.size
|
28
|
+
end
|
29
29
|
end
|
30
30
|
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
adapt_response(response)
|
31
|
+
# creates and returns a url as a string
|
32
|
+
# "url" is the base url
|
33
|
+
# "params" is an optional hash of GET style query params
|
34
|
+
# "string_query" is an extra query string that will be appended to the
|
35
|
+
# result of "url" and "params".
|
36
|
+
def build_url url='', params={}, string_query=''
|
37
|
+
queries = [string_query, hash_to_query(params)]
|
38
|
+
queries.delete_if{|i| i.to_s.empty?}
|
39
|
+
url += "?#{queries.join('&')}" unless queries.empty?
|
40
|
+
url
|
42
41
|
end
|
43
|
-
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
42
|
+
|
43
|
+
# converts a key value pair to an escaped string:
|
44
|
+
# Example:
|
45
|
+
# build_param(:id, 1) == "id=1"
|
46
|
+
def build_param(k,v)
|
47
|
+
"#{escape(k)}=#{escape(v)}"
|
48
|
+
end
|
49
|
+
|
47
50
|
#
|
48
|
-
#
|
49
|
-
#
|
51
|
+
# converts hash into URL query string, keys get an alpha sort
|
52
|
+
# if a value is an array, the array values get mapped to the same key:
|
53
|
+
# hash_to_query(:q=>'blah', :fq=>['blah', 'blah'], :facet=>{:field=>['location_facet', 'format_facet']})
|
54
|
+
# returns:
|
55
|
+
# ?q=blah&fq=blah&fq=blah&facet.field=location_facet&facet.field=format.facet
|
50
56
|
#
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
# send </optimize>
|
61
|
-
def optimize
|
62
|
-
update message.optimize
|
63
|
-
end
|
64
|
-
|
65
|
-
# send </rollback>
|
66
|
-
# NOTE: solr 1.4 only
|
67
|
-
def rollback
|
68
|
-
update message.rollback
|
69
|
-
end
|
70
|
-
|
71
|
-
# Delete one or many documents by id
|
72
|
-
# solr.delete_by_id 10
|
73
|
-
# solr.delete_by_id([12, 41, 199])
|
74
|
-
def delete_by_id(id)
|
75
|
-
update message.delete_by_id(id)
|
76
|
-
end
|
77
|
-
|
78
|
-
# delete one or many documents by query
|
79
|
-
# solr.delete_by_query 'available:0'
|
80
|
-
# solr.delete_by_query ['quantity:0', 'manu:"FQ"']
|
81
|
-
def delete_by_query(query)
|
82
|
-
update message.delete_by_query(query)
|
83
|
-
end
|
84
|
-
|
85
|
-
# shortcut to RSolr::Message::Builder
|
86
|
-
def message
|
87
|
-
@message ||= RSolr::Message::Builder.new
|
88
|
-
end
|
89
|
-
|
90
|
-
protected
|
91
|
-
|
92
|
-
# sets default params etc.. - could be used as a mapping hook
|
93
|
-
# type of request should be passed in here? -> map_params(:query, {})
|
94
|
-
def map_params(params)
|
95
|
-
params||={}
|
96
|
-
{:wt=>:ruby}.merge(params)
|
97
|
-
end
|
98
|
-
|
99
|
-
# "adapter_response" must be a hash with the following keys:
|
100
|
-
# :params - a sub hash of standard solr params
|
101
|
-
# : body - the raw response body from the solr server
|
102
|
-
# This method will evaluate the :body value if the params[:wt] == :ruby
|
103
|
-
# otherwise, the body is returned
|
104
|
-
# The return object has a special method attached called #adapter_response
|
105
|
-
# This method gives you access to the original response from the adapter,
|
106
|
-
# so you can access things like the actual :url sent to solr,
|
107
|
-
# the raw :body, original :params and original :data
|
108
|
-
def adapt_response(adapter_response)
|
109
|
-
data = adapter_response[:body]
|
110
|
-
# if the wt is :ruby, evaluate the ruby string response
|
111
|
-
if adapter_response[:params][:wt] == :ruby
|
112
|
-
data = Kernel.eval(data)
|
113
|
-
end
|
114
|
-
# attach a method called #adapter_response that returns the original adapter response value
|
115
|
-
def data.adapter_response
|
116
|
-
@adapter_response
|
57
|
+
# if a value is empty/nil etc., it is not added
|
58
|
+
def hash_to_query(params)
|
59
|
+
mapped = params.map do |k, v|
|
60
|
+
next if v.to_s.empty?
|
61
|
+
if v.class == Array
|
62
|
+
hash_to_query(v.map { |x| [k, x] })
|
63
|
+
else
|
64
|
+
build_param k, v
|
65
|
+
end
|
117
66
|
end
|
118
|
-
|
119
|
-
data
|
67
|
+
mapped.compact.join("&")
|
120
68
|
end
|
121
|
-
|
69
|
+
|
122
70
|
end
|
123
71
|
|
124
72
|
end
|
data/lib/rsolr/message.rb
CHANGED
@@ -2,11 +2,6 @@
|
|
2
2
|
|
3
3
|
module RSolr::Message
|
4
4
|
|
5
|
-
module Adapter
|
6
|
-
autoload :Builder, 'rsolr/message/adapter/builder'
|
7
|
-
autoload :Libxml, 'rsolr/message/adapter/libxml'
|
8
|
-
end
|
9
|
-
|
10
5
|
# A class that represents a "doc" xml element for a solr update
|
11
6
|
class Document
|
12
7
|
|
@@ -25,7 +20,7 @@ module RSolr::Message
|
|
25
20
|
values = [values] unless values.is_a?(Array)
|
26
21
|
values.each do |v|
|
27
22
|
next if v.to_s.empty?
|
28
|
-
@fields << Field.new({:name=>field}, v)
|
23
|
+
@fields << Field.new({:name=>field}, v.to_s)
|
29
24
|
end
|
30
25
|
end
|
31
26
|
@attrs={}
|
@@ -79,15 +74,6 @@ module RSolr::Message
|
|
79
74
|
|
80
75
|
class Builder
|
81
76
|
|
82
|
-
attr_writer :adapter
|
83
|
-
|
84
|
-
# b = Builder.new
|
85
|
-
# b.adapter = RSolr::Message::Adapter::LibXML.new
|
86
|
-
# b.optimize == '<optimize/>'
|
87
|
-
def adapter
|
88
|
-
@adapter ||= RSolr::Message::Adapter::Builder.new
|
89
|
-
end
|
90
|
-
|
91
77
|
# generates "add" xml for updating solr
|
92
78
|
# "data" can be a hash or an array of hashes.
|
93
79
|
# - each hash should be a simple key=>value pair representing a solr doc.
|
@@ -115,39 +101,54 @@ module RSolr::Message
|
|
115
101
|
#
|
116
102
|
def add(data, add_attrs={})
|
117
103
|
data = [data] unless data.is_a?(Array)
|
118
|
-
|
104
|
+
add = Xout.new :add, add_attrs
|
105
|
+
data.each do |doc|
|
119
106
|
doc = Document.new(doc) if doc.respond_to?(:each_pair)
|
120
107
|
yield doc if block_given?
|
121
|
-
doc
|
108
|
+
add.child :doc, doc.attrs do |doc_node|
|
109
|
+
doc.fields.each do |field_obj|
|
110
|
+
doc_node.child :field, field_obj.value, field_obj.attrs
|
111
|
+
end
|
112
|
+
end
|
122
113
|
end
|
123
|
-
|
114
|
+
add.to_xml
|
124
115
|
end
|
125
116
|
|
126
117
|
# generates a <commit/> message
|
127
118
|
def commit(opts={})
|
128
|
-
|
119
|
+
Xout.new(:commit, opts).to_xml
|
129
120
|
end
|
130
121
|
|
131
122
|
# generates a <optimize/> message
|
132
123
|
def optimize(opts={})
|
133
|
-
|
124
|
+
Xout.new(:optimize, opts).to_xml
|
134
125
|
end
|
135
126
|
|
136
127
|
# generates a <rollback/> message
|
137
128
|
def rollback
|
138
|
-
|
129
|
+
Xout.new(:rollback).to_xml
|
139
130
|
end
|
140
131
|
|
141
132
|
# generates a <delete><id>ID</id></delete> message
|
142
133
|
# "ids" can be a single value or array of values
|
143
134
|
def delete_by_id(ids)
|
144
|
-
|
135
|
+
ids = [ids] unless ids.is_a?(Array)
|
136
|
+
delete_node = Xout.new(:delete) do |xml|
|
137
|
+
ids.each { |id| xml.child :id, id }
|
138
|
+
end
|
139
|
+
delete_node.to_xml
|
145
140
|
end
|
146
141
|
|
147
142
|
# generates a <delete><query>ID</query></delete> message
|
148
143
|
# "queries" can be a single value or an array of values
|
149
144
|
def delete_by_query(queries)
|
150
|
-
|
145
|
+
queries = [queries] unless queries.is_a?(Array)
|
146
|
+
delete_node = Xout.new(:delete) do |xml|
|
147
|
+
queries.each { |query| xml.child :query, query }
|
148
|
+
end
|
149
|
+
delete_node.to_xml
|
151
150
|
end
|
151
|
+
|
152
152
|
end
|
153
|
-
|
153
|
+
|
154
|
+
end
|
data/lib/rsolr.rb
CHANGED
@@ -4,13 +4,15 @@ require 'rubygems'
|
|
4
4
|
|
5
5
|
$: << File.dirname(__FILE__) unless $:.include?(File.dirname(__FILE__))
|
6
6
|
|
7
|
+
require 'xout'
|
8
|
+
|
7
9
|
module RSolr
|
8
10
|
|
9
|
-
VERSION = '0.9.
|
11
|
+
VERSION = '0.9.7'
|
10
12
|
|
11
13
|
autoload :Message, 'rsolr/message'
|
14
|
+
autoload :Client, 'rsolr/client'
|
12
15
|
autoload :Connection, 'rsolr/connection'
|
13
|
-
autoload :HTTPClient, 'rsolr/http_client'
|
14
16
|
|
15
17
|
# Factory for creating connections.
|
16
18
|
# 2 modes of argument operations:
|
@@ -28,16 +30,16 @@ module RSolr
|
|
28
30
|
type = args.first.is_a?(Symbol) ? args.shift : :http
|
29
31
|
opts = args
|
30
32
|
type_class = case type
|
31
|
-
when :http,nil
|
32
|
-
'
|
33
|
+
when :net_http,:http,nil
|
34
|
+
'NetHttp'
|
33
35
|
when :direct
|
34
36
|
'Direct'
|
35
37
|
else
|
36
38
|
raise "Invalid connection type: #{type} - use :http, :direct or leave nil for :http/default"
|
37
39
|
end
|
38
|
-
adapter_class = RSolr::Connection
|
40
|
+
adapter_class = RSolr::Connection.const_get(type_class)
|
39
41
|
adapter = adapter_class.new(*opts)
|
40
|
-
RSolr::
|
42
|
+
RSolr::Client.new(adapter)
|
41
43
|
end
|
42
44
|
|
43
45
|
# A module that contains string related methods
|
@@ -55,7 +57,7 @@ module RSolr
|
|
55
57
|
# send the escape method into the Connection class ->
|
56
58
|
# solr = RSolr.connect
|
57
59
|
# solr.escape('asdf')
|
58
|
-
RSolr::
|
60
|
+
RSolr::Client.send(:include, Char)
|
59
61
|
|
60
62
|
# bring escape into this module (RSolr) -> RSolr.escape('asdf')
|
61
63
|
extend Char
|
data/lib/xout.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
class Xout
|
2
|
+
|
3
|
+
attr_reader :name, :text, :attrs, :children
|
4
|
+
|
5
|
+
def initialize node_name, *args, &block
|
6
|
+
@children = []
|
7
|
+
attrs = args.last.is_a?(Hash) ? args.pop : {}
|
8
|
+
text = args.empty? ? '' : args.pop.to_s
|
9
|
+
@name, @text, @attrs = node_name, text, attrs
|
10
|
+
yield self if block_given?
|
11
|
+
end
|
12
|
+
|
13
|
+
def child name, *args, &block
|
14
|
+
add_child self.class.new(name, *args, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_child node
|
18
|
+
children << node
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_xml
|
22
|
+
xml = ["<#{name}#{create_attrs(attrs)}"]
|
23
|
+
if not text.empty? or not children.empty?
|
24
|
+
xml << ">#{escape_text text.to_s}"
|
25
|
+
xml += children.map{|child|child.to_xml}
|
26
|
+
xml << "</#{name}>"
|
27
|
+
else
|
28
|
+
xml << '/>'
|
29
|
+
end
|
30
|
+
xml.join
|
31
|
+
end
|
32
|
+
|
33
|
+
alias :to_s :to_xml
|
34
|
+
|
35
|
+
def to_xml_doc
|
36
|
+
'<?xml version="1.0" encoding="UTF-8"?>' + to_xml
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
# builds an XML attribute string.
|
42
|
+
# escapes each attribute value by running it through #escape_attr
|
43
|
+
def create_attrs hash
|
44
|
+
r = hash.map { |k,v| "#{k}=\"#{escape_attr v.to_s}\"" }.join(' ')
|
45
|
+
" #{r}" unless r.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
# minimal escaping for attribute values
|
49
|
+
def escape_attr input
|
50
|
+
escape input, '&'=>'&', '<'=>'<', '>'=>'>', "'"=>''', '"'=>'"e;'
|
51
|
+
end
|
52
|
+
|
53
|
+
# minimal escaping for text
|
54
|
+
def escape_text input
|
55
|
+
escape input, '&'=>'&', '<'=>'<', '>'=>'>'
|
56
|
+
end
|
57
|
+
|
58
|
+
# accepts a string input and a hash mapping of characters => replacement values:
|
59
|
+
# Example:
|
60
|
+
# escape 'My <string>cat</strong>', '<'=>'>', '>'=>'<'
|
61
|
+
def escape input, map
|
62
|
+
input.gsub(/[#{map.keys.join}]+/) { | char | map[char] || char }
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|