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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -1
  3. data/.rubocop.yml +3 -0
  4. data/.rubocop_todo.yml +14 -22
  5. data/.travis.yml +7 -4
  6. data/CHANGELOG.md +53 -26
  7. data/Gemfile +1 -1
  8. data/README.md +414 -327
  9. data/RELEASING.md +3 -4
  10. data/example/api/endpoints.rb +132 -0
  11. data/example/api/entities.rb +18 -0
  12. data/example/config.ru +36 -2
  13. data/example/example_requests.postman_collection +146 -0
  14. data/example/swagger-example.png +0 -0
  15. data/grape-swagger.gemspec +9 -6
  16. data/lib/grape-swagger.rb +69 -99
  17. data/lib/grape-swagger/doc_methods.rb +69 -544
  18. data/lib/grape-swagger/doc_methods/data_type.rb +77 -0
  19. data/lib/grape-swagger/doc_methods/extensions.rb +75 -0
  20. data/lib/grape-swagger/doc_methods/move_params.rb +153 -0
  21. data/lib/grape-swagger/doc_methods/operation_id.rb +27 -0
  22. data/lib/grape-swagger/doc_methods/optional_object.rb +15 -0
  23. data/lib/grape-swagger/doc_methods/parse_params.rb +113 -0
  24. data/lib/grape-swagger/doc_methods/path_string.rb +29 -0
  25. data/lib/grape-swagger/doc_methods/produces_consumes.rb +12 -0
  26. data/lib/grape-swagger/doc_methods/status_codes.rb +17 -0
  27. data/lib/grape-swagger/doc_methods/tag_name_description.rb +26 -0
  28. data/lib/grape-swagger/endpoint.rb +317 -0
  29. data/lib/grape-swagger/version.rb +1 -1
  30. data/spec/lib/data_type_spec.rb +57 -0
  31. data/spec/lib/endpoint_spec.rb +6 -0
  32. data/spec/lib/extensions_spec.rb +127 -0
  33. data/spec/lib/move_params_spec.rb +298 -0
  34. data/spec/lib/operation_id_spec.rb +24 -0
  35. data/spec/lib/optional_object_spec.rb +40 -0
  36. data/spec/lib/path_string_spec.rb +38 -0
  37. data/spec/lib/produces_consumes_spec.rb +98 -0
  38. data/spec/markdown/kramdown_adapter_spec.rb +2 -9
  39. data/spec/markdown/redcarpet_adapter_spec.rb +2 -16
  40. data/spec/spec_helper.rb +7 -13
  41. data/spec/support/api_swagger_v2_result.rb +204 -0
  42. data/spec/support/namespace_tags.rb +73 -0
  43. data/spec/support/the_api_entities.rb +52 -0
  44. data/spec/support/the_paths_definitions.rb +94 -0
  45. data/spec/swagger_v2/api_swagger_v2_definitions-models_spec.rb +32 -0
  46. data/spec/swagger_v2/api_swagger_v2_detail_spec.rb +151 -0
  47. data/spec/swagger_v2/api_swagger_v2_extensions_spec.rb +109 -0
  48. data/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb +124 -0
  49. data/spec/swagger_v2/api_swagger_v2_global_configuration_spec.rb +51 -0
  50. data/spec/swagger_v2/api_swagger_v2_headers_spec.rb +44 -0
  51. data/spec/swagger_v2/api_swagger_v2_hide_documentation_path_spec.rb +56 -0
  52. data/spec/swagger_v2/api_swagger_v2_mounted_spec.rb +146 -0
  53. data/spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb +197 -0
  54. data/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb +151 -0
  55. data/spec/swagger_v2/api_swagger_v2_param_type_spec.rb +217 -0
  56. data/spec/swagger_v2/api_swagger_v2_request_params_fix_spec.rb +64 -0
  57. data/spec/swagger_v2/api_swagger_v2_response_spec.rb +184 -0
  58. data/spec/swagger_v2/api_swagger_v2_spec.rb +207 -0
  59. data/spec/swagger_v2/api_swagger_v2_type-format_spec.rb +121 -0
  60. data/spec/{boolean_params_spec.rb → swagger_v2/boolean_params_spec.rb} +2 -2
  61. data/spec/{default_api_spec.rb → swagger_v2/default_api_spec.rb} +40 -36
  62. data/spec/swagger_v2/description_not_initialized.rb +39 -0
  63. data/spec/{float_api_spec.rb → swagger_v2/float_api_spec.rb} +2 -2
  64. data/spec/{form_params_spec.rb → swagger_v2/form_params_spec.rb} +9 -9
  65. data/spec/{grape-swagger_spec.rb → swagger_v2/grape-swagger_spec.rb} +0 -0
  66. data/spec/swagger_v2/hide_api_spec.rb +131 -0
  67. data/spec/swagger_v2/mounted_target_class_spec.rb +76 -0
  68. data/spec/swagger_v2/namespace_tags_prefix_spec.rb +84 -0
  69. data/spec/swagger_v2/namespace_tags_spec.rb +76 -0
  70. data/spec/{namespaced_api_spec.rb → swagger_v2/namespaced_api_spec.rb} +6 -26
  71. data/spec/{param_type_spec.rb → swagger_v2/param_type_spec.rb} +10 -8
  72. data/spec/{param_values_spec.rb → swagger_v2/param_values_spec.rb} +52 -22
  73. data/spec/swagger_v2/params_array_spec.rb +63 -0
  74. data/spec/swagger_v2/params_hash_spec.rb +65 -0
  75. data/spec/swagger_v2/params_nested_spec.rb +63 -0
  76. data/spec/{reference_entity.rb → swagger_v2/reference_entity.rb} +18 -23
  77. data/spec/swagger_v2/response_model_spec.rb +212 -0
  78. data/spec/swagger_v2/simple_mounted_api_spec.rb +264 -0
  79. metadata +175 -90
  80. data/example/api.rb +0 -66
  81. data/lib/grape-swagger/markdown.rb +0 -23
  82. data/spec/api_description_spec.rb +0 -43
  83. data/spec/api_global_models_spec.rb +0 -77
  84. data/spec/api_models_spec.rb +0 -364
  85. data/spec/api_paths_spec.rb +0 -128
  86. data/spec/api_root_spec.rb +0 -30
  87. data/spec/api_with_nil_types.rb +0 -50
  88. data/spec/api_with_path_versioning_spec.rb +0 -33
  89. data/spec/api_with_prefix_and_namespace_spec.rb +0 -32
  90. data/spec/api_with_standalone_namespace_spec.rb +0 -215
  91. data/spec/array_entity_spec.rb +0 -34
  92. data/spec/array_params_spec.rb +0 -85
  93. data/spec/grape-swagger_helper_spec.rb +0 -152
  94. data/spec/group_params_spec.rb +0 -31
  95. data/spec/hash_params_spec.rb +0 -30
  96. data/spec/hide_api_spec.rb +0 -124
  97. data/spec/i18n_spec.rb +0 -364
  98. data/spec/markdown/markdown_spec.rb +0 -27
  99. data/spec/mounted_target_class_spec.rb +0 -63
  100. data/spec/mutually_exclusive_spec.rb +0 -36
  101. data/spec/non_default_api_spec.rb +0 -733
  102. data/spec/response_model_spec.rb +0 -121
  103. data/spec/simple_mounted_api_spec.rb +0 -213
  104. 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
@@ -1,3 +1,3 @@
1
1
  module GrapeSwagger
2
- VERSION = '0.11.0'.freeze
2
+ VERSION = '0.20.0'.freeze
3
3
  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