paradocs 1.0.24 → 1.1.4
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/.readthedocs.yml +5 -0
- data/README.md +1 -11
- data/docs/changelog.md +17 -0
- data/docs/custom_configuration.md +10 -0
- data/docs/documentation_generation.md +304 -0
- data/docs/faq.md +21 -0
- data/docs/form_objects_dsl.md +90 -0
- data/docs/index.md +106 -0
- data/docs/payload_builder.md +105 -0
- data/docs/policies.md +309 -0
- data/docs/schema.md +294 -0
- data/docs/struct.md +135 -0
- data/docs/subschema.md +29 -0
- data/lib/paradocs/extensions/payload_builder.rb +45 -0
- data/lib/paradocs/extensions/structure.rb +119 -0
- data/lib/paradocs/field_dsl.rb +12 -0
- data/lib/paradocs/schema.rb +32 -10
- data/lib/paradocs/struct.rb +1 -0
- data/lib/paradocs/version.rb +1 -1
- data/mkdocs.yml +17 -0
- data/paradocs.gemspec +3 -3
- data/requirements.txt +1 -0
- data/spec/extensions/payload_builder_spec.rb +70 -0
- data/spec/extensions/structures_spec.rb +250 -0
- data/spec/field_spec.rb +1 -1
- data/spec/schema_spec.rb +7 -7
- data/spec/struct_spec.rb +8 -8
- data/spec/subschema_spec.rb +4 -4
- metadata +29 -12
- data/lib/paradocs/extensions/insides.rb +0 -77
- data/spec/schema_structures_spec.rb +0 -169
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9ed12715c0df054876f622c3dada9cc4a2d8fd5
|
4
|
+
data.tar.gz: bfe8c1cb2eb4aa9f15eb08349425611deccb3517
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9d827bf00b03d7766600e438d8ee16a9938ab099cd807d0d236cfb37758d104d76f26fdf713c7f39c550ce65df56c30b4dcfbeedb5fa7c5ebc93fa67c66199d
|
7
|
+
data.tar.gz: c4ac5998e89948246c01b6ec04d39ce5332c66da32902ac2b63a06672746dc002a91dc013372bc4cb33410a72e15c1de85bfb08aab8a17659dc9da84f4c793b5
|
data/.readthedocs.yml
ADDED
data/README.md
CHANGED
@@ -37,14 +37,4 @@ form.errors # => {}
|
|
37
37
|
```
|
38
38
|
|
39
39
|
## Learn more
|
40
|
-
|
41
|
-
- [Built In Policies](https://github.com/mtkachenk0/paradocs/wiki/Policies#built-in-policies)
|
42
|
-
- [Type Policies](https://github.com/mtkachenk0/paradocs/wiki/Policies#type-coercions)
|
43
|
-
- [Presence Policies](https://github.com/mtkachenk0/paradocs/wiki/Policies#presence-policies)
|
44
|
-
- [Custom Policies](https://github.com/mtkachenk0/paradocs/wiki/Policies#custom-policies)
|
45
|
-
- [Schema](https://github.com/mtkachenk0/paradocs/wiki/schema)
|
46
|
-
- [Expanding fields dynamically](https://github.com/mtkachenk0/paradocs/wiki/schema#expanding-fields-dynamically)
|
47
|
-
- [Multiple schema definitions](https://github.com/mtkachenk0/paradocs/wiki/schema#multiple-schema-definitions)
|
48
|
-
- [Documentation Generation](https://github.com/mtkachenk0/paradocs/wiki/Documentation-Generation)
|
49
|
-
- [What if my fields are conditional?!](https://github.com/mtkachenk0/paradocs/wiki/subschema)
|
50
|
-
- [For those who need more: RTFM](https://github.com/mtkachenk0/paradocs/wiki)
|
40
|
+
Please read the [documentation](https://paradocs.readthedocs.io/en/latest)
|
data/docs/changelog.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## 1.1.2
|
4
|
+
- Regenerate structures each time without saving them into instance attributes.
|
5
|
+
|
6
|
+
## 1.1.1
|
7
|
+
- Fixed bug with missing `errors` meta key in `Structure#all_nested` and `Structure#all_flatten` methods.
|
8
|
+
- Fixed bug with absent `nested_name` meta key in `#Structure#all_nested` method.
|
9
|
+
- Added opportunity to sort generated by `PayloadBuilder` payload in the way it is described in schema.
|
10
|
+
|
11
|
+
## 1.1.0
|
12
|
+
> `Schema#structure` is not comptatible with previous versions
|
13
|
+
|
14
|
+
- Added `Paradocs::Extensions::StructureBuilder`. See [more](payload_builder)
|
15
|
+
- `Parardocs::Extensions::Structure` has replaced `Paradocs::Extensions::Insides` and changed `Schema#structure` behavior
|
16
|
+
- `Paradocs::Extensions::Structure` got more structure generation methods. See [Documentation Generation](documentation_generation)
|
17
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# Configuration
|
2
|
+
```rb
|
3
|
+
Paradocs.configure do |config|
|
4
|
+
config.explicit_errors = false # set to true if you want all errors from the policies to be explicitly registered in the policy
|
5
|
+
config.whitelisted_keys = [] # enrich it with global white-listed keys if you use WhiteList feature
|
6
|
+
config.default_schema_name = :schema # this name will be set for unnamed schemas
|
7
|
+
config.meta_prefix = "_" # used in #structure and #flatten_structure methods. All the metadata will be prefixed with this prefix.
|
8
|
+
config.whitelist_coercion = nil # set up a Proc here, that receives |value, field.meta| for each whitelisted field in order to enrich the whitelisting logic.
|
9
|
+
end
|
10
|
+
```
|
@@ -0,0 +1,304 @@
|
|
1
|
+
# Documentation Generation
|
2
|
+
|
3
|
+
A `Schema` instance has a `#structure` method that return `Paradocs::Extensions::Structure` instance that allows instrospecting schema meta data.
|
4
|
+
|
5
|
+
It's supposed to have the following schema:
|
6
|
+
```ruby
|
7
|
+
schema = Paradocs::Schema.new do
|
8
|
+
field(:data).type(:object).present.schema do
|
9
|
+
field(:id).type(:integer).present.policy(:policy_with_error)
|
10
|
+
field(:name).type(:string).meta(label: "very important staff")
|
11
|
+
field(:role).type(:string).declared.options(["admin", "user"]).default("user").mutates_schema! do |*|
|
12
|
+
:test_subschema
|
13
|
+
end
|
14
|
+
field(:extra).type(:array).required.schema do
|
15
|
+
field(:extra).declared.default(false).policy(:policy_with_silent_error)
|
16
|
+
end
|
17
|
+
|
18
|
+
mutation_by!(:name) { :subschema }
|
19
|
+
|
20
|
+
subschema(:subschema) do
|
21
|
+
field(:test_field).present
|
22
|
+
end
|
23
|
+
subschema(:test_subschema) do
|
24
|
+
field(:test1).present
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
## Structure#nested
|
31
|
+
> This method returns schema structure in a nested way including subschemes.
|
32
|
+
```ruby
|
33
|
+
schema.structure.nested.to_json # =>
|
34
|
+
{
|
35
|
+
"_errors": ["ArgumentError"],
|
36
|
+
"_subschemes": {},
|
37
|
+
"data": {
|
38
|
+
"type": "object",
|
39
|
+
"required": true,
|
40
|
+
"present": true,
|
41
|
+
"json_path": "$.data",
|
42
|
+
"nested_name": "data",
|
43
|
+
"structure": {
|
44
|
+
"_subschemes": {
|
45
|
+
"subschema": {
|
46
|
+
"_errors": [],
|
47
|
+
"_subschemes": {},
|
48
|
+
"test_field": {
|
49
|
+
"required": true,
|
50
|
+
"present": true,
|
51
|
+
"json_path": "$.data.test_field",
|
52
|
+
"nested_name": "data.test_field"
|
53
|
+
}
|
54
|
+
},
|
55
|
+
"test_subschema": {
|
56
|
+
"_errors": [],
|
57
|
+
"_subschemes": {},
|
58
|
+
"test1": {
|
59
|
+
"required": true,
|
60
|
+
"present": true,
|
61
|
+
"json_path": "$.data.test1",
|
62
|
+
"nested_name": "data.test1"
|
63
|
+
}
|
64
|
+
}
|
65
|
+
},
|
66
|
+
"id": {
|
67
|
+
"type": "integer",
|
68
|
+
"required": true,
|
69
|
+
"present": true,
|
70
|
+
"policy_with_error": {"errors": ["ArgumentError"]},
|
71
|
+
"json_path": "$.data.id",
|
72
|
+
"nested_name": "data.id"
|
73
|
+
},
|
74
|
+
"name": {
|
75
|
+
"type": "string",
|
76
|
+
"label": "very important staff",
|
77
|
+
"json_path": "$.data.name",
|
78
|
+
"mutates_schema": true,
|
79
|
+
"nested_name": "data.name"
|
80
|
+
},
|
81
|
+
"role": {
|
82
|
+
"type": "string",
|
83
|
+
"options": ["admin", "user"],
|
84
|
+
"default": "user",
|
85
|
+
"json_path": "$.data.role",
|
86
|
+
"mutates_schema": true,
|
87
|
+
"nested_name": "data.role"
|
88
|
+
},
|
89
|
+
"extra": {
|
90
|
+
"type": "array",
|
91
|
+
"required": true,
|
92
|
+
"json_path": "$.data.extra[]",
|
93
|
+
"nested_name": "data.extra",
|
94
|
+
"structure": {
|
95
|
+
"_subschemes": {},
|
96
|
+
"extra": {
|
97
|
+
"default": false,
|
98
|
+
"policy_with_silent_error": {"errors": []},
|
99
|
+
"json_path": "$.data.extra[].extra",
|
100
|
+
"nested_name": "data.extra.extra"
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
107
|
+
```
|
108
|
+
|
109
|
+
## Structure#flatten
|
110
|
+
> This method returns schema structure in a flatten (without deep nesting) way including subschemes.
|
111
|
+
```rb
|
112
|
+
schema.structure.flatten.to_json # =>
|
113
|
+
{
|
114
|
+
"_errors": ["ArgumentError"],
|
115
|
+
"_subschemes": {
|
116
|
+
"subschema": {
|
117
|
+
"_errors": [],
|
118
|
+
"_subschemes": {},
|
119
|
+
"data.test_field": {
|
120
|
+
"required": true,
|
121
|
+
"present": true,
|
122
|
+
"json_path": "$.data.test_field"
|
123
|
+
}
|
124
|
+
},
|
125
|
+
"test_subschema": {
|
126
|
+
"_errors": [],
|
127
|
+
"_subschemes": {},
|
128
|
+
"data.test1": {
|
129
|
+
"required": true,
|
130
|
+
"present": true,
|
131
|
+
"json_path": "$.data.test1"
|
132
|
+
}
|
133
|
+
}
|
134
|
+
},
|
135
|
+
"data": {
|
136
|
+
"type": "object",
|
137
|
+
"required": true,
|
138
|
+
"present": true,
|
139
|
+
"json_path": "$.data"
|
140
|
+
},
|
141
|
+
"data.id": {
|
142
|
+
"type": "integer",
|
143
|
+
"required": true,
|
144
|
+
"present": true,
|
145
|
+
"policy_with_error": {"errors": ["ArgumentError"]},
|
146
|
+
"json_path": "$.data.id"
|
147
|
+
},
|
148
|
+
"data.name": {
|
149
|
+
"type": "string",
|
150
|
+
"label": "very important staff",
|
151
|
+
"json_path": "$.data.name",
|
152
|
+
"mutates_schema": true
|
153
|
+
},
|
154
|
+
"data.role": {
|
155
|
+
"type": "string",
|
156
|
+
"options": ["admin", "user"],
|
157
|
+
"default": "user",
|
158
|
+
"json_path": "$.data.role",
|
159
|
+
"mutates_schema": true
|
160
|
+
},
|
161
|
+
"data.extra": {
|
162
|
+
"type": "array",
|
163
|
+
"required": true,
|
164
|
+
"json_path": "$.data.extra[]"
|
165
|
+
},
|
166
|
+
"data.extra.extra": {
|
167
|
+
"default": false,
|
168
|
+
"policy_with_silent_error": {"errors": []},
|
169
|
+
"json_path": "$.data.extra[].extra"
|
170
|
+
}
|
171
|
+
}
|
172
|
+
```
|
173
|
+
|
174
|
+
|
175
|
+
## Structure#all_nested
|
176
|
+
|
177
|
+
> This method returns all available combinations of schema (built on subschemas) saving the nesting.
|
178
|
+
|
179
|
+
Will return a hash with 2 structures named by the names of declared subschemas:
|
180
|
+
```rb
|
181
|
+
all_nested = schema.structure.all_nested
|
182
|
+
all_nested.keys # => [:subschema, :test_subschema]
|
183
|
+
all_nested[:subschema] # =>
|
184
|
+
{
|
185
|
+
_errors: [],
|
186
|
+
"data" => {
|
187
|
+
type: :object,
|
188
|
+
required: true,
|
189
|
+
present: true,
|
190
|
+
json_path: "$.data",
|
191
|
+
nested_name: "data",
|
192
|
+
structure: {
|
193
|
+
"role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true, nested_name: "data.role"},
|
194
|
+
"test_field" => {required: true, present: true, json_path: "$.data.test_field", nested_name: "data.test_field"},
|
195
|
+
"id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id", nested_name: "data.id"},
|
196
|
+
"name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true, nested_name: "data.name"},
|
197
|
+
"extra" => {
|
198
|
+
type: :array, required: true, json_path: "$.data.extra[]", nested_name: "data.extra",
|
199
|
+
structure: {"extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra", nested_name: "data.extra.extra"}}
|
200
|
+
}
|
201
|
+
}
|
202
|
+
}
|
203
|
+
}
|
204
|
+
all_nested[:test_subschema] # =>
|
205
|
+
{
|
206
|
+
_errors: [],
|
207
|
+
"data" => {
|
208
|
+
type: :object,
|
209
|
+
required: true,
|
210
|
+
present: true,
|
211
|
+
json_path: "$.data",
|
212
|
+
nested_name: "data",
|
213
|
+
structure: {
|
214
|
+
"role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true, nested_name: "data.role"},
|
215
|
+
"test1" => {required: true, present: true, json_path: "$.data.test1", nested_name: "data.test1"},
|
216
|
+
"id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id", nested_name: "data.id"},
|
217
|
+
"name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true, nested_name: "data.name"},
|
218
|
+
"extra" => {
|
219
|
+
type: :array, required: true, json_path: "$.data.extra[]", nested_name: "data.extra",
|
220
|
+
structure: {"extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra", nested_name: "data.extra.extra"}}
|
221
|
+
}
|
222
|
+
}
|
223
|
+
}
|
224
|
+
}
|
225
|
+
```
|
226
|
+
|
227
|
+
## Structure#all_flatten
|
228
|
+
> This method returns all available combinations of schema (built on subschema) without nesting (the same way as Structure#flatten method does)
|
229
|
+
|
230
|
+
Schema is the same as described in `Structure#all_nested`
|
231
|
+
```rb
|
232
|
+
schema.structure.all_flatten # =>
|
233
|
+
{
|
234
|
+
subschema: {
|
235
|
+
_errors: [],
|
236
|
+
"data" => {type: :object, required: true, present: true, json_path: "$.data", nested_name: "data"},
|
237
|
+
"data.id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id", nested_name: "data.id"},
|
238
|
+
"data.name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true, nested_name: "data.name"},
|
239
|
+
"data.role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true, nested_name: "data.role"},
|
240
|
+
"data.extra" => {type: :array, required: true, json_path: "$.data.extra[]", nested_name: "data.extra"},
|
241
|
+
"data.extra.extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra", nested_name: "data.extra.extra"},
|
242
|
+
"data.test_field" => {required: true, present: true, json_path: "$.data.test_field", nested_name: "data.test_field"}
|
243
|
+
},
|
244
|
+
test_subschema: {
|
245
|
+
_errors: [],
|
246
|
+
"data" => {type: :object, required: true, present: true, json_path: "$.data", nested_name: "data"},
|
247
|
+
"data.id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id", nested_name: "data.id"},
|
248
|
+
"data.name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true, nested_name: "data.name"},
|
249
|
+
"data.role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true, nested_name: "data.role"},
|
250
|
+
"data.extra" => {type: :array, required: true, json_path: "$.data.extra[]", nested_name: "data.extra"},
|
251
|
+
"data.extra.extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra", nested_name: "data.extra.extra"},
|
252
|
+
"data.test1" => {required: true, present: true, json_path: "$.data.test1", nested_name: "data.test1"}
|
253
|
+
}
|
254
|
+
}
|
255
|
+
```
|
256
|
+
|
257
|
+
## Passing a block
|
258
|
+
Given block to the methods above (`#flatten`, `#nested`, `#all_flatten`, `#all_nested`) will be executed for
|
259
|
+
each field, passing you as arguments `field.key` and `field.meta`. Mutating the second argument `field.meta`
|
260
|
+
will reflect onto returned `meta`.
|
261
|
+
|
262
|
+
## Schema#walk
|
263
|
+
|
264
|
+
The `#walk` method can recursively walk a schema definition and extract meta data or field attributes.
|
265
|
+
|
266
|
+
```ruby
|
267
|
+
schema_documentation = create_user_schema.walk do |field|
|
268
|
+
{type: field.meta_data[:type], label: field.meta_data[:label]}
|
269
|
+
end.output
|
270
|
+
|
271
|
+
# Returns
|
272
|
+
|
273
|
+
{
|
274
|
+
name: {type: :string, label: "User's full name"},
|
275
|
+
age: {type: :integer, label: "User's age"},
|
276
|
+
status: {type: :string, label: nil},
|
277
|
+
friends: [
|
278
|
+
{
|
279
|
+
name: {type: :string, label: "Friend full name"},
|
280
|
+
email: {type: nil, label: "Friend email"}
|
281
|
+
}
|
282
|
+
]
|
283
|
+
}
|
284
|
+
```
|
285
|
+
|
286
|
+
When passed a _symbol_, it will collect that key from field meta data.
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
schema_labels = create_user_schema.walk(:label).output
|
290
|
+
|
291
|
+
# returns
|
292
|
+
|
293
|
+
{
|
294
|
+
name: "User's full name",
|
295
|
+
age: "User's age",
|
296
|
+
status: nil,
|
297
|
+
friends: [
|
298
|
+
{name: "Friend full name", email: "Friend email"}
|
299
|
+
]
|
300
|
+
}
|
301
|
+
```
|
302
|
+
|
303
|
+
Potential uses for this are generating documentation (HTML, or [JSON Schema](http://json-schema.org/), [Swagger](http://swagger.io/), or maybe even mock API endpoints with example data.
|
304
|
+
|
data/docs/faq.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# FAQ
|
2
|
+
## Defaults
|
3
|
+
### Q: I need the child schema to be enriched with the specified defaults is parent key is absent.
|
4
|
+
```rb
|
5
|
+
schema do
|
6
|
+
field(:top_level).type(:string).required.default('top_level')
|
7
|
+
field(:nested).type(:object).required.schema do
|
8
|
+
field(:start_date).type(:datetime).required.default(->(a,b,c) { Time.now })
|
9
|
+
field(:ends_after).type(:integer).required.default(5)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
# usage
|
13
|
+
TestSchema.schema.resolve({}).output # => {:top_level=>"top_level", :nested=>nil, :configurations=>nil}
|
14
|
+
TestSchema.schema.resolve({nested: {}}).output # => {:top_level=>"top_level", :nested=>{:start_date=>#<DateTime: 2020-08-31T15:36:43+02:00 ((2459093j,49003s,0n),+7200s,2299161j)>, :ends_after=>5}, :configurations=>nil}
|
15
|
+
# I want resolving on {} to include the :nested structure.
|
16
|
+
```
|
17
|
+
|
18
|
+
### A: Set `.default({})` to your `:nested` field.
|
19
|
+
> Fields from nested schema are invoked only when the object for the schema exists.
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# Form objects DSL
|
2
|
+
|
3
|
+
## DSL
|
4
|
+
You can use schemas and fields on their own, or include the `DSL` module in your own classes to define form objects.
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
require "parametric/dsl"
|
8
|
+
|
9
|
+
class CreateUserForm
|
10
|
+
include Paradocs::DSL
|
11
|
+
|
12
|
+
schema(:test) do
|
13
|
+
field(:name).type(:string).required
|
14
|
+
field(:email).policy(:email).required
|
15
|
+
field(:age).type(:integer)
|
16
|
+
subschema_by(:age) { |age| age > 18 ? :allow : :deny }
|
17
|
+
end
|
18
|
+
|
19
|
+
subschema_for(:test, name: :allow) { field(:role).options(["sign_in"]) }
|
20
|
+
subschema_for(:test, name: :deny) { field(:role).options([]) }
|
21
|
+
|
22
|
+
attr_reader :params, :errors
|
23
|
+
|
24
|
+
def initialize(input_data)
|
25
|
+
results = self.class.schema.resolve(input_data)
|
26
|
+
@params = results.output
|
27
|
+
@errors = results.errors
|
28
|
+
end
|
29
|
+
|
30
|
+
def run!
|
31
|
+
if !valid?
|
32
|
+
raise InvalidFormError.new(errors)
|
33
|
+
end
|
34
|
+
|
35
|
+
run
|
36
|
+
end
|
37
|
+
|
38
|
+
def valid?
|
39
|
+
!errors.any?
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def run
|
45
|
+
User.create!(params)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Form schemas can also be defined by passing another form or schema instance. This can be useful when building form classes in runtime.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
UserSchema = Paradocs::Schema.new do
|
54
|
+
field(:name).type(:string).present
|
55
|
+
field(:age).type(:integer)
|
56
|
+
end
|
57
|
+
|
58
|
+
class CreateUserForm
|
59
|
+
include Paradocs::DSL
|
60
|
+
# copy from UserSchema
|
61
|
+
schema UserSchema
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
## Form object inheritance
|
66
|
+
|
67
|
+
Sub classes of classes using the DSL will inherit schemas defined on the parent class.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
class UpdateUserForm < CreateUserForm
|
71
|
+
# All field definitions in the parent are conserved.
|
72
|
+
# New fields can be defined
|
73
|
+
# or existing fields overriden
|
74
|
+
schema do
|
75
|
+
# make this field optional
|
76
|
+
field(:name).declared.present
|
77
|
+
end
|
78
|
+
|
79
|
+
def initialize(user, input_data)
|
80
|
+
super input_data
|
81
|
+
@user = user
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def run
|
86
|
+
@user.update params
|
87
|
+
end
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|