faraday 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
  - - ">="