swagger-diff 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4b908f910198d381cab6749fceb46dc189fcb824
4
- data.tar.gz: f78caffe05399b68b448a021e7dd4b8c19ef1fba
3
+ metadata.gz: 7025ab8a26aa9eb452cbb399bf2fbde273f46299
4
+ data.tar.gz: 2a57c963078b714a2e1fa042ce12b2c3fbfa37a3
5
5
  SHA512:
6
- metadata.gz: 7e534c39a09234677cf591f360d1f329a6f511cc16a052bd2ec49a474bcc87413cd78b4ce40b8e0b8a5408e6b78e7655b6f575c55d16047c3910ed382ab3dad0
7
- data.tar.gz: d714909471d1c5d605d67c88f44fd07985d70abe94e1ba434b3a57522ab577f01e056fd91de566ff22e2c1c474cf44319576a02ef6b78b7e4ff4c871d1fc89a3
6
+ metadata.gz: 5963d3d5faf6c84097ffa29ab5cbe45a91b9b7dfa945571aa418ea6a1cb48c9c907a125f47df06c31f5f8b6bb4bdb0c0043a339d15fdb0ccebb6c4545e79b575
7
+ data.tar.gz: 5f3579dd89962e0ebb2e88440f8b195886a00002fc147b94e0369f81be4ec2a686dc008918e4a5b129374e089691ebbc3ecfdb57c60bc8359857d00b6da76127
@@ -2,7 +2,7 @@ Metrics/AbcSize:
2
2
  Max: 30
3
3
 
4
4
  Metrics/ClassLength:
5
- Max: 200
5
+ Max: 240
6
6
 
7
7
  Metrics/LineLength:
8
8
  Max: 120
@@ -1 +1 @@
1
- 2.2.3
1
+ 2.3.1
@@ -1,5 +1,13 @@
1
1
  language: ruby
2
2
  cache: bundler
3
+ rvm:
4
+ - 2.0
5
+ - 2.1.9
6
+ - 2.2.5
7
+ - 2.3.1
8
+ before_install:
9
+ - gem update --system
10
+ - rvm @global do gem install bundler
3
11
  branches:
4
12
  only:
5
13
  - master
@@ -1,49 +1,88 @@
1
1
  # Change Log
2
2
 
3
- ## 1.0.5 (2015-11-16)
3
+ All notable changes to this project will be documented in this file.
4
+ This project adheres to [Semantic Versioning](http://semver.org/).
4
5
 
5
- ### Bugs Fixed
6
+ ## [Unreleased]
7
+
8
+ ## [1.1.0] - 2016-05-20
9
+
10
+ ### Added
11
+
12
+ * Added a [Code of Conduct](CODE_OF_CONDUCT.md)
13
+ * Added a matrix build of 2.0, 2.1, 2.2, and 2.3 to Travis
14
+ * [#33](https://github.com/civisanalytics/swagger-diff/pull/33)
15
+ added a changelog feature
16
+ * [#35](https://github.com/civisanalytics/swagger-diff/pull/35)
17
+ print a warning if an OAI specification is invalid
18
+
19
+ ### Changed
20
+
21
+ * Bumped the Ruby version for development to 2.3.1
22
+ * Bumped the RuboCop version for development to 0.40
23
+ * Bumped the WebMock version for development to 2.0
24
+ * Bumped the Rake version for development to 11.1
25
+
26
+ ### Fixed
27
+
28
+ * [#27](https://github.com/civisanalytics/swagger-diff/pull/27)
29
+ made the Ruby 2.0+ dependency explicit
30
+ * [#32](https://github.com/civisanalytics/swagger-diff/pull/32)
31
+ replaced the Swagger parser
32
+
33
+ ## [1.0.5] - 2015-11-16
34
+
35
+ ### Fixed
6
36
 
7
37
  * [#18](https://github.com/civisanalytics/swagger-diff/pull/18)
8
38
  parse non-ref parameter schemas (`allOf`, `properties`, and `items`)
9
39
 
10
- ## 1.0.4 (2015-11-11)
40
+ ## [1.0.4] - 2015-11-11
11
41
 
12
- ### Bugs Fixed
42
+ ### Fixed
13
43
 
14
44
  * [#14](https://github.com/civisanalytics/swagger-diff/pull/14)
15
45
  allow schema definitions without properties
16
46
  * [#15](https://github.com/civisanalytics/swagger-diff/pull/15)
17
47
  parse non-ref response schemas (`allOf`, `properties`, and `items`)
18
48
 
19
- ## 1.0.3 (2015-11-04)
49
+ ## [1.0.3] - 2015-11-04
20
50
 
21
- ### Changes
51
+ ### Added
22
52
 
23
53
  * Added a default Rake task to run Rubocop and RSpec
24
54
  * Added [CONTRIBUTING.md](CONTRIBUTING.md)
25
55
 
26
- ### Bugs Fixed
56
+ ### Fixed
27
57
 
28
58
  * [#8](https://github.com/civisanalytics/swagger-diff/pull/8)
29
59
  fixed parsing of header and formData parameters
30
60
  * [#10](https://github.com/civisanalytics/swagger-diff/pull/10)
31
61
  detect if a parameter's location (*i.e.*, `in` value) changes
32
62
 
33
- ## 1.0.2 (2015-10-08)
63
+ ## [1.0.2] - 2015-10-08
34
64
 
35
- ### Bugs Fixed
65
+ ### Fixed
36
66
 
37
67
  * [#3](https://github.com/civisanalytics/swagger-diff/pull/3)
38
68
  treat required elements in new child parameters as backwards-compatible
39
69
 
40
- ## 1.0.1 (2015-10-01)
70
+ ## [1.0.1] - 2015-10-01
41
71
 
42
- ### Bugs Fixed
72
+ ### Fixed
43
73
 
44
74
  * [#1](https://github.com/civisanalytics/swagger-diff/pull/1)
45
75
  added missing rspec-expectations dependency
46
76
 
47
- ## 1.0.0 (2015-10-01)
77
+ ## [1.0.0] - 2015-10-01 - [YANKED]
48
78
 
49
79
  * Initial Release
80
+
81
+ [Unreleased]: https://github.com/civisanalytics/swagger-diff/compare/v1.1.0...HEAD
82
+ [1.1.0]: https://github.com/civisanalytics/swagger-diff/compare/v1.0.5...v1.1.0
83
+ [1.0.5]: https://github.com/civisanalytics/swagger-diff/compare/v1.0.4...v1.0.5
84
+ [1.0.4]: https://github.com/civisanalytics/swagger-diff/compare/v1.0.3...v1.0.4
85
+ [1.0.3]: https://github.com/civisanalytics/swagger-diff/compare/v1.0.2...v1.0.3
86
+ [1.0.2]: https://github.com/civisanalytics/swagger-diff/compare/v1.0.1...v1.0.2
87
+ [1.0.1]: https://github.com/civisanalytics/swagger-diff/compare/v1.0.0...v1.0.1
88
+ [1.0.0]: https://github.com/civisanalytics/swagger-diff/commit/0f6390eedef2428e78bbd816cbb14f724543f59b
@@ -0,0 +1,50 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This Code of Conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at opensource@civisanalytics.com.
39
+ All complaints will be reviewed and investigated and will result in a response
40
+ that is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+
45
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
46
+ version 1.3.0, available at
47
+ [http://contributor-covenant.org/version/1/3/0/][version]
48
+
49
+ [homepage]: http://contributor-covenant.org
50
+ [version]: http://contributor-covenant.org/version/1/3/0/
@@ -1,6 +1,8 @@
1
1
  # Contributing to Swagger::Diff
2
2
 
3
- We welcome pull requests from everyone!
3
+ We welcome bug reports and pull requests from everyone!
4
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
5
+
4
6
 
5
7
  ## Getting Started
6
8
 
File without changes
data/README.md CHANGED
@@ -9,7 +9,8 @@
9
9
  > You can tell me by the way I walk - Genesis
10
10
 
11
11
  Swagger::Diff is a utility for comparing two different
12
- [Swagger](http://swagger.io/) specifications.
12
+ [Open API Initiative (OAI)](https://openapis.org/) specifications (fka
13
+ [Swagger](http://swagger.io/) specifications).
13
14
  Its intended use is to determine whether a newer API specification is
14
15
  backwards-compatible with an older API specification.
15
16
  It provides both an [RSpec](http://rspec.info/) matcher and helper functions
@@ -27,6 +28,9 @@ Specifications are considered backwards compatible if:
27
28
  - all response attributes in the old specification have the same type in the new
28
29
  one
29
30
 
31
+ It can also be used to enumerate all changes between two specifications (*i.e.*,
32
+ to generate a changelog).
33
+
30
34
  Read more on the [Civis Analytics blog](https://civisanalytics.com/blog/engineering/2015/10/02/using-swagger-to-detect-breaking-api-changes/).
31
35
 
32
36
  ## Installation
@@ -47,18 +51,15 @@ Or install it yourself as:
47
51
 
48
52
  ## Usage
49
53
 
50
- Swagger::Diff uses the [Swagger](https://github.com/swagger-rb/swagger-rb) gem
51
- to parse Swagger specifications.
52
- Specifications can be any
53
- [supported format](https://github.com/swagger-rb/swagger-rb/tree/v0.2.3#parsing):
54
+ Swagger specifications can be any valid Swagger file format, raw or parsed:
54
55
 
55
- - the path to a file containing a Swagger specification.
56
+ - the path to a file containing an OAI specification.
56
57
  This may be local (*e.g.*, `/path/to/swagger.json`) or remote (*e.g.*,
57
58
  `http://host.domain/swagger.yml`)
58
- - a Hash containing a parsed Swagger specification (*e.g.*, the output of
59
+ - a Hash containing a parsed OAI specification (*e.g.*, the output of
59
60
  `JSON.parse`)
60
- - a string of JSON containing a Swagger specification
61
- - a string of YAML containing a Swagger specification
61
+ - a string of JSON containing an OAI specification
62
+ - a string of YAML containing an OAI specification
62
63
 
63
64
  ### RSpec
64
65
 
@@ -97,17 +98,53 @@ request parameters, and response attributes; *e.g.*,
97
98
  }
98
99
  ```
99
100
 
101
+ You can also directly invoke the changes function:
102
+
103
+ ```ruby
104
+ diff = Swagger::Diff::Diff.new(<old>, <new>)
105
+ diff.changes
106
+ ```
107
+
108
+ `#changes` will return a hash containing the changed endpoints, request
109
+ parameters, and response attributes; *e.g.*,
110
+
111
+ ```ruby
112
+ { new_endpoints: ['delete /pets/{}', 'get /pets/{}', 'post /pets'],
113
+ new_request_params: {
114
+ 'get /pets' => ['new request param: tags (in: query, type: array)',
115
+ 'new request param: limit (in: query, type: integer)'] },
116
+ new_response_attributes: {},
117
+ removed_endpoints: [],
118
+ removed_request_params: {},
119
+ removed_response_attributes: {}
120
+ }
121
+ ```
122
+
100
123
  ### Command-Line
101
124
 
102
125
  It also includes a command-line version:
103
126
 
104
127
  ```bash
105
- $ swagger-diff <old> <new>
128
+ $ swagger-diff -i <old> <new>
106
129
  ```
107
130
 
108
131
  `swagger-diff` will print a list of any backwards-incompatibilities `new` has
109
132
  when compared to `old`.
110
133
 
134
+ For backwards-compatibility with previous versions of `swagger-diff`, the `-i`
135
+ argument is optional:
136
+
137
+ ```bash
138
+ $ swagger-diff <old> <new>
139
+ ```
140
+
141
+ The command-line version can also be used to generate a list of all changes
142
+ (*i.e.*, a changelog):
143
+
144
+ ```bash
145
+ $ swagger-diff -c <old> <new>
146
+ ```
147
+
111
148
  ## Gem Development
112
149
 
113
150
  After checking out the repo, run `bin/setup` to install dependencies.
@@ -122,4 +159,18 @@ See [CONTRIBUTING](CONTRIBUTING.md).
122
159
 
123
160
  ## License
124
161
 
125
- Swagger::Diff is released under the [BSD 3-Clause License](LICENSE.txt).
162
+ Swagger::Diff is released under the [BSD 3-Clause License](LICENSE.md).
163
+
164
+ ## OpenAPI (fka Swagger) Specification License
165
+
166
+ Swagger::Diff includes an
167
+ [unmodified copy of the OpenAPI Specification](schema/oai/schema.json).
168
+ The OpenAPI Specification is licensed under the
169
+ [Apache License, Version 2.0](schema/oai/LICENSE.md).
170
+
171
+ ## JSON Schema Specification License
172
+
173
+ Swagger::Diff includes an
174
+ [unmodified copy of the JSON Schema Specification, draft v4](schema/json/schema.json).
175
+ The JSON Schema Specification is licensed under the
176
+ [Simplified BSD License](schema/json/LICENSE.md).
@@ -1,17 +1,49 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'optparse'
3
4
  require 'swagger/diff'
4
5
 
6
+ options = {}
7
+ OptionParser.new do |opts|
8
+ opts.banner = 'Usage: swagger-diff [options] <old> <new>'
9
+
10
+ opts.on('-c', '--changes',
11
+ 'Generate a list of changes between <new>',
12
+ 'and <old>') do |c|
13
+ options[:changes] = c
14
+ end
15
+
16
+ opts.on('-i', '--incompatibilities',
17
+ 'Checks <new> for backwards-compatibility',
18
+ 'with <old>. If <new> is incompatible, a',
19
+ 'list of incompatibilities will be printed.') do |i|
20
+ options[:incompatibilities] = i
21
+ end
22
+
23
+ opts.on_tail('-h', '--help', 'This message') do
24
+ puts opts
25
+ exit
26
+ end
27
+
28
+ opts.on_tail('-v', '--version', 'Display the version') do
29
+ puts Swagger::Diff::VERSION
30
+ exit
31
+ end
32
+
33
+ options[:help] = opts
34
+ end.parse!
35
+
5
36
  if ARGV.length == 2
6
37
  diff = Swagger::Diff::Diff.new(ARGV[0], ARGV[1])
7
38
 
8
- unless diff.compatible?
9
- puts diff.incompatibilities_message
10
- exit 1
39
+ if options[:changes]
40
+ puts diff.changes_message
41
+ else
42
+ unless diff.compatible?
43
+ puts diff.incompatibilities_message
44
+ exit 1
45
+ end
11
46
  end
12
47
  else
13
- puts 'Usage: swagger-diff <old> <new>
14
-
15
- Checks <new> for backwards-compatibility with <old>. If <new> is incompatible,
16
- a list of incompatibilities will be printed.'
48
+ puts options[:help]
17
49
  end
@@ -1,8 +1,10 @@
1
- require 'forwardable' # Needed to require swagger-core.
2
- require 'swagger'
1
+ require 'json'
2
+ require 'open-uri'
3
+ require 'set'
4
+ require 'yaml'
5
+ require 'json-schema'
3
6
  require 'rspec/expectations'
4
7
  require 'swagger/diff/diff'
5
- require 'swagger/diff/patch'
6
8
  require 'swagger/diff/rspec_matchers'
7
9
  require 'swagger/diff/specification'
8
10
  require 'swagger/diff/version'
@@ -6,37 +6,69 @@ module Swagger
6
6
  @old_specification = Swagger::Diff::Specification.new(old)
7
7
  end
8
8
 
9
+ def changes
10
+ @changes ||= {
11
+ new_endpoints: new_endpoints.to_a.sort,
12
+ removed_endpoints: missing_endpoints.to_a.sort,
13
+ new_request_params: new_or_changed_request_params,
14
+ removed_request_params: incompatible_request_params,
15
+ new_response_attributes: new_or_changed_response_attributes,
16
+ removed_response_attributes: incompatible_response_attributes
17
+ }
18
+ end
19
+
20
+ def changes_message
21
+ changed_endpoints_message + changed_params_message + changed_attrs_message
22
+ end
23
+
9
24
  def compatible?
10
25
  endpoints_compatible? && requests_compatible? && responses_compatible?
11
26
  end
12
27
 
13
28
  def incompatibilities
14
- { endpoints: missing_endpoints.to_a.sort,
29
+ @incompatibilities ||= {
30
+ endpoints: missing_endpoints.to_a.sort,
15
31
  request_params: incompatible_request_params,
16
- response_attributes: incompatible_response_attributes }
32
+ response_attributes: incompatible_response_attributes
33
+ }
17
34
  end
18
35
 
19
36
  def incompatibilities_message
20
37
  msg = ''
21
- if incompatibilities[:endpoints]
22
- msg += incompatibilities_message_endpoints(incompatibilities[:endpoints])
23
- end
24
- if incompatibilities[:request_params]
25
- msg += incompatibilities_message_params(incompatibilities[:request_params])
26
- end
27
- if incompatibilities[:response_attributes]
28
- msg += incompatibilities_message_attributes(incompatibilities[:response_attributes])
29
- end
38
+ msg += endpoints_message('missing', incompatibilities[:endpoints])
39
+ msg += params_message('incompatible', incompatibilities[:request_params])
40
+ msg += attributes_message('incompatible', incompatibilities[:response_attributes])
30
41
  msg
31
42
  end
32
43
 
33
44
  private
34
45
 
35
- def incompatibilities_message_endpoints(endpoints)
46
+ def changed_endpoints_message
47
+ msg = ''
48
+ msg += endpoints_message('new', changes[:new_endpoints])
49
+ msg += endpoints_message('removed', changes[:removed_endpoints])
50
+ msg
51
+ end
52
+
53
+ def changed_params_message
54
+ msg = ''
55
+ msg += params_message('new', changes[:new_request_params])
56
+ msg += params_message('removed', changes[:removed_request_params])
57
+ msg
58
+ end
59
+
60
+ def changed_attrs_message
61
+ msg = ''
62
+ msg += attributes_message('new', changes[:new_response_attributes])
63
+ msg += attributes_message('removed', changes[:removed_response_attributes])
64
+ msg
65
+ end
66
+
67
+ def endpoints_message(type, endpoints)
36
68
  if endpoints.empty?
37
69
  ''
38
70
  else
39
- msg = "- missing endpoints\n"
71
+ msg = "- #{type} endpoints\n"
40
72
  endpoints.each do |endpoint|
41
73
  msg += " - #{endpoint}\n"
42
74
  end
@@ -44,11 +76,11 @@ module Swagger
44
76
  end
45
77
  end
46
78
 
47
- def incompatibilities_message_inner(typestr, collection)
79
+ def inner_message(nature, type, collection)
48
80
  if collection.nil? || collection.empty?
49
81
  ''
50
82
  else
51
- msg = "- incompatible #{typestr}\n"
83
+ msg = "- #{nature} #{type}\n"
52
84
  collection.sort.each do |endpoint, attributes|
53
85
  msg += " - #{endpoint}\n"
54
86
  attributes.each do |attribute|
@@ -59,27 +91,45 @@ module Swagger
59
91
  end
60
92
  end
61
93
 
62
- def incompatibilities_message_params(params)
63
- incompatibilities_message_inner('request params', params)
94
+ def params_message(type, params)
95
+ inner_message(type, 'request params', params)
64
96
  end
65
97
 
66
- def incompatibilities_message_attributes(attributes)
67
- incompatibilities_message_inner('response attributes', attributes)
98
+ def attributes_message(type, attributes)
99
+ inner_message(type, 'response attributes', attributes)
68
100
  end
69
101
 
70
102
  def missing_endpoints
71
103
  @old_specification.endpoints - @new_specification.endpoints
72
104
  end
73
105
 
74
- def incompatible_request_params
106
+ def new_endpoints
107
+ @new_specification.endpoints - @old_specification.endpoints
108
+ end
109
+
110
+ def change_hash(enumerator)
75
111
  ret = {}
76
- incompatible_request_params_enumerator.each do |key, val|
112
+ enumerator.each do |key, val|
77
113
  ret[key] ||= []
78
114
  ret[key] << val
79
115
  end
80
116
  ret
81
117
  end
82
118
 
119
+ def incompatible_request_params
120
+ change_hash(incompatible_request_params_enumerator)
121
+ end
122
+
123
+ def new_or_changed_request_params
124
+ enumerator = changed_request_params_enumerator(
125
+ @new_specification,
126
+ @old_specification,
127
+ '%{req} is no longer required',
128
+ 'new request param: %{req}'
129
+ )
130
+ change_hash(enumerator)
131
+ end
132
+
83
133
  def new_child?(req, old)
84
134
  idx = req.rindex('/')
85
135
  return false unless idx
@@ -87,49 +137,72 @@ module Swagger
87
137
  !old.any? { |param| param.start_with?(key) }
88
138
  end
89
139
 
90
- def incompatible_request_params_enumerator
140
+ def changed_request_params_enumerator(from, to, req_msg, missing_msg)
91
141
  Enumerator.new do |yielder|
92
- @old_specification.request_params.each do |key, old_params|
93
- new_params = @new_specification.request_params[key]
142
+ from.request_params.each do |key, old_params|
143
+ new_params = to.request_params[key]
94
144
  next if new_params.nil?
95
145
  (new_params[:required] - old_params[:required]).each do |req|
96
146
  next if new_child?(req, old_params[:all])
97
- yielder << [key, "new required request param: #{req}"]
147
+ yielder << [key, req_msg % { req: req }]
98
148
  end
99
149
  (old_params[:all] - new_params[:all]).each do |req|
100
- yielder << [key, "missing request param: #{req}"]
150
+ yielder << [key, missing_msg % { req: req }]
101
151
  end
102
152
  end
103
153
  end.lazy
104
154
  end
105
155
 
156
+ def incompatible_request_params_enumerator
157
+ changed_request_params_enumerator(
158
+ @old_specification,
159
+ @new_specification,
160
+ 'new required request param: %{req}',
161
+ 'missing request param: %{req}'
162
+ )
163
+ end
164
+
106
165
  def incompatible_response_attributes
107
- ret = {}
108
- incompatible_response_attributes_enumerator.each do |key, val|
109
- ret[key] ||= []
110
- ret[key] << val
111
- end
112
- ret
166
+ change_hash(incompatible_response_attributes_enumerator)
113
167
  end
114
168
 
115
- def incompatible_response_attributes_enumerator
169
+ def new_or_changed_response_attributes
170
+ enumerator = changed_response_attributes_enumerator(
171
+ @new_specification,
172
+ @old_specification,
173
+ 'new attribute for %{code} response: %{resp}',
174
+ 'new %{code} response'
175
+ )
176
+ change_hash(enumerator)
177
+ end
178
+
179
+ def changed_response_attributes_enumerator(from, to, attr_msg, code_msg)
116
180
  Enumerator.new do |yielder|
117
- @old_specification.response_attributes.each do |key, old_attributes|
118
- new_attributes = @new_specification.response_attributes[key]
181
+ from.response_attributes.each do |key, old_attributes|
182
+ new_attributes = to.response_attributes[key]
119
183
  next if new_attributes.nil?
120
184
  old_attributes.keys.each do |code|
121
185
  if new_attributes.key?(code)
122
186
  (old_attributes[code] - new_attributes[code]).each do |resp|
123
- yielder << [key, "missing attribute from #{code} response: #{resp}"]
187
+ yielder << [key, attr_msg % { code: code, resp: resp }]
124
188
  end
125
189
  else
126
- yielder << [key, "missing #{code} response"]
190
+ yielder << [key, code_msg % { code: code }]
127
191
  end
128
192
  end
129
193
  end
130
194
  end.lazy
131
195
  end
132
196
 
197
+ def incompatible_response_attributes_enumerator
198
+ changed_response_attributes_enumerator(
199
+ @old_specification,
200
+ @new_specification,
201
+ 'missing attribute from %{code} response: %{resp}',
202
+ 'missing %{code} response'
203
+ )
204
+ end
205
+
133
206
  def endpoints_compatible?
134
207
  missing_endpoints.empty?
135
208
  end