3
3
[ version-badge ] : http://img.shields.io/gem/v/super_diff.svg
4
4
[ rubygems ] : http://rubygems.org/gems/super_diff
5
5
[ travis-badge ] : http://img.shields.io/travis/mcmire/super_diff/master.svg
6
- [ travis ] : http://travis-ci.org/mcmire/super_diff
7
6
[ downloads-badge ] : http://img.shields.io/gem/dtv/super_diff.svg
8
7
[ hound-badge ] : https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg
9
8
[ hound ] : https://houndci.com
10
9
11
- ## Concept
10
+ SuperDiff is a tool that displays the differences between two data structures of
11
+ any type in Ruby.
12
+
13
+ ## Introduction
12
14
13
- SuperDiff is a utility that helps you diff two complex data structures in Ruby
14
- and gives you helpful output to show you exactly how the two data structures
15
- differ.
15
+ The primary motivation behind this gem is to replace RSpec's built-in diffing
16
+ capabilities. Sometimes, whenever you use a matcher such as ` eq ` , ` match ` ,
17
+ ` include ` , or ` have_attributes ` , you will get a diff of the two data structures
18
+ you are trying to match against. This is really helpful for strings, but not so
19
+ helpful for other, more "real world" kinds of values, such as arrays, hashes,
20
+ and full-scale objects. The reason this doesn't work is because [ RSpec will
21
+ naively run your ` expected ` and ` actual ` values through Ruby's PrettyPrinter
22
+ library] [ rspec-differ-fail ] and then perform a diff of these strings.
16
23
17
- Let's say you have two hashes and you want to compare them. Perhaps your first
18
- hash looks like this:
24
+ For instance, let's say you wanted to compare these two hashes:
19
25
20
26
``` ruby
21
- expected = {
27
+ actual = {
22
28
customer: {
23
- name: " Marty McFly" ,
29
+ person: SuperDiff :: Test :: Person . new ( name: " Marty McFly, Jr. " , age: 17 ) ,
24
30
shipping_address: {
25
- line_1: " 123 Main St ." ,
31
+ line_1: " 456 Ponderosa Ct ." ,
26
32
city: " Hill Valley" ,
27
33
state: " CA" ,
28
- zip: " 90382" ,
29
- },
34
+ zip: " 90382"
35
+ }
30
36
},
31
37
items: [
32
38
{
33
39
name: " Fender Stratocaster" ,
34
40
cost: 100_000 ,
35
- options: [" red" , " blue" , " green" ],
41
+ options: [" red" , " blue" , " green" ]
36
42
},
37
- { name: " Chevy 4x4 " },
38
- ],
43
+ { name: " Mattel Hoverboard " }
44
+ ]
39
45
}
40
- ```
41
-
42
- and your second hash looks like this:
43
46
44
- ``` ruby
45
- actual = {
47
+ expected = {
46
48
customer: {
47
- name: " Marty McFly, Jr. " ,
49
+ person: SuperDiff :: Test :: Person . new ( name: " Marty McFly" , age: 17 ) ,
48
50
shipping_address: {
49
- line_1: " 456 Ponderosa Ct ." ,
51
+ line_1: " 123 Main St ." ,
50
52
city: " Hill Valley" ,
51
53
state: " CA" ,
52
- zip: " 90382" ,
53
- },
54
+ zip: " 90382"
55
+ }
54
56
},
55
57
items: [
56
58
{
57
59
name: " Fender Stratocaster" ,
58
60
cost: 100_000 ,
59
- options: [" red" , " blue" , " green" ],
61
+ options: [" red" , " blue" , " green" ]
60
62
},
61
- { name: " Mattel Hoverboard " },
62
- ],
63
+ { name: " Chevy 4x4 " }
64
+ ]
63
65
}
64
66
```
65
67
66
- If you want to know what the difference between them is , you could say:
68
+ If, somewhere in a test , you were to say:
67
69
68
70
``` ruby
69
- SuperDiff :: EqualityMatcher .call (expected, actual )
71
+ expect(actual).to eq (expected)
70
72
```
71
73
72
- This will give you the following string :
74
+ You would get output that looks like :
73
75
74
- ```
75
- Differing hashes.
76
-
77
- Expected: { customer: { name: "Marty McFly", shipping_address: { line_1: "123 Main St.", city: "Hill Valley", state: "CA", zip: "90382" } }, items: [{ name: "Fender Stratocaster", cost: 100000, options: ["red", "blue", "green"] }, { name: "Chevy 4x4" }] }
78
- Got: { customer: { name: "Marty McFly, Jr.", shipping_address: { line_1: "456 Ponderosa Ct.", city: "Hill Valley", state: "CA", zip: "90382" } }, items: [{ name: "Fender Stratocaster", cost: 100000, options: ["red", "blue", "green"] }, { name: "Mattel Hoverboard" }] }
79
-
80
- Diff:
81
-
82
- {
83
- customer: {
84
- - name: "Marty McFly",
85
- + name: "Marty McFly, Jr.",
86
- shipping_address: {
87
- - line_1: "123 Main St.",
88
- + line_1: "456 Ponderosa Ct.",
89
- city: "Hill Valley",
90
- state: "CA",
91
- zip: "90382"
92
- }
93
- },
94
- items: [
95
- {
96
- name: "Fender Stratocaster",
97
- cost: 100000,
98
- options: ["red", "blue", "green"]
99
- },
100
- {
101
- - name: "Chevy 4x4"
102
- + name: "Mattel Hoverboard"
103
- }
104
- ]
105
- }
106
- ```
76
+ ![ Before super_diff] ( doc/before_super_diff.png )
77
+
78
+ Not great.
107
79
108
- When printed to a terminal, this will display in color, so the "expected" value
109
- in the summary and deleted lines in the diff will appear in red, while the
110
- "actual" value in the summary and inserted lines in the diff will appear in
111
- green.
80
+ This library provides a sophisticated set of comparators that know how to
81
+ intelligent compute the differences between two data structures and display them
82
+ in a way that makes sense. Using the example above, you'd get this instead:
112
83
113
- By the way, SuperDiff doesn't just work with hashes, but arrays as well as other
114
- objects, too!
84
+ ![ After super_diff] ( doc/after_super_diff.png )
115
85
116
- ## Usage
86
+ [ rspec-differ-fail ] : https://github.com/rspec/rspec-support/blob/c69a231d7369dd165ad7ce4742e1a2e21e3462b5/lib/rspec/support/differ.rb#L178
117
87
118
- There are two ways to use this gem. One way is to use the API methods that this
119
- gem provides, such as the method presented above.
88
+ ## Installation
120
89
121
- However, this gem was really designed for use specifically with RSpec. In recent
122
- years, RSpec has added a feature where if you're comparing two objects in a test
123
- and your test fails, you will see a diff between those objects (provided the
124
- objects are large enough). However, this diff is not always the most helpful.
125
- It's very common when writing tests for API endpoints to work with giant JSON
126
- hashes, and RSpec's diffs are not sufficient in highlighting changes between
127
- such structures. Therefore, this gem provides an integration layer where you can
128
- replace RSpec's differ with SuperDiff.
90
+ Want to try out this gem for yourself? As with most development-related gems,
91
+ there are a couple ways depending on your type of project:
129
92
130
- To get started, add the gem to your Gemfile under the ` test ` group:
93
+ ### Rails apps
94
+
95
+ If you're developing a Rails app, add the following to your Gemfile:
131
96
132
97
``` ruby
133
98
gem " super_diff"
134
99
```
135
100
136
- Then, open up ` spec_helper ` and add this line somewhere :
101
+ After running ` bundle install ` , add the following to your ` rails_helper ` :
137
102
138
103
``` ruby
139
104
require " super_diff/rspec"
140
105
```
141
106
142
- Now try writing a test using ` eq ` to compare two large data structures, and you
143
- should see a diff similar to the one given above.
107
+ You're done!
108
+
109
+ ### Libraries
110
+
111
+ If you're developing a library, add the following to your gemspec:
112
+
113
+ ``` ruby
114
+ spec.add_development_dependency " super_diff"
115
+ ```
116
+
117
+ Now add the following to your ` spec_helper ` :
118
+
119
+ ``` ruby
120
+ require " super_diff/rspec"
121
+ ```
122
+
123
+ You're done!
124
+
125
+ ## Configuration
126
+
127
+ As capable as this library is, it doesn't know how to deal with every kind of
128
+ object out there. You might find it necessary to instruct the gem on how to diff
129
+ your object. To do this, you can use a configuration block. Simply add this to
130
+ your test helper file (either ` rails_helper ` or ` spec_helper ` ):
131
+
132
+ ``` ruby
133
+ SuperDiff ::RSpec .configure do |config |
134
+ config.extra_differ_classes << YourDiffer
135
+ config.extra_operational_sequencer_classes << YourOperationalSequencer
136
+ config.extra_diff_formatter_classes << YourDiffFormatter
137
+ end
138
+ ```
139
+
140
+ * (More info here in the future on adding a custom differ, operational sequencer,
141
+ and diff formatter. Also explanations on what these are.)*
144
142
145
143
## Contributing
146
144
147
- If you encounter a bug or have an idea for how this could be better, I'm all
148
- ears! Feel free to create an issue.
145
+ If you encounter a bug or have an idea for how this could be better, feel free
146
+ to create an issue.
149
147
150
148
If you'd like to submit a PR instead, here's how to get started. First, fork
151
149
this repo and then run:
@@ -169,6 +167,13 @@ bundle exec rspec spec/unit/...
169
167
170
168
Finally, submit your PR and I'll take a look at it when I get a chance.
171
169
170
+ ## Compatibility
171
+
172
+ ` super_diff ` is [ tested] [ travis ] to work with RSpec 3.x, Ruby >= 2.4.x, and
173
+ JRuby >= 9.2.x.
174
+
175
+ [ travis ] : http://travis-ci.org/mcmire/super_diff
176
+
172
177
## Copyright/License
173
178
174
- © 2018 Elliot Winkler, released under the [ MIT license] ( LICENSE ) .
179
+ © 2018-2019 Elliot Winkler, released under the [ MIT license] ( LICENSE ) .
0 commit comments