httpi 0.7.4 → 0.7.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/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: []