sober_swag 0.15.0 → 0.20.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/lint.yml +4 -9
- data/.github/workflows/ruby.yml +2 -6
- data/.gitignore +4 -0
- data/.rubocop.yml +50 -5
- data/.yardopts +7 -0
- data/CHANGELOG.md +29 -1
- data/Gemfile +8 -0
- data/README.md +155 -4
- data/bin/rspec +29 -0
- data/docs/serializers.md +18 -13
- data/example/Gemfile +2 -2
- data/example/app/controllers/people_controller.rb +4 -0
- data/example/app/controllers/posts_controller.rb +5 -0
- data/example/config/environments/production.rb +1 -1
- data/lib/sober_swag.rb +6 -1
- data/lib/sober_swag/compiler.rb +29 -3
- data/lib/sober_swag/compiler/path.rb +49 -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/controller.rb +42 -15
- data/lib/sober_swag/controller/route.rb +133 -28
- data/lib/sober_swag/input_object.rb +117 -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.rb +35 -4
- data/lib/sober_swag/output_object/definition.rb +31 -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/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 +18 -2
- 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/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/sober_swag.gemspec +2 -2
- metadata +13 -10
@@ -3,34 +3,89 @@ 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
|
9
15
|
@action_name = action_name
|
10
16
|
@response_serializers = {}
|
11
17
|
@response_descriptions = {}
|
18
|
+
@tags = []
|
12
19
|
end
|
13
20
|
|
14
|
-
|
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
|
15
37
|
|
16
38
|
##
|
17
|
-
#
|
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
|
47
|
+
|
48
|
+
##
|
49
|
+
# What to parse the request body into.
|
50
|
+
# @return [Class] a swagger-able class type for a request body.
|
18
51
|
attr_reader :request_body_class
|
19
52
|
##
|
20
|
-
# What to parse the request query_params
|
53
|
+
# What to parse the request query_params into.
|
54
|
+
# @return [Class] a swagger-able class type for query parameters.
|
21
55
|
attr_reader :query_params_class
|
22
|
-
|
23
56
|
##
|
24
|
-
# What to parse the path params into
|
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
|
|
61
|
+
##
|
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
|
71
|
+
def tags(*args)
|
72
|
+
return @tags if args.empty?
|
73
|
+
|
74
|
+
@tags = args.flatten
|
75
|
+
end
|
76
|
+
|
27
77
|
##
|
28
78
|
# Define the request body, using SoberSwag's type-definition scheme.
|
29
|
-
# The block passed will be used to define the body of a new
|
30
|
-
#
|
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
|
31
86
|
def request_body(base = SoberSwag::InputObject, &block)
|
32
87
|
@request_body_class = make_input_object!(base, &block)
|
33
|
-
action_module.const_set('
|
88
|
+
action_module.const_set('RequestBody', @request_body_class)
|
34
89
|
end
|
35
90
|
|
36
91
|
##
|
@@ -40,9 +95,12 @@ module SoberSwag
|
|
40
95
|
end
|
41
96
|
|
42
97
|
##
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
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
|
46
104
|
def query_params(base = SoberSwag::InputObject, &block)
|
47
105
|
@query_params_class = make_input_object!(base, &block)
|
48
106
|
action_module.const_set('QueryParams', @query_params_class)
|
@@ -55,9 +113,12 @@ module SoberSwag
|
|
55
113
|
end
|
56
114
|
|
57
115
|
##
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
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
|
61
122
|
def path_params(base = SoberSwag::InputObject, &block)
|
62
123
|
@path_params_class = make_input_object!(base, &block)
|
63
124
|
action_module.const_set('PathParams', @path_params_class)
|
@@ -70,19 +131,27 @@ module SoberSwag
|
|
70
131
|
end
|
71
132
|
|
72
133
|
##
|
73
|
-
#
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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`.
|
80
141
|
def description(desc = nil)
|
81
142
|
return @description if desc.nil?
|
82
143
|
|
83
144
|
@description = desc
|
84
145
|
end
|
85
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
|
86
155
|
def summary(sum = nil)
|
87
156
|
return @summary if sum.nil?
|
88
157
|
|
@@ -92,18 +161,39 @@ module SoberSwag
|
|
92
161
|
##
|
93
162
|
# The container module for all the constants this will eventually define.
|
94
163
|
# Each class generated by this Route will be defined within this module.
|
164
|
+
# @return [Module] the module under which constants will be defined.
|
95
165
|
def action_module
|
96
166
|
@action_module ||= Module.new
|
97
167
|
end
|
98
168
|
|
99
169
|
##
|
100
|
-
#
|
101
|
-
#
|
102
|
-
# {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
|
103
193
|
def response(status_code, description, serializer = nil, &block)
|
104
194
|
status_key = Rack::Utils.status_code(status_code)
|
105
195
|
|
106
|
-
raise ArgumentError, 'Response
|
196
|
+
raise ArgumentError, 'Response defined!' if @response_serializers.key?(status_key)
|
107
197
|
|
108
198
|
serializer ||= SoberSwag::OutputObject.define(&block)
|
109
199
|
response_module.const_set(status_code.to_s.classify, serializer)
|
@@ -112,7 +202,8 @@ module SoberSwag
|
|
112
202
|
end
|
113
203
|
|
114
204
|
##
|
115
|
-
# 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]
|
116
207
|
def action_module_name
|
117
208
|
action_name.to_s.classify
|
118
209
|
end
|
@@ -124,8 +215,22 @@ module SoberSwag
|
|
124
215
|
end
|
125
216
|
|
126
217
|
def make_input_object!(base, &block)
|
127
|
-
|
128
|
-
|
218
|
+
if base.is_a?(Class)
|
219
|
+
make_input_class(base, block)
|
220
|
+
elsif block
|
221
|
+
raise ArgumentError, 'passed a non-class base and a block to an input'
|
222
|
+
else
|
223
|
+
base
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def make_input_class(base, block)
|
228
|
+
if block
|
229
|
+
Class.new(base, &block).tap do |e|
|
230
|
+
e.transform_keys(&:to_sym) if [SoberSwag::InputObject, Dry::Struct].include?(base)
|
231
|
+
end
|
232
|
+
else
|
233
|
+
base
|
129
234
|
end
|
130
235
|
end
|
131
236
|
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,12 +12,67 @@ 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
|
43
|
+
def attribute(key, parent = SoberSwag::InputObject, &block)
|
44
|
+
raise ArgumentError, "parent class #{parent} is not an input object type!" unless valid_field_def?(parent, block)
|
45
|
+
|
46
|
+
super(key, parent, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# @overload attribute(key, parent = SoberSwag::InputObject, &block)
|
51
|
+
# Defines an optional attribute by defining a sub-object inline.
|
52
|
+
# This differs from a nil-able attribute as it can be *not provided*, while nilable attributes must be set to `null`.
|
53
|
+
#
|
54
|
+
# Yields to the block like in {SoberSwag.input_object}
|
55
|
+
#
|
56
|
+
# @param key [Symbol] the attribute name
|
57
|
+
# @param parent [Class] the parent class to use for the sub-object
|
58
|
+
# @overload attribute(key, type)
|
59
|
+
# Defines an optional attribute with a given type.
|
60
|
+
# This differs from a nil-able attribute as it can be *not provided*, while nilable attributes must be set to `null`.
|
61
|
+
#
|
62
|
+
# @param key [Symbol] the attribute name
|
63
|
+
# @param type the attribute type, another parsable object.
|
64
|
+
def attribute?(key, parent = SoberSwag::InputObject, &block)
|
65
|
+
raise ArgumentError, "parent class #{parent} is not an input object type!" unless valid_field_def?(parent, block)
|
66
|
+
|
67
|
+
super(key, parent, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Add metadata keys, like `:description`, to the defined type.
|
72
|
+
# Note: does NOT mutate the type, returns a new type with the metadata added.
|
73
|
+
#
|
74
|
+
# @param args [Hash] the argument values
|
75
|
+
# @return [SoberSwag::InputObject] the new input object class
|
21
76
|
def meta(*args)
|
22
77
|
original = self
|
23
78
|
|
@@ -29,12 +84,67 @@ module SoberSwag
|
|
29
84
|
end
|
30
85
|
end
|
31
86
|
|
32
|
-
|
33
|
-
|
87
|
+
##
|
88
|
+
# Convenience method: you can use `.primitive` get a primitive parser for a given type.
|
89
|
+
# This lets you write:
|
90
|
+
#
|
91
|
+
# ```ruby
|
92
|
+
# class Foo < SoberSwag::InputObject
|
93
|
+
# attribute :bar, primitive(:String)
|
94
|
+
# end
|
95
|
+
# ```
|
96
|
+
#
|
97
|
+
# instead of
|
98
|
+
#
|
99
|
+
# ```ruby
|
100
|
+
# class Foo < SoberSwag::InputObject
|
101
|
+
# attribute :bar, SoberSwag::Types::String
|
102
|
+
# end
|
103
|
+
# ```
|
104
|
+
#
|
105
|
+
# @param args [Symbol] a symbol
|
106
|
+
# @return a primitive parser
|
107
|
+
def primitive(*args)
|
108
|
+
if args.length == 1
|
109
|
+
SoberSwag::Types.const_get(args.first)
|
110
|
+
else
|
111
|
+
super
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Convenience method: you can use `.param` to get a parameter parser of a given type.
|
117
|
+
# Said parsers are more loose: for example, `param(:Integer)` will parse the string `"10"` into `10`, while
|
118
|
+
# `primitive(:Integer)` will throw an error.
|
119
|
+
#
|
120
|
+
# This method lets you write:
|
121
|
+
#
|
122
|
+
# ```ruby
|
123
|
+
# class Foo < SoberSwag::InputObject
|
124
|
+
# attribute :bar, param(:Integer)
|
125
|
+
# end
|
126
|
+
# ```
|
127
|
+
#
|
128
|
+
# instead of
|
129
|
+
#
|
130
|
+
# ```ruby
|
131
|
+
# class Foo < SoberSwag::InputObject
|
132
|
+
# attribute :bar, SoberSwag::Types::Param::Integer
|
133
|
+
# end
|
134
|
+
# ```
|
135
|
+
#
|
136
|
+
# @param name [Symbol] the name of the parameter type to get
|
137
|
+
# @return a parameter parser
|
138
|
+
def param(name)
|
139
|
+
SoberSwag::Types::Params.const_get(name)
|
34
140
|
end
|
35
141
|
|
36
|
-
|
37
|
-
|
142
|
+
private
|
143
|
+
|
144
|
+
def valid_field_def?(parent, block)
|
145
|
+
return true if block.nil?
|
146
|
+
|
147
|
+
parent.is_a?(Class) && parent <= SoberSwag::InputObject
|
38
148
|
end
|
39
149
|
end
|
40
150
|
end
|
@@ -10,18 +10,37 @@ module SoberSwag
|
|
10
10
|
|
11
11
|
attr_reader :elements
|
12
12
|
|
13
|
+
##
|
14
|
+
# @see SoberSwag::Nodes::Array#map
|
15
|
+
#
|
13
16
|
def map(&block)
|
14
17
|
self.class.new(elements.map { |elem| elem.map(&block) })
|
15
18
|
end
|
16
19
|
|
20
|
+
##
|
21
|
+
# @see SoberSwag::Nodes::Array#cata
|
22
|
+
#
|
23
|
+
# The block will be called with each element contained in this array node in turn, then called with a {SoberSwag::Nodes::Array} constructed
|
24
|
+
# from the resulting values.
|
25
|
+
#
|
26
|
+
# @return whatever the block yields.
|
17
27
|
def cata(&block)
|
18
28
|
block.call(self.class.new(elements.map { |elem| elem.cata(&block) }))
|
19
29
|
end
|
20
30
|
|
31
|
+
##
|
32
|
+
# Deconstructs into the elements.
|
33
|
+
#
|
34
|
+
# @return [Array<SoberSwag::Nodes::Base>]
|
21
35
|
def deconstruct
|
22
36
|
@elements
|
23
37
|
end
|
24
38
|
|
39
|
+
##
|
40
|
+
# Deconstruction for pattern-matching
|
41
|
+
#
|
42
|
+
# @return [Hash{Symbol => ::Array<SoberSwag::Nodes::Base>}]
|
43
|
+
# a hash with the elements in the `:elements` key.
|
25
44
|
def deconstruct_keys(_keys)
|
26
45
|
{ elements: @elements }
|
27
46
|
end
|
@@ -1,8 +1,16 @@
|
|
1
1
|
module SoberSwag
|
2
2
|
module Nodes
|
3
3
|
##
|
4
|
-
#
|
4
|
+
# This is a node for one attribute of an object.
|
5
|
+
# An object type is represented by a `SoberSwag::Nodes::Object` full of these keys.
|
6
|
+
#
|
7
|
+
#
|
5
8
|
class Attribute < Base
|
9
|
+
##
|
10
|
+
# @param key [Symbol] the key of this attribute
|
11
|
+
# @param required [Boolean] if this attribute must be set or not
|
12
|
+
# @param value [Class] the type of this attribute
|
13
|
+
# @param meta [Hash] the metadata associated with this attribute
|
6
14
|
def initialize(key, required, value, meta = {})
|
7
15
|
@key = key
|
8
16
|
@required = required
|
@@ -10,22 +18,55 @@ module SoberSwag
|
|
10
18
|
@meta = meta
|
11
19
|
end
|
12
20
|
|
21
|
+
##
|
22
|
+
# Deconstruct into the {#key}, {#required}, {#value}, and {#meta} attributes
|
23
|
+
# of this {Attribute} object.
|
24
|
+
#
|
25
|
+
# @return [Array(Symbol, Boolean, Class, Hash)] the attributes of this object
|
13
26
|
def deconstruct
|
14
27
|
[key, required, value, meta]
|
15
28
|
end
|
16
29
|
|
17
|
-
|
30
|
+
##
|
31
|
+
# Deconstructs into {#key}, {#required}, {#value}, and {#meta} attributes, as a
|
32
|
+
# hash with the attribute names as the keys.
|
33
|
+
#
|
34
|
+
# @param _keys [void] ignored
|
35
|
+
# @return [Hash] the attributes as keys.
|
36
|
+
def deconstruct_keys(_keys)
|
18
37
|
{ key: key, required: required, value: value, meta: meta }
|
19
38
|
end
|
20
39
|
|
21
|
-
|
40
|
+
##
|
41
|
+
# @return [Symbol]
|
42
|
+
attr_reader :key
|
22
43
|
|
44
|
+
##
|
45
|
+
# @return [Boolean] true if this attribute must be set, false otherwise.
|
46
|
+
attr_reader :required
|
47
|
+
|
48
|
+
##
|
49
|
+
# @return [Class] the type of this attribute
|
50
|
+
attr_reader :value
|
51
|
+
|
52
|
+
##
|
53
|
+
# @return [Hash] the metadata for this attribute.
|
54
|
+
attr_reader :meta
|
55
|
+
|
56
|
+
##
|
57
|
+
# @see SoberSwag::Nodes::Base#map
|
23
58
|
def map(&block)
|
24
59
|
self.class.new(key, required, value.map(&block), meta)
|
25
60
|
end
|
26
61
|
|
62
|
+
##
|
63
|
+
# @see SoberSwag::Nodes::Base#cata
|
27
64
|
def cata(&block)
|
28
|
-
block.call(
|
65
|
+
block.call(
|
66
|
+
self.class.new(
|
67
|
+
key, required, value.cata(&block), meta
|
68
|
+
)
|
69
|
+
)
|
29
70
|
end
|
30
71
|
end
|
31
72
|
end
|