paradocs 1.1.0 → 1.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0df2185fac7b1e70254c9531622e135c6609f309
4
- data.tar.gz: 701ec92673e9044bc8a8384e251276aa7863d37e
3
+ metadata.gz: ba77710f31f4b6d12c2c764807c1274a7409e18f
4
+ data.tar.gz: 79e70eed1f40fbc5b2c7fab32b935ecee813b7b8
5
5
  SHA512:
6
- metadata.gz: aa14905a01be3d1d54589aabc53fbc2f14d3a17352742a9eece1e76b324f146d94f5860ae4f59d738007e809c1fb0eb3ae95579d2a8237798e80a7a6f43ff2b9
7
- data.tar.gz: 0c5fedee64178f630d403db573b2d8a4e2e4bc44b88e65df636c88aa1d9857836267d77ed34a1236036ff97bb105e37252f4948d46fcdc600850e682a5db082d
6
+ metadata.gz: 2365143b9765af228b14ed88105837d34fdba6b3da914e7cf71750e6bea120d6418767b7cd94678480b97ab7735af049129c3c180a6f46d7d590630d09f0d490
7
+ data.tar.gz: eae4b0b0593f473ac51fc5214bef19c8571490cde4a63b6274a755fc81c1099c226030eaeec56eb15eb91e4263062c57d0c31bf7c50bd01038ef3371c7382031
data/README.md CHANGED
@@ -37,14 +37,4 @@ form.errors # => {}
37
37
  ```
38
38
 
39
39
  ## Learn more
40
- - [Getting Started](https://github.com/mtkachenk0/paradocs/wiki/Getting-Started)
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)
@@ -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
+
@@ -188,12 +188,16 @@ all_nested[:subschema] # =>
188
188
  required: true,
189
189
  present: true,
190
190
  json_path: "$.data",
191
+ nested_name: "data",
191
192
  structure: {
192
- "role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true},
193
- "extra" => {type: :array, required: true, json_path: "$.data.extra[]", structure: {"extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra"}}},
194
- "test_field" => {required: true, present: true, json_path: "$.data.test_field"},
195
- "id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id"},
196
- "name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true}
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
+ }
197
201
  }
198
202
  }
199
203
  }
@@ -205,12 +209,16 @@ all_nested[:test_subschema] # =>
205
209
  required: true,
206
210
  present: true,
207
211
  json_path: "$.data",
212
+ nested_name: "data",
208
213
  structure: {
209
- "role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true},
210
- "extra" => {type: :array, required: true, json_path: "$.data.extra[]", structure: {"extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra"}}},
211
- "test1" => {required: true, present: true, json_path: "$.data.test1"},
212
- "id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id"},
213
- "name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true}
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
+ }
214
222
  }
215
223
  }
216
224
  }
@@ -219,33 +227,38 @@ all_nested[:test_subschema] # =>
219
227
  ## Structure#all_flatten
220
228
  > This method returns all available combinations of schema (built on subschema) without nesting (the same way as Structure#flatten method does)
221
229
 
222
- Schema is the same as described in Structure#all_nested
230
+ Schema is the same as described in `Structure#all_nested`
223
231
  ```rb
224
232
  schema.structure.all_flatten # =>
225
233
  {
226
234
  subschema: {
227
235
  _errors: [],
228
- "data" => {type: :object, required: true, present: true, json_path: "$.data"},
229
- "data.id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id"},
230
- "data.name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true},
231
- "data.role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true},
232
- "data.extra" => {type: :array, required: true, json_path: "$.data.extra[]"},
233
- "data.extra.extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra"},
234
- "data.test_field" => {required: true, present: true, json_path: "$.data.test_field"}
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"}
235
243
  },
236
244
  test_subschema: {
237
245
  _errors: [],
238
- "data" => {type: :object, required: true, present: true, json_path: "$.data"},
239
- "data.id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id"},
240
- "data.name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true},
241
- "data.role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true},
242
- "data.extra" => {type: :array, required: true, json_path: "$.data.extra[]"},
243
- "data.extra.extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra"},
244
- "data.test1" => {required: true, present: true, json_path: "$.data.test1"}
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"}
245
253
  }
246
254
  }
247
255
  ```
248
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
+
249
262
  ## Schema#walk
250
263
 
251
264
  The `#walk` method can recursively walk a schema definition and extract meta data or field attributes.
@@ -1,9 +1,8 @@
1
1
  # Generate examples from the Schema
2
2
 
3
- > Schema instance provides #example_payloads method that returns example of all possible structures.
3
+ > `Schema` instance provides `#example_payloads` method that returns example of all possible structures.
4
4
 
5
- NOTE: PayloadBuilder sets nil values by default. If options are given - builder will take on of them, if default is set - builder will use it.
6
- > PayloadBuilder#build! method takes a block as argument that may help you adding your custom rules.
5
+ NOTE: `PayloadBuilder` sets nil values by default. If options are given - builder will take on of them, if default is set - builder will use it.
7
6
 
8
7
  #### Example schema
9
8
  ```ruby
@@ -59,12 +58,14 @@ schema.example_payloads.to_json # =>
59
58
  ```
60
59
 
61
60
  ## Customize payload generation logic
62
- PayloadBuilder#build! allows passing a block that will receive the following arguments:
61
+ `PayloadBuilder#build!` arguments:
63
62
 
64
- - key: Field name
65
- - meta: Field meta data (that includes (if provided) field types, presence data, policies and other meta data
66
- - example_value: Provided by generator example value.
67
- - skip_word: Return this argument back if you want this item to be ommitted.
63
+ 1. `sort_by_schema: true` will try to return payload in the same way as declared in the schema.
64
+ 2. `&block` will be executed for each key receiving the following arguments:
65
+ - `key`: Field name
66
+ - `meta`: Field meta data (that includes (if provided) field types, presence data, policies and other meta data
67
+ - `example_value`: Provided by generator example value.
68
+ - `skip_word`: Return this argument back if you want this item to be ommitted.
68
69
 
69
70
  ```rb
70
71
  block = Proc.new do |key, meta, example, skip_word|
@@ -73,16 +73,6 @@ module Paradocs
73
73
  end
74
74
  end
75
75
 
76
- Paradocs.policy :split do
77
- coerce do |v, k, c|
78
- v.kind_of?(Array) ? v : v.to_s.split(/\s*,\s*/)
79
- end
80
-
81
- meta_data do
82
- {type: :array}
83
- end
84
- end
85
-
86
76
  Paradocs.policy :datetime do
87
77
  coerce do |v, k, c|
88
78
  DateTime.parse(v.to_s)
@@ -8,8 +8,9 @@ module Paradocs
8
8
  @skip_word = skip_word
9
9
  end
10
10
 
11
- def build!(&block)
12
- structure.all_nested.map { |name, struct| [name, build_simple_structure(struct, &block)] }.to_h
11
+ def build!(sort_by_schema: false, &block)
12
+ result = structure.all_nested.map { |name, struct| [name, build_simple_structure(struct, &block)] }.to_h
13
+ sort_by_schema ? schema.resolve(result).output : result
13
14
  end
14
15
 
15
16
  private
@@ -20,7 +21,8 @@ module Paradocs
20
21
  next if key.start_with?(Paradocs.config.meta_prefix) # skip all the meta fields
21
22
  ex_value = restore_one(key, value, &block)
22
23
  next if ex_value == @skip_word
23
- [key, ex_value]
24
+ key = value[:alias] || key
25
+ [key.to_s, ex_value]
24
26
  end.compact.to_h
25
27
  end
26
28
 
@@ -14,12 +14,8 @@ module Paradocs
14
14
  @root = root
15
15
  end
16
16
 
17
- def flush!
18
- @nested, @all_nested, @flatten, @all_flatten = [nil] * 4
19
- end
20
-
21
17
  def nested(&block)
22
- @nested ||= schema.fields.each_with_object({errors => [], subschemes => {}}) do |(_, field), result|
18
+ schema.fields.each_with_object({errors => [], subschemes => {}}) do |(_, field), result|
23
19
  meta, sc = collect_meta(field, root)
24
20
  if sc
25
21
  meta[:structure] = self.class.new(sc, ignore_transparent, meta[:json_path]).nested(&block)
@@ -27,8 +23,10 @@ module Paradocs
27
23
  else
28
24
  result[errors] += field.possible_errors
29
25
  end
30
- result[field.key] = meta unless ignore_transparent && field.transparent?
31
- yield(field.key, meta) if block_given?
26
+
27
+ field_key = field.meta_data[:alias] || field.key
28
+ result[field_key] = meta unless ignore_transparent && field.transparent?
29
+ yield(field_key, meta) if block_given?
32
30
 
33
31
  next unless field.mutates_schema?
34
32
  schema.subschemes.each do |name, subschema|
@@ -39,12 +37,13 @@ module Paradocs
39
37
  end
40
38
 
41
39
  def all_nested(&block)
42
- @all_nested ||= all_flatten(&block).each_with_object({}) do |(name, struct), obj|
40
+ all_flatten(&block).each_with_object({}) do |(name, struct), obj|
43
41
  obj[name] = {}
44
42
  # sort the flatten struct to have iterated 1lvl keys before 2lvl and so on...
45
43
  struct.sort_by { |k, v| k.to_s.count(".") }.each do |key, value|
46
44
  target = obj[name]
47
45
  key, value = key.to_s, value.clone # clone the values, because we do mutation below
46
+ value.merge!(nested_name: key) if value.respond_to?(:merge) # it can be array (_errors)
48
47
  next target[key.to_sym] = value if key.start_with?(Paradocs.config.meta_prefix) # copy meta fields
49
48
 
50
49
  parts = key.split(".")
@@ -60,17 +59,18 @@ module Paradocs
60
59
  end
61
60
 
62
61
  def all_flatten(schema_structure=nil, &block)
63
- return @all_flatten if @all_flatten
64
62
  schema_structure ||= flatten(&block)
65
63
  if schema_structure[subschemes].empty?
66
64
  schema_structure.delete(subschemes) # don't include redundant key
67
- return @all_flatten = {DEFAULT => schema_structure}
65
+ return {DEFAULT => schema_structure}
68
66
  end
69
- @all_flatten = schema_structure[subschemes].each_with_object({}) do |(name, subschema), result|
67
+ schema_structure[subschemes].each_with_object({}) do |(name, subschema), result|
70
68
  if subschema[subschemes].empty?
71
- result[name] = schema_structure.merge(subschema)
72
- result[name].delete(subschemes)
73
- next result[name]
69
+ result[name] = schema_structure.merge(subschema)
70
+ result[name][errors] += schema_structure[errors]
71
+ result[name][errors].uniq!
72
+ result[name].delete(subschemes)
73
+ next result[name]
74
74
  end
75
75
 
76
76
  all_flatten(subschema).each do |sub_name, schema|
@@ -80,7 +80,7 @@ module Paradocs
80
80
  end
81
81
 
82
82
  def flatten(&block)
83
- @flatten ||= schema.fields.each_with_object({errors => [], subschemes => {}}) do |(_, field), obj|
83
+ schema.fields.each_with_object({errors => [], subschemes => {}}) do |(_, field), obj|
84
84
  meta, sc = collect_meta(field, root)
85
85
  humanized_name = meta.delete(:nested_name)
86
86
  obj[humanized_name] = meta unless ignore_transparent && field.transparent?
@@ -105,7 +105,8 @@ module Paradocs
105
105
  private
106
106
 
107
107
  def collect_meta(field, root)
108
- json_path = root.empty? ? "$.#{field.key}" : "#{root}.#{field.key}"
108
+ field_key = field.meta_data[:alias] || field.key
109
+ json_path = root.empty? ? "$.#{field_key}" : "#{root}.#{field_key}"
109
110
  meta = field.meta_data.merge(json_path: json_path)
110
111
  sc = meta.delete(:schema)
111
112
  meta[:mutates_schema] = true if meta.delete(:mutates_schema)
@@ -32,5 +32,17 @@ module Paradocs
32
32
  def length(opts)
33
33
  policy :length, opts
34
34
  end
35
+
36
+ def description(text)
37
+ meta description: text
38
+ end
39
+
40
+ def as(identifier)
41
+ meta alias: identifier
42
+ end
43
+
44
+ def example(value)
45
+ meta example: value
46
+ end
35
47
  end
36
48
  end
@@ -5,7 +5,7 @@ module Paradocs
5
5
  class Format < Paradocs::BasePolicy
6
6
  attr_reader :message
7
7
 
8
- def initialize(fmt, msg = "invalid format")
8
+ def initialize(fmt, msg="invalid format")
9
9
  @message = msg
10
10
  @fmt = fmt
11
11
  end
@@ -18,12 +18,23 @@ module Paradocs
18
18
  !payload.key?(key) || !!(value.to_s =~ @fmt)
19
19
  end
20
20
  end
21
+
22
+ class Split < Paradocs::BasePolicy
23
+ def initialize(delimiter=/\s*,\s*/)
24
+ @delimiter = delimiter
25
+ end
26
+
27
+ def coerce(v, *)
28
+ v.kind_of?(Array) ? v : v.to_s.split(@delimiter)
29
+ end
30
+ end
21
31
  end
22
32
 
23
33
  # Default validators
24
34
  EMAIL_REGEXP = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i.freeze
25
35
 
26
36
  Paradocs.policy :format, Policies::Format
37
+ Paradocs.policy :split, Policies::Split
27
38
  Paradocs.policy :email, Policies::Format.new(EMAIL_REGEXP, 'invalid email')
28
39
 
29
40
  Paradocs.policy :noop do
@@ -181,7 +181,8 @@ module Paradocs
181
181
  invoke_subschemes!(val, context, flds: flds)
182
182
  flds.each_with_object({}) do |(_, field), m|
183
183
  r = field.resolve(val, context.sub(field.key))
184
- m[field.key] = r.value if r.eligible?
184
+ key = field.meta_data[:alias] || field.key
185
+ m[key] = r.value if r.eligible?
185
186
  end
186
187
  end
187
188
 
@@ -57,6 +57,7 @@ module Paradocs
57
57
  # this hook is called after schema definition in DSL module
58
58
  def paradocs_after_define_schema(schema)
59
59
  schema.fields.keys.each do |key|
60
+ key = schema.fields[key].meta_data[:alias] || key
60
61
  define_method key do
61
62
  _graph[key]
62
63
  end
@@ -1,3 +1,3 @@
1
1
  module Paradocs
2
- VERSION = "1.1.0"
2
+ VERSION = "1.1.5"
3
3
  end
data/mkdocs.yml CHANGED
@@ -13,4 +13,5 @@ nav:
13
13
  - 'payload_builder.md'
14
14
  - 'custom_configuration.md'
15
15
  - 'faq.md'
16
+ - 'changelog.md'
16
17
 
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Paradocs::VERSION
9
9
  spec.authors = ["Maxim Tkachenko", "Ismael Celis"]
10
10
  spec.email = ["tkachenko.maxim.w@gmail.com", "ismaelct@gmail.com"]
11
- spec.description = %q{Flexible DSL for declaring allowed parameters focused on DRY validation that gives you opportunity to generate API documentation on-the-fly.}
11
+ spec.description = %q{Flexible DRY validations with API docs generation done right TLDR; parametrics on steroids.}
12
12
  spec.summary = %q{A huge add-on for original gem mostly focused on retrieving the more metadata from declared schemas as possible.}
13
13
  spec.homepage = "https://paradocs.readthedocs.io/en/latest"
14
14
  spec.license = "MIT"
@@ -22,7 +22,7 @@ describe Paradocs::Extensions::PayloadBuilder do
22
22
  end
23
23
  subschema(:fooschema) { }
24
24
  subschema(:barschema) do
25
- field(:barfield).present.type(:boolean)
25
+ field(:barfield).present.type(:boolean).as(:bar_field)
26
26
  end
27
27
  end
28
28
  end
@@ -32,7 +32,7 @@ describe Paradocs::Extensions::PayloadBuilder do
32
32
  allow_any_instance_of(Array).to receive(:sample) { "bar" }
33
33
  payloads = described_class.new(schema).build!
34
34
  expect(payloads.keys.sort).to eq([:barschema, :fooschema, :subschema1, :subschema2_deep_schema, :subschema2_empty])
35
- expect(payloads[:barschema]).to eq({"test" => nil, "foo" => {"bar" => "bar", "barfield" => nil}})
35
+ expect(payloads[:barschema]).to eq({"test" => nil, "foo" => {"bar" => "bar", "bar_field" => nil}})
36
36
  expect(payloads[:fooschema]).to eq({"test" => nil, "foo" => {"bar" => "bar"}})
37
37
  expect(payloads[:subschema1]).to eq({"test" => nil, "foo" => {"bar" => "bar"}, "subtest1" => nil})
38
38
  expect(payloads[:subschema2_deep_schema]).to eq({
@@ -57,7 +57,7 @@ describe Paradocs::Extensions::PayloadBuilder do
57
57
  end
58
58
 
59
59
  expect(payloads.keys.sort).to eq([:barschema, :fooschema, :subschema1, :subschema2_deep_schema, :subschema2_empty])
60
- expect(payloads[:barschema]).to eq({"test" => nil, "foo" => {"bar" => nil, "barfield" => true}}) # barfield is change to true and bar is nil
60
+ expect(payloads[:barschema]).to eq({"test" => nil, "foo" => {"bar" => nil, "bar_field" => true}}) # barfield is change to true and bar is nil
61
61
  expect(payloads[:fooschema]).to eq({"test" => nil, "foo" => {"bar" => nil}}) # bar is nil
62
62
  expect(payloads[:subschema1]).to eq({"test" => nil, "foo" => {"bar" => nil}}) # subtest is missing, bar is nil
63
63
  expect(payloads[:subschema2_deep_schema]).to eq({
@@ -18,8 +18,8 @@ describe Paradocs::Extensions::Structure do
18
18
  subschema(:highest_level) { field(:test).present } # no mutations on this level -> subschema ignored
19
19
 
20
20
  field(:data).type(:object).present.schema do
21
- field(:id).type(:integer).present.policy(:policy_with_error)
22
- field(:name).type(:string).meta(label: "very important staff")
21
+ field(:id).type(:integer).present.policy(:policy_with_error).as(:user_id)
22
+ field(:name).type(:string).meta(label: "very important staff").description("Example description").example("John")
23
23
  field(:role).type(:string).declared.options(["admin", "user"]).default("user").mutates_schema! do |*|
24
24
  :test_subschema
25
25
  end
@@ -64,17 +64,20 @@ describe Paradocs::Extensions::Structure do
64
64
  test_field: {required: true, present: true, json_path: "$.data.test_field", nested_name: "data.test_field"}
65
65
  }
66
66
  })
67
- expect(data_structure[:id]).to eq({
67
+ expect(data_structure[:user_id]).to eq({
68
68
  type: :integer,
69
69
  required: true,
70
70
  present: true,
71
71
  policy_with_error: {errors: [ArgumentError]},
72
- json_path: "$.data.id",
73
- nested_name: "data.id"
72
+ alias: :user_id,
73
+ json_path: "$.data.user_id",
74
+ nested_name: "data.user_id"
74
75
  })
75
76
  expect(data_structure[:name]).to eq({
76
77
  type: :string,
77
78
  label: "very important staff",
79
+ description: "Example description",
80
+ example: "John",
78
81
  mutates_schema: true,
79
82
  block_works: true,
80
83
  json_path: "$.data.name",
@@ -129,17 +132,20 @@ describe Paradocs::Extensions::Structure do
129
132
  json_path: "$.data.extra[].extra",
130
133
  policy_with_silent_error: {errors: []}
131
134
  },
132
- "data.id" => {
135
+ "data.user_id" => {
133
136
  type: :integer,
134
137
  required: true,
135
138
  present: true,
136
- json_path: "$.data.id",
139
+ alias: :user_id,
140
+ json_path: "$.data.user_id",
137
141
  policy_with_error: {errors: [ArgumentError]}
138
142
  },
139
143
  "data.name" => {
140
144
  type: :string,
141
145
  json_path: "$.data.name",
142
146
  label: "very important staff",
147
+ description: "Example description",
148
+ example: "John",
143
149
  mutates_schema: true
144
150
  },
145
151
  "data.role" => {
@@ -174,20 +180,20 @@ describe Paradocs::Extensions::Structure do
174
180
  it "generates N structures, where N = number of unique combinations of applied subschemas" do
175
181
  expect(schema.structure.all_flatten).to eq({
176
182
  subschema: {
177
- _errors: [],
183
+ _errors: [ArgumentError],
178
184
  "data" => {type: :object, required: true, present: true, json_path: "$.data"},
179
- "data.id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id"},
180
- "data.name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true},
185
+ "data.user_id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, alias: :user_id, json_path: "$.data.user_id"},
186
+ "data.name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true, description: "Example description", example: "John"},
181
187
  "data.role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true},
182
188
  "data.extra" => {type: :array, required: true, json_path: "$.data.extra[]"},
183
189
  "data.extra.extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra"},
184
190
  "data.test_field" => {required: true, present: true, json_path: "$.data.test_field"}
185
191
  },
186
192
  test_subschema: {
187
- _errors: [],
193
+ _errors: [ArgumentError],
188
194
  "data" => {type: :object, required: true, present: true, json_path: "$.data"},
189
- "data.id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id"},
190
- "data.name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true},
195
+ "data.user_id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, alias: :user_id, json_path: "$.data.user_id"},
196
+ "data.name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true, description: "Example description", example: "John"},
191
197
  "data.role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true},
192
198
  "data.extra" => {type: :array, required: true, json_path: "$.data.extra[]"},
193
199
  "data.extra.extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra"},
@@ -201,34 +207,41 @@ describe Paradocs::Extensions::Structure do
201
207
  it "generates N structures, where N = number of unique combinations of applied subschemas" do
202
208
  result = schema.structure.all_nested
203
209
  expect(result[:subschema]).to eq({
204
- _errors: [],
210
+ _errors: [ArgumentError],
205
211
  "data" => {
206
- type: :object,
207
- required: true,
208
- present: true,
209
- json_path: "$.data",
212
+ type: :object,
213
+ required: true,
214
+ present: true,
215
+ json_path: "$.data",
216
+ nested_name: "data",
210
217
  structure: {
211
- "role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true},
212
- "extra" => {type: :array, required: true, json_path: "$.data.extra[]", structure: {"extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra"}}},
213
- "test_field" => {required: true, present: true, json_path: "$.data.test_field"},
214
- "id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id"},
215
- "name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true}
218
+ "role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", nested_name: "data.role", mutates_schema: true},
219
+ "test_field" => {required: true, present: true, json_path: "$.data.test_field", nested_name: "data.test_field"},
220
+ "user_id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, alias: :user_id, json_path: "$.data.user_id", nested_name: "data.user_id"},
221
+ "name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true, nested_name: "data.name", description: "Example description", example: "John"},
222
+ "extra" => {
223
+ type: :array, required: true, json_path: "$.data.extra[]", nested_name: "data.extra",
224
+ structure: {"extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra", nested_name: "data.extra.extra"}}
225
+ }
216
226
  }
217
227
  }
218
228
  })
219
229
  expect(result[:test_subschema]).to eq({
220
- _errors: [],
230
+ _errors: [ArgumentError],
221
231
  "data" => {
222
232
  type: :object,
223
233
  required: true,
224
234
  present: true,
225
235
  json_path: "$.data",
236
+ nested_name: "data",
226
237
  structure: {
227
- "role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", mutates_schema: true},
228
- "extra" => {type: :array, required: true, json_path: "$.data.extra[]", structure: {"extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra"}}},
229
- "test1" => {required: true, present: true, json_path: "$.data.test1"},
230
- "id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, json_path: "$.data.id"},
231
- "name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true}
238
+ "role" => {type: :string, options: ["admin", "user"], default: "user", json_path: "$.data.role", nested_name: "data.role", mutates_schema: true},
239
+ "test1" => {required: true, present: true, json_path: "$.data.test1", nested_name: "data.test1"},
240
+ "user_id" => {type: :integer, required: true, present: true, policy_with_error: {errors: [ArgumentError]}, alias: :user_id, json_path: "$.data.user_id", nested_name: "data.user_id"},
241
+ "name" => {type: :string, label: "very important staff", json_path: "$.data.name", mutates_schema: true, nested_name: "data.name", description: "Example description", example: "John"},
242
+ "extra" => {
243
+ type: :array, required: true, json_path: "$.data.extra[]", nested_name: "data.extra",
244
+ structure: {"extra" => {default: false, policy_with_silent_error: {errors: []}, json_path: "$.data.extra[].extra", nested_name: "data.extra.extra"}}}
232
245
  }
233
246
  }
234
247
  })
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Paradocs::Field do
4
- let(:context) { Paradocs::Context.new }
4
+ let(:context) { Paradocs::Context.new }
5
5
 
6
6
  subject { described_class.new(:a_key) }
7
7
 
@@ -16,7 +16,7 @@ describe Paradocs::Schema do
16
16
 
17
17
  subject do
18
18
  described_class.new do
19
- field(:title).policy(:string).present
19
+ field(:title).policy(:string).present.as(:article_title)
20
20
  field(:price).policy(:integer).meta(label: "A price")
21
21
  field(:status).policy(:string).options(['visible', 'hidden'])
22
22
  field(:tags).policy(:split).policy(:array)
@@ -33,8 +33,8 @@ describe Paradocs::Schema do
33
33
  describe "#structure" do
34
34
  it "represents data structure and meta data" do
35
35
  sc = subject.structure.nested
36
- expect(sc[:title][:present]).to be true
37
- expect(sc[:title][:type]).to eq :string
36
+ expect(sc[:article_title][:present]).to be true
37
+ expect(sc[:article_title][:type]).to eq :string
38
38
  expect(sc[:price][:type]).to eq :integer
39
39
  expect(sc[:price][:label]).to eq "A price"
40
40
  expect(sc[:variants][:type]).to eq :array
@@ -76,7 +76,7 @@ describe Paradocs::Schema do
76
76
 
77
77
  output = subject.resolve(payload).output
78
78
  expect(output).to eq({
79
- title: "title",
79
+ article_title: "title",
80
80
  price: 100,
81
81
  status: "visible",
82
82
  tags: ["tag"],
@@ -101,7 +101,7 @@ describe Paradocs::Schema do
101
101
  variants: [{name: 'v1', sku: 'ABC', stock: '10', available_if_no_stock: true}]
102
102
  },
103
103
  {
104
- title: 'iPhone 6 Plus',
104
+ article_title: 'iPhone 6 Plus',
105
105
  price: 100,
106
106
  status: 'visible',
107
107
  tags: ['tag1', 'tag2'],
@@ -114,7 +114,7 @@ describe Paradocs::Schema do
114
114
  variants: [{name: 'v1', available_if_no_stock: '1'}]
115
115
  },
116
116
  {
117
- title: 'iPhone 6 Plus',
117
+ article_title: 'iPhone 6 Plus',
118
118
  variants: [{name: 'v1', stock: 1, available_if_no_stock: true}]
119
119
  })
120
120
 
@@ -16,13 +16,13 @@ describe Paradocs::Struct do
16
16
  include Paradocs::Struct
17
17
 
18
18
  schema do
19
- field(:title).type(:string).present
19
+ field(:title).type(:string).present.as(:example_title)
20
20
  field(:friends).type(:array).default([]).schema friend_class
21
21
  end
22
22
  end
23
23
 
24
24
  new_instance = klass.new
25
- expect(new_instance.title).to eq ''
25
+ expect(new_instance.example_title).to eq ''
26
26
  expect(new_instance.friends).to eq []
27
27
  expect(new_instance.valid?).to be false
28
28
  expect(new_instance.errors['$.title']).not_to be_nil
@@ -35,7 +35,7 @@ describe Paradocs::Struct do
35
35
  ]
36
36
  })
37
37
 
38
- expect(instance.title).to eq 'foo'
38
+ expect(instance.example_title).to eq 'foo'
39
39
  expect(instance.friends.size).to eq 2
40
40
  expect(instance.friends.first.name).to eq 'Ismael'
41
41
  expect(instance.friends.first).to be_a friend_class
@@ -154,7 +154,7 @@ describe Paradocs::Struct do
154
154
  schema do
155
155
  field(:title).type(:string).present
156
156
  field(:friends).type(:array).schema do
157
- field(:name).type(:string)
157
+ field(:name).type(:string).as(:person_name)
158
158
  field(:age).type(:integer).default(20)
159
159
  end
160
160
  end
@@ -171,8 +171,8 @@ describe Paradocs::Struct do
171
171
  expect(instance.to_h).to eq({
172
172
  title: 'foo',
173
173
  friends: [
174
- {name: 'Jane', age: 20},
175
- {name: 'Joe', age: 39},
174
+ {person_name: 'Jane', age: 20},
175
+ {person_name: 'Joe', age: 39},
176
176
  ]
177
177
  })
178
178
 
@@ -190,7 +190,7 @@ describe Paradocs::Struct do
190
190
  include Paradocs::Struct
191
191
 
192
192
  schema do
193
- field(:title).type(:string).present
193
+ field(:title).type(:string).present.as(:example_title)
194
194
  field(:friends).type(:array).schema do
195
195
  field(:name).type(:string)
196
196
  field(:age).type(:integer).default(20)
@@ -213,7 +213,7 @@ describe Paradocs::Struct do
213
213
  ]
214
214
  )
215
215
 
216
- expect(instance.title).to eq 'foo'
216
+ expect(instance.example_title).to eq 'foo'
217
217
  expect(instance.email).to eq 'email@me.com'
218
218
  expect(instance.friends.size).to eq 2
219
219
  end
@@ -72,7 +72,6 @@ describe "schemes with subschemes" do
72
72
  expect(result.errors).to eq({"$.fail_field"=>["is required"]})
73
73
  expect(result.output).to eq({error: :here, fail_field: nil})
74
74
  expect(schema.structure.nested).to eq(structure)
75
- schema.structure.flush!
76
75
  expect(schema.structure(ignore_transparent: false).nested).to eq(structure.merge(
77
76
  error: {transparent: true, mutates_schema: true, json_path: "$.error", nested_name: "error"}
78
77
  ))
@@ -80,9 +79,7 @@ describe "schemes with subschemes" do
80
79
  result = schema.resolve({})
81
80
  expect(result.errors).to eq({"$.success_field"=>["is required"]})
82
81
  expect(result.output).to eq({success_field: nil})
83
- schema.structure.flush!
84
82
  expect(schema.structure.nested).to eq(structure)
85
- schema.structure.flush!
86
83
  expect(schema.structure(ignore_transparent: false).nested).to eq(structure.merge(
87
84
  error: {transparent: true, mutates_schema: true, json_path: "$.error", nested_name: "error"}
88
85
  ))
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paradocs
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxim Tkachenko
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-09-10 00:00:00.000000000 Z
12
+ date: 2020-11-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -67,8 +67,8 @@ dependencies:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0'
70
- description: Flexible DSL for declaring allowed parameters focused on DRY validation
71
- that gives you opportunity to generate API documentation on-the-fly.
70
+ description: Flexible DRY validations with API docs generation done right TLDR; parametrics
71
+ on steroids.
72
72
  email:
73
73
  - tkachenko.maxim.w@gmail.com
74
74
  - ismaelct@gmail.com
@@ -88,6 +88,7 @@ files:
88
88
  - README.md
89
89
  - Rakefile
90
90
  - bin/console
91
+ - docs/changelog.md
91
92
  - docs/custom_configuration.md
92
93
  - docs/documentation_generation.md
93
94
  - docs/faq.md