faraday 0.15.0 → 0.17.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +232 -0
  3. data/README.md +20 -6
  4. data/Rakefile +13 -0
  5. data/lib/faraday/adapter/em_http.rb +9 -9
  6. data/lib/faraday/adapter/em_synchrony.rb +5 -5
  7. data/lib/faraday/adapter/excon.rb +6 -3
  8. data/lib/faraday/adapter/httpclient.rb +4 -4
  9. data/lib/faraday/adapter/net_http.rb +23 -7
  10. data/lib/faraday/adapter/net_http_persistent.rb +22 -17
  11. data/lib/faraday/adapter/patron.rb +7 -12
  12. data/lib/faraday/adapter/rack.rb +1 -1
  13. data/lib/faraday/deprecate.rb +109 -0
  14. data/lib/faraday/error.rb +127 -35
  15. data/lib/faraday/options.rb +6 -5
  16. data/lib/faraday/parameters.rb +2 -1
  17. data/lib/faraday/rack_builder.rb +2 -2
  18. data/lib/faraday/request/retry.rb +9 -7
  19. data/lib/faraday/request.rb +22 -0
  20. data/lib/faraday/response/logger.rb +1 -1
  21. data/lib/faraday/response/raise_error.rb +7 -3
  22. data/lib/faraday/response.rb +3 -3
  23. data/lib/faraday.rb +2 -3
  24. data/spec/faraday/deprecate_spec.rb +147 -0
  25. data/spec/faraday/error_spec.rb +102 -0
  26. data/spec/faraday/response/raise_error_spec.rb +106 -0
  27. data/spec/spec_helper.rb +105 -0
  28. data/test/adapters/default_test.rb +14 -0
  29. data/test/adapters/em_http_test.rb +30 -0
  30. data/test/adapters/em_synchrony_test.rb +32 -0
  31. data/test/adapters/excon_test.rb +30 -0
  32. data/test/adapters/httpclient_test.rb +34 -0
  33. data/test/adapters/integration.rb +263 -0
  34. data/test/adapters/logger_test.rb +136 -0
  35. data/test/adapters/net_http_persistent_test.rb +114 -0
  36. data/test/adapters/net_http_test.rb +79 -0
  37. data/test/adapters/patron_test.rb +40 -0
  38. data/test/adapters/rack_test.rb +38 -0
  39. data/test/adapters/test_middleware_test.rb +157 -0
  40. data/test/adapters/typhoeus_test.rb +38 -0
  41. data/test/authentication_middleware_test.rb +65 -0
  42. data/test/composite_read_io_test.rb +109 -0
  43. data/test/connection_test.rb +738 -0
  44. data/test/env_test.rb +268 -0
  45. data/test/helper.rb +75 -0
  46. data/test/live_server.rb +67 -0
  47. data/test/middleware/instrumentation_test.rb +88 -0
  48. data/test/middleware/retry_test.rb +282 -0
  49. data/test/middleware_stack_test.rb +260 -0
  50. data/test/multibyte.txt +1 -0
  51. data/test/options_test.rb +333 -0
  52. data/test/parameters_test.rb +157 -0
  53. data/test/request_middleware_test.rb +126 -0
  54. data/test/response_middleware_test.rb +72 -0
  55. data/test/strawberry.rb +2 -0
  56. data/test/utils_test.rb +98 -0
  57. metadata +48 -7
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Faraday
4
+ # @param new_klass [Class] new Klass to use
5
+ #
6
+ # @return [Class] A modified version of new_klass that warns on
7
+ # usage about deprecation.
8
+ # @see Faraday::Deprecate
9
+ module DeprecatedClass
10
+ def self.proxy_class(origclass, ver = '1.0')
11
+ proxy = Class.new(origclass) do
12
+ const_set("ORIG_CLASS", origclass)
13
+
14
+ class << self
15
+ extend Faraday::Deprecate
16
+
17
+ def ===(other)
18
+ (superclass == const_get("ORIG_CLASS") && other.is_a?(superclass)) || super
19
+ end
20
+ end
21
+ end
22
+ proxy.singleton_class.send(:deprecate, :new, "#{origclass}.new", ver)
23
+ proxy.singleton_class.send(:deprecate, :inherited, origclass.name, ver)
24
+ proxy
25
+ end
26
+ end
27
+
28
+ # Deprecation using semver instead of date, based on Gem::Deprecate
29
+ # Provides a single method +deprecate+ to be used to declare when
30
+ # something is going away.
31
+ #
32
+ # class Legacy
33
+ # def self.klass_method
34
+ # # ...
35
+ # end
36
+ #
37
+ # def instance_method
38
+ # # ...
39
+ # end
40
+ #
41
+ # extend Faraday::Deprecate
42
+ # deprecate :instance_method, "X.z", '1.0'
43
+ #
44
+ # class << self
45
+ # extend Faraday::Deprecate
46
+ # deprecate :klass_method, :none, '1.0'
47
+ # end
48
+ # end
49
+ module Deprecate
50
+ def self.skip # :nodoc:
51
+ @skip ||= begin
52
+ case ENV['FARADAY_DEPRECATE'].to_s.downcase
53
+ when '1', 'warn' then :warn
54
+ else :skip
55
+ end
56
+ end
57
+ @skip == :skip
58
+ end
59
+
60
+ def self.skip=(value) # :nodoc:
61
+ @skip = value ? :skip : :warn
62
+ end
63
+
64
+ # Temporarily turn off warnings. Intended for tests only.
65
+ def skip_during
66
+ original = Faraday::Deprecate.skip
67
+ Faraday::Deprecate.skip, = true
68
+ yield
69
+ ensure
70
+ Faraday::Deprecate.skip = original
71
+ end
72
+
73
+ # Simple deprecation method that deprecates +name+ by wrapping it up
74
+ # in a dummy method. It warns on each call to the dummy method
75
+ # telling the user of +repl+ (unless +repl+ is :none) and the
76
+ # semver that it is planned to go away.
77
+ # @param name [Symbol] the method symbol to deprecate
78
+ # @param repl [#to_s, :none] the replacement to use, when `:none` it will
79
+ # alert the user that no replacemtent is present.
80
+ # @param ver [String] the semver the method will be removed.
81
+ def deprecate(name, repl, ver)
82
+ class_eval do
83
+ gem_ver = Gem::Version.new(ver)
84
+ old = "_deprecated_#{name}"
85
+ alias_method old, name
86
+ define_method name do |*args, &block|
87
+ mod = is_a? Module
88
+ target = mod ? "#{self}." : "#{self.class}#"
89
+ target_message = if name == :inherited
90
+ "Inheriting #{self}"
91
+ else
92
+ "#{target}#{name}"
93
+ end
94
+
95
+ msg = [
96
+ "NOTE: #{target_message} is deprecated",
97
+ repl == :none ? ' with no replacement' : "; use #{repl} instead. ",
98
+ "It will be removed in or after version #{gem_ver}",
99
+ "\n#{target}#{name} called from #{Gem.location_of_caller.join(':')}"
100
+ ]
101
+ warn "#{msg.join}." unless Faraday::Deprecate.skip
102
+ send old, *args, &block
103
+ end
104
+ end
105
+ end
106
+
107
+ module_function :deprecate, :skip_during
108
+ end
109
+ end
data/lib/faraday/error.rb CHANGED
@@ -1,22 +1,17 @@
1
- module Faraday
2
- class Error < StandardError; end
1
+ # frozen_string_literal: true
3
2
 
4
- class ClientError < Error
5
- attr_reader :response, :wrapped_exception
3
+ require 'faraday/deprecate'
6
4
 
7
- def initialize(ex, response = nil)
8
- @wrapped_exception = nil
9
- @response = response
5
+ # Faraday namespace.
6
+ module Faraday
7
+ # Faraday error base class.
8
+ class Error < StandardError
9
+ attr_reader :response, :wrapped_exception
10
10
 
11
- if ex.respond_to?(:backtrace)
12
- super(ex.message)
13
- @wrapped_exception = ex
14
- elsif ex.respond_to?(:each_key)
15
- super("the server responded with status #{ex[:status]}")
16
- @response = ex
17
- else
18
- super(ex.to_s)
19
- end
11
+ def initialize(exc, response = nil)
12
+ @wrapped_exception = nil unless defined?(@wrapped_exception)
13
+ @response = nil unless defined?(@response)
14
+ super(exc_msg_and_response!(exc, response))
20
15
  end
21
16
 
22
17
  def backtrace
@@ -29,38 +24,135 @@ module Faraday
29
24
 
30
25
  def inspect
31
26
  inner = ''
32
- if @wrapped_exception
33
- inner << " wrapped=#{@wrapped_exception.inspect}"
34
- end
35
- if @response
36
- inner << " response=#{@response.inspect}"
37
- end
38
- if inner.empty?
39
- inner << " #{super}"
40
- end
27
+ inner += " wrapped=#{@wrapped_exception.inspect}" if @wrapped_exception
28
+ inner += " response=#{@response.inspect}" if @response
29
+ inner += " #{super}" if inner.empty?
41
30
  %(#<#{self.class}#{inner}>)
42
31
  end
32
+
33
+ protected
34
+
35
+ # Pulls out potential parent exception and response hash, storing them in
36
+ # instance variables.
37
+ # exc - Either an Exception, a string message, or a response hash.
38
+ # response - Hash
39
+ # :status - Optional integer HTTP response status
40
+ # :headers - String key/value hash of HTTP response header
41
+ # values.
42
+ # :body - Optional string HTTP response body.
43
+ #
44
+ # If a subclass has to call this, then it should pass a string message
45
+ # to `super`. See NilStatusError.
46
+ def exc_msg_and_response!(exc, response = nil)
47
+ if @response.nil? && @wrapped_exception.nil?
48
+ @wrapped_exception, msg, @response = exc_msg_and_response(exc, response)
49
+ return msg
50
+ end
51
+
52
+ exc.to_s
53
+ end
54
+
55
+ # Pulls out potential parent exception and response hash.
56
+ def exc_msg_and_response(exc, response = nil)
57
+ return [exc, exc.message, response] if exc.respond_to?(:backtrace)
58
+
59
+ return [nil, "the server responded with status #{exc[:status]}", exc] \
60
+ if exc.respond_to?(:each_key)
61
+
62
+ [nil, exc.to_s, response]
63
+ end
64
+ end
65
+
66
+ # Faraday client error class. Represents 4xx status responses.
67
+ class ClientError < Error
68
+ end
69
+
70
+ # Raised by Faraday::Response::RaiseError in case of a 400 response.
71
+ class BadRequestError < ClientError
43
72
  end
44
73
 
45
- class ConnectionFailed < ClientError; end
46
- class ResourceNotFound < ClientError; end
47
- class ParsingError < ClientError; end
74
+ # Raised by Faraday::Response::RaiseError in case of a 401 response.
75
+ class UnauthorizedError < ClientError
76
+ end
77
+
78
+ # Raised by Faraday::Response::RaiseError in case of a 403 response.
79
+ class ForbiddenError < ClientError
80
+ end
48
81
 
82
+ # Raised by Faraday::Response::RaiseError in case of a 404 response.
83
+ class ResourceNotFound < ClientError
84
+ end
85
+
86
+ # Raised by Faraday::Response::RaiseError in case of a 407 response.
87
+ class ProxyAuthError < ClientError
88
+ end
89
+
90
+ # Raised by Faraday::Response::RaiseError in case of a 409 response.
91
+ class ConflictError < ClientError
92
+ end
93
+
94
+ # Raised by Faraday::Response::RaiseError in case of a 422 response.
95
+ class UnprocessableEntityError < ClientError
96
+ end
97
+
98
+ # Faraday server error class. Represents 5xx status responses.
99
+ class ServerError < Error
100
+ end
101
+
102
+ # A unified client error for timeouts.
49
103
  class TimeoutError < ClientError
50
- def initialize(ex = nil)
51
- super(ex || "timeout")
104
+ def initialize(exc = 'timeout', response = nil)
105
+ super(exc, response)
52
106
  end
53
107
  end
54
108
 
55
- class SSLError < ClientError
109
+ # Raised by Faraday::Response::RaiseError in case of a nil status in response.
110
+ class NilStatusError < ServerError
111
+ def initialize(exc, response = nil)
112
+ exc_msg_and_response!(exc, response)
113
+ @response = unwrap_resp!(@response)
114
+ super('http status could not be derived from the server response')
115
+ end
116
+
117
+ private
118
+
119
+ extend Faraday::Deprecate
120
+
121
+ def unwrap_resp(resp)
122
+ if inner = (resp.keys.size == 1 && resp[:response])
123
+ return unwrap_resp(inner)
124
+ end
125
+
126
+ resp
127
+ end
128
+
129
+ alias_method :unwrap_resp!, :unwrap_resp
130
+ deprecate('unwrap_resp', nil, '1.0')
56
131
  end
57
132
 
58
- class RetriableResponse < ClientError; end
133
+ # A unified error for failed connections.
134
+ class ConnectionFailed < ClientError
135
+ end
59
136
 
60
- [:ClientError, :ConnectionFailed, :ResourceNotFound,
61
- :ParsingError, :TimeoutError, :SSLError, :RetriableResponse].each do |const|
62
- Error.const_set(const, Faraday.const_get(const))
137
+ # A unified client error for SSL errors.
138
+ class SSLError < ClientError
139
+ end
140
+
141
+ # Raised by FaradayMiddleware::ResponseMiddleware
142
+ class ParsingError < ClientError
63
143
  end
64
144
 
145
+ # Exception used to control the Retry middleware.
146
+ #
147
+ # @see Faraday::Request::Retry
148
+ class RetriableResponse < ClientError
149
+ end
65
150
 
151
+ [:ClientError, :ConnectionFailed, :ResourceNotFound,
152
+ :ParsingError, :TimeoutError, :SSLError, :RetriableResponse].each do |const|
153
+ Error.const_set(
154
+ const,
155
+ DeprecatedClass.proxy_class(Faraday.const_get(const))
156
+ )
157
+ end
66
158
  end
@@ -72,7 +72,7 @@ module Faraday
72
72
  if args.size > 0
73
73
  send(key_setter, args.first)
74
74
  elsif block_given?
75
- send(key_setter, Proc.new.call(key))
75
+ send(key_setter, yield(key))
76
76
  else
77
77
  raise self.class.fetch_error_class, "key not found: #{key.inspect}"
78
78
  end
@@ -162,8 +162,8 @@ module Faraday
162
162
  @attribute_options ||= {}
163
163
  end
164
164
 
165
- def self.memoized(key)
166
- memoized_attributes[key.to_sym] = Proc.new
165
+ def self.memoized(key, &block)
166
+ memoized_attributes[key.to_sym] = block
167
167
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
168
168
  def #{key}() self[:#{key}]; end
169
169
  RUBY
@@ -202,7 +202,7 @@ module Faraday
202
202
  end
203
203
 
204
204
  class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
205
- :timeout, :open_timeout, :boundary, :oauth, :context)
205
+ :timeout, :open_timeout, :write_timeout, :boundary, :oauth, :context)
206
206
 
207
207
  def []=(key, value)
208
208
  if key && key.to_sym == :proxy
@@ -214,7 +214,8 @@ module Faraday
214
214
  end
215
215
 
216
216
  class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
217
- :cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth, :version)
217
+ :cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth,
218
+ :version, :min_version, :max_version)
218
219
 
219
220
  def verify?
220
221
  verify != false
@@ -40,9 +40,10 @@ module Faraday
40
40
  end
41
41
  return buffer.chop
42
42
  elsif value.is_a?(Array)
43
+ new_parent = "#{parent}%5B%5D"
44
+ return new_parent if value.empty?
43
45
  buffer = ""
44
46
  value.each_with_index do |val, i|
45
- new_parent = "#{parent}%5B%5D"
46
47
  buffer << "#{to_query.call(new_parent, val)}&"
47
48
  end
48
49
  return buffer.chop
@@ -49,10 +49,10 @@ module Faraday
49
49
  end
50
50
  end
51
51
 
52
- def initialize(handlers = [])
52
+ def initialize(handlers = [], &block)
53
53
  @handlers = handlers
54
54
  if block_given?
55
- build(&Proc.new)
55
+ build(&block)
56
56
  elsif @handlers.empty?
57
57
  # default stack, if nothing else is configured
58
58
  self.request :url_encoded
@@ -1,3 +1,5 @@
1
+ require 'date'
2
+
1
3
  module Faraday
2
4
  # Catches exceptions and retries each request a limited number of times.
3
5
  #
@@ -19,7 +21,9 @@ module Faraday
19
21
  # interval that is random between 0.1 and 0.15
20
22
  #
21
23
  class Request::Retry < Faraday::Middleware
22
-
24
+ DEFAULT_EXCEPTIONS = [Errno::ETIMEDOUT, 'Timeout::Error',
25
+ Faraday::TimeoutError, Faraday::RetriableResponse
26
+ ].freeze
23
27
  IDEMPOTENT_METHODS = [:delete, :get, :head, :options, :put]
24
28
 
25
29
  class Options < Faraday::Options.new(:max, :interval, :max_interval, :interval_randomness,
@@ -57,9 +61,7 @@ module Faraday
57
61
  end
58
62
 
59
63
  def exceptions
60
- Array(self[:exceptions] ||= [Errno::ETIMEDOUT, 'Timeout::Error',
61
- Error::TimeoutError,
62
- Faraday::Error::RetriableResponse])
64
+ Array(self[:exceptions] ||= DEFAULT_EXCEPTIONS)
63
65
  end
64
66
 
65
67
  def methods
@@ -94,7 +96,7 @@ module Faraday
94
96
  # exceptions - The list of exceptions to handle. Exceptions can be
95
97
  # given as Class, Module, or String. (default:
96
98
  # [Errno::ETIMEDOUT, 'Timeout::Error',
97
- # Error::TimeoutError, Faraday::Error::RetriableResponse])
99
+ # Faraday::TimeoutError, Faraday::RetriableResponse])
98
100
  # methods - A list of HTTP methods to retry without calling retry_if. Pass
99
101
  # an empty Array to call retry_if for all exceptions.
100
102
  # (defaults to the idempotent HTTP methods in IDEMPOTENT_METHODS)
@@ -127,7 +129,7 @@ module Faraday
127
129
  begin
128
130
  env[:body] = request_body # after failure env[:body] is set to the response body
129
131
  @app.call(env).tap do |resp|
130
- raise Faraday::Error::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status)
132
+ raise Faraday::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status)
131
133
  end
132
134
  rescue @errmatch => exception
133
135
  if retries > 0 && retry_request?(env, exception)
@@ -140,7 +142,7 @@ module Faraday
140
142
  end
141
143
  end
142
144
 
143
- if exception.is_a?(Faraday::Error::RetriableResponse)
145
+ if exception.is_a?(Faraday::RetriableResponse)
144
146
  exception.response
145
147
  else
146
148
  raise
@@ -12,6 +12,8 @@ module Faraday
12
12
  class Request < Struct.new(:method, :path, :params, :headers, :body, :options)
13
13
  extend MiddlewareRegistry
14
14
 
15
+ alias_method :http_method, :method
16
+
15
17
  register_middleware File.expand_path('../request', __FILE__),
16
18
  :url_encoded => [:UrlEncoded, 'url_encoded'],
17
19
  :multipart => [:Multipart, 'multipart'],
@@ -69,6 +71,26 @@ module Faraday
69
71
  headers[key] = value
70
72
  end
71
73
 
74
+ def marshal_dump
75
+ {
76
+ :method => method,
77
+ :body => body,
78
+ :headers => headers,
79
+ :path => path,
80
+ :params => params,
81
+ :options => options
82
+ }
83
+ end
84
+
85
+ def marshal_load(serialised)
86
+ self.method = serialised[:method]
87
+ self.body = serialised[:body]
88
+ self.headers = serialised[:headers]
89
+ self.path = serialised[:path]
90
+ self.params = serialised[:params]
91
+ self.options = serialised[:options]
92
+ end
93
+
72
94
  # ENV Keys
73
95
  # :method - a symbolized request method (:get, :post)
74
96
  # :body - the request body that will eventually be converted to a string.
@@ -10,7 +10,7 @@ module Faraday
10
10
  super(app)
11
11
  @logger = logger || begin
12
12
  require 'logger'
13
- ::Logger.new(STDOUT)
13
+ ::Logger.new($stdout)
14
14
  end
15
15
  @filter = []
16
16
  @options = DEFAULT_OPTIONS.merge(options)
@@ -5,12 +5,16 @@ module Faraday
5
5
  def on_complete(env)
6
6
  case env[:status]
7
7
  when 404
8
- raise Faraday::Error::ResourceNotFound, response_values(env)
8
+ raise Faraday::ResourceNotFound, response_values(env)
9
9
  when 407
10
10
  # mimic the behavior that we get with proxy requests with HTTPS
11
- raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
11
+ raise Faraday::ConnectionFailed.new(
12
+ %{407 "Proxy Authentication Required "},
13
+ response_values(env))
12
14
  when ClientErrorStatuses
13
- raise Faraday::Error::ClientError, response_values(env)
15
+ raise Faraday::ClientError, response_values(env)
16
+ when nil
17
+ raise Faraday::NilStatusError, response_values(env)
14
18
  end
15
19
  end
16
20
 
@@ -54,9 +54,9 @@ module Faraday
54
54
  !!env
55
55
  end
56
56
 
57
- def on_complete
58
- if not finished?
59
- @on_complete_callbacks << Proc.new
57
+ def on_complete(&block)
58
+ if !finished?
59
+ @on_complete_callbacks << block
60
60
  else
61
61
  yield(env)
62
62
  end
data/lib/faraday.rb CHANGED
@@ -14,7 +14,7 @@ require 'forwardable'
14
14
  # conn.get '/'
15
15
  #
16
16
  module Faraday
17
- VERSION = "0.15.0"
17
+ VERSION = "0.17.5"
18
18
 
19
19
  class << self
20
20
  # Public: Gets or sets the root path that Faraday is being loaded from.
@@ -64,8 +64,7 @@ module Faraday
64
64
  # :params => {:page => 1}
65
65
  #
66
66
  # Returns a Faraday::Connection.
67
- def new(url = nil, options = nil)
68
- block = block_given? ? Proc.new : nil
67
+ def new(url = nil, options = nil, &block)
69
68
  options = options ? default_connection_options.merge(options) : default_connection_options
70
69
  Faraday::Connection.new(url, options, &block)
71
70
  end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::DeprecatedClass do
4
+ class SampleClass < StandardError
5
+ attr_accessor :foo
6
+
7
+ def initialize(foo = nil)
8
+ @foo = foo || :foo
9
+ end
10
+ end
11
+
12
+ SampleDeprecatedClass = Faraday::DeprecatedClass.proxy_class(SampleClass)
13
+
14
+ it 'does not raise error for deprecated classes but prints an error message' do
15
+ error_message, foobar = with_warn_squelching { SampleDeprecatedClass.new(:foo_bar) }
16
+ expect(foobar).to be_a(SampleClass)
17
+ expect(foobar.foo).to eq(:foo_bar)
18
+ expect(error_message).to match(
19
+ Regexp.new(
20
+ 'NOTE: SampleDeprecatedClass.new is deprecated; '\
21
+ 'use SampleClass.new instead. It will be removed in or after version 1.0'
22
+ )
23
+ )
24
+ end
25
+
26
+ it 'does not raise an error for inherited error-namespaced classes but prints an error message' do
27
+ error_message, = with_warn_squelching { Class.new(SampleDeprecatedClass) }
28
+
29
+ expect(error_message).to match(
30
+ Regexp.new(
31
+ 'NOTE: Inheriting SampleDeprecatedClass is deprecated; '\
32
+ 'use SampleClass instead. It will be removed in or after version 1.0'
33
+ )
34
+ )
35
+ end
36
+
37
+ it 'allows backward-compatible class to be subclassed' do
38
+ expect {
39
+ with_warn_squelching { Class.new(SampleDeprecatedClass) }
40
+ }.not_to raise_error
41
+ end
42
+
43
+ it 'allows rescuing of a current error with a deprecated error' do
44
+ expect { raise SampleClass, nil }.to raise_error(SampleDeprecatedClass)
45
+ end
46
+
47
+ it 'allows rescuing of a current error with a current error' do
48
+ expect { raise SampleClass, nil }.to raise_error(SampleClass)
49
+ end
50
+
51
+ it 'allows rescuing of a deprecated error with a deprecated error' do
52
+ expect { raise SampleDeprecatedClass, nil }.to raise_error(SampleDeprecatedClass)
53
+ end
54
+
55
+ it 'allows rescuing of a deprecated error with a current error' do
56
+ expect { raise SampleDeprecatedClass, nil }.to raise_error(SampleClass)
57
+ end
58
+
59
+ describe 'match behavior' do
60
+ class SampleDeprecatedClassA < SampleDeprecatedClass; end
61
+ class SampleDeprecatedClassB < SampleDeprecatedClass; end
62
+
63
+ class SampleDeprecatedClassAX < SampleDeprecatedClassA; end
64
+
65
+ class SampleClassA < SampleClass; end
66
+
67
+ describe 'undeprecated class' do
68
+ it 'is === to instance of deprecated class' do
69
+ expect(SampleClass === SampleDeprecatedClass.new).to be true
70
+ end
71
+
72
+ it 'is === to instance of subclass of deprecated class' do
73
+ expect(SampleClass === SampleDeprecatedClassA.new).to be true
74
+ end
75
+
76
+ it 'is === to instance of subclass of subclass of deprecated class' do
77
+ expect(SampleClass === SampleDeprecatedClassAX.new).to be true
78
+ end
79
+ end
80
+
81
+ describe 'subclass of undeprecated class' do
82
+ it 'is not === to instance of undeprecated class' do
83
+ expect(SampleClassA === SampleClass.new).to be false
84
+ end
85
+
86
+ it 'is not === to instance of deprecated class' do
87
+ expect(SampleClassA === SampleDeprecatedClass.new).to be false
88
+ end
89
+ end
90
+
91
+ describe 'deprecated class' do
92
+ it 'is === to instance of undeprecated class' do
93
+ expect(SampleDeprecatedClass === SampleClass.new).to be true
94
+ end
95
+
96
+ it 'is === to instance of subclass of undeprecated class' do
97
+ expect(SampleDeprecatedClass === SampleClassA.new).to be true
98
+ end
99
+
100
+ it 'is === to instance of subclass of deprecated class' do
101
+ expect(SampleDeprecatedClass === SampleDeprecatedClassA.new).to be true
102
+ end
103
+
104
+ it 'is === to instance of subclass of subclass of deprecated class' do
105
+ expect(SampleDeprecatedClass === SampleDeprecatedClassAX.new).to be true
106
+ end
107
+ end
108
+
109
+ describe 'subclass of deprecated class' do
110
+ it 'is not === to instance of subclass of undeprecated class' do
111
+ expect(SampleDeprecatedClassA === SampleClass.new).to be false
112
+ end
113
+
114
+ it 'is not === to instance of another subclass of deprecated class' do
115
+ expect(SampleDeprecatedClassA === SampleDeprecatedClassB.new).to be false
116
+ end
117
+
118
+ it 'is === to instance of its subclass' do
119
+ expect(SampleDeprecatedClassA === SampleDeprecatedClassAX.new).to be true
120
+ end
121
+
122
+ it 'is === to instance of deprecated class' do
123
+ expect(SampleDeprecatedClass === SampleDeprecatedClassB.new).to be true
124
+ end
125
+ end
126
+
127
+ describe 'subclass of subclass of deprecated class' do
128
+ it 'is not === to instance of subclass of another subclass of deprecated class' do
129
+ expect(SampleDeprecatedClassAX === SampleDeprecatedClassB.new).to be false
130
+ end
131
+
132
+ it 'is not === to instance of its superclass' do
133
+ expect(SampleDeprecatedClassA === SampleDeprecatedClass.new).to be false
134
+ end
135
+ end
136
+ end
137
+
138
+ def with_warn_squelching
139
+ stderr_catcher = StringIO.new
140
+ original_stderr = $stderr
141
+ $stderr = stderr_catcher
142
+ result = yield if block_given?
143
+ [stderr_catcher.tap(&:rewind).string, result]
144
+ ensure
145
+ $stderr = original_stderr
146
+ end
147
+ end