specdiff 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +203 -0
- data/.tool-versions +1 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +76 -0
- data/LICENSE.txt +21 -0
- data/README.md +84 -0
- data/Rakefile +12 -0
- data/examples/webmock/Gemfile +6 -0
- data/examples/webmock/Gemfile.lock +50 -0
- data/examples/webmock/json.rb +37 -0
- data/examples/webmock/text.rb +39 -0
- data/glossary.txt +24 -0
- data/lib/specdiff/colorize.rb +31 -0
- data/lib/specdiff/config.rb +27 -0
- data/lib/specdiff/diff.rb +27 -0
- data/lib/specdiff/differ/hashdiff.rb +85 -0
- data/lib/specdiff/differ/not_found.rb +24 -0
- data/lib/specdiff/differ/text.rb +73 -0
- data/lib/specdiff/differ.rb +100 -0
- data/lib/specdiff/plugin.rb +11 -0
- data/lib/specdiff/plugins/json.rb +42 -0
- data/lib/specdiff/plugins.rb +73 -0
- data/lib/specdiff/threadlocal.rb +8 -0
- data/lib/specdiff/version.rb +3 -0
- data/lib/specdiff/webmock/request_body_diff.rb +41 -0
- data/lib/specdiff/webmock.rb +1 -0
- data/lib/specdiff.rb +16 -0
- data/specdiff.gemspec +31 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7da7ac63f4638bd752f83ff41a27488757e43e57c028891d4fd944afd03f58ca
|
4
|
+
data.tar.gz: d5a49e6aeb3525a454df920aa7d1b541a0812ffb9f8d0e1813a4bc05b57b006f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 38ae83cd45a69892ca6d22915e0b253447eb12f42165a7673751abbb3993381702a02771ad3181a96d26204e6d171268a14423e85c2323a345df243be918f5a5
|
7
|
+
data.tar.gz: f44ce432951f3e2198ed6c4ed4cfc975b4eb201ced235791cd917c2476ca7a60fcb4ce0aff023fd4423f97b7eee2819d395d514b970188a5bc232ce89ee44ea6
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 3.0
|
3
|
+
|
4
|
+
require:
|
5
|
+
- rubocop-rspec
|
6
|
+
- rubocop-rake
|
7
|
+
|
8
|
+
##
|
9
|
+
# LAYOUT COPS
|
10
|
+
##
|
11
|
+
|
12
|
+
Layout:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Layout/LineLength:
|
16
|
+
Enabled: true
|
17
|
+
Max: 120
|
18
|
+
|
19
|
+
Layout/SpaceInsideBlockBraces:
|
20
|
+
Enabled: true
|
21
|
+
EnforcedStyle: space
|
22
|
+
SpaceBeforeBlockParameters: no_space
|
23
|
+
Layout/SpaceInsideHashLiteralBraces:
|
24
|
+
Enabled: true
|
25
|
+
EnforcedStyle: no_space
|
26
|
+
|
27
|
+
Layout/MultilineMethodCallIndentation:
|
28
|
+
Enabled: true
|
29
|
+
EnforcedStyle: indented
|
30
|
+
|
31
|
+
##
|
32
|
+
# STYLE COPS
|
33
|
+
##
|
34
|
+
|
35
|
+
Style:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
Style/TrailingCommaInArrayLiteral:
|
39
|
+
Enabled: true
|
40
|
+
EnforcedStyleForMultiline: consistent_comma
|
41
|
+
|
42
|
+
Style/TrailingCommaInHashLiteral:
|
43
|
+
Enabled: true
|
44
|
+
EnforcedStyleForMultiline: consistent_comma
|
45
|
+
|
46
|
+
Style/SpecialGlobalVars:
|
47
|
+
Enabled: true
|
48
|
+
EnforcedStyle: use_english_names
|
49
|
+
|
50
|
+
##
|
51
|
+
# NAMING COPS
|
52
|
+
##
|
53
|
+
|
54
|
+
Naming/BlockForwarding: # new in 1.24
|
55
|
+
Enabled: false
|
56
|
+
Naming/MethodParameterName:
|
57
|
+
Enabled: false
|
58
|
+
|
59
|
+
##
|
60
|
+
# SECURITY COPS
|
61
|
+
##
|
62
|
+
|
63
|
+
Security/CompoundHash: # new in 1.28
|
64
|
+
Enabled: true
|
65
|
+
Security/IoMethods: # new in 1.22
|
66
|
+
Enabled: true
|
67
|
+
|
68
|
+
##
|
69
|
+
# LINT COPS
|
70
|
+
##
|
71
|
+
|
72
|
+
Lint/SuppressedException:
|
73
|
+
AllowComments: true
|
74
|
+
Lint/AmbiguousAssignment: # new in 1.7
|
75
|
+
Enabled: true
|
76
|
+
Lint/AmbiguousOperatorPrecedence: # new in 1.21
|
77
|
+
Enabled: true
|
78
|
+
Lint/AmbiguousRange: # new in 1.19
|
79
|
+
Enabled: true
|
80
|
+
Lint/ConstantOverwrittenInRescue: # new in 1.31
|
81
|
+
Enabled: true
|
82
|
+
Lint/DeprecatedConstants: # new in 1.8
|
83
|
+
Enabled: true
|
84
|
+
Lint/DuplicateBranch: # new in 1.3
|
85
|
+
Enabled: true
|
86
|
+
IgnoreLiteralBranches: true
|
87
|
+
IgnoreConstantBranches: true
|
88
|
+
Lint/DuplicateMagicComment: # new in 1.37
|
89
|
+
Enabled: true
|
90
|
+
Lint/DuplicateMatchPattern: # new in 1.50
|
91
|
+
Enabled: true
|
92
|
+
Lint/DuplicateRegexpCharacterClassElement: # new in 1.1
|
93
|
+
Enabled: true
|
94
|
+
Lint/EmptyBlock: # new in 1.1
|
95
|
+
Enabled: true
|
96
|
+
Lint/EmptyClass: # new in 1.3
|
97
|
+
Enabled: true
|
98
|
+
Lint/EmptyInPattern: # new in 1.16
|
99
|
+
Enabled: true
|
100
|
+
Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21
|
101
|
+
Enabled: true
|
102
|
+
Lint/LambdaWithoutLiteralBlock: # new in 1.8
|
103
|
+
Enabled: true
|
104
|
+
Lint/MixedCaseRange: # new in 1.53
|
105
|
+
Enabled: true
|
106
|
+
Lint/NoReturnInBeginEndBlocks: # new in 1.2
|
107
|
+
Enabled: true
|
108
|
+
Lint/NonAtomicFileOperation: # new in 1.31
|
109
|
+
Enabled: true
|
110
|
+
Lint/NumberedParameterAssignment: # new in 1.9
|
111
|
+
Enabled: true
|
112
|
+
Lint/OrAssignmentToConstant: # new in 1.9
|
113
|
+
Enabled: true
|
114
|
+
Lint/RedundantDirGlobSort: # new in 1.8
|
115
|
+
Enabled: true
|
116
|
+
Lint/RedundantRegexpQuantifiers: # new in 1.53
|
117
|
+
Enabled: true
|
118
|
+
Lint/RefinementImportMethods: # new in 1.27
|
119
|
+
Enabled: true
|
120
|
+
Lint/RequireRangeParentheses: # new in 1.32
|
121
|
+
Enabled: true
|
122
|
+
Lint/RequireRelativeSelfPath: # new in 1.22
|
123
|
+
Enabled: true
|
124
|
+
Lint/SymbolConversion: # new in 1.9
|
125
|
+
Enabled: true
|
126
|
+
Lint/ToEnumArguments: # new in 1.1
|
127
|
+
Enabled: true
|
128
|
+
Lint/TripleQuotes: # new in 1.9
|
129
|
+
Enabled: true
|
130
|
+
Lint/UnexpectedBlockArity: # new in 1.5
|
131
|
+
Enabled: true
|
132
|
+
Lint/UnmodifiedReduceAccumulator: # new in 1.1
|
133
|
+
Enabled: true
|
134
|
+
Lint/UselessRescue: # new in 1.43
|
135
|
+
Enabled: true
|
136
|
+
Lint/UselessRuby2Keywords: # new in 1.23
|
137
|
+
Enabled: true
|
138
|
+
|
139
|
+
##
|
140
|
+
# METRICS COPS
|
141
|
+
##
|
142
|
+
|
143
|
+
Metrics:
|
144
|
+
Enabled: false
|
145
|
+
|
146
|
+
##
|
147
|
+
# GEMSPEC COPS
|
148
|
+
##
|
149
|
+
|
150
|
+
Gemspec/DeprecatedAttributeAssignment: # new in 1.30
|
151
|
+
Enabled: true
|
152
|
+
Gemspec/DevelopmentDependencies: # new in 1.44
|
153
|
+
Enabled: true
|
154
|
+
Gemspec/RequireMFA: # new in 1.23
|
155
|
+
Enabled: false
|
156
|
+
Gemspec/OrderedDependencies:
|
157
|
+
Enabled: false
|
158
|
+
|
159
|
+
##
|
160
|
+
# BUNDLER COPS
|
161
|
+
##
|
162
|
+
|
163
|
+
Bundler/OrderedGems:
|
164
|
+
Enabled: false
|
165
|
+
|
166
|
+
##
|
167
|
+
# RSPEC COPS
|
168
|
+
##
|
169
|
+
|
170
|
+
# documentation can be found in
|
171
|
+
# http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/<name>
|
172
|
+
RSpec:
|
173
|
+
Enabled: false
|
174
|
+
|
175
|
+
RSpec/HookArgument:
|
176
|
+
Enabled: true
|
177
|
+
EnforcedStyle: each
|
178
|
+
RSpec/MessageSpies:
|
179
|
+
Enabled: true
|
180
|
+
EnforcedStyle: receive
|
181
|
+
|
182
|
+
##
|
183
|
+
# CAPYBARA COPS
|
184
|
+
##
|
185
|
+
|
186
|
+
# cant remember installing capybara but whatever
|
187
|
+
Capybara:
|
188
|
+
Enabled: false
|
189
|
+
|
190
|
+
##
|
191
|
+
# FACTORYBOT COPS
|
192
|
+
##
|
193
|
+
|
194
|
+
# cant remember installing factorybot but whatever
|
195
|
+
FactoryBot:
|
196
|
+
Enabled: false
|
197
|
+
|
198
|
+
##
|
199
|
+
# RAKE COPS
|
200
|
+
##
|
201
|
+
|
202
|
+
Rake:
|
203
|
+
Enabled: true
|
data/.tool-versions
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby 3.2.2
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
specdiff (0.1.0)
|
5
|
+
diff-lcs (~> 1.5)
|
6
|
+
hashdiff (~> 1.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
ast (2.4.2)
|
12
|
+
diff-lcs (1.5.0)
|
13
|
+
hashdiff (1.0.1)
|
14
|
+
json (2.6.3)
|
15
|
+
language_server-protocol (3.17.0.3)
|
16
|
+
parallel (1.23.0)
|
17
|
+
parser (3.2.2.4)
|
18
|
+
ast (~> 2.4.1)
|
19
|
+
racc
|
20
|
+
racc (1.7.3)
|
21
|
+
rainbow (3.1.1)
|
22
|
+
rake (13.1.0)
|
23
|
+
regexp_parser (2.8.2)
|
24
|
+
rexml (3.2.6)
|
25
|
+
rspec (3.12.0)
|
26
|
+
rspec-core (~> 3.12.0)
|
27
|
+
rspec-expectations (~> 3.12.0)
|
28
|
+
rspec-mocks (~> 3.12.0)
|
29
|
+
rspec-core (3.12.2)
|
30
|
+
rspec-support (~> 3.12.0)
|
31
|
+
rspec-expectations (3.12.3)
|
32
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
33
|
+
rspec-support (~> 3.12.0)
|
34
|
+
rspec-mocks (3.12.6)
|
35
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
36
|
+
rspec-support (~> 3.12.0)
|
37
|
+
rspec-support (3.12.1)
|
38
|
+
rubocop (1.57.2)
|
39
|
+
json (~> 2.3)
|
40
|
+
language_server-protocol (>= 3.17.0)
|
41
|
+
parallel (~> 1.10)
|
42
|
+
parser (>= 3.2.2.4)
|
43
|
+
rainbow (>= 2.2.2, < 4.0)
|
44
|
+
regexp_parser (>= 1.8, < 3.0)
|
45
|
+
rexml (>= 3.2.5, < 4.0)
|
46
|
+
rubocop-ast (>= 1.28.1, < 2.0)
|
47
|
+
ruby-progressbar (~> 1.7)
|
48
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
49
|
+
rubocop-ast (1.30.0)
|
50
|
+
parser (>= 3.2.1.0)
|
51
|
+
rubocop-capybara (2.19.0)
|
52
|
+
rubocop (~> 1.41)
|
53
|
+
rubocop-factory_bot (2.24.0)
|
54
|
+
rubocop (~> 1.33)
|
55
|
+
rubocop-rake (0.6.0)
|
56
|
+
rubocop (~> 1.0)
|
57
|
+
rubocop-rspec (2.25.0)
|
58
|
+
rubocop (~> 1.40)
|
59
|
+
rubocop-capybara (~> 2.17)
|
60
|
+
rubocop-factory_bot (~> 2.22)
|
61
|
+
ruby-progressbar (1.13.0)
|
62
|
+
unicode-display_width (2.5.0)
|
63
|
+
|
64
|
+
PLATFORMS
|
65
|
+
x86_64-linux
|
66
|
+
|
67
|
+
DEPENDENCIES
|
68
|
+
rake (~> 13.0)
|
69
|
+
rspec (~> 3.0)
|
70
|
+
rubocop (~> 1.21)
|
71
|
+
rubocop-rake (~> 0.6.0)
|
72
|
+
rubocop-rspec (~> 2.25)
|
73
|
+
specdiff!
|
74
|
+
|
75
|
+
BUNDLED WITH
|
76
|
+
2.3.5
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Odin H B
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Specdiff
|
2
|
+
|
3
|
+
A gem for improving diff output in webmock.
|
4
|
+
|
5
|
+
Webmock currently has a somewhat hidden feature where it will produce a diff
|
6
|
+
between a request body and a registered stub when making an unregistered request
|
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.
|
10
|
+
|
11
|
+
Specdiff automagically detects the types of provided data and prints a suitable
|
12
|
+
diff between them.
|
13
|
+
|
14
|
+
Check out the examples directory to see what it might look like.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem "specdiff", require: false
|
22
|
+
```
|
23
|
+
|
24
|
+
And then execute:
|
25
|
+
|
26
|
+
$ bundle install
|
27
|
+
|
28
|
+
Or install it yourself as:
|
29
|
+
|
30
|
+
$ gem install specdiff
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
Put the following in your `spec_helper.rb`. (Or equivalent initializer
|
35
|
+
for test environment) You probably don't want to load/use this gem in a release
|
36
|
+
environment.
|
37
|
+
|
38
|
+
```rb
|
39
|
+
# spec_helper.rb
|
40
|
+
|
41
|
+
require "specdiff"
|
42
|
+
require "specdiff/webmock" # optional, webmock patches
|
43
|
+
|
44
|
+
# optionally, you can turn off terminal colors
|
45
|
+
Specdiff.configure do |config|
|
46
|
+
config.colorize = true
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
The webmock patch should make webmock show diffs from the specdiff gem when
|
51
|
+
stubs mismatch.
|
52
|
+
|
53
|
+
### Direct usage
|
54
|
+
|
55
|
+
You can also use the gem directly:
|
56
|
+
|
57
|
+
```rb
|
58
|
+
diff = Specdiff.diff(something, and_something_else)
|
59
|
+
|
60
|
+
diff.empty? # => true/false, if it is empty you might want to not print the diff, it is probably useless
|
61
|
+
diff.to_s # => a string for showing to a developer who may or may not be scratching their head
|
62
|
+
```
|
63
|
+
|
64
|
+
## Development
|
65
|
+
|
66
|
+
Install the software versions specified in `.tool-versions`.
|
67
|
+
|
68
|
+
Run `bin/setup` to install dependencies. Then, run `bundle exec rake` to run the tests and linter and make sure they're green before starting to make your changes.
|
69
|
+
|
70
|
+
Run `bundle exec rake -AD` gor a full list of all the available tasks you may use for development purposes.
|
71
|
+
|
72
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment with the gem code loaded.
|
73
|
+
|
74
|
+
## Releasing
|
75
|
+
|
76
|
+
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
77
|
+
|
78
|
+
## Contributing
|
79
|
+
|
80
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/odinhb/specdiff.
|
81
|
+
|
82
|
+
## License
|
83
|
+
|
84
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../..
|
3
|
+
specs:
|
4
|
+
specdiff (0.1.0)
|
5
|
+
diff-lcs (~> 1.5)
|
6
|
+
hashdiff (~> 1.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
addressable (2.8.5)
|
12
|
+
public_suffix (>= 2.0.2, < 6.0)
|
13
|
+
crack (0.4.5)
|
14
|
+
rexml
|
15
|
+
diff-lcs (1.5.0)
|
16
|
+
domain_name (0.6.20231109)
|
17
|
+
ffi (1.16.3)
|
18
|
+
ffi-compiler (1.0.1)
|
19
|
+
ffi (>= 1.0.0)
|
20
|
+
rake
|
21
|
+
hashdiff (1.0.1)
|
22
|
+
http (5.1.1)
|
23
|
+
addressable (~> 2.8)
|
24
|
+
http-cookie (~> 1.0)
|
25
|
+
http-form_data (~> 2.2)
|
26
|
+
llhttp-ffi (~> 0.4.0)
|
27
|
+
http-cookie (1.0.5)
|
28
|
+
domain_name (~> 0.5)
|
29
|
+
http-form_data (2.3.0)
|
30
|
+
llhttp-ffi (0.4.0)
|
31
|
+
ffi-compiler (~> 1.0)
|
32
|
+
rake (~> 13.0)
|
33
|
+
public_suffix (5.0.4)
|
34
|
+
rake (13.1.0)
|
35
|
+
rexml (3.2.6)
|
36
|
+
webmock (3.19.1)
|
37
|
+
addressable (>= 2.8.0)
|
38
|
+
crack (>= 0.3.2)
|
39
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
40
|
+
|
41
|
+
PLATFORMS
|
42
|
+
x86_64-linux
|
43
|
+
|
44
|
+
DEPENDENCIES
|
45
|
+
http
|
46
|
+
specdiff!
|
47
|
+
webmock
|
48
|
+
|
49
|
+
BUNDLED WITH
|
50
|
+
2.3.5
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "webmock"
|
2
|
+
require "specdiff"
|
3
|
+
require "specdiff/webmock"
|
4
|
+
|
5
|
+
Specdiff.load!(:json)
|
6
|
+
|
7
|
+
include WebMock::API
|
8
|
+
|
9
|
+
WebMock.enable!
|
10
|
+
WebMock.show_body_diff! # on by default
|
11
|
+
|
12
|
+
stub_request(:post, "https://www.example.com")
|
13
|
+
.with(
|
14
|
+
body: JSON.generate({
|
15
|
+
my_hash: "is great",
|
16
|
+
the_hash: "is amazing",
|
17
|
+
})
|
18
|
+
)
|
19
|
+
.to_return(status: 400, body: "hello")
|
20
|
+
|
21
|
+
begin
|
22
|
+
HTTP.post(
|
23
|
+
"https://www.example.com",
|
24
|
+
body: JSON.generate({
|
25
|
+
i_had_to_go: "and post a different hash",
|
26
|
+
my_hash: "is different",
|
27
|
+
}),
|
28
|
+
)
|
29
|
+
rescue WebMock::NetConnectNotAllowedError => e
|
30
|
+
puts "success! webmock stopped the request"
|
31
|
+
puts "here is the error text:\n\n"
|
32
|
+
|
33
|
+
puts e.message
|
34
|
+
exit 0
|
35
|
+
end
|
36
|
+
|
37
|
+
puts "nothing was raised??"
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "webmock"
|
2
|
+
require "specdiff"
|
3
|
+
require "specdiff/webmock"
|
4
|
+
|
5
|
+
include WebMock::API
|
6
|
+
|
7
|
+
WebMock.enable!
|
8
|
+
WebMock.show_body_diff! # on by default
|
9
|
+
|
10
|
+
stub_request(:post, "https://www.example.com")
|
11
|
+
.with(
|
12
|
+
body: <<~TEXT1,
|
13
|
+
this is the expected body
|
14
|
+
that you should send
|
15
|
+
nothing less
|
16
|
+
nothing more
|
17
|
+
TEXT1
|
18
|
+
)
|
19
|
+
.to_return(status: 400, body: "hello")
|
20
|
+
|
21
|
+
begin
|
22
|
+
HTTP.post(
|
23
|
+
"https://www.example.com",
|
24
|
+
body: <<~TEXT2,
|
25
|
+
this is the unexpected body
|
26
|
+
that i should not have sent
|
27
|
+
nothing less
|
28
|
+
nothing more
|
29
|
+
TEXT2
|
30
|
+
)
|
31
|
+
rescue WebMock::NetConnectNotAllowedError => e
|
32
|
+
puts "success! webmock stopped the request"
|
33
|
+
puts "here is the error text:\n\n"
|
34
|
+
|
35
|
+
puts e.message
|
36
|
+
exit 0
|
37
|
+
end
|
38
|
+
|
39
|
+
puts "nothing was raised??"
|
data/glossary.txt
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
diff
|
2
|
+
the return value from the Specdiff::diff method.
|
3
|
+
this is not the direct return value from a plugin/differ, that is the
|
4
|
+
"raw diff" (or diff.raw)
|
5
|
+
|
6
|
+
differ
|
7
|
+
a class responding to ::diff(a, b) and ::stringify(diff) able to produce a
|
8
|
+
human-comprehensible diff output for your terminal
|
9
|
+
|
10
|
+
plugin
|
11
|
+
external differ (responding to more methods), able to be provided by third
|
12
|
+
parties or end users themselves
|
13
|
+
|
14
|
+
type
|
15
|
+
a symbol like :text, :json or :hash which denotes the type of data in a way
|
16
|
+
which is useful for picking a differ
|
17
|
+
|
18
|
+
:text
|
19
|
+
a string which likely contains plaintext data of some kind
|
20
|
+
|
21
|
+
side
|
22
|
+
an object containing either side of a comparison that needs to be made
|
23
|
+
when defining a plugin, the diff method receives two sides: a, b
|
24
|
+
most importantly, a side contains a value and a type
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Specdiff::Colorize
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def colorize_by_line(string, line_separator = "\n")
|
5
|
+
return string if !::Specdiff.config.colorize?
|
6
|
+
|
7
|
+
string.lines(line_separator).map do |line|
|
8
|
+
yield(line)
|
9
|
+
end.join
|
10
|
+
end
|
11
|
+
|
12
|
+
def reset_color(text)
|
13
|
+
"\e[0m#{text}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def red(text)
|
17
|
+
"\e[31m#{text}\e[0m"
|
18
|
+
end
|
19
|
+
|
20
|
+
def green(text)
|
21
|
+
"\e[32m#{text}\e[0m"
|
22
|
+
end
|
23
|
+
|
24
|
+
def yellow(text)
|
25
|
+
"\e[33m#{text}\e[0m"
|
26
|
+
end
|
27
|
+
|
28
|
+
def blue(text)
|
29
|
+
"\e[34m#{text}\e[0m"
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Specdiff
|
2
|
+
Config = Struct.new(:colorize, keyword_init: true) do
|
3
|
+
def colorize?
|
4
|
+
colorize
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
# Read the configuration
|
9
|
+
def self.config
|
10
|
+
threadlocal[:config] ||= default_configuration
|
11
|
+
end
|
12
|
+
|
13
|
+
# private, used for testing
|
14
|
+
def self._set_config(new_config)
|
15
|
+
threadlocal[:config] = new_config
|
16
|
+
end
|
17
|
+
|
18
|
+
# Set the configuration
|
19
|
+
def self.configure
|
20
|
+
yield(config)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Generates the default configuration
|
24
|
+
def self.default_configuration
|
25
|
+
Config.new(colorize: true)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
::Specdiff::Diff = Struct.new(
|
2
|
+
:differ, :a, :b, :raw, keyword_init: true,
|
3
|
+
) do
|
4
|
+
def differ_id
|
5
|
+
differ.id
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_s
|
9
|
+
differ.stringify(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
def empty?
|
13
|
+
differ == ::Specdiff::Differ::NotFound
|
14
|
+
end
|
15
|
+
|
16
|
+
def types
|
17
|
+
[a.type, b.type]
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
if empty?
|
22
|
+
"<Specdiff::Diff (empty)>"
|
23
|
+
else
|
24
|
+
"<Specdiff::Diff w/ #{raw&.bytesize || 0} bytes of #raw diff>"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "hashdiff"
|
2
|
+
require "pp"
|
3
|
+
|
4
|
+
class Specdiff::Differ::Hashdiff
|
5
|
+
extend ::Specdiff::Colorize
|
6
|
+
|
7
|
+
def self.diff(a, b)
|
8
|
+
# array_path: true returns the path as an array, which differentiates
|
9
|
+
# between symbol keys and string keys in hashes, while the string
|
10
|
+
# representation does not.
|
11
|
+
# hmm it really seems like use_lcs: true gives much less human-readable
|
12
|
+
# (human-comprehensible) output when arrays are involved.
|
13
|
+
Hashdiff.diff(
|
14
|
+
a.value, b.value,
|
15
|
+
array_path: true,
|
16
|
+
use_lcs: false,
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.stringify(diff)
|
21
|
+
diff.raw.pretty_inspect
|
22
|
+
|
23
|
+
result = +""
|
24
|
+
|
25
|
+
diff.raw.each do |change|
|
26
|
+
type = change[0] # the char '+', '-' or '~'
|
27
|
+
path = change[1] # for example key1.key2[2] (as ["key1", :key2, 2])
|
28
|
+
path2 = _stringify_path(path)
|
29
|
+
|
30
|
+
if type == "+"
|
31
|
+
value = change[2]
|
32
|
+
|
33
|
+
result << "added #{path2} with value #{value.inspect}"
|
34
|
+
elsif type == "-"
|
35
|
+
value = change[2]
|
36
|
+
|
37
|
+
result << "removed #{path2} with value #{value.inspect}"
|
38
|
+
elsif type == "~"
|
39
|
+
from = change[2]
|
40
|
+
to = change[3]
|
41
|
+
|
42
|
+
result << "changed #{path2} from #{from.inspect} to #{to.inspect}"
|
43
|
+
else
|
44
|
+
result << change.inspect
|
45
|
+
end
|
46
|
+
|
47
|
+
result << "\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
colorize_by_line(result) do |line|
|
51
|
+
if line.start_with?("removed")
|
52
|
+
red(line)
|
53
|
+
elsif line.start_with?("added")
|
54
|
+
green(line)
|
55
|
+
elsif line.start_with?("changed")
|
56
|
+
yellow(line)
|
57
|
+
else
|
58
|
+
reset_color(line)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
PATH_SEPARATOR = ".".freeze
|
64
|
+
|
65
|
+
def self._stringify_path(path)
|
66
|
+
result = +""
|
67
|
+
|
68
|
+
path.each do |component|
|
69
|
+
if component.is_a?(Numeric)
|
70
|
+
result.chomp!(PATH_SEPARATOR)
|
71
|
+
result << "[#{component}]"
|
72
|
+
elsif component.is_a?(Symbol)
|
73
|
+
# by not inspecting symbols they look prettier than strings, but you
|
74
|
+
# can still tell the difference in the printed output
|
75
|
+
result << component.to_s
|
76
|
+
else
|
77
|
+
result << component.inspect
|
78
|
+
end
|
79
|
+
|
80
|
+
result << PATH_SEPARATOR
|
81
|
+
end
|
82
|
+
|
83
|
+
result.chomp(PATH_SEPARATOR)
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# this is the null differ
|
2
|
+
class Specdiff::Differ::NotFound
|
3
|
+
def self.diff(a, b)
|
4
|
+
comparison = "!="
|
5
|
+
comparison = "=" if a.value == b.value
|
6
|
+
|
7
|
+
a_representation = _representation_for(a)
|
8
|
+
b_representation = _representation_for(b)
|
9
|
+
|
10
|
+
"#{a_representation} #{comparison} #{b_representation}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self._representation_for(side)
|
14
|
+
if side.type == :binary
|
15
|
+
"<binary content>"
|
16
|
+
else
|
17
|
+
side.value.inspect
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.stringify(diff)
|
22
|
+
diff.raw
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require "diff/lcs"
|
2
|
+
require "diff/lcs/hunk"
|
3
|
+
|
4
|
+
class Specdiff::Differ::Text
|
5
|
+
extend ::Specdiff::Colorize
|
6
|
+
|
7
|
+
NEWLINE = "\n".freeze
|
8
|
+
CONTEXT_LINES = 3
|
9
|
+
|
10
|
+
# this implementation is based on RSpec::Support::Differ
|
11
|
+
# https://github.com/rspec/rspec-support/blob/main/lib/rspec/support/differ.rb
|
12
|
+
# and also the hunk generator it uses
|
13
|
+
def self.diff(a, b)
|
14
|
+
a_value = a.value
|
15
|
+
b_value = b.value
|
16
|
+
|
17
|
+
if a_value.encoding != b_value.encoding
|
18
|
+
return <<~MSG
|
19
|
+
Strings have different encodings:
|
20
|
+
#{a.value.encoding.inspect} != #{b.value.encoding.inspect}
|
21
|
+
MSG
|
22
|
+
end
|
23
|
+
|
24
|
+
diff = ""
|
25
|
+
|
26
|
+
a_lines = a_value.split(NEWLINE).map! { _1.chomp }
|
27
|
+
b_lines = b_value.split(NEWLINE).map! { _1.chomp }
|
28
|
+
hunks = ::Diff::LCS.diff(a_lines, b_lines).map do |piece|
|
29
|
+
::Diff::LCS::Hunk.new(
|
30
|
+
a_lines, b_lines, piece, CONTEXT_LINES, 0,
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
hunks.each_cons(2) do |prev_hunk, current_hunk|
|
35
|
+
begin
|
36
|
+
if current_hunk.overlaps?(prev_hunk)
|
37
|
+
current_hunk.merge(prev_hunk)
|
38
|
+
else
|
39
|
+
diff << prev_hunk.diff(:unified).to_s
|
40
|
+
end
|
41
|
+
ensure
|
42
|
+
diff << NEWLINE
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
if hunks.last
|
47
|
+
diff << hunks.last.diff(:unified).to_s
|
48
|
+
end
|
49
|
+
|
50
|
+
diff << "\n"
|
51
|
+
|
52
|
+
return colorize_by_line(diff) do |line|
|
53
|
+
case line[0].chr
|
54
|
+
when "+"
|
55
|
+
green(line)
|
56
|
+
when "-"
|
57
|
+
red(line)
|
58
|
+
when "@"
|
59
|
+
if line[1].chr == "@"
|
60
|
+
blue(line)
|
61
|
+
else
|
62
|
+
reset_color(line)
|
63
|
+
end
|
64
|
+
else
|
65
|
+
reset_color(line)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.stringify(diff)
|
71
|
+
diff.raw
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
class Specdiff::Differ
|
2
|
+
Side = Struct.new(:value, :type, keyword_init: true)
|
3
|
+
|
4
|
+
def self.call(...)
|
5
|
+
new.call(...)
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(raw_a, raw_b)
|
9
|
+
a = parse_side(raw_a)
|
10
|
+
b = parse_side(raw_b)
|
11
|
+
|
12
|
+
if a.type == :text && b.type == :binary
|
13
|
+
new_b = try_reencode(b.value, a.value.encoding)
|
14
|
+
if new_b
|
15
|
+
b = b.dup
|
16
|
+
b.type = :text
|
17
|
+
b.value = new_b
|
18
|
+
end
|
19
|
+
elsif a.type == :binary && b.type == :text
|
20
|
+
new_a = try_reencode(a.value, b.value.encoding)
|
21
|
+
if new_a
|
22
|
+
a = a.dup
|
23
|
+
a.type = :text
|
24
|
+
a.value = new_a
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
differ = pick_differ(a, b)
|
29
|
+
raw = differ.diff(a, b)
|
30
|
+
|
31
|
+
if raw.is_a?(::Specdiff::Diff) # detect recursive plugins, such as json
|
32
|
+
raw
|
33
|
+
else
|
34
|
+
::Specdiff::Diff.new(raw: raw, differ: differ, a: a, b: b)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def parse_side(raw_value)
|
41
|
+
type = detect_type(raw_value)
|
42
|
+
|
43
|
+
Side.new(value: raw_value, type: type)
|
44
|
+
end
|
45
|
+
|
46
|
+
def detect_type(thing)
|
47
|
+
if (type = detect_plugin_types(thing))
|
48
|
+
type
|
49
|
+
elsif thing.is_a?(Hash)
|
50
|
+
:hash
|
51
|
+
elsif thing.is_a?(Array)
|
52
|
+
:array
|
53
|
+
elsif thing.is_a?(String) && thing.encoding == Encoding::BINARY
|
54
|
+
:binary
|
55
|
+
elsif thing.is_a?(String)
|
56
|
+
:text
|
57
|
+
elsif thing.nil?
|
58
|
+
:nil
|
59
|
+
else
|
60
|
+
:unknown
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def detect_plugin_types(thing)
|
65
|
+
Specdiff.plugins
|
66
|
+
.filter { |plugin| plugin.respond_to?(:detect_type) }
|
67
|
+
.detect { |plugin| plugin.detect_type(thing) }
|
68
|
+
&.id
|
69
|
+
end
|
70
|
+
|
71
|
+
def try_reencode(binary_string, target_encoding)
|
72
|
+
binary_string.encode(target_encoding)
|
73
|
+
rescue StandardError
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def pick_differ(a, b)
|
78
|
+
if (differ = pick_plugin_differ(a, b))
|
79
|
+
differ
|
80
|
+
elsif a.type == :text && b.type == :text
|
81
|
+
Specdiff::Differ::Text
|
82
|
+
elsif a.type == :hash && b.type == :hash
|
83
|
+
Specdiff::Differ::Hashdiff
|
84
|
+
elsif a.type == :array && b.type == :array
|
85
|
+
Specdiff::Differ::Hashdiff
|
86
|
+
else
|
87
|
+
Specdiff::Differ::NotFound
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def pick_plugin_differ(a, b)
|
92
|
+
Specdiff.plugins
|
93
|
+
.detect { |plugin| plugin.compatible?(a, b) }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# require only the builtin differs, plugins are optionally loaded later
|
98
|
+
require_relative "differ/not_found"
|
99
|
+
require_relative "differ/text"
|
100
|
+
require_relative "differ/hashdiff"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
class Specdiff::Plugins::Json
|
4
|
+
include ::Specdiff::Plugin
|
5
|
+
|
6
|
+
def self.id
|
7
|
+
:json
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.detect_type(thing)
|
11
|
+
thing.is_a?(String) && _json_parsable?(thing)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self._json_parsable?(thing)
|
15
|
+
return false unless thing.is_a?(String)
|
16
|
+
|
17
|
+
JSON.parse(thing)
|
18
|
+
true
|
19
|
+
rescue JSON::ParserError
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.compatible?(a, b)
|
24
|
+
a.type == :json || b.type == :json
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.diff(a, b)
|
28
|
+
a_value = a.value
|
29
|
+
b_value = b.value
|
30
|
+
|
31
|
+
a_value = JSON.parse(a_value) if a.type == :json
|
32
|
+
b_value = JSON.parse(b_value) if b.type == :json
|
33
|
+
|
34
|
+
::Specdiff.diff(a_value, b_value)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.stringify(_diff)
|
38
|
+
# since we recurse back into Specdiff, we don't need to stringify in this
|
39
|
+
# plugin. the built in hash/array/text differs should do the stringification
|
40
|
+
raise "#{self.class}::stringify was called, this should never happen"
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Specdiff
|
2
|
+
THREADLOCAL_PLUGINS_KEY = :__specdiff_plugins
|
3
|
+
|
4
|
+
def self.plugins
|
5
|
+
threadlocal[THREADLOCAL_PLUGINS_KEY]
|
6
|
+
end
|
7
|
+
|
8
|
+
BUILTIN_PLUGINS = %i[json]
|
9
|
+
BUILTIN_TYPES = %i[hash array binary text nil]
|
10
|
+
|
11
|
+
# Load extra type support, such as support for json strings
|
12
|
+
def self.load!(*plugins)
|
13
|
+
return if plugins.size == 0
|
14
|
+
|
15
|
+
plugins.each do |new_plugin|
|
16
|
+
if BUILTIN_PLUGINS.include?(new_plugin)
|
17
|
+
case new_plugin
|
18
|
+
when :json
|
19
|
+
require "#{__dir__}/plugins/json"
|
20
|
+
load_plugin_class!(::Specdiff::Plugins::Json)
|
21
|
+
end
|
22
|
+
else
|
23
|
+
load_plugin_class!(new_plugin)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
PLUGIN_INTERFACE = [:id, :detect_type, :compatible?, :diff, :stringify].freeze
|
31
|
+
|
32
|
+
# Load a single plugin class, does not support symbols for builtin plugins.
|
33
|
+
def self.load_plugin_class!(plugin)
|
34
|
+
plugin_interface = PLUGIN_INTERFACE
|
35
|
+
|
36
|
+
if plugin.respond_to?(:id)
|
37
|
+
if BUILTIN_TYPES.include?(plugin.id)
|
38
|
+
plugin_interface = PLUGIN_INTERFACE - [:detect_type]
|
39
|
+
end
|
40
|
+
|
41
|
+
if plugin.id == :unknown
|
42
|
+
raise <<~MSG
|
43
|
+
plugin #{plugin.inspect} defined #id to = :unknown, but this is not \
|
44
|
+
allowed because it would undermine the utility of the #empty? method \
|
45
|
+
on the diff.
|
46
|
+
MSG
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
missing = plugin_interface.filter do |method_name|
|
51
|
+
!plugin.respond_to?(method_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
if missing.any?
|
55
|
+
raise <<~MSG
|
56
|
+
plugin #{plugin.inspect} does not respond to required methods:
|
57
|
+
these are required: #{plugin_interface}
|
58
|
+
these were missing: #{missing.inspect}
|
59
|
+
MSG
|
60
|
+
end
|
61
|
+
|
62
|
+
::Specdiff.plugins << plugin
|
63
|
+
end
|
64
|
+
|
65
|
+
# private
|
66
|
+
def self._clear_plugins!
|
67
|
+
threadlocal[THREADLOCAL_PLUGINS_KEY] = []
|
68
|
+
end
|
69
|
+
_clear_plugins!
|
70
|
+
|
71
|
+
module Plugins
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "hashdiff"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module WebMock
|
5
|
+
class RequestBodyDiff
|
6
|
+
def initialize(request_signature, request_stub)
|
7
|
+
@request_signature = request_signature
|
8
|
+
@request_stub = request_stub
|
9
|
+
end
|
10
|
+
|
11
|
+
PrettyPrintableThingy = Struct.new(:specdiff) do
|
12
|
+
# webmock does not print the diff if it responds true to this.
|
13
|
+
def empty?
|
14
|
+
specdiff.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
# webmock prints the diff by passing us to PP.pp, which in turn uses this
|
18
|
+
# method.
|
19
|
+
def pretty_print(pp)
|
20
|
+
pp.text("\r") # remove a space that isn't supposed to be there
|
21
|
+
pp.text(specdiff.to_s)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def body_diff
|
26
|
+
specdiff = Specdiff.diff(request_stub_body, request_signature.body)
|
27
|
+
PrettyPrintableThingy.new(specdiff)
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :request_signature, :request_stub
|
31
|
+
private :request_signature, :request_stub
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def request_stub_body
|
36
|
+
request_stub.request_pattern &&
|
37
|
+
request_stub.request_pattern.body_pattern &&
|
38
|
+
request_stub.request_pattern.body_pattern.pattern
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "webmock/request_body_diff"
|
data/lib/specdiff.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative "specdiff/version"
|
2
|
+
require_relative "specdiff/threadlocal"
|
3
|
+
require_relative "specdiff/config"
|
4
|
+
require_relative "specdiff/colorize"
|
5
|
+
|
6
|
+
module Specdiff
|
7
|
+
# Diff two things
|
8
|
+
def self.diff(...)
|
9
|
+
::Specdiff::Differ.call(...)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
require_relative "specdiff/diff"
|
14
|
+
require_relative "specdiff/differ"
|
15
|
+
require_relative "specdiff/plugin"
|
16
|
+
require_relative "specdiff/plugins"
|
data/specdiff.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/specdiff/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "specdiff"
|
7
|
+
spec.version = Specdiff::VERSION
|
8
|
+
spec.authors = ["Odin Heggvold Bekkelund"]
|
9
|
+
spec.email = ["odinhb@protonmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Improved request body diffs for webmock"
|
12
|
+
spec.homepage = "https://github.com/odinhb/specdiff"
|
13
|
+
spec.license = "MIT"
|
14
|
+
spec.required_ruby_version = ">= 3.0.0"
|
15
|
+
|
16
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
17
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
18
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
23
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
24
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
spec.add_dependency "hashdiff", "~> 1.0"
|
30
|
+
spec.add_dependency "diff-lcs", "~> 1.5"
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: specdiff
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Odin Heggvold Bekkelund
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-11-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hashdiff
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: diff-lcs
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.5'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.5'
|
41
|
+
description:
|
42
|
+
email:
|
43
|
+
- odinhb@protonmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".rspec"
|
49
|
+
- ".rubocop.yml"
|
50
|
+
- ".tool-versions"
|
51
|
+
- CHANGELOG.md
|
52
|
+
- Gemfile
|
53
|
+
- Gemfile.lock
|
54
|
+
- LICENSE.txt
|
55
|
+
- README.md
|
56
|
+
- Rakefile
|
57
|
+
- examples/webmock/Gemfile
|
58
|
+
- examples/webmock/Gemfile.lock
|
59
|
+
- examples/webmock/json.rb
|
60
|
+
- examples/webmock/text.rb
|
61
|
+
- glossary.txt
|
62
|
+
- lib/specdiff.rb
|
63
|
+
- lib/specdiff/colorize.rb
|
64
|
+
- lib/specdiff/config.rb
|
65
|
+
- lib/specdiff/diff.rb
|
66
|
+
- lib/specdiff/differ.rb
|
67
|
+
- lib/specdiff/differ/hashdiff.rb
|
68
|
+
- lib/specdiff/differ/not_found.rb
|
69
|
+
- lib/specdiff/differ/text.rb
|
70
|
+
- lib/specdiff/plugin.rb
|
71
|
+
- lib/specdiff/plugins.rb
|
72
|
+
- lib/specdiff/plugins/json.rb
|
73
|
+
- lib/specdiff/threadlocal.rb
|
74
|
+
- lib/specdiff/version.rb
|
75
|
+
- lib/specdiff/webmock.rb
|
76
|
+
- lib/specdiff/webmock/request_body_diff.rb
|
77
|
+
- specdiff.gemspec
|
78
|
+
homepage: https://github.com/odinhb/specdiff
|
79
|
+
licenses:
|
80
|
+
- MIT
|
81
|
+
metadata:
|
82
|
+
homepage_uri: https://github.com/odinhb/specdiff
|
83
|
+
source_code_uri: https://github.com/odinhb/specdiff
|
84
|
+
changelog_uri: https://github.com/odinhb/specdiff/CHANGELOG.md
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 3.0.0
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubygems_version: 3.4.10
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: Improved request body diffs for webmock
|
104
|
+
test_files: []
|