Skip to content

Commit

Permalink
Abstract out the content parsing of the response.
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Bleigh committed Jul 21, 2011
1 parent b372f8f commit 46046fa
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 9 deletions.
55 changes: 46 additions & 9 deletions lib/oauth2/response.rb
Expand Up @@ -6,6 +6,19 @@ class Response
attr_reader :response
attr_accessor :error, :options

# Adds a new content type parser.
#
# @param [Symbol] key A descriptive symbol key such as :json or :query.
# @param [Array] One or more mime types to which this parser applies.
# @yield [String] A block returning parsed content.
def self.register_parser(key, mime_types, &block)
key = key.to_sym
PARSERS[key] = block
Array(mime_types).each do |mime_type|
CONTENT_TYPES[mime_type] = key
end
end

# Initializes a Response instance
#
# @param [Faraday::Response] response The Faraday response instance
Expand All @@ -32,19 +45,43 @@ def body
response.body || ''
end

# The HTTP response body
def to_s
body
end

# Procs that, when called, will parse a response body according
# to the specified format.
PARSERS = {
:json => lambda{|body| MultiJson.decode(body) rescue body },
:query => lambda{|body| Rack::Utils.parse_query(body) },
:text => lambda{|body| body}
}

# Content type assignments for various potential HTTP content types.
CONTENT_TYPES = {
'application/json' => :json,
'application/x-www-form-urlencoded' => :query,
'text/plain' => :text
}

# The parsed response body.
# Will attempt to parse application/x-www-form-urlencoded and
# application/json Content-Type response bodies
def parsed
@parsed ||= begin
content_type = (response.headers.values_at('content-type', 'Content-Type').compact.first || '').strip

if options[:parse] == :json || (content_type.include?('application/json'))
MultiJson.decode(body) rescue body
elsif options[:parse] == :query || (content_type.include?('application/x-www-form-urlencoded'))
Rack::Utils.parse_query(body)
end
end
return nil unless PARSERS.key?(parser)
@parsed ||= PARSERS[parser].call(body)
end

# Attempts to determine the content type of the response.
def content_type
(response.headers.values_at('content-type', 'Content-Type').compact.first || '').strip
end

# Determines the parser that will be used to supply the content of #parsed
def parser
return options[:parse].to_sym if PARSERS.key?(options[:parse])
CONTENT_TYPES[content_type]
end
end
end
22 changes: 22 additions & 0 deletions spec/oauth2/response_spec.rb
Expand Up @@ -17,6 +17,28 @@
end
end

describe '.register_parser' do
let(:response) {
double('response', :headers => {'Content-Type' => 'application/foo-bar'},
:status => 200,
:body => 'baz')
}
before do
OAuth2::Response.register_parser(:foobar, 'application/foo-bar') do |body|
"foobar #{body}"
end
end

it 'should add to the content types and parsers' do
OAuth2::Response::PARSERS.keys.should be_include(:foobar)
OAuth2::Response::CONTENT_TYPES.keys.should be_include('application/foo-bar')
end

it 'should be able to parse that content type automatically' do
OAuth2::Response.new(response).parsed.should == 'foobar baz'
end
end

describe '#parsed' do
it "parses application/x-www-form-urlencoded body" do
headers = {'Content-Type' => 'application/x-www-form-urlencoded'}
Expand Down

0 comments on commit 46046fa

Please sign in to comment.