mwmitchell-rsolr 0.8.4 → 0.8.5

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 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) do |solr_response,adapter_response|
16
- puts "URL : #{adapter_response[:url]}"
17
- solr_response[:response][:docs].each do |doc|
18
- puts doc[:timestamp]
19
- end
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
@@ -57,13 +57,11 @@ class RSolr::Adapter::Direct
57
57
  raise RSolr::RequestError.new($!.message)
58
58
  end
59
59
  {
60
- :status_code=>nil,
61
60
  :body=>body,
62
61
  :url=>url,
63
62
  :path=>path,
64
63
  :params=>params,
65
64
  :data=>data,
66
- :headers=>nil
67
65
  }
68
66
  end
69
67
 
@@ -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 post headers
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
@@ -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] if data.respond_to?(:each_pair)
112
+ data = [data] unless data.is_a?(Array)
100
113
  xml.add(add_attrs) do |add_node|
101
- data.each do |item|
114
+ data.each do |doc|
102
115
  # create doc, passing in fields
103
- doc = Document.new(item)
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.4'
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
- end
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
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-03 00:00:00 -07:00
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
@@ -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
@@ -1,4 +0,0 @@
1
- require 'rubygems'
2
- require 'spec'
3
-
4
- require File.join(File.dirname(__FILE__), '..', 'lib', 'rsolr')
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