jsapi 0.5.0 → 0.6.1

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jsapi/controller/methods.rb +39 -13
  3. data/lib/jsapi/controller/parameters.rb +25 -23
  4. data/lib/jsapi/controller/response.rb +35 -22
  5. data/lib/jsapi/dsl/class_methods.rb +18 -10
  6. data/lib/jsapi/dsl/definitions.rb +11 -0
  7. data/lib/jsapi/dsl/openapi/callbacks.rb +34 -0
  8. data/lib/jsapi/dsl/openapi/examples.rb +32 -0
  9. data/lib/jsapi/dsl/openapi.rb +2 -0
  10. data/lib/jsapi/dsl/operation.rb +1 -1
  11. data/lib/jsapi/dsl/parameter.rb +1 -1
  12. data/lib/jsapi/dsl/request_body.rb +1 -1
  13. data/lib/jsapi/dsl/response.rb +1 -1
  14. data/lib/jsapi/dsl.rb +1 -3
  15. data/lib/jsapi/helpers/invalid_value_helper.rb +17 -0
  16. data/lib/jsapi/invalid_argument_error.rb +12 -0
  17. data/lib/jsapi/invalid_value_error.rb +12 -0
  18. data/lib/jsapi/json/object.rb +15 -14
  19. data/lib/jsapi/json.rb +1 -1
  20. data/lib/jsapi/meta/{attributes/class_methods.rb → base/attributes.rb} +2 -2
  21. data/lib/jsapi/meta/base/model.rb +44 -0
  22. data/lib/jsapi/meta/base/reference.rb +36 -0
  23. data/lib/jsapi/meta/{attributes → base}/type_caster.rb +2 -2
  24. data/lib/jsapi/meta/base.rb +4 -40
  25. data/lib/jsapi/meta/callable/symbol_evaluator.rb +30 -0
  26. data/lib/jsapi/meta/callable/symbol_sequence_evaluator.rb +29 -0
  27. data/lib/jsapi/meta/callable.rb +28 -0
  28. data/lib/jsapi/meta/defaults.rb +28 -0
  29. data/lib/jsapi/meta/definitions.rb +35 -29
  30. data/lib/jsapi/meta/openapi/callback/model.rb +1 -1
  31. data/lib/jsapi/meta/openapi/callback/reference.rb +1 -1
  32. data/lib/jsapi/meta/openapi/contact.rb +1 -1
  33. data/lib/jsapi/meta/openapi/example/model.rb +1 -1
  34. data/lib/jsapi/meta/openapi/example/reference.rb +1 -1
  35. data/lib/jsapi/meta/openapi/external_documentation.rb +1 -1
  36. data/lib/jsapi/meta/openapi/header/model.rb +17 -2
  37. data/lib/jsapi/meta/openapi/header/reference.rb +1 -1
  38. data/lib/jsapi/meta/openapi/info.rb +1 -1
  39. data/lib/jsapi/meta/openapi/license.rb +1 -1
  40. data/lib/jsapi/meta/openapi/link/model.rb +1 -1
  41. data/lib/jsapi/meta/openapi/link/reference.rb +1 -1
  42. data/lib/jsapi/meta/openapi/oauth_flow.rb +2 -2
  43. data/lib/jsapi/meta/openapi/root.rb +6 -20
  44. data/lib/jsapi/meta/openapi/security_requirement.rb +2 -2
  45. data/lib/jsapi/meta/openapi/security_scheme/base.rb +1 -1
  46. data/lib/jsapi/meta/openapi/security_scheme.rb +1 -1
  47. data/lib/jsapi/meta/openapi/server.rb +1 -1
  48. data/lib/jsapi/meta/openapi/server_variable.rb +1 -1
  49. data/lib/jsapi/meta/openapi/tag.rb +1 -1
  50. data/lib/jsapi/meta/operation.rb +21 -24
  51. data/lib/jsapi/meta/parameter/model.rb +4 -3
  52. data/lib/jsapi/meta/parameter/reference.rb +1 -1
  53. data/lib/jsapi/meta/property.rb +9 -3
  54. data/lib/jsapi/meta/request_body/model.rb +8 -3
  55. data/lib/jsapi/meta/request_body/reference.rb +1 -1
  56. data/lib/jsapi/meta/response/model.rb +9 -4
  57. data/lib/jsapi/meta/response/reference.rb +1 -1
  58. data/lib/jsapi/meta/schema/additional_properties.rb +5 -6
  59. data/lib/jsapi/meta/schema/base.rb +13 -7
  60. data/lib/jsapi/meta/schema/discriminator.rb +1 -9
  61. data/lib/jsapi/meta/schema/object.rb +27 -4
  62. data/lib/jsapi/meta/schema/reference.rb +1 -1
  63. data/lib/jsapi/meta/schema.rb +12 -5
  64. data/lib/jsapi/meta.rb +3 -5
  65. data/lib/jsapi/model/attributes.rb +10 -4
  66. data/lib/jsapi/model/base.rb +1 -1
  67. data/lib/jsapi/model/nestable.rb +25 -10
  68. data/lib/jsapi/version.rb +1 -1
  69. data/lib/jsapi.rb +4 -0
  70. metadata +15 -11
  71. data/lib/jsapi/dsl/callbacks.rb +0 -32
  72. data/lib/jsapi/dsl/examples.rb +0 -30
  73. data/lib/jsapi/meta/attributes.rb +0 -4
  74. data/lib/jsapi/meta/base_reference.rb +0 -34
  75. data/lib/jsapi/meta/invalid_argument_error.rb +0 -12
  76. data/lib/jsapi/meta/method_chain.rb +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 162f63ee5ef06ba76a2acb100e92928144533e8d2486175b95cf4f8a38d6f93d
4
- data.tar.gz: bf6579a80a1bdc8eb2ab3ca7921f42f1a68466508425568e3c5b984e7e1b34b8
3
+ metadata.gz: cb2e35d1d98201647ee5ec6087437891fc7781e94c717804275a6ed1ee870267
4
+ data.tar.gz: 1295f4128a5e096e64be1243f532ada34a58032860b87515836697ee48c7a51f
5
5
  SHA512:
6
- metadata.gz: 71c6b38cb010530b4b6f4cfebee131981c2874114bf663287739452f709863e64e073b358dded464ee86d2d14ce68439170e15c709667d1098a804f874728cd3
7
- data.tar.gz: 8e60c31c91af85df15c2bb9c2c0a17fa67599df3621c90603bbe624615a6749e3a909b1a8e91cb5ea5a7aab8d75ee03adaf32ea28e4abd95d30bc7fd1cadd754
6
+ metadata.gz: 0f826bdf8be20affd8181feaf0f507705cf87ab9960711e1715dd4b2a7abb6ba072654532e99a7701359b8a38685f80c19aa39be1e0538f27befd460a8c8c74c
7
+ data.tar.gz: fbd3593855e17a5e6621e572ed292073d5849f802dc39febbb20d59e0f2a3133118cbc1c84413f8cfbd4a17047d28b5989a476abe8904f6a0c2f8390abda4dbf
@@ -13,9 +13,9 @@ module Jsapi
13
13
  end
14
14
 
15
15
  # Performs an API operation by calling the given block. The request parameters are
16
- # passed as an instance of the operation's model class to the block. Parameter names
17
- # are converted to snake case. The object returned by the block is implicitly rendered
18
- # according to the appropriate +response+ specification.
16
+ # passed as an instance of the operation's model class to the block. The object
17
+ # returned by the block is implicitly rendered according to the appropriate +response+
18
+ # specification.
19
19
  #
20
20
  # api_operation('foo') do |api_params|
21
21
  # # ...
@@ -23,13 +23,22 @@ module Jsapi
23
23
  #
24
24
  # +operation_name+ can be +nil+ if the controller handles one operation only.
25
25
  #
26
- # If +strong+ is +true+, parameters that can be mapped are accepted only. That means
26
+ # If +:strong+ is +true+, parameters that can be mapped are accepted only. That means
27
27
  # that the model passed to the block is invalid if there are any request parameters
28
28
  # that can't be mapped to a parameter or a request body property of the operation.
29
29
  #
30
- def api_operation(operation_name = nil, status: nil, strong: false, &block)
30
+ # The +:omit+ option specifies on which conditions properties are omitted.
31
+ # Possible values are:
32
+ #
33
+ # - +:empty+ - All of the properties whose value is empty are omitted.
34
+ # - +:nil+ - All of the properties whose value is +nil+ are omitted.
35
+ #
36
+ # Raises an InvalidArgumentError when the value of +:omit+ is invalid.
37
+ def api_operation(operation_name = nil, omit: nil, status: nil, strong: false, &block)
31
38
  _perform_api_operation(
32
- operation_name, false,
39
+ operation_name,
40
+ bang: false,
41
+ omit: omit,
33
42
  status: status,
34
43
  strong: strong,
35
44
  &block
@@ -43,9 +52,11 @@ module Jsapi
43
52
  # # ...
44
53
  # end
45
54
  #
46
- def api_operation!(operation_name = nil, status: nil, strong: false, &block)
55
+ def api_operation!(operation_name = nil, omit: nil, status: nil, strong: false, &block)
47
56
  _perform_api_operation(
48
- operation_name, true,
57
+ operation_name,
58
+ bang: true,
59
+ omit: omit,
49
60
  status: status,
50
61
  strong: strong,
51
62
  &block
@@ -79,12 +90,20 @@ module Jsapi
79
90
  # render(json: api_response(bar, 'foo', status: 200))
80
91
  #
81
92
  # +operation_name+ can be +nil+ if the controller handles one operation only.
82
- def api_response(result, operation_name = nil, status: nil)
93
+ #
94
+ # The +:omit+ option specifies on which conditions properties are omitted.
95
+ # Possible values are:
96
+ #
97
+ # - +:empty+ - All of the properties whose value is empty are omitted.
98
+ # - +:nil+ - All of the properties whose value is +nil+ are omitted.
99
+ #
100
+ # Raises an InvalidArgumentError when the value of +:omit+ is invalid.
101
+ def api_response(result, operation_name = nil, omit: nil, status: nil)
83
102
  definitions = api_definitions
84
103
  operation = _api_operation(operation_name, definitions)
85
104
  response = _api_response(operation, status, definitions)
86
105
 
87
- Response.new(result, response, api_definitions)
106
+ Response.new(result, response, api_definitions, omit: omit)
88
107
  end
89
108
 
90
109
  private
@@ -98,7 +117,13 @@ module Jsapi
98
117
 
99
118
  def _api_params(operation, definitions, strong:)
100
119
  (operation.model || Model::Base).new(
101
- Parameters.new(params, operation, definitions, strong: strong)
120
+ Parameters.new(
121
+ params.except(:action, :controller, :format).permit!,
122
+ headers,
123
+ operation,
124
+ definitions,
125
+ strong: strong
126
+ )
102
127
  )
103
128
  end
104
129
 
@@ -109,7 +134,7 @@ module Jsapi
109
134
  raise "status code not defined: #{status}"
110
135
  end
111
136
 
112
- def _perform_api_operation(operation_name, bang, status:, strong:, &block)
137
+ def _perform_api_operation(operation_name, bang:, omit:, status:, strong:, &block)
113
138
  definitions = api_definitions
114
139
  operation = _api_operation(operation_name, definitions)
115
140
  response = _api_response(operation, status, definitions)
@@ -141,10 +166,11 @@ module Jsapi
141
166
 
142
167
  ErrorResult.new(e, status: status)
143
168
  end
144
- render(json: Response.new(result, response, definitions), status: status)
169
+ render(json: Response.new(result, response, definitions, omit: omit), status: status)
145
170
  else
146
171
  head(status)
147
172
  end
173
+ self.content_type = response.content_type
148
174
  end
149
175
  end
150
176
  end
@@ -6,7 +6,7 @@ module Jsapi
6
6
  class Parameters
7
7
  include Model::Nestable
8
8
 
9
- attr_reader :raw_attributes
9
+ attr_reader :raw_additional_attributes, :raw_attributes
10
10
 
11
11
  # Creates a new instance that wraps +params+ according to +operation+. References are
12
12
  # resolved to API components in +definitions+.
@@ -14,29 +14,35 @@ module Jsapi
14
14
  # If +strong+ is true+ parameters that can be mapped are accepted only. That means that
15
15
  # the instance created is invalid if +params+ contains any parameters that can't be
16
16
  # mapped to a parameter or a request body property of +operation+.
17
- def initialize(params, operation, definitions, strong: false)
18
- @params = params
17
+ def initialize(params, headers, operation, definitions, strong: false)
18
+ @params = params.to_h
19
19
  @strong = strong == true
20
20
  @raw_attributes = {}
21
+ @raw_additional_attributes = {}
21
22
 
22
- # Merge parameters and request body properties
23
- meta_models = operation.parameters.transform_values do |parameter|
24
- parameter.resolve(definitions)
25
- end
26
- request_body = operation.request_body&.resolve(definitions)
27
- if request_body && request_body.schema.respond_to?(:properties)
28
- meta_models.merge!(request_body.schema.resolve_properties(:write, definitions))
29
- end
23
+ # Parameters
24
+ operation.parameters.each do |name, parameter_model|
25
+ parameter_model = parameter_model.resolve(definitions)
30
26
 
31
- # Wrap params
32
- meta_models.each do |name, meta_model|
33
- @raw_attributes[name.underscore] = JSON.wrap(params[name], meta_model.schema, definitions)
27
+ @raw_attributes[name] = JSON.wrap(
28
+ parameter_model.in == 'header' ? headers[name] : @params[name],
29
+ parameter_model.schema.resolve(definitions),
30
+ definitions
31
+ )
34
32
  end
35
- end
36
33
 
37
- def inspect # :nodoc:
38
- "#<#{self.class.name} " \
39
- "#{attributes.map { |k, v| "#{k}: #{v.inspect}" }.join(', ')}>"
34
+ # Request body
35
+ request_body_schema = operation.request_body&.resolve(definitions)
36
+ &.schema&.resolve(definitions)
37
+ if request_body_schema&.object?
38
+ request_body = JSON.wrap(
39
+ @params.except(*operation.parameters.keys),
40
+ request_body_schema,
41
+ definitions
42
+ )
43
+ @raw_attributes.merge!(request_body.raw_attributes)
44
+ @raw_additional_attributes = request_body.raw_additional_attributes
45
+ end
40
46
  end
41
47
 
42
48
  # Validates the request parameters. Returns true if the parameters are valid, false
@@ -44,11 +50,7 @@ module Jsapi
44
50
  def validate(errors)
45
51
  [
46
52
  validate_attributes(errors),
47
- !@strong || validate_parameters(
48
- @params.except(:controller, :action, :format),
49
- attributes,
50
- errors
51
- )
53
+ !@strong || validate_parameters(@params, attributes, errors)
52
54
  ].all?
53
55
  end
54
56
 
@@ -7,10 +7,23 @@ module Jsapi
7
7
 
8
8
  # Creates a new instance to serialize +object+ according to +response+. References
9
9
  # are resolved to API components in +definitions+.
10
- def initialize(object, response, definitions)
10
+ #
11
+ # The +:omit+ option specifies on which conditions properties are omitted.
12
+ # Possible values are:
13
+ #
14
+ # - +:empty+ - All of the properties whose value is empty are omitted.
15
+ # - +:nil+ - All of the properties whose value is +nil+ are omitted.
16
+ #
17
+ # Raises an InvalidArgumentError when the value of +:omit+ is invalid.
18
+ def initialize(object, response, definitions, omit: nil)
19
+ if [:empty, :nil, nil].exclude?(omit)
20
+ raise InvalidArgumentError.new('omit', omit, valid_values: %i[empty nil])
21
+ end
22
+
11
23
  @object = object
12
24
  @response = response
13
25
  @definitions = definitions
26
+ @omit = omit
14
27
  end
15
28
 
16
29
  def inspect # :nodoc:
@@ -32,7 +45,9 @@ module Jsapi
32
45
  private
33
46
 
34
47
  def serialize(object, schema, path = nil)
48
+ object = schema.default_value(@definitions, context: :response) if object.nil?
35
49
  return if object.nil? && schema.nullable?
50
+
36
51
  raise "#{path || 'response'} can't be nil" if object.nil?
37
52
 
38
53
  case schema.type
@@ -68,36 +83,33 @@ module Jsapi
68
83
  end
69
84
 
70
85
  def serialize_object(object, schema, path)
71
- return if object.blank? # {}
72
-
73
- # Select inherriting schema on polymorphism
74
- if (discriminator = schema.discriminator)
75
- discriminator_property = schema.properties[discriminator.property_name]
76
- schema = discriminator.resolve(
77
- object.public_send(discriminator_property.source || discriminator_property.name.underscore),
78
- @definitions
79
- )
80
- end
86
+ schema = schema.resolve_schema(object, @definitions, context: :response)
87
+ properties = {}
88
+
81
89
  # Serialize properties
82
- properties = schema.resolve_properties(:read, @definitions).transform_values do |property|
83
- serialize(
84
- if (method_chain = property.source).present?
85
- method_chain.call(object)
86
- else
87
- object.public_send(property.name.underscore)
88
- end,
89
- property.schema.resolve(@definitions),
90
+ schema.resolve_properties(@definitions, context: :response).each do |key, property|
91
+ property_schema = property.schema.resolve(@definitions)
92
+ property_value = property.reader.call(object)
93
+ property_value = property_schema.default if property_value.nil?
94
+
95
+ next if ((@omit == :empty && property_value.try(:empty?)) ||
96
+ (@omit == :nil && property_value.nil?)) &&
97
+ property_schema.omittable?
98
+
99
+ properties[key] = serialize(
100
+ property_value,
101
+ property_schema,
90
102
  path.nil? ? property.name : "#{path}.#{property.name}"
91
103
  )
92
104
  end
93
- if (additional_properties = schema.additional_properties&.resolve(@definitions))
105
+ # Serialize additional properties
106
+ if (additional_properties = schema.additional_properties)
94
107
  additional_properties_schema = additional_properties.schema.resolve(@definitions)
95
108
 
96
109
  additional_properties.source.call(object)&.each do |key, value|
97
110
  # Don't replace the property with the same key
98
111
  next if properties.key?(key = key.to_s)
99
112
 
100
- # Serialize the additional property
101
113
  properties[key] = serialize(
102
114
  value,
103
115
  additional_properties_schema,
@@ -105,7 +117,8 @@ module Jsapi
105
117
  )
106
118
  end
107
119
  end
108
- properties
120
+ # Return properties if present, otherwise nil
121
+ properties if properties.present?
109
122
  end
110
123
  end
111
124
  end
@@ -3,6 +3,14 @@
3
3
  module Jsapi
4
4
  module DSL
5
5
  module ClassMethods
6
+ # Specifies the general default values for +type+.
7
+ #
8
+ # api_default 'array', read: [], write: []
9
+ #
10
+ def api_default(type, **keywords, &block)
11
+ api_definitions { default(type, **keywords, &block) }
12
+ end
13
+
6
14
  # The API definitions of the current class.
7
15
  def api_definitions(&block)
8
16
  @api_definitions ||= Meta::Definitions.new(self)
@@ -30,24 +38,24 @@ module Jsapi
30
38
  # end
31
39
  #
32
40
  # +name+ can be +nil+ if the controller handles one operation only.
33
- def api_operation(name = nil, **options, &block)
34
- api_definitions { operation(name, **options, &block) }
41
+ def api_operation(name = nil, **keywords, &block)
42
+ api_definitions { operation(name, **keywords, &block) }
35
43
  end
36
44
 
37
45
  # Defines a reusable parameter.
38
46
  #
39
47
  # api_parameter 'foo', type: 'string'
40
48
  #
41
- def api_parameter(name, **options, &block)
42
- api_definitions { parameter(name, **options, &block) }
49
+ def api_parameter(name, **keywords, &block)
50
+ api_definitions { parameter(name, **keywords, &block) }
43
51
  end
44
52
 
45
53
  # Defines a reusable request body.
46
54
  #
47
55
  # api_request_body 'foo', type: 'string'
48
56
  #
49
- def api_request_body(name, **options, &block)
50
- api_definitions { request_body(name, **options, &block) }
57
+ def api_request_body(name, **keywords, &block)
58
+ api_definitions { request_body(name, **keywords, &block) }
51
59
  end
52
60
 
53
61
  # Specifies the HTTP status code of an error response rendered when an
@@ -64,8 +72,8 @@ module Jsapi
64
72
  # api_response 'Foo', type: 'object' do
65
73
  # property 'bar', type: 'string'
66
74
  # end
67
- def api_response(name, **options, &block)
68
- api_definitions { response(name, **options, &block) }
75
+ def api_response(name, **keywords, &block)
76
+ api_definitions { response(name, **keywords, &block) }
69
77
  end
70
78
 
71
79
  # Defines a reusable schema.
@@ -73,8 +81,8 @@ module Jsapi
73
81
  # api_schema 'Foo' do
74
82
  # property 'bar', type: 'string'
75
83
  # end
76
- def api_schema(name, **options, &block)
77
- api_definitions { schema(name, **options, &block) }
84
+ def api_schema(name, **keywords, &block)
85
+ api_definitions { schema(name, **keywords, &block) }
78
86
  end
79
87
 
80
88
  # Defines the root of an OpenAPI document.
@@ -5,6 +5,17 @@ module Jsapi
5
5
  # Used to define top-level API components.
6
6
  class Definitions < Node
7
7
 
8
+ # Specifies the general default values for +type+.
9
+ #
10
+ # default 'array', read: [], write: []
11
+ #
12
+ def default(type, **keywords, &block)
13
+ _define('default', type.inspect) do
14
+ default = _meta_model.add_default(type, keywords)
15
+ Node.new(default, &block) if block
16
+ end
17
+ end
18
+
8
19
  # Includes API definitions from +klasses+.
9
20
  def include(*klasses)
10
21
  klasses.each do |klass|
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsapi
4
+ module DSL
5
+ module OpenAPI
6
+ module Callbacks
7
+ # Defines an \OpenAPI callback or refers a reusable callback.
8
+ #
9
+ # # define a callback
10
+ # callback 'foo' do
11
+ # operation '{$request.query.foo}'
12
+ # end
13
+ #
14
+ # # refer a reusable callback
15
+ # callback ref: 'foo'
16
+ #
17
+ # Refers the reusable callback with the same name if neither any
18
+ # keywords nor a block is specified.
19
+ #
20
+ # callback 'foo'
21
+ #
22
+ def callback(name = nil, **keywords, &block)
23
+ _define('callback', name&.inspect) do
24
+ name = keywords[:ref] if name.nil?
25
+ keywords = { ref: name } unless keywords.any? || block
26
+
27
+ callback_model = _meta_model.add_callback(name, keywords)
28
+ _eval(callback_model, OpenAPI::Callback, &block)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsapi
4
+ module DSL
5
+ module OpenAPI
6
+ module Examples
7
+ # Adds an example.
8
+ #
9
+ # example 'foo', value: 'bar'
10
+ #
11
+ # example 'foo'
12
+ #
13
+ # The default name is <code>'default'</code>.
14
+ def example(name_or_value = nil, **keywords, &block)
15
+ _define('example', name_or_value&.inspect) do
16
+ if keywords.any? || block
17
+ # example 'foo', value: 'bar', ...
18
+ name = name_or_value
19
+ else
20
+ # example 'foo'
21
+ name = nil
22
+ keywords = { value: name_or_value }
23
+ end
24
+
25
+ example = _meta_model.add_example(name, keywords)
26
+ Node.new(example, &block) if block
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,4 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'openapi/callbacks'
4
+ require_relative 'openapi/examples'
3
5
  require_relative 'openapi/callback'
4
6
  require_relative 'openapi/root'
@@ -4,7 +4,7 @@ module Jsapi
4
4
  module DSL
5
5
  # Used to specify details of an operation.
6
6
  class Operation < Node
7
- include Callbacks
7
+ include OpenAPI::Callbacks
8
8
 
9
9
  ##
10
10
  # :method: deprecated
@@ -4,7 +4,7 @@ module Jsapi
4
4
  module DSL
5
5
  # Used to specify details of a parameter.
6
6
  class Parameter < Schema
7
- include Examples
7
+ include OpenAPI::Examples
8
8
 
9
9
  ##
10
10
  # :method: deprecated
@@ -4,7 +4,7 @@ module Jsapi
4
4
  module DSL
5
5
  # Used to specify details of a request body.
6
6
  class RequestBody < Schema
7
- include Examples
7
+ include OpenAPI::Examples
8
8
 
9
9
  ##
10
10
  # :method: deprecated
@@ -4,7 +4,7 @@ module Jsapi
4
4
  module DSL
5
5
  # Used to specify details of a response.
6
6
  class Response < Schema
7
- include Examples
7
+ include OpenAPI::Examples
8
8
 
9
9
  ##
10
10
  # :method: deprecated
data/lib/jsapi/dsl.rb CHANGED
@@ -1,15 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'dsl/callbacks'
4
- require_relative 'dsl/examples'
5
3
  require_relative 'dsl/error'
6
4
  require_relative 'dsl/node'
5
+ require_relative 'dsl/openapi'
7
6
  require_relative 'dsl/schema'
8
7
  require_relative 'dsl/parameter'
9
8
  require_relative 'dsl/request_body'
10
9
  require_relative 'dsl/response'
11
10
  require_relative 'dsl/operation'
12
- require_relative 'dsl/openapi'
13
11
  require_relative 'dsl/definitions'
14
12
  require_relative 'dsl/class_methods'
15
13
 
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsapi
4
+ module InvalidValueHelper
5
+ def build_message(name, value, valid_values)
6
+ case valid_values.count
7
+ when 0
8
+ "#{name} must not be #{value.inspect}"
9
+ when 1
10
+ "#{name} must be #{valid_values.first.inspect}, is #{value.inspect}"
11
+ else
12
+ "#{name} must be one of #{valid_values[0..-2].map(&:inspect).join(', ')} " \
13
+ "or #{valid_values.last.inspect}, is #{value.inspect}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsapi
4
+ # Raised when an argument isn't contained in the list of valid values.
5
+ class InvalidArgumentError < ArgumentError
6
+ include InvalidValueHelper
7
+
8
+ def initialize(name, value, valid_values: [])
9
+ super(build_message(name, value, valid_values))
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsapi
4
+ # Raised when a value isn't contained in the list of valid values.
5
+ class InvalidValueError < RuntimeError
6
+ include InvalidValueHelper
7
+
8
+ def initialize(name, value, valid_values: [])
9
+ super(build_message(name, value, valid_values))
10
+ end
11
+ end
12
+ end
@@ -6,18 +6,24 @@ module Jsapi
6
6
  class Object < Value
7
7
  include Model::Nestable
8
8
 
9
- attr_reader :raw_attributes
9
+ attr_reader :raw_additional_attributes, :raw_attributes
10
10
 
11
11
  def initialize(attributes, schema, definitions)
12
- # Select inherriting schema on polymorphism
13
- if (discriminator = schema.discriminator)
14
- schema = discriminator.resolve(attributes[discriminator.property_name], definitions)
12
+ schema = schema.resolve_schema(attributes, definitions, context: :request)
13
+ properties = schema.resolve_properties(definitions, context: :request)
14
+
15
+ @raw_attributes = properties.transform_values do |property|
16
+ JSON.wrap(attributes[property.name], property.schema, definitions)
15
17
  end
16
- # Wrap attribute values
17
- @raw_attributes =
18
- schema.resolve_properties(:write, definitions).transform_values do |property|
19
- JSON.wrap(attributes[property.name], property.schema, definitions)
20
- end
18
+
19
+ @raw_additional_attributes =
20
+ if (additional_properties = schema.additional_properties)
21
+ additional_properties_schema = additional_properties.schema.resolve(definitions)
22
+
23
+ attributes.except(*properties.keys).transform_values do |value|
24
+ JSON.wrap(value, additional_properties_schema, definitions)
25
+ end
26
+ end || {}
21
27
 
22
28
  super(schema)
23
29
  end
@@ -27,11 +33,6 @@ module Jsapi
27
33
  @raw_attributes.values.all?(&:empty?)
28
34
  end
29
35
 
30
- def inspect # :nodoc:
31
- "#<#{self.class.name} " \
32
- "#{@raw_attributes.map { |k, v| "#{k}: #{v.inspect}" }.join(', ')}>"
33
- end
34
-
35
36
  # Returns a model to read attributes by.
36
37
  def model
37
38
  @model ||= (schema.model || Model::Base).new(self)
data/lib/jsapi/json.rb CHANGED
@@ -16,7 +16,7 @@ module Jsapi
16
16
  def wrap(object, schema, definitions = nil)
17
17
  schema = schema.resolve(definitions) unless definitions.nil?
18
18
 
19
- object = schema.default if object.nil?
19
+ object = schema.default_value(definitions, context: :request) if object.nil?
20
20
  return Null.new(schema) if object.nil?
21
21
 
22
22
  case schema.type
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Jsapi
4
4
  module Meta
5
- module Attributes
6
- module ClassMethods
5
+ module Base
6
+ module Attributes
7
7
  # Defines an attribute.
8
8
  def attribute(name, type = Object,
9
9
  keys: nil,