specdiff 0.3.0.rc2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/DEVELOPMENT.md +74 -0
- data/README.md +139 -98
- data/glossary.txt +4 -0
- data/lib/specdiff/differ/hash.rb +5 -0
- data/lib/specdiff/hashprint.rb +36 -29
- data/lib/specdiff/rspec.rb +2 -0
- data/lib/specdiff/version.rb +1 -1
- data/lib/specdiff/webmock.rb +1 -0
- data/lib/specdiff.rb +0 -5
- data/specdiff.gemspec +11 -3
- metadata +17 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16d43f0ff6248844478dc69d99ebb9e5de1212804fba96b859d947e446e5fae7
|
4
|
+
data.tar.gz: 0c9e973795920664617d2c57211e40569a0aee10ee6b6c35b02680a6789edf2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a21ca995b7418a69deaeb6c024f40b2fc6342200edc33f4179f979ce7555bf346b29012184784b59f0736ac55b089a55836dd21756e14100d7a76260b5c7d69a
|
7
|
+
data.tar.gz: e457b0266ddc5f11df693baae9594dd790498e687ce7a4d263b9b291108af2a14f976499dd3b1eee9294a6827e2f15f527c0ae451035c8f73dc2dbaea9245f2d
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.3.0] - 2024-04-16
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
|
14
|
+
- Hashprint now sorts keys (if all the keys are strings or symbols), leading to better text diffs from the hash differ.
|
15
|
+
|
10
16
|
## [0.3.0.rc2] - 2024-04-05
|
11
17
|
|
12
18
|
### Changed
|
data/DEVELOPMENT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Development
|
2
|
+
|
3
|
+
## Glossary
|
4
|
+
|
5
|
+
Check out the [glossary](./glossary.txt) to make sure we are using the same
|
6
|
+
words for things.
|
7
|
+
|
8
|
+
## Setup
|
9
|
+
|
10
|
+
Install the software versions specified in `.tool-versions`.
|
11
|
+
|
12
|
+
Run `bin/setup` to install dependencies. Then, run `bundle exec rake` to run
|
13
|
+
the tests and linter and make sure they're green
|
14
|
+
before starting to make your changes.
|
15
|
+
|
16
|
+
Run `bundle exec rake -AD` for a full list of all the available tasks you may use for development purposes.
|
17
|
+
|
18
|
+
Run `bundle exec rake` to run the tests and linter.
|
19
|
+
|
20
|
+
## Examples
|
21
|
+
|
22
|
+
The `examples/` directory is used as an ad-hoc integration testing method.
|
23
|
+
[Read more here](./examples/)
|
24
|
+
|
25
|
+
## Pull request checklist
|
26
|
+
|
27
|
+
- [ ] Make sure the tests are passing
|
28
|
+
- [ ] Make sure the linter is happy
|
29
|
+
- [ ] Make sure the `examples/` look the same or have suffered and improvement
|
30
|
+
- [ ] Update the unreleased section of the [changelog](./CHANGELOG.md) with a human readable explanation of your changes
|
31
|
+
|
32
|
+
## Architecture
|
33
|
+
|
34
|
+
High level description of the heuristic specdiff implements
|
35
|
+
|
36
|
+
1. receive 2 pieces of data: `a` and `b`
|
37
|
+
2. determine types for `a` and `b`
|
38
|
+
1. test against plugin types
|
39
|
+
2. test against built in types
|
40
|
+
3. fall back to the `:unknown` type
|
41
|
+
3. determine which differ is appropriate for the types
|
42
|
+
1. test against plugin differs
|
43
|
+
2. test against built in differs
|
44
|
+
3. fall back to the null differ (`NotFound`)
|
45
|
+
7. run the selected differ with a and b
|
46
|
+
8. package it into a `::Specdiff::Diff` which records the detected types
|
47
|
+
|
48
|
+
\<time passes>
|
49
|
+
|
50
|
+
6. at some point later when `#to_s` is invoked, stringify the diff using the differ's `#stringify`
|
51
|
+
|
52
|
+
## Maintainer's notes
|
53
|
+
|
54
|
+
### Release procedure
|
55
|
+
|
56
|
+
- [ ] unit tests are passing (`$ bundle exec rake test`)
|
57
|
+
- [ ] linter is happy (`$ bundle exec rake lint`)
|
58
|
+
- [ ] `examples/` look good
|
59
|
+
- [ ] check the package size using `$ bundle exec inspect_build`, make sure you haven't added any large files by accident
|
60
|
+
- [ ] update the version number in `version.rb`
|
61
|
+
- [ ] make sure the `examples/` `Gemfile.lock` files are updated (run bundle install)
|
62
|
+
- [ ] make sure `Gemfile.lock` is updated (run bundle install)
|
63
|
+
- [ ] move unreleased changes to the next version in the [changelog](./CHANGELOG.md)
|
64
|
+
- [ ] commit in the form "vX.X.X" and push
|
65
|
+
- [ ] make sure the pipeline is green
|
66
|
+
- [ ] `$ bundle exec rake release`
|
67
|
+
|
68
|
+
### Contemplated improvements (AKA the todo list)
|
69
|
+
|
70
|
+
- [ ] word diff
|
71
|
+
- [ ] yard documentation?
|
72
|
+
- [ ] 2.7.0 support
|
73
|
+
- [ ] actual integration tests (replacing `examples/`)
|
74
|
+
- [ ] real documentation for the plugin interface
|
data/README.md
CHANGED
@@ -1,36 +1,40 @@
|
|
1
1
|
# Specdiff
|
2
2
|
|
3
|
-
|
3
|
+
Specdiff is an opinionated gem that provides diffing between arbitrary data. It
|
4
|
+
was built in an effort to improve [WebMock](https://rubygems.org/gems/webmock)'s
|
5
|
+
and [RSpec](https://rubygems.org/gems/rspec)'s diff output, and
|
6
|
+
comes with integrations for both. It produces output that looks very similiar to
|
7
|
+
RSpec, but with better support for nested hash/array structures.
|
4
8
|
|
5
|
-
|
6
|
-
|
7
|
-
if they happen to both be json (including setting content type). This gem aims
|
8
|
-
to bring text diffing (ala rspec) to webmock via monkey-patch, as well as
|
9
|
-
dropping the content type requirement.
|
9
|
+
By default, specdiff will produce diff output for multiline text by using
|
10
|
+
[diff-lcs](https://rubygems.org/gems/diff-lcs):
|
10
11
|
|
11
|
-
|
12
|
-
diff between them.
|
12
|
+
![example of multiline text](assets/specdiff_multiline_text_diff_example.png)
|
13
13
|
|
14
|
-
|
14
|
+
It also diffs hashes and arrays:
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
diff
|
16
|
+
| ![img](assets/specdiff_hashdiff_diff_example.png) | ![img](assets/specdiff_text_based_hash_diff_example.png) |
|
17
|
+
| --- | --- |
|
18
|
+
| Hashdiff based hash diff | Text based hash diff |
|
19
19
|
|
20
|
-
|
20
|
+
Specdiff will automatically switch between these two types of hash/array diff
|
21
|
+
output depending on what it thinks is more readable. The first type of output
|
22
|
+
showcased here comes from the
|
23
|
+
[hashdiff](https://rubygems.org/gems/hashdiff) gem, one of specdiff's
|
24
|
+
dependencies. The other is the *text diff* run on the output of *hashprint*.
|
25
|
+
Specdiff switches to using hashprint/text diff when it estimates that a lot of
|
26
|
+
the keys changed names, which is a point of weakness for hashdiff's output.
|
21
27
|
|
22
|
-
|
23
|
-
even if the request did not have the content type header:
|
24
|
-
|
25
|
-
![d](./assets/webmock_json_with_specdiff.png)
|
26
|
-
|
27
|
-
(The output of the json diff is experimental, feedback would be great!)
|
28
|
+
## Installation
|
28
29
|
|
29
|
-
|
30
|
+
### Requirements
|
30
31
|
|
31
|
-
|
32
|
+
Specdiff is tested to work with:
|
33
|
+
- Ruby `>= 3.0`.
|
34
|
+
- RSpec `3.13.0`, `3.12.2`, `3.12.0`.
|
35
|
+
- WebMock `3.19.1`, `3.18.1`.
|
32
36
|
|
33
|
-
|
37
|
+
### Use bundler
|
34
38
|
|
35
39
|
Add this line to your application's Gemfile:
|
36
40
|
|
@@ -40,122 +44,159 @@ gem "specdiff", require: false
|
|
40
44
|
|
41
45
|
And then execute:
|
42
46
|
|
43
|
-
|
44
|
-
|
45
|
-
Or install it yourself as:
|
47
|
+
`$ bundle install`
|
46
48
|
|
47
|
-
|
49
|
+
### Loading the gem and its integrations
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
Put the following in your `spec_helper.rb`. (Or equivalent initializer
|
52
|
-
for test environment) You probably don't want to load/use this gem in a release
|
53
|
-
environment.
|
51
|
+
Put the following in the initializer for your test environment (`spec_helper.rb`):
|
54
52
|
|
55
53
|
```rb
|
56
|
-
#
|
57
|
-
|
58
|
-
require "specdiff"
|
59
|
-
|
54
|
+
require "specdiff" # may be unneccessary if you're using bundler to load your gems
|
55
|
+
require "specdiff/rspec" # optional, enables RSpec integration
|
56
|
+
require "specdiff/webmock" # optional, enables WebMock integration
|
57
|
+
Specdiff.load!(:json) # optional, automatically detects json and uses the hash differ on it
|
60
58
|
|
61
|
-
# optionally, you can turn off terminal colors
|
62
59
|
Specdiff.configure do |config|
|
63
|
-
config.colorize = true
|
60
|
+
config.colorize = true # toggles color output
|
64
61
|
end
|
65
62
|
```
|
66
63
|
|
64
|
+
The monkey-patches should go after the gems they are patching.
|
65
|
+
|
66
|
+
*This gem is intended for use in test environments, not production or release environments.*
|
67
|
+
|
68
|
+
## Usage
|
69
|
+
|
70
|
+
Specdiff has two integrations: [WebMock](https://rubygems.org/gems/webmock) and
|
71
|
+
[RSpec](https://rubygems.org/gems/rspec). These are the main way specdiff is
|
72
|
+
intended to be used.
|
73
|
+
|
74
|
+
### RSpec
|
75
|
+
|
76
|
+
The RSpec integration improves on RSpec's built in diffing functionality by
|
77
|
+
diffing nested hash/array structures with
|
78
|
+
[hashdiff](https://rubygems.org/gems/hashdiff). This produces clearer
|
79
|
+
output when deeply nested structures are involved:
|
80
|
+
|
81
|
+
| ![img](assets/source_hashdiff_hash.png) | ![img](assets/rspecs_hashdiff_hash.png) | ![img](assets/specdiffs_hashdiff_hash.png) |
|
82
|
+
| --- | --- | --- |
|
83
|
+
| Test source | RSpec's diff | Specdiff's diff |
|
84
|
+
|
85
|
+
In some cases specdiff may produce a text-based diff of deeply nested hashes or
|
86
|
+
arrays instead. This also represents an improvement over RSpec's text-based diff
|
87
|
+
of nested hashes/arrays, by virtue of custom pretty-printing code designed for
|
88
|
+
the text differ to work on:
|
89
|
+
|
90
|
+
| ![img](assets/source_text_hash.png) | ![img](assets/rspecs_text_hash.png) | ![img](assets/specdiffs_text_hash.png) |
|
91
|
+
| --- | --- | --- |
|
92
|
+
| Test source | RSpec's diff | Specdiff's diff |
|
93
|
+
|
94
|
+
The RSpec integration also prevents RSpec from truncating your data before
|
95
|
+
printing it (by replacing the inspect implementation), avoiding the necessity
|
96
|
+
of a diff in some instances:
|
97
|
+
|
98
|
+
| ![img](assets/rspec_truncating.png) | ![img](assets/specdiff_no_truncating.png) |
|
99
|
+
| --- | --- |
|
100
|
+
| RSpec truncating your data | Specdiff preventing truncation |
|
101
|
+
|
102
|
+
(Although this is an instance where a "word diff" would be more helpful)
|
103
|
+
|
67
104
|
### WebMock
|
68
105
|
|
69
|
-
|
70
|
-
|
106
|
+
WebMock already ships with a dependency on
|
107
|
+
[hashdiff](https://rubygems.org/gems/hashdiff), providing diffs of json request
|
108
|
+
stubs. Specdiff prints hashdiff's output differently, and does not require the
|
109
|
+
content type to be specified:
|
71
110
|
|
72
|
-
|
111
|
+
(This requires you to enable the json plugin)
|
73
112
|
|
74
|
-
|
113
|
+
| ![img](assets/webmock_json_diff_source.png) | ![img](assets/webmock_json_diff.png) | ![img](assets/webmock_json_diff_specdiff.png) |
|
114
|
+
| --- | --- | --- |
|
115
|
+
| Source | WebMock | Specdiff |
|
75
116
|
|
76
|
-
|
77
|
-
diff = Specdiff.diff(something, and_something_else)
|
117
|
+
With specdiff enabled you also get text diffs where previously there were none:
|
78
118
|
|
79
|
-
|
80
|
-
|
81
|
-
|
119
|
+
| ![img](assets/webmock_newlines_diff_source.png) | ![img](assets/webmock_newlines_diff.png) | ![img](assets/webmock_newlines_diff_specdiff.png) |
|
120
|
+
| --- | --- | --- |
|
121
|
+
| Source | WebMock | Specdiff |
|
82
122
|
|
83
|
-
|
123
|
+
The WebMock integration continues to respect the `show_body_diff` setting in
|
124
|
+
WebMock:
|
84
125
|
|
85
126
|
```rb
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
Specdiff.load!(MyCustomType)
|
127
|
+
# this will cause diffs to not be produced, regardless of whether specdiff is
|
128
|
+
# loaded. body diffs are enabled by default in WebMock so you don't need to
|
129
|
+
# touch this.
|
130
|
+
WebMock.hide_body_diff!
|
91
131
|
```
|
92
132
|
|
93
|
-
|
133
|
+
### Direct usage
|
134
|
+
|
135
|
+
It is also possible to call into specdiff with arbitrary data.
|
136
|
+
This is essentially what the integrations do for you.
|
137
|
+
This is suitable if you are developing a library and intend to depend on
|
138
|
+
specdiff for diff output.
|
94
139
|
|
95
|
-
|
140
|
+
```rb
|
141
|
+
# Generate a diff, using all plugins available.
|
142
|
+
diff = Specdiff.diff(something, anything)
|
96
143
|
|
97
|
-
|
98
|
-
|
144
|
+
diff.empty? # => true/false, if true you probably don't want to actually show the diff
|
145
|
+
diff.to_s # => a String for showing to a developer who may or may not be scratching their head
|
99
146
|
|
100
|
-
|
147
|
+
# Generate an indented, pretty-printed string representation of a ruby hash.
|
148
|
+
printed_hash = Specdiff.hashprint(my_big_nested_hash)
|
149
|
+
printed_hash # => String
|
150
|
+
|
151
|
+
# Inspect something, but with prettier output for certain classes
|
152
|
+
# (Time/DateTime/BigDecimal). This is not indented. Usually defers to #inspect.
|
153
|
+
specdiff_inspected = Specdiff.diff_inspect(something)
|
154
|
+
specdiff_inspected # => String
|
155
|
+
```
|
101
156
|
|
102
|
-
|
157
|
+
Any methods or properties not documented here are considered private
|
158
|
+
implementation details.
|
103
159
|
|
104
|
-
|
160
|
+
## Plugins
|
105
161
|
|
106
|
-
|
162
|
+
It is possible to create and load plugins into specdiff to customize Specdiff's
|
163
|
+
behaviour. This was implemented in case you have special needs (e.g. diffing
|
164
|
+
things other than text, hashes, arrays and json).
|
107
165
|
|
108
|
-
|
166
|
+
### JSON
|
109
167
|
|
110
|
-
|
168
|
+
The built-in json plugin is optional, and loaded like so:
|
111
169
|
|
112
|
-
|
170
|
+
```rb
|
171
|
+
Specdiff.load!(:json)
|
172
|
+
```
|
113
173
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
2. test against built in types
|
118
|
-
3. fall back to the `:unknown` type
|
119
|
-
3. determine which differ is appropriate for the types
|
120
|
-
1. test against plugin differs
|
121
|
-
2. test against built in differs
|
122
|
-
3. fall back to the null differ (`NotFound`)
|
123
|
-
7. run the selected differ with a and b
|
124
|
-
8. package it into a `::Specdiff::Diff` which records the detected types
|
174
|
+
The JSON plugin attempts to parse strings into json using `JSON.parse`. If
|
175
|
+
successful, it considers that string a json, and will use the parse result as if
|
176
|
+
it had been passed directly to specdiff in the first place.
|
125
177
|
|
126
|
-
|
178
|
+
### Defining your own plugins
|
127
179
|
|
128
|
-
|
180
|
+
While other plugins are loaded by simply passing them to `::load!`:
|
129
181
|
|
130
|
-
|
182
|
+
```rb
|
183
|
+
class MySpecdiffPlugin
|
184
|
+
# Read the source code to figure out how plugins work. Sorry.
|
185
|
+
end
|
131
186
|
|
132
|
-
|
187
|
+
Specdiff.load!(MySpecdiffPlugin)
|
188
|
+
```
|
133
189
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
- [ ] check the package size using `$ bundle exec inspect_build`, make sure you haven't added any large files by accident
|
138
|
-
- [ ] update the version number in `version.rb`
|
139
|
-
- [ ] make sure the `examples/` `Gemfile.lock` files are updated (run bundle install)
|
140
|
-
- [ ] make sure `Gemfile.lock` is updated (run bundle install)
|
141
|
-
- [ ] move unreleased changes to the next version in the [changelog](./CHANGELOG.md)
|
142
|
-
- [ ] commit in the form "vX.X.X" and push
|
143
|
-
- [ ] make sure the pipeline is green
|
144
|
-
- [ ] `$ bundle exec rake release`
|
190
|
+
This was intended to allow implementing (potentially janky and inefficient)
|
191
|
+
plugins to help diff XML, but in practice the text differ was good enough for
|
192
|
+
diffing indented XML.
|
145
193
|
|
146
194
|
## Contributing
|
147
195
|
|
196
|
+
Read [DEVELOPMENT.md](./DEVELOPMENT.md) for current development practices.
|
197
|
+
|
148
198
|
Bug reports and pull requests are welcome on GitHub at https://github.com/odinhb/specdiff.
|
149
199
|
|
150
200
|
## License
|
151
201
|
|
152
202
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
153
|
-
|
154
|
-
## TODO
|
155
|
-
|
156
|
-
This documents potential improvements/issues I know about or have thought about.
|
157
|
-
|
158
|
-
- [ ] test the webmock monkey-patch. currently there is an empty webmock_spec.rb (should we do this using rspec?) and the examples/ directory contains a few webmock examples (which are a good idea to run before releasing) but it would be nice to have the pipeline fail if it doesn't work for whatever reason
|
159
|
-
- [ ] finalize plugin interface (are the methods named intuitively? should we split type detector definitions and differ definitions?)
|
160
|
-
- [ ] document how to define a plugin properly (instead of just linking to the source code)
|
161
|
-
- [ ] is the stringification of hashdiff's output really better than pretty print? or just more wordy? (the colors are definitely nice)
|
data/glossary.txt
CHANGED
@@ -44,3 +44,7 @@ side
|
|
44
44
|
compare
|
45
45
|
the procedure that implements the main function of specdiff including
|
46
46
|
accounting for any plugin types and differs
|
47
|
+
|
48
|
+
integration
|
49
|
+
refers to the provided monkey-patches and conscious relationship between
|
50
|
+
specdiff and another gem or piece of software it was intended to work with.
|
data/lib/specdiff/differ/hash.rb
CHANGED
@@ -15,8 +15,13 @@ class Specdiff::Differ::Hash
|
|
15
15
|
# array_path: true returns the path as an array, which differentiates
|
16
16
|
# between symbol keys and string keys in hashes, while the string
|
17
17
|
# representation does not.
|
18
|
+
|
18
19
|
# hmm it really seems like use_lcs: true gives much less human-readable
|
19
20
|
# (human-comprehensible) output when arrays are involved.
|
21
|
+
|
22
|
+
# use_lcs: true may also cause Hashdiff to use a lot of memory when BIG
|
23
|
+
# arrays are involved: https://github.com/liufengyun/hashdiff/issues/49
|
24
|
+
# so we might as well avoid that problem altogether.
|
20
25
|
hashdiff_diff = ::Hashdiff.diff(
|
21
26
|
a.value, b.value,
|
22
27
|
array_path: true,
|
data/lib/specdiff/hashprint.rb
CHANGED
@@ -17,7 +17,7 @@ class Specdiff::Hashprint
|
|
17
17
|
@indentation_level = 0
|
18
18
|
@indentation_per_level = SPACE * INDENTATION_SPACES
|
19
19
|
@indent = ""
|
20
|
-
@
|
20
|
+
@next_value_is_hash_value = false
|
21
21
|
|
22
22
|
@output = StringIO.new
|
23
23
|
|
@@ -42,15 +42,15 @@ private
|
|
42
42
|
recalculate_indent
|
43
43
|
end
|
44
44
|
|
45
|
-
def
|
46
|
-
@
|
45
|
+
def next_value_is_hash_value
|
46
|
+
@next_value_is_hash_value = true
|
47
47
|
|
48
48
|
nil
|
49
49
|
end
|
50
50
|
|
51
|
-
def
|
52
|
-
if @
|
53
|
-
@
|
51
|
+
def outputting_hash_value?
|
52
|
+
if @next_value_is_hash_value
|
53
|
+
@next_value_is_hash_value = false
|
54
54
|
true
|
55
55
|
else
|
56
56
|
false
|
@@ -89,33 +89,34 @@ private
|
|
89
89
|
COLON = ":".freeze
|
90
90
|
|
91
91
|
def output_hash(hash)
|
92
|
-
@output << @indent unless
|
92
|
+
@output << @indent unless outputting_hash_value?
|
93
93
|
|
94
94
|
@output << HASH_OPEN
|
95
95
|
@output << NEWLINE
|
96
96
|
|
97
97
|
increase_indentation
|
98
98
|
track_recursion(hash) do
|
99
|
-
hash
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
99
|
+
try_to_sort(hash)
|
100
|
+
.each do |key, value|
|
101
|
+
@output << @indent
|
102
|
+
|
103
|
+
if key.is_a?(Symbol)
|
104
|
+
@output << key
|
105
|
+
@output << COLON
|
106
|
+
@output << SPACE
|
107
|
+
else
|
108
|
+
@output << ::Specdiff.diff_inspect(key)
|
109
|
+
@output << SPACE
|
110
|
+
@output << HASHROCKET
|
111
|
+
@output << SPACE
|
112
|
+
end
|
113
|
+
|
114
|
+
next_value_is_hash_value
|
115
|
+
output(value)
|
116
|
+
|
117
|
+
@output << COMMA
|
118
|
+
@output << NEWLINE
|
111
119
|
end
|
112
|
-
|
113
|
-
skip_next_opening_indent
|
114
|
-
output(value)
|
115
|
-
|
116
|
-
@output << COMMA
|
117
|
-
@output << NEWLINE
|
118
|
-
end
|
119
120
|
end
|
120
121
|
decrease_indentation
|
121
122
|
|
@@ -123,11 +124,17 @@ private
|
|
123
124
|
@output << HASH_CLOSE
|
124
125
|
end
|
125
126
|
|
127
|
+
def try_to_sort(hash)
|
128
|
+
return hash unless hash.keys.all? { |k| String === k || Symbol === k }
|
129
|
+
|
130
|
+
hash.sort_by { |k, _v| k.to_s }
|
131
|
+
end
|
132
|
+
|
126
133
|
ARRAY_OPEN = "[".freeze
|
127
134
|
ARRAY_CLOSE = "]".freeze
|
128
135
|
|
129
136
|
def output_array(array)
|
130
|
-
@output << @indent unless
|
137
|
+
@output << @indent unless outputting_hash_value?
|
131
138
|
|
132
139
|
@output << ARRAY_OPEN
|
133
140
|
@output << NEWLINE
|
@@ -147,7 +154,7 @@ private
|
|
147
154
|
end
|
148
155
|
|
149
156
|
def output_unknown(thing)
|
150
|
-
@output << @indent unless
|
157
|
+
@output << @indent unless outputting_hash_value?
|
151
158
|
|
152
159
|
@output << ::Specdiff.diff_inspect(thing)
|
153
160
|
end
|
@@ -157,7 +164,7 @@ private
|
|
157
164
|
STANDARD_INSPECT_RECURSIVE_HASH = "{...}".freeze
|
158
165
|
|
159
166
|
def output_deja_vu(thing)
|
160
|
-
@output << @indent unless
|
167
|
+
@output << @indent unless outputting_hash_value?
|
161
168
|
|
162
169
|
case thing
|
163
170
|
when Array
|
data/lib/specdiff/rspec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
raise "rspec must be required before specdiff/rspec!" unless defined?(RSpec)
|
2
2
|
raise "RSpec::Support is missing????" unless defined?(RSpec::Support)
|
3
3
|
|
4
|
+
# https://github.com/rspec/rspec-support/blob/v3.13.1/lib/rspec/support/differ.rb
|
4
5
|
class RSpec::Support::Differ
|
5
6
|
alias old_diff diff
|
6
7
|
|
@@ -16,6 +17,7 @@ end
|
|
16
17
|
|
17
18
|
# This stops rspec from truncating strings w/ ellipsis, as well as making the
|
18
19
|
# "inspect" output consistent with specdiff's.
|
20
|
+
# https://github.com/rspec/rspec-support/blob/v3.13.1/lib/rspec/support/object_formatter.rb
|
19
21
|
class RSpec::Support::ObjectFormatter
|
20
22
|
def format(object)
|
21
23
|
::Specdiff.diff_inspect(object)
|
data/lib/specdiff/version.rb
CHANGED
data/lib/specdiff/webmock.rb
CHANGED
data/lib/specdiff.rb
CHANGED
@@ -6,19 +6,14 @@ require_relative "specdiff/hashprint"
|
|
6
6
|
require_relative "specdiff/compare"
|
7
7
|
|
8
8
|
module Specdiff
|
9
|
-
# Compare two things, returns a Specdiff::Diff.
|
10
9
|
def self.diff(...)
|
11
10
|
::Specdiff::Compare.call(...)
|
12
11
|
end
|
13
12
|
|
14
|
-
# Use Specdiff's implementation for turning a nested hash/array structure
|
15
|
-
# into a string. Optimized for diff quality.
|
16
13
|
def self.hashprint(...)
|
17
14
|
::Specdiff::Hashprint.call(...)
|
18
15
|
end
|
19
16
|
|
20
|
-
# Use Specdiff's inspect, which has some extra logic layered in for
|
21
|
-
# dates/time/bigdecimal. For most objects this just delegates to #inspect.
|
22
17
|
def self.diff_inspect(...)
|
23
18
|
::Specdiff::Inspect.call(...)
|
24
19
|
end
|
data/specdiff.gemspec
CHANGED
@@ -6,10 +6,18 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = "specdiff"
|
7
7
|
spec.version = Specdiff::VERSION
|
8
8
|
spec.authors = ["Odin Heggvold Bekkelund"]
|
9
|
-
spec.email = ["
|
9
|
+
spec.email = ["odin.heggvold.bekkelund@dev.dodo.no"]
|
10
10
|
|
11
|
-
spec.summary = "Improved
|
12
|
-
spec.
|
11
|
+
spec.summary = "Improved diffing for WebMock and RSpec"
|
12
|
+
spec.description = <<~TXT
|
13
|
+
Specdiff aims to improve both RSpec's and WebMock's diffing by applying \
|
14
|
+
opinionated heuristics, and comes with integrations (monkey-patches) for \
|
15
|
+
both. Particularly noteworthy improvements are made to working with deeply \
|
16
|
+
nested hash/array structures in RSpec, and plaintext/xml request bodies in \
|
17
|
+
WebMock.
|
18
|
+
TXT
|
19
|
+
|
20
|
+
spec.homepage = "https://github.com/dodoas/specdiff"
|
13
21
|
spec.license = "MIT"
|
14
22
|
spec.required_ruby_version = ">= 3.0.0"
|
15
23
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: specdiff
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.0
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Odin Heggvold Bekkelund
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hashdiff
|
@@ -38,15 +38,21 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.5'
|
41
|
-
description:
|
41
|
+
description: 'Specdiff aims to improve both RSpec''s and WebMock''s diffing by applying
|
42
|
+
opinionated heuristics, and comes with integrations (monkey-patches) for both. Particularly
|
43
|
+
noteworthy improvements are made to working with deeply nested hash/array structures
|
44
|
+
in RSpec, and plaintext/xml request bodies in WebMock.
|
45
|
+
|
46
|
+
'
|
42
47
|
email:
|
43
|
-
-
|
48
|
+
- odin.heggvold.bekkelund@dev.dodo.no
|
44
49
|
executables: []
|
45
50
|
extensions: []
|
46
51
|
extra_rdoc_files: []
|
47
52
|
files:
|
48
53
|
- ".gitignore"
|
49
54
|
- CHANGELOG.md
|
55
|
+
- DEVELOPMENT.md
|
50
56
|
- LICENSE.txt
|
51
57
|
- README.md
|
52
58
|
- glossary.txt
|
@@ -68,13 +74,13 @@ files:
|
|
68
74
|
- lib/specdiff/version.rb
|
69
75
|
- lib/specdiff/webmock.rb
|
70
76
|
- specdiff.gemspec
|
71
|
-
homepage: https://github.com/
|
77
|
+
homepage: https://github.com/dodoas/specdiff
|
72
78
|
licenses:
|
73
79
|
- MIT
|
74
80
|
metadata:
|
75
|
-
homepage_uri: https://github.com/
|
76
|
-
source_code_uri: https://github.com/
|
77
|
-
changelog_uri: https://github.com/
|
81
|
+
homepage_uri: https://github.com/dodoas/specdiff
|
82
|
+
source_code_uri: https://github.com/dodoas/specdiff
|
83
|
+
changelog_uri: https://github.com/dodoas/specdiff/CHANGELOG.md
|
78
84
|
post_install_message:
|
79
85
|
rdoc_options: []
|
80
86
|
require_paths:
|
@@ -86,12 +92,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
92
|
version: 3.0.0
|
87
93
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
94
|
requirements:
|
89
|
-
- - "
|
95
|
+
- - ">="
|
90
96
|
- !ruby/object:Gem::Version
|
91
|
-
version:
|
97
|
+
version: '0'
|
92
98
|
requirements: []
|
93
99
|
rubygems_version: 3.2.22
|
94
100
|
signing_key:
|
95
101
|
specification_version: 4
|
96
|
-
summary: Improved
|
102
|
+
summary: Improved diffing for WebMock and RSpec
|
97
103
|
test_files: []
|