faraday 0.6.1 → 0.7.4

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/Gemfile CHANGED
@@ -1,19 +1,29 @@
1
- source "http://rubygems.org"
1
+ source 'http://rubygems.org'
2
2
 
3
- # Bundle gems for the local environment. Make sure to
4
- # put test-only gems in this group so their generators
5
- # and rake tasks are available in development mode:
6
- group :development, :test do
7
- gem 'patron', '~> 0.4', :platforms => :ruby
8
- gem 'sinatra', '~> 1.1'
9
- gem 'typhoeus', '~> 0.2', :platforms => :ruby
10
- gem 'excon', '~> 0.5.8'
11
- gem 'em-http-request', '~> 0.3', :require => 'em-http', :platforms => :ruby
3
+ gem 'addressable', '~> 2.2.6'
4
+ gem 'multipart-post', '~> 1.1.0'
5
+ gem 'rack', ['>= 1.1.0', '<= 1.2.0']
6
+
7
+ group :development do
8
+ gem 'sinatra', '~> 1.2'
9
+ end
10
+
11
+ group :test do
12
+ gem 'em-http-request', '~> 0.3', :require => 'em-http'
12
13
  gem 'em-synchrony', '~> 0.2', :require => ['em-synchrony', 'em-synchrony/em-http'], :platforms => :ruby_19
13
- gem 'webmock'
14
+ gem 'excon', '~> 0.6'
15
+ gem 'leftright', '~> 0.9', :require => false
16
+ gem 'patron', '~> 0.4'
17
+ gem 'rake', '~> 0.8'
18
+ gem 'test-unit', '~> 2.3'
19
+ gem 'typhoeus', '~> 0.2'
20
+ gem 'webmock', '~> 1.6'
14
21
  # ActiveSupport::JSON will be used in ruby 1.8 and Yajl in 1.9; this is to test against both adapters
15
- gem 'activesupport', '~> 2.3.8', :require => nil, :platforms => [:ruby_18, :jruby]
16
- gem 'yajl-ruby', :require => 'yajl', :platforms => :ruby_19
22
+ gem 'activesupport', '~> 2.3', :require => nil, :platforms => [:ruby_18, :jruby]
23
+ gem 'yajl-ruby', '~> 0.8', :require => 'yajl', :platforms => :ruby_19
17
24
  end
18
25
 
19
- gemspec
26
+ platforms :jruby do
27
+ gem 'jruby-openssl', '~> 0.7'
28
+ gem 'ffi-ncurses', '~> 0.3'
29
+ end
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-* rick olson, zack hobson
1
+ Copyright (c) 2009 rick olson, zack hobson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
- # faraday
2
-
1
+ faraday
2
+ =======
3
3
  Modular HTTP client library using middleware heavily inspired by Rack.
4
4
 
5
5
  This mess is gonna get raw, like sushi. So, haters to the left.
6
6
 
7
- ## Usage
8
-
7
+ Usage
8
+ -----
9
9
  conn = Faraday.new(:url => 'http://sushi.com') do |builder|
10
10
  builder.use Faraday::Request::UrlEncoded # convert request params as "www-form-urlencoded"
11
11
  builder.use Faraday::Request::JSON # encode request params as json
@@ -18,23 +18,23 @@ This mess is gonna get raw, like sushi. So, haters to the left.
18
18
  builder.response :logger
19
19
  builder.adapter :net_http
20
20
  end
21
-
21
+
22
22
  ## GET ##
23
23
 
24
24
  response = conn.get '/nigiri/sake.json' # GET http://sushi.com/nigiri/sake.json
25
25
  response.body
26
26
 
27
27
  conn.get '/nigiri', 'X-Awesome' => true # custom request header
28
-
28
+
29
29
  conn.get do |req| # GET http://sushi.com/search?page=2&limit=100
30
30
  req.url '/search', :page => 2
31
31
  req.params['limit'] = 100
32
32
  end
33
-
33
+
34
34
  ## POST ##
35
-
35
+
36
36
  conn.post '/nigiri', { :name => 'Maguro' } # POST "name=maguro" to http://sushi.com/nigiri
37
-
37
+
38
38
  # post payload as JSON instead of "www-form-urlencoded" encoding:
39
39
  conn.post '/nigiri', payload, 'Content-Type' => 'application/json'
40
40
 
@@ -50,8 +50,8 @@ If you're ready to roll with just the bare minimum:
50
50
  # default stack (net/http), no extra middleware:
51
51
  response = Faraday.get 'http://sushi.com/nigiri/sake.json'
52
52
 
53
- ## Advanced middleware usage
54
-
53
+ Advanced middleware usage
54
+ -------------------------
55
55
  The order in which middleware is stacked is important. Like with Rack, the first middleware on the list wraps all others, while the last middleware is the innermost one, so that's usually the adapter.
56
56
 
57
57
  conn = Faraday.new(:url => 'http://sushi.com') do |builder|
@@ -59,7 +59,7 @@ The order in which middleware is stacked is important. Like with Rack, the first
59
59
  builder.request :multipart
60
60
  builder.request :url_encoded
61
61
  builder.request :json
62
-
62
+
63
63
  builder.adapter :net_http
64
64
  end
65
65
 
@@ -74,23 +74,23 @@ Because "UrlEncoded" is higher on the stack than JSON encoder, it will get to pr
74
74
  Examples:
75
75
 
76
76
  payload = { :name => 'Maguro' }
77
-
77
+
78
78
  # post payload as JSON instead of urlencoded:
79
79
  conn.post '/nigiri', payload, 'Content-Type' => 'application/json'
80
-
80
+
81
81
  # uploading a file:
82
82
  payload = { :profile_pic => Faraday::UploadIO.new('avatar.jpg', 'image/jpeg') }
83
-
83
+
84
84
  # "Multipart" middleware detects files and encodes with "multipart/form-data":
85
85
  conn.put '/profile', payload
86
86
 
87
- ## Writing middleware
88
-
87
+ Writing middleware
88
+ ------------------
89
89
  Middleware are classes that respond to `call()`. They wrap the request/response cycle.
90
90
 
91
91
  def call(env)
92
92
  # do something with the request
93
-
93
+
94
94
  @app.call(env).on_complete do
95
95
  # do something with the response
96
96
  end
@@ -111,8 +111,8 @@ The `env` is a hash with symbol keys that contains info about the request and, l
111
111
  :body - the response body
112
112
  :response_headers
113
113
 
114
- ## Testing
115
-
114
+ Testing
115
+ -------
116
116
  # It's possible to define stubbed request outside a test adapter block.
117
117
  stubs = Faraday::Adapter::Test::Stubs.new do |stub|
118
118
  stub.get('/tamago') { [200, {}, 'egg'] }
@@ -138,21 +138,21 @@ The `env` is a hash with symbol keys that contains info about the request and, l
138
138
  resp.body # => 'urchin'
139
139
  resp = test.get '/else' #=> raises "no such stub" error
140
140
 
141
- # If you like, you can treat your stubs as mocks by verifying that all of
141
+ # If you like, you can treat your stubs as mocks by verifying that all of
142
142
  # the stubbed calls were made. NOTE that this feature is still fairly
143
143
  # experimental: It will not verify the order or count of any stub, only that
144
144
  # it was called once during the course of the test.
145
145
  stubs.verify_stubbed_calls
146
146
 
147
- ## TODO
148
-
147
+ TODO
148
+ ----
149
149
  * support streaming requests/responses
150
150
  * better stubbing API
151
151
  * Support timeouts
152
152
  * Add curb, em-http, fast_http
153
153
 
154
- ## Note on Patches/Pull Requests
155
-
154
+ Note on Patches/Pull Requests
155
+ -----------------------------
156
156
  * Fork the project.
157
157
  * Make your feature addition or bug fix.
158
158
  * Add tests for it. This is important so I don't break it in a
@@ -161,6 +161,8 @@ The `env` is a hash with symbol keys that contains info about the request and, l
161
161
  (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
162
162
  * Send me a pull request. Bonus points for topic branches.
163
163
 
164
- ## Copyright
164
+ Copyright
165
+ ---------
166
+ Copyright (c) 2009-2011 rick, hobson. See [LICENSE][license] for details.
165
167
 
166
- Copyright (c) 2009-2011 rick, hobson. See LICENSE for details.
168
+ [license]: https://github.com/technoweenie/faraday/blob/master/LICENSE.md
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
- require 'rubygems'
2
- require 'rake'
1
+ #!/usr/bin/env rake
2
+
3
3
  require 'date'
4
4
 
5
5
  #############################################################################
@@ -52,6 +52,14 @@ Rake::TestTask.new(:test) do |test|
52
52
  test.verbose = true
53
53
  end
54
54
 
55
+ TEST_SERVER = 'http://faradaylive.heroku.com'
56
+
57
+ desc "Run tests including live tests against #{TEST_SERVER}"
58
+ task :"test:live" do
59
+ ENV['LIVE'] = TEST_SERVER
60
+ Rake::Task[:test].invoke
61
+ end
62
+
55
63
  desc "Open an irb session preloaded with this library"
56
64
  task :console do
57
65
  sh "irb -rubygems -r ./lib/#{name}.rb"
data/config.ru ADDED
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup
4
+
5
+ require File.expand_path('../test/live_server', __FILE__)
6
+ run Sinatra::Application
data/faraday.gemspec CHANGED
@@ -12,8 +12,8 @@ Gem::Specification.new do |s|
12
12
  ## If your rubyforge_project name is different, then edit it and comment out
13
13
  ## the sub! line in the Rakefile
14
14
  s.name = 'faraday'
15
- s.version = '0.6.1'
16
- s.date = '2011-04-13'
15
+ s.version = '0.7.4'
16
+ s.date = '2011-07-08'
17
17
  s.rubyforge_project = 'faraday'
18
18
 
19
19
  ## Make sure your summary is short. The description may be as long
@@ -32,10 +32,12 @@ Gem::Specification.new do |s|
32
32
  ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
33
33
  s.require_paths = %w[lib]
34
34
 
35
- s.add_development_dependency('rake', '~> 0.8')
36
- s.add_runtime_dependency('addressable', '~> 2.2.4')
37
- s.add_runtime_dependency('multipart-post', '~> 1.1.0')
38
- s.add_runtime_dependency('rack', ['>= 1.1.0', "< 2"])
35
+ s.add_development_dependency 'rake', '~> 0.9'
36
+ s.add_development_dependency 'test-unit', '~> 2.3'
37
+ s.add_development_dependency 'webmock', '~> 1.6'
38
+ s.add_runtime_dependency 'addressable', '~> 2.2.6'
39
+ s.add_runtime_dependency 'multipart-post', '~> 1.1.0'
40
+ s.add_runtime_dependency 'rack', ['>= 1.1.0', '< 2']
39
41
 
40
42
  ## Leave this section as-is. It will be automatically generated from the
41
43
  ## contents of your Git repository via the gemspec task. DO NOT REMOVE
@@ -43,9 +45,10 @@ Gem::Specification.new do |s|
43
45
  # = MANIFEST =
44
46
  s.files = %w[
45
47
  Gemfile
46
- LICENSE
48
+ LICENSE.md
47
49
  README.md
48
50
  Rakefile
51
+ config.ru
49
52
  faraday.gemspec
50
53
  lib/faraday.rb
51
54
  lib/faraday/adapter.rb
@@ -15,15 +15,15 @@ module Faraday
15
15
 
16
16
  http = net_http_class(env).new(url.host, url.inferred_port)
17
17
 
18
- if http.use_ssl = (url.scheme == 'https' && env[:ssl])
19
- ssl = env[:ssl]
18
+ if http.use_ssl = (url.scheme == 'https' && (ssl = env[:ssl]) && true)
20
19
  http.verify_mode = ssl[:verify_mode] || ssl.fetch(:verify, true) ?
21
20
  OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
22
- http.cert = ssl[:client_cert] if ssl[:client_cert]
23
- http.key = ssl[:client_key] if ssl[:client_key]
24
- http.ca_file = ssl[:ca_file] if ssl[:ca_file]
25
- http.ca_path = ssl[:ca_path] if ssl[:ca_path]
26
- http.cert_store = ssl[:cert_store] if ssl[:cert_store]
21
+ http.cert = ssl[:client_cert] if ssl[:client_cert]
22
+ http.key = ssl[:client_key] if ssl[:client_key]
23
+ http.ca_file = ssl[:ca_file] if ssl[:ca_file]
24
+ http.ca_path = ssl[:ca_path] if ssl[:ca_path]
25
+ http.cert_store = ssl[:cert_store] if ssl[:cert_store]
26
+ http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
27
27
  end
28
28
 
29
29
  http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout]
@@ -12,11 +12,8 @@ module Faraday
12
12
  session = ::Patron::Session.new
13
13
 
14
14
  response = begin
15
- if Connection::METHODS_WITH_BODIES.include? env[:method]
16
- session.send(env[:method], env[:url].to_s, env[:body].to_s, env[:request_headers])
17
- else
18
- session.send(env[:method], env[:url].to_s, env[:request_headers])
19
- end
15
+ data = Connection::METHODS_WITH_BODIES.include?(env[:method]) ? env[:body].to_s : nil
16
+ session.request(env[:method], env[:url].to_s, env[:request_headers], :data => data)
20
17
  rescue Errno::ECONNREFUSED
21
18
  raise Error::ConnectionFailed, $!
22
19
  end
@@ -25,6 +22,15 @@ module Faraday
25
22
 
26
23
  @app.call env
27
24
  end
25
+
26
+ if loaded? && defined?(::Patron::Request::VALID_ACTIONS)
27
+ # HAX: helps but doesn't work completely
28
+ # https://github.com/toland/patron/issues/34
29
+ ::Patron::Request::VALID_ACTIONS.tap do |actions|
30
+ actions << :patch unless actions.include? :patch
31
+ actions << :options unless actions.include? :options
32
+ end
33
+ end
28
34
  end
29
35
  end
30
36
  end
@@ -17,6 +17,9 @@ module Faraday
17
17
  def self.loaded?() false end
18
18
 
19
19
  class Stubs
20
+ class NotFound < StandardError
21
+ end
22
+
20
23
  def initialize
21
24
  # {:get => [Stub, Stub]}
22
25
  @stack, @consumed = {}, {}
@@ -84,9 +87,29 @@ module Faraday
84
87
  end
85
88
  end
86
89
 
87
- class Stub < Struct.new(:path, :body, :block)
88
- def matches?(request_path, request_body)
89
- request_path == path && (body.to_s.size.zero? || request_body == body)
90
+ class Stub < Struct.new(:path, :params, :body, :block)
91
+ def initialize(full, body, block)
92
+ path, query = full.split('?')
93
+ params = query ?
94
+ Rack::Utils.parse_nested_query(query) :
95
+ {}
96
+ super path, params, body, block
97
+ end
98
+
99
+ def matches?(request_uri, request_body)
100
+ request_path, request_query = request_uri.split('?')
101
+ request_params = request_query ?
102
+ Rack::Utils.parse_nested_query(request_query) :
103
+ {}
104
+ request_path == path &&
105
+ params_match?(request_params) &&
106
+ (body.to_s.size.zero? || request_body == body)
107
+ end
108
+
109
+ def params_match?(request_params)
110
+ params.keys.all? do |key|
111
+ request_params[key] == params[key]
112
+ end
90
113
  end
91
114
 
92
115
  def to_s
@@ -109,10 +132,13 @@ module Faraday
109
132
  normalized_path = Faraday::Utils.normalize_path(env[:url])
110
133
 
111
134
  if stub = stubs.match(env[:method], normalized_path, env[:body])
135
+ env[:params] = (query = env[:url].query) ?
136
+ Rack::Utils.parse_nested_query(query) :
137
+ {}
112
138
  status, headers, body = stub.block.call(env)
113
139
  save_response(env, status, body, headers)
114
140
  else
115
- raise "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}"
141
+ raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}"
116
142
  end
117
143
  @app.call(env)
118
144
  end
@@ -21,6 +21,13 @@ module Faraday
21
21
  :headers => env[:request_headers],
22
22
  :disable_ssl_peer_verification => (env[:ssl] && !env[:ssl].fetch(:verify, true))
23
23
 
24
+ if ssl = env[:ssl]
25
+ req.ssl_cert = ssl[:client_cert_file] if ssl[:client_cert_file]
26
+ req.ssl_key = ssl[:client_key_file] if ssl[:client_key_file]
27
+ req.ssl_cacert = ssl[:ca_file] if ssl[:ca_file]
28
+ req.ssl_capath = ssl[:ca_path] if ssl[:ca_path]
29
+ end
30
+
24
31
  env_req = env[:request]
25
32
  req.timeout = req.connect_timeout = (env_req[:timeout] * 1000) if env_req[:timeout]
26
33
  req.connect_timeout = (env_req[:open_timeout] * 1000) if env_req[:open_timeout]
@@ -12,6 +12,9 @@ module Faraday
12
12
  new { |builder| yield builder }
13
13
  end
14
14
 
15
+ # Error raised when trying to modify the stack after calling `lock!`
16
+ class StackLocked < RuntimeError; end
17
+
15
18
  # borrowed from ActiveSupport::Dependencies::Reference &
16
19
  # ActionDispatch::MiddlewareStack::Middleware
17
20
  class Handler
@@ -31,7 +34,9 @@ module Faraday
31
34
  def inspect() @name end
32
35
 
33
36
  def ==(other)
34
- if other.respond_to? :name
37
+ if other.is_a? Handler
38
+ self.name == other.name
39
+ elsif other.respond_to? :name
35
40
  klass == other
36
41
  else
37
42
  @name == other.to_s
@@ -55,6 +60,7 @@ module Faraday
55
60
  end
56
61
 
57
62
  def build(options = {})
63
+ raise_if_locked
58
64
  @handlers.clear unless options[:keep]
59
65
  yield self if block_given?
60
66
  end
@@ -76,7 +82,17 @@ module Faraday
76
82
  @handlers.reverse.inject(inner_app) { |app, handler| handler.build(app) }
77
83
  end
78
84
 
85
+ # Locks the middleware stack to ensure no further modifications are possible.
86
+ def lock!
87
+ @handlers.freeze
88
+ end
89
+
90
+ def locked?
91
+ @handlers.frozen?
92
+ end
93
+
79
94
  def use(klass, *args)
95
+ raise_if_locked
80
96
  block = block_given? ? Proc.new : nil
81
97
  @handlers << self.class::Handler.new(klass, *args, &block)
82
98
  end
@@ -99,6 +115,7 @@ module Faraday
99
115
  ## methods to push onto the various positions in the stack:
100
116
 
101
117
  def insert(index, *args, &block)
118
+ raise_if_locked
102
119
  index = assert_index(index)
103
120
  handler = self.class::Handler.new(*args, &block)
104
121
  @handlers.insert(index, handler)
@@ -112,17 +129,23 @@ module Faraday
112
129
  end
113
130
 
114
131
  def swap(index, *args, &block)
132
+ raise_if_locked
115
133
  index = assert_index(index)
116
134
  @handlers.delete_at(index)
117
135
  insert(index, *args, &block)
118
136
  end
119
137
 
120
138
  def delete(handler)
139
+ raise_if_locked
121
140
  @handlers.delete(handler)
122
141
  end
123
142
 
124
143
  private
125
144
 
145
+ def raise_if_locked
146
+ raise StackLocked, "can't modify middleware stack after making a request" if locked?
147
+ end
148
+
126
149
  def use_symbol(mod, key, *args)
127
150
  block = block_given? ? Proc.new : nil
128
151
  use(mod.lookup_module(key), *args, &block)
@@ -4,10 +4,10 @@ require 'base64'
4
4
 
5
5
  module Faraday
6
6
  class Connection
7
- include Addressable, Faraday::Utils
7
+ include Addressable
8
8
 
9
- METHODS = Set.new [:get, :post, :put, :delete, :head]
10
- METHODS_WITH_BODIES = Set.new [:post, :put]
9
+ METHODS = Set.new [:get, :post, :put, :delete, :head, :patch, :options]
10
+ METHODS_WITH_BODIES = Set.new [:post, :put, :patch, :options]
11
11
 
12
12
  attr_accessor :host, :port, :scheme, :params, :headers, :parallel_manager
13
13
  attr_reader :path_prefix, :builder, :options, :ssl
@@ -22,15 +22,17 @@ module Faraday
22
22
  options = url
23
23
  url = options[:url]
24
24
  end
25
- @headers = Headers.new
26
- @params = {}
25
+ @headers = Utils::Headers.new
26
+ @params = Utils::ParamsHash.new
27
27
  @options = options[:request] || {}
28
28
  @ssl = options[:ssl] || {}
29
29
  @parallel_manager = options[:parallel]
30
+
30
31
  self.url_prefix = url if url
31
32
  proxy(options[:proxy])
32
- merge_params @params, options[:params] if options[:params]
33
- merge_headers @headers, options[:headers] if options[:headers]
33
+
34
+ @params.update options[:params] if options[:params]
35
+ @headers.update options[:headers] if options[:headers]
34
36
 
35
37
  if block_given?
36
38
  @builder = Builder.create { |b| yield b }
@@ -59,6 +61,25 @@ module Faraday
59
61
  @builder.build(options, &block)
60
62
  end
61
63
 
64
+ # The "rack app" wrapped in middleware. All requests are sent here.
65
+ #
66
+ # The builder is responsible for creating the app object. After this,
67
+ # the builder gets locked to ensure no further modifications are made
68
+ # to the middleware stack.
69
+ #
70
+ # Returns an object that responds to `call` and returns a Response.
71
+ def app
72
+ @app ||= begin
73
+ builder.lock!
74
+ builder.to_app(lambda { |env|
75
+ # the inner app that creates and returns the Response object
76
+ response = Response.new
77
+ response.finish(env) unless env[:parallel_manager]
78
+ env[:response] = response
79
+ })
80
+ end
81
+ end
82
+
62
83
  def get(url = nil, headers = nil)
63
84
  block = block_given? ? Proc.new : nil
64
85
  run_request(:get, url, nil, headers, &block)
@@ -74,6 +95,11 @@ module Faraday
74
95
  run_request(:put, url, body, headers, &block)
75
96
  end
76
97
 
98
+ def patch(url = nil, body = nil, headers = nil)
99
+ block = block_given? ? Proc.new : nil
100
+ run_request(:patch, url, body, headers, &block)
101
+ end
102
+
77
103
  def head(url = nil, headers = nil)
78
104
  block = block_given? ? Proc.new : nil
79
105
  run_request(:head, url, nil, headers, &block)
@@ -145,12 +171,11 @@ module Faraday
145
171
  self.host = uri.host
146
172
  self.port = uri.port
147
173
  self.path_prefix = uri.path
148
- if uri.query && !uri.query.empty?
149
- merge_params @params, parse_query(uri.query)
150
- end
151
- if uri.user && uri.password
152
- basic_auth(uri.user, uri.password)
153
- end
174
+
175
+ @params.merge_query(uri.query)
176
+ basic_auth(uri.user, uri.password) if uri.user && uri.password
177
+
178
+ uri
154
179
  end
155
180
 
156
181
  # Ensures that the path prefix always has a leading / and no trailing /
@@ -167,12 +192,15 @@ module Faraday
167
192
  raise ArgumentError, "unknown http method: #{method}"
168
193
  end
169
194
 
170
- Request.run(self, method) do |req|
195
+ request = Request.create(method) do |req|
171
196
  req.url(url) if url
172
197
  req.headers.update(headers) if headers
173
198
  req.body = body if body
174
199
  yield req if block_given?
175
200
  end
201
+
202
+ env = request.to_env(self)
203
+ self.app.call(env)
176
204
  end
177
205
 
178
206
  # Takes a relative url for a request and combines it with the defaults
@@ -186,15 +214,21 @@ module Faraday
186
214
  # conn.build_url("nigiri?page=2") # => https://sushi.com/api/nigiri?token=abc&page=2
187
215
  # conn.build_url("nigiri", :page => 2) # => https://sushi.com/api/nigiri?token=abc&page=2
188
216
  #
189
- def build_url(url, params = nil)
217
+ def build_url(url, extra_params = nil)
190
218
  uri = URI.parse(url.to_s)
191
219
  if @path_prefix && uri.path !~ /^\//
192
- uri.path = "#{@path_prefix.size > 1 ? @path_prefix : nil}/#{uri.path}"
220
+ new_path = @path_prefix.size > 1 ? @path_prefix.dup : ''
221
+ new_path << "/#{uri.path}" unless uri.path.empty?
222
+ uri.path = new_path
193
223
  end
194
224
  uri.host ||= @host
195
225
  uri.port ||= @port
196
226
  uri.scheme ||= @scheme
197
- replace_query(uri, params)
227
+
228
+ params = @params.dup.merge_query(uri.query)
229
+ params.update extra_params if extra_params
230
+ uri.query = params.empty? ? nil : params.to_query
231
+
198
232
  uri
199
233
  end
200
234
 
@@ -202,18 +236,6 @@ module Faraday
202
236
  self.class.new(build_url(''), :headers => headers.dup, :params => params.dup, :builder => builder.dup)
203
237
  end
204
238
 
205
- def replace_query(uri, params)
206
- url_params = @params.dup
207
- if uri.query && !uri.query.empty?
208
- merge_params(url_params, parse_query(uri.query))
209
- end
210
- if params && !params.empty?
211
- merge_params(url_params, params)
212
- end
213
- uri.query = url_params.empty? ? nil : build_query(url_params)
214
- uri
215
- end
216
-
217
239
  def proxy_arg_to_uri(arg)
218
240
  case arg
219
241
  when String then URI.parse(arg)
data/lib/faraday/error.rb CHANGED
@@ -34,5 +34,7 @@ module Faraday
34
34
  class ConnectionFailed < ClientError; end
35
35
  class ResourceNotFound < ClientError; end
36
36
  class ParsingError < ClientError; end
37
+
38
+ class MissingDependency < StandardError; end
37
39
  end
38
40
  end
@@ -3,7 +3,11 @@ module Faraday
3
3
  self.mime_type = 'application/json'.freeze
4
4
 
5
5
  class << self
6
- attr_accessor :adapter
6
+ attr_writer :adapter
7
+
8
+ def adapter
9
+ @adapter or raise Error::MissingDependency, "No JSON adapter available. Install either activesupport or yajl-ruby."
10
+ end
7
11
  end
8
12
 
9
13
  # loads the JSON encoder either from yajl-ruby or activesupport