sober_swag 0.17.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/benchmark.yml +39 -0
- data/.github/workflows/lint.yml +2 -4
- data/.github/workflows/ruby.yml +1 -1
- data/.gitignore +3 -0
- data/.rubocop.yml +5 -1
- data/.yardopts +7 -0
- data/CHANGELOG.md +21 -0
- data/Gemfile +12 -0
- data/README.md +1 -1
- data/bench/benchmark.rb +34 -0
- data/bench/benchmarks/basic_field_serializer.rb +21 -0
- data/bench/benchmarks/view_selection.rb +47 -0
- data/docs/serializers.md +4 -1
- data/example/Gemfile +2 -2
- data/example/Gemfile.lock +46 -44
- data/example/config/environments/production.rb +1 -1
- data/lib/sober_swag/compiler/path.rb +42 -3
- data/lib/sober_swag/compiler/paths.rb +20 -0
- data/lib/sober_swag/compiler/primitive.rb +20 -1
- data/lib/sober_swag/compiler/type.rb +105 -22
- data/lib/sober_swag/compiler.rb +29 -3
- data/lib/sober_swag/controller/route.rb +103 -20
- data/lib/sober_swag/controller.rb +39 -12
- data/lib/sober_swag/input_object.rb +124 -7
- data/lib/sober_swag/nodes/array.rb +19 -0
- data/lib/sober_swag/nodes/attribute.rb +45 -4
- data/lib/sober_swag/nodes/base.rb +27 -7
- data/lib/sober_swag/nodes/binary.rb +30 -13
- data/lib/sober_swag/nodes/enum.rb +16 -1
- data/lib/sober_swag/nodes/list.rb +20 -0
- data/lib/sober_swag/nodes/nullable_primitive.rb +3 -0
- data/lib/sober_swag/nodes/object.rb +4 -1
- data/lib/sober_swag/nodes/one_of.rb +11 -3
- data/lib/sober_swag/nodes/primitive.rb +34 -2
- data/lib/sober_swag/nodes/sum.rb +8 -0
- data/lib/sober_swag/output_object/definition.rb +57 -1
- data/lib/sober_swag/output_object/field.rb +31 -11
- data/lib/sober_swag/output_object/field_syntax.rb +19 -3
- data/lib/sober_swag/output_object/view.rb +46 -1
- data/lib/sober_swag/output_object.rb +40 -19
- data/lib/sober_swag/parser.rb +7 -1
- data/lib/sober_swag/serializer/array.rb +27 -3
- data/lib/sober_swag/serializer/base.rb +75 -25
- data/lib/sober_swag/serializer/conditional.rb +33 -1
- data/lib/sober_swag/serializer/field_list.rb +23 -5
- data/lib/sober_swag/serializer/hash.rb +53 -0
- data/lib/sober_swag/serializer/mapped.rb +10 -1
- data/lib/sober_swag/serializer/optional.rb +18 -1
- data/lib/sober_swag/serializer/primitive.rb +3 -0
- data/lib/sober_swag/serializer.rb +1 -0
- data/lib/sober_swag/server.rb +27 -11
- data/lib/sober_swag/type/named.rb +14 -0
- data/lib/sober_swag/types/comma_array.rb +4 -0
- data/lib/sober_swag/version.rb +1 -1
- data/lib/sober_swag.rb +6 -1
- metadata +9 -2
@@ -3,6 +3,12 @@ module SoberSwag
|
|
3
3
|
##
|
4
4
|
# Describe a single controller endpoint.
|
5
5
|
class Route
|
6
|
+
##
|
7
|
+
# @param method [Symbol] the HTTP method to get
|
8
|
+
# @param action_name [Symbol] the name of the rails action
|
9
|
+
# (the name of the controller method, usually)
|
10
|
+
# @param path [String] an OpenAPI V3 path template,
|
11
|
+
# which should [match this format](https://swagger.io/docs/specification/describing-parameters/#path-parameters)
|
6
12
|
def initialize(method, action_name, path)
|
7
13
|
@method = method
|
8
14
|
@path = path
|
@@ -12,20 +18,56 @@ module SoberSwag
|
|
12
18
|
@tags = []
|
13
19
|
end
|
14
20
|
|
15
|
-
|
21
|
+
##
|
22
|
+
# A hash of response code -> response serializer
|
23
|
+
# @return [Hash{Symbol => SoberSwag::Serializer::Base}]
|
24
|
+
# response code to response serializer
|
25
|
+
attr_reader :response_serializers
|
26
|
+
|
27
|
+
##
|
28
|
+
# A hash of response code -> response description
|
29
|
+
# @return [Hash{Symbol => String}]
|
30
|
+
# response code to response description
|
31
|
+
attr_reader :response_descriptions
|
32
|
+
|
33
|
+
##
|
34
|
+
# The HTTP method of this route.
|
35
|
+
# @return [Symbol]
|
36
|
+
attr_reader :method
|
37
|
+
|
38
|
+
##
|
39
|
+
# The swagger path specifier of this route.
|
40
|
+
# @return [String]
|
41
|
+
attr_reader :path
|
42
|
+
|
43
|
+
##
|
44
|
+
# The name of the rails action (usually the controller method) of this route.
|
45
|
+
# @return [Symbol]
|
46
|
+
attr_reader :action_name
|
16
47
|
|
17
48
|
##
|
18
49
|
# What to parse the request body into.
|
50
|
+
# @return [Class] a swagger-able class type for a request body.
|
19
51
|
attr_reader :request_body_class
|
20
52
|
##
|
21
53
|
# What to parse the request query_params into.
|
54
|
+
# @return [Class] a swagger-able class type for query parameters.
|
22
55
|
attr_reader :query_params_class
|
23
56
|
##
|
24
57
|
# What to parse the path params into.
|
58
|
+
# @return [Class] a swagger-able class type for path parameters.
|
25
59
|
attr_reader :path_params_class
|
26
60
|
|
27
61
|
##
|
28
62
|
# Standard swagger tags.
|
63
|
+
#
|
64
|
+
# @overload tags()
|
65
|
+
# Get the tags for this route.
|
66
|
+
# @return [Array<String,Symbol>] the tags.
|
67
|
+
# @overload tags(*args)
|
68
|
+
# Set the tags for this route.
|
69
|
+
# @param tags [Array<String,Symbol>] the tags to set
|
70
|
+
# @return [Array<String,Symbol>] the tags used
|
29
71
|
def tags(*args)
|
30
72
|
return @tags if args.empty?
|
31
73
|
|
@@ -34,8 +76,13 @@ module SoberSwag
|
|
34
76
|
|
35
77
|
##
|
36
78
|
# Define the request body, using SoberSwag's type-definition scheme.
|
37
|
-
# The block passed will be used to define the body of a new
|
38
|
-
#
|
79
|
+
# The block passed will be used to define the body of a new subclass of `base` (defaulted to {SoberSwag::InputObject}.)
|
80
|
+
# @overload request_body(base)
|
81
|
+
# Give a Swagger-able type that will be used to parse the request body, and used in generated docs.
|
82
|
+
# @param base [Class] a swagger-able class
|
83
|
+
# @overload request_body(base = SoberSwag::InputObject, &block)
|
84
|
+
# Define a Swagger-able type inline to use to parse the request body.
|
85
|
+
# @see SoberSwag.input_object
|
39
86
|
def request_body(base = SoberSwag::InputObject, &block)
|
40
87
|
@request_body_class = make_input_object!(base, &block)
|
41
88
|
action_module.const_set('RequestBody', @request_body_class)
|
@@ -48,9 +95,12 @@ module SoberSwag
|
|
48
95
|
end
|
49
96
|
|
50
97
|
##
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
98
|
+
# @overload query_params(base)
|
99
|
+
# Give a Swagger-able type that will be used to parse the query params, and used in generated docs.
|
100
|
+
# @param base [Class] a swagger-able class
|
101
|
+
# @overload query_params(base = SoberSwag::InputObject, &block)
|
102
|
+
# Define a Swagger-able type inline to use to parse the query params.
|
103
|
+
# @see SoberSwag.input_object
|
54
104
|
def query_params(base = SoberSwag::InputObject, &block)
|
55
105
|
@query_params_class = make_input_object!(base, &block)
|
56
106
|
action_module.const_set('QueryParams', @query_params_class)
|
@@ -63,9 +113,12 @@ module SoberSwag
|
|
63
113
|
end
|
64
114
|
|
65
115
|
##
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
116
|
+
# @overload path_params(base)
|
117
|
+
# Give a Swagger-able type that will be used to parse the path params, and used in generated docs.
|
118
|
+
# @param base [Class] a swagger-able class
|
119
|
+
# @overload path_params(base = SoberSwag::InputObject, &block)
|
120
|
+
# Define a Swagger-able type inline to use to parse the path params.
|
121
|
+
# @see SoberSwag.input_object
|
69
122
|
def path_params(base = SoberSwag::InputObject, &block)
|
70
123
|
@path_params_class = make_input_object!(base, &block)
|
71
124
|
action_module.const_set('PathParams', @path_params_class)
|
@@ -78,19 +131,27 @@ module SoberSwag
|
|
78
131
|
end
|
79
132
|
|
80
133
|
##
|
81
|
-
#
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
134
|
+
# @overload description()
|
135
|
+
# Get a description of this route object.
|
136
|
+
# @return [String] markdown-formatted description
|
137
|
+
# @overload description(desc)
|
138
|
+
# Set the description of this route object.
|
139
|
+
# @param desc [String] markdown-formatted description
|
140
|
+
# @return [String] `desc`.
|
88
141
|
def description(desc = nil)
|
89
142
|
return @description if desc.nil?
|
90
143
|
|
91
144
|
@description = desc
|
92
145
|
end
|
93
146
|
|
147
|
+
##
|
148
|
+
# @overload summary()
|
149
|
+
# Get the summary of this route object, a short string that identifies
|
150
|
+
# what it does.
|
151
|
+
# @return [String] markdown-formatted summary
|
152
|
+
# @overload summary(sum)
|
153
|
+
# Set a short, markdown-formatted summary of what this route does.
|
154
|
+
# @param sum [String] markdown-formatted summary
|
94
155
|
def summary(sum = nil)
|
95
156
|
return @summary if sum.nil?
|
96
157
|
|
@@ -100,14 +161,35 @@ module SoberSwag
|
|
100
161
|
##
|
101
162
|
# The container module for all the constants this will eventually define.
|
102
163
|
# Each class generated by this Route will be defined within this module.
|
164
|
+
# @return [Module] the module under which constants will be defined.
|
103
165
|
def action_module
|
104
166
|
@action_module ||= Module.new
|
105
167
|
end
|
106
168
|
|
107
169
|
##
|
108
|
-
#
|
109
|
-
#
|
110
|
-
# {SoberSwag::OutputObject.define}
|
170
|
+
# @overload response(status_code, description, &block)
|
171
|
+
# Define a new response from this route, by defining a serializer inline.
|
172
|
+
# This serializer will be defined as if with {SoberSwag::OutputObject.define}
|
173
|
+
#
|
174
|
+
# Generally, you want to define your serializers elsewhere for independent testing and such.
|
175
|
+
# However, if you have a really quick thing to serialize, this works.
|
176
|
+
# @param status_code [Symbol]
|
177
|
+
# the name of the HTTP status of this response.
|
178
|
+
# @param description [String]
|
179
|
+
# a description of what this response is, markdown-formatted
|
180
|
+
# @param block [Proc]
|
181
|
+
# passed to {SoberSwag::OutputObject.define}
|
182
|
+
#
|
183
|
+
# @overload response(status_code, description, serializer)
|
184
|
+
# Define a new response from this route, with an existing serializer.
|
185
|
+
# The generated swagger will document this response's format using the serializer.
|
186
|
+
#
|
187
|
+
# @param status_code [Symbol]
|
188
|
+
# the name of the HTTP status of this response
|
189
|
+
# @param description [String]
|
190
|
+
# a description of what this response is, markdown-formatted
|
191
|
+
# @param serializer [SoberSwag::Serializer::Base] a serializer to use for the
|
192
|
+
# body of this response
|
111
193
|
def response(status_code, description, serializer = nil, &block)
|
112
194
|
status_key = Rack::Utils.status_code(status_code)
|
113
195
|
|
@@ -120,7 +202,8 @@ module SoberSwag
|
|
120
202
|
end
|
121
203
|
|
122
204
|
##
|
123
|
-
# What you should call the module of this action in your controller
|
205
|
+
# What you should call the module of this action in your controller.
|
206
|
+
# @return [String]
|
124
207
|
def action_module_name
|
125
208
|
action_name.to_s.classify
|
126
209
|
end
|
@@ -2,7 +2,8 @@ require 'active_support/concern'
|
|
2
2
|
|
3
3
|
module SoberSwag
|
4
4
|
##
|
5
|
-
#
|
5
|
+
# This module can be included in any subclass of `ActionController` or `ActionController::API` to make it `SoberSwag`-able.
|
6
|
+
# This means that you can use the mechanics of SoberSwag to define a type-safe API, with generated Swagger documentation!
|
6
7
|
module Controller
|
7
8
|
extend ActiveSupport::Concern
|
8
9
|
|
@@ -17,14 +18,18 @@ module SoberSwag
|
|
17
18
|
include ::Dry::Types()
|
18
19
|
end
|
19
20
|
|
20
|
-
|
21
|
+
##
|
22
|
+
# Module containing class methods.
|
23
|
+
# Any class that `include`s {SoberSwag::Controller} will also `extend` {SoberSwag::Controller::ClassMethods}.
|
24
|
+
module ClassMethods
|
21
25
|
##
|
22
26
|
# Define a new action with the given HTTP method, action name, and path.
|
23
|
-
# This will
|
27
|
+
# This will eventually delegate to making an actual method on your controller,
|
24
28
|
# so you can use controllers as you wish with no harm.
|
25
29
|
#
|
26
30
|
# This method takes a block, evaluated in the context of a {SoberSwag::Controller::Route}.
|
27
31
|
# Used like:
|
32
|
+
#
|
28
33
|
# define(:get, :show, '/posts/{id}') do
|
29
34
|
# path_params do
|
30
35
|
# attribute :id, Types::Integer
|
@@ -36,32 +41,46 @@ module SoberSwag
|
|
36
41
|
# end
|
37
42
|
#
|
38
43
|
# This will define an "action module" on this class to contain the generated types.
|
39
|
-
# In the above example, the following constants will be
|
40
|
-
#
|
41
|
-
#
|
44
|
+
# In the above example, the following constants will be defined on the controller:
|
45
|
+
#
|
46
|
+
# - `PostsController::Show` - the container module for everything in this action
|
47
|
+
# - `PostsController::Show::PathParams` - the dry-struct type for the path attribute.
|
48
|
+
#
|
42
49
|
# So, in the same controller, you can refer to Show::PathParams to get the type created by the 'path_params' block above.
|
50
|
+
#
|
51
|
+
# The block given evaluates in the context of `SoberSwag::Controller::Route`.
|
52
|
+
#
|
53
|
+
# @todo Explore parsing the `path` parameter from rails routes so we can avoid forcing the duplicate boilerplate.
|
54
|
+
#
|
55
|
+
# @param method [Symbol] the HTTP method of this route
|
56
|
+
# @param action [Symbol] the name of the controller method this maps onto
|
57
|
+
# @param path [String] an OpenAPI v3 Path Specifier
|
43
58
|
def define(method, action, path, &block)
|
44
59
|
r = Route.new(method, action, path)
|
45
60
|
r.instance_eval(&block)
|
46
61
|
const_set(r.action_module_name, r.action_module)
|
47
62
|
defined_routes << r
|
48
|
-
define_method(action, r.action) if r.action
|
49
63
|
end
|
50
64
|
|
51
65
|
##
|
52
66
|
# All the routes that this controller knows about.
|
67
|
+
# @return [Array<SoberSwag::Controller::Route>
|
53
68
|
def defined_routes
|
54
69
|
@defined_routes ||= []
|
55
70
|
end
|
56
71
|
|
57
72
|
##
|
58
73
|
# Find a route with the given name.
|
74
|
+
# @param name [Symbol] the name
|
75
|
+
# @return [SoberSwag::Controller::Route]
|
59
76
|
def find_route(name)
|
60
77
|
defined_routes.find { |r| r.action_name.to_s == name.to_s }
|
61
78
|
end
|
62
79
|
|
63
80
|
##
|
64
|
-
#
|
81
|
+
# Get the OpenAPI v3 definition for this controller.
|
82
|
+
#
|
83
|
+
# @return [Hash]
|
65
84
|
def swagger_info
|
66
85
|
@swagger_info ||=
|
67
86
|
begin
|
@@ -74,14 +93,19 @@ module SoberSwag
|
|
74
93
|
end
|
75
94
|
end
|
76
95
|
|
96
|
+
included do |base|
|
97
|
+
base.extend ClassMethods
|
98
|
+
end
|
99
|
+
|
77
100
|
##
|
78
|
-
#
|
101
|
+
# ActiveController action to get the swagger definition for this API.
|
102
|
+
# It renders a JSON of the OpenAPI v3 schema for this API.
|
79
103
|
def swagger
|
80
104
|
render json: self.class.swagger_info
|
81
105
|
end
|
82
106
|
|
83
107
|
##
|
84
|
-
# Get the path parameters, parsed into the type you defined with {SoberSwag::Controller
|
108
|
+
# Get the path parameters, parsed into the type you defined with {SoberSwag::Controller::ClassMethods#define}
|
85
109
|
# @raise [UndefinedPathError] if there's no path params defined for this route
|
86
110
|
# @raise [Dry::Struct::Error] if we cannot convert the path params to the defined type.
|
87
111
|
def parsed_path
|
@@ -95,7 +119,7 @@ module SoberSwag
|
|
95
119
|
end
|
96
120
|
|
97
121
|
##
|
98
|
-
# Get the request body, parsed into the type you defined with {SoberSwag::Controller
|
122
|
+
# Get the request body, parsed into the type you defined with {SoberSwag::Controller::ClassMethods#define}.
|
99
123
|
# @raise [UndefinedBodyError] if there's no request body defined for this route
|
100
124
|
# @raise [Dry::Struct::Error] if we cannot convert the path params to the defined type.
|
101
125
|
def parsed_body
|
@@ -109,7 +133,7 @@ module SoberSwag
|
|
109
133
|
end
|
110
134
|
|
111
135
|
##
|
112
|
-
# Get the query params, parsed into the type you defined with {SoberSwag::Controller
|
136
|
+
# Get the query params, parsed into the type you defined with {SoberSwag::Controller::ClassMethods#define}
|
113
137
|
# @raise [UndefinedQueryError] if there's no query params defined for this route
|
114
138
|
# @raise [Dry::Struct::Error] if we cannot convert the path params to the defined type.
|
115
139
|
def parsed_query
|
@@ -140,6 +164,8 @@ module SoberSwag
|
|
140
164
|
# This kinda violates the "be liberal in what you accept" principle,
|
141
165
|
# but it keeps the docs honest: parameters sent in the body *must* be
|
142
166
|
# in the body.
|
167
|
+
#
|
168
|
+
# @return [Hash]
|
143
169
|
def body_params
|
144
170
|
request.request_parameters
|
145
171
|
end
|
@@ -147,6 +173,7 @@ module SoberSwag
|
|
147
173
|
##
|
148
174
|
# Get the action-definition for the current action.
|
149
175
|
# Under the hood, delegates to the `:action` key of rails params.
|
176
|
+
# @return [SoberSwag::Controller::Route]
|
150
177
|
def current_action_def
|
151
178
|
self.class.find_route(params[:action])
|
152
179
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module SoberSwag
|
2
2
|
##
|
3
|
-
# A variant of Dry::Struct that allows you to set a "model name" that is
|
3
|
+
# A variant of Dry::Struct that allows you to set a "model name" that is publicly visible.
|
4
4
|
# If you do not set one, it will be the Ruby class name, with any '::' replaced with a '.'.
|
5
5
|
#
|
6
6
|
# This otherwise behaves exactly like a Dry::Struct.
|
@@ -12,24 +12,101 @@ module SoberSwag
|
|
12
12
|
class << self
|
13
13
|
##
|
14
14
|
# The name to use for this type in external documentation.
|
15
|
-
|
16
|
-
|
15
|
+
#
|
16
|
+
# @param new_ident [String] what to call this InputObject in external documentation.
|
17
|
+
def identifier(new_ident = nil)
|
18
|
+
@identifier = new_ident if new_ident
|
17
19
|
|
18
20
|
@identifier || name.to_s.gsub('::', '.')
|
19
21
|
end
|
20
22
|
|
23
|
+
##
|
24
|
+
# @overload attribute(key, parent = SoberSwag::InputObject, &block)
|
25
|
+
# Defines an attribute as a direct sub-object.
|
26
|
+
# This block will be called as in {SoberSwag.input_object}.
|
27
|
+
# This might be useful in a case like the following:
|
28
|
+
#
|
29
|
+
# ```ruby
|
30
|
+
# class Classroom < SoberSwag::InputObject
|
31
|
+
# attribute :biographical_detail do
|
32
|
+
# attribute :student_name, primitive(:String)
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
# ```
|
36
|
+
#
|
37
|
+
# @param key [Symbol] the attribute name
|
38
|
+
# @param parent [Class] the parent class to use for the sub-object
|
39
|
+
# @overload attribute(key, type)
|
40
|
+
# Defines a new attribute with the given type.
|
41
|
+
# @param key [Symbol] the attribute name
|
42
|
+
# @param type the attribute type
|
21
43
|
def attribute(key, parent = SoberSwag::InputObject, &block)
|
22
44
|
raise ArgumentError, "parent class #{parent} is not an input object type!" unless valid_field_def?(parent, block)
|
23
45
|
|
24
46
|
super(key, parent, &block)
|
25
47
|
end
|
26
48
|
|
49
|
+
##
|
50
|
+
# Add on an attribute which only ever parses from a constant value.
|
51
|
+
# By default, this attribute will be called `type`, but you can override it with the kwarg.
|
52
|
+
# This is useful in situations where you want to emulate a sum type.
|
53
|
+
# For example, if you want to make an API endpoint that can either accept or reject proposals
|
54
|
+
#
|
55
|
+
# ```ruby
|
56
|
+
#
|
57
|
+
# ApiInputType = SoberSwag.input_object {
|
58
|
+
# identifier 'AcceptProposal'
|
59
|
+
# type_attribute 'accept'
|
60
|
+
# attribute(:message, primitive(:String))
|
61
|
+
# } | SoberSwag.input_object {
|
62
|
+
# identifier 'RejectProposal'
|
63
|
+
# type_attribute 'reject'
|
64
|
+
# attribute(:message, primitive(:String))
|
65
|
+
# }
|
66
|
+
# ```
|
67
|
+
#
|
68
|
+
# Under the hood, this basically looks like:
|
69
|
+
#
|
70
|
+
# ```ruby
|
71
|
+
# type_attribute 'archive'
|
72
|
+
# # is equivalent to
|
73
|
+
#
|
74
|
+
# attribute(:type, SoberSwag::Types::String.enum('archive'))
|
75
|
+
# ```
|
76
|
+
#
|
77
|
+
# @param value [String,Symbol] the value to parse
|
78
|
+
# @param attribute_key [Symbol] what key to use
|
79
|
+
def type_attribute(value, attribute_key: :type)
|
80
|
+
attribute(attribute_key, SoberSwag::Types::String.enum(value.to_s))
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# @overload attribute(key, parent = SoberSwag::InputObject, &block)
|
85
|
+
# Defines an optional attribute by defining a sub-object inline.
|
86
|
+
# This differs from a nil-able attribute as it can be *not provided*, while nilable attributes must be set to `null`.
|
87
|
+
#
|
88
|
+
# Yields to the block like in {SoberSwag.input_object}
|
89
|
+
#
|
90
|
+
# @param key [Symbol] the attribute name
|
91
|
+
# @param parent [Class] the parent class to use for the sub-object
|
92
|
+
# @overload attribute(key, type)
|
93
|
+
# Defines an optional attribute with a given type.
|
94
|
+
# This differs from a nil-able attribute as it can be *not provided*, while nilable attributes must be set to `null`.
|
95
|
+
#
|
96
|
+
# @param key [Symbol] the attribute name
|
97
|
+
# @param type the attribute type, another parsable object.
|
27
98
|
def attribute?(key, parent = SoberSwag::InputObject, &block)
|
28
99
|
raise ArgumentError, "parent class #{parent} is not an input object type!" unless valid_field_def?(parent, block)
|
29
100
|
|
30
101
|
super(key, parent, &block)
|
31
102
|
end
|
32
103
|
|
104
|
+
##
|
105
|
+
# Add metadata keys, like `:description`, to the defined type.
|
106
|
+
# Note: does NOT mutate the type, returns a new type with the metadata added.
|
107
|
+
#
|
108
|
+
# @param args [Hash] the argument values
|
109
|
+
# @return [SoberSwag::InputObject] the new input object class
|
33
110
|
def meta(*args)
|
34
111
|
original = self
|
35
112
|
|
@@ -42,8 +119,25 @@ module SoberSwag
|
|
42
119
|
end
|
43
120
|
|
44
121
|
##
|
45
|
-
#
|
46
|
-
#
|
122
|
+
# Convenience method: you can use `.primitive` get a primitive parser for a given type.
|
123
|
+
# This lets you write:
|
124
|
+
#
|
125
|
+
# ```ruby
|
126
|
+
# class Foo < SoberSwag::InputObject
|
127
|
+
# attribute :bar, primitive(:String)
|
128
|
+
# end
|
129
|
+
# ```
|
130
|
+
#
|
131
|
+
# instead of
|
132
|
+
#
|
133
|
+
# ```ruby
|
134
|
+
# class Foo < SoberSwag::InputObject
|
135
|
+
# attribute :bar, SoberSwag::Types::String
|
136
|
+
# end
|
137
|
+
# ```
|
138
|
+
#
|
139
|
+
# @param args [Symbol] a symbol
|
140
|
+
# @return a primitive parser
|
47
141
|
def primitive(*args)
|
48
142
|
if args.length == 1
|
49
143
|
SoberSwag::Types.const_get(args.first)
|
@@ -52,8 +146,31 @@ module SoberSwag
|
|
52
146
|
end
|
53
147
|
end
|
54
148
|
|
55
|
-
|
56
|
-
|
149
|
+
##
|
150
|
+
# Convenience method: you can use `.param` to get a parameter parser of a given type.
|
151
|
+
# Said parsers are more loose: for example, `param(:Integer)` will parse the string `"10"` into `10`, while
|
152
|
+
# `primitive(:Integer)` will throw an error.
|
153
|
+
#
|
154
|
+
# This method lets you write:
|
155
|
+
#
|
156
|
+
# ```ruby
|
157
|
+
# class Foo < SoberSwag::InputObject
|
158
|
+
# attribute :bar, param(:Integer)
|
159
|
+
# end
|
160
|
+
# ```
|
161
|
+
#
|
162
|
+
# instead of
|
163
|
+
#
|
164
|
+
# ```ruby
|
165
|
+
# class Foo < SoberSwag::InputObject
|
166
|
+
# attribute :bar, SoberSwag::Types::Param::Integer
|
167
|
+
# end
|
168
|
+
# ```
|
169
|
+
#
|
170
|
+
# @param name [Symbol] the name of the parameter type to get
|
171
|
+
# @return a parameter parser
|
172
|
+
def param(name)
|
173
|
+
SoberSwag::Types::Params.const_get(name)
|
57
174
|
end
|
58
175
|
|
59
176
|
private
|