grape-swagger 0.11.0 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +8 -1
- data/.rubocop.yml +3 -0
- data/.rubocop_todo.yml +14 -22
- data/.travis.yml +7 -4
- data/CHANGELOG.md +53 -26
- data/Gemfile +1 -1
- data/README.md +414 -327
- data/RELEASING.md +3 -4
- data/example/api/endpoints.rb +132 -0
- data/example/api/entities.rb +18 -0
- data/example/config.ru +36 -2
- data/example/example_requests.postman_collection +146 -0
- data/example/swagger-example.png +0 -0
- data/grape-swagger.gemspec +9 -6
- data/lib/grape-swagger.rb +69 -99
- data/lib/grape-swagger/doc_methods.rb +69 -544
- data/lib/grape-swagger/doc_methods/data_type.rb +77 -0
- data/lib/grape-swagger/doc_methods/extensions.rb +75 -0
- data/lib/grape-swagger/doc_methods/move_params.rb +153 -0
- data/lib/grape-swagger/doc_methods/operation_id.rb +27 -0
- data/lib/grape-swagger/doc_methods/optional_object.rb +15 -0
- data/lib/grape-swagger/doc_methods/parse_params.rb +113 -0
- data/lib/grape-swagger/doc_methods/path_string.rb +29 -0
- data/lib/grape-swagger/doc_methods/produces_consumes.rb +12 -0
- data/lib/grape-swagger/doc_methods/status_codes.rb +17 -0
- data/lib/grape-swagger/doc_methods/tag_name_description.rb +26 -0
- data/lib/grape-swagger/endpoint.rb +317 -0
- data/lib/grape-swagger/version.rb +1 -1
- data/spec/lib/data_type_spec.rb +57 -0
- data/spec/lib/endpoint_spec.rb +6 -0
- data/spec/lib/extensions_spec.rb +127 -0
- data/spec/lib/move_params_spec.rb +298 -0
- data/spec/lib/operation_id_spec.rb +24 -0
- data/spec/lib/optional_object_spec.rb +40 -0
- data/spec/lib/path_string_spec.rb +38 -0
- data/spec/lib/produces_consumes_spec.rb +98 -0
- data/spec/markdown/kramdown_adapter_spec.rb +2 -9
- data/spec/markdown/redcarpet_adapter_spec.rb +2 -16
- data/spec/spec_helper.rb +7 -13
- data/spec/support/api_swagger_v2_result.rb +204 -0
- data/spec/support/namespace_tags.rb +73 -0
- data/spec/support/the_api_entities.rb +52 -0
- data/spec/support/the_paths_definitions.rb +94 -0
- data/spec/swagger_v2/api_swagger_v2_definitions-models_spec.rb +32 -0
- data/spec/swagger_v2/api_swagger_v2_detail_spec.rb +151 -0
- data/spec/swagger_v2/api_swagger_v2_extensions_spec.rb +109 -0
- data/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb +124 -0
- data/spec/swagger_v2/api_swagger_v2_global_configuration_spec.rb +51 -0
- data/spec/swagger_v2/api_swagger_v2_headers_spec.rb +44 -0
- data/spec/swagger_v2/api_swagger_v2_hide_documentation_path_spec.rb +56 -0
- data/spec/swagger_v2/api_swagger_v2_mounted_spec.rb +146 -0
- data/spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb +197 -0
- data/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb +151 -0
- data/spec/swagger_v2/api_swagger_v2_param_type_spec.rb +217 -0
- data/spec/swagger_v2/api_swagger_v2_request_params_fix_spec.rb +64 -0
- data/spec/swagger_v2/api_swagger_v2_response_spec.rb +184 -0
- data/spec/swagger_v2/api_swagger_v2_spec.rb +207 -0
- data/spec/swagger_v2/api_swagger_v2_type-format_spec.rb +121 -0
- data/spec/{boolean_params_spec.rb → swagger_v2/boolean_params_spec.rb} +2 -2
- data/spec/{default_api_spec.rb → swagger_v2/default_api_spec.rb} +40 -36
- data/spec/swagger_v2/description_not_initialized.rb +39 -0
- data/spec/{float_api_spec.rb → swagger_v2/float_api_spec.rb} +2 -2
- data/spec/{form_params_spec.rb → swagger_v2/form_params_spec.rb} +9 -9
- data/spec/{grape-swagger_spec.rb → swagger_v2/grape-swagger_spec.rb} +0 -0
- data/spec/swagger_v2/hide_api_spec.rb +131 -0
- data/spec/swagger_v2/mounted_target_class_spec.rb +76 -0
- data/spec/swagger_v2/namespace_tags_prefix_spec.rb +84 -0
- data/spec/swagger_v2/namespace_tags_spec.rb +76 -0
- data/spec/{namespaced_api_spec.rb → swagger_v2/namespaced_api_spec.rb} +6 -26
- data/spec/{param_type_spec.rb → swagger_v2/param_type_spec.rb} +10 -8
- data/spec/{param_values_spec.rb → swagger_v2/param_values_spec.rb} +52 -22
- data/spec/swagger_v2/params_array_spec.rb +63 -0
- data/spec/swagger_v2/params_hash_spec.rb +65 -0
- data/spec/swagger_v2/params_nested_spec.rb +63 -0
- data/spec/{reference_entity.rb → swagger_v2/reference_entity.rb} +18 -23
- data/spec/swagger_v2/response_model_spec.rb +212 -0
- data/spec/swagger_v2/simple_mounted_api_spec.rb +264 -0
- metadata +175 -90
- data/example/api.rb +0 -66
- data/lib/grape-swagger/markdown.rb +0 -23
- data/spec/api_description_spec.rb +0 -43
- data/spec/api_global_models_spec.rb +0 -77
- data/spec/api_models_spec.rb +0 -364
- data/spec/api_paths_spec.rb +0 -128
- data/spec/api_root_spec.rb +0 -30
- data/spec/api_with_nil_types.rb +0 -50
- data/spec/api_with_path_versioning_spec.rb +0 -33
- data/spec/api_with_prefix_and_namespace_spec.rb +0 -32
- data/spec/api_with_standalone_namespace_spec.rb +0 -215
- data/spec/array_entity_spec.rb +0 -34
- data/spec/array_params_spec.rb +0 -85
- data/spec/grape-swagger_helper_spec.rb +0 -152
- data/spec/group_params_spec.rb +0 -31
- data/spec/hash_params_spec.rb +0 -30
- data/spec/hide_api_spec.rb +0 -124
- data/spec/i18n_spec.rb +0 -364
- data/spec/markdown/markdown_spec.rb +0 -27
- data/spec/mounted_target_class_spec.rb +0 -63
- data/spec/mutually_exclusive_spec.rb +0 -36
- data/spec/non_default_api_spec.rb +0 -733
- data/spec/response_model_spec.rb +0 -121
- data/spec/simple_mounted_api_spec.rb +0 -213
- data/spec/support/i18n_helper.rb +0 -8
@@ -0,0 +1,29 @@
|
|
1
|
+
module GrapeSwagger
|
2
|
+
module DocMethods
|
3
|
+
class PathString
|
4
|
+
class << self
|
5
|
+
def build(path, options = {})
|
6
|
+
# always removing format
|
7
|
+
path.sub!(/\(\.\w+?\)$/, '')
|
8
|
+
path.sub!('(.:format)', '')
|
9
|
+
|
10
|
+
# ... format path params
|
11
|
+
path.gsub!(/:(\w+)/, '{\1}')
|
12
|
+
|
13
|
+
# set item from path, this could be used for the definitions object
|
14
|
+
item = path.gsub(%r{/{(.+?)}}, '').split('/').last.singularize.underscore.camelize || 'Item'
|
15
|
+
|
16
|
+
if options[:version] && options[:add_version]
|
17
|
+
path.sub!('{version}', options[:version])
|
18
|
+
else
|
19
|
+
path.sub!('/{version}', '')
|
20
|
+
end
|
21
|
+
|
22
|
+
path = "#{GrapeSwagger::DocMethods::OptionalObject.build(:base_path, options)}#{path}" if options[:add_base_path]
|
23
|
+
|
24
|
+
[item, path.start_with?('/') ? path : "/#{path}"]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module GrapeSwagger
|
2
|
+
module DocMethods
|
3
|
+
class ProducesConsumes
|
4
|
+
class << self
|
5
|
+
def call(*args)
|
6
|
+
return ['application/json'] unless args.flatten.present?
|
7
|
+
args.flatten.map { |x| Grape::ContentTypes::CONTENT_TYPES[x] || x }.uniq
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module GrapeSwagger
|
2
|
+
module DocMethods
|
3
|
+
class StatusCodes
|
4
|
+
class << self
|
5
|
+
def get
|
6
|
+
{
|
7
|
+
get: { code: 200, message: 'get {item}(s)' },
|
8
|
+
post: { code: 201, message: 'created {item}' },
|
9
|
+
put: { code: 200, message: 'updated {item}' },
|
10
|
+
patch: { code: 200, message: 'patched {item}' },
|
11
|
+
delete: { code: 200, message: 'deleted {item}' }
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module GrapeSwagger
|
2
|
+
module DocMethods
|
3
|
+
class TagNameDescription
|
4
|
+
class << self
|
5
|
+
def build(options = {})
|
6
|
+
target_class = options[:target_class]
|
7
|
+
namespaces = target_class.combined_namespaces
|
8
|
+
namespace_routes = target_class.combined_namespace_routes
|
9
|
+
|
10
|
+
namespace_routes.keys.map do |local_route|
|
11
|
+
next if namespace_routes[local_route].map(&:route_hidden).all? { |value| value.respond_to?(:call) ? value.call : value }
|
12
|
+
|
13
|
+
original_namespace_name = target_class.combined_namespace_identifiers.key?(local_route) ? target_class.combined_namespace_identifiers[local_route] : local_route
|
14
|
+
description = namespaces[original_namespace_name] && namespaces[original_namespace_name].options[:desc]
|
15
|
+
description ||= "Operations about #{original_namespace_name.pluralize}"
|
16
|
+
|
17
|
+
{
|
18
|
+
name: local_route,
|
19
|
+
description: description
|
20
|
+
}
|
21
|
+
end.compact
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,317 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/core_ext/string/inflections.rb'
|
3
|
+
|
4
|
+
module Grape
|
5
|
+
class Endpoint
|
6
|
+
def content_types_for(target_class)
|
7
|
+
content_types = (target_class.content_types || {}).values
|
8
|
+
|
9
|
+
if content_types.empty?
|
10
|
+
formats = [target_class.format, target_class.default_format].compact.uniq
|
11
|
+
formats = Grape::Formatter::Base.formatters({}).keys if formats.empty?
|
12
|
+
content_types = Grape::ContentTypes::CONTENT_TYPES.select { |content_type, _mime_type| formats.include? content_type }.values
|
13
|
+
end
|
14
|
+
|
15
|
+
content_types.uniq
|
16
|
+
end
|
17
|
+
|
18
|
+
# swagger spec2.0 related parts
|
19
|
+
#
|
20
|
+
# required keys for SwaggerObject
|
21
|
+
def swagger_object(target_class, request, options)
|
22
|
+
{
|
23
|
+
info: info_object(options[:info].merge(version: options[:api_version])),
|
24
|
+
swagger: '2.0',
|
25
|
+
produces: content_types_for(target_class),
|
26
|
+
authorizations: options[:authorizations],
|
27
|
+
host: GrapeSwagger::DocMethods::OptionalObject.build(:host, options, request.env['HTTP_HOST']),
|
28
|
+
basePath: GrapeSwagger::DocMethods::OptionalObject.build(:base_path, options, request.env['SCRIPT_NAME']),
|
29
|
+
tags: GrapeSwagger::DocMethods::TagNameDescription.build(options),
|
30
|
+
schemes: options[:schemes].is_a?(String) ? [options[:schemes]] : options[:schemes]
|
31
|
+
}.delete_if { |_, value| value.blank? }
|
32
|
+
end
|
33
|
+
|
34
|
+
# building info object
|
35
|
+
def info_object(infos)
|
36
|
+
{
|
37
|
+
title: infos[:title] || 'API title',
|
38
|
+
description: infos[:description],
|
39
|
+
termsOfServiceUrl: infos[:terms_of_service_url],
|
40
|
+
contact: contact_object(infos),
|
41
|
+
license: license_object(infos),
|
42
|
+
version: infos[:version]
|
43
|
+
}.delete_if { |_, value| value.blank? }
|
44
|
+
end
|
45
|
+
|
46
|
+
# sub-objects of info object
|
47
|
+
# license
|
48
|
+
def license_object(infos)
|
49
|
+
{
|
50
|
+
name: infos.delete(:license),
|
51
|
+
url: infos.delete(:license_url)
|
52
|
+
}.delete_if { |_, value| value.blank? }
|
53
|
+
end
|
54
|
+
|
55
|
+
# contact
|
56
|
+
def contact_object(infos)
|
57
|
+
{
|
58
|
+
name: infos.delete(:contact_name),
|
59
|
+
email: infos.delete(:contact_email),
|
60
|
+
url: infos.delete(:contact_url)
|
61
|
+
}.delete_if { |_, value| value.blank? }
|
62
|
+
end
|
63
|
+
|
64
|
+
# building path and definitions objects
|
65
|
+
def path_and_definition_objects(namespace_routes, options)
|
66
|
+
@paths = {}
|
67
|
+
@definitions = {}
|
68
|
+
namespace_routes.keys.each do |key|
|
69
|
+
routes = namespace_routes[key]
|
70
|
+
path_item(routes, options)
|
71
|
+
end
|
72
|
+
|
73
|
+
add_definitions_from options[:models]
|
74
|
+
GrapeSwagger::DocMethods::MoveParams.to_definition(@paths, @definitions)
|
75
|
+
[@paths, @definitions]
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_definitions_from(models)
|
79
|
+
return if models.nil?
|
80
|
+
|
81
|
+
models.each { |x| expose_params_from_model(x) }
|
82
|
+
end
|
83
|
+
|
84
|
+
# path object
|
85
|
+
def path_item(routes, options)
|
86
|
+
routes.each do |route|
|
87
|
+
next if hidden?(route)
|
88
|
+
|
89
|
+
@item, path = GrapeSwagger::DocMethods::PathString.build(route.route_path, options)
|
90
|
+
@entity = route.route_entity || route.route_success
|
91
|
+
|
92
|
+
method = route.route_method.downcase.to_sym
|
93
|
+
request_params = method_object(route, options, path)
|
94
|
+
|
95
|
+
if @paths.key?(path.to_sym)
|
96
|
+
@paths[path.to_sym][method] = request_params
|
97
|
+
else
|
98
|
+
@paths[path.to_sym] = { method => request_params }
|
99
|
+
end
|
100
|
+
|
101
|
+
GrapeSwagger::DocMethods::Extensions.add(@paths[path.to_sym], @definitions, route)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def method_object(route, options, path)
|
106
|
+
method = {}
|
107
|
+
method[:description] = description_object(route, options[:markdown])
|
108
|
+
method[:headers] = route.route_headers if route.route_headers
|
109
|
+
method[:produces] = produces_object(route, options[:produces] || options[:format])
|
110
|
+
method[:consumes] = consumes_object(route, options[:format])
|
111
|
+
method[:parameters] = params_object(route)
|
112
|
+
method[:responses] = response_object(route, options[:markdown])
|
113
|
+
method[:tags] = tag_object(route, options[:version])
|
114
|
+
method[:operationId] = GrapeSwagger::DocMethods::OperationId.build(route.route_method, path)
|
115
|
+
method.delete_if { |_, value| value.blank? }
|
116
|
+
end
|
117
|
+
|
118
|
+
def description_object(route, markdown)
|
119
|
+
description = route.route_desc if route.route_desc.present?
|
120
|
+
description = route.route_description if route.route_description.present?
|
121
|
+
description = "# #{description} " if markdown
|
122
|
+
description += "\n #{route.route_detail}" if route.route_detail
|
123
|
+
description = markdown.markdown(description.to_s).chomp if markdown
|
124
|
+
|
125
|
+
description
|
126
|
+
end
|
127
|
+
|
128
|
+
def produces_object(route, format)
|
129
|
+
mime_types = GrapeSwagger::DocMethods::ProducesConsumes.call(format)
|
130
|
+
|
131
|
+
route_mime_types = [:route_formats, :route_content_types, :route_produces].map do |producer|
|
132
|
+
possible = route.send(producer)
|
133
|
+
GrapeSwagger::DocMethods::ProducesConsumes.call(possible) if possible.present?
|
134
|
+
end.flatten.compact.uniq
|
135
|
+
|
136
|
+
route_mime_types.present? ? route_mime_types : mime_types
|
137
|
+
end
|
138
|
+
|
139
|
+
def consumes_object(route, format)
|
140
|
+
method = route.route_method.downcase.to_sym
|
141
|
+
format = route.route_settings[:description][:consumes] if route.route_settings[:description] && route.route_settings[:description][:consumes]
|
142
|
+
mime_types = GrapeSwagger::DocMethods::ProducesConsumes.call(format) if [:post, :put].include?(method)
|
143
|
+
|
144
|
+
mime_types
|
145
|
+
end
|
146
|
+
|
147
|
+
def params_object(route)
|
148
|
+
partition_params(route).map do |param, value|
|
149
|
+
value = { required: false }.merge(value) if value.is_a?(Hash)
|
150
|
+
_, value = default_type([[param, value]]).first if value == ''
|
151
|
+
GrapeSwagger::DocMethods::ParseParams.call(param, value, route)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def response_object(route, markdown)
|
156
|
+
default_code = GrapeSwagger::DocMethods::StatusCodes.get[route.route_method.downcase.to_sym]
|
157
|
+
default_code[:model] = @entity if @entity
|
158
|
+
default_code[:message] = route.route_description || default_code[:message].sub('{item}', @item)
|
159
|
+
|
160
|
+
codes = [default_code] + (route.route_http_codes || route.route_failure || [])
|
161
|
+
codes.map! { |x| x.is_a?(Array) ? { code: x[0], message: x[1], model: x[2] } : x }
|
162
|
+
|
163
|
+
codes.each_with_object({}) do |value, memo|
|
164
|
+
memo[value[:code]] = { description: value[:message] }
|
165
|
+
|
166
|
+
response_model = @item
|
167
|
+
response_model = expose_params_from_model(value[:model]) if value[:model]
|
168
|
+
|
169
|
+
if memo.key?(200) && route.route_method == 'DELETE' && value[:model].nil?
|
170
|
+
memo[204] = memo.delete(200)
|
171
|
+
value[:code] = 204
|
172
|
+
end
|
173
|
+
|
174
|
+
next if memo.key?(204)
|
175
|
+
next unless !response_model.start_with?('Swagger_doc') &&
|
176
|
+
((@definitions[response_model] && value[:code].to_s.start_with?('2')) || value[:model])
|
177
|
+
|
178
|
+
@definitions[response_model][:description] = description_object(route, markdown)
|
179
|
+
# TODO: proof that the definition exist, if model isn't specified
|
180
|
+
memo[value[:code]][:schema] = if route.route_is_array
|
181
|
+
{ 'type' => 'array', 'items' => { '$ref' => "#/definitions/#{response_model}" } }
|
182
|
+
else
|
183
|
+
{ '$ref' => "#/definitions/#{response_model}" }
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def tag_object(route, version)
|
189
|
+
Array(route.route_path.split('{')[0].split('/').reject(&:empty?).delete_if { |i| ((i == route.route_prefix.to_s) || (i == version)) }.first)
|
190
|
+
end
|
191
|
+
|
192
|
+
private
|
193
|
+
|
194
|
+
def partition_params(route)
|
195
|
+
declared_params = route.route_settings[:declared_params] if route.route_settings[:declared_params].present?
|
196
|
+
required, exposed = route.route_params.partition { |x| x.first.is_a? String }
|
197
|
+
|
198
|
+
default_type(required)
|
199
|
+
default_type(exposed)
|
200
|
+
|
201
|
+
unless declared_params.nil?
|
202
|
+
request_params = parse_request_params(required)
|
203
|
+
end
|
204
|
+
|
205
|
+
if !exposed.empty?
|
206
|
+
exposed_params = exposed.each_with_object({}) { |x, memo| memo[x.first] = x.last }
|
207
|
+
properties = parse_response_params(exposed_params)
|
208
|
+
else
|
209
|
+
properties = parse_response_params(required)
|
210
|
+
end
|
211
|
+
|
212
|
+
key = model_name(@entity || @item)
|
213
|
+
|
214
|
+
unless properties.empty? || (route.route_method == 'DELETE' && !@entity)
|
215
|
+
@definitions[key] = { type: 'object', properties: properties } unless @definitions.key?(key)
|
216
|
+
@definitions[key][:properties].merge!(properties) if @definitions.key?(key)
|
217
|
+
end
|
218
|
+
|
219
|
+
return route.route_params if route.route_params && !route.route_settings[:declared_params].present?
|
220
|
+
request_params || {}
|
221
|
+
end
|
222
|
+
|
223
|
+
def default_type(params)
|
224
|
+
params.each do |param|
|
225
|
+
param[-1] = param.last == '' ? { required: true, type: 'Integer' } : param.last
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def parse_request_params(required)
|
230
|
+
required.each_with_object({}) do |param, memo|
|
231
|
+
@array_key = param.first.to_s.gsub('[', '[][') if param.last[:type] == 'Array'
|
232
|
+
possible_key = param.first.to_s.gsub('[', '[][')
|
233
|
+
if @array_key && possible_key.start_with?(@array_key)
|
234
|
+
key = possible_key
|
235
|
+
param.last[:is_array] = true
|
236
|
+
else
|
237
|
+
key = param.first
|
238
|
+
end
|
239
|
+
memo[key] = param.last unless param.last[:type] == 'Hash' || param.last[:type] == 'Array' && !param.last.key?(:documentation)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def parse_response_params(params)
|
244
|
+
return if params.nil?
|
245
|
+
|
246
|
+
params.each_with_object({}) do |x, memo|
|
247
|
+
x[0] = x.last[:as] if x.last[:as]
|
248
|
+
|
249
|
+
model = x.last[:using] if x.last[:using].present?
|
250
|
+
model ||= x.last[:documentation][:type] if x.last[:documentation] && could_it_be_a_model?(x.last[:documentation])
|
251
|
+
|
252
|
+
if model
|
253
|
+
name = expose_params_from_model(model)
|
254
|
+
memo[x.first] = if x.last[:documentation] && x.last[:documentation][:is_array]
|
255
|
+
{ 'type' => 'array', 'items' => { '$ref' => "#/definitions/#{name}" } }
|
256
|
+
else
|
257
|
+
{ '$ref' => "#/definitions/#{name}" }
|
258
|
+
end
|
259
|
+
else
|
260
|
+
documented_type = x.last[:type]
|
261
|
+
documented_type ||= x.last[:documentation][:type] if x.last[:documentation]
|
262
|
+
data_type = GrapeSwagger::DocMethods::DataType.call(documented_type)
|
263
|
+
|
264
|
+
if GrapeSwagger::DocMethods::DataType.primitive?(data_type)
|
265
|
+
data = GrapeSwagger::DocMethods::DataType.mapping(data_type)
|
266
|
+
memo[x.first] = { type: data.first, format: data.last }
|
267
|
+
else
|
268
|
+
memo[x.first] = { type: data_type }
|
269
|
+
end
|
270
|
+
|
271
|
+
memo[x.first][:enum] = x.last[:values] if x.last[:values] && x.last[:values].is_a?(Array)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def expose_params_from_model(model)
|
277
|
+
model_name = model_name(model)
|
278
|
+
|
279
|
+
# TODO: this should only be a temporary hack ;)
|
280
|
+
if GrapeEntity::VERSION =~ /0\.4\.\d/
|
281
|
+
parameters = model.exposures ? model.exposures : model.documentation
|
282
|
+
elsif GrapeEntity::VERSION =~ /0\.5\.\d/
|
283
|
+
parameters = model.root_exposures.each_with_object({}) do |value, memo|
|
284
|
+
memo[value.attribute] = value.send(:options)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
properties = parse_response_params(parameters)
|
288
|
+
|
289
|
+
@definitions[model_name] = { type: 'object', properties: properties }
|
290
|
+
|
291
|
+
model_name
|
292
|
+
end
|
293
|
+
|
294
|
+
def model_name(name)
|
295
|
+
name.respond_to?(:name) ? name.name.demodulize.camelize : name.split('::').last
|
296
|
+
end
|
297
|
+
|
298
|
+
def could_it_be_a_model?(value)
|
299
|
+
(
|
300
|
+
value[:type].to_s.include?('Entity') || value[:type].to_s.include?('Entities')
|
301
|
+
) || (
|
302
|
+
value[:type] &&
|
303
|
+
value[:type].is_a?(Class) &&
|
304
|
+
!GrapeSwagger::DocMethods::DataType.primitive?(value[:type].name.downcase) &&
|
305
|
+
!value[:type] == Array
|
306
|
+
)
|
307
|
+
end
|
308
|
+
|
309
|
+
def hidden?(route)
|
310
|
+
if route.route_hidden
|
311
|
+
return route.route_hidden.is_a?(Proc) ? route.route_hidden.call : route.route_hidden
|
312
|
+
end
|
313
|
+
|
314
|
+
false
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GrapeSwagger::DocMethods::DataType do
|
4
|
+
|
5
|
+
subject { described_class.call(value) }
|
6
|
+
|
7
|
+
describe "standards" do
|
8
|
+
['Boolean', Date, Integer, String, Float].each do |type|
|
9
|
+
specify do
|
10
|
+
data_type = described_class.call({ type: type })
|
11
|
+
expect(data_type).to eql type.to_s.downcase
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "Hash" do
|
17
|
+
let(:value) { { type: Hash } }
|
18
|
+
|
19
|
+
it { expect(subject).to eql 'object' }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "Rack::Multipart::UploadedFile" do
|
23
|
+
let(:value) { { type: Rack::Multipart::UploadedFile } }
|
24
|
+
|
25
|
+
it { expect(subject).to eql 'file' }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "Virtus::Attribute::Boolean" do
|
29
|
+
let(:value) { { type: Virtus::Attribute::Boolean } }
|
30
|
+
|
31
|
+
it { expect(subject).to eql 'boolean' }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "BigDecimal" do
|
35
|
+
let(:value) { { type: BigDecimal } }
|
36
|
+
|
37
|
+
it { expect(subject).to eql 'double' }
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "DateTime" do
|
41
|
+
let(:value) { { type: DateTime } }
|
42
|
+
|
43
|
+
it { expect(subject).to eql 'dateTime' }
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "Numeric" do
|
47
|
+
let(:value) { { type: Numeric } }
|
48
|
+
|
49
|
+
it { expect(subject).to eql 'long' }
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "Symbol" do
|
53
|
+
let(:value) { { type: Symbol } }
|
54
|
+
|
55
|
+
it { expect(subject).to eql 'string' }
|
56
|
+
end
|
57
|
+
end
|