faraday 0.13.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +496 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +28 -328
  5. data/Rakefile +7 -0
  6. data/examples/client_spec.rb +97 -0
  7. data/examples/client_test.rb +118 -0
  8. data/lib/faraday/adapter/test.rb +127 -68
  9. data/lib/faraday/adapter.rb +71 -22
  10. data/lib/faraday/adapter_registry.rb +30 -0
  11. data/lib/faraday/connection.rb +314 -226
  12. data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
  13. data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
  14. data/lib/faraday/error.rb +121 -37
  15. data/lib/faraday/logging/formatter.rb +106 -0
  16. data/lib/faraday/methods.rb +6 -0
  17. data/lib/faraday/middleware.rb +18 -25
  18. data/lib/faraday/middleware_registry.rb +65 -0
  19. data/lib/faraday/options/connection_options.rb +22 -0
  20. data/lib/faraday/options/env.rb +181 -0
  21. data/lib/faraday/options/proxy_options.rb +32 -0
  22. data/lib/faraday/options/request_options.rb +22 -0
  23. data/lib/faraday/options/ssl_options.rb +59 -0
  24. data/lib/faraday/options.rb +41 -195
  25. data/lib/faraday/parameters.rb +4 -196
  26. data/lib/faraday/rack_builder.rb +91 -74
  27. data/lib/faraday/request/authorization.rb +37 -29
  28. data/lib/faraday/request/instrumentation.rb +47 -27
  29. data/lib/faraday/request/json.rb +55 -0
  30. data/lib/faraday/request/url_encoded.rb +45 -23
  31. data/lib/faraday/request.rb +74 -32
  32. data/lib/faraday/response/json.rb +54 -0
  33. data/lib/faraday/response/logger.rb +22 -69
  34. data/lib/faraday/response/raise_error.rb +57 -14
  35. data/lib/faraday/response.rb +26 -33
  36. data/lib/faraday/utils/headers.rb +139 -0
  37. data/lib/faraday/utils/params_hash.rb +61 -0
  38. data/lib/faraday/utils.rb +47 -251
  39. data/lib/faraday/version.rb +5 -0
  40. data/lib/faraday.rb +104 -197
  41. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  42. data/spec/faraday/adapter/test_spec.rb +377 -0
  43. data/spec/faraday/adapter_registry_spec.rb +28 -0
  44. data/spec/faraday/adapter_spec.rb +55 -0
  45. data/spec/faraday/connection_spec.rb +787 -0
  46. data/spec/faraday/error_spec.rb +60 -0
  47. data/spec/faraday/middleware_spec.rb +52 -0
  48. data/spec/faraday/options/env_spec.rb +70 -0
  49. data/spec/faraday/options/options_spec.rb +297 -0
  50. data/spec/faraday/options/proxy_options_spec.rb +44 -0
  51. data/spec/faraday/options/request_options_spec.rb +19 -0
  52. data/spec/faraday/params_encoders/flat_spec.rb +42 -0
  53. data/spec/faraday/params_encoders/nested_spec.rb +142 -0
  54. data/spec/faraday/rack_builder_spec.rb +302 -0
  55. data/spec/faraday/request/authorization_spec.rb +83 -0
  56. data/spec/faraday/request/instrumentation_spec.rb +74 -0
  57. data/spec/faraday/request/json_spec.rb +111 -0
  58. data/spec/faraday/request/url_encoded_spec.rb +82 -0
  59. data/spec/faraday/request_spec.rb +109 -0
  60. data/spec/faraday/response/json_spec.rb +117 -0
  61. data/spec/faraday/response/logger_spec.rb +220 -0
  62. data/spec/faraday/response/raise_error_spec.rb +172 -0
  63. data/spec/faraday/response_spec.rb +75 -0
  64. data/spec/faraday/utils/headers_spec.rb +82 -0
  65. data/spec/faraday/utils_spec.rb +117 -0
  66. data/spec/faraday_spec.rb +37 -0
  67. data/spec/spec_helper.rb +132 -0
  68. data/spec/support/disabling_stub.rb +14 -0
  69. data/spec/support/fake_safe_buffer.rb +15 -0
  70. data/spec/support/helper_methods.rb +96 -0
  71. data/spec/support/shared_examples/adapter.rb +104 -0
  72. data/spec/support/shared_examples/params_encoder.rb +18 -0
  73. data/spec/support/shared_examples/request_method.rb +249 -0
  74. data/spec/support/streaming_response_checker.rb +35 -0
  75. metadata +71 -34
  76. data/lib/faraday/adapter/em_http.rb +0 -243
  77. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
  78. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
  79. data/lib/faraday/adapter/em_synchrony.rb +0 -106
  80. data/lib/faraday/adapter/excon.rb +0 -80
  81. data/lib/faraday/adapter/httpclient.rb +0 -128
  82. data/lib/faraday/adapter/net_http.rb +0 -135
  83. data/lib/faraday/adapter/net_http_persistent.rb +0 -54
  84. data/lib/faraday/adapter/patron.rb +0 -83
  85. data/lib/faraday/adapter/rack.rb +0 -58
  86. data/lib/faraday/adapter/typhoeus.rb +0 -123
  87. data/lib/faraday/autoload.rb +0 -84
  88. data/lib/faraday/request/basic_authentication.rb +0 -13
  89. data/lib/faraday/request/multipart.rb +0 -68
  90. data/lib/faraday/request/retry.rb +0 -164
  91. data/lib/faraday/request/token_authentication.rb +0 -15
  92. data/lib/faraday/upload_io.rb +0 -67
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ module Utils
5
+ # A case-insensitive Hash that preserves the original case of a header
6
+ # when set.
7
+ #
8
+ # Adapted from Rack::Utils::HeaderHash
9
+ class Headers < ::Hash
10
+ def self.from(value)
11
+ new(value)
12
+ end
13
+
14
+ def self.allocate
15
+ new_self = super
16
+ new_self.initialize_names
17
+ new_self
18
+ end
19
+
20
+ def initialize(hash = nil)
21
+ super()
22
+ @names = {}
23
+ update(hash || {})
24
+ end
25
+
26
+ def initialize_names
27
+ @names = {}
28
+ end
29
+
30
+ # on dup/clone, we need to duplicate @names hash
31
+ def initialize_copy(other)
32
+ super
33
+ @names = other.names.dup
34
+ end
35
+
36
+ # need to synchronize concurrent writes to the shared KeyMap
37
+ keymap_mutex = Mutex.new
38
+
39
+ # symbol -> string mapper + cache
40
+ KeyMap = Hash.new do |map, key|
41
+ value = if key.respond_to?(:to_str)
42
+ key
43
+ else
44
+ key.to_s.split('_') # user_agent: %w(user agent)
45
+ .each(&:capitalize!) # => %w(User Agent)
46
+ .join('-') # => "User-Agent"
47
+ end
48
+ keymap_mutex.synchronize { map[key] = value }
49
+ end
50
+ KeyMap[:etag] = 'ETag'
51
+
52
+ def [](key)
53
+ key = KeyMap[key]
54
+ super(key) || super(@names[key.downcase])
55
+ end
56
+
57
+ def []=(key, val)
58
+ key = KeyMap[key]
59
+ key = (@names[key.downcase] ||= key)
60
+ # join multiple values with a comma
61
+ val = val.to_ary.join(', ') if val.respond_to?(:to_ary)
62
+ super(key, val)
63
+ end
64
+
65
+ def fetch(key, *args, &block)
66
+ key = KeyMap[key]
67
+ key = @names.fetch(key.downcase, key)
68
+ super(key, *args, &block)
69
+ end
70
+
71
+ def delete(key)
72
+ key = KeyMap[key]
73
+ key = @names[key.downcase]
74
+ return unless key
75
+
76
+ @names.delete key.downcase
77
+ super(key)
78
+ end
79
+
80
+ def include?(key)
81
+ @names.include? key.downcase
82
+ end
83
+
84
+ alias has_key? include?
85
+ alias member? include?
86
+ alias key? include?
87
+
88
+ def merge!(other)
89
+ other.each { |k, v| self[k] = v }
90
+ self
91
+ end
92
+
93
+ alias update merge!
94
+
95
+ def merge(other)
96
+ hash = dup
97
+ hash.merge! other
98
+ end
99
+
100
+ def replace(other)
101
+ clear
102
+ @names.clear
103
+ update other
104
+ self
105
+ end
106
+
107
+ def to_hash
108
+ {}.update(self)
109
+ end
110
+
111
+ def parse(header_string)
112
+ return unless header_string && !header_string.empty?
113
+
114
+ headers = header_string.split("\r\n")
115
+
116
+ # Find the last set of response headers.
117
+ start_index = headers.rindex { |x| x.start_with?('HTTP/') } || 0
118
+ last_response = headers.slice(start_index, headers.size)
119
+
120
+ last_response
121
+ .tap { |a| a.shift if a.first.start_with?('HTTP/') }
122
+ .map { |h| h.split(/:\s*/, 2) } # split key and value
123
+ .reject { |p| p[0].nil? } # ignore blank lines
124
+ .each { |key, value| add_parsed(key, value) }
125
+ end
126
+
127
+ protected
128
+
129
+ attr_reader :names
130
+
131
+ private
132
+
133
+ # Join multiple values with a comma.
134
+ def add_parsed(key, value)
135
+ self[key] ? self[key] << ', ' << value : self[key] = value
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ module Utils
5
+ # A hash with stringified keys.
6
+ class ParamsHash < Hash
7
+ def [](key)
8
+ super(convert_key(key))
9
+ end
10
+
11
+ def []=(key, value)
12
+ super(convert_key(key), value)
13
+ end
14
+
15
+ def delete(key)
16
+ super(convert_key(key))
17
+ end
18
+
19
+ def include?(key)
20
+ super(convert_key(key))
21
+ end
22
+
23
+ alias has_key? include?
24
+ alias member? include?
25
+ alias key? include?
26
+
27
+ def update(params)
28
+ params.each do |key, value|
29
+ self[key] = value
30
+ end
31
+ self
32
+ end
33
+ alias merge! update
34
+
35
+ def merge(params)
36
+ dup.update(params)
37
+ end
38
+
39
+ def replace(other)
40
+ clear
41
+ update(other)
42
+ end
43
+
44
+ def merge_query(query, encoder = nil)
45
+ return self unless query && !query.empty?
46
+
47
+ update((encoder || Utils.default_params_encoder).decode(query))
48
+ end
49
+
50
+ def to_query(encoder = nil)
51
+ (encoder || Utils.default_params_encoder).encode(self)
52
+ end
53
+
54
+ private
55
+
56
+ def convert_key(key)
57
+ key.to_s
58
+ end
59
+ end
60
+ end
61
+ end
data/lib/faraday/utils.rb CHANGED
@@ -1,193 +1,14 @@
1
- require 'thread'
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'uri'
5
+ require 'faraday/utils/headers'
6
+ require 'faraday/utils/params_hash'
2
7
 
3
8
  module Faraday
9
+ # Utils contains various static helper methods.
4
10
  module Utils
5
- extend self
6
-
7
- # Adapted from Rack::Utils::HeaderHash
8
- class Headers < ::Hash
9
- def self.from(value)
10
- new(value)
11
- end
12
-
13
- def self.allocate
14
- new_self = super
15
- new_self.initialize_names
16
- new_self
17
- end
18
-
19
- def initialize(hash = nil)
20
- super()
21
- @names = {}
22
- self.update(hash || {})
23
- end
24
-
25
- def initialize_names
26
- @names = {}
27
- end
28
-
29
- # on dup/clone, we need to duplicate @names hash
30
- def initialize_copy(other)
31
- super
32
- @names = other.names.dup
33
- end
34
-
35
- # need to synchronize concurrent writes to the shared KeyMap
36
- keymap_mutex = Mutex.new
37
-
38
- # symbol -> string mapper + cache
39
- KeyMap = Hash.new do |map, key|
40
- value = if key.respond_to?(:to_str)
41
- key
42
- else
43
- key.to_s.split('_'). # :user_agent => %w(user agent)
44
- each { |w| w.capitalize! }. # => %w(User Agent)
45
- join('-') # => "User-Agent"
46
- end
47
- keymap_mutex.synchronize { map[key] = value }
48
- end
49
- KeyMap[:etag] = "ETag"
50
-
51
- def [](k)
52
- k = KeyMap[k]
53
- super(k) || super(@names[k.downcase])
54
- end
55
-
56
- def []=(k, v)
57
- k = KeyMap[k]
58
- k = (@names[k.downcase] ||= k)
59
- # join multiple values with a comma
60
- v = v.to_ary.join(', ') if v.respond_to? :to_ary
61
- super(k, v)
62
- end
63
-
64
- def fetch(k, *args, &block)
65
- k = KeyMap[k]
66
- key = @names.fetch(k.downcase, k)
67
- super(key, *args, &block)
68
- end
69
-
70
- def delete(k)
71
- k = KeyMap[k]
72
- if k = @names[k.downcase]
73
- @names.delete k.downcase
74
- super(k)
75
- end
76
- end
77
-
78
- def include?(k)
79
- @names.include? k.downcase
80
- end
81
-
82
- alias_method :has_key?, :include?
83
- alias_method :member?, :include?
84
- alias_method :key?, :include?
85
-
86
- def merge!(other)
87
- other.each { |k, v| self[k] = v }
88
- self
89
- end
90
- alias_method :update, :merge!
91
-
92
- def merge(other)
93
- hash = dup
94
- hash.merge! other
95
- end
96
-
97
- def replace(other)
98
- clear
99
- @names.clear
100
- self.update other
101
- self
102
- end
103
-
104
- def to_hash() ::Hash.new.update(self) end
105
-
106
- def parse(header_string)
107
- return unless header_string && !header_string.empty?
108
-
109
- headers = header_string.split(/\r\n/)
110
-
111
- # Find the last set of response headers.
112
- start_index = headers.rindex { |x| x.match(/^HTTP\//) } || 0
113
- last_response = headers.slice(start_index, headers.size)
114
-
115
- last_response.
116
- tap { |a| a.shift if a.first.index('HTTP/') == 0 }. # drop the HTTP status line
117
- map { |h| h.split(/:\s*/, 2) }.reject { |p| p[0].nil? }. # split key and value, ignore blank lines
118
- each { |key, value|
119
- # join multiple values with a comma
120
- if self[key]
121
- self[key] << ', ' << value
122
- else
123
- self[key] = value
124
- end
125
- }
126
- end
127
-
128
- protected
129
-
130
- def names
131
- @names
132
- end
133
- end
134
-
135
- # hash with stringified keys
136
- class ParamsHash < Hash
137
- def [](key)
138
- super(convert_key(key))
139
- end
140
-
141
- def []=(key, value)
142
- super(convert_key(key), value)
143
- end
144
-
145
- def delete(key)
146
- super(convert_key(key))
147
- end
148
-
149
- def include?(key)
150
- super(convert_key(key))
151
- end
152
-
153
- alias_method :has_key?, :include?
154
- alias_method :member?, :include?
155
- alias_method :key?, :include?
156
-
157
- def update(params)
158
- params.each do |key, value|
159
- self[key] = value
160
- end
161
- self
162
- end
163
- alias_method :merge!, :update
164
-
165
- def merge(params)
166
- dup.update(params)
167
- end
168
-
169
- def replace(other)
170
- clear
171
- update(other)
172
- end
173
-
174
- def merge_query(query, encoder = nil)
175
- if query && !query.empty?
176
- update((encoder || Utils.default_params_encoder).decode(query))
177
- end
178
- self
179
- end
180
-
181
- def to_query(encoder = nil)
182
- (encoder || Utils.default_params_encoder).encode(self)
183
- end
184
-
185
- private
186
-
187
- def convert_key(key)
188
- key.to_s
189
- end
190
- end
11
+ module_function
191
12
 
192
13
  def build_query(params)
193
14
  FlatParamsEncoder.encode(params)
@@ -197,17 +18,27 @@ module Faraday
197
18
  NestedParamsEncoder.encode(params)
198
19
  end
199
20
 
200
- ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/
21
+ def default_space_encoding
22
+ @default_space_encoding ||= '+'
23
+ end
24
+
25
+ class << self
26
+ attr_writer :default_space_encoding
27
+ end
28
+
29
+ ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/.freeze
201
30
 
202
- def escape(s)
203
- s.to_s.gsub(ESCAPE_RE) {|match|
204
- '%' + match.unpack('H2' * match.bytesize).join('%').upcase
205
- }.tr(' ', '+')
31
+ def escape(str)
32
+ str.to_s.gsub(ESCAPE_RE) do |match|
33
+ "%#{match.unpack('H2' * match.bytesize).join('%').upcase}"
34
+ end.gsub(' ', default_space_encoding)
206
35
  end
207
36
 
208
- def unescape(s) CGI.unescape s.to_s end
37
+ def unescape(str)
38
+ CGI.unescape str.to_s
39
+ end
209
40
 
210
- DEFAULT_SEP = /[&;] */n
41
+ DEFAULT_SEP = /[&;] */n.freeze
211
42
 
212
43
  # Adapted from Rack
213
44
  def parse_query(query)
@@ -222,45 +53,14 @@ module Faraday
222
53
  @default_params_encoder ||= NestedParamsEncoder
223
54
  end
224
55
 
225
- class << self
226
- attr_writer :default_params_encoder
56
+ def basic_header_from(login, pass)
57
+ value = Base64.encode64("#{login}:#{pass}")
58
+ value.delete!("\n")
59
+ "Basic #{value}"
227
60
  end
228
61
 
229
- # Stolen from Rack
230
- def normalize_params(params, name, v = nil)
231
- name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
232
- k = $1 || ''
233
- after = $' || ''
234
-
235
- return if k.empty?
236
-
237
- if after == ""
238
- if params[k]
239
- params[k] = Array[params[k]] unless params[k].kind_of?(Array)
240
- params[k] << v
241
- else
242
- params[k] = v
243
- end
244
- elsif after == "[]"
245
- params[k] ||= []
246
- raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
247
- params[k] << v
248
- elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
249
- child_key = $1
250
- params[k] ||= []
251
- raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
252
- if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key)
253
- normalize_params(params[k].last, child_key, v)
254
- else
255
- params[k] << normalize_params({}, child_key, v)
256
- end
257
- else
258
- params[k] ||= {}
259
- raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash)
260
- params[k] = normalize_params(params[k], after, v)
261
- end
262
-
263
- return params
62
+ class << self
63
+ attr_writer :default_params_encoder
264
64
  end
265
65
 
266
66
  # Normalize URI() behavior across Ruby versions
@@ -268,46 +68,44 @@ module Faraday
268
68
  # url - A String or URI.
269
69
  #
270
70
  # Returns a parsed URI.
271
- def URI(url)
71
+ def URI(url) # rubocop:disable Naming/MethodName
272
72
  if url.respond_to?(:host)
273
73
  url
274
74
  elsif url.respond_to?(:to_str)
275
75
  default_uri_parser.call(url)
276
76
  else
277
- raise ArgumentError, "bad argument (expected URI object or URI string)"
77
+ raise ArgumentError, 'bad argument (expected URI object or URI string)'
278
78
  end
279
79
  end
280
80
 
281
81
  def default_uri_parser
282
- @default_uri_parser ||= begin
283
- require 'uri'
284
- Kernel.method(:URI)
285
- end
82
+ @default_uri_parser ||= Kernel.method(:URI)
286
83
  end
287
84
 
288
85
  def default_uri_parser=(parser)
289
86
  @default_uri_parser = if parser.respond_to?(:call) || parser.nil?
290
- parser
291
- else
292
- parser.method(:parse)
293
- end
87
+ parser
88
+ else
89
+ parser.method(:parse)
90
+ end
294
91
  end
295
92
 
296
- # Receives a String or URI and returns just the path with the query string sorted.
93
+ # Receives a String or URI and returns just
94
+ # the path with the query string sorted.
297
95
  def normalize_path(url)
298
96
  url = URI(url)
299
- (url.path.start_with?('/') ? url.path : '/' + url.path) +
300
- (url.query ? "?#{sort_query_params(url.query)}" : "")
97
+ (url.path.start_with?('/') ? url.path : "/#{url.path}") +
98
+ (url.query ? "?#{sort_query_params(url.query)}" : '')
301
99
  end
302
100
 
303
101
  # Recursive hash update
304
102
  def deep_merge!(target, hash)
305
103
  hash.each do |key, value|
306
- if Hash === value and Hash === target[key]
307
- target[key] = deep_merge(target[key], value)
308
- else
309
- target[key] = value
310
- end
104
+ target[key] = if value.is_a?(Hash) && (target[key].is_a?(Hash) || target[key].is_a?(Options))
105
+ deep_merge(target[key], value)
106
+ else
107
+ value
108
+ end
311
109
  end
312
110
  target
313
111
  end
@@ -317,8 +115,6 @@ module Faraday
317
115
  deep_merge!(source.dup, hash)
318
116
  end
319
117
 
320
- protected
321
-
322
118
  def sort_query_params(query)
323
119
  query.split('&').sort.join('&')
324
120
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ VERSION = '2.0.0'
5
+ end