faraday 1.0.1 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d23ec0aefc40d23ccc4410db08092bd29e477309fb8aa6794b3c8401961de10
4
- data.tar.gz: c33ca7313dcccbf148266a80aa4e12d4cba96a4feb96ecfc3e8ff50fa06756c5
3
+ metadata.gz: 47236f354f9fda55254c8bd2b9e3552de12e8894fcecea0035ffbeb3ccc46b9c
4
+ data.tar.gz: f6eb36d3da02314fe799368c1ff4c17c5841f0badd18c5a89772e00bae43065c
5
5
  SHA512:
6
- metadata.gz: 8058c22dc6e78bc3d46a9c8a22c458656a1380a4aed62b31e11b9b054fc6791373dd103276fc018148daed3934a724bcb39390bbe88e2762281ff810b61b408d
7
- data.tar.gz: 341f3b44148f666bb03f8e7b232fd92e26b8c34d758090e6e82f1276af29ff17d4f62bdb58871254ba48b2232ab58269c71db08df7a4b0c35c53f2c7e9bbe7e8
6
+ metadata.gz: 300153861873b2a5b3a3a9f552c47a2b70dd083ffd5478d8eca2c4c2005e5a74d09d962b51fb9a780ea90bb1ac87bdfa902639e86b2147d5b4d4374791789bd1
7
+ data.tar.gz: 3628d85508cdd669111ae6175b6b5a191380d0d405f345612f6342e487aec0f3cc9d2e1726a2cdde7d82ee86fae82aa41f4a62ea330343598383ae3f644b5a85
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-2019 Rick Olson, Zack Hobson
1
+ Copyright (c) 2009-2020 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,8 +1,7 @@
1
1
  # [![Faraday](./docs/assets/img/repo-card-slim.png)][website]
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/faraday.svg)](https://rubygems.org/gems/faraday)
4
- ![GitHub Actions CI](https://github.com/lostisland/faraday/workflows/CI/badge.svg)
5
- [![Test Coverage](https://api.codeclimate.com/v1/badges/f869daab091ceef1da73/test_coverage)](https://codeclimate.com/github/lostisland/faraday/test_coverage)
4
+ [![GitHub Actions CI](https://github.com/lostisland/faraday/workflows/CI/badge.svg)](https://github.com/lostisland/faraday/actions?query=workflow%3ACI)
6
5
  [![Maintainability](https://api.codeclimate.com/v1/badges/f869daab091ceef1da73/maintainability)](https://codeclimate.com/github/lostisland/faraday/maintainability)
7
6
  [![Gitter](https://badges.gitter.im/lostisland/faraday.svg)](https://gitter.im/lostisland/faraday?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
8
7
 
@@ -43,7 +42,7 @@ Open the issues page and check for the `help wanted` label!
43
42
  But before you start coding, please read our [Contributing Guide][contributing]
44
43
 
45
44
  ## Copyright
46
- © 2009 - 2019, the [Faraday Team][faraday_team]. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
45
+ © 2009 - 2020, the [Faraday Team][faraday_team]. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
47
46
 
48
47
  [website]: https://lostisland.github.io/faraday
49
48
  [faraday_team]: https://lostisland.github.io/faraday/team
@@ -19,7 +19,7 @@ class Client
19
19
  end
20
20
  end
21
21
 
22
- Rspec.describe Client do
22
+ RSpec.describe Client do
23
23
  let(:stubs) { Faraday::Adapter::Test::Stubs.new }
24
24
  let(:conn) { Faraday.new { |b| b.adapter(:test, stubs) } }
25
25
  let(:client) { Client.new(conn) }
@@ -19,7 +19,7 @@ require 'faraday/dependency_loader'
19
19
  # conn.get '/'
20
20
  #
21
21
  module Faraday
22
- VERSION = '1.0.1'
22
+ VERSION = '1.1.0'
23
23
  METHODS_WITH_QUERY = %w[get head delete trace].freeze
24
24
  METHODS_WITH_BODY = %w[post put patch].freeze
25
25
 
@@ -27,6 +27,7 @@ module Faraday
27
27
  # This module marks an Adapter as supporting parallel requests.
28
28
  module Parallelism
29
29
  attr_writer :supports_parallel
30
+
30
31
  def supports_parallel?
31
32
  @supports_parallel
32
33
  end
@@ -231,7 +231,7 @@ module Faraday
231
231
 
232
232
  def add(&block)
233
233
  if running?
234
- perform_request { yield }
234
+ perform_request(&block)
235
235
  else
236
236
  @registered_procs << block
237
237
  end
@@ -34,9 +34,9 @@ module Faraday
34
34
 
35
35
  @app.call(env)
36
36
  rescue ::Excon::Errors::SocketError => e
37
- raise Faraday::TimeoutError, e if e.message =~ /\btimeout\b/
37
+ raise Faraday::TimeoutError, e if e.message.match?(/\btimeout\b/)
38
38
 
39
- raise Faraday::SSLError, e if e.message =~ /\bcertificate\b/
39
+ raise Faraday::SSLError, e if e.message.match?(/\bcertificate\b/)
40
40
 
41
41
  raise Faraday::ConnectionFailed, e
42
42
  rescue ::Excon::Errors::Timeout => e
@@ -23,7 +23,7 @@ module Faraday
23
23
  #
24
24
  # @return [void]
25
25
  def autoload_all(prefix, options)
26
- if prefix =~ %r{^faraday(/|$)}i
26
+ if prefix.match? %r{^faraday(/|$)}i
27
27
  prefix = File.join(Faraday.root_path, prefix)
28
28
  end
29
29
 
@@ -429,7 +429,7 @@ module Faraday
429
429
  # @return [String] the new path prefix
430
430
  def path_prefix=(value)
431
431
  url_prefix.path = if value
432
- value = '/' + value unless value[0, 1] == '/'
432
+ value = "/#{value}" unless value[0, 1] == '/'
433
433
  value
434
434
  end
435
435
  end
@@ -520,7 +520,7 @@ module Faraday
520
520
  base = url_prefix
521
521
  if url && base.path && base.path !~ %r{/$}
522
522
  base = base.dup
523
- base.path = base.path + '/' # ensure trailing slash
523
+ base.path = "#{base.path}/" # ensure trailing slash
524
524
  end
525
525
  uri = url ? base + url : base
526
526
  if params
@@ -593,7 +593,7 @@ module Faraday
593
593
  uri = ENV['http_proxy']
594
594
  return unless uri && !uri.empty?
595
595
 
596
- uri = 'http://' + uri if uri !~ /^http/i
596
+ uri = "http://#{uri}" unless uri.match?(/^http/i)
597
597
  uri
598
598
  end
599
599
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ruby2_keywords'
4
+
3
5
  module Faraday
4
6
  # DependencyLoader helps Faraday adapters and middleware load dependencies.
5
7
  module DependencyLoader
@@ -13,7 +15,7 @@ module Faraday
13
15
  self.load_error = e
14
16
  end
15
17
 
16
- def new(*)
18
+ ruby2_keywords def new(*)
17
19
  unless loaded?
18
20
  raise "missing dependency for #{self}: #{load_error.message}"
19
21
  end
@@ -33,9 +33,9 @@ module Faraday
33
33
  key = key.to_s if key.is_a?(Symbol)
34
34
  [key, value]
35
35
  end
36
- # Useful default for OAuth and caching.
36
+
37
37
  # Only to be used for non-Array inputs. Arrays should preserve order.
38
- params.sort!
38
+ params.sort! if @sort_params
39
39
  end
40
40
 
41
41
  # The params have form [['key1', 'value1'], ['key2', 'value2']].
@@ -94,5 +94,12 @@ module Faraday
94
94
  end
95
95
  end
96
96
  end
97
+
98
+ class << self
99
+ attr_accessor :sort_params
100
+ end
101
+
102
+ # Useful default for OAuth and caching.
103
+ @sort_params = true
97
104
  end
98
105
  end
@@ -21,9 +21,9 @@ module Faraday
21
21
  key = key.to_s if key.is_a?(Symbol)
22
22
  [key, value]
23
23
  end
24
- # Useful default for OAuth and caching.
24
+
25
25
  # Only to be used for non-Array inputs. Arrays should preserve order.
26
- params.sort!
26
+ params.sort! if @sort_params
27
27
  end
28
28
 
29
29
  # The params have form [['key1', 'value1'], ['key2', 'value2']].
@@ -161,10 +161,15 @@ module Faraday
161
161
  # for your requests.
162
162
  module NestedParamsEncoder
163
163
  class << self
164
+ attr_accessor :sort_params
165
+
164
166
  extend Forwardable
165
167
  def_delegators :'Faraday::Utils', :escape, :unescape
166
168
  end
167
169
 
170
+ # Useful default for OAuth and caching.
171
+ @sort_params = true
172
+
168
173
  extend EncodeMethods
169
174
  extend DecodeMethods
170
175
  end
@@ -38,6 +38,14 @@ module Faraday
38
38
  # :headers - String key/value hash of HTTP response header
39
39
  # values.
40
40
  # :body - Optional string HTTP response body.
41
+ # :request - Hash
42
+ # :method - Symbol with the request HTTP method.
43
+ # :url_path - String with the url path requested.
44
+ # :params - String key/value hash of query params
45
+ # present in the request.
46
+ # :headers - String key/value hash of HTTP request
47
+ # header values.
48
+ # :body - String HTTP request body.
41
49
  #
42
50
  # If a subclass has to call this, then it should pass a string message
43
51
  # to `super`. See NilStatusError.
@@ -103,12 +103,10 @@ module Faraday
103
103
  end
104
104
 
105
105
  # Public
106
- def each_key
106
+ def each_key(&block)
107
107
  return to_enum(:each_key) unless block_given?
108
108
 
109
- keys.each do |key|
110
- yield(key)
111
- end
109
+ keys.each(&block)
112
110
  end
113
111
 
114
112
  # Public
@@ -119,12 +117,10 @@ module Faraday
119
117
  alias has_key? key?
120
118
 
121
119
  # Public
122
- def each_value
120
+ def each_value(&block)
123
121
  return to_enum(:each_value) unless block_given?
124
122
 
125
- values.each do |value|
126
- yield(value)
127
- end
123
+ values.each(&block)
128
124
  end
129
125
 
130
126
  # Public
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ruby2_keywords'
3
4
  require 'faraday/adapter_registry'
4
5
 
5
6
  module Faraday
@@ -27,7 +28,7 @@ module Faraday
27
28
 
28
29
  attr_reader :name
29
30
 
30
- def initialize(klass, *args, &block)
31
+ ruby2_keywords def initialize(klass, *args, &block)
31
32
  @name = klass.to_s
32
33
  REGISTRY.set(klass) if klass.respond_to?(:name)
33
34
  @args = args
@@ -89,7 +90,7 @@ module Faraday
89
90
  @handlers.frozen?
90
91
  end
91
92
 
92
- def use(klass, *args, &block)
93
+ ruby2_keywords def use(klass, *args, &block)
93
94
  if klass.is_a? Symbol
94
95
  use_symbol(Faraday::Middleware, klass, *args, &block)
95
96
  else
@@ -99,15 +100,15 @@ module Faraday
99
100
  end
100
101
  end
101
102
 
102
- def request(key, *args, &block)
103
+ ruby2_keywords def request(key, *args, &block)
103
104
  use_symbol(Faraday::Request, key, *args, &block)
104
105
  end
105
106
 
106
- def response(key, *args, &block)
107
+ ruby2_keywords def response(key, *args, &block)
107
108
  use_symbol(Faraday::Response, key, *args, &block)
108
109
  end
109
110
 
110
- def adapter(klass = NO_ARGUMENT, *args, &block)
111
+ ruby2_keywords def adapter(klass = NO_ARGUMENT, *args, &block)
111
112
  return @adapter if klass == NO_ARGUMENT
112
113
 
113
114
  klass = Faraday::Adapter.lookup_middleware(klass) if klass.is_a?(Symbol)
@@ -116,7 +117,7 @@ module Faraday
116
117
 
117
118
  ## methods to push onto the various positions in the stack:
118
119
 
119
- def insert(index, *args, &block)
120
+ ruby2_keywords def insert(index, *args, &block)
120
121
  raise_if_locked
121
122
  index = assert_index(index)
122
123
  handler = self.class::Handler.new(*args, &block)
@@ -125,12 +126,12 @@ module Faraday
125
126
 
126
127
  alias insert_before insert
127
128
 
128
- def insert_after(index, *args, &block)
129
+ ruby2_keywords def insert_after(index, *args, &block)
129
130
  index = assert_index(index)
130
131
  insert(index + 1, *args, &block)
131
132
  end
132
133
 
133
- def swap(index, *args, &block)
134
+ ruby2_keywords def swap(index, *args, &block)
134
135
  raise_if_locked
135
136
  index = assert_index(index)
136
137
  @handlers.delete_at(index)
@@ -186,7 +187,7 @@ module Faraday
186
187
  end
187
188
 
188
189
  # ENV Keys
189
- # :method - a symbolized request method (:get, :post)
190
+ # :http_method - a symbolized request HTTP method (:get, :post)
190
191
  # :body - the request body that will eventually be converted to a string.
191
192
  # :url - URI instance for the current request.
192
193
  # :status - HTTP response status code
@@ -207,7 +208,7 @@ module Faraday
207
208
  request.options.params_encoder
208
209
  )
209
210
 
210
- Env.new(request.method, request.body, exclusive_url,
211
+ Env.new(request.http_method, request.body, exclusive_url,
211
212
  request.options, request.headers, connection.ssl,
212
213
  connection.parallel_manager)
213
214
  end
@@ -231,10 +232,10 @@ module Faraday
231
232
  end
232
233
 
233
234
  def is_adapter?(klass) # rubocop:disable Naming/PredicateName
234
- klass.ancestors.include?(Faraday::Adapter)
235
+ klass <= Faraday::Adapter
235
236
  end
236
237
 
237
- def use_symbol(mod, key, *args, &block)
238
+ ruby2_keywords def use_symbol(mod, key, *args, &block)
238
239
  use(mod.lookup_middleware(key), *args, &block)
239
240
  end
240
241
 
@@ -12,7 +12,7 @@ module Faraday
12
12
  # req.body = 'abc'
13
13
  # end
14
14
  #
15
- # @!attribute method
15
+ # @!attribute http_method
16
16
  # @return [Symbol] the HTTP method of the Request
17
17
  # @!attribute path
18
18
  # @return [URI, String] the path
@@ -26,7 +26,9 @@ module Faraday
26
26
  # @return [RequestOptions] options
27
27
  #
28
28
  # rubocop:disable Style/StructInheritance
29
- class Request < Struct.new(:method, :path, :params, :headers, :body, :options)
29
+ class Request < Struct.new(
30
+ :http_method, :path, :params, :headers, :body, :options
31
+ )
30
32
  # rubocop:enable Style/StructInheritance
31
33
 
32
34
  extend MiddlewareRegistry
@@ -56,6 +58,14 @@ module Faraday
56
58
  end
57
59
  end
58
60
 
61
+ def method
62
+ warn <<~TEXT
63
+ WARNING: `Faraday::Request##{__method__}` is deprecated; use `#http_method` instead. It will be removed in or after version 2.0.
64
+ `Faraday::Request##{__method__}` called from #{caller_locations(1..1).first}
65
+ TEXT
66
+ http_method
67
+ end
68
+
59
69
  # Replace params, preserving the existing hash type.
60
70
  #
61
71
  # @param hash [Hash] new params
@@ -116,7 +126,7 @@ module Faraday
116
126
  # @return [Hash] the hash ready to be serialized in Marshal.
117
127
  def marshal_dump
118
128
  {
119
- method: method,
129
+ http_method: http_method,
120
130
  body: body,
121
131
  headers: headers,
122
132
  path: path,
@@ -129,17 +139,17 @@ module Faraday
129
139
  # Restores the instance variables according to the +serialised+.
130
140
  # @param serialised [Hash] the serialised object.
131
141
  def marshal_load(serialised)
132
- self.method = serialised[:method]
133
- self.body = serialised[:body]
134
- self.headers = serialised[:headers]
135
- self.path = serialised[:path]
136
- self.params = serialised[:params]
137
- self.options = serialised[:options]
142
+ self.http_method = serialised[:http_method]
143
+ self.body = serialised[:body]
144
+ self.headers = serialised[:headers]
145
+ self.path = serialised[:path]
146
+ self.params = serialised[:params]
147
+ self.options = serialised[:options]
138
148
  end
139
149
 
140
150
  # @return [Env] the Env for this Request
141
151
  def to_env(connection)
142
- Env.new(method, body, connection.build_exclusive_url(path, params),
152
+ Env.new(http_method, body, connection.build_exclusive_url(path, params),
143
153
  options, headers, connection.ssl, connection.parallel_manager)
144
154
  end
145
155
  end
@@ -12,6 +12,11 @@ module Faraday
12
12
  DEFAULT_BOUNDARY_PREFIX = '-----------RubyMultipartPost'
13
13
  end
14
14
 
15
+ def initialize(app = nil, options = {})
16
+ super(app)
17
+ @options = options
18
+ end
19
+
15
20
  # Checks for files in the payload, otherwise leaves everything untouched.
16
21
  #
17
22
  # @param env [Faraday::Env]
@@ -30,7 +35,7 @@ module Faraday
30
35
  type = request_type(env)
31
36
  env.body.respond_to?(:each_key) && !env.body.empty? && (
32
37
  (type.empty? && has_multipart?(env.body)) ||
33
- (type == self.class.mime_type)
38
+ (type == self.class.mime_type)
34
39
  )
35
40
  end
36
41
 
@@ -79,7 +84,9 @@ module Faraday
79
84
  # @param pieces [Array]
80
85
  def process_params(params, prefix = nil, pieces = nil, &block)
81
86
  params.inject(pieces || []) do |all, (key, value)|
82
- key = "#{prefix}[#{key}]" if prefix
87
+ if prefix
88
+ key = @options[:flat_encode] ? prefix.to_s : "#{prefix}[#{key}]"
89
+ end
83
90
 
84
91
  case value
85
92
  when Array
@@ -38,7 +38,18 @@ module Faraday
38
38
  end
39
39
 
40
40
  def response_values(env)
41
- { status: env.status, headers: env.response_headers, body: env.body }
41
+ {
42
+ status: env.status,
43
+ headers: env.response_headers,
44
+ body: env.body,
45
+ request: {
46
+ method: env.method,
47
+ url_path: env.url.path,
48
+ params: env.params,
49
+ headers: env.request_headers,
50
+ body: env.request_body
51
+ }
52
+ }
42
53
  end
43
54
  end
44
55
  end
@@ -28,7 +28,7 @@ module Faraday
28
28
 
29
29
  def escape(str)
30
30
  str.to_s.gsub(ESCAPE_RE) do |match|
31
- '%' + match.unpack('H2' * match.bytesize).join('%').upcase
31
+ "%#{match.unpack('H2' * match.bytesize).join('%').upcase}"
32
32
  end.gsub(' ', default_space_encoding)
33
33
  end
34
34
 
@@ -89,7 +89,7 @@ module Faraday
89
89
  # the path with the query string sorted.
90
90
  def normalize_path(url)
91
91
  url = URI(url)
92
- (url.path.start_with?('/') ? url.path : '/' + url.path) +
92
+ (url.path.start_with?('/') ? url.path : "/#{url.path}") +
93
93
  (url.query ? "?#{sort_query_params(url.query)}" : '')
94
94
  end
95
95
 
@@ -105,7 +105,7 @@ module Faraday
105
105
  end
106
106
 
107
107
  def to_hash
108
- ::Hash.new.update(self)
108
+ {}.update(self)
109
109
  end
110
110
 
111
111
  def parse(header_string)
@@ -114,7 +114,7 @@ module Faraday
114
114
  headers = header_string.split(/\r\n/)
115
115
 
116
116
  # Find the last set of response headers.
117
- start_index = headers.rindex { |x| x.match(%r{^HTTP/}) } || 0
117
+ start_index = headers.rindex { |x| x.start_with?('HTTP/') } || 0
118
118
  last_response = headers.slice(start_index, headers.size)
119
119
 
120
120
  last_response
@@ -0,0 +1,260 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Adapter::Test do
4
+ let(:stubs) do
5
+ described_class::Stubs.new do |stub|
6
+ stub.get('http://domain.test/hello') do
7
+ [200, { 'Content-Type' => 'text/html' }, 'domain: hello']
8
+ end
9
+
10
+ stub.get('http://wrong.test/hello') do
11
+ [200, { 'Content-Type' => 'text/html' }, 'wrong: hello']
12
+ end
13
+
14
+ stub.get('http://wrong.test/bait') do
15
+ [404, { 'Content-Type' => 'text/html' }]
16
+ end
17
+
18
+ stub.get('/hello') do
19
+ [200, { 'Content-Type' => 'text/html' }, 'hello']
20
+ end
21
+
22
+ stub.get('/method-echo') do |env|
23
+ [200, { 'Content-Type' => 'text/html' }, env[:method].to_s]
24
+ end
25
+
26
+ stub.get(%r{\A/resources/\d+(?:\?|\z)}) do
27
+ [200, { 'Content-Type' => 'text/html' }, 'show']
28
+ end
29
+
30
+ stub.get(%r{\A/resources/(specified)\z}) do |_env, meta|
31
+ [200, { 'Content-Type' => 'text/html' }, "show #{meta[:match_data][1]}"]
32
+ end
33
+ end
34
+ end
35
+
36
+ let(:connection) do
37
+ Faraday.new do |builder|
38
+ builder.adapter :test, stubs
39
+ end
40
+ end
41
+
42
+ let(:response) { connection.get('/hello') }
43
+
44
+ context 'with simple path sets status' do
45
+ subject { response.status }
46
+
47
+ it { is_expected.to eq 200 }
48
+ end
49
+
50
+ context 'with simple path sets headers' do
51
+ subject { response.headers['Content-Type'] }
52
+
53
+ it { is_expected.to eq 'text/html' }
54
+ end
55
+
56
+ context 'with simple path sets body' do
57
+ subject { response.body }
58
+
59
+ it { is_expected.to eq 'hello' }
60
+ end
61
+
62
+ context 'with host points to the right stub' do
63
+ subject { connection.get('http://domain.test/hello').body }
64
+
65
+ it { is_expected.to eq 'domain: hello' }
66
+ end
67
+
68
+ describe 'can be called several times' do
69
+ subject { connection.get('/hello').body }
70
+
71
+ it { is_expected.to eq 'hello' }
72
+ end
73
+
74
+ describe 'can handle regular expression path' do
75
+ subject { connection.get('/resources/1').body }
76
+
77
+ it { is_expected.to eq 'show' }
78
+ end
79
+
80
+ describe 'can handle single parameter block' do
81
+ subject { connection.get('/method-echo').body }
82
+
83
+ it { is_expected.to eq 'get' }
84
+ end
85
+
86
+ describe 'can handle regular expression path with captured result' do
87
+ subject { connection.get('/resources/specified').body }
88
+
89
+ it { is_expected.to eq 'show specified' }
90
+ end
91
+
92
+ context 'with get params' do
93
+ subject { connection.get('/param?a=1').body }
94
+
95
+ before do
96
+ stubs.get('/param?a=1') { [200, {}, 'a'] }
97
+ end
98
+
99
+ it { is_expected.to eq 'a' }
100
+ end
101
+
102
+ describe 'ignoring unspecified get params' do
103
+ before do
104
+ stubs.get('/optional?a=1') { [200, {}, 'a'] }
105
+ end
106
+
107
+ context 'with multiple params' do
108
+ subject { connection.get('/optional?a=1&b=1').body }
109
+
110
+ it { is_expected.to eq 'a' }
111
+ end
112
+
113
+ context 'with single param' do
114
+ subject { connection.get('/optional?a=1').body }
115
+
116
+ it { is_expected.to eq 'a' }
117
+ end
118
+
119
+ context 'without params' do
120
+ subject(:request) { connection.get('/optional') }
121
+
122
+ it do
123
+ expect { request }.to raise_error(
124
+ Faraday::Adapter::Test::Stubs::NotFound
125
+ )
126
+ end
127
+ end
128
+ end
129
+
130
+ context 'with http headers' do
131
+ before do
132
+ stubs.get('/yo', 'X-HELLO' => 'hello') { [200, {}, 'a'] }
133
+ stubs.get('/yo') { [200, {}, 'b'] }
134
+ end
135
+
136
+ context 'with header' do
137
+ subject do
138
+ connection.get('/yo') { |env| env.headers['X-HELLO'] = 'hello' }.body
139
+ end
140
+
141
+ it { is_expected.to eq 'a' }
142
+ end
143
+
144
+ context 'without header' do
145
+ subject do
146
+ connection.get('/yo').body
147
+ end
148
+
149
+ it { is_expected.to eq 'b' }
150
+ end
151
+ end
152
+
153
+ describe 'different outcomes for the same request' do
154
+ def make_request
155
+ connection.get('/foo')
156
+ end
157
+
158
+ subject(:request) { make_request.body }
159
+
160
+ before do
161
+ stubs.get('/foo') { [200, { 'Content-Type' => 'text/html' }, 'hello'] }
162
+ stubs.get('/foo') { [200, { 'Content-Type' => 'text/html' }, 'world'] }
163
+ end
164
+
165
+ context 'the first request' do
166
+ it { is_expected.to eq 'hello' }
167
+ end
168
+
169
+ context 'the second request' do
170
+ before do
171
+ make_request
172
+ end
173
+
174
+ it { is_expected.to eq 'world' }
175
+ end
176
+ end
177
+
178
+ describe 'yielding env to stubs' do
179
+ subject { connection.get('http://foo.com/foo?a=1').body }
180
+
181
+ before do
182
+ stubs.get '/foo' do |env|
183
+ expect(env[:url].path).to eq '/foo'
184
+ expect(env[:url].host).to eq 'foo.com'
185
+ expect(env[:params]['a']).to eq '1'
186
+ expect(env[:request_headers]['Accept']).to eq 'text/plain'
187
+ [200, {}, 'a']
188
+ end
189
+
190
+ connection.headers['Accept'] = 'text/plain'
191
+ end
192
+
193
+ it { is_expected.to eq 'a' }
194
+ end
195
+
196
+ describe 'params parsing' do
197
+ subject { connection.get('http://foo.com/foo?a[b]=1').body }
198
+
199
+ context 'with default encoder' do
200
+ before do
201
+ stubs.get '/foo' do |env|
202
+ expect(env[:params]['a']['b']).to eq '1'
203
+ [200, {}, 'a']
204
+ end
205
+ end
206
+
207
+ it { is_expected.to eq 'a' }
208
+ end
209
+
210
+ context 'with nested encoder' do
211
+ before do
212
+ stubs.get '/foo' do |env|
213
+ expect(env[:params]['a']['b']).to eq '1'
214
+ [200, {}, 'a']
215
+ end
216
+
217
+ connection.options.params_encoder = Faraday::NestedParamsEncoder
218
+ end
219
+
220
+ it { is_expected.to eq 'a' }
221
+ end
222
+
223
+ context 'with flat encoder' do
224
+ before do
225
+ stubs.get '/foo' do |env|
226
+ expect(env[:params]['a[b]']).to eq '1'
227
+ [200, {}, 'a']
228
+ end
229
+
230
+ connection.options.params_encoder = Faraday::FlatParamsEncoder
231
+ end
232
+
233
+ it { is_expected.to eq 'a' }
234
+ end
235
+ end
236
+
237
+ describe 'raising an error if no stub was found' do
238
+ describe 'for request' do
239
+ subject(:request) { connection.get('/invalid') { [200, {}, []] } }
240
+
241
+ it { expect { request }.to raise_error described_class::Stubs::NotFound }
242
+ end
243
+
244
+ describe 'for specified host' do
245
+ subject(:request) { connection.get('http://domain.test/bait') }
246
+
247
+ it { expect { request }.to raise_error described_class::Stubs::NotFound }
248
+ end
249
+
250
+ describe 'for request without specified header' do
251
+ subject(:request) { connection.get('/yo') }
252
+
253
+ before do
254
+ stubs.get('/yo', 'X-HELLO' => 'hello') { [200, {}, 'a'] }
255
+ end
256
+
257
+ it { expect { request }.to raise_error described_class::Stubs::NotFound }
258
+ end
259
+ end
260
+ end
@@ -31,4 +31,12 @@ RSpec.describe Faraday::FlatParamsEncoder do
31
31
  params = { a: [] }
32
32
  expect(subject.encode(params)).to eq('a=')
33
33
  end
34
+
35
+ it 'encodes unsorted when asked' do
36
+ params = { b: false, a: true }
37
+ expect(subject.encode(params)).to eq('a=true&b=false')
38
+ Faraday::FlatParamsEncoder.sort_params = false
39
+ expect(subject.encode(params)).to eq('b=false&a=true')
40
+ Faraday::FlatParamsEncoder.sort_params = true
41
+ end
34
42
  end
@@ -94,6 +94,14 @@ RSpec.describe Faraday::NestedParamsEncoder do
94
94
  expect(subject.encode(params)).to eq('a%5B%5D=true&a%5B%5D=false')
95
95
  end
96
96
 
97
+ it 'encodes unsorted when asked' do
98
+ params = { b: false, a: true }
99
+ expect(subject.encode(params)).to eq('a=true&b=false')
100
+ Faraday::NestedParamsEncoder.sort_params = false
101
+ expect(subject.encode(params)).to eq('b=false&a=true')
102
+ Faraday::NestedParamsEncoder.sort_params = true
103
+ end
104
+
97
105
  shared_examples 'a wrong decoding' do
98
106
  it do
99
107
  expect { subject.decode(query) }.to raise_error(TypeError) do |e|
@@ -193,4 +193,153 @@ RSpec.describe Faraday::RackBuilder do
193
193
  end
194
194
  end
195
195
  end
196
+
197
+ context 'when middleware is added with named arguments' do
198
+ let(:conn) { Faraday::Connection.new {} }
199
+
200
+ let(:dog_middleware) do
201
+ Class.new(Faraday::Middleware) do
202
+ attr_accessor :name
203
+
204
+ def initialize(app, name:)
205
+ super(app)
206
+ @name = name
207
+ end
208
+ end
209
+ end
210
+ let(:dog) do
211
+ subject.handlers.find { |handler| handler == dog_middleware }.build
212
+ end
213
+
214
+ it 'adds a handler to construct middleware with options passed to use' do
215
+ subject.use dog_middleware, name: 'Rex'
216
+ expect { dog }.to_not output(
217
+ /warning: Using the last argument as keyword parameters is deprecated/
218
+ ).to_stderr
219
+ expect(dog.name).to eq('Rex')
220
+ end
221
+ end
222
+
223
+ context 'when a request adapter is added with named arguments' do
224
+ let(:conn) { Faraday::Connection.new {} }
225
+
226
+ let(:cat_request) do
227
+ Class.new(Faraday::Middleware) do
228
+ attr_accessor :name
229
+
230
+ def initialize(app, name:)
231
+ super(app)
232
+ @name = name
233
+ end
234
+ end
235
+ end
236
+ let(:cat) do
237
+ subject.handlers.find { |handler| handler == cat_request }.build
238
+ end
239
+
240
+ it 'adds a handler to construct request adapter with options passed to request' do
241
+ Faraday::Request.register_middleware cat_request: cat_request
242
+ subject.request :cat_request, name: 'Felix'
243
+ expect { cat }.to_not output(
244
+ /warning: Using the last argument as keyword parameters is deprecated/
245
+ ).to_stderr
246
+ expect(cat.name).to eq('Felix')
247
+ end
248
+ end
249
+
250
+ context 'when a response adapter is added with named arguments' do
251
+ let(:conn) { Faraday::Connection.new {} }
252
+
253
+ let(:fish_response) do
254
+ Class.new(Faraday::Response::Middleware) do
255
+ attr_accessor :name
256
+
257
+ def initialize(app, name:)
258
+ super(app)
259
+ @name = name
260
+ end
261
+ end
262
+ end
263
+ let(:fish) do
264
+ subject.handlers.find { |handler| handler == fish_response }.build
265
+ end
266
+
267
+ it 'adds a handler to construct response adapter with options passed to response' do
268
+ Faraday::Response.register_middleware fish_response: fish_response
269
+ subject.response :fish_response, name: 'Bubbles'
270
+ expect { fish }.to_not output(
271
+ /warning: Using the last argument as keyword parameters is deprecated/
272
+ ).to_stderr
273
+ expect(fish.name).to eq('Bubbles')
274
+ end
275
+ end
276
+
277
+ context 'when a plain adapter is added with named arguments' do
278
+ let(:conn) { Faraday::Connection.new {} }
279
+
280
+ let(:rabbit_adapter) do
281
+ Class.new(Faraday::Adapter) do
282
+ attr_accessor :name
283
+
284
+ def initialize(app, name:)
285
+ super(app)
286
+ @name = name
287
+ end
288
+ end
289
+ end
290
+ let(:rabbit) do
291
+ subject.adapter.build
292
+ end
293
+
294
+ it 'adds a handler to construct adapter with options passed to adapter' do
295
+ Faraday::Adapter.register_middleware rabbit_adapter: rabbit_adapter
296
+ subject.adapter :rabbit_adapter, name: 'Thumper'
297
+ expect { rabbit }.to_not output(
298
+ /warning: Using the last argument as keyword parameters is deprecated/
299
+ ).to_stderr
300
+ expect(rabbit.name).to eq('Thumper')
301
+ end
302
+ end
303
+
304
+ context 'when handlers are directly added or updated' do
305
+ let(:conn) { Faraday::Connection.new {} }
306
+
307
+ let(:rock_handler) do
308
+ Class.new do
309
+ attr_accessor :name
310
+
311
+ def initialize(_app, name:)
312
+ @name = name
313
+ end
314
+ end
315
+ end
316
+ let(:rock) do
317
+ subject.handlers.find { |handler| handler == rock_handler }.build
318
+ end
319
+
320
+ it 'adds a handler to construct adapter with options passed to insert' do
321
+ subject.insert 0, rock_handler, name: 'Stony'
322
+ expect { rock }.to_not output(
323
+ /warning: Using the last argument as keyword parameters is deprecated/
324
+ ).to_stderr
325
+ expect(rock.name).to eq('Stony')
326
+ end
327
+
328
+ it 'adds a handler with options passed to insert_after' do
329
+ subject.insert_after 0, rock_handler, name: 'Rocky'
330
+ expect { rock }.to_not output(
331
+ /warning: Using the last argument as keyword parameters is deprecated/
332
+ ).to_stderr
333
+ expect(rock.name).to eq('Rocky')
334
+ end
335
+
336
+ it 'adds a handler with options passed to swap' do
337
+ subject.insert 0, rock_handler, name: 'Flint'
338
+ subject.swap 0, rock_handler, name: 'Chert'
339
+ expect { rock }.to_not output(
340
+ /warning: Using the last argument as keyword parameters is deprecated/
341
+ ).to_stderr
342
+ expect(rock.name).to eq('Chert')
343
+ end
344
+ end
196
345
  end
@@ -56,7 +56,7 @@ RSpec.describe Faraday::Request::Authorization do
56
56
  end
57
57
 
58
58
  context 'when other values are provided' do
59
- let(:auth_config) { ['baz', foo: 42] }
59
+ let(:auth_config) { ['baz', { foo: 42 }] }
60
60
 
61
61
  it { expect(response.body).to match(/^Token /) }
62
62
  it { expect(response.body).to match(/token="baz"/) }
@@ -78,7 +78,7 @@ RSpec.describe Faraday::Request::Authorization do
78
78
  end
79
79
 
80
80
  context 'when passed a string and a hash' do
81
- let(:auth_config) { ['baz', foo: 42] }
81
+ let(:auth_config) { ['baz', { foo: 42 }] }
82
82
 
83
83
  it { expect(response.body).to eq('baz foo="42"') }
84
84
 
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe Faraday::Request::Multipart do
4
+ let(:options) { {} }
4
5
  let(:conn) do
5
6
  Faraday.new do |b|
6
- b.request :multipart
7
+ b.request :multipart, options
7
8
  b.request :url_encoded
8
9
  b.adapter :test do |stub|
9
10
  stub.post('/echo') do |env|
@@ -54,9 +55,10 @@ RSpec.describe Faraday::Request::Multipart do
54
55
  part_bc, body_bc = result.part('b[c]')
55
56
  expect(part_bc).to_not be_nil
56
57
  expect(part_bc.filename).to eq('multipart_spec.rb')
57
- expect(part_bc.headers['content-disposition']).to eq(
58
- 'form-data; foo=1; name="b[c]"; filename="multipart_spec.rb"'
59
- )
58
+ expect(part_bc.headers['content-disposition'])
59
+ .to eq(
60
+ 'form-data; foo=1; name="b[c]"; filename="multipart_spec.rb"'
61
+ )
60
62
  expect(part_bc.headers['content-type']).to eq('text/x-ruby')
61
63
  expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
62
64
  expect(body_bc).to eq(File.read(__FILE__))
@@ -135,9 +137,10 @@ RSpec.describe Faraday::Request::Multipart do
135
137
  part_bc, body_bc = result.part('b[][c]')
136
138
  expect(part_bc).to_not be_nil
137
139
  expect(part_bc.filename).to eq('multipart_spec.rb')
138
- expect(part_bc.headers['content-disposition']).to eq(
139
- 'form-data; name="b[][c]"; filename="multipart_spec.rb"'
140
- )
140
+ expect(part_bc.headers['content-disposition'])
141
+ .to eq(
142
+ 'form-data; name="b[][c]"; filename="multipart_spec.rb"'
143
+ )
141
144
  expect(part_bc.headers['content-type']).to eq('text/x-ruby')
142
145
  expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
143
146
  expect(body_bc).to eq(File.read(__FILE__))
@@ -177,9 +180,10 @@ RSpec.describe Faraday::Request::Multipart do
177
180
  part_bc, body_bc = result.part('b[c]')
178
181
  expect(part_bc).to_not be_nil
179
182
  expect(part_bc.filename).to eq('multipart_spec.rb')
180
- expect(part_bc.headers['content-disposition']).to eq(
181
- 'form-data; foo=1; name="b[c]"; filename="multipart_spec.rb"'
182
- )
183
+ expect(part_bc.headers['content-disposition'])
184
+ .to eq(
185
+ 'form-data; foo=1; name="b[c]"; filename="multipart_spec.rb"'
186
+ )
183
187
  expect(part_bc.headers['content-type']).to eq('text/x-ruby')
184
188
  expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
185
189
  expect(body_bc).to eq(File.read(__FILE__))
@@ -258,9 +262,10 @@ RSpec.describe Faraday::Request::Multipart do
258
262
  part_bc, body_bc = result.part('b[][c]')
259
263
  expect(part_bc).to_not be_nil
260
264
  expect(part_bc.filename).to eq('multipart_spec.rb')
261
- expect(part_bc.headers['content-disposition']).to eq(
262
- 'form-data; name="b[][c]"; filename="multipart_spec.rb"'
263
- )
265
+ expect(part_bc.headers['content-disposition'])
266
+ .to eq(
267
+ 'form-data; name="b[][c]"; filename="multipart_spec.rb"'
268
+ )
264
269
  expect(part_bc.headers['content-type']).to eq('text/x-ruby')
265
270
  expect(part_bc.headers['content-transfer-encoding']).to eq('binary')
266
271
  expect(body_bc).to eq(File.read(__FILE__))
@@ -271,4 +276,27 @@ RSpec.describe Faraday::Request::Multipart do
271
276
  expect(body_bd).to eq('2')
272
277
  end
273
278
  end
279
+
280
+ context 'when passing flat_encode=true option' do
281
+ let(:options) { { flat_encode: true } }
282
+ let(:io) { StringIO.new('io-content') }
283
+ let(:payload) do
284
+ {
285
+ a: 1,
286
+ b: [
287
+ Faraday::UploadIO.new(io, 'application/pdf'),
288
+ Faraday::UploadIO.new(io, 'application/pdf')
289
+ ]
290
+ }
291
+ end
292
+
293
+ it_behaves_like 'a multipart request'
294
+
295
+ it 'encode params using flat encoder' do
296
+ response = conn.post('/echo', payload)
297
+
298
+ expect(response.body).to include('name="b"')
299
+ expect(response.body).not_to include('name="b[]"')
300
+ end
301
+ end
274
302
  end
@@ -6,20 +6,31 @@ RSpec.describe Faraday::Request do
6
6
  headers: { 'Mime-Version' => '1.0' },
7
7
  request: { oauth: { consumer_key: 'anonymous' } })
8
8
  end
9
- let(:method) { :get }
9
+ let(:http_method) { :get }
10
10
  let(:block) { nil }
11
11
 
12
- subject { conn.build_request(method, &block) }
12
+ subject { conn.build_request(http_method, &block) }
13
13
 
14
14
  context 'when nothing particular is configured' do
15
- it { expect(subject.method).to eq(:get) }
15
+ it { expect(subject.http_method).to eq(:get) }
16
16
  it { expect(subject.to_env(conn).ssl.verify).to be_falsey }
17
17
  end
18
18
 
19
- context 'when method is post' do
20
- let(:method) { :post }
19
+ context 'when HTTP method is post' do
20
+ let(:http_method) { :post }
21
+
22
+ it { expect(subject.http_method).to eq(:post) }
23
+ end
24
+
25
+ describe 'deprecate method for HTTP method' do
26
+ let(:http_method) { :post }
27
+ let(:expected_warning) do
28
+ %r{WARNING: `Faraday::Request#method` is deprecated; use `#http_method` instead. It will be removed in or after version 2.0.\n`Faraday::Request#method` called from .+/spec/faraday/request_spec.rb:\d+.}
29
+ end
21
30
 
22
31
  it { expect(subject.method).to eq(:post) }
32
+
33
+ it { expect { subject.method }.to output(expected_warning).to_stderr }
23
34
  end
24
35
 
25
36
  context 'when setting the url on setup with a URI' do
@@ -103,4 +103,37 @@ RSpec.describe Faraday::Response::RaiseError do
103
103
  expect(ex.response[:status]).to eq(500)
104
104
  end
105
105
  end
106
+
107
+ describe 'request info' do
108
+ let(:conn) do
109
+ Faraday.new do |b|
110
+ b.response :raise_error
111
+ b.adapter :test do |stub|
112
+ stub.post('request?full=true', request_body, request_headers) do
113
+ [400, { 'X-Reason' => 'because' }, 'keep looking']
114
+ end
115
+ end
116
+ end
117
+ end
118
+ let(:request_body) { JSON.generate({ 'item' => 'sth' }) }
119
+ let(:request_headers) { { 'Authorization' => 'Basic 123' } }
120
+
121
+ subject(:perform_request) do
122
+ conn.post 'request' do |req|
123
+ req.headers['Authorization'] = 'Basic 123'
124
+ req.params[:full] = true
125
+ req.body = request_body
126
+ end
127
+ end
128
+
129
+ it 'returns the request info in the exception' do
130
+ expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
131
+ expect(ex.response[:request][:method]).to eq(:post)
132
+ expect(ex.response[:request][:url_path]).to eq('/request')
133
+ expect(ex.response[:request][:params]).to eq({ 'full' => 'true' })
134
+ expect(ex.response[:request][:headers]).to match(a_hash_including(request_headers))
135
+ expect(ex.response[:request][:body]).to eq(request_body)
136
+ end
137
+ end
138
+ end
106
139
  end
@@ -13,8 +13,8 @@ shared_examples 'a request method' do |http_method|
13
13
  end
14
14
 
15
15
  it 'handles headers with multiple values' do
16
- request_stub.to_return(headers: { 'Set-Cookie' => 'one, two' })
17
- expect(response.headers['set-cookie']).to eq('one, two')
16
+ request_stub.to_return(headers: { 'Set-Cookie' => 'name=value' })
17
+ expect(response.headers['set-cookie']).to eq('name=value')
18
18
  end
19
19
 
20
20
  it 'retrieves the response headers' do
@@ -119,7 +119,7 @@ shared_examples 'a request method' do |http_method|
119
119
  request_stub.with(headers: { 'Content-Type' => %r{\Amultipart/form-data} }) do |request|
120
120
  # WebMock does not support matching body for multipart/form-data requests yet :(
121
121
  # https://github.com/bblimke/webmock/issues/623
122
- request.body =~ /RubyMultipartPost/
122
+ request.body.include?('RubyMultipartPost')
123
123
  end
124
124
  conn.public_send(http_method, '/', payload)
125
125
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faraday
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - "@technoweenie"
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-03-29 00:00:00.000000000 Z
13
+ date: 2020-10-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: multipart-post
@@ -32,6 +32,20 @@ dependencies:
32
32
  - - "<"
33
33
  - !ruby/object:Gem::Version
34
34
  version: '3'
35
+ - !ruby/object:Gem::Dependency
36
+ name: ruby2_keywords
37
+ requirement: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
35
49
  description:
36
50
  email: technoweenie@gmail.com
37
51
  executables: []
@@ -101,6 +115,7 @@ files:
101
115
  - spec/faraday/adapter/net_http_spec.rb
102
116
  - spec/faraday/adapter/patron_spec.rb
103
117
  - spec/faraday/adapter/rack_spec.rb
118
+ - spec/faraday/adapter/test_spec.rb
104
119
  - spec/faraday/adapter/typhoeus_spec.rb
105
120
  - spec/faraday/adapter_registry_spec.rb
106
121
  - spec/faraday/adapter_spec.rb
@@ -142,7 +157,7 @@ licenses:
142
157
  - MIT
143
158
  metadata:
144
159
  homepage_uri: https://lostisland.github.io/faraday
145
- changelog_uri: https://github.com/lostisland/faraday/releases/tag/v1.0.1
160
+ changelog_uri: https://github.com/lostisland/faraday/releases/tag/v1.1.0
146
161
  source_code_uri: https://github.com/lostisland/faraday
147
162
  bug_tracker_uri: https://github.com/lostisland/faraday/issues
148
163
  post_install_message:
@@ -154,7 +169,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
154
169
  requirements:
155
170
  - - ">="
156
171
  - !ruby/object:Gem::Version
157
- version: '2.3'
172
+ version: '2.4'
158
173
  required_rubygems_version: !ruby/object:Gem::Requirement
159
174
  requirements:
160
175
  - - ">="