rspec-rails-api 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +54 -0
- data/README.md +39 -36
- data/Rakefile +3 -0
- data/lib/rspec/rails/api/dsl/example.rb +94 -16
- 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 +12 -3
- data/lib/rspec/rails/api/matchers.rb +16 -3
- data/lib/rspec/rails/api/metadata.rb +149 -32
- data/lib/rspec/rails/api/open_api_renderer.rb +185 -25
- data/lib/rspec/rails/api/utils.rb +66 -7
- 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,36 +42,64 @@ 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
|
|
55
|
+
file_types = %i[yaml json]
|
56
|
+
|
42
57
|
only.each do |type|
|
43
|
-
next unless
|
58
|
+
next unless file_types.include? type
|
44
59
|
|
45
|
-
File.write "#{path}.#{type}",
|
60
|
+
File.write "#{path}.#{type}", prepare_metadata.send("to_#{type}")
|
46
61
|
end
|
47
62
|
end
|
48
63
|
|
64
|
+
##
|
65
|
+
# Extracts metadata from context to generate an OpenAPI structure
|
66
|
+
#
|
67
|
+
# @return [Hash] The OpenAPI structure
|
49
68
|
def prepare_metadata
|
50
|
-
# Example: https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore-expanded.yaml
|
51
69
|
extract_metadatas
|
52
|
-
|
70
|
+
# Example: https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore-expanded.yaml
|
71
|
+
hash = {
|
53
72
|
openapi: '3.0.0',
|
54
73
|
info: @api_infos,
|
55
74
|
servers: @api_servers,
|
56
75
|
paths: @api_paths,
|
57
76
|
components: @api_components,
|
58
77
|
tags: @api_tags,
|
59
|
-
}
|
78
|
+
}
|
79
|
+
JSON.parse(JSON.pretty_generate(hash))
|
60
80
|
end
|
61
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]
|
62
90
|
def api_contact=(name: nil, email: nil, url: nil)
|
63
91
|
@api_contact[:name] = name if name
|
64
92
|
@api_contact[:email] = email if email
|
65
93
|
@api_contact[:url] = url if url
|
66
94
|
end
|
67
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]
|
68
103
|
def api_license=(name: nil, url: nil)
|
69
104
|
@api_license[:name] = name if name
|
70
105
|
@api_license[:url] = url if url
|
@@ -72,14 +107,26 @@ module RSpec
|
|
72
107
|
|
73
108
|
private
|
74
109
|
|
110
|
+
##
|
111
|
+
# Extracts metadata for rendering
|
112
|
+
#
|
113
|
+
# @return [void]
|
75
114
|
def extract_metadatas
|
76
115
|
extract_from_resources
|
77
116
|
api_infos
|
78
117
|
api_servers
|
79
118
|
end
|
80
119
|
|
81
|
-
|
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] ||= {}
|
82
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
|
83
130
|
@api_tags.push(
|
84
131
|
name: resource_key.to_s,
|
85
132
|
description: resource[:description]
|
@@ -88,14 +135,23 @@ module RSpec
|
|
88
135
|
end
|
89
136
|
end
|
90
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]
|
91
146
|
def process_resource(resource: nil, resource_config: nil) # rubocop:disable Metrics/MethodLength
|
147
|
+
http_verbs = %i[get post put patch delete]
|
92
148
|
resource_config[:paths].each do |path_key, path|
|
93
149
|
url = path_with_params path_key.to_s
|
94
150
|
actions = {}
|
95
151
|
parameters = path.key?(:path_params) ? process_path_params(path[:path_params]) : []
|
96
152
|
|
97
153
|
path[:actions].each_key do |action|
|
98
|
-
next unless
|
154
|
+
next unless http_verbs.include? action
|
99
155
|
|
100
156
|
actions[action] = process_action resource: resource,
|
101
157
|
path: path_key,
|
@@ -108,6 +164,10 @@ module RSpec
|
|
108
164
|
end
|
109
165
|
end
|
110
166
|
|
167
|
+
##
|
168
|
+
# Processes path parameters for rendering
|
169
|
+
#
|
170
|
+
# @param params [Hash] Path parameters
|
111
171
|
def process_path_params(params)
|
112
172
|
parameters = []
|
113
173
|
params.each do |name, param|
|
@@ -117,7 +177,40 @@ module RSpec
|
|
117
177
|
parameters
|
118
178
|
end
|
119
179
|
|
120
|
-
def
|
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]
|
213
|
+
def process_path_param(name, param) # rubocop:disable Metrics/MethodLength
|
121
214
|
parameter = {
|
122
215
|
name: name.to_s,
|
123
216
|
description: param[:description],
|
@@ -133,18 +226,30 @@ module RSpec
|
|
133
226
|
parameter
|
134
227
|
end
|
135
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"
|
136
242
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
137
243
|
def process_action(resource: nil, path: nil, path_config: nil, action_config: nil, parameters: nil)
|
138
244
|
responses = {}
|
139
245
|
request_body = nil
|
140
246
|
|
141
|
-
if %i[post put
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
247
|
+
if %i[post put
|
248
|
+
patch].include?(action_config) && path_config[:actions][action_config][:params].keys.count.positive?
|
249
|
+
schema = path_config[:actions][action_config][:params]
|
250
|
+
schema_ref = escape_operation_id("#{action_config}_#{path}")
|
251
|
+
examples = process_examples(path_config[:actions][action_config][:statuses])
|
252
|
+
request_body = process_request_body schema: schema, ref: schema_ref, examples: examples
|
148
253
|
end
|
149
254
|
|
150
255
|
path_config[:actions][action_config][:statuses].each do |status_key, status|
|
@@ -152,10 +257,11 @@ module RSpec
|
|
152
257
|
responses[status_key] = process_response status: status_key, status_config: status, content: content
|
153
258
|
end
|
154
259
|
|
155
|
-
|
156
|
-
action
|
157
|
-
|
158
|
-
|
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]/, '_'),
|
159
265
|
parameters: parameters,
|
160
266
|
responses: responses,
|
161
267
|
tags: [resource.to_s],
|
@@ -167,6 +273,14 @@ module RSpec
|
|
167
273
|
end
|
168
274
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
169
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]
|
170
284
|
def process_request_body(schema: nil, ref: nil, examples: {})
|
171
285
|
Utils.deep_set @api_components, "schemas.#{ref}", schema
|
172
286
|
{
|
@@ -181,22 +295,48 @@ module RSpec
|
|
181
295
|
}
|
182
296
|
end
|
183
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]
|
184
306
|
def process_response(status: nil, status_config: nil, content: nil)
|
185
|
-
response = {
|
186
|
-
description: status_config[:description],
|
187
|
-
}
|
307
|
+
response = { description: status_config[:description] }
|
188
308
|
|
189
309
|
return response if status.to_s == '204' && content # No content
|
190
310
|
|
191
311
|
response[:content] = {
|
192
312
|
'application/json': {
|
193
|
-
|
313
|
+
schema: response_schema(status_config[:expectations]),
|
314
|
+
examples: { default: { value: JSON.parse(content) } },
|
194
315
|
},
|
195
316
|
}
|
196
317
|
|
197
318
|
response
|
198
319
|
end
|
199
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
|
200
340
|
def process_examples(statuses)
|
201
341
|
request_examples = {}
|
202
342
|
|
@@ -210,17 +350,33 @@ module RSpec
|
|
210
350
|
request_examples
|
211
351
|
end
|
212
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
|
213
359
|
def path_with_params(string)
|
214
360
|
string.gsub(/(?::(\w*))/) do |e|
|
215
361
|
"{#{e.sub(':', '')}}"
|
216
362
|
end
|
217
363
|
end
|
218
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
|
219
371
|
def escape_operation_id(string)
|
220
372
|
string.downcase.gsub(/[^\w]+/, '_')
|
221
373
|
end
|
222
374
|
|
223
|
-
|
375
|
+
##
|
376
|
+
# Fills the API general information sections
|
377
|
+
#
|
378
|
+
# @return [void]
|
379
|
+
def api_infos
|
224
380
|
@api_infos = {
|
225
381
|
title: @api_title || 'Some sample app',
|
226
382
|
version: @api_version || '1.0',
|
@@ -233,6 +389,10 @@ module RSpec
|
|
233
389
|
@api_infos
|
234
390
|
end
|
235
391
|
|
392
|
+
##
|
393
|
+
# Fills the API servers section
|
394
|
+
#
|
395
|
+
# @return [void]
|
236
396
|
def api_servers
|
237
397
|
@api_servers || [
|
238
398
|
{ url: 'http://api.example.com' },
|
@@ -7,14 +7,29 @@ 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)
|
13
20
|
|
14
|
-
sub_hash[key.to_sym]
|
21
|
+
sub_hash[key.to_sym] # rubocop:disable Lint/UnmodifiedReduceAccumulator
|
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,7 +42,14 @@ module RSpec
|
|
27
42
|
hash
|
28
43
|
end
|
29
44
|
|
30
|
-
|
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
|
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)
|
33
55
|
|
@@ -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:
|
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:
|