Module: HTTPAdapter

Included in:
NetHTTPAdapter, RackAdapter, TyphoeusAdapter
Defined in:
lib/httpadapter.rb,
lib/httpadapter/version.rb,
lib/httpadapter/connection.rb,
lib/httpadapter/adapters/mock.rb,
lib/httpadapter/adapters/rack.rb,
lib/httpadapter/adapters/net_http.rb,
lib/httpadapter/adapters/typhoeus.rb

Overview

A module which provides methods to aid in conversion of HTTP request and response objects. It uses tuples as a generic intermediary format.

Examples:

class StubAdapter
  include HTTPAdapter

  def convert_request_to_a(request_obj)
    return ['GET', '/', [], [""]] # Stubbed request tuple
  end

  def convert_request_from_a(request_ary)
    return Object.new # Stubbed request object
  end

  def convert_response_to_a(response_obj)
    return [200, [], ['']] # Stubbed response tuple
  end

  def convert_response_from_a(response_ary)
    return Object.new # Stubbed response object
  end

  def fetch_resource(request_ary, connection=nil)
    return [200, [], ['']] # Stubbed response tuple from server
  end
end

Defined Under Namespace

Modules: MockAdapter, VERSION Classes: Connection, NetHTTPAdapter, RackAdapter, TyphoeusAdapter

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.verified_request(request) ⇒ Array

Verifies a request tuple matches the specification.

Parameters:

  • request (Array)

    The request object to be verified.

Returns:

  • (Array)

    The tuple, after normalization.



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/httpadapter.rb', line 166

def self.verified_request(request)
  if !request.kind_of?(Array)
    raise TypeError, "Expected Array, got #{request.class}."
  end
  if request.size == 4
    # Verify that the request object matches the specification
    method, uri, headers, body = request
    method = method.to_str if method.respond_to?(:to_str)
    # Special-casing symbols here
    method = method.to_s if method.kind_of?(Symbol)
    if !method.kind_of?(String)
      raise TypeError,
        "Expected String, got #{method.class}."
    end
    method = method.upcase
    if uri.respond_to?(:to_str)
      uri = uri.to_str
    else
      raise TypeError, "Expected String, got #{uri.class}."
    end
    original_headers, headers = headers, []
    if original_headers.respond_to?(:each)
      original_headers.each do |header, value|
        if header.respond_to?(:to_str)
          header = header.to_str
        else
          raise TypeError, "Expected String, got #{header.class}."
        end
        if value.respond_to?(:to_str)
          value = value.to_str
        else
          raise TypeError, "Expected String, got #{value.class}."
        end
        headers << [header, value]
      end
    else
      raise TypeError, 'Expected headers to respond to #each.'
    end
    if body.kind_of?(String)
      raise TypeError,
        'Body must not be a String; it must respond to #each and ' +
        'emit String values.'
    end
    # Can't verify that all chunks are Strings because #each may be
    # effectively destructive.
    if !body.respond_to?(:each)
      raise TypeError, 'Expected body to respond to #each.'
    end
  else
    raise TypeError,
      "Expected tuple of [method, uri, headers, body], " +
      "got #{request.inspect}."
  end
  return [method, uri, headers, body]
end

.verified_response(response) ⇒ Array

Verifies a response tuple matches the specification.

Parameters:

  • response (Array)

    The response object to be verified.

Returns:

  • (Array)

    The tuple, after normalization.



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/httpadapter.rb', line 229

def self.verified_response(response)
  if !response.kind_of?(Array)
    raise TypeError, "Expected Array, got #{response.class}."
  end
  if response.size == 3
    # Verify that the response object matches the specification
    status, headers, body = response
    status = status.to_i if status.respond_to?(:to_i)
    if !status.kind_of?(Integer)
      raise TypeError, "Expected Integer, got #{status.class}."
    end
    original_headers, headers = headers, []
    if original_headers.respond_to?(:each)
      original_headers.each do |header, value|
        if header.respond_to?(:to_str)
          header = header.to_str
        else
          raise TypeError, "Expected String, got #{header.class}."
        end
        if value.respond_to?(:to_str)
          value = value.to_str
        else
          raise TypeError, "Expected String, got #{value.class}."
        end
        headers << [header, value]
      end
    else
      raise TypeError, 'Expected headers to respond to #each.'
    end
    if body.kind_of?(String)
      raise TypeError,
        'Body must not be a String; it must respond to #each and ' +
        'emit String values.'
    end
    # Can't verify that all chunks are Strings because #each may be
    # effectively destructive.
    if !body.respond_to?(:each)
      raise TypeError, 'Expected body to respond to #each.'
    end
  else
    raise TypeError,
      "Expected tuple of [status, headers, body], got #{response.inspect}."
  end
  return [status, headers, body]
end

Instance Method Details

#adapt_request(request_obj) ⇒ Array

Converts an HTTP request object to a simple tuple.

Parameters:

  • request (Object)

    The request object to be converted. The adapter must implement the #convert_request_to_a method, which takes the request object as a parameter.

Returns:

  • (Array)

    The tuple that the request was converted to.



57
58
59
60
61
62
63
64
65
# File 'lib/httpadapter.rb', line 57

def adapt_request(request_obj)
  if self.respond_to?(:convert_request_to_a)
    converted_request = self.convert_request_to_a(request_obj)
  else
    raise TypeError,
      'Expected adapter to implement #convert_request_to_a.'
  end
  return HTTPAdapter.verified_request(converted_request)
end

#adapt_response(response_obj) ⇒ Array

Converts an HTTP response object to a simple tuple.

Parameters:

  • response (Object)

    The response object to be converted. The adapter must implement the #convert_response_to_a method, which takes the response object as a parameter.

Returns:

  • (Array)

    The tuple that the reponse was converted to.



99
100
101
102
103
104
105
106
107
# File 'lib/httpadapter.rb', line 99

def adapt_response(response_obj)
  if self.respond_to?(:convert_response_to_a)
    converted_response = self.convert_response_to_a(response_obj)
  else
    raise TypeError,
      'Expected adapter to implement #convert_response_to_a.'
  end
  return HTTPAdapter.verified_response(converted_response)
end

#specialize_request(request_ary) ⇒ Array

Converts a tuple to a specific HTTP implementation’s request format.

Parameters:

  • request_ary (Array)

    The request array to be converted. The request array must be a tuple with a length of 4. The first element must be the request method. The second element must be the URI. The URI may be relative. The third element contains the headers. It must respond to #each and iterate over the header names and values. The fourth element must be the body. It must respond to #each but may not be a String. It should emit String objects.

Returns:

  • (Array)

    The implementation-specific request object.



80
81
82
83
84
85
86
87
88
# File 'lib/httpadapter.rb', line 80

def specialize_request(request_ary)
  request = HTTPAdapter.verified_request(request_ary)
  if self.respond_to?(:convert_request_from_a)
    return self.convert_request_from_a(request)
  else
    raise TypeError,
      'Expected adapter to implement #convert_request_from_a.'
  end
end

#specialize_response(response_ary) ⇒ Array

Converts a tuple to a specific HTTP implementation’s response format.

Parameters:

  • response_ary (Array)

    The response object to be converted. The response object must be a tuple with a length of 3. The first element must be the HTTP status code. The second element contains the headers. It must respond to #each and iterate over the header names and values. The third element must be the body. It must respond to #each but may not be a String. It should emit String objects. This is essentially the same format that Rack uses.

Returns:

  • (Array)

    The implementation-specific response object.



123
124
125
126
127
128
129
130
131
# File 'lib/httpadapter.rb', line 123

def specialize_response(response_ary)
  response_ary = HTTPAdapter.verified_response(response_ary)
  if self.respond_to?(:convert_response_from_a)
    return self.convert_response_from_a(response_ary)
  else
    raise TypeError,
      'Expected adapter to implement #convert_response_from_a.'
  end
end

#transmit(request_ary, connection = nil) ⇒ Array

Transmits a request.

Parameters:

  • request_ary (Array)

    The request tuple that will be sent.

  • connection (HTTPAdapter::Connection) (defaults to: nil)

    An object representing a connection. This object represents an open HTTP connection that is used to make multiple HTTP requests.

Returns:

  • (Array)

    The response given by the server.

  • (Array)

    A tuple representing the response from the server.



145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/httpadapter.rb', line 145

def transmit(request_ary, connection=nil)
  request_ary = HTTPAdapter.verified_request(request_ary)
  if connection && !connection.kind_of?(HTTPAdapter::Connection)
    raise TypeError,
      "Expected HTTPAdapter::Connection, got #{connection.class}."
  end
  if self.respond_to?(:fetch_resource)
    response_ary = self.fetch_resource(request_ary, connection)
    return HTTPAdapter.verified_response(response_ary)
  else
    raise TypeError, 'Expected adapter to implement .fetch_resource.'
  end
end