parametric 0.2.19 → 0.2.20

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
  SHA256:
3
- metadata.gz: 98676c8edebba19bd1adff020f5eadf9dce07e44f89125be4f0451d6bdee50cf
4
- data.tar.gz: 5a5d0ecded864e5185d2b1d1cafe5eeb2307d92cf52c4111e7dd85ebe65c0321
3
+ metadata.gz: 0a4f53d13fdfe4476f9467127b58740f86b8f301979b56940eb9e228fd588225
4
+ data.tar.gz: 5b26af44589c43bc2825a75e988318eefc3147581183a4c4cc65af5b98a47fed
5
5
  SHA512:
6
- metadata.gz: 1a3b81c816a02516450bdeb70ddb5b804741481ec0084167f31cdddcef4c3734f25b0d69da022048d9889c7b47a462cd821bf3a4cef07d719aff9b57293e10ef
7
- data.tar.gz: 5a2cd8dd4d68cd896901d744f656fca3385f6d3763bc05d62dbd1b6c53362a32092781e7bd57e439b27c6e0071d1179a0355372778d33b9c96f893e6fd4e07d3
6
+ metadata.gz: a5f7fbdfee4363b05e2044439499bd17954552b6a8c9b95442a613969e4775dcc2d05ee2340ba06df3b55b12df2414a16b672fe76c5b1ee2485ba6dede5cbdf7
7
+ data.tar.gz: 9ea239bd608ef85e8f92a07060e10aff57b0552b92562b4e4ea1507e1a91a71173382565fd7f198d8f3a2595756b8a6badeb46638de14997fd15bf13250e4910
data/README.md CHANGED
@@ -293,6 +293,21 @@ Like `:declared`, it stops the policy chain if a key is not in input, but it als
293
293
  field(:name).policy(:declared_no_default).present
294
294
  ```
295
295
 
296
+ ### :nullable
297
+
298
+ Check that key is present in input. If value is `nil`, processing and validations stop, but key is still included in output.
299
+
300
+ ```ruby
301
+ schema = Parametric::Schema.new do
302
+ field(:age).nullable.type(:integer).policy(:gt: 21)
303
+ end
304
+
305
+ schema.resolve(age: '22').output[:age] # 22
306
+ schema.resolve(age: 10).errors[:age] # has error because < 21
307
+ schema.resolve(age: nil).output[:age] # nil, no errors
308
+ schema.resolve({}).output[:age] # nil, no errors
309
+ ```
310
+
296
311
  ### :gt
297
312
 
298
313
  Validate that the value is greater than a number
@@ -387,6 +402,12 @@ class MyPolicyRunner
387
402
  true
388
403
  end
389
404
 
405
+ # If this policy is not eligible, should the key and value be included in the output?
406
+ # @return [Boolean]
407
+ def include_non_eligible_in_ouput?
408
+ true
409
+ end
410
+
390
411
  # If [false], add [#message] to result errors and halt processing field.
391
412
  # @return [Boolean]
392
413
  def valid?
@@ -88,7 +88,7 @@ module Parametric
88
88
  begin
89
89
  pol = policy.build(key, value, payload:, context:)
90
90
  if !pol.eligible?
91
- eligible = false
91
+ eligible = pol.include_non_eligible_in_ouput?
92
92
  if has_default?
93
93
  eligible = true
94
94
  value = default_block.call(key, payload, context)
@@ -22,5 +22,9 @@ module Parametric
22
22
  def options(opts)
23
23
  policy :options, opts
24
24
  end
25
+
26
+ def nullable
27
+ policy :nullable
28
+ end
25
29
  end
26
30
  end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Parametric
4
+ # A policy that allows a field to be nullable.
5
+ # Fields with nil values are not processed further, and the value is returned as-is.
6
+ # @example
7
+ # field(:age).nullable.type(:integer)
8
+ # field(:age).nullable.type(:integer).required
9
+ #
10
+ class NullablePolicy
11
+ def meta_data; {}; end
12
+
13
+ def build(key, value, payload:, context:)
14
+ Runner.new(key, value, payload, context)
15
+ end
16
+
17
+ class Runner
18
+ def initialize(key, value, payload, context)
19
+ @key = key
20
+ @value = value
21
+ @payload = payload
22
+ @context = context
23
+ end
24
+
25
+ # Should this policy run at all?
26
+ # returning [false] halts the field policy chain.
27
+ # @return [Boolean]
28
+ def eligible?
29
+ @payload.key?(@key) && !@value.nil?
30
+ end
31
+
32
+ # If this policy is not eligible, should the key and value be included in the output?
33
+ # @return [Boolean]
34
+ def include_non_eligible_in_ouput?
35
+ true
36
+ end
37
+
38
+ # If [false], add [#message] to result errors and halt processing field.
39
+ # @return [Boolean]
40
+ def valid?
41
+ true
42
+ end
43
+
44
+ # Coerce the value, or return as-is.
45
+ # @return [Any]
46
+ def value
47
+ @value
48
+ end
49
+
50
+ # Error message for this policy
51
+ # @return [String]
52
+ def message
53
+ ''
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'parametric/nullable_policy'
4
+
3
5
  module Parametric
4
6
  module Policies
5
7
  class Format
@@ -59,6 +61,7 @@ module Parametric
59
61
  Parametric.policy :format, Policies::Format
60
62
  Parametric.policy :email, Policies::Format.new(EMAIL_REGEXP, 'invalid email')
61
63
  Parametric.policy :value, Policies::Value
64
+ Parametric.policy :nullable, Parametric::NullablePolicy
62
65
 
63
66
  Parametric.policy :noop do
64
67
  eligible do |value, key, payload|
@@ -14,6 +14,14 @@ module Parametric
14
14
  @policy.eligible?(@raw_value, @key, @payload)
15
15
  end
16
16
 
17
+ # If a policy is not #eligible?, use this to decide if its key
18
+ # should still be included in output hash.
19
+ #
20
+ # @return [Boolean]
21
+ def include_non_eligible_in_ouput?
22
+ false
23
+ end
24
+
17
25
  # @return [Boolean]
18
26
  def valid?
19
27
  @policy.valid?(value, @key, @payload)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parametric
4
- VERSION = '0.2.19'
4
+ VERSION = '0.2.20'
5
5
  end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'nullable policy' do
6
+ specify 'dealing with nil values' do
7
+ schema = Parametric::Schema.new do
8
+ field(:age).nullable.type(:integer)
9
+ end
10
+
11
+ expect(schema.resolve({ age: 10 }).output[:age]).to eq 10
12
+ expect(schema.resolve({ age: '10' }).output[:age]).to eq 10
13
+ expect(schema.resolve({ age: nil }).output[:age]).to eq nil
14
+ expect(schema.resolve({ age: false }).output[:age]).to be false
15
+ expect(schema.resolve({ nope: 1 }).output.key?(:age)).to be true
16
+ end
17
+
18
+ specify 'with required/present types' do
19
+ schema = Parametric::Schema.new do
20
+ field(:age).nullable.type(:integer).present.policy(:gt, 9)
21
+ end
22
+
23
+ schema.resolve({ age: '10' }).tap do |r|
24
+ expect(r.output[:age]).to eq 10
25
+ expect(r.errors.any?).to be false
26
+ end
27
+
28
+ schema.resolve({ age: '7' }).tap do |r|
29
+ expect(r.output[:age]).to eq 7
30
+ expect(r.errors.any?).to be true
31
+ end
32
+
33
+ schema.resolve({ age: nil }).tap do |r|
34
+ expect(r.output[:age]).to eq nil
35
+ expect(r.errors.any?).to be false
36
+ end
37
+
38
+ schema.resolve({}).tap do |r|
39
+ expect(r.output.key?(:age)).to be true
40
+ expect(r.output[:age]).to eq nil
41
+ expect(r.errors.any?).to be false
42
+ end
43
+ end
44
+
45
+ specify 'interacting with custom types that validate' do
46
+ Parametric.policy :validating_integer do
47
+ exp = /^\d+$/
48
+
49
+ validate do |value, _key, _context|
50
+ !!(value.to_s =~ exp)
51
+ end
52
+
53
+ coerce do |value, _key, _context|
54
+ if value.to_s =~ exp
55
+ value.to_i
56
+ else
57
+ value
58
+ end
59
+ end
60
+
61
+ message do
62
+ 'error!'
63
+ end
64
+ end
65
+
66
+ schema = Parametric::Schema.new do
67
+ field(:age).nullable.type(:validating_integer)
68
+ end
69
+
70
+ expect(schema.resolve({ age: 10 }).output[:age]).to eq 10
71
+ expect(schema.resolve({ age: '10' }).output[:age]).to eq 10
72
+ schema.resolve({ age: 'nope' }).tap do |r|
73
+ expect(r.output[:age]).to eq 'nope'
74
+ expect(r.errors.any?).to be true
75
+ end
76
+ schema.resolve({ age: nil }).tap do |r|
77
+ expect(r.output.key?(:age)).to be(true)
78
+ expect(r.output[:age]).to eq nil
79
+ expect(r.errors.any?).to be false
80
+ end
81
+ expect(schema.resolve({ age: nil }).output[:age]).to eq nil
82
+ expect(schema.resolve({ nope: 1 }).output.key?(:age)).to be true
83
+ end
84
+
85
+ specify 'interacting with required fields' do
86
+ schema = Parametric::Schema.new do
87
+ field(:age).nullable.type(:integer).required
88
+ end
89
+
90
+ result = schema.resolve({})
91
+ expect(result.output.key?(:age)).to be(true)
92
+ expect(result.output[:age]).to eq nil
93
+ expect(result.errors['$.age']).to eq nil
94
+ end
95
+
96
+ specify 'copying policies via Field#from' do
97
+ source_schema = Parametric::Schema.new do
98
+ field(:age).nullable.type(:integer).required
99
+ end
100
+
101
+ target_schema = Parametric::Schema.new do |sc, _|
102
+ source_schema.fields.each do |key, f|
103
+ sc.field(key).from(f)
104
+ end
105
+ end
106
+
107
+ result = target_schema.resolve({})
108
+ expect(result.output[:age]).to eq nil
109
+ expect(result.errors['$.age']).to eq nil
110
+ end
111
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parametric
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.19
4
+ version: 0.2.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ismael Celis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-10 00:00:00.000000000 Z
11
+ date: 2023-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -76,6 +76,7 @@ files:
76
76
  - lib/parametric/dsl.rb
77
77
  - lib/parametric/field.rb
78
78
  - lib/parametric/field_dsl.rb
79
+ - lib/parametric/nullable_policy.rb
79
80
  - lib/parametric/policies.rb
80
81
  - lib/parametric/policy_adapter.rb
81
82
  - lib/parametric/registry.rb
@@ -89,6 +90,7 @@ files:
89
90
  - spec/dsl_spec.rb
90
91
  - spec/expand_spec.rb
91
92
  - spec/field_spec.rb
93
+ - spec/nullable_policy_spec.rb
92
94
  - spec/policies_spec.rb
93
95
  - spec/schema_lifecycle_hooks_spec.rb
94
96
  - spec/schema_spec.rb
@@ -115,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
117
  - !ruby/object:Gem::Version
116
118
  version: '0'
117
119
  requirements: []
118
- rubygems_version: 3.4.18
120
+ rubygems_version: 3.4.22
119
121
  signing_key:
120
122
  specification_version: 4
121
123
  summary: DSL for declaring allowed parameters with options, regexp patern and default
@@ -125,6 +127,7 @@ test_files:
125
127
  - spec/dsl_spec.rb
126
128
  - spec/expand_spec.rb
127
129
  - spec/field_spec.rb
130
+ - spec/nullable_policy_spec.rb
128
131
  - spec/policies_spec.rb
129
132
  - spec/schema_lifecycle_hooks_spec.rb
130
133
  - spec/schema_spec.rb