httpi 0.7.4 → 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -25,7 +25,7 @@ Here's a POST request with a request object:
25
25
  request = HTTPI::Request.new
26
26
  request.url = "http://post.example.com"
27
27
  request.body = "send me"
28
-
28
+
29
29
  HTTPI.post request
30
30
 
31
31
  And a GET request using HTTP basic auth and the Curb adapter:
@@ -33,7 +33,7 @@ And a GET request using HTTP basic auth and the Curb adapter:
33
33
  request = HTTPI::Request.new
34
34
  request.url = "http://auth.example.com"
35
35
  request.auth.basic "username", "password"
36
-
36
+
37
37
  HTTPI.get request, :curb
38
38
 
39
39
  HTTPI also comes shortcuts. This executes a PUT request:
@@ -102,7 +102,7 @@ By default, HTTPI uses the `HTTPClient` adapter. But changing the default is fai
102
102
 
103
103
  HTTPI::Adapter.use = :curb # or one of [:httpclient, :net_http]
104
104
 
105
- Notice: HTTPI does not force you to install any of these libraries. Instead you need to make sure to install the HTTP library of your choice and/or add it to your Gemfile. HTTPI will then load the library when executing HTTP requests.
105
+ Notice: HTTPI does not force you to install any of these libraries. So please make sure to install the HTTP library of your choice and/or add it to your Gemfile. HTTPI will then load the library when executing HTTP requests. HTTPI will fall back to using net/http when any other adapter could not be loaded.
106
106
 
107
107
  HTTPI::Request
108
108
  --------------
@@ -178,6 +178,15 @@ The `response.body` handles gzipped and [DIME](http://en.wikipedia.org/wiki/Dire
178
178
  * Return the original `HTTPI::Request` for debugging purposes
179
179
  * Return the time it took to execute the request
180
180
 
181
+ Logging
182
+ -------
183
+
184
+ HTTPI by default logs each HTTP request to STDOUT using a log level of :debug.
185
+
186
+ HTTPI.log = false # disabling logging
187
+ HTTPI.logger = MyLogger # changing the logger
188
+ HTTPI.log_level = :info # changing the log level
189
+
181
190
  Participate
182
191
  -----------
183
192
 
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.add_development_dependency "curb", "~> 0.7.8"
21
21
 
22
22
  s.add_development_dependency "rspec", "~> 2.2"
23
+ s.add_development_dependency "autotest"
23
24
  s.add_development_dependency "mocha", "~> 0.9.9"
24
25
  s.add_development_dependency "webmock", "~> 1.4.0"
25
26
 
@@ -1,3 +1,4 @@
1
+ require "logger"
1
2
  require "httpi/version"
2
3
  require "httpi/request"
3
4
  require "httpi/adapter"
@@ -72,13 +73,15 @@ module HTTPI
72
73
 
73
74
  REQUEST_METHODS = [:get, :post, :head, :put, :delete]
74
75
 
76
+ DEFAULT_LOG_LEVEL = :debug
77
+
75
78
  class << self
76
79
 
77
80
  # Executes an HTTP GET request.
78
81
  def get(request, adapter = nil)
79
82
  request = Request.new :url => request if request.kind_of? String
80
83
 
81
- with request, adapter do |adapter|
84
+ with_adapter :get, request, adapter do |adapter|
82
85
  yield adapter.client if block_given?
83
86
  adapter.get request
84
87
  end
@@ -88,7 +91,7 @@ module HTTPI
88
91
  def post(*args)
89
92
  request, adapter = request_and_adapter_from(args)
90
93
 
91
- with request, adapter do |adapter|
94
+ with_adapter :post, request, adapter do |adapter|
92
95
  yield adapter.client if block_given?
93
96
  adapter.post request
94
97
  end
@@ -98,7 +101,7 @@ module HTTPI
98
101
  def head(request, adapter = nil)
99
102
  request = Request.new :url => request if request.kind_of? String
100
103
 
101
- with request, adapter do |adapter|
104
+ with_adapter :head, request, adapter do |adapter|
102
105
  yield adapter.client if block_given?
103
106
  adapter.head request
104
107
  end
@@ -108,7 +111,7 @@ module HTTPI
108
111
  def put(*args)
109
112
  request, adapter = request_and_adapter_from(args)
110
113
 
111
- with request, adapter do |adapter|
114
+ with_adapter :put, request, adapter do |adapter|
112
115
  yield adapter.client if block_given?
113
116
  adapter.put request
114
117
  end
@@ -118,7 +121,7 @@ module HTTPI
118
121
  def delete(request, adapter = nil)
119
122
  request = Request.new :url => request if request.kind_of? String
120
123
 
121
- with request, adapter do |adapter|
124
+ with_adapter :delete, request, adapter do |adapter|
122
125
  yield adapter.client if block_given?
123
126
  adapter.delete request
124
127
  end
@@ -130,6 +133,42 @@ module HTTPI
130
133
  send method, request, adapter
131
134
  end
132
135
 
136
+ # Sets whether to log HTTP requests.
137
+ attr_writer :log
138
+
139
+ # Returns whether to log HTTP requests. Defaults to +true+.
140
+ def log?
141
+ @log != false
142
+ end
143
+
144
+ # Sets the logger to use.
145
+ attr_writer :logger
146
+
147
+ # Returns the logger. Defaults to an instance of +Logger+ writing to STDOUT.
148
+ def logger
149
+ @logger ||= ::Logger.new STDOUT
150
+ end
151
+
152
+ # Sets the log level.
153
+ attr_writer :log_level
154
+
155
+ # Returns the log level. Defaults to :debug.
156
+ def log_level
157
+ @log_level ||= :debug
158
+ end
159
+
160
+ # Logs given +messages+.
161
+ def log(*messages)
162
+ logger.send log_level, messages.join(" ") if log?
163
+ end
164
+
165
+ # Reset the default config.
166
+ def reset_config!
167
+ @log = nil
168
+ @logger = nil
169
+ @log_level = nil
170
+ end
171
+
133
172
  private
134
173
 
135
174
  # Checks whether +args+ contains of an <tt>HTTPI::Request</tt> or a URL
@@ -140,11 +179,14 @@ module HTTPI
140
179
  [Request.new(:url => args[0], :body => args[1]), args[2]]
141
180
  end
142
181
 
143
- # Expects a +request+ and an +adapter+ (defaults to <tt>Adapter.use</tt>)
144
- # and yields a new instance of the adapter to a given block.
145
- def with(request, adapter)
182
+ # Expects a request +method+, a +request+ and an +adapter+ (defaults to
183
+ # <tt>Adapter.use</tt>) and yields an instance of the adapter to a given block.
184
+ def with_adapter(method, request, adapter)
146
185
  adapter ||= Adapter.use
147
- yield Adapter.find(adapter).new(request)
186
+ adapter, adapter_class = Adapter.find adapter
187
+
188
+ HTTPI.log "HTTPI executes HTTP #{method.to_s.upcase} using the #{adapter} adapter"
189
+ yield adapter_class.new(request)
148
190
  end
149
191
 
150
192
  end
@@ -15,6 +15,9 @@ module HTTPI
15
15
  # The default adapter.
16
16
  DEFAULT = :httpclient
17
17
 
18
+ # The fallback (worst-choice) adapter.
19
+ FALLBACK = :net_http
20
+
18
21
  # Returns the adapter to use. Defaults to <tt>HTTPI::Adapter::DEFAULT</tt>.
19
22
  def self.use
20
23
  @use ||= DEFAULT
@@ -28,13 +31,17 @@ module HTTPI
28
31
 
29
32
  # Returns a memoized +Hash+ of adapters.
30
33
  def self.adapters
31
- @adapters ||= { :httpclient => HTTPClient, :curb => Curb, :net_http => NetHTTP }
34
+ @adapters ||= {
35
+ :httpclient => { :class => HTTPClient, :require => "httpclient" },
36
+ :curb => { :class => Curb, :require => "curb" },
37
+ :net_http => { :class => NetHTTP, :require => "net/https" }
38
+ }
32
39
  end
33
40
 
34
41
  # Returns an +adapter+. Raises an +ArgumentError+ unless the +adapter+ exists.
35
42
  def self.find(adapter)
36
43
  validate_adapter! adapter
37
- adapters[adapter]
44
+ load_adapter adapter
38
45
  end
39
46
 
40
47
  private
@@ -44,5 +51,17 @@ module HTTPI
44
51
  raise ArgumentError, "Invalid HTTPI adapter: #{adapter}" unless adapters[adapter]
45
52
  end
46
53
 
54
+ # Tries to load and return the given +adapter+ name and class and falls back to the +FALLBACK+ adapter.
55
+ def self.load_adapter(adapter)
56
+ require adapters[adapter][:require]
57
+ [adapter, adapters[adapter][:class]]
58
+ rescue LoadError
59
+ HTTPI.log "HTTPI tried to use the #{adapter} adapter, but was unable to find the library in the LOAD_PATH.",
60
+ "Falling back to using the #{FALLBACK} adapter now."
61
+
62
+ require adapters[FALLBACK][:require]
63
+ [FALLBACK, adapters[FALLBACK][:class]]
64
+ end
65
+
47
66
  end
48
67
  end
@@ -9,9 +9,7 @@ module HTTPI
9
9
  # http://rubygems.org/gems/curb
10
10
  class Curb
11
11
 
12
- # Requires the "curb" gem.
13
12
  def initialize(request = nil)
14
- require "curb"
15
13
  end
16
14
 
17
15
  # Returns a memoized <tt>Curl::Easy</tt> instance.
@@ -9,9 +9,7 @@ module HTTPI
9
9
  # http://rubygems.org/gems/httpclient
10
10
  class HTTPClient
11
11
 
12
- # Requires the "httpclient" gem.
13
12
  def initialize(request = nil)
14
- require "httpclient"
15
13
  end
16
14
 
17
15
  # Returns a memoized <tt>HTTPClient</tt> instance.
@@ -10,9 +10,7 @@ module HTTPI
10
10
  # http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/
11
11
  class NetHTTP
12
12
 
13
- # Requires the "net/https" library and sets up a new client.
14
13
  def initialize(request)
15
- require "net/https"
16
14
  self.client = new_client request
17
15
  end
18
16
 
@@ -1,5 +1,5 @@
1
1
  module HTTPI
2
2
 
3
- VERSION = "0.7.4"
3
+ VERSION = "0.7.5"
4
4
 
5
5
  end
@@ -8,13 +8,6 @@ describe HTTPI::Adapter::Curb do
8
8
  let(:adapter) { HTTPI::Adapter::Curb.new }
9
9
  let(:curb) { Curl::Easy.any_instance }
10
10
 
11
- describe ".new" do
12
- it "should require the Curb gem" do
13
- HTTPI::Adapter::Curb.any_instance.expects(:require).with("curb")
14
- HTTPI::Adapter::Curb.new
15
- end
16
- end
17
-
18
11
  describe "#get" do
19
12
  before do
20
13
  curb.expects(:http_get)
@@ -9,13 +9,6 @@ describe HTTPI::Adapter::HTTPClient do
9
9
  let(:httpclient) { HTTPClient.any_instance }
10
10
  let(:ssl_config) { HTTPClient::SSLConfig.any_instance }
11
11
 
12
- describe ".new" do
13
- it "should require the HTTPClient gem" do
14
- HTTPI::Adapter::HTTPClient.any_instance.expects(:require).with("httpclient")
15
- HTTPI::Adapter::HTTPClient.new
16
- end
17
- end
18
-
19
12
  describe "#get" do
20
13
  it "should return a valid HTTPI::Response" do
21
14
  httpclient.expects(:get).with(basic_request.url, nil, basic_request.headers).returns(http_message)
@@ -9,13 +9,6 @@ describe HTTPI::Adapter::NetHTTP do
9
9
  @adapter ||= HTTPI::Adapter::NetHTTP.new request
10
10
  end
11
11
 
12
- describe ".new" do
13
- it "should require the Net::HTTP library" do
14
- HTTPI::Adapter::NetHTTP.any_instance.expects(:require).with("net/https")
15
- HTTPI::Adapter::NetHTTP.new HTTPI::Request.new(:url => "http://example.com")
16
- end
17
- end
18
-
19
12
  describe "#get" do
20
13
  it "should return a valid HTTPI::Response" do
21
14
  stub_request(:get, basic_request.url.to_s).to_return(:body => Fixture.xml)
@@ -23,24 +23,47 @@ describe HTTPI::Adapter do
23
23
  end
24
24
 
25
25
  describe ".adapters" do
26
- it "should return a memoized Hash of adapters" do
27
- adapter.adapters.should have(3).items
28
- adapter.adapters.should include(
29
- :httpclient => HTTPI::Adapter::HTTPClient,
30
- :curb => HTTPI::Adapter::Curb,
31
- :net_http => HTTPI::Adapter::NetHTTP
32
- )
26
+ it "should return a Hash of adapter details" do
27
+ adapter.adapters.should == {
28
+ :httpclient => { :class => HTTPI::Adapter::HTTPClient, :require => "httpclient" },
29
+ :curb => { :class => HTTPI::Adapter::Curb, :require => "curb" },
30
+ :net_http => { :class => HTTPI::Adapter::NetHTTP, :require => "net/https" }
31
+ }
32
+ end
33
+
34
+ it "should return a memoized Hash" do
35
+ adapter.adapters.should equal(adapter.adapters)
33
36
  end
34
37
  end
35
38
 
36
39
  describe ".find" do
37
- it "should return the adapter for a given Symbol" do
38
- adapter.find(:httpclient).should == HTTPI::Adapter::HTTPClient
40
+ it "should return the adapter name and class for a given Symbol" do
41
+ adapter.find(:httpclient).should == [:httpclient, HTTPI::Adapter::HTTPClient]
39
42
  end
40
43
 
41
44
  it "should raise an ArgumentError in case of an invalid adapter" do
42
45
  lambda { adapter.find :unknown }.should raise_error(ArgumentError)
43
46
  end
47
+
48
+ context "when the given adapter could not be found" do
49
+ before do
50
+ adapter.expects(:require).with("httpclient").raises(LoadError)
51
+ adapter.expects(:require).with(HTTPI::Adapter.adapters[HTTPI::Adapter::FALLBACK][:require])
52
+ end
53
+
54
+ it "should fall back to use the HTTPI::Adapter::FALLBACK adapter" do
55
+ adapter.find :httpclient
56
+ end
57
+
58
+ it "should log that the adapter to use could not be required" do
59
+ HTTPI.expects(:log).with(
60
+ "HTTPI tried to use the httpclient adapter, but was unable to find the library in the LOAD_PATH.",
61
+ "Falling back to using the #{HTTPI::Adapter::FALLBACK} adapter now."
62
+ )
63
+
64
+ adapter.find :httpclient
65
+ end
66
+ end
44
67
  end
45
68
 
46
69
  end
@@ -3,8 +3,8 @@ require "httpi"
3
3
 
4
4
  describe HTTPI do
5
5
  let(:client) { HTTPI }
6
- let(:default_adapter) { HTTPI::Adapter.find HTTPI::Adapter.use }
7
- let(:curb) { HTTPI::Adapter.find :curb }
6
+ let(:default_adapter) { HTTPI::Adapter.find(HTTPI::Adapter.use)[1] }
7
+ let(:curb) { HTTPI::Adapter.find(:curb)[1] }
8
8
 
9
9
  describe ".get(request)" do
10
10
  it "should execute an HTTP GET request using the default adapter" do
@@ -197,7 +197,6 @@ describe HTTPI do
197
197
  end
198
198
 
199
199
  HTTPI::REQUEST_METHODS.each do |method|
200
-
201
200
  describe ".request(#{method}, request, adapter)" do
202
201
  it "should delegate to the .#{method} method" do
203
202
  HTTPI.expects(method)
@@ -206,25 +205,30 @@ describe HTTPI do
206
205
  end
207
206
 
208
207
  describe ".#{method}" do
208
+ let(:request) { HTTPI::Request.new :url => "http://example.com" }
209
+
209
210
  it "should raise an ArgumentError in case of an invalid adapter" do
210
- lambda { client.request method, HTTPI::Request.new, :invalid }.should raise_error(ArgumentError)
211
+ lambda { client.request method, request, :invalid }.should raise_error(ArgumentError)
211
212
  end
212
213
 
213
214
  it "should raise an ArgumentError in case of an invalid request" do
214
215
  lambda { client.request method, "invalid" }.should raise_error(ArgumentError)
215
216
  end
216
217
 
217
- HTTPI::Adapter.adapters.each do |adapter, adapter_class|
218
+ HTTPI::Adapter.adapters.each do |adapter, values|
218
219
  client_class = {
219
220
  :httpclient => lambda { HTTPClient },
220
221
  :curb => lambda { Curl::Easy },
221
222
  :net_http => lambda { Net::HTTP }
222
223
  }
223
224
 
224
- context "using :#{adapter} with a block" do
225
- let(:request) { HTTPI::Request.new :url => "http://example.com" }
225
+ context "using #{adapter}" do
226
+ before { values[:class].any_instance.expects(method) }
226
227
 
227
- before { adapter_class.any_instance.stubs(method) }
228
+ it "should log that we're executing an HTTP request" do
229
+ HTTPI.expects(:log).with("HTTPI executes HTTP #{method.to_s.upcase} using the #{adapter} adapter")
230
+ client.request method, request, adapter
231
+ end
228
232
 
229
233
  it "should yield the HTTP client instance used for the request" do
230
234
  block = lambda { |http| http.should be_a(client_class[adapter].call) }
@@ -233,6 +237,75 @@ describe HTTPI do
233
237
  end
234
238
  end
235
239
 
240
+ HTTPI::Adapter.adapters.reject { |key, value| key == HTTPI::Adapter::FALLBACK }.each do |adapter, values|
241
+ context "when #{adapter} could not be loaded" do
242
+ before do
243
+ HTTPI::Adapter.expects(:require).with(values[:require]).raises(LoadError)
244
+ HTTPI::Adapter.expects(:require).with("net/https")
245
+ HTTPI::Adapter::NetHTTP.any_instance.expects(method)
246
+ end
247
+
248
+ it "should fall back to using the FALLBACK adapter" do
249
+ HTTPI.expects(:log).with(
250
+ "HTTPI tried to use the #{adapter} adapter, but was unable to find the library in the LOAD_PATH.",
251
+ "Falling back to using the #{HTTPI::Adapter::FALLBACK} adapter now."
252
+ )
253
+ HTTPI.expects(:log).with("HTTPI executes HTTP #{method.to_s.upcase} using the #{HTTPI::Adapter::FALLBACK} adapter")
254
+
255
+ client.request method, request, adapter
256
+ end
257
+ end
258
+ end
259
+ end
260
+ end
261
+
262
+ context "with resetting the defaults" do
263
+ before { HTTPI.reset_config! }
264
+
265
+ after do
266
+ HTTPI.reset_config!
267
+ HTTPI.log = false # disable for specs
268
+ end
269
+
270
+ describe ".log" do
271
+ it "should default to true" do
272
+ HTTPI.log?.should be_true
273
+ end
274
+
275
+ it "should set whether to log" do
276
+ HTTPI.log = false
277
+ HTTPI.log?.should be_false
278
+ end
279
+ end
280
+
281
+ describe ".logger" do
282
+ it "should default to Logger writing to STDOUT" do
283
+ HTTPI.logger.should be_a(Logger)
284
+ end
285
+
286
+ it "should set the logger to use" do
287
+ MyLogger = Class.new
288
+ HTTPI.logger = MyLogger
289
+ HTTPI.logger.should == MyLogger
290
+ end
291
+ end
292
+
293
+ describe ".log_level" do
294
+ it "should default to :debug" do
295
+ HTTPI.log_level.should == :debug
296
+ end
297
+
298
+ it "should set the log level to use" do
299
+ HTTPI.log_level = :info
300
+ HTTPI.log_level.should == :info
301
+ end
302
+ end
303
+
304
+ describe ".log" do
305
+ it "should log given messages" do
306
+ HTTPI.logger.expects(:debug).with("Log this")
307
+ HTTPI.log "Log", "this"
308
+ end
236
309
  end
237
310
  end
238
311
 
@@ -6,5 +6,7 @@ RSpec.configure do |config|
6
6
  config.mock_with :mocha
7
7
  end
8
8
 
9
+ HTTPI.log = false # disable for specs
10
+
9
11
  require "support/fixture"
10
12
  require "support/matchers"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httpi
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 9
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 7
9
- - 4
10
- version: 0.7.4
9
+ - 5
10
+ version: 0.7.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Daniel Harrington
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-12-20 00:00:00 +01:00
19
+ date: 2010-12-22 00:00:00 +01:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -81,9 +81,23 @@ dependencies:
81
81
  type: :development
82
82
  version_requirements: *id004
83
83
  - !ruby/object:Gem::Dependency
84
- name: mocha
84
+ name: autotest
85
85
  prerelease: false
86
86
  requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ type: :development
96
+ version_requirements: *id005
97
+ - !ruby/object:Gem::Dependency
98
+ name: mocha
99
+ prerelease: false
100
+ requirement: &id006 !ruby/object:Gem::Requirement
87
101
  none: false
88
102
  requirements:
89
103
  - - ~>
@@ -95,11 +109,11 @@ dependencies:
95
109
  - 9
96
110
  version: 0.9.9
97
111
  type: :development
98
- version_requirements: *id005
112
+ version_requirements: *id006
99
113
  - !ruby/object:Gem::Dependency
100
114
  name: webmock
101
115
  prerelease: false
102
- requirement: &id006 !ruby/object:Gem::Requirement
116
+ requirement: &id007 !ruby/object:Gem::Requirement
103
117
  none: false
104
118
  requirements:
105
119
  - - ~>
@@ -111,7 +125,7 @@ dependencies:
111
125
  - 0
112
126
  version: 1.4.0
113
127
  type: :development
114
- version_requirements: *id006
128
+ version_requirements: *id007
115
129
  description: HTTPI provides a common interface for Ruby HTTP libraries.
116
130
  email: me@rubiii.com
117
131
  executables: []