Class: Matchi::BeAnInstanceOf
- Inherits:
-
Object
- Object
- Matchi::BeAnInstanceOf
- Defined in:
- lib/matchi/be_an_instance_of.rb
Overview
Type/class matcher with enhanced class checking.
This matcher aims to provide a more reliable way to check if an object is an exact instance of a specific class (not a subclass). While not foolproof, it uses a more robust method to get the actual class of an object that helps resist common attempts at type checking manipulation.
Instance Method Summary collapse
-
#initialize(expected) ⇒ BeAnInstanceOf
constructor
Initialize the matcher with (the name of) a class or module.
-
#match? ⇒ Boolean
Securely checks if the yielded object is an instance of the expected class.
-
#to_s ⇒ String
Returns a string representing the matcher.
Constructor Details
#initialize(expected) ⇒ BeAnInstanceOf
Initialize the matcher with (the name of) a class or module.
60 61 62 63 64 65 66 |
# File 'lib/matchi/be_an_instance_of.rb', line 60 def initialize(expected) @expected = String(expected) return if /\A[A-Z]/.match?(@expected) raise ::ArgumentError, "expected must start with an uppercase letter (got: #{@expected})" end |
Instance Method Details
#match? ⇒ Boolean
Securely checks if the yielded object is an instance of the expected class.
This method uses a specific Ruby reflection technique to get the true class of an object, bypassing potential method overrides:
-
::Object.instance_method(:class) retrieves the original, unoverridden ‘class’ method from the Object class
-
.bind_call(obj) binds this original method to our object and calls it, ensuring we get the real class regardless of method overrides
This approach is more reliable than obj.class because it uses Ruby’s method binding mechanism to call the original implementation directly. While not completely foolproof, it provides better protection against type check spoofing than using regular method calls which can be overridden.
94 95 96 97 98 99 |
# File 'lib/matchi/be_an_instance_of.rb', line 94 def match? raise ::ArgumentError, "a block must be provided" unless block_given? actual_class = ::Object.instance_method(:class).bind_call(yield) expected_class == actual_class end |
#to_s ⇒ String
Returns a string representing the matcher.
104 105 106 |
# File 'lib/matchi/be_an_instance_of.rb', line 104 def to_s "be an instance of #{@expected}" end |