james-rc-rest 2.2.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.
@@ -0,0 +1,30 @@
1
+ = 2.2.1
2
+
3
+ * Turn IOError into RCRest::CommunicationError for #post and #post_multipart.
4
+
5
+ = 2.2.0
6
+
7
+ * Moved to seattlerb rubyforge project
8
+ * Moved to p4
9
+ * Wrap communication errors in RCRest::CommunicationError
10
+
11
+ = 2.1.1
12
+
13
+ * Fix dependency on ZenTest for testing
14
+
15
+ = 2.1.0
16
+
17
+ * Don't split strings into extra params pairs on newlines
18
+ * Added RCRest#post_multipart and RCRest#make_multipart
19
+ * Fixed various query parameter incompatiblities
20
+
21
+ = 2.0.0
22
+
23
+ * Added +method+ parameter to RCRest#make_url to add path components
24
+ to a generic endpoint
25
+ * Added RCRest#post
26
+
27
+ = 1.0.0
28
+
29
+ * Birthday!
30
+
@@ -0,0 +1,27 @@
1
+ Copyright 2006 Eric Hodel, The Robot Co-op. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ 3. Neither the names of the authors nor the names of their contributors
13
+ may be used to endorse or promote products derived from this software
14
+ without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
17
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
20
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
@@ -0,0 +1,9 @@
1
+ History.txt
2
+ LICENSE.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ lib/rc_rest.rb
7
+ lib/rc_rest/net_http_stub.rb
8
+ lib/rc_rest/uri_stub.rb
9
+ test/test_rc_rest.rb
@@ -0,0 +1,32 @@
1
+ = rc-rest
2
+
3
+ Rubyforge Project:
4
+
5
+ http://rubyforge.org/projects/rctools/
6
+
7
+ Documentation:
8
+
9
+ http://dev.robotcoop.com/Libraries/rc-rest/
10
+
11
+ == About
12
+
13
+ This is an abstract class for creating wrappers for REST web service APIs.
14
+
15
+ == Installing rc-rest
16
+
17
+ Just install the gem:
18
+
19
+ $ sudo gem install rc-rest
20
+
21
+ == Using rc-rest
22
+
23
+ rc-rest is used by gems such as yahoo-search, google-geocode and geocoder-us.
24
+ If you'd like to write bindings a web service using rc-rest see RCRest, its
25
+ tests or the above-mentioned gems for examples.
26
+
27
+ == Upgrading from 1.x
28
+
29
+ RCRest#get and RCRest#make_url now accept a method argument as the
30
+ first parameter. To use 2.x, pass the last component of the path to
31
+ RCRest#get or RCRest#make_url.
32
+
@@ -0,0 +1,18 @@
1
+ require 'hoe'
2
+ require './lib/rc_rest'
3
+
4
+ Hoe.new 'rc-rest', RCRest::VERSION do |p|
5
+ p.summary = 'Robot Co-op REST web services base class'
6
+ p.description = 'This library makes it easy to implement REST-like web services APIs.'
7
+ p.author = 'Eric Hodel'
8
+ p.email = 'drbrain@segment7.net'
9
+ p.url = "http://seattlerb.rubyforge.org/rc-rest"
10
+ p.rubyforge_name = 'seattlerb'
11
+
12
+ p.changes = File.read('History.txt').scan(/\A(=.*?)^=/m).first.first
13
+
14
+ p.extra_deps << ['ZenTest', '>= 3.4.2']
15
+ end
16
+
17
+ # vim: syntax=Ruby
18
+
@@ -0,0 +1,279 @@
1
+ require 'net/http'
2
+ require 'open-uri'
3
+ require 'rexml/document'
4
+
5
+ ##
6
+ # Abstract class for implementing REST APIs.
7
+ #
8
+ # === Example
9
+ #
10
+ # The following methods must be implemented in sublcasses:
11
+ #
12
+ # +initialize+:: Sets @url to the service enpoint.
13
+ # +check_error+:: Checks for errors in the server response.
14
+ # +parse_response+:: Extracts information from the server response.
15
+ #
16
+ # If you have extra URL paramaters (application id, output type) or need to
17
+ # perform URL customization, override +make_url+ and +make_multipart+.
18
+ #
19
+ # class FakeService < RCRest
20
+ #
21
+ # class Error < RCRest::Error; end
22
+ #
23
+ # def initialize(appid)
24
+ # @appid = appid
25
+ # @url = URI.parse 'http://example.com/api/'
26
+ # end
27
+ #
28
+ # def check_error(xml)
29
+ # raise Error, xml.elements['error'].text if xml.elements['error']
30
+ # end
31
+ #
32
+ # def make_url(method, params)
33
+ # params[:appid] = @appid
34
+ # super method, params
35
+ # end
36
+ #
37
+ # def parse_response(xml)
38
+ # return xml
39
+ # end
40
+ #
41
+ # def test(query)
42
+ # get :test, :q => query
43
+ # end
44
+ #
45
+ # end
46
+
47
+ class RCRest
48
+
49
+ ##
50
+ # You are using this version of RCRest
51
+
52
+ VERSION = '2.2.1'
53
+
54
+ ##
55
+ # Abstract Error class.
56
+
57
+ class Error < RuntimeError; end
58
+
59
+ ##
60
+ # Error raised when communicating with the server
61
+
62
+ class CommunicationError < Error
63
+
64
+ ##
65
+ # The original exception
66
+
67
+ attr_accessor :original_exception
68
+
69
+ ##
70
+ # Creates a new CommunicationError with +message+ and +original_exception+
71
+
72
+ def initialize(original_exception)
73
+ @original_exception = original_exception
74
+ message = "Communication error: #{original_exception.message}(#{original_exception.class})"
75
+ super message
76
+ end
77
+
78
+ end
79
+
80
+ ##
81
+ # Web services initializer.
82
+ #
83
+ # Concrete web services implementations must set the +url+ instance
84
+ # variable which must be a URI.
85
+
86
+ def initialize
87
+ raise NotImplementedError, 'need to implement #intialize and set @url'
88
+ end
89
+
90
+ ##
91
+ # Must extract and raise an error from +xml+, an REXML::Document, if any.
92
+ # Must return if no error could be found.
93
+
94
+ def check_error(xml)
95
+ raise NotImplementedError
96
+ end
97
+
98
+ def expand_params(params) # :nodoc:
99
+ expanded_params = []
100
+
101
+ params.each do |k,v|
102
+ if v.respond_to? :each and not String === v then
103
+ v.each { |v| expanded_params << [k, v] }
104
+ else
105
+ expanded_params << [k, v]
106
+ end
107
+ end
108
+
109
+ expanded_params.sort_by { |k,v| [k.to_s, v.to_s] }
110
+ end
111
+
112
+ ##
113
+ # Performs a GET request for method +method+ with +params+. Calls
114
+ # #parse_response on the concrete class with an REXML::Document instance and
115
+ # returns its result.
116
+
117
+ def get(method, params = {})
118
+ url = make_url method, params
119
+
120
+ url.open do |xml|
121
+ res = REXML::Document.new xml.read
122
+
123
+ check_error res
124
+
125
+ return parse_response(res)
126
+ end
127
+ rescue IOError, SystemCallError, SocketError, Timeout::Error,
128
+ REXML::ParseException => e
129
+ raise CommunicationError.new(e)
130
+ rescue OpenURI::HTTPError => e
131
+ begin
132
+ xml = REXML::Document.new e.io.read
133
+ check_error xml
134
+ rescue REXML::ParseException => e
135
+ end
136
+ new_e = CommunicationError.new e
137
+ new_e.message << "\n\nunhandled error:\n#{xml.to_s}"
138
+ raise new_e
139
+ end
140
+
141
+ ##
142
+ # Creates a URI for method +method+ and a Hash of parameters +params+.
143
+ # Override this then call super if you need to add extra params like an
144
+ # application id, output type, etc.
145
+ #
146
+ # If the value of a parameter responds to #each, make_url creates a
147
+ # key-value pair per value in the param.
148
+ #
149
+ # Examples:
150
+ #
151
+ # If the URL base is:
152
+ #
153
+ # http://example.com/api/
154
+ #
155
+ # then:
156
+ #
157
+ # make_url nil, :a => '1 2', :b => [4, 3]
158
+ #
159
+ # creates the URL:
160
+ #
161
+ # http://example.com/api/?a=1%202&b=3&b=4
162
+ #
163
+ # and
164
+ #
165
+ # make_url :method, :a => '1'
166
+ #
167
+ # creates the URL:
168
+ #
169
+ # http://example.com/api/method?a=1
170
+
171
+ def make_url(method, params = nil)
172
+ escaped_params = expand_params(params).map do |k,v|
173
+ k = URI.escape(k.to_s).gsub(';', '%3B').gsub('+', '%2B').gsub('&', '%26')
174
+ v = URI.escape(v.to_s).gsub(';', '%3B').gsub('+', '%2B').gsub('&', '%26')
175
+ "#{k}=#{v}"
176
+ end
177
+
178
+ query = escaped_params.join '&'
179
+
180
+ url = @url + "./#{method}"
181
+ url.query = query
182
+ return url
183
+ end
184
+
185
+ ##
186
+ # Creates a multipart form post for the Hash of parameters +params+.
187
+ # Override this then call super if you need to add extra params like an
188
+ # application id, output type, etc.
189
+ #
190
+ # #make_multipart handles arguments similarly to #make_url.
191
+
192
+ def make_multipart(params)
193
+ boundary = (0...8).map { rand(255).to_s 16 }.join '_'
194
+ data = expand_params(params).map do |key, value|
195
+ [ "--#{boundary}",
196
+ "Content-Disposition: form-data; name=\"#{key}\"",
197
+ nil,
198
+ value]
199
+ end
200
+
201
+ data << "--#{boundary}--"
202
+ return [boundary, data.join("\r\n")]
203
+ end
204
+
205
+ ##
206
+ # Must parse results from +xml+, an REXML::Document, into something sensible
207
+ # for the API.
208
+
209
+ def parse_response(xml)
210
+ raise NotImplementedError
211
+ end
212
+
213
+ ##
214
+ # Performs a POST request for method +method+ with +params+. Calls
215
+ # #parse_response on the concrete class with an REXML::Document instance and
216
+ # returns its result.
217
+
218
+ def post(method, params = {})
219
+ url = make_url method, params
220
+ query = url.query
221
+ url.query = nil
222
+
223
+ req = Net::HTTP::Post.new url.path
224
+ req.body = query
225
+ req.content_type = 'application/x-www-form-urlencoded'
226
+
227
+ res = Net::HTTP.start url.host, url.port do |http|
228
+ http.request req
229
+ end
230
+
231
+ xml = REXML::Document.new res.body
232
+
233
+ check_error xml
234
+
235
+ parse_response xml
236
+ rescue SystemCallError, SocketError, Timeout::Error, IOError,
237
+ REXML::ParseException => e
238
+ raise CommunicationError.new(e)
239
+ rescue Net::HTTPError => e
240
+ xml = REXML::Document.new e.res.body
241
+ check_error xml
242
+ raise CommunicationError.new(e)
243
+ end
244
+
245
+ ##
246
+ # Performs a POST request for method +method+ with +params+, submitting a
247
+ # multipart form. Calls #parse_response on the concrete class with an
248
+ # REXML::Document instance and returns its result.
249
+
250
+ def post_multipart(method, params = {})
251
+ url = make_url method, {}
252
+ url.query = nil
253
+
254
+ boundary, data = make_multipart params
255
+
256
+ req = Net::HTTP::Post.new url.path
257
+ req.content_type = "multipart/form-data; boundary=#{boundary}"
258
+ req.body = data
259
+
260
+ res = Net::HTTP.start url.host, url.port do |http|
261
+ http.request req
262
+ end
263
+
264
+ xml = REXML::Document.new res.body
265
+
266
+ check_error xml
267
+
268
+ parse_response xml
269
+ rescue SystemCallError, SocketError, Timeout::Error, IOError,
270
+ REXML::ParseException => e
271
+ raise CommunicationError.new(e)
272
+ rescue Net::HTTPError => e
273
+ xml = REXML::Document.new e.res.body
274
+ check_error xml
275
+ raise CommunicationError.new(e)
276
+ end
277
+
278
+ end
279
+
@@ -0,0 +1,65 @@
1
+ require 'net/http'
2
+
3
+ class Net::HTTPResponse
4
+
5
+ ##
6
+ # Setter for body content
7
+
8
+ attr_accessor :body
9
+
10
+ end
11
+
12
+ class Net::HTTP
13
+
14
+ @params = nil
15
+ @paths = nil
16
+ @responses = nil
17
+
18
+ class << self
19
+
20
+ ##
21
+ # Records submitted POST params
22
+
23
+ attr_accessor :params
24
+
25
+ ##
26
+ # Records POST paths
27
+
28
+ attr_accessor :paths
29
+
30
+ ##
31
+ # Holds POST body responses
32
+
33
+ attr_accessor :responses
34
+
35
+ remove_method :start
36
+
37
+ end
38
+
39
+ ##
40
+ # Override Net::HTTP::start to not connect
41
+
42
+ def self.start(host, port)
43
+ yield Net::HTTP.new(host)
44
+ end
45
+
46
+ remove_method :request
47
+
48
+ ##
49
+ # Override Net::HTTP#request to fake its results
50
+
51
+ def request(req)
52
+ self.class.paths << req.path
53
+ self.class.params << req.body
54
+ response = self.class.responses.shift
55
+ if response.respond_to? :call then
56
+ response.call req
57
+ else
58
+ res = Net::HTTPResponse.new '1.0', 200, 'OK'
59
+ res.body = response
60
+ res
61
+ end
62
+ end
63
+
64
+ end
65
+
@@ -0,0 +1,56 @@
1
+ require 'open-uri'
2
+
3
+ module URI # :nodoc:
4
+ end
5
+
6
+ ##
7
+ # This stub overrides OpenURI's open method to allow programs that use OpenURI
8
+ # to be easily tested.
9
+ #
10
+ # == Usage
11
+ #
12
+ # require 'rc_rest/uri_stub'
13
+ #
14
+ # class TestMyClass < Test::Unit::TestCase
15
+ #
16
+ # def setup
17
+ # URI::HTTP.responses = []
18
+ # URI::HTTP.uris = []
19
+ #
20
+ # @obj = MyClass.new
21
+ # end
22
+ #
23
+ # def test_my_method
24
+ # URI::HTTP.responses << 'some text open would ordinarily return'
25
+ #
26
+ # result = @obj.my_method
27
+ #
28
+ # assert_equal :something_meaninfgul, result
29
+ #
30
+ # assert_equal true, URI::HTTP.responses.empty?
31
+ # assert_equal 1, URI::HTTP.uris.length
32
+ # assert_equal 'http://example.com/path', URI::HTTP.uris.first
33
+ # end
34
+ #
35
+ # end
36
+
37
+ class URI::HTTP # :nodoc:
38
+
39
+ class << self
40
+ attr_accessor :responses, :uris
41
+ end
42
+
43
+ alias original_open open
44
+
45
+ def open
46
+ self.class.uris << self.to_s
47
+ response = self.class.responses.shift
48
+ if response.respond_to? :call then
49
+ response.call
50
+ else
51
+ yield StringIO.new(response)
52
+ end
53
+ end
54
+
55
+ end
56
+
@@ -0,0 +1,268 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'test/zentest_assertions'
4
+ require 'rc_rest/uri_stub'
5
+ require 'rc_rest/net_http_stub'
6
+ require 'rc_rest'
7
+
8
+ class FakeService < RCRest
9
+
10
+ class Error < RCRest::Error; end
11
+
12
+ def initialize
13
+ @url = URI.parse 'http://example.com/test'
14
+ end
15
+
16
+ def check_error(xml)
17
+ raise Error, xml.elements['error'].text if xml.elements['error']
18
+ end
19
+
20
+ def do_get
21
+ get :method
22
+ end
23
+
24
+ def do_post
25
+ post :method, :param => 'value'
26
+ end
27
+
28
+ def do_post_multipart
29
+ post_multipart :method, :param => 'value'
30
+ end
31
+
32
+ def parse_response(xml)
33
+ return xml
34
+ end
35
+
36
+ end
37
+
38
+ class TestFakeService < Test::Unit::TestCase
39
+
40
+ def setup
41
+ URI::HTTP.responses = []
42
+ URI::HTTP.uris = []
43
+
44
+ Net::HTTP.params = []
45
+ Net::HTTP.paths = []
46
+ Net::HTTP.responses = []
47
+
48
+ @fs = FakeService.new
49
+
50
+ srand 0
51
+ end
52
+
53
+ def test_check_error
54
+ xml = REXML::Document.new '<error>you broked it</error>'
55
+ @fs.check_error xml
56
+
57
+ rescue FakeService::Error => e
58
+ assert_equal 'you broked it', e.message
59
+
60
+ else
61
+ flunk 'expected an error'
62
+ end
63
+
64
+ def test_do_get
65
+ xml = '<result>stuff</result>'
66
+ URI::HTTP.responses << xml
67
+
68
+ result = @fs.do_get
69
+
70
+ assert_equal xml, result.to_s
71
+ assert_equal 'http://example.com/method?', URI::HTTP.uris.first
72
+ end
73
+
74
+ def test_do_get_bad_xml
75
+ xml = '<result>stuff</result><extra/>'
76
+ URI::HTTP.responses << xml
77
+
78
+ assert_raise RCRest::CommunicationError do @fs.do_get end
79
+ end
80
+
81
+ def test_do_get_error_400
82
+ URI::HTTP.responses << proc do
83
+ xml = '<error>you did the bad thing</error>'
84
+ raise OpenURI::HTTPError.new('400 Bad Request', StringIO.new(xml))
85
+ end
86
+
87
+ assert_raise FakeService::Error do @fs.do_get end
88
+ end
89
+
90
+ def test_do_get_error_400_bad_xml
91
+ URI::HTTP.responses << proc do
92
+ xml = '<error>you did the bad thing</error><extra/>'
93
+ raise OpenURI::HTTPError.new('400 Bad Request', StringIO.new(xml))
94
+ end
95
+
96
+ assert_raise RCRest::CommunicationError do @fs.do_get end
97
+ end
98
+
99
+ def test_do_get_error_unhandled
100
+ URI::HTTP.responses << proc do
101
+ xml = '<other_error>you did the bad thing</other_error>'
102
+ raise OpenURI::HTTPError.new('500 Internal Server Error', StringIO.new(xml))
103
+ end
104
+
105
+ e = assert_raise RCRest::CommunicationError do @fs.do_get end
106
+
107
+ expected = <<-EOF.strip
108
+ Communication error: 500 Internal Server Error(OpenURI::HTTPError)
109
+
110
+ unhandled error:
111
+ <other_error>you did the bad thing</other_error>
112
+ EOF
113
+
114
+ assert_equal expected, e.message
115
+ end
116
+
117
+ def test_do_get_eof_error
118
+ URI::HTTP.responses << proc do
119
+ xml = '<error>you did the bad thing</error>'
120
+ raise EOFError, 'end of file reached'
121
+ end
122
+
123
+ assert_raise RCRest::CommunicationError do @fs.do_get end
124
+ end
125
+
126
+ def test_do_post
127
+ xml = '<result>stuff</result>'
128
+ Net::HTTP.responses << xml
129
+
130
+ result = @fs.do_post
131
+
132
+ assert_equal xml, result.to_s
133
+
134
+ assert_equal 1, Net::HTTP.params.length
135
+ assert_equal 1, Net::HTTP.paths.length
136
+ assert_empty Net::HTTP.responses
137
+
138
+ assert_equal 'param=value', Net::HTTP.params.first
139
+ assert_equal '/method', Net::HTTP.paths.first
140
+ end
141
+
142
+ def test_do_post_bad_xml
143
+ xml = '<result>stuff</result><extra/>'
144
+ Net::HTTP.responses << xml
145
+
146
+ assert_raise RCRest::CommunicationError do @fs.do_post end
147
+ end
148
+
149
+ def test_do_post_eof_error
150
+ Net::HTTP.responses << proc do
151
+ raise IOError, 'end of file reached'
152
+ end
153
+
154
+ assert_raise RCRest::CommunicationError do @fs.do_post end
155
+ end
156
+
157
+ def test_do_post_multipart
158
+ xml = '<result>stuff</result>'
159
+ Net::HTTP.responses << xml
160
+
161
+ result = @fs.do_post_multipart
162
+
163
+ assert_equal xml, result.to_s
164
+
165
+ assert_equal 1, Net::HTTP.params.length
166
+ assert_equal 1, Net::HTTP.paths.length
167
+ assert_empty Net::HTTP.responses
168
+
169
+ expected = <<-EOF.strip
170
+ --ac_2f_75_c0_43_fb_c3_67\r
171
+ Content-Disposition: form-data; name="param"\r
172
+ \r
173
+ value\r
174
+ --ac_2f_75_c0_43_fb_c3_67--
175
+ EOF
176
+
177
+ assert_equal expected, Net::HTTP.params.first
178
+ assert_equal '/method', Net::HTTP.paths.first
179
+ end
180
+
181
+ def test_do_post_multipart_eof_error
182
+ Net::HTTP.responses << proc do
183
+ raise EOFError, 'end of file reached'
184
+ end
185
+
186
+ assert_raise RCRest::CommunicationError do @fs.do_post_multipart end
187
+ end
188
+
189
+ def test_do_post_multipart_bad_xml
190
+ xml = '<result>stuff</result><extra/>'
191
+ Net::HTTP.responses << xml
192
+
193
+ assert_raise RCRest::CommunicationError do @fs.do_post_multipart end
194
+ end
195
+
196
+ end
197
+
198
+ class TestRCRest < Test::Unit::TestCase
199
+
200
+ def test_initialize
201
+ e = assert_raise NotImplementedError do
202
+ RCRest.new
203
+ end
204
+
205
+ assert_equal 'need to implement #intialize and set @url', e.message
206
+ end
207
+
208
+ def test_check_error
209
+ r = RCRest.allocate
210
+ assert_raise NotImplementedError do r.check_error nil end
211
+ end
212
+
213
+ def test_make_multipart
214
+ srand 0
215
+
216
+ r = RCRest.allocate
217
+ boundary, data = r.make_multipart :a => 'b c', :x => 'y z',
218
+ :array => ['v2', 'v1'],
219
+ :newlines => "a\nb"
220
+
221
+ assert_equal 'ac_2f_75_c0_43_fb_c3_67', boundary
222
+
223
+ expected = <<-EOF.strip
224
+ --ac_2f_75_c0_43_fb_c3_67\r
225
+ Content-Disposition: form-data; name="a"\r
226
+ \r
227
+ b c\r
228
+ --ac_2f_75_c0_43_fb_c3_67\r
229
+ Content-Disposition: form-data; name="array"\r
230
+ \r
231
+ v1\r
232
+ --ac_2f_75_c0_43_fb_c3_67\r
233
+ Content-Disposition: form-data; name="array"\r
234
+ \r
235
+ v2\r
236
+ --ac_2f_75_c0_43_fb_c3_67\r
237
+ Content-Disposition: form-data; name="newlines"\r
238
+ \r
239
+ a
240
+ b\r
241
+ --ac_2f_75_c0_43_fb_c3_67\r
242
+ Content-Disposition: form-data; name="x"\r
243
+ \r
244
+ y z\r
245
+ --ac_2f_75_c0_43_fb_c3_67--
246
+ EOF
247
+
248
+ assert_equal expected, data
249
+ end
250
+
251
+ def test_make_url
252
+ r = RCRest.allocate
253
+ r.instance_variable_set :@url, URI.parse('http://example.com/')
254
+
255
+ url = r.make_url :method, :a => 'b c', :x => 'y z', :array => ['v2', 'v1'],
256
+ :newlines => "a\nb", :funky => 'a;b+c&d'
257
+
258
+ assert_equal 'http://example.com/method?a=b%20c&array=v1&array=v2&funky=a%3Bb%2Bc%26d&newlines=a%0Ab&x=y%20z',
259
+ url.to_s
260
+ end
261
+
262
+ def test_parse_response
263
+ r = RCRest.allocate
264
+ assert_raise NotImplementedError do r.parse_response nil end
265
+ end
266
+
267
+ end
268
+
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: james-rc-rest
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Eric Hodel
8
+ - James Darling
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain:
12
+ date: 2007-01-31 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ZenTest
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 3.4.2
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: hoe
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 1.1.7
32
+ version:
33
+ description: JAMES' VERSION OF This library makes it easy to implement REST-like web services APIs.
34
+ email: drbrain@segment7.net
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files: []
40
+
41
+ files:
42
+ - History.txt
43
+ - LICENSE.txt
44
+ - Manifest.txt
45
+ - README.txt
46
+ - Rakefile
47
+ - lib/rc_rest.rb
48
+ - lib/rc_rest/net_http_stub.rb
49
+ - lib/rc_rest/uri_stub.rb
50
+ - test/test_rc_rest.rb
51
+ has_rdoc: true
52
+ homepage: http://seattlerb.rubyforge.org/rc-rest
53
+ post_install_message:
54
+ rdoc_options: []
55
+
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">"
61
+ - !ruby/object:Gem::Version
62
+ version: 0.0.0
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.2.0
74
+ signing_key:
75
+ specification_version: 1
76
+ summary: James' mashup of rc-rest
77
+ test_files:
78
+ - test/test_rc_rest.rb