rspec-rails-api 0.3.4 → 0.4.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 +4 -4
- data/CHANGELOG.md +42 -0
- data/README.md +39 -36
- data/Rakefile +3 -0
- data/lib/rspec/rails/api/dsl/example.rb +93 -15
- data/lib/rspec/rails/api/dsl/example_group.rb +134 -48
- data/lib/rspec/rails/api/entity_config.rb +31 -4
- data/lib/rspec/rails/api/field_config.rb +8 -0
- data/lib/rspec/rails/api/matchers.rb +16 -3
- data/lib/rspec/rails/api/metadata.rb +135 -11
- data/lib/rspec/rails/api/open_api_renderer.rb +171 -13
- data/lib/rspec/rails/api/utils.rb +64 -5
- data/lib/rspec/rails/api/version.rb +1 -1
- data/lib/rspec_rails_api.rb +8 -0
- data/rspec-rails-api.gemspec +6 -4
- metadata +21 -6
@@ -27,6 +27,13 @@ module RSpec
|
|
27
27
|
@api_license = {}
|
28
28
|
end
|
29
29
|
|
30
|
+
##
|
31
|
+
# Merges example context definition with the renderer data
|
32
|
+
#
|
33
|
+
# @param context [Hash] Metadata hash
|
34
|
+
# @param dump_metadata [Boolean] Saves the raw metadata in `tmp/rra_metadata.yaml` for debugging
|
35
|
+
#
|
36
|
+
# @return [void
|
30
37
|
def merge_context(context, dump_metadata: false)
|
31
38
|
@metadata[:resources].deep_merge! context[:resources]
|
32
39
|
@metadata[:entities].deep_merge! context[:entities]
|
@@ -35,8 +42,14 @@ module RSpec
|
|
35
42
|
File.write ::Rails.root.join('tmp', 'rra_metadata.yaml'), context.to_yaml if dump_metadata
|
36
43
|
end
|
37
44
|
|
45
|
+
##
|
46
|
+
# Write OpenAPI files
|
47
|
+
#
|
48
|
+
# @param path [String, nil] Where to save the files. Defaults to `/tmp/rspec_api_rails.*` when unset
|
49
|
+
# @param only [[Symbol]] Formats to save the file to. Allowed values are `:yaml` and `:json`
|
50
|
+
#
|
51
|
+
# @return [void]
|
38
52
|
def write_files(path = nil, only: %i[yaml json])
|
39
|
-
content = prepare_metadata
|
40
53
|
path ||= ::Rails.root.join('tmp', 'rspec_api_rails')
|
41
54
|
|
42
55
|
file_types = %i[yaml json]
|
@@ -44,29 +57,49 @@ module RSpec
|
|
44
57
|
only.each do |type|
|
45
58
|
next unless file_types.include? type
|
46
59
|
|
47
|
-
File.write "#{path}.#{type}",
|
60
|
+
File.write "#{path}.#{type}", prepare_metadata.send("to_#{type}")
|
48
61
|
end
|
49
62
|
end
|
50
63
|
|
64
|
+
##
|
65
|
+
# Extracts metadata from context to generate an OpenAPI structure
|
66
|
+
#
|
67
|
+
# @return [Hash] The OpenAPI structure
|
51
68
|
def prepare_metadata
|
52
|
-
# Example: https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore-expanded.yaml
|
53
69
|
extract_metadatas
|
54
|
-
|
70
|
+
# Example: https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore-expanded.yaml
|
71
|
+
hash = {
|
55
72
|
openapi: '3.0.0',
|
56
73
|
info: @api_infos,
|
57
74
|
servers: @api_servers,
|
58
75
|
paths: @api_paths,
|
59
76
|
components: @api_components,
|
60
77
|
tags: @api_tags,
|
61
|
-
}
|
78
|
+
}
|
79
|
+
JSON.parse(JSON.pretty_generate(hash))
|
62
80
|
end
|
63
81
|
|
82
|
+
##
|
83
|
+
# Sets the contact field
|
84
|
+
#
|
85
|
+
# @param name [String, nil] Contact name
|
86
|
+
# @param email [String, nil] Contact Email
|
87
|
+
# @param url [String, nil] Contact URL
|
88
|
+
#
|
89
|
+
# @return [void]
|
64
90
|
def api_contact=(name: nil, email: nil, url: nil)
|
65
91
|
@api_contact[:name] = name if name
|
66
92
|
@api_contact[:email] = email if email
|
67
93
|
@api_contact[:url] = url if url
|
68
94
|
end
|
69
95
|
|
96
|
+
##
|
97
|
+
# Sets the license field
|
98
|
+
#
|
99
|
+
# @param name [String, nil] License name
|
100
|
+
# @param url [String, nil] License URL
|
101
|
+
#
|
102
|
+
# @return [void]
|
70
103
|
def api_license=(name: nil, url: nil)
|
71
104
|
@api_license[:name] = name if name
|
72
105
|
@api_license[:url] = url if url
|
@@ -74,14 +107,26 @@ module RSpec
|
|
74
107
|
|
75
108
|
private
|
76
109
|
|
110
|
+
##
|
111
|
+
# Extracts metadata for rendering
|
112
|
+
#
|
113
|
+
# @return [void]
|
77
114
|
def extract_metadatas
|
78
115
|
extract_from_resources
|
79
116
|
api_infos
|
80
117
|
api_servers
|
81
118
|
end
|
82
119
|
|
83
|
-
|
120
|
+
##
|
121
|
+
# Extracts metadata from resources for rendering
|
122
|
+
#
|
123
|
+
# @return [void]
|
124
|
+
def extract_from_resources # rubocop:disable Metrics/MethodLength
|
125
|
+
@api_components[:schemas] ||= {}
|
84
126
|
@metadata[:resources].each do |resource_key, resource|
|
127
|
+
resource[:entities].each do |name, entity|
|
128
|
+
@api_components[:schemas][name] = process_entity(entity)
|
129
|
+
end
|
85
130
|
@api_tags.push(
|
86
131
|
name: resource_key.to_s,
|
87
132
|
description: resource[:description]
|
@@ -90,6 +135,14 @@ module RSpec
|
|
90
135
|
end
|
91
136
|
end
|
92
137
|
|
138
|
+
##
|
139
|
+
# Processes a resource from metadata
|
140
|
+
#
|
141
|
+
# @param resource [Symbol, nil] Resource name
|
142
|
+
# @param resource_config [Hash, nil] Resource declaration
|
143
|
+
#
|
144
|
+
#
|
145
|
+
# @return [void]
|
93
146
|
def process_resource(resource: nil, resource_config: nil) # rubocop:disable Metrics/MethodLength
|
94
147
|
http_verbs = %i[get post put patch delete]
|
95
148
|
resource_config[:paths].each do |path_key, path|
|
@@ -111,6 +164,10 @@ module RSpec
|
|
111
164
|
end
|
112
165
|
end
|
113
166
|
|
167
|
+
##
|
168
|
+
# Processes path parameters for rendering
|
169
|
+
#
|
170
|
+
# @param params [Hash] Path parameters
|
114
171
|
def process_path_params(params)
|
115
172
|
parameters = []
|
116
173
|
params.each do |name, param|
|
@@ -120,6 +177,39 @@ module RSpec
|
|
120
177
|
parameters
|
121
178
|
end
|
122
179
|
|
180
|
+
def process_entity(entity) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
181
|
+
schema = {
|
182
|
+
properties: {},
|
183
|
+
}
|
184
|
+
required = []
|
185
|
+
entity.fields.each do |name, field|
|
186
|
+
property = {
|
187
|
+
description: field.description,
|
188
|
+
type: PARAM_TYPES[field.type][:type],
|
189
|
+
}
|
190
|
+
property[:format] = PARAM_TYPES[field.type][:format] if PARAM_TYPES[field.type][:format]
|
191
|
+
schema[:properties][name] = property
|
192
|
+
# Primitives support
|
193
|
+
if PRIMITIVES.include? field.attributes
|
194
|
+
property[:items] =
|
195
|
+
{ type: field.attributes.to_s.split('_').last.to_sym }
|
196
|
+
end
|
197
|
+
required.push name unless field.required == false
|
198
|
+
end
|
199
|
+
|
200
|
+
schema[:required] = required unless required.size.zero?
|
201
|
+
|
202
|
+
schema
|
203
|
+
end
|
204
|
+
|
205
|
+
##
|
206
|
+
# Processes a path parameter from metadata
|
207
|
+
#
|
208
|
+
# @param name [Symbol, nil] Parameter name
|
209
|
+
# @param param [Hash, nil] Parameter declaration
|
210
|
+
#
|
211
|
+
#
|
212
|
+
# @return [void]
|
123
213
|
def process_path_param(name, param) # rubocop:disable Metrics/MethodLength
|
124
214
|
parameter = {
|
125
215
|
name: name.to_s,
|
@@ -136,6 +226,19 @@ module RSpec
|
|
136
226
|
parameter
|
137
227
|
end
|
138
228
|
|
229
|
+
##
|
230
|
+
# Processes an action from metadata
|
231
|
+
#
|
232
|
+
# @param resource [Symbol, nil] Target resource
|
233
|
+
# @param path [Symbol, nil] Target path
|
234
|
+
# @param path_config [Hash, nil] Path configuraton
|
235
|
+
# @param action_config [Symbol, nil] Target action
|
236
|
+
# @param parameters [Array, nil] Path parameters
|
237
|
+
#
|
238
|
+
# @return [void]
|
239
|
+
#
|
240
|
+
# FIXME: Rename "action_config" to "action"
|
241
|
+
# FIXME: Rename "parameters" to "path_parameters"
|
139
242
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
140
243
|
def process_action(resource: nil, path: nil, path_config: nil, action_config: nil, parameters: nil)
|
141
244
|
responses = {}
|
@@ -154,10 +257,11 @@ module RSpec
|
|
154
257
|
responses[status_key] = process_response status: status_key, status_config: status, content: content
|
155
258
|
end
|
156
259
|
|
157
|
-
|
158
|
-
action
|
159
|
-
|
160
|
-
|
260
|
+
summary = path_config[:actions][action_config][:summary]
|
261
|
+
action = {
|
262
|
+
summary: summary,
|
263
|
+
description: path_config[:actions][action_config][:description],
|
264
|
+
operationId: "#{resource} #{summary}".downcase.gsub(/[^\w]/, '_'),
|
161
265
|
parameters: parameters,
|
162
266
|
responses: responses,
|
163
267
|
tags: [resource.to_s],
|
@@ -169,6 +273,14 @@ module RSpec
|
|
169
273
|
end
|
170
274
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
171
275
|
|
276
|
+
##
|
277
|
+
# Processes a request body from metadata
|
278
|
+
#
|
279
|
+
# @param schema [Hash] Schema
|
280
|
+
# @param ref [String] Reference
|
281
|
+
# @param examples [Hash] Example
|
282
|
+
#
|
283
|
+
# @return [void]
|
172
284
|
def process_request_body(schema: nil, ref: nil, examples: {})
|
173
285
|
Utils.deep_set @api_components, "schemas.#{ref}", schema
|
174
286
|
{
|
@@ -183,15 +295,22 @@ module RSpec
|
|
183
295
|
}
|
184
296
|
end
|
185
297
|
|
298
|
+
##
|
299
|
+
# Process a response from metadata
|
300
|
+
#
|
301
|
+
# @param status [Symbol] Status code
|
302
|
+
# @param status_config [Hash] Configuration for status code
|
303
|
+
# @param content [String] Response content
|
304
|
+
#
|
305
|
+
# @return [void]
|
186
306
|
def process_response(status: nil, status_config: nil, content: nil)
|
187
|
-
response = {
|
188
|
-
description: status_config[:description],
|
189
|
-
}
|
307
|
+
response = { description: status_config[:description] }
|
190
308
|
|
191
309
|
return response if status.to_s == '204' && content # No content
|
192
310
|
|
193
311
|
response[:content] = {
|
194
312
|
'application/json': {
|
313
|
+
schema: response_schema(status_config[:expectations]),
|
195
314
|
examples: { default: { value: JSON.parse(content) } },
|
196
315
|
},
|
197
316
|
}
|
@@ -199,6 +318,25 @@ module RSpec
|
|
199
318
|
response
|
200
319
|
end
|
201
320
|
|
321
|
+
def response_schema(expectations)
|
322
|
+
if expectations[:many]
|
323
|
+
items = if PRIMITIVES.include?(expectations[:many])
|
324
|
+
{ type: expectations[:many].to_s.split('_').last }
|
325
|
+
else
|
326
|
+
{ '$ref' => "#/components/schemas/#{expectations[:many]}" }
|
327
|
+
end
|
328
|
+
{ type: 'array', items: items }
|
329
|
+
elsif expectations[:one]
|
330
|
+
{ '$ref' => "#/components/schemas/#{expectations[:one]}" }
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
##
|
335
|
+
# Processes examples from statuses
|
336
|
+
#
|
337
|
+
# @param statuses [Hash]
|
338
|
+
#
|
339
|
+
# @return [Hash] Request examples
|
202
340
|
def process_examples(statuses)
|
203
341
|
request_examples = {}
|
204
342
|
|
@@ -212,16 +350,32 @@ module RSpec
|
|
212
350
|
request_examples
|
213
351
|
end
|
214
352
|
|
353
|
+
##
|
354
|
+
# Converts path with params like ":id" to their OpenAPI representation
|
355
|
+
#
|
356
|
+
# @param string [String] The original path
|
357
|
+
#
|
358
|
+
# @return [String] OpenAPI path representation
|
215
359
|
def path_with_params(string)
|
216
360
|
string.gsub(/(?::(\w*))/) do |e|
|
217
361
|
"{#{e.sub(':', '')}}"
|
218
362
|
end
|
219
363
|
end
|
220
364
|
|
365
|
+
##
|
366
|
+
# Converts a string to a snake_cased string to use as operationId
|
367
|
+
#
|
368
|
+
# @param string [String] Original string
|
369
|
+
#
|
370
|
+
# @return [String] Snake_cased string
|
221
371
|
def escape_operation_id(string)
|
222
372
|
string.downcase.gsub(/[^\w]+/, '_')
|
223
373
|
end
|
224
374
|
|
375
|
+
##
|
376
|
+
# Fills the API general information sections
|
377
|
+
#
|
378
|
+
# @return [void]
|
225
379
|
def api_infos
|
226
380
|
@api_infos = {
|
227
381
|
title: @api_title || 'Some sample app',
|
@@ -235,6 +389,10 @@ module RSpec
|
|
235
389
|
@api_infos
|
236
390
|
end
|
237
391
|
|
392
|
+
##
|
393
|
+
# Fills the API servers section
|
394
|
+
#
|
395
|
+
# @return [void]
|
238
396
|
def api_servers
|
239
397
|
@api_servers || [
|
240
398
|
{ url: 'http://api.example.com' },
|
@@ -7,6 +7,13 @@ module RSpec
|
|
7
7
|
module Api
|
8
8
|
# Helper methods
|
9
9
|
class Utils
|
10
|
+
##
|
11
|
+
# Gets a value in a hash by specifying a dotted path
|
12
|
+
#
|
13
|
+
# @param hash [Hash] The hash to search in
|
14
|
+
# @param path [String] The dotted path
|
15
|
+
#
|
16
|
+
# @return [*] The value or nil
|
10
17
|
def self.deep_get(hash, path)
|
11
18
|
path.split('.').inject(hash) do |sub_hash, key|
|
12
19
|
return nil unless sub_hash.is_a?(Hash) && sub_hash.key?(key.to_sym)
|
@@ -15,6 +22,14 @@ module RSpec
|
|
15
22
|
end
|
16
23
|
end
|
17
24
|
|
25
|
+
##
|
26
|
+
# Sets a value at given dotted path in a hash
|
27
|
+
#
|
28
|
+
# @param hash [Hash] The target hash
|
29
|
+
# @param path [String] Dotted path
|
30
|
+
# @param value [*] Value to set
|
31
|
+
#
|
32
|
+
# @return [Hash] The modified hash
|
18
33
|
def self.deep_set(hash, path, value)
|
19
34
|
path = path.split('.') unless path.is_a? Array
|
20
35
|
|
@@ -27,6 +42,13 @@ module RSpec
|
|
27
42
|
hash
|
28
43
|
end
|
29
44
|
|
45
|
+
##
|
46
|
+
# Checks if a value is of the given parameter type
|
47
|
+
#
|
48
|
+
# @param type [Symbol] Type to compare to
|
49
|
+
# @param value [*] Value to test
|
50
|
+
#
|
51
|
+
# @return [Boolean] True when the value corresponds to the given type
|
30
52
|
def self.check_value_type(type, value)
|
31
53
|
return true if type == :boolean && (value.is_a?(TrueClass) || value.is_a?(FalseClass))
|
32
54
|
return true if type == :array && value.is_a?(Array)
|
@@ -36,6 +58,13 @@ module RSpec
|
|
36
58
|
value.is_a? PARAM_TYPES[type][:class]
|
37
59
|
end
|
38
60
|
|
61
|
+
##
|
62
|
+
# Validates an object keys and values types
|
63
|
+
#
|
64
|
+
# @param actual [Hash] Hash to compare
|
65
|
+
# @param expected [Hash] Structure to compare
|
66
|
+
#
|
67
|
+
# @return [Boolean] True when the object matches the structure
|
39
68
|
def self.validate_object_structure(actual, expected)
|
40
69
|
# Check keys
|
41
70
|
return false unless same_keys? actual, expected
|
@@ -56,23 +85,53 @@ module RSpec
|
|
56
85
|
true
|
57
86
|
end
|
58
87
|
|
59
|
-
|
88
|
+
##
|
89
|
+
# Validates an array or hash against a definition
|
90
|
+
#
|
91
|
+
# @param expected_type [:object, :array] The expected type
|
92
|
+
# @param expected_attributes [Hash] Attributes configuration
|
93
|
+
# @param actual [Array, Hash] Value to check
|
94
|
+
#
|
95
|
+
# @return [Boolean] True when `actual` is of the expected definition
|
60
96
|
def self.validate_deep_object(expected_type, expected_attributes, actual)
|
61
97
|
if %i[object array].include?(expected_type) && expected_attributes.is_a?(Hash)
|
62
98
|
case expected_type
|
63
99
|
when :object
|
64
100
|
return false unless validate_object_structure actual, expected_attributes
|
65
101
|
when :array
|
66
|
-
actual
|
67
|
-
return false unless validate_object_structure array_entry, expected_attributes
|
68
|
-
end
|
102
|
+
return false unless validate_deep_object_array actual, expected_attributes
|
69
103
|
end
|
70
104
|
end
|
71
105
|
|
72
106
|
true
|
73
107
|
end
|
74
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
75
108
|
|
109
|
+
##
|
110
|
+
# Validates each entry of an array
|
111
|
+
#
|
112
|
+
# @param array [Array] The array to check
|
113
|
+
# @param expected_attributes [Hash] Attributes configuration
|
114
|
+
#
|
115
|
+
# @return [Boolean] True when all values matches the attribute configuration
|
116
|
+
def self.validate_deep_object_array(array, expected_attributes)
|
117
|
+
array.each do |array_entry|
|
118
|
+
if expected_attributes[:type]
|
119
|
+
return false unless check_value_type expected_attributes[:type], array_entry
|
120
|
+
else
|
121
|
+
return false unless validate_object_structure array_entry, expected_attributes
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
true
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Checks if a hash have the required keys in it
|
130
|
+
#
|
131
|
+
# @param actual [Hash] The hash
|
132
|
+
# @param expected [Hash] Attributes definitions
|
133
|
+
#
|
134
|
+
# @return [Boolean] True when the object is valid
|
76
135
|
def self.same_keys?(actual, expected)
|
77
136
|
optional = expected.reject { |_key, value| value[:required] }.keys
|
78
137
|
actual.symbolize_keys.keys.sort - optional == expected.keys.sort - optional
|
data/lib/rspec_rails_api.rb
CHANGED
@@ -15,6 +15,8 @@ module RSpec
|
|
15
15
|
class Error < StandardError
|
16
16
|
end
|
17
17
|
|
18
|
+
##
|
19
|
+
# OpenAPI types, format and Ruby class correspondence
|
18
20
|
PARAM_TYPES = {
|
19
21
|
int32: { type: 'integer', format: 'int32', class: Integer },
|
20
22
|
int64: { type: 'integer', format: 'int64', class: Integer },
|
@@ -32,6 +34,12 @@ module RSpec
|
|
32
34
|
array: { type: 'array', format: nil, class: Array },
|
33
35
|
object: { type: 'object', format: nil, class: Hash },
|
34
36
|
}.freeze
|
37
|
+
|
38
|
+
EXCLUDED_PRIMITIVES = %i[array object].freeze
|
39
|
+
|
40
|
+
PRIMITIVES = PARAM_TYPES.keys
|
41
|
+
.reject { |key| EXCLUDED_PRIMITIVES.include? key }
|
42
|
+
.map { |key| "type_#{key}".to_sym }
|
35
43
|
end
|
36
44
|
end
|
37
45
|
end
|
data/rspec-rails-api.gemspec
CHANGED
@@ -18,9 +18,10 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.homepage = 'https://gitlab.com/experimentslabs/rspec-rails-api'
|
19
19
|
spec.license = 'MIT'
|
20
20
|
spec.metadata = {
|
21
|
-
'source_code_uri'
|
22
|
-
'bug_tracker_uri'
|
23
|
-
'changelog_uri'
|
21
|
+
'source_code_uri' => 'https://gitlab.com/experimentslabs/rspec-rails-api',
|
22
|
+
'bug_tracker_uri' => 'https://gitlab.com/experimentslabs/rspec-rails-api/issues',
|
23
|
+
'changelog_uri' => 'https://gitlab.com/experimentslabs/rspec-rails-api/blob/master/CHANGELOG.md',
|
24
|
+
'rubygems_mfa_required' => 'true',
|
24
25
|
}
|
25
26
|
|
26
27
|
# Specify which files should be added to the gem when it is released.
|
@@ -35,11 +36,12 @@ Gem::Specification.new do |spec|
|
|
35
36
|
spec.required_ruby_version = '>= 2.5.0'
|
36
37
|
|
37
38
|
spec.add_development_dependency 'activesupport', '~> 6.0'
|
38
|
-
spec.add_development_dependency 'bundler'
|
39
|
+
spec.add_development_dependency 'bundler'
|
39
40
|
spec.add_development_dependency 'byebug'
|
40
41
|
spec.add_development_dependency 'rake', '~> 10.0'
|
41
42
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
42
43
|
spec.add_development_dependency 'rubocop'
|
43
44
|
spec.add_development_dependency 'rubocop-performance'
|
44
45
|
spec.add_development_dependency 'simplecov'
|
46
|
+
spec.add_development_dependency 'yard'
|
45
47
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-rails-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manuel Tancoigne
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: byebug
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: yard
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
125
139
|
description: |
|
126
140
|
Create acceptance tests to check the Rails API responses and generate
|
127
141
|
documentation from it.
|
@@ -162,6 +176,7 @@ metadata:
|
|
162
176
|
source_code_uri: https://gitlab.com/experimentslabs/rspec-rails-api
|
163
177
|
bug_tracker_uri: https://gitlab.com/experimentslabs/rspec-rails-api/issues
|
164
178
|
changelog_uri: https://gitlab.com/experimentslabs/rspec-rails-api/blob/master/CHANGELOG.md
|
179
|
+
rubygems_mfa_required: 'true'
|
165
180
|
post_install_message:
|
166
181
|
rdoc_options: []
|
167
182
|
require_paths:
|