schemable 0.1.1 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +16 -2
- data/Gemfile +7 -6
- data/Gemfile.lock +21 -13
- data/README.md +165 -9
- data/Rakefile +3 -3
- data/lib/generators/schemable/install_generator.rb +2 -2
- data/lib/generators/schemable/model_generator.rb +10 -6
- data/lib/schemable/version.rb +1 -1
- data/lib/schemable.rb +382 -315
- data/schemable.gemspec +16 -17
- metadata +8 -8
data/lib/schemable.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative 'schemable/version'
|
4
4
|
require 'active_support/concern'
|
5
5
|
|
6
6
|
module Schemable
|
@@ -9,7 +9,6 @@ module Schemable
|
|
9
9
|
extend ActiveSupport::Concern
|
10
10
|
|
11
11
|
included do
|
12
|
-
|
13
12
|
# Maps a given type name to a corresponding JSON schema object that represents that type.
|
14
13
|
#
|
15
14
|
# @param type_name [String, Symbol] A String or Symbol representing the type of the property to be mapped.
|
@@ -22,7 +21,7 @@ module Schemable
|
|
22
21
|
integer: { type: :integer },
|
23
22
|
float: { type: :number, format: :float },
|
24
23
|
decimal: { type: :number, format: :double },
|
25
|
-
datetime: { type: :string, format: :
|
24
|
+
datetime: { type: :string, format: :'date-time' },
|
26
25
|
date: { type: :string, format: :date },
|
27
26
|
time: { type: :string, format: :time },
|
28
27
|
boolean: { type: :boolean },
|
@@ -42,42 +41,43 @@ module Schemable
|
|
42
41
|
# Modify a JSON schema object by merging new properties into it or deleting a specified path.
|
43
42
|
#
|
44
43
|
# @param original_schema [Hash] The original schema object to modify.
|
44
|
+
#
|
45
45
|
# @param new_props [Hash] The new properties to merge into the schema.
|
46
|
-
#
|
47
|
-
# Use dot notation to specify nested properties (e.g. "person.address.city").
|
46
|
+
#
|
47
|
+
# @param given_path [String, nil] The path to the property to modify or delete, if any. Use dot notation to specify nested properties (e.g. "person.address.city").
|
48
|
+
#
|
48
49
|
# @param delete [Boolean] Whether to delete the property at the given path, if it exists.
|
50
|
+
#
|
49
51
|
# @raise [ArgumentError] If `delete` is true but `given_path` is nil, or if `given_path` does not exist in the original schema.
|
50
52
|
#
|
51
53
|
# @return [Hash] A new schema object with the specified modifications.
|
52
54
|
#
|
53
|
-
# @example
|
54
|
-
#
|
55
|
-
# new_props = { properties: { age: { type: 'integer' } } }
|
56
|
-
# modify_schema(original_schema, new_props)
|
57
|
-
# # => { type: 'object', properties: { name: { type: 'string' }, age: { type: 'integer' } } }
|
55
|
+
# @example
|
56
|
+
# `Merge new properties into the schema`
|
58
57
|
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
58
|
+
# original_schema = { type: 'object', properties: { name: { type: 'string' } } }
|
59
|
+
# new_props = { properties: { age: { type: 'integer' } } }
|
60
|
+
# modify_schema(original_schema, new_props)
|
61
|
+
# => {type: 'object', properties: {name: {type: 'string'}, age: {type: 'integer'}}}
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# `Delete a property from the schema`
|
65
|
+
#
|
66
|
+
# original_schema = { type: 'object', properties: { name: { type: 'string' } } }
|
67
|
+
# modify_schema(original_schema, {}, 'properties.name', delete: true)
|
68
|
+
# => {type: 'object', properties: {}}
|
63
69
|
def modify_schema(original_schema, new_props, given_path = nil, delete: false)
|
64
70
|
return new_props if original_schema.nil?
|
65
71
|
|
66
|
-
if given_path.nil? && delete
|
67
|
-
raise ArgumentError, "Cannot delete without a given path"
|
68
|
-
end
|
72
|
+
raise ArgumentError, 'Cannot delete without a given path' if given_path.nil? && delete
|
69
73
|
|
70
74
|
if given_path.present?
|
71
75
|
path_segments = given_path.split('.').map(&:to_sym)
|
72
76
|
|
73
77
|
if path_segments.size == 1
|
74
|
-
unless original_schema.key?(path_segments.first)
|
75
|
-
raise ArgumentError, "Given path does not exist in the original schema"
|
76
|
-
end
|
78
|
+
raise ArgumentError, 'Given path does not exist in the original schema' unless original_schema.key?(path_segments.first)
|
77
79
|
else
|
78
|
-
unless original_schema.dig(*path_segments[0..-2]).is_a?(Hash) && original_schema.dig(*path_segments)
|
79
|
-
raise ArgumentError, "Given path does not exist in the original schema"
|
80
|
-
end
|
80
|
+
raise ArgumentError, 'Given path does not exist in the original schema' unless original_schema.dig(*path_segments[0..-2]).is_a?(Hash) && original_schema.dig(*path_segments)
|
81
81
|
end
|
82
82
|
|
83
83
|
path_hash = path_segments.reverse.reduce(new_props) { |a, n| { n => a } }
|
@@ -104,38 +104,27 @@ module Schemable
|
|
104
104
|
# @return [Hash] The JSON Schema attribute definition as a Hash or an empty Hash if the attribute does not exist on the model.
|
105
105
|
#
|
106
106
|
# @example
|
107
|
-
# attribute_schema(:title)
|
108
|
-
# # => { "type": "string" }
|
107
|
+
# attribute_schema(:title) => { "type": "string" }
|
109
108
|
def attribute_schema(attribute)
|
110
109
|
# Get the column hash for the attribute
|
111
110
|
column_hash = model.columns_hash[attribute.to_s]
|
112
111
|
|
113
112
|
# Check if this attribute has a custom JSON Schema definition
|
114
|
-
if array_types.keys.include?(attribute)
|
115
|
-
return array_types[attribute]
|
116
|
-
end
|
113
|
+
return array_types[attribute] if array_types.keys.include?(attribute)
|
117
114
|
|
118
|
-
if additional_response_attributes.keys.include?(attribute)
|
119
|
-
return additional_response_attributes[attribute]
|
120
|
-
end
|
115
|
+
return additional_response_attributes[attribute] if additional_response_attributes.keys.include?(attribute)
|
121
116
|
|
122
117
|
# Check if this is an array attribute
|
123
|
-
if column_hash.as_json.try(:[], 'sql_type_metadata').try(:[], 'sql_type').include?('[]')
|
124
|
-
return type_mapper(:array)
|
125
|
-
end
|
118
|
+
return type_mapper(:array) if column_hash.as_json.try(:[], 'sql_type_metadata').try(:[], 'sql_type').include?('[]')
|
126
119
|
|
127
120
|
# Map the column type to a JSON Schema type if none of the above conditions are met
|
128
121
|
response = type_mapper(column_hash.try(:type))
|
129
122
|
|
130
123
|
# If the attribute is nullable, modify the schema accordingly
|
131
|
-
if response && nullable_attributes.include?(attribute)
|
132
|
-
return modify_schema(response, { nullable: true })
|
133
|
-
end
|
124
|
+
return modify_schema(response, { nullable: true }) if response && nullable_attributes.include?(attribute)
|
134
125
|
|
135
126
|
# If attribute is an enum, modify the schema accordingly
|
136
|
-
if response && model.defined_enums.key?(attribute.to_s)
|
137
|
-
return modify_schema(response, { type: :string, enum: model.defined_enums[attribute.to_s].keys })
|
138
|
-
end
|
127
|
+
return modify_schema(response, { type: :string, enum: model.defined_enums[attribute.to_s].keys }) if response && model.defined_enums.key?(attribute.to_s)
|
139
128
|
|
140
129
|
return response unless response.nil?
|
141
130
|
|
@@ -147,7 +136,6 @@ module Schemable
|
|
147
136
|
|
148
137
|
# If we still haven't found a schema type, default to object
|
149
138
|
type_mapper(:object)
|
150
|
-
|
151
139
|
rescue NoMethodError
|
152
140
|
# Log a warning if the attribute does not exist on the model
|
153
141
|
Rails.logger.warn("\e[33mWARNING: #{model} does not have an attribute named \e[31m#{attribute}\e[0m")
|
@@ -159,27 +147,26 @@ module Schemable
|
|
159
147
|
#
|
160
148
|
# @note The `additional_response_attributes` and `excluded_response_attributes` are applied to the schema returned by this method.
|
161
149
|
#
|
162
|
-
# @example
|
163
|
-
# {
|
164
|
-
# type: :object,
|
165
|
-
# properties: {
|
166
|
-
# id: { type: :string },
|
167
|
-
# title: { type: :string }
|
168
|
-
# }
|
169
|
-
# }
|
170
|
-
#
|
171
150
|
# @return [Hash] The JSON Schema for the model's attributes.
|
151
|
+
#
|
152
|
+
# @example
|
153
|
+
# {
|
154
|
+
# type: :object,
|
155
|
+
# properties: {
|
156
|
+
# id: { type: :string },
|
157
|
+
# title: { type: :string }
|
158
|
+
# }
|
159
|
+
# }
|
172
160
|
def attributes_schema
|
173
161
|
schema = {
|
174
162
|
type: :object,
|
175
|
-
properties: attributes.
|
176
|
-
|
177
|
-
props
|
163
|
+
properties: attributes.index_with do |attr|
|
164
|
+
attribute_schema(attr)
|
178
165
|
end
|
179
166
|
}
|
180
167
|
|
181
168
|
# modify the schema to include additional response relations
|
182
|
-
schema = modify_schema(schema, additional_response_attributes,
|
169
|
+
schema = modify_schema(schema, additional_response_attributes, 'properties')
|
183
170
|
|
184
171
|
# modify the schema to exclude response relations
|
185
172
|
excluded_response_attributes.each do |key|
|
@@ -191,35 +178,35 @@ module Schemable
|
|
191
178
|
|
192
179
|
# Generates the schema for the relationships of a resource.
|
193
180
|
#
|
194
|
-
# @param relations [Hash] A hash representing the relationships of the resource in the form of { belongs_to: {}, has_many: {} }.
|
195
|
-
# If not provided, the relationships will be inferred from the model's associations.
|
196
|
-
#
|
197
181
|
# @note The `additional_response_relations` and `excluded_response_relations` are applied to the schema returned by this method.
|
198
182
|
#
|
183
|
+
# @param relations [Hash] A hash representing the relationships of the resource in the form of { belongs_to: {}, has_many: {} }. If not provided, the relationships will be inferred from the model's associations.
|
184
|
+
#
|
199
185
|
# @param expand [Boolean] A boolean indicating whether to expand the relationships in the schema.
|
200
|
-
# @param exclude_from_expansion [Array] An array of relationship names to exclude from expansion.
|
201
186
|
#
|
202
|
-
# @
|
203
|
-
# {
|
204
|
-
# type: :object,
|
205
|
-
# properties: {
|
206
|
-
# province: {
|
207
|
-
# type: :object,
|
208
|
-
# properties: {
|
209
|
-
# meta: {
|
210
|
-
# type: :object,
|
211
|
-
# properties: {
|
212
|
-
# included: {
|
213
|
-
# type: :boolean, default: false
|
214
|
-
# }
|
215
|
-
# }
|
216
|
-
# }
|
217
|
-
# }
|
218
|
-
# }
|
219
|
-
# }
|
220
|
-
# }
|
187
|
+
# @param exclude_from_expansion [Array] An array of relationship names to exclude from expansion.
|
221
188
|
#
|
222
189
|
# @return [Hash] A hash representing the schema for the relationships.
|
190
|
+
#
|
191
|
+
# @example
|
192
|
+
# {
|
193
|
+
# type: :object,
|
194
|
+
# properties: {
|
195
|
+
# province: {
|
196
|
+
# type: :object,
|
197
|
+
# properties: {
|
198
|
+
# meta: {
|
199
|
+
# type: :object,
|
200
|
+
# properties: {
|
201
|
+
# included: {
|
202
|
+
# type: :boolean, default: false
|
203
|
+
# }
|
204
|
+
# }
|
205
|
+
# }
|
206
|
+
# }
|
207
|
+
# }
|
208
|
+
# }
|
209
|
+
# }
|
223
210
|
def relationships_schema(relations = try(:relationships), expand: false, exclude_from_expansion: [])
|
224
211
|
return {} if relations.blank?
|
225
212
|
return {} if relations == { belongs_to: {}, has_many: {} }
|
@@ -242,7 +229,6 @@ module Schemable
|
|
242
229
|
if relation_type == :has_many
|
243
230
|
props.merge!(
|
244
231
|
relation_definitions.keys.index_with do |relationship|
|
245
|
-
|
246
232
|
result = {
|
247
233
|
type: :object,
|
248
234
|
properties: {
|
@@ -267,7 +253,6 @@ module Schemable
|
|
267
253
|
else
|
268
254
|
props.merge!(
|
269
255
|
relation_definitions.keys.index_with do |relationship|
|
270
|
-
|
271
256
|
result = {
|
272
257
|
type: :object,
|
273
258
|
properties: {
|
@@ -292,7 +277,7 @@ module Schemable
|
|
292
277
|
}
|
293
278
|
|
294
279
|
# modify the schema to include additional response relations
|
295
|
-
schema = modify_schema(schema, additional_response_relations,
|
280
|
+
schema = modify_schema(schema, additional_response_relations, 'properties')
|
296
281
|
|
297
282
|
# modify the schema to exclude response relations
|
298
283
|
excluded_response_relations.each do |key|
|
@@ -306,39 +291,41 @@ module Schemable
|
|
306
291
|
#
|
307
292
|
# @note The `additional_response_includes` and `excluded_response_includes` (yet to be implemented) are applied to the schema returned by this method.
|
308
293
|
#
|
309
|
-
# @param relations [Hash] A hash representing the relationships of the resource in the form of { belongs_to: {}, has_many: {} }.
|
310
|
-
#
|
294
|
+
# @param relations [Hash] A hash representing the relationships of the resource in the form of { belongs_to: {}, has_many: {} }. If not provided, the relationships will be inferred from the model's associations.
|
295
|
+
#
|
311
296
|
# @param expand [Boolean] A boolean indicating whether to expand the relationships of the relationships in the schema.
|
297
|
+
#
|
312
298
|
# @param exclude_from_expansion [Array] An array of relationship names to exclude from expansion.
|
313
|
-
# @param metadata [Hash] Additional metadata to include in the schema, usually received from the nested_relationships method sent by the response_schema method.
|
314
299
|
#
|
315
|
-
# @
|
316
|
-
# {
|
317
|
-
# included: {
|
318
|
-
# type: :array,
|
319
|
-
# items: {
|
320
|
-
# anyOf:
|
321
|
-
# [
|
322
|
-
# {
|
323
|
-
# type: :object,
|
324
|
-
# properties: {
|
325
|
-
# type: { type: :string, default: "provinces" },
|
326
|
-
# id: { type: :string },
|
327
|
-
# attributes: {
|
328
|
-
# type: :object,
|
329
|
-
# properties: {
|
330
|
-
# id: { type: :string },
|
331
|
-
# name: { type: :string }
|
332
|
-
# }
|
333
|
-
# }
|
334
|
-
# }
|
335
|
-
# }
|
336
|
-
# ]
|
337
|
-
# }
|
338
|
-
# }
|
339
|
-
# }
|
300
|
+
# @param metadata [Hash] Additional metadata to include in the schema, usually received from the nested_relationships method sent by the response_schema method.
|
340
301
|
#
|
341
302
|
# @return [Hash] A hash representing the schema for the included resources.
|
303
|
+
#
|
304
|
+
# @example
|
305
|
+
# {
|
306
|
+
# included: {
|
307
|
+
# type: :array,
|
308
|
+
# items: {
|
309
|
+
# anyOf:
|
310
|
+
# [
|
311
|
+
# {
|
312
|
+
# type: :object,
|
313
|
+
# properties: {
|
314
|
+
# type: { type: :string, default: "provinces" },
|
315
|
+
# id: { type: :string },
|
316
|
+
# attributes: {
|
317
|
+
# type: :object,
|
318
|
+
# properties: {
|
319
|
+
# id: { type: :string },
|
320
|
+
# name: { type: :string }
|
321
|
+
# }
|
322
|
+
# }
|
323
|
+
# }
|
324
|
+
# }
|
325
|
+
# ]
|
326
|
+
# }
|
327
|
+
# }
|
328
|
+
# }
|
342
329
|
def included_schema(relations = try(:relationships), expand: false, exclude_from_expansion: [], metadata: {})
|
343
330
|
return {} if relations.blank?
|
344
331
|
return {} if relations == { belongs_to: {}, has_many: {} }
|
@@ -348,7 +335,7 @@ module Schemable
|
|
348
335
|
type: :array,
|
349
336
|
items: {
|
350
337
|
anyOf:
|
351
|
-
relations.reduce([]) do |props, (
|
338
|
+
relations.reduce([]) do |props, (_relation_type, relation_definitions)|
|
352
339
|
props + relation_definitions.keys.reduce([]) do |props, relationship|
|
353
340
|
props + [
|
354
341
|
unless exclude_from_expansion.include?(relationship)
|
@@ -358,16 +345,16 @@ module Schemable
|
|
358
345
|
type: { type: :string, default: relation_definitions[relationship].model_name },
|
359
346
|
id: { type: :string },
|
360
347
|
attributes: begin
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
348
|
+
relation_definitions[relationship].new.attributes_schema || {}
|
349
|
+
rescue NoMethodError
|
350
|
+
{}
|
351
|
+
end
|
365
352
|
}.merge(
|
366
353
|
if relation_definitions[relationship].new.relationships != { belongs_to: {}, has_many: {} } || relation_definitions[relationship].new.relationships.blank?
|
367
354
|
if !expand || metadata.blank?
|
368
355
|
{ relationships: relation_definitions[relationship].new.relationships_schema(expand: false) }
|
369
356
|
else
|
370
|
-
{ relationships: relation_definitions[relationship].new.relationships_schema(relations = metadata[:nested_relationships][relationship], expand: true, exclude_from_expansion:
|
357
|
+
{ relationships: relation_definitions[relationship].new.relationships_schema(relations = metadata[:nested_relationships][relationship], expand: true, exclude_from_expansion:) }
|
371
358
|
end
|
372
359
|
else
|
373
360
|
{}
|
@@ -377,36 +364,34 @@ module Schemable
|
|
377
364
|
end
|
378
365
|
].concat(
|
379
366
|
[
|
380
|
-
if expand && metadata.present? &&
|
367
|
+
if expand && metadata.present? && exclude_from_expansion.exclude?(relationship)
|
381
368
|
extra_relations = []
|
382
369
|
metadata[:nested_relationships].keys.reduce({}) do |props, nested_relationship|
|
383
|
-
if metadata[:nested_relationships][relationship].
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
)
|
409
|
-
end
|
370
|
+
next if metadata[:nested_relationships][relationship].blank?
|
371
|
+
|
372
|
+
props.merge!(metadata[:nested_relationships][nested_relationship].keys.each_with_object({}) do |relationship_type, _inner_props|
|
373
|
+
props.merge!(metadata[:nested_relationships][nested_relationship][relationship_type].keys.each_with_object({}) do |relationship, _inner_inner_props|
|
374
|
+
extra_relation_schema = {
|
375
|
+
type: :object,
|
376
|
+
properties: {
|
377
|
+
type: { type: :string, default: metadata[:nested_relationships][nested_relationship][relationship_type][relationship].model_name },
|
378
|
+
id: { type: :string },
|
379
|
+
attributes: metadata[:nested_relationships][nested_relationship][relationship_type][relationship].new.attributes_schema
|
380
|
+
}.merge(
|
381
|
+
if metadata[:nested_relationships][nested_relationship][relationship_type][relationship].new.relationships == { belongs_to: {}, has_many: {} } || metadata[:nested_relationships][nested_relationship][relationship_type][relationship].new.relationships.blank?
|
382
|
+
{}
|
383
|
+
else
|
384
|
+
result = { relationships: metadata[:nested_relationships][nested_relationship][relationship_type][relationship].new.relationships_schema(expand: false) }
|
385
|
+
return {} if result == { relationships: {} }
|
386
|
+
|
387
|
+
result
|
388
|
+
end
|
389
|
+
)
|
390
|
+
}
|
391
|
+
|
392
|
+
extra_relations << extra_relation_schema
|
393
|
+
end)
|
394
|
+
end)
|
410
395
|
end
|
411
396
|
|
412
397
|
extra_relations
|
@@ -419,38 +404,39 @@ module Schemable
|
|
419
404
|
}
|
420
405
|
}
|
421
406
|
|
422
|
-
|
423
|
-
|
424
|
-
schema
|
407
|
+
modify_schema(schema, additional_response_included, 'included.items')
|
425
408
|
end
|
426
409
|
|
427
410
|
# Generates the schema for the response of a resource or collection of resources in JSON API format.
|
428
411
|
#
|
429
|
-
# @param relations [Hash] A hash representing the relationships of the resource in the form of { belongs_to: {}, has_many: {} }.
|
430
|
-
#
|
412
|
+
# @param relations [Hash] A hash representing the relationships of the resource in the form of { belongs_to: {}, has_many: {} }. If not provided, the relationships will be inferred from the model's associations.
|
413
|
+
#
|
431
414
|
# @param expand [Boolean] A boolean indicating whether to expand the relationships of the relationships in the schema.
|
415
|
+
#
|
432
416
|
# @param exclude_from_expansion [Array] An array of relationship names to exclude from expansion.
|
417
|
+
#
|
433
418
|
# @param multi [Boolean] A boolean indicating whether the response contains multiple resources.
|
419
|
+
#
|
434
420
|
# @param nested [Boolean] A boolean indicating whether the response is to be expanded further than the first level of relationships. (expand relationships of relationships)
|
435
|
-
# @param metadata [Hash] Additional metadata to include in the schema, usually received from the nested_relationships method sent by the response_schema method.
|
436
421
|
#
|
437
|
-
# @
|
438
|
-
# The returned schema will have a JSON API format, including the data (included attributes and relationships), included and meta keys.
|
422
|
+
# @param metadata [Hash] Additional metadata to include in the schema, usually received from the nested_relationships method sent by the response_schema method.
|
439
423
|
#
|
440
424
|
# @return [Hash] A hash representing the schema for the response.
|
425
|
+
#
|
426
|
+
# @example
|
427
|
+
# "The returned schema will have a JSON API format, including the data (included attributes and relationships), included and meta keys."
|
441
428
|
def response_schema(relations = try(:relationships), expand: false, exclude_from_expansion: [], multi: false, nested: false, metadata: { nested_relationships: try(:nested_relationships) })
|
442
|
-
|
443
429
|
data = {
|
444
430
|
type: :object,
|
445
431
|
properties: {
|
446
432
|
type: { type: :string, default: itself.class.model_name },
|
447
433
|
id: { type: :string },
|
448
|
-
attributes: attributes_schema
|
434
|
+
attributes: attributes_schema
|
449
435
|
}.merge(
|
450
436
|
if relations.blank? || relations == { belongs_to: {}, has_many: {} }
|
451
437
|
{}
|
452
438
|
else
|
453
|
-
{ relationships: relationships_schema(relations, expand
|
439
|
+
{ relationships: relationships_schema(relations, expand:, exclude_from_expansion:) }
|
454
440
|
end
|
455
441
|
)
|
456
442
|
}
|
@@ -464,26 +450,26 @@ module Schemable
|
|
464
450
|
}
|
465
451
|
else
|
466
452
|
{
|
467
|
-
data:
|
453
|
+
data:
|
468
454
|
}
|
469
455
|
end
|
470
456
|
|
471
457
|
schema.merge!(
|
472
458
|
if nested && expand
|
473
|
-
included_schema(relations, expand: nested, exclude_from_expansion
|
459
|
+
included_schema(relations, expand: nested, exclude_from_expansion:, metadata:)
|
474
460
|
elsif !nested && expand
|
475
|
-
included_schema(relations, expand: nested, exclude_from_expansion:
|
461
|
+
included_schema(relations, expand: nested, exclude_from_expansion:)
|
476
462
|
else
|
477
463
|
{}
|
478
464
|
end
|
479
465
|
).merge!(
|
480
|
-
if
|
481
|
-
{ meta: meta }
|
482
|
-
else
|
466
|
+
if expand
|
483
467
|
{}
|
468
|
+
else
|
469
|
+
{ meta: }
|
484
470
|
end
|
485
471
|
).merge!(
|
486
|
-
jsonapi:
|
472
|
+
jsonapi:
|
487
473
|
)
|
488
474
|
|
489
475
|
{
|
@@ -492,29 +478,72 @@ module Schemable
|
|
492
478
|
}
|
493
479
|
end
|
494
480
|
|
495
|
-
# Generates the schema for the request payload of a resource.
|
481
|
+
# Generates the schema for the creation request payload of a resource.
|
496
482
|
#
|
497
|
-
# @note The `
|
483
|
+
# @note The `additional_create_request_attributes` and `excluded_create_request_attributes` applied to the returned schema by this method.
|
498
484
|
# @note The `required_attributes` are applied to the returned schema by this method.
|
499
485
|
# @note The `nullable_attributes` are applied to the returned schema by this method.
|
500
486
|
#
|
487
|
+
# @return [Hash] A hash representing the schema for the request payload.
|
488
|
+
#
|
501
489
|
# @example
|
502
|
-
#
|
503
|
-
#
|
504
|
-
#
|
505
|
-
#
|
506
|
-
#
|
507
|
-
#
|
508
|
-
#
|
509
|
-
#
|
510
|
-
#
|
511
|
-
#
|
512
|
-
#
|
513
|
-
#
|
514
|
-
#
|
490
|
+
# {
|
491
|
+
# type: :object,
|
492
|
+
# properties: {
|
493
|
+
# data: {
|
494
|
+
# type: :object,
|
495
|
+
# properties: {
|
496
|
+
# firstName: { type: :string },
|
497
|
+
# lastName: { type: :string }
|
498
|
+
# },
|
499
|
+
# required: [:firstName, :lastName]
|
500
|
+
# }
|
501
|
+
# }
|
502
|
+
# }
|
503
|
+
def create_request_schema
|
504
|
+
schema = {
|
505
|
+
type: :object,
|
506
|
+
properties: {
|
507
|
+
data: attributes_schema
|
508
|
+
}
|
509
|
+
}
|
510
|
+
|
511
|
+
schema = modify_schema(schema, additional_create_request_attributes, 'properties.data.properties')
|
512
|
+
|
513
|
+
excluded_create_request_attributes.each do |key|
|
514
|
+
schema = modify_schema(schema, {}, "properties.data.properties.#{key}", delete: true)
|
515
|
+
end
|
516
|
+
|
517
|
+
required_attributes = {
|
518
|
+
required: (schema.as_json['properties']['data']['properties'].keys - optional_create_request_attributes.map(&:to_s) - nullable_attributes.map(&:to_s)).map { |key| key.to_s.camelize(:lower).to_sym }
|
519
|
+
}
|
520
|
+
|
521
|
+
modify_schema(schema, required_attributes, 'properties.data')
|
522
|
+
end
|
523
|
+
|
524
|
+
# Generates the schema for the update request payload of a resource.
|
525
|
+
#
|
526
|
+
# @note The `additional_update_request_attributes` and `excluded_update_request_attributes` applied to the returned schema by this method.
|
527
|
+
# @note The `required_attributes` are applied to the returned schema by this method.
|
528
|
+
# @note The `nullable_attributes` are applied to the returned schema by this method.
|
515
529
|
#
|
516
530
|
# @return [Hash] A hash representing the schema for the request payload.
|
517
|
-
|
531
|
+
#
|
532
|
+
# @example
|
533
|
+
# {
|
534
|
+
# type: :object,
|
535
|
+
# properties: {
|
536
|
+
# data: {
|
537
|
+
# type: :object,
|
538
|
+
# properties: {
|
539
|
+
# firstName: { type: :string },
|
540
|
+
# lastName: { type: :string }
|
541
|
+
# },
|
542
|
+
# required: [:firstName, :lastName]
|
543
|
+
# }
|
544
|
+
# }
|
545
|
+
# }
|
546
|
+
def update_request_schema
|
518
547
|
schema = {
|
519
548
|
type: :object,
|
520
549
|
properties: {
|
@@ -522,27 +551,23 @@ module Schemable
|
|
522
551
|
}
|
523
552
|
}
|
524
553
|
|
525
|
-
schema = modify_schema(schema,
|
554
|
+
schema = modify_schema(schema, additional_update_request_attributes, 'properties.data.properties')
|
526
555
|
|
527
|
-
|
556
|
+
excluded_update_request_attributes.each do |key|
|
528
557
|
schema = modify_schema(schema, {}, "properties.data.properties.#{key}", delete: true)
|
529
558
|
end
|
530
559
|
|
531
560
|
required_attributes = {
|
532
|
-
required: schema.as_json['properties']['data']['properties'].keys -
|
561
|
+
required: (schema.as_json['properties']['data']['properties'].keys - optional_update_request_attributes.map(&:to_s) - nullable_attributes.map(&:to_s)).map { |key| key.to_s.camelize(:lower).to_sym }
|
533
562
|
}
|
534
563
|
|
535
|
-
|
536
|
-
|
537
|
-
schema
|
564
|
+
modify_schema(schema, required_attributes, 'properties.data')
|
538
565
|
end
|
539
566
|
|
540
567
|
# Returns the schema for the meta data of the response body.
|
541
|
-
#
|
542
568
|
# This is used to provide pagination information usually (in the case of a collection).
|
543
569
|
#
|
544
|
-
# Note that this is an opinionated schema and may not be suitable for all use cases.
|
545
|
-
# If you need to override this schema, you can do so by overriding the `meta` method in your definition.
|
570
|
+
# @note Note that this is an opinionated schema and may not be suitable for all use cases. If you need to override this schema, you can do so by overriding the `meta` method in your definition.
|
546
571
|
#
|
547
572
|
# @return [Hash] The schema for the meta data of the response body.
|
548
573
|
def meta
|
@@ -583,7 +608,7 @@ module Schemable
|
|
583
608
|
properties: {
|
584
609
|
version: {
|
585
610
|
type: :string,
|
586
|
-
default:
|
611
|
+
default: '1.0'
|
587
612
|
}
|
588
613
|
}
|
589
614
|
}
|
@@ -591,179 +616,213 @@ module Schemable
|
|
591
616
|
|
592
617
|
# Returns the resource serializer to be used for serialization. This method must be implemented in the definition class.
|
593
618
|
#
|
619
|
+
# @abstract This method must be implemented in the definition class.
|
620
|
+
#
|
594
621
|
# @raise [NotImplementedError] If the method is not implemented in the definition class.
|
595
622
|
#
|
596
|
-
# @
|
623
|
+
# @return [Class] The resource serializer class.
|
597
624
|
#
|
598
|
-
# @
|
625
|
+
# @example
|
626
|
+
# V1::UserSerializer
|
599
627
|
#
|
600
|
-
# @return [Class] The resource serializer class.
|
601
628
|
def serializer
|
602
629
|
raise NotImplementedError, 'serializer method must be implemented in the definition class'
|
603
630
|
end
|
604
631
|
|
605
632
|
# Returns the attributes defined in the serializer (Auto generated from the serializer).
|
606
633
|
#
|
607
|
-
# @example
|
608
|
-
# [:id, :name, :email, :created_at, :updated_at]
|
609
|
-
#
|
610
634
|
# @return [Array<Symbol>, nil] The attributes defined in the serializer or nil if there are none.
|
635
|
+
#
|
636
|
+
# @example
|
637
|
+
# [:id, :name, :email, :created_at, :updated_at]
|
611
638
|
def attributes
|
612
639
|
serializer.attribute_blocks.transform_keys { |key| key.to_s.underscore.to_sym }.keys || nil
|
613
640
|
end
|
614
641
|
|
615
642
|
# Returns the relationships defined in the serializer.
|
616
643
|
#
|
617
|
-
#
|
644
|
+
# @return [Hash] The relationships defined in the serializer.
|
618
645
|
#
|
619
|
-
# @
|
620
|
-
# {
|
621
|
-
# belongs_to: {
|
622
|
-
# district: Swagger::Definitions::District,
|
623
|
-
# user: Swagger::Definitions::User
|
624
|
-
# },
|
625
|
-
# has_many: {
|
626
|
-
# applicants: Swagger::Definitions::Applicant,
|
627
|
-
# }
|
628
|
-
# }
|
646
|
+
# @note Note that the format of the relationships is as follows:
|
647
|
+
# { belongs_to: { relationship_name: relationship_definition }, has_many: { relationship_name: relationship_definition }
|
629
648
|
#
|
630
|
-
# @
|
649
|
+
# @example
|
650
|
+
# {
|
651
|
+
# belongs_to: {
|
652
|
+
# district: Swagger::Definitions::District,
|
653
|
+
# user: Swagger::Definitions::User
|
654
|
+
# },
|
655
|
+
# has_many: {
|
656
|
+
# applicants: Swagger::Definitions::Applicant,
|
657
|
+
# }
|
658
|
+
# }
|
631
659
|
def relationships
|
632
660
|
{ belongs_to: {}, has_many: {} }
|
633
661
|
end
|
634
662
|
|
635
663
|
# Returns a hash of all the arrays defined for the model. The schema for each array is defined in the definition class manually.
|
636
|
-
#
|
637
664
|
# This method must be implemented in the definition class if there are any arrays.
|
638
665
|
#
|
639
|
-
# @example
|
640
|
-
# {
|
641
|
-
# metadata: {
|
642
|
-
# type: :array,
|
643
|
-
# items: {
|
644
|
-
# type: :object, nullable: true,
|
645
|
-
# properties: { name: { type: :string, nullable: true } }
|
646
|
-
# }
|
647
|
-
# }
|
648
|
-
# }
|
649
|
-
#
|
650
666
|
# @return [Hash] The arrays of the model and their schemas.
|
667
|
+
#
|
668
|
+
# @example
|
669
|
+
# {
|
670
|
+
# metadata: {
|
671
|
+
# type: :array,
|
672
|
+
# items: {
|
673
|
+
# type: :object, nullable: true,
|
674
|
+
# properties: { name: { type: :string, nullable: true } }
|
675
|
+
# }
|
676
|
+
# }
|
677
|
+
# }
|
651
678
|
def array_types
|
652
679
|
{}
|
653
680
|
end
|
654
681
|
|
655
|
-
# Returns the attributes that are optional in the request body. This means that they are not required to be present in the request body thus they are taken out of the required array.
|
682
|
+
# Returns the attributes that are optional in the create request body. This means that they are not required to be present in the create request body thus they are taken out of the required array.
|
656
683
|
#
|
657
|
-
# @
|
658
|
-
# [:name, :email]
|
684
|
+
# @return [Array<Symbol>] The attributes that are optional in the create request body.
|
659
685
|
#
|
660
|
-
# @
|
661
|
-
|
686
|
+
# @example
|
687
|
+
# [:name, :email]
|
688
|
+
def optional_create_request_attributes
|
662
689
|
%i[]
|
663
690
|
end
|
664
691
|
|
665
|
-
# Returns the attributes that are
|
692
|
+
# Returns the attributes that are optional in the update request body. This means that they are not required to be present in the update request body thus they are taken out of the required array.
|
666
693
|
#
|
667
|
-
#
|
694
|
+
# @return [Array<Symbol>] The attributes that are optional in the update request body.
|
668
695
|
#
|
669
696
|
# @example
|
670
|
-
#
|
697
|
+
# [:name, :email]
|
698
|
+
def optional_update_request_attributes
|
699
|
+
%i[]
|
700
|
+
end
|
701
|
+
|
702
|
+
# Returns the attributes that are nullable in the request/response body. This means that they can be present in the request/response body but they can be null.
|
703
|
+
# They are not required to be present in the request body.
|
671
704
|
#
|
672
705
|
# @return [Array<Symbol>] The attributes that are nullable in the request/response body.
|
706
|
+
#
|
707
|
+
# @example
|
708
|
+
# [:name, :email]
|
673
709
|
def nullable_attributes
|
674
710
|
%i[]
|
675
711
|
end
|
676
712
|
|
677
|
-
# Returns the additional request attributes that are not automatically generated. These attributes are appended to the request schema.
|
713
|
+
# Returns the additional create request attributes that are not automatically generated. These attributes are appended to the create request schema.
|
678
714
|
#
|
679
|
-
# @
|
680
|
-
# {
|
681
|
-
# name: { type: :string }
|
682
|
-
# }
|
715
|
+
# @return [Hash] The additional create request attributes that are not automatically generated (if any).
|
683
716
|
#
|
684
|
-
# @
|
685
|
-
|
717
|
+
# @example
|
718
|
+
# {
|
719
|
+
# name: { type: :string }
|
720
|
+
# }
|
721
|
+
def additional_create_request_attributes
|
686
722
|
{}
|
687
723
|
end
|
688
724
|
|
689
|
-
# Returns the additional
|
725
|
+
# Returns the additional update request attributes that are not automatically generated. These attributes are appended to the update request schema.
|
726
|
+
#
|
727
|
+
# @return [Hash] The additional update request attributes that are not automatically generated (if any).
|
690
728
|
#
|
691
729
|
# @example
|
692
|
-
#
|
693
|
-
#
|
694
|
-
#
|
730
|
+
# {
|
731
|
+
# name: { type: :string }
|
732
|
+
# }
|
733
|
+
def additional_update_request_attributes
|
734
|
+
{}
|
735
|
+
end
|
736
|
+
|
737
|
+
# Returns the additional response attributes that are not automatically generated. These attributes are appended to the response schema.
|
695
738
|
#
|
696
739
|
# @return [Hash] The additional response attributes that are not automatically generated (if any).
|
740
|
+
#
|
741
|
+
# @example
|
742
|
+
# {
|
743
|
+
# name: { type: :string }
|
744
|
+
# }
|
697
745
|
def additional_response_attributes
|
698
746
|
{}
|
699
747
|
end
|
700
748
|
|
701
749
|
# Returns the additional response relations that are not automatically generated. These relations are appended to the response schema's relationships.
|
702
750
|
#
|
703
|
-
# @example
|
704
|
-
# {
|
705
|
-
# users: {
|
706
|
-
# type: :object,
|
707
|
-
# properties: {
|
708
|
-
# data: {
|
709
|
-
# type: :array,
|
710
|
-
# items: {
|
711
|
-
# type: :object,
|
712
|
-
# properties: {
|
713
|
-
# id: { type: :string },
|
714
|
-
# type: { type: :string }
|
715
|
-
# }
|
716
|
-
# }
|
717
|
-
# }
|
718
|
-
# }
|
719
|
-
# }
|
720
|
-
# }
|
721
|
-
#
|
722
751
|
# @return [Hash] The additional response relations that are not automatically generated (if any).
|
752
|
+
#
|
753
|
+
# @example
|
754
|
+
# {
|
755
|
+
# users: {
|
756
|
+
# type: :object,
|
757
|
+
# properties: {
|
758
|
+
# data: {
|
759
|
+
# type: :array,
|
760
|
+
# items: {
|
761
|
+
# type: :object,
|
762
|
+
# properties: {
|
763
|
+
# id: { type: :string },
|
764
|
+
# type: { type: :string }
|
765
|
+
# }
|
766
|
+
# }
|
767
|
+
# }
|
768
|
+
# }
|
769
|
+
# }
|
770
|
+
# }
|
723
771
|
def additional_response_relations
|
724
772
|
{}
|
725
773
|
end
|
726
774
|
|
727
775
|
# Returns the additional response included that are not automatically generated. These included are appended to the response schema's included.
|
728
776
|
#
|
729
|
-
# @example
|
730
|
-
# {
|
731
|
-
# type: :object,
|
732
|
-
# properties: {
|
733
|
-
# id: { type: :string },
|
734
|
-
# type: { type: :string },
|
735
|
-
# attributes: {
|
736
|
-
# type: :object,
|
737
|
-
# properties: {
|
738
|
-
# name: { type: :string }
|
739
|
-
# }
|
740
|
-
# }
|
741
|
-
# }
|
742
|
-
# }
|
743
|
-
#
|
744
777
|
# @return [Hash] The additional response included that are not automatically generated (if any).
|
778
|
+
#
|
779
|
+
# @example
|
780
|
+
# {
|
781
|
+
# type: :object,
|
782
|
+
# properties: {
|
783
|
+
# id: { type: :string },
|
784
|
+
# type: { type: :string },
|
785
|
+
# attributes: {
|
786
|
+
# type: :object,
|
787
|
+
# properties: {
|
788
|
+
# name: { type: :string }
|
789
|
+
# }
|
790
|
+
# }
|
791
|
+
# }
|
792
|
+
# }
|
745
793
|
def additional_response_included
|
746
794
|
{}
|
747
795
|
end
|
748
796
|
|
749
|
-
# Returns the attributes that are excluded from the request schema.
|
750
|
-
# These attributes are not required or not needed to be present in the request body.
|
797
|
+
# Returns the attributes that are excluded from the create request schema.
|
798
|
+
# These attributes are not required or not needed to be present in the create request body.
|
799
|
+
#
|
800
|
+
# @return [Array<Symbol>] The attributes that are excluded from the create request schema.
|
751
801
|
#
|
752
802
|
# @example
|
753
|
-
#
|
803
|
+
# [:id, :updated_at, :created_at]
|
804
|
+
def excluded_create_request_attributes
|
805
|
+
%i[]
|
806
|
+
end
|
807
|
+
|
808
|
+
# Returns the attributes that are excluded from the update request schema.
|
809
|
+
# These attributes are not required or not needed to be present in the update request body.
|
754
810
|
#
|
755
|
-
# @return [Array<Symbol>] The attributes that are excluded from the request schema.
|
756
|
-
|
811
|
+
# @return [Array<Symbol>] The attributes that are excluded from the update request schema.
|
812
|
+
#
|
813
|
+
# @example
|
814
|
+
# [:id, :updated_at, :created_at]
|
815
|
+
def excluded_update_request_attributes
|
757
816
|
%i[]
|
758
817
|
end
|
759
818
|
|
760
819
|
# Returns the attributes that are excluded from the response schema.
|
761
820
|
# These attributes are not needed to be present in the response body.
|
762
821
|
#
|
763
|
-
# @example
|
764
|
-
# [:id, :updated_at, :created_at]
|
765
|
-
#
|
766
822
|
# @return [Array<Symbol>] The attributes that are excluded from the response schema.
|
823
|
+
#
|
824
|
+
# @example
|
825
|
+
# [:id, :updated_at, :created_at]
|
767
826
|
def excluded_response_attributes
|
768
827
|
%i[]
|
769
828
|
end
|
@@ -771,10 +830,10 @@ module Schemable
|
|
771
830
|
# Returns the relationships that are excluded from the response schema.
|
772
831
|
# These relationships are not needed to be present in the response body.
|
773
832
|
#
|
774
|
-
# @example
|
775
|
-
# [:users, :applicants]
|
776
|
-
#
|
777
833
|
# @return [Array<Symbol>] The relationships that are excluded from the response schema.
|
834
|
+
#
|
835
|
+
# @example
|
836
|
+
# [:users, :applicants]
|
778
837
|
def excluded_response_relations
|
779
838
|
%i[]
|
780
839
|
end
|
@@ -782,73 +841,81 @@ module Schemable
|
|
782
841
|
# Returns the included that are excluded from the response schema.
|
783
842
|
# These included are not needed to be present in the response body.
|
784
843
|
#
|
785
|
-
# @
|
844
|
+
# @return [Array<Symbol>] The included that are excluded from the response schema.
|
786
845
|
#
|
787
846
|
# @example
|
788
|
-
#
|
847
|
+
# [:users, :applicants]
|
789
848
|
#
|
790
|
-
# @
|
849
|
+
# @todo
|
850
|
+
# This method is not used anywhere yet.
|
791
851
|
def excluded_response_included
|
792
852
|
%i[]
|
793
853
|
end
|
794
854
|
|
795
855
|
# Returns the relationships to be further expanded in the response schema.
|
796
856
|
#
|
797
|
-
# @example
|
798
|
-
# {
|
799
|
-
# applicants: {
|
800
|
-
# belongs_to: {
|
801
|
-
# district: Swagger::Definitions::District,
|
802
|
-
# province: Swagger::Definitions::Province,
|
803
|
-
# },
|
804
|
-
# has_many: {
|
805
|
-
# attachments: Swagger::Definitions::Upload,
|
806
|
-
# }
|
807
|
-
# }
|
808
|
-
# }
|
809
|
-
#
|
810
857
|
# @return [Hash] The relationships to be further expanded in the response schema.
|
858
|
+
#
|
859
|
+
# @example
|
860
|
+
# {
|
861
|
+
# applicants: {
|
862
|
+
# belongs_to: {
|
863
|
+
# district: Swagger::Definitions::District,
|
864
|
+
# province: Swagger::Definitions::Province,
|
865
|
+
# },
|
866
|
+
# has_many: {
|
867
|
+
# attachments: Swagger::Definitions::Upload,
|
868
|
+
# }
|
869
|
+
# }
|
870
|
+
# }
|
811
871
|
def nested_relationships
|
812
872
|
{}
|
813
873
|
end
|
814
874
|
|
815
875
|
# Returns the model class (Constantized from the definition class name)
|
816
876
|
#
|
817
|
-
# @example
|
818
|
-
# User
|
819
|
-
#
|
820
877
|
# @return [Class] The model class (Constantized from the definition class name)
|
878
|
+
#
|
879
|
+
# @example
|
880
|
+
# User
|
821
881
|
def model
|
822
|
-
self.class.name.gsub(
|
882
|
+
self.class.name.gsub('Swagger::Definitions::', '').constantize
|
823
883
|
end
|
824
884
|
|
825
885
|
# Returns the model name. Used for schema type naming.
|
826
886
|
#
|
827
|
-
# @example
|
828
|
-
# 'users' for the User model
|
829
|
-
# 'citizen_applications' for the CitizenApplication model
|
830
|
-
#
|
831
887
|
# @return [String] The model name.
|
888
|
+
#
|
889
|
+
# @example
|
890
|
+
# 'users' for the User model
|
891
|
+
# 'citizen_applications' for the CitizenApplication model
|
832
892
|
def self.model_name
|
833
|
-
name.gsub(
|
893
|
+
name.gsub('Swagger::Definitions::', '').pluralize.underscore.downcase
|
834
894
|
end
|
835
895
|
|
836
896
|
# Returns the generated schemas in JSONAPI format that are used in the swagger documentation.
|
837
897
|
#
|
838
|
-
# @
|
839
|
-
#
|
840
|
-
#
|
841
|
-
#
|
898
|
+
# @return [Array<Hash>] The generated schemas in JSONAPI format that are used in the swagger documentation.
|
899
|
+
#
|
900
|
+
# @note This method is used for generating schema in 4 different formats: request (both create and update), response and response expanded.
|
901
|
+
#
|
902
|
+
# @option CreateRequest
|
903
|
+
# is the schema for the creation request body.
|
904
|
+
# @option UpdateRequest
|
905
|
+
# is the schema for the updating request body.
|
906
|
+
# @option Response
|
907
|
+
# is the schema for the response body (without any relationships expanded), used for collection responses.
|
908
|
+
# @option ResponseExpanded: The schema for the response body with all the relationships expanded, used for single resource responses.
|
842
909
|
#
|
843
910
|
# @note The returned schemas are in JSONAPI format are usually appended to the rswag component's 'schemas' in swagger_helper.
|
844
911
|
#
|
845
912
|
# @note The method can be overridden in the definition class if there are any additional customizations needed.
|
846
913
|
#
|
847
|
-
# @return [Array<Hash>] The generated schemas in JSONAPI format that are used in the swagger documentation.
|
848
914
|
def self.definitions
|
849
|
-
schema_instance =
|
915
|
+
schema_instance = new
|
850
916
|
[
|
851
|
-
"#{schema_instance.model}
|
917
|
+
"#{schema_instance.model}CreateRequest": schema_instance.camelize_keys(schema_instance.create_request_schema),
|
918
|
+
"#{schema_instance.model}UpdateRequest": schema_instance.camelize_keys(schema_instance.update_request_schema),
|
852
919
|
"#{schema_instance.model}Response": schema_instance.camelize_keys(schema_instance.response_schema(multi: true)),
|
853
920
|
"#{schema_instance.model}ResponseExpanded": schema_instance.camelize_keys(schema_instance.response_schema(expand: true))
|
854
921
|
]
|
@@ -858,10 +925,10 @@ module Schemable
|
|
858
925
|
#
|
859
926
|
# @param hash [Array | Hash] The hash with all the keys camelized.
|
860
927
|
#
|
861
|
-
# @example
|
862
|
-
# { first_name: 'John', last_name: 'Doe' } => { firstName: 'John', lastName: 'Doe' }
|
863
|
-
#
|
864
928
|
# @return [Array | Hash] The hash with all the keys camelized.
|
929
|
+
#
|
930
|
+
# @example
|
931
|
+
# { first_name: 'John', last_name: 'Doe' } => { firstName: 'John', lastName: 'Doe' }
|
865
932
|
def camelize_keys(hash)
|
866
933
|
hash.deep_transform_keys { |key| key.to_s.camelize(:lower).to_sym }
|
867
934
|
end
|