The MismatchInspectable module provides a way to compare two objects and find the differences in their attributes. The module can be included in any class to compare objects of that class, and it provides options for the output format, recursion, and inclusion of class names in the output.
Usage
To use MismatchInspectable, first include it in your class and list the attributes you want to compare using the inspect_mismatch_for method.
class Thing
include MismatchInspectable
inspect_mismatch_for :color, :shape, :is_cool
def initialize(color, shape, is_cool)
@color = color
@shape = shape
@is_cool = is_cool
end
# Your class implementation
end
Then, to compare two objects of the class, call the inspect_mismatch method on one of the objects and pass the other object as an argument.
thing1 = Thing.new("red", "circle", true)
thing2 = Thing.new("blue", "circle", false)
mismatch = thing1.inspect_mismatch(thing2)
Options
format
You can choose from three different output formats: :array, :hash, or :object. The default format is :array.
• :array format example:
[
['Thing#color', 'red', 'blue'],
['Thing#is_cool', true, false]
]
• :hash format example:
{
'Thing#color' => ['red', 'blue'],
'Thing#is_cool' => [true, false]
}
:object format example:
{
Thing: {
color: ['red', 'blue'],
is_cool: [true, false]
}
}
include_class (default: true)
When this option is set to true, the comparison will include the class in the output for the objects being compared. If the objects being compared have different classes, a mismatch will always be reported, regardless of this flag being set. If set to false, you will simply not see the class names in the output.
recursive (default: false)
When this option is set to true, the comparison will be performed recursively on
all instance variables which are passed to inspect_mismatch_for. If any of the
instance variables are also objects that include the MismatchInspectable
module, their inspect_mismatch method will be called with the same options. If
set to false,the comparison will only be performed on the top-level instance
variables which are passed to inspect_mismatch_for and will not delve deeper
into the objects. Instead it will do a simple comparison of said instance
variables.
Examples
Example 1: Basic usage
require "mismatch_inspectable"
class Car
include MismatchInspectable
inspect_mismatch_for :make, :model, :year
def initialize(make, model, year)
@make = make
@model = model
@year = year
end
attr_accessor :make, :model, :year
end
car1 = Car.new("Toyota", "Camry", 2020)
car2 = Car.new("Toyota", "Corolla", 2020)
mismatches = car1.inspect_mismatch(car2)
# Output with default format: array
# [["Car#model", "Camry", "Corolla"]]
Example 2: Using different formats
mismatches_hash = car1.inspect_mismatch(car2, format: :hash)
# Output with format: hash
# {"Car#model" => ["Camry", "Corolla"]}
mismatches_object = car1.inspect_mismatch(car2, format: :object)
# Output with format: object
# {Car: {model: ["Camry", "Corolla"]}}
Example 3: Comparing nested objects
class Owner
include MismatchInspectable
inspect_mismatch_for :name, :age
def initialize(name, age)
@name = name
@age = age
end
attr_accessor :name, :age
end
class Pet
include MismatchInspectable
inspect_mismatch_for :name, :species, :owner
def initialize(name, species, owner)
@name = name
@species = species
@owner = owner
end
attr_accessor :name, :species, :owner
end
owner1 = Owner.new("Alice", 30)
owner2 = Owner.new("Bob", 35)
pet1 = Pet.new("Fluffy", "cat", owner1)
pet2 = Pet.new("Fluffy", "cat", owner2)
mismatches = pet1.inspect_mismatch(pet2, recursive: true)
# Output with recursive: true
# [["Pet#owner.Owner#name", "Alice", "Bob"], ["Pet#owner.Owner#age", 30, 35]]
Example 4: Excluding class from output
mismatches_no_class = pet1.inspect_mismatch(pet2, recursive: true, include_class: false)
# Output with include_class: false
# [["owner.name", "Alice", "Bob"], ["owner.age", 30, 35]]
Example 5: Comparing objects with recursive set to false
pet5 = Pet.new("Max", "dog", owner1)
pet6 = Pet.new("Max", "dog", owner2)
mismatches_non_recursive = pet5.inspect_mismatch(pet6, recursive: false)
# Output with recursive: false and non-nil owners
# [["Pet#owner", #<Owner:0x00007fe3d206d3c8 @name="Alice", @age=30>, #<Owner:0x00007fe3d207d3c8 @name="Bob", @age=35>]]
Example 6: Comparing objects when one is null
owner3 = Owner.new("Charlie", 40)
pet3 = Pet.new("Buddy", "dog", owner3)
pet4 = Pet.new("Buddy", "dog", nil)
mismatches_owner_nil = pet3.inspect_mismatch(pet4, recursive: true)
# Output with recursive: true and one nil owner
# [["Pet#owner", #<Owner:0x00007fe3d206d3c8 @name="Charlie", @age=40>, nil]]