SuperDiff Gem Version Build Status Downloads Hound

SuperDiff is a Ruby gem that intelligently displays the differences between two data structures of any type.

📢 See what's changed in the latest version (0.2.0).

Introduction

The primary motivation behind this gem is to replace RSpec's built-in diffing capabilities. Sometimes, whenever you use a matcher such as eq, match, include, or have_attributes, you will get a diff of the two data structures you are trying to match against. This is really helpful for strings, but not so helpful for other, more "real world" kinds of values, such as arrays, hashes, and full-scale objects. The reason this doesn't work is because all RSpec does is run your expected and actual values through Ruby's PrettyPrinter library and then perform a diff of these strings.

For instance, let's say you wanted to compare these two hashes:

actual = {
  customer: {
    person: SuperDiff::Test::Person.new(name: "Marty McFly, Jr.", age: 17),
    shipping_address: {
      line_1: "456 Ponderosa Ct.",
      city: "Hill Valley",
      state: "CA",
      zip: "90382"
    }
  },
  items: [
    {
      name: "Fender Stratocaster",
      cost: 100_000,
      options: ["red", "blue", "green"]
    },
    { name: "Mattel Hoverboard" }
  ]
}

expected = {
  customer: {
    person: SuperDiff::Test::Person.new(name: "Marty McFly", age: 17),
    shipping_address: {
      line_1: "123 Main St.",
      city: "Hill Valley",
      state: "CA",
      zip: "90382"
    }
  },
  items: [
    {
      name: "Fender Stratocaster",
      cost: 100_000,
      options: ["red", "blue", "green"]
    },
    { name: "Chevy 4x4" }
  ]
}

If, somewhere in a test, you were to say:

expect(actual).to eq(expected)

You would get output that looks like:

Before super_diff

Not great.

This library provides a diff engine that knows how to figure out the differences between any two data structures and display them in a sensible way. Using the example above, you'd get this instead:

After super_diff

Installation

Want to try out this gem for yourself? As with most development-related gems, there are a couple ways depending on your type of project:

Rails apps

If you're developing a Rails app, add the following to your Gemfile:

gem "super_diff"

After running bundle install, add the following to your rails_helper:

require "super_diff/rspec-rails"

You're done!

Libraries

If you're developing a library, add the following to your gemspec:

spec.add_development_dependency "super_diff"

Now add the following to your spec_helper:

require "super_diff/rspec"

You're done!

Configuration

As capable as this library is, it doesn't know how to deal with every kind of object out there. You might find it necessary to instruct the gem on how to diff your object. To do this, you can use a configuration block. Simply add this to your test helper file (either rails_helper or spec_helper):

SuperDiff::RSpec.configure do |config|
  config.add_extra_differ_class(YourDiffer)
  config.add_extra_operational_sequencer_class(YourOperationalSequencer)
  config.add_extra_diff_formatter_class(YourDiffFormatter)
end

(More info here in the future on adding a custom differ, operational sequencer, and diff formatter. Also explanations on what these are.)

Contributing

If you encounter a bug or have an idea for how this could be better, feel free to create an issue.

If you'd like to submit a PR instead, here's how to get started. First, fork this repo. Then, when you've cloned your fork, run:

bundle install

This will install various dependencies. After this, you can run all of the tests:

bundle exec rake

Or a single test:

bundle exec rspec spec/acceptance/...
bundle exec rspec spec/unit/...

Finally, submit your PR and I'll take a look at it when I get a chance.

Compatibility

super_diff is tested to work with Ruby >= 2.4.x, RSpec 3.x, and Rails >= 5.x.

Inspiration/Thanks

In developing this gem I made use of or was heavily inspired by these libraries:

Thank you so much!

© 2018-2019 Elliot Winkler, released under the MIT license.