mwmitchell-rsolr 0.8.4 → 0.8.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +8 -0
- data/LICENSE +0 -0
- data/Rakefile +0 -0
- data/examples/direct.rb +0 -0
- data/examples/http.rb +6 -5
- data/lib/core_ext.rb +0 -0
- data/lib/mash.rb +0 -0
- data/lib/rsolr/adapter/direct.rb +0 -2
- data/lib/rsolr/adapter/http.rb +1 -5
- data/lib/rsolr/adapter.rb +0 -0
- data/lib/rsolr/http_client/adapter.rb +0 -0
- data/lib/rsolr/http_client.rb +27 -4
- data/lib/rsolr/message.rb +19 -6
- data/lib/rsolr.rb +3 -1
- data/test/connection/direct_test.rb +0 -0
- data/test/connection/http_test.rb +0 -0
- data/test/connection/test_methods.rb +0 -0
- data/test/http_client/curb_test.rb +0 -0
- data/test/http_client/net_http_test.rb +0 -0
- data/test/http_client/test_methods.rb +0 -0
- data/test/http_client/util_test.rb +0 -0
- data/test/message_test.rb +29 -1
- metadata +2 -5
- data/spec/connection_spec.rb +0 -151
- data/spec/helper.rb +0 -4
- data/spec/rsolr_spec.rb +0 -29
data/CHANGES.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
0.8.5 - April 7, 2009
|
2
|
+
The RSolr::Message #add method now accepts a single Message::Document or an array of Message::Document objects
|
3
|
+
The Message::Document class has a new method: #add_field
|
4
|
+
Tests added for both changes
|
5
|
+
Permissions of files changed to non-executable
|
6
|
+
-- the above changes were made by Mat Brown, thank you Mat!
|
7
|
+
Added CannedSolrResponse module for mocks in the specs... not used yet
|
8
|
+
|
1
9
|
0.8.4 - April 3, 2009
|
2
10
|
New test suite using RSpec and mocks coming. Run "rake spec"
|
3
11
|
- added specs for RSolr and RSolr::Connection
|
data/LICENSE
CHANGED
File without changes
|
data/Rakefile
CHANGED
File without changes
|
data/examples/direct.rb
CHANGED
File without changes
|
data/examples/http.rb
CHANGED
@@ -12,11 +12,12 @@ end
|
|
12
12
|
|
13
13
|
puts
|
14
14
|
|
15
|
-
solr.select(:q=>'ipod', :fq=>'price:[0 TO 50]', :rows=>2, :start=>0)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
response = solr.select(:q=>'ipod', :fq=>'price:[0 TO 50]', :rows=>2, :start=>0)
|
16
|
+
|
17
|
+
puts "URL : #{response.adapter_response[:url]} -> #{response.adapter_response[:status_code]}"
|
18
|
+
|
19
|
+
solr_response[:response][:docs].each do |doc|
|
20
|
+
puts doc[:timestamp]
|
20
21
|
end
|
21
22
|
|
22
23
|
solr.delete_by_query('*:*') and solr.commit
|
data/lib/core_ext.rb
CHANGED
File without changes
|
data/lib/mash.rb
CHANGED
File without changes
|
data/lib/rsolr/adapter/direct.rb
CHANGED
data/lib/rsolr/adapter/http.rb
CHANGED
@@ -7,10 +7,6 @@ class RSolr::Adapter::HTTP
|
|
7
7
|
|
8
8
|
# opts can have:
|
9
9
|
# :url => 'http://localhost:8080/solr'
|
10
|
-
# :select_path => '/the/url/path/to/the/select/handler'
|
11
|
-
# :update_path => '/the/url/path/to/the/update/handler'
|
12
|
-
# :luke_path => '/admin/luke'
|
13
|
-
#
|
14
10
|
def initialize(opts={}, &block)
|
15
11
|
opts[:url]||='http://127.0.0.1:8983/solr'
|
16
12
|
@opts = opts
|
@@ -36,7 +32,7 @@ class RSolr::Adapter::HTTP
|
|
36
32
|
|
37
33
|
protected
|
38
34
|
|
39
|
-
# The standard
|
35
|
+
# The standard POST headers
|
40
36
|
def post_headers
|
41
37
|
{"Content-Type" => 'text/xml; charset=utf-8'}
|
42
38
|
end
|
data/lib/rsolr/adapter.rb
CHANGED
File without changes
|
File without changes
|
data/lib/rsolr/http_client.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
# A simple wrapper for different http client implementations.
|
2
2
|
# Supports #get and #post
|
3
3
|
# This was motivated by: http://apocryph.org/2008/11/09/more_indepth_analysis_ruby_http_client_performance/
|
4
|
-
# Curb is the default adapter
|
5
4
|
|
6
|
-
# Each adapters response should be a hash with the following keys:
|
5
|
+
# Each adapters' response should be a hash with the following keys:
|
7
6
|
# :status_code
|
8
7
|
# :url
|
9
8
|
# :body
|
@@ -36,6 +35,13 @@ module RSolr::HTTPClient
|
|
36
35
|
@adapter_name = adapter_name
|
37
36
|
end
|
38
37
|
|
38
|
+
# Creates and returns an instance of RSolr::HTTPClient::Adapter::*
|
39
|
+
# The "url" is a full/valid url.
|
40
|
+
# Example:
|
41
|
+
# connector = RSolr::HTTPClient::Connector.new
|
42
|
+
# client = connector.connect('http://google.com')
|
43
|
+
#
|
44
|
+
# TODO: this should be less verbose... something like RSolr:HTTPClient.connect(url, adapter=:curb)
|
39
45
|
def connect(url)
|
40
46
|
case adapter_name
|
41
47
|
when :curb
|
@@ -54,14 +60,19 @@ module RSolr::HTTPClient
|
|
54
60
|
|
55
61
|
end
|
56
62
|
|
63
|
+
# The base class for interacting with one of the HTTP client adapters
|
57
64
|
class Base
|
58
65
|
|
59
66
|
attr_reader :adapter
|
60
67
|
|
68
|
+
# requires an instace of RSolr::HTTPClient::*
|
61
69
|
def initialize(adapter)
|
62
70
|
@adapter = adapter
|
63
71
|
end
|
64
72
|
|
73
|
+
# sends a GET reqest to the "path" variable
|
74
|
+
# an optional hash of "params" can be used,
|
75
|
+
# which is later transformed into a GET query string
|
65
76
|
def get(path, params={})
|
66
77
|
begin
|
67
78
|
http_context = @adapter.get(path, params)
|
@@ -71,6 +82,10 @@ module RSolr::HTTPClient
|
|
71
82
|
http_context
|
72
83
|
end
|
73
84
|
|
85
|
+
# sends a POST request to the "path" variable
|
86
|
+
# "data" is required, and must be a string
|
87
|
+
# "params" is an optional hash for query string params...
|
88
|
+
# "headers" is a hash for setting request header values.
|
74
89
|
def post(path, data, params={}, headers={})
|
75
90
|
begin
|
76
91
|
http_context = @adapter.post(path, data, params, headers)
|
@@ -90,14 +105,22 @@ module RSolr::HTTPClient
|
|
90
105
|
'%'+$1.unpack('H2'*$1.size).join('%').upcase
|
91
106
|
}.tr(' ', '+')
|
92
107
|
end
|
93
|
-
|
108
|
+
|
109
|
+
# creates and returns a url as a string
|
110
|
+
# "url" is the base url
|
111
|
+
# "params" is an optional hash of GET style query params
|
112
|
+
# "string_query" is an extra query string that will be appended to the
|
113
|
+
# result of "url" and "params".
|
94
114
|
def build_url(url='', params={}, string_query='')
|
95
115
|
queries = [string_query, hash_to_params(params)]
|
96
116
|
queries.delete_if{|i| i.to_s.empty?}
|
97
117
|
url += "?#{queries.join('&')}" unless queries.empty?
|
98
118
|
url
|
99
119
|
end
|
100
|
-
|
120
|
+
|
121
|
+
# converts a key value pair to an escaped string:
|
122
|
+
# Example:
|
123
|
+
# build_param(:id, 1) == "id=1"
|
101
124
|
def build_param(k,v)
|
102
125
|
"#{escape(k)}=#{escape(v)}"
|
103
126
|
end
|
data/lib/rsolr/message.rb
CHANGED
@@ -16,7 +16,7 @@ class RSolr::Message
|
|
16
16
|
# "doc_hash" must be a Hash/Mash object
|
17
17
|
# If a value in the "doc_hash" is an array,
|
18
18
|
# a field object is created for each value...
|
19
|
-
def initialize(doc_hash)
|
19
|
+
def initialize(doc_hash = {})
|
20
20
|
@fields = []
|
21
21
|
doc_hash.each_pair do |field,values|
|
22
22
|
# create a new field for each value (multi-valued)
|
@@ -35,11 +35,24 @@ class RSolr::Message
|
|
35
35
|
@fields.select{|f|f.name==name}
|
36
36
|
end
|
37
37
|
|
38
|
-
# returns the first field that matches the "name" arg
|
38
|
+
# returns the *first* field that matches the "name" arg
|
39
39
|
def field_by_name(name)
|
40
40
|
@fields.detect{|f|f.name==name}
|
41
41
|
end
|
42
42
|
|
43
|
+
#
|
44
|
+
# Add a field value to the document. Options map directly to
|
45
|
+
# XML attributes in the Solr <field> node.
|
46
|
+
# See http://wiki.apache.org/solr/UpdateXmlMessages#head-8315b8028923d028950ff750a57ee22cbf7977c6
|
47
|
+
#
|
48
|
+
# === Example:
|
49
|
+
#
|
50
|
+
# document.add_field('title', 'A Title', :boost => 2.0)
|
51
|
+
#
|
52
|
+
def add_field(name, value, options = {})
|
53
|
+
@fields << Field.new(options.merge({:name=>name}), value)
|
54
|
+
end
|
55
|
+
|
43
56
|
end
|
44
57
|
|
45
58
|
# A class that represents a "doc"/"field" xml element for a solr update
|
@@ -96,11 +109,11 @@ class RSolr::Message
|
|
96
109
|
# if the doc had a "nickname" field with the value of "Tim".
|
97
110
|
#
|
98
111
|
def add(data, add_attrs={}, &blk)
|
99
|
-
data = [data]
|
112
|
+
data = [data] unless data.is_a?(Array)
|
100
113
|
xml.add(add_attrs) do |add_node|
|
101
|
-
data.each do |
|
114
|
+
data.each do |doc|
|
102
115
|
# create doc, passing in fields
|
103
|
-
doc = Document.new(
|
116
|
+
doc = Document.new(doc) if doc.respond_to?(:each_pair)
|
104
117
|
yield doc if block_given?
|
105
118
|
add_node.doc(doc.attrs) do |doc_node|
|
106
119
|
doc.fields.each do |field_obj|
|
@@ -150,4 +163,4 @@ class RSolr::Message
|
|
150
163
|
|
151
164
|
end
|
152
165
|
|
153
|
-
end
|
166
|
+
end
|
data/lib/rsolr.rb
CHANGED
@@ -9,7 +9,7 @@ require 'mash'
|
|
9
9
|
|
10
10
|
module RSolr
|
11
11
|
|
12
|
-
VERSION = '0.8.
|
12
|
+
VERSION = '0.8.5'
|
13
13
|
|
14
14
|
autoload :Message, 'rsolr/message'
|
15
15
|
autoload :Connection, 'rsolr/connection'
|
@@ -30,6 +30,7 @@ module RSolr
|
|
30
30
|
RSolr::Connection.new(adapter, options)
|
31
31
|
end
|
32
32
|
|
33
|
+
# A module that contains string related methods
|
33
34
|
module Char
|
34
35
|
|
35
36
|
# escape - from the solr-ruby library
|
@@ -49,6 +50,7 @@ module RSolr
|
|
49
50
|
# bring escape into this module (RSolr) -> RSolr.escape('asdf')
|
50
51
|
extend Char
|
51
52
|
|
53
|
+
# RequestError is a common/generic exception class used by the adapters
|
52
54
|
class RequestError < RuntimeError; end
|
53
55
|
|
54
56
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/test/message_test.rb
CHANGED
@@ -104,4 +104,32 @@ class MessageTest < RSolrBaseTest
|
|
104
104
|
assert result.to_s =~ /<field name="name">matt2<\/field>/
|
105
105
|
end
|
106
106
|
|
107
|
-
|
107
|
+
def test_add_single_document
|
108
|
+
document = RSolr::Message::Document.new
|
109
|
+
document.add_field('id', 1)
|
110
|
+
document.add_field('name', 'matt', :boost => 2.0)
|
111
|
+
result = RSolr::Message.add(document)
|
112
|
+
|
113
|
+
assert result.to_s =~ /<field name="id">1<\/field>/
|
114
|
+
|
115
|
+
# depending on which ruby version, the attributes can be out of place
|
116
|
+
# so we need to test both... there's gotta be a better way to do this?
|
117
|
+
assert(
|
118
|
+
result.to_s =~ /<field name="name" boost="2.0">matt<\/field>/ ||
|
119
|
+
result.to_s =~ /<field boost="2.0" name="name">matt<\/field>/
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_add_multiple_documents
|
124
|
+
documents = (1..2).map do |i|
|
125
|
+
doc = RSolr::Message::Document.new
|
126
|
+
doc.add_field('id', i)
|
127
|
+
doc.add_field('name', "matt#{i}")
|
128
|
+
doc
|
129
|
+
end
|
130
|
+
result = RSolr::Message.add(documents)
|
131
|
+
|
132
|
+
assert result.to_s =~ /<field name="name">matt1<\/field>/
|
133
|
+
assert result.to_s =~ /<field name="name">matt2<\/field>/
|
134
|
+
end
|
135
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mwmitchell-rsolr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Mitchell
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-07 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -91,6 +91,3 @@ test_files:
|
|
91
91
|
- test/message_test.rb
|
92
92
|
- test/rsolr_test
|
93
93
|
- test/test_helpers.rb
|
94
|
-
- spec/connection_spec.rb
|
95
|
-
- spec/helper.rb
|
96
|
-
- spec/rsolr_spec.rb
|
data/spec/connection_spec.rb
DELETED
@@ -1,151 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe RSolr::Connection do
|
4
|
-
|
5
|
-
context 'the initialize method' do
|
6
|
-
|
7
|
-
it 'should require one argument' do
|
8
|
-
lambda{RSolr::Connection.new}.should raise_error(ArgumentError)
|
9
|
-
end
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
before(:each) do
|
14
|
-
@adapter = mock('RSolr::Adapter::HTTP')
|
15
|
-
@connection = RSolr::Connection.new(@adapter)
|
16
|
-
end
|
17
|
-
|
18
|
-
context '#map_params method' do
|
19
|
-
it 'should merge :wt=>:ruby to the incoming params' do
|
20
|
-
result = @connection.send(:map_params, {})
|
21
|
-
result[:wt].should == :ruby
|
22
|
-
end
|
23
|
-
it 'should not overwrite an existing :wt param' do
|
24
|
-
result = @connection.send(:map_params, {:wt=>'xml'})
|
25
|
-
result[:wt].should == 'xml'
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
context '#adapt_response method' do
|
30
|
-
it 'should evaluate the :body value if the :wt param IS :ruby' do
|
31
|
-
response_from_adapter = {:body=>'{}', :params=>{:wt=>:ruby}}
|
32
|
-
result = @connection.send(:adapt_response, response_from_adapter)
|
33
|
-
result.should be_a(Hash)
|
34
|
-
end
|
35
|
-
it 'should not evaluate the :body value if the :wt is NOT :ruby' do
|
36
|
-
response_from_adapter = {:body=>'</xml>', :params=>{:wt=>:xml}}
|
37
|
-
result = @connection.send(:adapt_response, response_from_adapter)
|
38
|
-
result.should be_a(String)
|
39
|
-
end
|
40
|
-
it 'should return an object that will respond_to?(:adapter_response)' do
|
41
|
-
response_from_adapter = {:body=>'</xml>', :params=>{:wt=>:xml}}
|
42
|
-
result = @connection.send(:adapt_response, response_from_adapter)
|
43
|
-
result.should respond_to(:adapter_response)
|
44
|
-
end
|
45
|
-
it 'should return the original adapter response from #adapter_response method' do
|
46
|
-
response_from_adapter = {:body=>'</xml>', :params=>{:wt=>:xml}}
|
47
|
-
result = @connection.send(:adapt_response, response_from_adapter)
|
48
|
-
result.adapter_response.should == response_from_adapter
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'should have an adapter' do
|
53
|
-
@connection.adapter.should == @adapter
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'should send requests to the adapter' do
|
57
|
-
params = {:wt=>:ruby, :q=>'test'}
|
58
|
-
expected_return = {:params=>params, :body=>'{}'}
|
59
|
-
@adapter.should_receive(:send_request).with(
|
60
|
-
'/documents',
|
61
|
-
params,
|
62
|
-
nil
|
63
|
-
).once.and_return(expected_return)
|
64
|
-
@connection.send_request('/documents', :q=>'test')
|
65
|
-
end
|
66
|
-
|
67
|
-
context '#select method' do
|
68
|
-
|
69
|
-
it 'should set the solr request path to /select' do
|
70
|
-
params = {:wt=>:ruby, :q=>'test'}
|
71
|
-
expected_return = {:params=>params, :body=>'{}'}
|
72
|
-
@adapter.should_receive(:send_request).with(
|
73
|
-
'/select',
|
74
|
-
params,
|
75
|
-
nil
|
76
|
-
).once.and_return(expected_return)
|
77
|
-
@connection.select(:q=>'test')
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'should add a :qt=>:ruby to the params, then pass the params to the adapter' do
|
81
|
-
input_params = {:q=>'test', :fq=>'filter:one', :fq=>'documents'}
|
82
|
-
expected_modified_params = input_params.merge({:wt=>:ruby})
|
83
|
-
expected_return = {:body=>'{}', :params=>expected_modified_params}
|
84
|
-
@adapter.should_receive(:send_request).with(
|
85
|
-
'/select',
|
86
|
-
hash_including(expected_modified_params),
|
87
|
-
nil
|
88
|
-
).once.and_return(expected_return)
|
89
|
-
@connection.select(input_params)
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'should return a hash' do
|
93
|
-
@adapter.should_receive(:send_request).and_return(
|
94
|
-
{:body=>'{}', :params=>{:wt=>:ruby}}
|
95
|
-
)
|
96
|
-
@connection.select(:q=>'test').should be_a(Hash)
|
97
|
-
end
|
98
|
-
|
99
|
-
end
|
100
|
-
|
101
|
-
context '#update method' do
|
102
|
-
|
103
|
-
it 'should set the solr request path to /update' do
|
104
|
-
expected_params = {:name=>'test', :wt=>:ruby}
|
105
|
-
@adapter.should_receive(:send_request).with(
|
106
|
-
'/update',
|
107
|
-
hash_including(expected_params),
|
108
|
-
'</optimize>'
|
109
|
-
).once.and_return(
|
110
|
-
{:body=>'{}', :params=>expected_params}
|
111
|
-
)
|
112
|
-
@connection.update('</optimize>', :name=>'test')
|
113
|
-
end
|
114
|
-
|
115
|
-
it 'should accept a solr params hash' do
|
116
|
-
@adapter.should_receive(:send_request).with(
|
117
|
-
'/update',
|
118
|
-
hash_including(:xyz=>123, :wt=>:ruby),
|
119
|
-
'</optimize>'
|
120
|
-
).once.and_return(
|
121
|
-
{:body=>'{}', :params=>{:xyz=>123, :wt=>:ruby}}
|
122
|
-
)
|
123
|
-
@connection.update('</optimize>', :xyz=>123)
|
124
|
-
end
|
125
|
-
|
126
|
-
end
|
127
|
-
|
128
|
-
context '#send_request method' do
|
129
|
-
|
130
|
-
it 'should send the request path to the adapter' do
|
131
|
-
@adapter.should_receive(:send_request).with(
|
132
|
-
'/documents',
|
133
|
-
hash_including(:q=>'test', :wt=>:ruby),
|
134
|
-
nil
|
135
|
-
).once.and_return({:body=>'{}', :params=>{:wt=>:ruby, :q=>'test'}})
|
136
|
-
@connection.send_request('/documents', :q=>'test')
|
137
|
-
end
|
138
|
-
|
139
|
-
it 'should return an object will respond_to :adapter_response' do
|
140
|
-
@adapter.should_receive(:send_request).with(
|
141
|
-
'/select',
|
142
|
-
hash_including(:q=>'test', :wt=>:ruby),
|
143
|
-
nil
|
144
|
-
).once.and_return({:body=>'{}', :params=>{:q=>'test', :wt=>:ruby}})
|
145
|
-
response = @connection.select(:q=>'test')
|
146
|
-
response.should respond_to(:adapter_response)
|
147
|
-
end
|
148
|
-
|
149
|
-
end
|
150
|
-
|
151
|
-
end
|
data/spec/helper.rb
DELETED
data/spec/rsolr_spec.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe RSolr::Connection do
|
4
|
-
|
5
|
-
context 'the #connect method' do
|
6
|
-
|
7
|
-
it 'should exist' do
|
8
|
-
RSolr.should respond_to(:connect)
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'should return an RSolr::Connection object' do
|
12
|
-
RSolr.connect.should be_a(RSolr::Connection)
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
context "the #escape method" do
|
18
|
-
|
19
|
-
it "should exist" do
|
20
|
-
RSolr.should respond_to(:escape)
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should escape properly" do
|
24
|
-
RSolr.escape('Trying & % different "characters" here!').should == "Trying\\ \\&\\ \\%\\ different\\ \\\"characters\\\"\\ here\\!"
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|