grape-swagger 0.33.0 → 1.0.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/.rubocop.yml +7 -7
- data/.rubocop_todo.yml +0 -6
- data/.travis.yml +11 -10
- data/CHANGELOG.md +75 -5
- data/Gemfile +5 -5
- data/README.md +73 -5
- data/grape-swagger.gemspec +1 -1
- data/lib/grape-swagger/doc_methods/build_model_definition.rb +0 -17
- data/lib/grape-swagger/doc_methods/data_type.rb +1 -1
- data/lib/grape-swagger/doc_methods/extensions.rb +6 -1
- data/lib/grape-swagger/doc_methods/format_data.rb +51 -0
- data/lib/grape-swagger/doc_methods/move_params.rb +22 -49
- data/lib/grape-swagger/doc_methods/parse_params.rb +6 -0
- data/lib/grape-swagger/doc_methods.rb +2 -0
- data/lib/grape-swagger/endpoint/params_parser.rb +22 -22
- data/lib/grape-swagger/endpoint.rb +33 -14
- data/lib/grape-swagger/version.rb +1 -1
- data/lib/grape-swagger.rb +1 -1
- data/spec/issues/751_deeply_nested_objects_spec.rb +190 -0
- data/spec/lib/data_type_spec.rb +2 -2
- data/spec/lib/endpoint/params_parser_spec.rb +46 -21
- data/spec/lib/endpoint_spec.rb +4 -4
- data/spec/lib/extensions_spec.rb +10 -0
- data/spec/lib/format_data_spec.rb +91 -0
- data/spec/lib/move_params_spec.rb +4 -266
- data/spec/lib/optional_object_spec.rb +0 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/support/model_parsers/entity_parser.rb +1 -1
- data/spec/support/model_parsers/representable_parser.rb +1 -1
- data/spec/swagger_v2/api_swagger_v2_hash_and_array_spec.rb +3 -1
- data/spec/swagger_v2/api_swagger_v2_hide_param_spec.rb +14 -3
- data/spec/swagger_v2/api_swagger_v2_response_with_root_spec.rb +153 -0
- data/spec/swagger_v2/boolean_params_spec.rb +1 -1
- data/spec/swagger_v2/description_not_initialized_spec.rb +39 -0
- data/spec/swagger_v2/endpoint_versioned_path_spec.rb +33 -0
- data/spec/swagger_v2/mounted_target_class_spec.rb +1 -1
- data/spec/swagger_v2/namespace_tags_prefix_spec.rb +15 -1
- data/spec/swagger_v2/params_array_spec.rb +2 -2
- data/spec/swagger_v2/parent_less_namespace_spec.rb +32 -0
- data/spec/swagger_v2/{reference_entity.rb → reference_entity_spec.rb} +17 -10
- metadata +20 -13
- data/spec/swagger_v2/description_not_initialized.rb +0 -39
- data/spec/swagger_v2/parent_less_namespace.rb +0 -49
@@ -87,7 +87,12 @@ module GrapeSwagger
|
|
87
87
|
part.select { |x| x == identifier }
|
88
88
|
end
|
89
89
|
|
90
|
-
def method
|
90
|
+
def method(*args)
|
91
|
+
# We're shadowing Object.method(:symbol) here so we provide
|
92
|
+
# a compatibility layer for code that introspects the methods
|
93
|
+
# of this class
|
94
|
+
return super if args.size.positive?
|
95
|
+
|
91
96
|
@route.request_method.downcase.to_sym
|
92
97
|
end
|
93
98
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GrapeSwagger
|
4
|
+
module DocMethods
|
5
|
+
class FormatData
|
6
|
+
class << self
|
7
|
+
def to_format(parameters)
|
8
|
+
parameters.reject { |parameter| parameter[:in] == 'body' }.each do |b|
|
9
|
+
related_parameters = parameters.select do |p|
|
10
|
+
p[:name] != b[:name] && p[:name].to_s.include?(b[:name].to_s.gsub(/\[\]\z/, '') + '[')
|
11
|
+
end
|
12
|
+
parameters.reject! { |p| p[:name] == b[:name] } if move_down(b, related_parameters)
|
13
|
+
end
|
14
|
+
parameters
|
15
|
+
end
|
16
|
+
|
17
|
+
def move_down(parameter, related_parameters)
|
18
|
+
case parameter[:type]
|
19
|
+
when 'array'
|
20
|
+
add_array(parameter, related_parameters)
|
21
|
+
unless related_parameters.blank?
|
22
|
+
add_braces(parameter, related_parameters) if parameter[:name].match?(/\A.*\[\]\z/)
|
23
|
+
return true
|
24
|
+
end
|
25
|
+
when 'object'
|
26
|
+
return true
|
27
|
+
end
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_braces(parameter, related_parameters)
|
32
|
+
param_name = parameter[:name].gsub(/\A(.*)\[\]\z/, '\1')
|
33
|
+
related_parameters.each { |p| p[:name] = p[:name].gsub(param_name, param_name + '[]') }
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_array(parameter, related_parameters)
|
37
|
+
related_parameters.each do |p|
|
38
|
+
p_type = p[:type] == 'array' ? 'string' : p[:type]
|
39
|
+
p[:items] = { type: p_type, format: p[:format], enum: p[:enum], is_array: p[:is_array] }
|
40
|
+
p[:items].delete_if { |_k, v| v.nil? }
|
41
|
+
p[:type] = 'array'
|
42
|
+
p[:is_array] = parameter[:is_array]
|
43
|
+
p.delete(:format)
|
44
|
+
p.delete(:enum)
|
45
|
+
p.delete_if { |_k, v| v.nil? }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -8,7 +8,7 @@ module GrapeSwagger
|
|
8
8
|
class << self
|
9
9
|
attr_accessor :definitions
|
10
10
|
|
11
|
-
def can_be_moved?(
|
11
|
+
def can_be_moved?(http_verb, params)
|
12
12
|
move_methods.include?(http_verb) && includes_body_param?(params)
|
13
13
|
end
|
14
14
|
|
@@ -51,22 +51,33 @@ module GrapeSwagger
|
|
51
51
|
|
52
52
|
def move_params_to_new(definition, params)
|
53
53
|
params, nested_params = params.partition { |x| !x[:name].to_s.include?('[') }
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
add_properties_to_definition(definition,
|
54
|
+
params.each do |param|
|
55
|
+
property = param[:name]
|
56
|
+
param_properties, param_required = build_properties([param])
|
57
|
+
add_properties_to_definition(definition, param_properties, param_required)
|
58
|
+
related_nested_params, nested_params = nested_params.partition { |x| x[:name].start_with?("#{property}[") }
|
59
|
+
prepare_nested_names(property, related_nested_params)
|
60
|
+
|
61
|
+
next if related_nested_params.blank?
|
62
|
+
|
63
|
+
nested_definition = if should_expose_as_array?([param])
|
64
|
+
move_params_to_new(array_type, related_nested_params)
|
65
|
+
else
|
66
|
+
move_params_to_new(object_type, related_nested_params)
|
67
|
+
end
|
68
|
+
if definition.key?(:items)
|
69
|
+
definition[:items][:properties][property.to_sym].deep_merge!(nested_definition)
|
70
|
+
else
|
71
|
+
definition[:properties][property.to_sym].deep_merge!(nested_definition)
|
72
|
+
end
|
58
73
|
end
|
59
|
-
|
60
|
-
nested_properties = build_nested_properties(nested_params) unless nested_params.blank?
|
61
|
-
add_properties_to_definition(definition, nested_properties, []) unless nested_params.blank?
|
74
|
+
definition
|
62
75
|
end
|
63
76
|
|
64
77
|
def build_properties(params)
|
65
78
|
properties = {}
|
66
79
|
required = []
|
67
80
|
|
68
|
-
prepare_nested_types(params) if should_expose_as_array?(params)
|
69
|
-
|
70
81
|
params.each do |param|
|
71
82
|
name = param[:name].to_sym
|
72
83
|
|
@@ -103,28 +114,6 @@ module GrapeSwagger
|
|
103
114
|
end
|
104
115
|
end
|
105
116
|
|
106
|
-
def build_nested_properties(params, properties = {})
|
107
|
-
property = params.bsearch { |x| x[:name].include?('[') }[:name].split('[').first
|
108
|
-
|
109
|
-
nested_params, params = params.partition { |x| x[:name].start_with?("#{property}[") }
|
110
|
-
prepare_nested_names(property, nested_params)
|
111
|
-
|
112
|
-
recursive_call(properties, property, nested_params) unless nested_params.empty?
|
113
|
-
build_nested_properties(params, properties) unless params.empty?
|
114
|
-
|
115
|
-
properties
|
116
|
-
end
|
117
|
-
|
118
|
-
def recursive_call(properties, property, nested_params)
|
119
|
-
if should_expose_as_array?(nested_params)
|
120
|
-
properties[property.to_sym] = array_type
|
121
|
-
move_params_to_new(properties[property.to_sym][:items], nested_params)
|
122
|
-
else
|
123
|
-
properties[property.to_sym] = object_type
|
124
|
-
move_params_to_new(properties[property.to_sym], nested_params)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
117
|
def movable_params(params)
|
129
118
|
to_delete = params.each_with_object([]) { |x, memo| memo << x if deletable?(x) }
|
130
119
|
delete_from(params, to_delete)
|
@@ -177,22 +166,6 @@ module GrapeSwagger
|
|
177
166
|
{ type: 'object', properties: {} }
|
178
167
|
end
|
179
168
|
|
180
|
-
def prepare_nested_types(params)
|
181
|
-
params.each do |param|
|
182
|
-
next unless param[:items]
|
183
|
-
|
184
|
-
param[:type] = if param[:items][:type] == 'array'
|
185
|
-
'string'
|
186
|
-
elsif param[:items].key?('$ref')
|
187
|
-
param[:type] = 'object'
|
188
|
-
else
|
189
|
-
param[:items][:type]
|
190
|
-
end
|
191
|
-
param[:format] = param[:items][:format] if param[:items][:format]
|
192
|
-
param.delete(:items) if param[:type] != 'object'
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
169
|
def prepare_nested_names(property, params)
|
197
170
|
params.each { |x| x[:name] = x[:name].sub(property, '').sub('[', '').sub(']', '') }
|
198
171
|
end
|
@@ -208,7 +181,7 @@ module GrapeSwagger
|
|
208
181
|
end
|
209
182
|
|
210
183
|
def property_keys
|
211
|
-
%i[type format description minimum maximum items enum default]
|
184
|
+
%i[type format description minimum maximum items enum default additionalProperties]
|
212
185
|
end
|
213
186
|
|
214
187
|
def deletable?(param)
|
@@ -25,6 +25,7 @@ module GrapeSwagger
|
|
25
25
|
document_default_value(settings) unless value_type[:is_array]
|
26
26
|
document_range_values(settings) unless value_type[:is_array]
|
27
27
|
document_required(settings)
|
28
|
+
document_additional_properties(settings)
|
28
29
|
|
29
30
|
@parsed_param
|
30
31
|
end
|
@@ -91,6 +92,11 @@ module GrapeSwagger
|
|
91
92
|
@parsed_param[:collectionFormat] = collection_format if DataType.collections.include?(collection_format)
|
92
93
|
end
|
93
94
|
|
95
|
+
def document_additional_properties(settings)
|
96
|
+
additional_properties = settings[:additionalProperties]
|
97
|
+
@parsed_param[:additionalProperties] = additional_properties if additional_properties
|
98
|
+
end
|
99
|
+
|
94
100
|
def param_type(value_type)
|
95
101
|
param_type = value_type[:param_type] || value_type[:in]
|
96
102
|
if value_type[:path].include?("{#{value_type[:param_name]}}")
|
@@ -4,6 +4,7 @@ require 'grape-swagger/doc_methods/status_codes'
|
|
4
4
|
require 'grape-swagger/doc_methods/produces_consumes'
|
5
5
|
require 'grape-swagger/doc_methods/data_type'
|
6
6
|
require 'grape-swagger/doc_methods/extensions'
|
7
|
+
require 'grape-swagger/doc_methods/format_data'
|
7
8
|
require 'grape-swagger/doc_methods/operation_id'
|
8
9
|
require 'grape-swagger/doc_methods/optional_object'
|
9
10
|
require 'grape-swagger/doc_methods/path_string'
|
@@ -102,6 +103,7 @@ module GrapeSwagger
|
|
102
103
|
base_path: nil,
|
103
104
|
add_base_path: false,
|
104
105
|
add_version: true,
|
106
|
+
add_root: false,
|
105
107
|
hide_documentation_path: true,
|
106
108
|
format: :json,
|
107
109
|
authorizations: nil,
|
@@ -3,49 +3,37 @@
|
|
3
3
|
module GrapeSwagger
|
4
4
|
module Endpoint
|
5
5
|
class ParamsParser
|
6
|
-
attr_reader :params, :settings
|
6
|
+
attr_reader :params, :settings, :endpoint
|
7
7
|
|
8
|
-
def self.parse_request_params(params, settings)
|
9
|
-
new(params, settings).parse_request_params
|
8
|
+
def self.parse_request_params(params, settings, endpoint)
|
9
|
+
new(params, settings, endpoint).parse_request_params
|
10
10
|
end
|
11
11
|
|
12
|
-
def initialize(params, settings)
|
12
|
+
def initialize(params, settings, endpoint)
|
13
13
|
@params = params
|
14
14
|
@settings = settings
|
15
|
+
@endpoint = endpoint
|
15
16
|
end
|
16
17
|
|
17
18
|
def parse_request_params
|
18
|
-
array_keys = []
|
19
19
|
public_params.each_with_object({}) do |(name, options), memo|
|
20
20
|
name = name.to_s
|
21
21
|
param_type = options[:type]
|
22
22
|
param_type = param_type.to_s unless param_type.nil?
|
23
23
|
|
24
24
|
if param_type_is_array?(param_type)
|
25
|
-
array_keys << name
|
26
25
|
options[:is_array] = true
|
27
|
-
|
28
|
-
name += '[]' if array_use_braces?(options)
|
29
|
-
else
|
30
|
-
keys = array_keys.find_all { |key| name.start_with? "#{key}[" }
|
31
|
-
if keys.any?
|
32
|
-
options[:is_array] = true
|
33
|
-
if array_use_braces?(options)
|
34
|
-
keys.sort.reverse_each do |key|
|
35
|
-
name = name.sub(key, "#{key}[]")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
26
|
+
name += '[]' if array_use_braces?
|
39
27
|
end
|
40
28
|
|
41
|
-
memo[name] = options
|
29
|
+
memo[name] = options
|
42
30
|
end
|
43
31
|
end
|
44
32
|
|
45
33
|
private
|
46
34
|
|
47
|
-
def array_use_braces?
|
48
|
-
settings[:array_use_braces] && !
|
35
|
+
def array_use_braces?
|
36
|
+
@array_use_braces ||= settings[:array_use_braces] && !includes_body_param?
|
49
37
|
end
|
50
38
|
|
51
39
|
def param_type_is_array?(param_type)
|
@@ -68,9 +56,21 @@ module GrapeSwagger
|
|
68
56
|
return true unless param_options.key?(:documentation) && !param_options[:required]
|
69
57
|
|
70
58
|
param_hidden = param_options[:documentation].fetch(:hidden, false)
|
71
|
-
|
59
|
+
if param_hidden.is_a?(Proc)
|
60
|
+
param_hidden = if settings[:token_owner]
|
61
|
+
param_hidden.call(endpoint.send(settings[:token_owner].to_sym))
|
62
|
+
else
|
63
|
+
param_hidden.call
|
64
|
+
end
|
65
|
+
end
|
72
66
|
!param_hidden
|
73
67
|
end
|
68
|
+
|
69
|
+
def includes_body_param?
|
70
|
+
params.any? do |_, options|
|
71
|
+
options.dig(:documentation, :param_type) == 'body' || options.dig(:documentation, :in) == 'body'
|
72
|
+
end
|
73
|
+
end
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
@@ -78,8 +78,7 @@ module Grape
|
|
78
78
|
def path_and_definition_objects(namespace_routes, options)
|
79
79
|
@paths = {}
|
80
80
|
@definitions = {}
|
81
|
-
namespace_routes.
|
82
|
-
routes = namespace_routes[key]
|
81
|
+
namespace_routes.each_value do |routes|
|
83
82
|
path_item(routes, options)
|
84
83
|
end
|
85
84
|
|
@@ -121,7 +120,7 @@ module Grape
|
|
121
120
|
method[:consumes] = consumes_object(route, options[:format])
|
122
121
|
method[:parameters] = params_object(route, options, path)
|
123
122
|
method[:security] = security_object(route)
|
124
|
-
method[:responses] = response_object(route)
|
123
|
+
method[:responses] = response_object(route, options)
|
125
124
|
method[:tags] = route.options.fetch(:tags, tag_object(route, path))
|
126
125
|
method[:operationId] = GrapeSwagger::DocMethods::OperationId.build(route, path)
|
127
126
|
method[:deprecated] = deprecated_object(route)
|
@@ -179,22 +178,24 @@ module Grape
|
|
179
178
|
parameters = partition_params(route, options).map do |param, value|
|
180
179
|
value = { required: false }.merge(value) if value.is_a?(Hash)
|
181
180
|
_, value = default_type([[param, value]]).first if value == ''
|
182
|
-
if value
|
183
|
-
expose_params(value[:type])
|
184
|
-
elsif value[:documentation]
|
181
|
+
if value.dig(:documentation, :type)
|
185
182
|
expose_params(value[:documentation][:type])
|
183
|
+
elsif value[:type]
|
184
|
+
expose_params(value[:type])
|
186
185
|
end
|
187
186
|
GrapeSwagger::DocMethods::ParseParams.call(param, value, path, route, @definitions)
|
188
187
|
end
|
189
188
|
|
190
|
-
if GrapeSwagger::DocMethods::MoveParams.can_be_moved?(
|
189
|
+
if GrapeSwagger::DocMethods::MoveParams.can_be_moved?(route.request_method, parameters)
|
191
190
|
parameters = GrapeSwagger::DocMethods::MoveParams.to_definition(path, parameters, route, @definitions)
|
192
191
|
end
|
193
192
|
|
193
|
+
GrapeSwagger::DocMethods::FormatData.to_format(parameters)
|
194
|
+
|
194
195
|
parameters.presence
|
195
196
|
end
|
196
197
|
|
197
|
-
def response_object(route)
|
198
|
+
def response_object(route, options)
|
198
199
|
codes = http_codes_from_route(route)
|
199
200
|
codes.map! { |x| x.is_a?(Array) ? { code: x[0], message: x[1], model: x[2], examples: x[3], headers: x[4] } : x }
|
200
201
|
|
@@ -219,7 +220,7 @@ module Grape
|
|
219
220
|
|
220
221
|
@definitions[response_model][:description] = description_object(route)
|
221
222
|
|
222
|
-
memo[value[:code]][:schema] = build_reference(route, value, response_model)
|
223
|
+
memo[value[:code]][:schema] = build_reference(route, value, response_model, options)
|
223
224
|
memo[value[:code]][:examples] = value[:examples] if value[:examples]
|
224
225
|
end
|
225
226
|
end
|
@@ -250,20 +251,38 @@ module Grape
|
|
250
251
|
def tag_object(route, path)
|
251
252
|
version = GrapeSwagger::DocMethods::Version.get(route)
|
252
253
|
version = [version] unless version.is_a?(Array)
|
253
|
-
|
254
|
+
prefix = route.prefix.to_s.split('/').reject(&:empty?)
|
254
255
|
Array(
|
255
256
|
path.split('{')[0].split('/').reject(&:empty?).delete_if do |i|
|
256
|
-
|
257
|
+
prefix.include?(i) || version.map(&:to_s).include?(i)
|
257
258
|
end.first
|
258
259
|
).presence
|
259
260
|
end
|
260
261
|
|
261
262
|
private
|
262
263
|
|
263
|
-
def build_reference(route, value, response_model)
|
264
|
+
def build_reference(route, value, response_model, settings)
|
264
265
|
# TODO: proof that the definition exist, if model isn't specified
|
265
266
|
reference = { '$ref' => "#/definitions/#{response_model}" }
|
266
|
-
|
267
|
+
return reference unless value[:code] < 300
|
268
|
+
|
269
|
+
reference = { type: 'array', items: reference } if route.options[:is_array]
|
270
|
+
build_root(route, reference, response_model, settings)
|
271
|
+
end
|
272
|
+
|
273
|
+
def build_root(route, reference, response_model, settings)
|
274
|
+
default_root = response_model.underscore
|
275
|
+
default_root = default_root.pluralize if route.options[:is_array]
|
276
|
+
case route.settings.dig(:swagger, :root)
|
277
|
+
when true
|
278
|
+
{ type: 'object', properties: { default_root => reference } }
|
279
|
+
when false
|
280
|
+
reference
|
281
|
+
when nil
|
282
|
+
settings[:add_root] ? { type: 'object', properties: { default_root => reference } } : reference
|
283
|
+
else
|
284
|
+
{ type: 'object', properties: { route.settings.dig(:swagger, :root) => reference } }
|
285
|
+
end
|
267
286
|
end
|
268
287
|
|
269
288
|
def file_response?(value)
|
@@ -282,7 +301,7 @@ module Grape
|
|
282
301
|
default_type(required)
|
283
302
|
|
284
303
|
request_params = unless declared_params.nil? && route.headers.nil?
|
285
|
-
GrapeSwagger::Endpoint::ParamsParser.parse_request_params(required, settings)
|
304
|
+
GrapeSwagger::Endpoint::ParamsParser.parse_request_params(required, settings, self)
|
286
305
|
end || {}
|
287
306
|
|
288
307
|
request_params.empty? ? required : request_params
|
data/lib/grape-swagger.rb
CHANGED
@@ -26,7 +26,7 @@ module SwaggerRouting
|
|
26
26
|
def combine_routes(app, doc_klass)
|
27
27
|
app.routes.each do |route|
|
28
28
|
route_path = route.path
|
29
|
-
route_match = route_path.split(/^.*?#{route.prefix
|
29
|
+
route_match = route_path.split(/^.*?#{route.prefix}/).last
|
30
30
|
next unless route_match
|
31
31
|
|
32
32
|
route_match = route_match.match('\/([\w|-]*?)[\.\/\(]') || route_match.match('\/([\w|-]*)$')
|
@@ -0,0 +1,190 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe '751 deeply nested objects' do
|
6
|
+
let(:app) do
|
7
|
+
Class.new(Grape::API) do
|
8
|
+
content_type :json, 'application/json; charset=UTF-8'
|
9
|
+
default_format :json
|
10
|
+
class Vrp < Grape::API
|
11
|
+
def self.vrp_request_timewindow(this)
|
12
|
+
this.optional(:start, types: [String, Float, Integer])
|
13
|
+
this.optional(:end, types: [String, Float, Integer])
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.vrp_request_point(this)
|
17
|
+
this.requires(:id, type: String, allow_blank: false)
|
18
|
+
this.optional(:matrix_index, type: Integer)
|
19
|
+
this.optional(:location, type: Hash) do
|
20
|
+
requires(:lat, type: Float, allow_blank: false)
|
21
|
+
requires(:lon, type: Float, allow_blank: false)
|
22
|
+
end
|
23
|
+
this.at_least_one_of :matrix_index, :location
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.vrp_request_activity(this)
|
27
|
+
this.optional(:duration, types: [String, Float, Integer])
|
28
|
+
this.requires(:point_id, type: String, allow_blank: false)
|
29
|
+
this.optional(:timewindows, type: Array) do
|
30
|
+
Vrp.vrp_request_timewindow(self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.vrp_request_service(this)
|
35
|
+
this.requires(:id, type: String, allow_blank: false)
|
36
|
+
this.optional(:skills, type: Array[String])
|
37
|
+
|
38
|
+
this.optional(:activity, type: Hash) do
|
39
|
+
Vrp.vrp_request_activity(self)
|
40
|
+
end
|
41
|
+
this.optional(:activities, type: Array) do
|
42
|
+
Vrp.vrp_request_activity(self)
|
43
|
+
end
|
44
|
+
this.mutually_exclusive :activity, :activities
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
namespace :vrp do
|
49
|
+
resource :submit do
|
50
|
+
desc 'Submit Problems', nickname: 'vrp'
|
51
|
+
params do
|
52
|
+
optional(:vrp, type: Hash, documentation: { param_type: 'body' }) do
|
53
|
+
optional(:points, type: Array) do
|
54
|
+
Vrp.vrp_request_point(self)
|
55
|
+
end
|
56
|
+
|
57
|
+
optional(:services, type: Array) do
|
58
|
+
Vrp.vrp_request_service(self)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
post do
|
63
|
+
{ vrp: params[:vrp] }.to_json
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
add_swagger_documentation format: :json
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
subject do
|
73
|
+
get '/swagger_doc'
|
74
|
+
JSON.parse(last_response.body)
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'Correctness of vrp Points' do
|
78
|
+
let(:get_points_response) { subject['definitions']['postVrpSubmit']['properties']['vrp']['properties']['points'] }
|
79
|
+
specify do
|
80
|
+
expect(get_points_response).to eql(
|
81
|
+
'type' => 'array',
|
82
|
+
'items' => {
|
83
|
+
'type' => 'object',
|
84
|
+
'properties' => {
|
85
|
+
'id' => {
|
86
|
+
'type' => 'string'
|
87
|
+
},
|
88
|
+
'matrix_index' => {
|
89
|
+
'type' => 'integer',
|
90
|
+
'format' => 'int32'
|
91
|
+
},
|
92
|
+
'location' => {
|
93
|
+
'type' => 'object',
|
94
|
+
'properties' => {
|
95
|
+
'lat' => {
|
96
|
+
'type' => 'number',
|
97
|
+
'format' => 'float'
|
98
|
+
},
|
99
|
+
'lon' => {
|
100
|
+
'type' => 'number',
|
101
|
+
'format' => 'float'
|
102
|
+
}
|
103
|
+
},
|
104
|
+
'required' => %w[lat lon]
|
105
|
+
}
|
106
|
+
},
|
107
|
+
'required' => ['id']
|
108
|
+
}
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe 'Correctness of vrp Services' do
|
114
|
+
let(:get_service_response) { subject['definitions']['postVrpSubmit']['properties']['vrp']['properties']['services'] }
|
115
|
+
specify do
|
116
|
+
expect(get_service_response).to include(
|
117
|
+
'type' => 'array',
|
118
|
+
'items' => {
|
119
|
+
'type' => 'object',
|
120
|
+
'properties' => {
|
121
|
+
'id' => {
|
122
|
+
'type' => 'string'
|
123
|
+
},
|
124
|
+
'skills' => {
|
125
|
+
'type' => 'array',
|
126
|
+
'items' => {
|
127
|
+
'type' => 'string'
|
128
|
+
}
|
129
|
+
},
|
130
|
+
'activity' => {
|
131
|
+
'type' => 'object',
|
132
|
+
'properties' => {
|
133
|
+
'duration' => {
|
134
|
+
'type' => 'string'
|
135
|
+
},
|
136
|
+
'point_id' => {
|
137
|
+
'type' => 'string'
|
138
|
+
},
|
139
|
+
'timewindows' => {
|
140
|
+
'type' => 'array',
|
141
|
+
'items' => {
|
142
|
+
'type' => 'object',
|
143
|
+
'properties' => {
|
144
|
+
'start' => {
|
145
|
+
'type' => 'string'
|
146
|
+
},
|
147
|
+
'end' => {
|
148
|
+
'type' => 'string'
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
},
|
154
|
+
'required' => ['point_id']
|
155
|
+
}, 'activities' => {
|
156
|
+
'type' => 'array',
|
157
|
+
'items' => {
|
158
|
+
'type' => 'object',
|
159
|
+
'properties' => {
|
160
|
+
'duration' => {
|
161
|
+
'type' => 'string'
|
162
|
+
},
|
163
|
+
'point_id' => {
|
164
|
+
'type' => 'string'
|
165
|
+
},
|
166
|
+
'timewindows' => {
|
167
|
+
'type' => 'array',
|
168
|
+
'items' => {
|
169
|
+
'type' => 'object',
|
170
|
+
'properties' => {
|
171
|
+
'start' => {
|
172
|
+
'type' => 'string'
|
173
|
+
},
|
174
|
+
'end' => {
|
175
|
+
'type' => 'string'
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
179
|
+
}
|
180
|
+
},
|
181
|
+
'required' => ['point_id']
|
182
|
+
}
|
183
|
+
}
|
184
|
+
},
|
185
|
+
'required' => ['id']
|
186
|
+
}
|
187
|
+
)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
data/spec/lib/data_type_spec.rb
CHANGED
@@ -55,8 +55,8 @@ describe GrapeSwagger::DocMethods::DataType do
|
|
55
55
|
it { is_expected.to eq 'file' }
|
56
56
|
end
|
57
57
|
|
58
|
-
describe '
|
59
|
-
let(:value) { { type:
|
58
|
+
describe 'Grape::API::Boolean' do
|
59
|
+
let(:value) { { type: Grape::API::Boolean } }
|
60
60
|
|
61
61
|
it { is_expected.to eq 'boolean' }
|
62
62
|
end
|