httpadapter 0.2.1 → 1.0.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.
@@ -19,20 +19,24 @@ require 'rack/response'
19
19
  require 'addressable/uri'
20
20
 
21
21
  module HTTPAdapter #:nodoc:
22
- class RackRequestAdapter
23
- def initialize(request, error_stream=STDERR)
24
- unless request.kind_of?(Rack::Request)
25
- raise TypeError, "Expected Rack::Request, got #{request.class}."
26
- end
27
- @request = request
28
- @error_stream = error_stream
22
+ class RackAdapter
23
+ include HTTPAdapter
24
+
25
+ def initialize(options={})
26
+ options = {
27
+ :error_stream => $stderr
28
+ }.merge(options)
29
+ @error_stream = options[:error_stream]
29
30
  end
30
31
 
31
- def to_ary
32
- method = @request.request_method.to_s.upcase
33
- uri = Addressable::URI.parse(@request.url.to_s).normalize.to_s
32
+ def convert_request_to_a(request_obj)
33
+ unless request_obj.kind_of?(Rack::Request)
34
+ raise TypeError, "Expected Rack::Request, got #{request_obj.class}."
35
+ end
36
+ method = request_obj.request_method.to_s.upcase
37
+ uri = Addressable::URI.parse(request_obj.url.to_s).normalize.to_s
34
38
  headers = []
35
- @request.env.each do |parameter, value|
39
+ request_obj.env.each do |parameter, value|
36
40
  next if parameter !~ /^HTTP_/
37
41
  # Ugh, lossy canonicalization again
38
42
  header = (parameter.gsub(/^HTTP_/, '').split('_').map do |chunk|
@@ -40,12 +44,12 @@ module HTTPAdapter #:nodoc:
40
44
  end).join('-')
41
45
  headers << [header, value]
42
46
  end
43
- return [method, uri, headers, @request.body]
47
+ return [method, uri, headers, request_obj.body]
44
48
  end
45
49
 
46
- def self.from_ary(array)
50
+ def convert_request_from_a(request_ary)
47
51
  # These contortions are really obnoxious; lossiness is bad!
48
- method, uri, headers, body = array
52
+ method, uri, headers, body = request_ary
49
53
  env = {}
50
54
  method = method.to_s.upcase
51
55
  uri = Addressable::URI.parse(uri)
@@ -88,26 +92,15 @@ module HTTPAdapter #:nodoc:
88
92
  return request
89
93
  end
90
94
 
91
- def self.transmit(request, connection=nil)
92
- raise NotImplementedError,
93
- 'No HTTP client implementation available to transmit a Rack::Request.'
94
- end
95
- end
96
-
97
- class RackResponseAdapter
98
- def initialize(response)
99
- unless response.kind_of?(Rack::Response)
100
- raise TypeError, "Expected Rack::Response, got #{response.class}."
95
+ def convert_response_to_a(response_obj)
96
+ unless response_obj.kind_of?(Rack::Response)
97
+ raise TypeError, "Expected Rack::Response, got #{response_obj.class}."
101
98
  end
102
- @response = response
103
- end
104
-
105
- def to_ary
106
- return @response.finish
99
+ return response_obj.finish
107
100
  end
108
101
 
109
- def self.from_ary(array)
110
- status, headers, body = array
102
+ def convert_response_from_a(request_ary)
103
+ status, headers, body = request_ary
111
104
  status = status.to_i
112
105
  body.each do |chunk|
113
106
  # Purely for strict type-checking
@@ -118,5 +111,10 @@ module HTTPAdapter #:nodoc:
118
111
  response = Rack::Response.new(body, status, Hash[headers])
119
112
  return response
120
113
  end
114
+
115
+ def fetch_resource(request_ary, connection=nil)
116
+ raise NotImplementedError,
117
+ 'No HTTP client implementation available to transmit a Rack::Request.'
118
+ end
121
119
  end
122
120
  end
@@ -19,27 +19,26 @@ require 'typhoeus/response'
19
19
  require 'addressable/uri'
20
20
 
21
21
  module HTTPAdapter #:nodoc:
22
- class TyphoeusRequestAdapter
23
- def initialize(request)
24
- unless request.kind_of?(Typhoeus::Request)
25
- raise TypeError, "Expected Typhoeus::Request, got #{request.class}."
26
- end
27
- @request = request
28
- end
22
+ class TyphoeusAdapter
23
+ include HTTPAdapter
29
24
 
30
- def to_ary
31
- method = @request.method.to_s.upcase
32
- uri = @request.url.to_str
25
+ def convert_request_to_a(request_obj)
26
+ unless request_obj.kind_of?(Typhoeus::Request)
27
+ raise TypeError,
28
+ "Expected Typhoeus::Request, got #{request_obj.class}."
29
+ end
30
+ method = request_obj.method.to_s.upcase
31
+ uri = request_obj.url.to_str
33
32
  headers = []
34
- @request.headers.each do |header, value|
33
+ request_obj.headers.each do |header, value|
35
34
  headers << [header, value]
36
35
  end
37
- body = @request.body || ""
36
+ body = request_obj.body || ""
38
37
  return [method, uri, headers, [body]]
39
38
  end
40
39
 
41
- def self.from_ary(array)
42
- method, uri, headers, body = array
40
+ def convert_request_from_a(request_ary)
41
+ method, uri, headers, body = request_ary
43
42
  method = method.to_s.downcase.to_sym
44
43
  uri = Addressable::URI.parse(uri)
45
44
  headers = Hash[headers]
@@ -59,41 +58,14 @@ module HTTPAdapter #:nodoc:
59
58
  return request
60
59
  end
61
60
 
62
- def self.transmit(request, connection=nil)
63
- method, uri, headers, body = request
64
- uri = Addressable::URI.parse(uri)
65
- typhoeus_request = self.from_ary([method, uri, headers, body])
66
- typhoeus_response = nil
67
- unless connection
68
- hydra = Typhoeus::Hydra.new
69
- connection = HTTPAdapter::Connection.new(
70
- uri.host, uri.inferred_port, hydra,
71
- :join => [:run, [], nil]
72
- )
73
- else
74
- http = nil
75
- end
76
- typhoeus_request.on_complete do |response|
77
- typhoeus_response = response
78
- end
79
- connection.connection.queue(typhoeus_request)
80
- connection.join
81
- return TyphoeusResponseAdapter.new(typhoeus_response).to_ary
82
- end
83
- end
84
-
85
- class TyphoeusResponseAdapter
86
- def initialize(response)
87
- unless response.kind_of?(Typhoeus::Response)
88
- raise TypeError, "Expected Typhoeus::Response, got #{response.class}."
61
+ def convert_response_to_a(response_obj)
62
+ unless response_obj.kind_of?(Typhoeus::Response)
63
+ raise TypeError,
64
+ "Expected Typhoeus::Response, got #{response_obj.class}."
89
65
  end
90
- @response = response
91
- end
92
-
93
- def to_ary
94
- status = @response.code.to_i
66
+ status = response_obj.code.to_i
95
67
  headers = []
96
- @response.headers_hash.each do |header, value|
68
+ response_obj.headers_hash.each do |header, value|
97
69
  # Eh? Seriously? This is NOT a header!
98
70
  next if header =~ /^HTTP\/\d\.\d \d{3} .+$/
99
71
  if value.kind_of?(Array)
@@ -105,12 +77,12 @@ module HTTPAdapter #:nodoc:
105
77
  headers << [header, value]
106
78
  end
107
79
  end
108
- body = @response.body || ""
80
+ body = response_obj.body || ""
109
81
  return [status, headers, [body]]
110
82
  end
111
83
 
112
- def self.from_ary(array)
113
- status, headers, body = array
84
+ def convert_response_from_a(request_ary)
85
+ status, headers, body = request_ary
114
86
  status = status.to_i
115
87
  merged_body = ""
116
88
  body.each do |chunk|
@@ -123,5 +95,29 @@ module HTTPAdapter #:nodoc:
123
95
  )
124
96
  return response
125
97
  end
98
+
99
+ def fetch_resource(request_ary, connection=nil)
100
+ method, uri, headers, body = request_ary
101
+ uri = Addressable::URI.parse(uri)
102
+ typhoeus_request = self.convert_request_from_a(
103
+ [method, uri, headers, body]
104
+ )
105
+ typhoeus_response = nil
106
+ unless connection
107
+ hydra = Typhoeus::Hydra.new
108
+ connection = HTTPAdapter::Connection.new(
109
+ uri.host, uri.inferred_port, hydra,
110
+ :join => [:run, [], nil]
111
+ )
112
+ else
113
+ http = nil
114
+ end
115
+ typhoeus_request.on_complete do |response|
116
+ typhoeus_response = response
117
+ end
118
+ connection.connection.queue(typhoeus_request)
119
+ connection.join
120
+ return self.convert_response_to_a(typhoeus_response)
121
+ end
126
122
  end
127
123
  end
@@ -12,8 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'httpadapter'
16
-
17
15
  module HTTPAdapter #:nodoc:
18
16
  class Connection
19
17
  def initialize(host, port, connection, options={})
@@ -16,9 +16,9 @@
16
16
  unless defined? HTTPAdapter::VERSION
17
17
  module HTTPAdapter #:nodoc:
18
18
  module VERSION #:nodoc:
19
- MAJOR = 0
20
- MINOR = 2
21
- TINY = 1
19
+ MAJOR = 1
20
+ MINOR = 0
21
+ TINY = 0
22
22
 
23
23
  STRING = [MAJOR, MINOR, TINY].join('.')
24
24
  end
@@ -0,0 +1,170 @@
1
+ # Copyright (C) 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ shared_examples_for 'adapter type-checking example' do
16
+ before do
17
+ @request = ['GET', '/', [], ['']]
18
+ @response = [200, [], ['']]
19
+ end
20
+
21
+ describe 'when attempting to specialize a request' do
22
+ it 'should raise an error for converting from an invalid tuple' do
23
+ (lambda do
24
+ @adapter.specialize_request(42)
25
+ end).should raise_error(TypeError)
26
+ end
27
+
28
+ it 'should raise an error for converting from an invalid tuple' do
29
+ (lambda do
30
+ @adapter.specialize_request([42])
31
+ end).should raise_error(TypeError)
32
+ end
33
+
34
+ it 'should raise an error for converting from an invalid tuple' do
35
+ (lambda do
36
+ @adapter.specialize_request([42, 42, 42, 42])
37
+ end).should raise_error(TypeError)
38
+ end
39
+
40
+ it 'should raise an error for converting from an invalid tuple' do
41
+ (lambda do
42
+ @adapter.specialize_request(['GET', 42, [], ['']])
43
+ end).should raise_error(TypeError)
44
+ end
45
+
46
+ it 'should raise an error for converting from an invalid tuple' do
47
+ (lambda do
48
+ @adapter.specialize_request(['GET', '/', 42, ['']])
49
+ end).should raise_error(TypeError)
50
+ end
51
+
52
+ it 'should raise an error for converting from an invalid tuple' do
53
+ (lambda do
54
+ @adapter.specialize_request(['GET', '/', [42], ['']])
55
+ end).should raise_error(TypeError)
56
+ end
57
+
58
+ it 'should raise an error for converting from an invalid tuple' do
59
+ (lambda do
60
+ @adapter.specialize_request(['GET', '/', [[42, 'value']], ['']])
61
+ end).should raise_error(TypeError)
62
+ end
63
+
64
+ it 'should raise an error for converting from an invalid tuple' do
65
+ (lambda do
66
+ @adapter.specialize_request(['GET', '/', [['X', 42]], ['']])
67
+ end).should raise_error(TypeError)
68
+ end
69
+
70
+ it 'should raise an error for converting from an invalid tuple' do
71
+ (lambda do
72
+ @adapter.specialize_request(['GET', '/', [], 42])
73
+ end).should raise_error(TypeError)
74
+ end
75
+
76
+ it 'should raise an error for converting from an invalid tuple' do
77
+ (lambda do
78
+ # Note that the body value here should be [''], not ''.
79
+ @adapter.specialize_request(['GET', '/', [], ''])
80
+ end).should raise_error(TypeError)
81
+ end
82
+ end
83
+
84
+ describe 'when attempting to specialize a response' do
85
+ it 'should raise an error for converting from an invalid tuple' do
86
+ (lambda do
87
+ @adapter.specialize_response(42)
88
+ end).should raise_error(TypeError)
89
+ end
90
+
91
+ it 'should raise an error for converting from an invalid tuple' do
92
+ (lambda do
93
+ @adapter.specialize_response([42])
94
+ end).should raise_error(TypeError)
95
+ end
96
+
97
+ it 'should raise an error for converting from an invalid tuple' do
98
+ (lambda do
99
+ @adapter.specialize_response([42, 42, 42])
100
+ end).should raise_error(TypeError)
101
+ end
102
+
103
+ it 'should raise an error for converting from an invalid tuple' do
104
+ (lambda do
105
+ @adapter.specialize_response([Object.new, [], ['']])
106
+ end).should raise_error(TypeError)
107
+ end
108
+
109
+ it 'should raise an error for converting from an invalid tuple' do
110
+ (lambda do
111
+ @adapter.specialize_response(['', 42, ['']])
112
+ end).should raise_error(TypeError)
113
+ end
114
+
115
+ it 'should raise an error for converting from an invalid tuple' do
116
+ (lambda do
117
+ @adapter.specialize_response([200, [42], ['']])
118
+ end).should raise_error(TypeError)
119
+ end
120
+
121
+ it 'should raise an error for converting from an invalid tuple' do
122
+ (lambda do
123
+ @adapter.specialize_response([200, [[42, 'value']], ['']])
124
+ end).should raise_error(TypeError)
125
+ end
126
+
127
+ it 'should raise an error for converting from an invalid tuple' do
128
+ (lambda do
129
+ @adapter.specialize_response([200, [['X', 42]], ['']])
130
+ end).should raise_error(TypeError)
131
+ end
132
+
133
+ it 'should raise an error for converting from an invalid tuple' do
134
+ (lambda do
135
+ @adapter.specialize_response([200, [], 42])
136
+ end).should raise_error(TypeError)
137
+ end
138
+
139
+ it 'should raise an error for converting from an invalid tuple' do
140
+ (lambda do
141
+ # Note that the body value here should be [''], not ''.
142
+ @adapter.specialize_response([200, [], ''])
143
+ end).should raise_error(TypeError)
144
+ end
145
+ end
146
+
147
+ it 'should raise an error for invalid adapt request calls' do
148
+ (lambda do
149
+ @adapter.adapt_request(42)
150
+ end).should raise_error(TypeError)
151
+ end
152
+
153
+ it 'should raise an error for invalid adapt response calls' do
154
+ (lambda do
155
+ @adapter.adapt_response(42)
156
+ end).should raise_error(TypeError)
157
+ end
158
+
159
+ it 'should raise an error for invalid transmission calls' do
160
+ (lambda do
161
+ @adapter.transmit(42)
162
+ end).should raise_error(TypeError)
163
+ end
164
+
165
+ it 'should raise an error for invalid transmission calls' do
166
+ (lambda do
167
+ @adapter.transmit(@request, 42)
168
+ end).should raise_error(TypeError)
169
+ end
170
+ end
@@ -0,0 +1,81 @@
1
+ # Copyright (C) 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'spec_helper'
16
+ require 'spec/httpadapter/adapter_type_checking_spec'
17
+
18
+ require 'httpadapter/adapters/mock'
19
+
20
+ describe HTTPAdapter::MockAdapter do
21
+ describe 'with no response mocked' do
22
+ before do
23
+ @adapter = HTTPAdapter::MockAdapter.create do |request_ary, connection|
24
+ method, uri, headers, body = request_ary
25
+ headers.should be_any { |k, v| k.downcase == 'user-agent' }
26
+ end
27
+ end
28
+
29
+ it_should_behave_like 'adapter type-checking example'
30
+
31
+ describe 'when transmitting a request' do
32
+ it 'should have an expectation failure' do
33
+ (lambda do
34
+ @adapter.transmit(['GET', 'http://www.google.com/', [], ['']])
35
+ end).should raise_error(Spec::Expectations::ExpectationNotMetError)
36
+ end
37
+
38
+ it 'should meet all expectations' do
39
+ response = @adapter.transmit([
40
+ 'GET',
41
+ 'http://www.google.com/',
42
+ [['User-Agent', 'Mock Agent']],
43
+ ['']
44
+ ])
45
+ status, headers, body = response
46
+ status.should == 200
47
+ end
48
+ end
49
+ end
50
+
51
+ describe 'with a mocked response' do
52
+ before do
53
+ @adapter = HTTPAdapter::MockAdapter.create do |request_ary, connection|
54
+ method, uri, headers, body = request_ary
55
+ headers.should be_any { |k, v| k.downcase == 'user-agent' }
56
+ [400, [], ['']]
57
+ end
58
+ end
59
+
60
+ it_should_behave_like 'adapter type-checking example'
61
+
62
+ describe 'when transmitting a request' do
63
+ it 'should have an expectation failure' do
64
+ (lambda do
65
+ @adapter.transmit(['GET', 'http://www.google.com/', [], ['']])
66
+ end).should raise_error(Spec::Expectations::ExpectationNotMetError)
67
+ end
68
+
69
+ it 'should meet all expectations' do
70
+ response = @adapter.transmit([
71
+ 'GET',
72
+ 'http://www.google.com/',
73
+ [['User-Agent', 'Mock Agent']],
74
+ ['']
75
+ ])
76
+ status, headers, body = response
77
+ status.should == 400
78
+ end
79
+ end
80
+ end
81
+ end