http-client 0.1.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG +3 -0
- data/README.md +65 -0
- data/lib/http-client.rb +3 -0
- data/lib/http/client.rb +333 -0
- data/test/helper.rb +9 -0
- data/test/test_request.rb +34 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 53ce70d44f5b7cf0dbc85317ce3d6f6606b9c8e1
|
4
|
+
data.tar.gz: 4eaa5aee72f9e60d288b6c9b52ba883ef88798a4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fae9eb821a1e374769f9dd8c2134f00817f62de88d77fcfaf3f02db284c45fc0e3c2faaef9bb88bec627c9dd055e3ac20a69af2f522133e955f1c667f081cb71
|
7
|
+
data.tar.gz: 8fb4cbc0035594e46e4f2d66b76e59cd639dc95d41906c6757c77e2162ab5576a2db4f5f507cdd3e2908adcd331bebe1280ea76d9c12eaf2bd0720c000883520
|
data/CHANGELOG
ADDED
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# HTTP Client
|
2
|
+
|
3
|
+
A simple Net::HTTP wrapper with multi-part and cookie-jar support.
|
4
|
+
|
5
|
+
## Install
|
6
|
+
|
7
|
+
```
|
8
|
+
gem install http-client
|
9
|
+
```
|
10
|
+
|
11
|
+
## Example
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
require 'http-client'
|
15
|
+
res = HTTP::Client::Request.new(:get, "http://www.example.org", max_redirects: 2).execute
|
16
|
+
|
17
|
+
# save a few keystrokes.
|
18
|
+
res = HTTP::Client.get("http://www.example.org/", max_redirects: 2)
|
19
|
+
res = HTTP::Client.post("http://www.example.org/", files: {pic: "kittens.jpg"}, query: {title: "the usual suspects"})
|
20
|
+
```
|
21
|
+
|
22
|
+
## API
|
23
|
+
|
24
|
+
```
|
25
|
+
HTTP::Client::Request
|
26
|
+
.new(verb, uri, arguments = {})
|
27
|
+
#execute
|
28
|
+
|
29
|
+
HTTP::Client::Response
|
30
|
+
.new net_http_response, last_effective_uri
|
31
|
+
#code
|
32
|
+
#body
|
33
|
+
#headers
|
34
|
+
#last_effective_uri
|
35
|
+
```
|
36
|
+
|
37
|
+
### Request parameters
|
38
|
+
|
39
|
+
Required:
|
40
|
+
|
41
|
+
| Name | Type | Description |
|
42
|
+
|------|------|-------------|
|
43
|
+
| verb | Symbol | HTTP verb, one of :get, :head, :put, :post, :delete, :options, :trace. |
|
44
|
+
| uri | String | Remote URI |
|
45
|
+
|
46
|
+
Optional arguments hash:
|
47
|
+
|
48
|
+
| Name | Type | Description |
|
49
|
+
|------|------|-------------|
|
50
|
+
| headers | Hash | Net::HTTP headers, in key-value pairs. |
|
51
|
+
| query | Hash | Net::HTTP query-string in key-value pairs. |
|
52
|
+
| files | Hash | Multi-part file uploads, in key-value pairs of {name => path_to_file} or {name => File} |
|
53
|
+
| body | String | Request body. |
|
54
|
+
| auth | Hash | Basic-Auth hash. {username: "...", password: "..."} |
|
55
|
+
| timeout | Integer | Fixed timeout for connection, read and ssl handshake in seconds. |
|
56
|
+
| open_timeout | Integer | Connection timeout in seconds. |
|
57
|
+
| read_timeout | Integer | Read timeout in seconds. |
|
58
|
+
| ssl_timeout | Integer | SSL handshake timeout in seconds. |
|
59
|
+
| max_redirects | Integer | Max redirect follow, default: 0 |
|
60
|
+
| ssl_verify | Integer | OpenSSL verification, HTTP::Client::SSL_VERIFY_PEER or HTTP::Client::SSL_VERIFY_NONE, defaults to SSL_VERIFY_PEER. |
|
61
|
+
| jar | HTTP::CookieJar | Optional cookie jar to use. Relies on HTTP::CookieJar from http-cookie gem. |
|
62
|
+
|
63
|
+
## License
|
64
|
+
|
65
|
+
MIT
|
data/lib/http-client.rb
ADDED
data/lib/http/client.rb
ADDED
@@ -0,0 +1,333 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'net/http'
|
3
|
+
require 'openssl'
|
4
|
+
require 'uri'
|
5
|
+
require 'mime/types'
|
6
|
+
require 'http-cookie'
|
7
|
+
|
8
|
+
module HTTP
|
9
|
+
module Client
|
10
|
+
VERSION = '0.1.0'
|
11
|
+
|
12
|
+
GET = Net::HTTP::Get
|
13
|
+
HEAD = Net::HTTP::Head
|
14
|
+
PUT = Net::HTTP::Put
|
15
|
+
POST = Net::HTTP::Post
|
16
|
+
DELETE = Net::HTTP::Delete
|
17
|
+
OPTIONS = Net::HTTP::Options
|
18
|
+
TRACE = Net::HTTP::Trace
|
19
|
+
VALID_VERBS = [GET, HEAD, PUT, POST, DELETE, OPTIONS, TRACE]
|
20
|
+
|
21
|
+
SSL_VERIFY_NONE = OpenSSL::SSL::VERIFY_NONE
|
22
|
+
SSL_VERIFY_PEER = OpenSSL::SSL::VERIFY_PEER
|
23
|
+
VALID_SSL_VERIFICATIONS = [SSL_VERIFY_NONE, SSL_VERIFY_PEER]
|
24
|
+
|
25
|
+
DEFAULT_HEADERS = {'User-Agent' => 'HTTP Client API/1.0'}
|
26
|
+
|
27
|
+
class Request
|
28
|
+
attr_reader :uri
|
29
|
+
|
30
|
+
VALID_PARAMETERS = %w(headers files query body auth timeout open_timeout ssl_timeout read_timeout max_redirects ssl_verify jar)
|
31
|
+
|
32
|
+
# Create a new HTTP Client Request.
|
33
|
+
#
|
34
|
+
# @param verb [Symbol] HTTP verb, one of :get, :head, :put, :post, :delete, :options, :trace.
|
35
|
+
# @param uri [String] Remote URI
|
36
|
+
# @param headers [Hash] Net::HTTP headers, in key-value pairs.
|
37
|
+
# @param query [Hash] Net::HTTP query-string in key-value pairs.
|
38
|
+
# @param files [Hash] Multi-part file uploads, in key-value pairs of {name => path_to_file} or {name => File}
|
39
|
+
# @param body [String] Request body.
|
40
|
+
# @param auth [Hash] Basic-Auth hash. {username: "...", password: "..."}
|
41
|
+
# @param timeout [Integer] Fixed timeout for connection, read and ssl handshake in seconds.
|
42
|
+
# @param open_timeout [Integer] Connection timeout in seconds.
|
43
|
+
# @param read_timeout [Integer] Read timeout in seconds.
|
44
|
+
# @param ssl_timeout [Integer] SSL handshake timeout in seconds.
|
45
|
+
# @param max_redirects [Integer] Max redirect follow, default: 0
|
46
|
+
# @param ssl_verify [Integer] OpenSSL verification, HTTP::Client::SSL_VERIFY_PEER or HTTP::Client::SSL_VERIFY_NONE, defaults to SSL_VERIFY_PEER.
|
47
|
+
# @param jar [HTTP::CookieJar] Optional cookie jar to use. Relies on HTTP::CookieJar from http-cookie gem.
|
48
|
+
#
|
49
|
+
# @return [HTTP::Client::Request]
|
50
|
+
#
|
51
|
+
def initialize verb, uri, args = {}
|
52
|
+
args.each do |k, v|
|
53
|
+
raise ArgumentError, "unknown argument #{k}" unless VALID_PARAMETERS.include?(k.to_s)
|
54
|
+
end
|
55
|
+
|
56
|
+
parse_uri! uri
|
57
|
+
setup_request_delegate! verb, args
|
58
|
+
|
59
|
+
if body = args[:body]
|
60
|
+
raise ArgumentError, "#{verb} cannot have body" unless klass.const_get(:REQUEST_HAS_BODY)
|
61
|
+
@delegate.body = body
|
62
|
+
end
|
63
|
+
|
64
|
+
if auth = args[:auth]
|
65
|
+
@delegate.basic_auth(auth.fetch(:username), auth.fetch(:password))
|
66
|
+
end
|
67
|
+
|
68
|
+
# generic timeout
|
69
|
+
if timeout = args[:timeout]
|
70
|
+
@open_timeout = timeout
|
71
|
+
@ssl_timeout = timeout
|
72
|
+
@read_timeout = timeout
|
73
|
+
end
|
74
|
+
|
75
|
+
# overrides
|
76
|
+
@open_timeout = args[:open_timeout] if args[:open_timeout]
|
77
|
+
@ssl_timeout = args[:ssl_timeout] if args[:ssl_timeout]
|
78
|
+
@read_timeout = args[:read_timeout] if args[:read_timeout]
|
79
|
+
|
80
|
+
@redirects = args.fetch(:max_redirects, 0)
|
81
|
+
@ssl_verify = args.fetch(:ssl_verify, SSL_VERIFY_PEER)
|
82
|
+
@jar = args.fetch(:jar, HTTP::CookieJar.new)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Executes a request.
|
86
|
+
#
|
87
|
+
# @return [HTTP::Client::Response]
|
88
|
+
#
|
89
|
+
def execute
|
90
|
+
@last_effective_uri = uri
|
91
|
+
|
92
|
+
cookie = HTTP::Cookie.cookie_value(@jar.cookies(uri))
|
93
|
+
if cookie && !cookie.empty?
|
94
|
+
@delegate.add_field('Cookie', cookie)
|
95
|
+
end
|
96
|
+
|
97
|
+
response = request!(uri, @delegate)
|
98
|
+
@jar.parse(response['set-cookie'].to_s, uri)
|
99
|
+
|
100
|
+
while @redirects > 0 && [301, 302, 307].include?(response.code.to_i)
|
101
|
+
@redirects -= 1
|
102
|
+
redirect = redirect_to(response['location'])
|
103
|
+
|
104
|
+
cookie = HTTP::Cookie.cookie_value(@jar.cookies(@last_effective_uri))
|
105
|
+
if cookie && !cookie.empty?
|
106
|
+
redirect.add_field('Cookie', cookie)
|
107
|
+
end
|
108
|
+
|
109
|
+
response = request!(@last_effective_uri, redirect)
|
110
|
+
@jar.parse(response['set-cookie'].to_s, @last_effective_uri)
|
111
|
+
end
|
112
|
+
|
113
|
+
Response.new(response, @last_effective_uri)
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
def parse_uri! uri
|
118
|
+
@uri = URI.parse(uri)
|
119
|
+
case @uri
|
120
|
+
when URI::HTTP, URI::HTTPS
|
121
|
+
# ok
|
122
|
+
else
|
123
|
+
raise ArgumentError, "Invalid URI #{uri}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def setup_request_delegate! verb, args
|
128
|
+
klass = find_delegate_class(verb)
|
129
|
+
@headers = DEFAULT_HEADERS.merge(args.fetch(:headers, {}))
|
130
|
+
|
131
|
+
files = args[:files]
|
132
|
+
qs = args[:query]
|
133
|
+
|
134
|
+
if files
|
135
|
+
raise ArgumentError, "#{verb} cannot have body" unless klass.const_get(:REQUEST_HAS_BODY)
|
136
|
+
multipart = Multipart.new(files, qs)
|
137
|
+
@delegate = klass.new(@uri.request_uri, headers_for(@uri))
|
138
|
+
@delegate.content_type = multipart.content_type
|
139
|
+
@delegate.body = multipart.body
|
140
|
+
elsif qs
|
141
|
+
if klass.const_get(:REQUEST_HAS_BODY)
|
142
|
+
@delegate = klass.new(@uri.request_uri, headers_for(@uri))
|
143
|
+
@delegate.set_form_data(qs)
|
144
|
+
else
|
145
|
+
@uri.query = URI.encode_www_form(qs)
|
146
|
+
@delegate = klass.new(@uri.request_uri, headers_for(@uri))
|
147
|
+
end
|
148
|
+
else
|
149
|
+
@delegate = klass.new(@uri.request_uri, headers_for(@uri))
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def request! uri, delegate
|
154
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
155
|
+
if uri.scheme == 'https'
|
156
|
+
http.use_ssl = true
|
157
|
+
http.verify_mode = @ssl_verify
|
158
|
+
end
|
159
|
+
|
160
|
+
http.open_timeout = @open_timeout if @open_timeout
|
161
|
+
http.read_timeout = @read_timeout if @read_timeout
|
162
|
+
http.ssl_timeout = @ssl_timeout if @ssl_timeout
|
163
|
+
|
164
|
+
response = http.request(delegate)
|
165
|
+
http.finish if http.started?
|
166
|
+
response
|
167
|
+
end
|
168
|
+
|
169
|
+
def redirect_to uri
|
170
|
+
@last_effective_uri = URI.parse(uri)
|
171
|
+
GET.new(@last_effective_uri.request_uri, headers_for(@last_effective_uri))
|
172
|
+
end
|
173
|
+
|
174
|
+
def headers_for uri
|
175
|
+
@headers
|
176
|
+
end
|
177
|
+
|
178
|
+
def find_delegate_class verb
|
179
|
+
if VALID_VERBS.include?(verb)
|
180
|
+
verb
|
181
|
+
else
|
182
|
+
find_verb_class(verb.to_s)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def find_verb_class string
|
187
|
+
case string
|
188
|
+
when /^get$/i then GET
|
189
|
+
when /^head$/i then HEAD
|
190
|
+
when /^put$/i then PUT
|
191
|
+
when /^post$/i then POST
|
192
|
+
when /^delete$/i then DELETE
|
193
|
+
else
|
194
|
+
raise ArgumentError, "Invalid verb #{string}"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end # Request
|
198
|
+
|
199
|
+
class Response
|
200
|
+
attr_reader :last_effective_uri
|
201
|
+
|
202
|
+
def initialize response, last_effective_uri
|
203
|
+
@response = response
|
204
|
+
@last_effective_uri = last_effective_uri
|
205
|
+
end
|
206
|
+
|
207
|
+
def code
|
208
|
+
@response.code.to_i
|
209
|
+
end
|
210
|
+
|
211
|
+
def headers
|
212
|
+
@headers ||= @response.each_header.entries
|
213
|
+
end
|
214
|
+
|
215
|
+
def body
|
216
|
+
@response.body
|
217
|
+
end
|
218
|
+
|
219
|
+
def inspect
|
220
|
+
"#<#{self.class} @code=#{code} @last_effective_uri=#{last_effective_uri}>"
|
221
|
+
end
|
222
|
+
end # Response
|
223
|
+
|
224
|
+
class Multipart
|
225
|
+
attr_reader :boundary
|
226
|
+
|
227
|
+
EOL = "\r\n"
|
228
|
+
DEFAULT_MIME_TYPE = 'application/octet-stream'
|
229
|
+
|
230
|
+
def initialize files, query = {}
|
231
|
+
@files = files
|
232
|
+
@query = query
|
233
|
+
@boundary = generate_boundary
|
234
|
+
end
|
235
|
+
|
236
|
+
def content_type
|
237
|
+
"multipart/form-data; boundary=#{boundary}"
|
238
|
+
end
|
239
|
+
|
240
|
+
def body
|
241
|
+
body = ''.encode('ASCII-8BIT')
|
242
|
+
separator = "--#{boundary}"
|
243
|
+
|
244
|
+
@query.each do |key, value|
|
245
|
+
body << separator << EOL
|
246
|
+
body << %Q{Content-Disposition: form-data; name="#{key}"} << EOL
|
247
|
+
body << EOL
|
248
|
+
body << value
|
249
|
+
body << EOL
|
250
|
+
end
|
251
|
+
|
252
|
+
@files.each do |name, handle|
|
253
|
+
if handle.respond_to?(:read)
|
254
|
+
path = handle.path
|
255
|
+
data = io.read
|
256
|
+
else
|
257
|
+
path = handle
|
258
|
+
data = IO.read(path)
|
259
|
+
end
|
260
|
+
|
261
|
+
filename = File.basename(path)
|
262
|
+
mime = mime_type(filename)
|
263
|
+
|
264
|
+
body << separator << EOL
|
265
|
+
body << %Q{Content-Disposition: form-data; name="#{name}"; filename="#{filename}"} << EOL
|
266
|
+
body << %Q{Content-Type: #{mime}} << EOL
|
267
|
+
body << %Q{Content-Transfer-Encoding: binary} << EOL
|
268
|
+
body << %Q{Content-Length: #{data.bytesize}} << EOL
|
269
|
+
body << EOL
|
270
|
+
body << data
|
271
|
+
body << EOL
|
272
|
+
end
|
273
|
+
|
274
|
+
body << separator << "--" << EOL
|
275
|
+
body
|
276
|
+
end
|
277
|
+
|
278
|
+
private
|
279
|
+
def generate_boundary
|
280
|
+
SecureRandom.random_bytes(16).unpack('H*').first
|
281
|
+
end
|
282
|
+
|
283
|
+
def mime_type filename
|
284
|
+
MIME::Types.type_for(File.extname(filename)).first || DEFAULT_MIME_TYPE
|
285
|
+
end
|
286
|
+
end # Multipart
|
287
|
+
|
288
|
+
# Helpers
|
289
|
+
class << self
|
290
|
+
# Creates a GET request and executes it, returning the response.
|
291
|
+
# @see HTTP::Client::Request#initialize
|
292
|
+
#
|
293
|
+
# @return [HTTP::Client::Response]
|
294
|
+
#
|
295
|
+
def get *args; Request.new(GET, *args).execute; end
|
296
|
+
|
297
|
+
# Creates a PUT request and executes it, returning the response.
|
298
|
+
# @see HTTP::Client::Request#initialize
|
299
|
+
#
|
300
|
+
# @return [HTTP::Client::Response]
|
301
|
+
#
|
302
|
+
def put *args; Request.new(PUT, *args).execute; end
|
303
|
+
|
304
|
+
# Creates a POST request and executes it, returning the response.
|
305
|
+
# @see HTTP::Client::Request#initialize
|
306
|
+
#
|
307
|
+
# @return [HTTP::Client::Response]
|
308
|
+
#
|
309
|
+
def post *args; Request.new(POST, *args).execute; end
|
310
|
+
|
311
|
+
# Creates a DELETE request and executes it, returning the response.
|
312
|
+
# @see HTTP::Client::Request#initialize
|
313
|
+
#
|
314
|
+
# @return [HTTP::Client::Response]
|
315
|
+
#
|
316
|
+
def delete *args; Request.new(DELETE, *args).execute; end
|
317
|
+
|
318
|
+
# Creates a OPTIONS request and executes it, returning the response.
|
319
|
+
# @see HTTP::Client::Request#initialize
|
320
|
+
#
|
321
|
+
# @return [HTTP::Client::Response]
|
322
|
+
#
|
323
|
+
def options *args; Request.new(OPTIONS, *args).execute; end
|
324
|
+
|
325
|
+
# Creates a TRACE request and executes it, returning the response.
|
326
|
+
# @see HTTP::Client::Request#initialize
|
327
|
+
#
|
328
|
+
# @return [HTTP::Client::Response]
|
329
|
+
#
|
330
|
+
def trace *args; Request.new(TRACE, *args).execute; end
|
331
|
+
end
|
332
|
+
end # Client
|
333
|
+
end # HTTP
|
data/test/helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
describe 'HTTP Client Request' do
|
4
|
+
it 'should reject invalid arguments' do
|
5
|
+
assert_raises(ArgumentError, "invalid verb") {HTTP::Client::Request.new(:foo)}
|
6
|
+
assert_raises(URI::InvalidURIError, "invalid uri") {HTTP::Client::Request.new(:get, "http://")}
|
7
|
+
assert_raises(ArgumentError, "invalid argument") {HTTP::Client::Request.new(:get, "http://example.org/", foo: 1)}
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'validates body based on request verb' do
|
11
|
+
assert_raises(ArgumentError, "get cannot have body") {HTTP::Client::Request.new(:get, "http://a.c", files: {test: __FILE__})}
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'allows creation of valid request object' do
|
15
|
+
assert HTTP::Client::Request.new(
|
16
|
+
:post,
|
17
|
+
"http://example.org/",
|
18
|
+
query: {title: "test"},
|
19
|
+
files: {test1: __FILE__, test2: __FILE__},
|
20
|
+
max_redirects: 2,
|
21
|
+
timeout: 10,
|
22
|
+
ssl_verify: HTTP::Client::SSL_VERIFY_NONE
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
# TODO: mock http endpoint
|
27
|
+
it 'executes a request and returns reponse' do
|
28
|
+
assert HTTP::Client.get("http://www.google.com")
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'raises timeout errors' do
|
32
|
+
assert_raises(Net::OpenTimeout) {HTTP::Client.get("http://dingus.in:1000/", timeout: 0.2)}
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: http-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bharanee Rathna
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mime-types
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: http-cookie
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '11.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '11.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest-reporters
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
69
|
+
description: Light weight wrapper around Net::HTTP
|
70
|
+
email:
|
71
|
+
- deepfryed@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- CHANGELOG
|
77
|
+
- README.md
|
78
|
+
- lib/http-client.rb
|
79
|
+
- lib/http/client.rb
|
80
|
+
- test/helper.rb
|
81
|
+
- test/test_request.rb
|
82
|
+
homepage: http://github.com/deepfryed/http-client
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 2.2.2
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: A client wrapper around Net::HTTP
|
106
|
+
test_files: []
|