/usr/lib/ruby/vendor_ruby/rspec/mocks/instance_method_stasher.rb is in ruby-rspec-mocks 3.5.0c3e0m0s0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | module RSpec
module Mocks
# @private
class InstanceMethodStasher
def initialize(object, method)
@object = object
@method = method
@klass = (class << object; self; end)
@original_method = nil
@method_is_stashed = false
end
attr_reader :original_method
if RUBY_VERSION.to_f < 1.9
# @private
def method_is_stashed?
@method_is_stashed
end
# @private
def stash
return if !method_defined_directly_on_klass? || @method_is_stashed
@klass.__send__(:alias_method, stashed_method_name, @method)
@method_is_stashed = true
end
# @private
def stashed_method_name
"obfuscated_by_rspec_mocks__#{@method}"
end
# @private
def restore
return unless @method_is_stashed
if @klass.__send__(:method_defined?, @method)
@klass.__send__(:undef_method, @method)
end
@klass.__send__(:alias_method, @method, stashed_method_name)
@klass.__send__(:remove_method, stashed_method_name)
@method_is_stashed = false
end
else
# @private
def method_is_stashed?
!!@original_method
end
# @private
def stash
return unless method_defined_directly_on_klass?
@original_method ||= ::RSpec::Support.method_handle_for(@object, @method)
@klass.__send__(:undef_method, @method)
end
# @private
def restore
return unless @original_method
if @klass.__send__(:method_defined?, @method)
@klass.__send__(:undef_method, @method)
end
handle_restoration_failures do
@klass.__send__(:define_method, @method, @original_method)
end
@original_method = nil
end
end
if RUBY_DESCRIPTION.include?('2.0.0p247') || RUBY_DESCRIPTION.include?('2.0.0p195')
# ruby 2.0.0-p247 and 2.0.0-p195 both have a bug that we can't work around :(.
# https://bugs.ruby-lang.org/issues/8686
def handle_restoration_failures
yield
rescue TypeError
RSpec.warn_with(
"RSpec failed to properly restore a partial double (#{@object.inspect}) " \
"to its original state due to a known bug in MRI 2.0.0-p195 & p247 " \
"(https://bugs.ruby-lang.org/issues/8686). This object may remain " \
"screwed up for the rest of this process. Please upgrade to 2.0.0-p353 or above.",
:call_site => nil, :use_spec_location_as_call_site => true
)
end
else
def handle_restoration_failures
# No known reasons for restoration to fail on other rubies.
yield
end
end
private
# @private
def method_defined_directly_on_klass?
method_defined_on_klass? && method_owned_by_klass?
end
# @private
def method_defined_on_klass?(klass=@klass)
MethodReference.method_defined_at_any_visibility?(klass, @method)
end
def method_owned_by_klass?
owner = @klass.instance_method(@method).owner
# On Ruby 2.0.0+ the owner of a method on a class which has been
# `prepend`ed may actually be an instance, e.g.
# `#<MyClass:0x007fbb94e3cd10>`, rather than the expected `MyClass`.
owner = owner.class unless Module === owner
# On some 1.9s (e.g. rubinius) aliased methods
# can report the wrong owner. Example:
# class MyClass
# class << self
# alias alternate_new new
# end
# end
#
# MyClass.owner(:alternate_new) returns `Class` when incorrect,
# but we need to consider the owner to be `MyClass` because
# it is not actually available on `Class` but is on `MyClass`.
# Hence, we verify that the owner actually has the method defined.
# If the given owner does not have the method defined, we assume
# that the method is actually owned by @klass.
owner == @klass || !(method_defined_on_klass?(owner))
end
end
end
end
|