diff --git a/lib/httparty.rb b/lib/httparty.rb index 3f79147..d5aee4d 100644 --- a/lib/httparty.rb +++ b/lib/httparty.rb @@ -16,12 +16,16 @@ module HTTParty base.extend ClassMethods end - module ClassMethods + class UnsupportedFormat < StandardError; end + + AllowedFormats = %w[xml json] + + module ClassMethods def base_uri(base_uri=nil) return @base_uri unless base_uri # don't want this to ever end with / base_uri = base_uri.ends_with?('/') ? base_uri.chop : base_uri - @base_uri = ensure_http(base_uri) + @base_uri = normalize_base_uri(base_uri) end def basic_auth(u, p) @@ -39,13 +43,11 @@ module HTTParty @http end - def headers - @headers ||= {} - end - - def headers=(h) + def headers(h={}) raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash) - headers.merge!(h) + @headers ||= {} + return @headers if h.blank? + @headers.merge!(h) end def get(path, options={}) @@ -64,8 +66,10 @@ module HTTParty send_request 'delete', path, options end - def format(f=nil) - @format = f.to_s + def format(f) + f = f.to_s + raise UnsupportedFormat, "Must be one of: #{AllowedFormats.join(', ')}" unless AllowedFormats.include?(f) + @format = f end private @@ -84,23 +88,24 @@ module HTTParty request.body = options[:body] unless options[:body].blank? request.initialize_http_header headers.merge(options[:headers] || {}) request.basic_auth(@auth[:username], @auth[:password]) if @auth - @response = http.start() { |conn| conn.request(request) } - parse(@response.body) + response = http.start() { |conn| conn.request(request) } + parse_response(response.body) end - def parse(body) + def parse_response(body) case @format when 'xml' Hash.from_xml(body) when 'json' ActiveSupport::JSON.decode(body) else + # just return the response if no format body end end # Makes it so uri is sure to parse stuff like google.com with the http - def ensure_http(str) + def normalize_base_uri(str) str =~ /^https?:\/\// ? str : "http#{'s' if str.include?(':443')}://#{str}" end @@ -109,14 +114,8 @@ module HTTParty # /foobar.xml => 'xml' # /foobar.json => 'json' def format_from_path(path) - return case path - when /\.xml$/ - 'xml' - when /\.json$/ - 'json' - else - nil - end + ext = File.extname(path)[1..-1] + !ext.blank? && AllowedFormats.include?(ext) ? ext : nil end end end \ No newline at end of file diff --git a/spec/hash_spec.rb b/spec/hash_spec.rb new file mode 100644 index 0000000..775b718 --- /dev/null +++ b/spec/hash_spec.rb @@ -0,0 +1,11 @@ +require File.join(File.dirname(__FILE__), 'spec_helper') + +describe HTTParty::CoreExt::HashConversions do + it "should convert hash to struct" do + {'foo' => 'bar'}.to_struct.should == OpenStruct.new(:foo => 'bar') + end + + it 'should convert nested hash to struct' do + {'foo' => {'bar' => 'baz'}}.to_struct.should == OpenStruct.new(:foo => OpenStruct.new(:bar => 'baz')) + end +end \ No newline at end of file diff --git a/spec/httparty_spec.rb b/spec/httparty_spec.rb index f8b251b..3274434 100644 --- a/spec/httparty_spec.rb +++ b/spec/httparty_spec.rb @@ -36,9 +36,75 @@ describe HTTParty do end end + it "should initialize headers to empty hash" do + Foo.headers.should == {} + end + + it "should allow updating the headers" do + init_headers = {:foo => 'bar', :baz => 'spax'} + Foo.headers init_headers + Foo.headers.should == init_headers + end + it 'should be able to set basic authentication' do Foo.basic_auth 'foobar', 'secret' Foo.instance_variable_get("@auth").should == {:username => 'foobar', :password => 'secret'} end + describe "format" do + it "should allow xml" do + Foo.format :xml + Foo.instance_variable_get("@format").should == 'xml' + end + + it "should allow json" do + Foo.format :json + Foo.instance_variable_get("@format").should == 'json' + end + + it 'should not allow funky format' do + lambda do + Foo.format :foobar + end.should raise_error(HTTParty::UnsupportedFormat) + end + end + + describe "deriving format from path" do + it "should work if there is extension and extension is an allowed format" do + %w[xml json].each do |ext| + Foo.send(:format_from_path, "/foo/bar.#{ext}").should == ext + end + end + + it "should NOT work if there is extension but extention is not allow format" do + Foo.send(:format_from_path, '/foo/bar.php').should == nil + end + + it 'should NOT work if there is no extension' do + ['', '.'].each do |ext| + Foo.send(:format_from_path, "/foo/bar#{ext}").should == nil + end + end + end + + describe 'parsing responses' do + it 'should parse xml automatically' do + xml = < + + 1234 + Foo Bar! + + +EOF + Foo.format :xml + Foo.send(:parse_response, xml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}} + end + + it 'should parse json automatically' do + json = %q[{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}] + Foo.format :json + Foo.send(:parse_response, json).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}} + end + end end \ No newline at end of file