definition 0.7.1 → 0.8.1

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.
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "definition/v1_deprecator"
4
+
3
5
  module Definition
4
6
  module Dsl
5
7
  module Comparators
6
8
  # Example:
7
9
  # MaxSize(5)
8
- def MaxSize(max_size) # rubocop:disable Style/MethodName
10
+ def MaxSize(max_size) # rubocop:disable Naming/MethodName
9
11
  Types::Lambda.new(:max_size, context: { max_size: max_size }) do |value|
10
12
  case value
11
13
  when String, Enumerable
@@ -18,7 +20,7 @@ module Definition
18
20
 
19
21
  # Example:
20
22
  # MinSize(5)
21
- def MinSize(min_size) # rubocop:disable Style/MethodName
23
+ def MinSize(min_size) # rubocop:disable Naming/MethodName
22
24
  Types::Lambda.new(:min_size, context: { min_size: min_size }) do |value|
23
25
  case value
24
26
  when String, Enumerable
@@ -31,45 +33,53 @@ module Definition
31
33
 
32
34
  # Example:
33
35
  # NonEmptyString
34
- def NonEmptyString # rubocop:disable Style/MethodName
36
+ def NonEmptyString # rubocop:disable Naming/MethodName
35
37
  Types::And.new(:non_empty_string, Type(String), MinSize(1))
36
38
  end
37
39
 
38
40
  # Example:
39
- # GreaterThen(5)
40
- def GreaterThen(min_value) # rubocop:disable Style/MethodName
41
- Types::Lambda.new("greater_then", context: { min_value: min_value }) do |value|
41
+ # GreaterThan(5)
42
+ def GreaterThan(min_value) # rubocop:disable Naming/MethodName
43
+ Types::Lambda.new("greater_than", context: { min_value: min_value }) do |value|
42
44
  conform_with(value) if value.is_a?(Numeric) && value > min_value
43
45
  end
44
46
  end
47
+ alias GreaterThen GreaterThan
48
+ deprecate :GreaterThen, deprecator: V1Deprecator
45
49
 
46
50
  # Example:
47
- # GreaterThenEqual(5)
48
- def GreaterThenEqual(min_value) # rubocop:disable Style/MethodName
49
- Types::Lambda.new("greater_then_equal", context: { min_value: min_value }) do |value|
51
+ # GreaterThanEqual(5)
52
+ def GreaterThanEqual(min_value) # rubocop:disable Naming/MethodName
53
+ Types::Lambda.new("greater_than_equal", context: { min_value: min_value }) do |value|
50
54
  conform_with(value) if value.is_a?(Numeric) && value >= min_value
51
55
  end
52
56
  end
57
+ alias GreaterThenEqual GreaterThanEqual
58
+ deprecate :GreaterThenEqual, deprecator: V1Deprecator
53
59
 
54
60
  # Example:
55
- # LessThen(5)
56
- def LessThen(max_value) # rubocop:disable Style/MethodName
57
- Types::Lambda.new("less_then", context: { max_value: max_value }) do |value|
61
+ # LessThan(5)
62
+ def LessThan(max_value) # rubocop:disable Naming/MethodName
63
+ Types::Lambda.new("less_than", context: { max_value: max_value }) do |value|
58
64
  conform_with(value) if value.is_a?(Numeric) && value < max_value
59
65
  end
60
66
  end
67
+ alias LessThen LessThan
68
+ deprecate :LessThen, deprecator: V1Deprecator
61
69
 
62
70
  # Example:
63
- # LessThenEqual(5)
64
- def LessThenEqual(max_value) # rubocop:disable Style/MethodName
65
- Types::Lambda.new("less_then_equal", context: { max_value: max_value }) do |value|
71
+ # LessThanEqual(5)
72
+ def LessThanEqual(max_value) # rubocop:disable Naming/MethodName
73
+ Types::Lambda.new("less_than_equal", context: { max_value: max_value }) do |value|
66
74
  conform_with(value) if value.is_a?(Numeric) && value <= max_value
67
75
  end
68
76
  end
77
+ alias LessThenEqual LessThanEqual
78
+ deprecate :LessThenEqual, deprecator: V1Deprecator
69
79
 
70
80
  # Example:
71
81
  # Equal("value")
72
- def Equal(expected_value) # rubocop:disable Style/MethodName
82
+ def Equal(expected_value) # rubocop:disable Naming/MethodName
73
83
  Types::Lambda.new(:equal, context: { expected_value: expected_value }) do |value|
74
84
  conform_with(value) if value == expected_value
75
85
  end
@@ -77,7 +87,7 @@ module Definition
77
87
 
78
88
  # Example:
79
89
  # Empty
80
- def Empty # rubocop:disable Style/MethodName
90
+ def Empty # rubocop:disable Naming/MethodName
81
91
  Types::Lambda.new(:empty) do |value|
82
92
  case value
83
93
  when String, Array, Hash
@@ -90,7 +100,7 @@ module Definition
90
100
 
91
101
  # Example:
92
102
  # NonEmpty
93
- def NonEmpty # rubocop:disable Style/MethodName
103
+ def NonEmpty # rubocop:disable Naming/MethodName
94
104
  Types::Lambda.new(:non_empty) do |value|
95
105
  case value
96
106
  when String, Array, Hash
@@ -103,7 +113,7 @@ module Definition
103
113
 
104
114
  # Example:
105
115
  # Regex
106
- def Regex(regex, name: :regex) # rubocop:disable Style/MethodName
116
+ def Regex(regex, name: :regex) # rubocop:disable Naming/MethodName
107
117
  Types::Lambda.new(name, context: { regex: regex.inspect }) do |value|
108
118
  case value
109
119
  when String
@@ -5,7 +5,7 @@ module Definition
5
5
  module Nil
6
6
  # Example:
7
7
  # Nil
8
- def Nil # rubocop:disable Style/MethodName
8
+ def Nil # rubocop:disable Naming/MethodName
9
9
  Types::Lambda.new(:nil) do |value|
10
10
  conform_with(value) if value.nil?
11
11
  end
@@ -9,33 +9,33 @@ module Definition
9
9
  # required :name, Types::Type(String)
10
10
  # optional :age, Types::Type(Integer)
11
11
  # end
12
- def Keys(&block) # rubocop:disable Style/MethodName
12
+ def Keys(&block) # rubocop:disable Naming/MethodName
13
13
  Types::Keys.new(:hash).tap do |instance|
14
14
  instance.instance_exec(&block)
15
15
  end
16
16
  end
17
17
 
18
18
  # Example:
19
- # And(Types::Type(Float), Types::GreaterThen(10.0))
20
- def And(*definitions) # rubocop:disable Style/MethodName
19
+ # And(Types::Type(Float), Types::GreaterThan(10.0))
20
+ def And(*definitions) # rubocop:disable Naming/MethodName
21
21
  Types::And.new(:and, *definitions)
22
22
  end
23
23
 
24
24
  # Example:
25
25
  # Or(Types::Type(Float), Types::Type(Integer))
26
- def Or(*definitions) # rubocop:disable Style/MethodName
26
+ def Or(*definitions) # rubocop:disable Naming/MethodName
27
27
  Types::Or.new(:or, *definitions)
28
28
  end
29
29
 
30
30
  # Example:
31
31
  # Type(Integer)
32
- def Type(klass) # rubocop:disable Style/MethodName
32
+ def Type(klass) # rubocop:disable Naming/MethodName
33
33
  Types::Type.new(:type, klass)
34
34
  end
35
35
 
36
36
  # Example:
37
37
  # CoercibleType(Integer)
38
- def CoercibleType(klass) # rubocop:disable Style/MethodName
38
+ def CoercibleType(klass) # rubocop:disable Naming/MethodName
39
39
  unless Kernel.respond_to?(klass.name)
40
40
  raise ArgumentError.new("#{klass} can't be used as CoercibleType because its not "\
41
41
  "a primitive that has a coercion function defined")
@@ -51,13 +51,13 @@ module Definition
51
51
  # Lambda(:even) do |value|
52
52
  # value.even?
53
53
  # end
54
- def Lambda(name, context: {}, &block) # rubocop:disable Style/MethodName
54
+ def Lambda(name, context: {}, &block) # rubocop:disable Naming/MethodName
55
55
  Types::Lambda.new(name, context: context, &block)
56
56
  end
57
57
 
58
58
  # Example:
59
59
  # Enum("allowed_value1", "allowed_value2")
60
- def Enum(*allowed_values) # rubocop:disable Style/MethodName
60
+ def Enum(*allowed_values) # rubocop:disable Naming/MethodName
61
61
  Lambda("enum", context: { allowed_values: allowed_values }) do |value|
62
62
  conform_with(value) if allowed_values.include?(value)
63
63
  end
@@ -65,24 +65,24 @@ module Definition
65
65
 
66
66
  # Example:
67
67
  # Each(Definition::Type(Integer))
68
- def Each(definition) # rubocop:disable Style/MethodName
68
+ def Each(definition) # rubocop:disable Naming/MethodName
69
69
  Types::Each.new(:each, definition: definition)
70
70
  end
71
71
 
72
72
  # Example:
73
73
  # Boolean
74
- def Boolean # rubocop:disable Style/MethodName
74
+ def Boolean # rubocop:disable Naming/MethodName
75
75
  Types::Or.new(:boolean, Type(TrueClass), Type(FalseClass))
76
76
  end
77
77
 
78
78
  # Example:
79
- # CoercibleValueObject(ValueObjectClass)
80
- def CoercibleValueObject(klass) # rubocop:disable Style/MethodName
81
- Types::Or.new(:coercible_value_object,
79
+ # CoercibleModel(ModelClass)
80
+ def CoercibleModel(klass) # rubocop:disable Naming/MethodName
81
+ Types::Or.new(:coercible_model,
82
82
  Definition.Type(klass), # If its of ther correct type already this will let it pass already
83
83
  And(
84
84
  klass, # First make sure that the input could be coerced to 'klass'
85
- Lambda("value_object_coercion", context: { value_object_class: klass }) do |value|
85
+ Lambda("value_object_coercion", context: { model_class: klass }) do |value|
86
86
  conform_with(klass.new(value)) # Actually coerce the input to klass
87
87
  end
88
88
  ))
@@ -90,7 +90,7 @@ module Definition
90
90
 
91
91
  # Example:
92
92
  # Nilable(Definition.Type(Integer))
93
- def Nilable(definition) # rubocop:disable Style/MethodName
93
+ def Nilable(definition) # rubocop:disable Naming/MethodName
94
94
  Types::Or.new(:nilable, Nil(), definition)
95
95
  end
96
96
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Definition
4
+ module Initializer
5
+ class InvalidArgumentError < ArgumentError
6
+ attr_accessor :conform_result
7
+
8
+ def initialize(conform_result)
9
+ super("Arguments passed into the initializer are invalid: #{conform_result.error_message}")
10
+ self.conform_result = conform_result
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ def required(name, *args)
16
+ _keys_definition.required(name, *args)
17
+ _define_attr_accessor(name)
18
+ end
19
+
20
+ def optional(name, *args, **kwargs)
21
+ _keys_definition.optional(name, *args, **kwargs)
22
+ _define_attr_accessor(name)
23
+ end
24
+
25
+ def _keys_definition
26
+ @_keys_definition ||= Definition.Keys {}
27
+ end
28
+
29
+ def _define_attr_accessor(key)
30
+ define_method(key) do
31
+ @_attributes.fetch(key, nil)
32
+ end
33
+ define_method("#{key}=") do |value|
34
+ @_attributes[key] = value
35
+ end
36
+ protected key
37
+ protected "#{key}="
38
+ end
39
+ end
40
+
41
+ def self.included(klass)
42
+ klass.extend(ClassMethods)
43
+ end
44
+
45
+ def initialize(**kwargs)
46
+ result = self.class._keys_definition.conform(kwargs)
47
+ raise InvalidArgumentError.new(result) unless result.passed?
48
+
49
+ @_attributes = result.value
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Definition
4
+ class InvalidModelError < StandardError
5
+ attr_accessor :conform_result
6
+
7
+ def initialize(conform_result)
8
+ super(conform_result.error_message)
9
+ self.conform_result = conform_result
10
+ end
11
+ end
12
+
13
+ class Model
14
+ class << self
15
+ def conform(value)
16
+ _definition.conform(value)
17
+ end
18
+
19
+ def required(key, definition)
20
+ _define_attr_accessor(key)
21
+ _definition.required(key, definition)
22
+ end
23
+
24
+ def optional(key, definition, **opts)
25
+ _define_attr_accessor(key)
26
+ _definition.optional(key, definition, **opts)
27
+ end
28
+
29
+ def option(option_name)
30
+ _definition.option(option_name)
31
+ end
32
+
33
+ def _define_attr_accessor(key)
34
+ define_method(key) do
35
+ @_attributes.fetch(key, nil)
36
+ end
37
+ end
38
+
39
+ def _definition
40
+ @_definition ||= ::Definition.Keys {}
41
+ end
42
+ end
43
+
44
+ def initialize(hash = nil, **kwargs)
45
+ result = self.class.conform(hash || kwargs)
46
+ raise InvalidModelError.new(result) unless result.passed?
47
+
48
+ @_attributes = result.value.freeze
49
+ end
50
+
51
+ def new(**kwargs)
52
+ self.class.new(**to_h.merge!(kwargs))
53
+ end
54
+
55
+ def ==(other)
56
+ return false unless other.is_a?(self.class)
57
+
58
+ @_attributes.hash == other.instance_variable_get(:@_attributes).hash
59
+ end
60
+ alias eql? ==
61
+
62
+ def hash
63
+ @_attributes.hash
64
+ end
65
+
66
+ def to_h
67
+ _deep_transform_values_in_object(@_attributes) do |value|
68
+ value.is_a?(::Definition::Model) ? value.to_h : value
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def _deep_transform_values_in_object(object, &block)
75
+ case object
76
+ when Hash
77
+ object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
78
+ when Array
79
+ object.map { |e| _deep_transform_values_in_object(e, &block) }
80
+ else
81
+ yield(object)
82
+ end
83
+ end
84
+ end
85
+ end
@@ -9,11 +9,11 @@ module Definition
9
9
  class Keys < Base
10
10
  module Dsl
11
11
  def required(key, definition)
12
- required_definitions[key] = definition
12
+ required_definitions << { key: key, definition: definition }
13
13
  end
14
14
 
15
15
  def optional(key, definition, **opts)
16
- optional_definitions[key] = definition
16
+ optional_definitions << { key: key, definition: definition }
17
17
  default(key, opts[:default]) if opts.key?(:default)
18
18
  end
19
19
 
@@ -30,15 +30,10 @@ module Definition
30
30
  raise ArgumentError.new("Included Definition can only be a Keys Definition") unless other.is_a?(Types::Keys)
31
31
 
32
32
  ensure_keys_do_not_interfere(other)
33
- other.required_definitions.each do |key, definition|
34
- required(key, definition)
35
- end
36
- other.optional_definitions.each do |key, definition|
37
- optional(key, definition)
38
- end
39
- other.defaults.each do |key, default|
40
- default(key, default)
41
- end
33
+
34
+ self.required_definitions += other.required_definitions
35
+ self.optional_definitions += other.optional_definitions
36
+ defaults.merge!(other.defaults)
42
37
  end
43
38
 
44
39
  private
@@ -62,8 +57,8 @@ module Definition
62
57
 
63
58
  def initialize(name, req: {}, opt: {}, defaults: {}, options: {})
64
59
  super(name)
65
- self.required_definitions = req
66
- self.optional_definitions = opt
60
+ self.required_definitions = req.map { |key, definition| { key: key, definition: definition } }
61
+ self.optional_definitions = opt.map { |key, definition| { key: key, definition: definition } }
67
62
  self.defaults = defaults
68
63
  self.ignore_extra_keys = options.fetch(:ignore_extra_keys, false)
69
64
  end
@@ -73,7 +68,7 @@ module Definition
73
68
  end
74
69
 
75
70
  def keys
76
- required_definitions.keys + optional_definitions.keys
71
+ (required_definitions + optional_definitions).map { |hash| hash[:key] }
77
72
  end
78
73
 
79
74
  class Conformer
@@ -81,18 +76,15 @@ module Definition
81
76
  self.definition = definition
82
77
  self.value = value
83
78
  self.errors = []
79
+ @conform_result_value = {} # This will be the output value after conforming
80
+ @not_conformed_value_keys = value.dup # Used to track which keys are left over in the end (unexpected keys)
84
81
  end
85
82
 
86
83
  def conform
87
- if valid_input_type?
88
- add_extra_key_errors unless definition.ignore_extra_keys
89
- add_missing_key_errors
90
- values = conform_all_keys
91
- else
92
- errors.push(ConformError.new(definition,
93
- "#{definition.name} is not a Hash",
94
- i18n_key: "keys.not_a_hash"))
95
- end
84
+ return invalid_input_result unless valid_input_type?
85
+
86
+ values = conform_all_keys
87
+ add_extra_key_errors unless definition.ignore_extra_keys
96
88
 
97
89
  ConformResult.new(values, errors: errors)
98
90
  end
@@ -101,12 +93,19 @@ module Definition
101
93
 
102
94
  attr_accessor :errors
103
95
 
96
+ def invalid_input_result
97
+ errors = [ConformError.new(definition,
98
+ "#{definition.name} is not a Hash",
99
+ i18n_key: "keys.not_a_hash")]
100
+ ConformResult.new(value, errors: errors)
101
+ end
102
+
104
103
  def valid_input_type?
105
104
  value.is_a?(Hash)
106
105
  end
107
106
 
108
107
  def add_extra_key_errors
109
- extra_keys = value.keys - all_keys
108
+ extra_keys = @not_conformed_value_keys.keys
110
109
  return if extra_keys.empty?
111
110
 
112
111
  extra_keys.each do |key|
@@ -120,59 +119,42 @@ module Definition
120
119
  end
121
120
 
122
121
  def conform_all_keys
123
- required_keys_values = conform_definitions(required_definitions)
124
- optional_keys_values = conform_definitions(optional_definitions)
122
+ conform_definitions(definition.required_definitions, required: true)
123
+ conform_definitions(definition.optional_definitions, required: false)
125
124
 
126
- definition.defaults.merge(required_keys_values.merge!(optional_keys_values))
125
+ @conform_result_value
127
126
  end
128
127
 
129
- def all_keys
130
- required_keys + optional_keys
131
- end
132
-
133
- def required_definitions
134
- definition.required_definitions
135
- end
136
-
137
- def required_keys
138
- required_definitions.keys
139
- end
140
-
141
- def optional_definitions
142
- definition.optional_definitions
143
- end
144
-
145
- def optional_keys
146
- optional_definitions.keys
128
+ def conform_definitions(keys, required:)
129
+ keys.each do |hash|
130
+ key = hash[:key]
131
+ key_definition = hash[:definition]
132
+ conform_definition(key, key_definition, required: required)
133
+ end
147
134
  end
148
135
 
149
- def conform_definitions(keys)
150
- keys.each_with_object({}) do |(key, key_definition), result_value|
151
- next unless value.key?(key)
136
+ # Rubcop rules are disabled for performance optimization purposes
137
+ def conform_definition(key, key_definition, required:) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
138
+ @not_conformed_value_keys.delete(key) # Keys left over in that hash at the end are considered unexpected
152
139
 
153
- result = key_definition.conform(value[key])
154
- result_value[key] = result.value
155
- next if result.passed?
156
-
157
- errors.push(KeyConformError.new(key_definition,
158
- "#{definition.name} fails validation for key #{key}",
159
- key: key,
160
- sub_errors: result.error_tree))
140
+ # If the input value is missing a key:
141
+ # a) add a missing key error if it is a required key
142
+ # b) otherwise initialize the missing key in the output value if a default value is configured
143
+ unless value.key?(key)
144
+ errors.push(missing_key_error(key)) if required
145
+ @conform_result_value[key] = definition.defaults[key] if definition.defaults.key?(key)
146
+ return
161
147
  end
162
- end
163
148
 
164
- def add_missing_key_errors
165
- required_definition = Types::Include.new(
166
- definition.name,
167
- *required_keys
168
- )
169
-
170
- result = required_definition.conform(value)
149
+ # If the input value has a key then its value is conformed against the configured definition
150
+ result = key_definition.conform(value[key])
151
+ @conform_result_value[key] = result.value
171
152
  return if result.passed?
172
153
 
173
- result.errors.each do |error|
174
- errors.push(missing_key_error(error.key))
175
- end
154
+ errors.push(KeyConformError.new(key_definition,
155
+ "#{definition.name} fails validation for key #{key}",
156
+ key: key,
157
+ sub_errors: result.error_tree))
176
158
  end
177
159
 
178
160
  def missing_key_error(key)
@@ -52,10 +52,16 @@ module Definition
52
52
  "Did not pass test for #{definition.name}"
53
53
  end
54
54
 
55
+ def contextual_error_message
56
+ return standard_error_message if definition.context.empty?
57
+
58
+ "#{standard_error_message} (#{definition.context.values.join(',')})"
59
+ end
60
+
55
61
  def failure_result_with(value, error_message)
56
62
  ConformResult.new(value, errors: [
57
63
  ConformError.new(definition,
58
- standard_error_message,
64
+ contextual_error_message,
59
65
  translated_message: error_message)
60
66
  ])
61
67
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/deprecation"
4
+
5
+ module Definition
6
+ V1Deprecator = ActiveSupport::Deprecation.new("1.0", "Definition")
7
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Definition
4
- VERSION = "0.7.1"
4
+ VERSION = "0.8.1"
5
5
  end
data/lib/definition.rb CHANGED
@@ -5,6 +5,8 @@ require "definition/dsl"
5
5
  require "definition/dsl/comparators"
6
6
  require "definition/dsl/nil"
7
7
  require "definition/value_object"
8
+ require "definition/initializer"
9
+ require "definition/model"
8
10
  require "definition/i18n"
9
11
 
10
12
  module Definition
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: definition
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Goltermann
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-04 00:00:00.000000000 Z
11
+ date: 2022-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -266,8 +266,11 @@ files:
266
266
  - LICENSE
267
267
  - README.md
268
268
  - Rakefile
269
+ - UpgradeNotes.md
269
270
  - benchmark/coercion.rb
270
271
  - benchmark/complex_example.rb
272
+ - benchmark/initializer.rb
273
+ - benchmark/model.rb
271
274
  - benchmark/validation_only.rb
272
275
  - bin/console
273
276
  - bin/setup
@@ -280,7 +283,9 @@ files:
280
283
  - lib/definition/dsl/comparators.rb
281
284
  - lib/definition/dsl/nil.rb
282
285
  - lib/definition/i18n.rb
286
+ - lib/definition/initializer.rb
283
287
  - lib/definition/key_conform_error.rb
288
+ - lib/definition/model.rb
284
289
  - lib/definition/types.rb
285
290
  - lib/definition/types/and.rb
286
291
  - lib/definition/types/base.rb
@@ -293,9 +298,9 @@ files:
293
298
  - lib/definition/types/lambda.rb
294
299
  - lib/definition/types/or.rb
295
300
  - lib/definition/types/type.rb
301
+ - lib/definition/v1_deprecator.rb
296
302
  - lib/definition/value_object.rb
297
303
  - lib/definition/version.rb
298
- - tags
299
304
  homepage: https://github.com/Goltergaul/definition
300
305
  licenses:
301
306
  - MIT
@@ -315,7 +320,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
315
320
  - !ruby/object:Gem::Version
316
321
  version: '0'
317
322
  requirements: []
318
- rubygems_version: 3.1.2
323
+ rubygems_version: 3.3.7
319
324
  signing_key:
320
325
  specification_version: 4
321
326
  summary: Simple and composable validation and coercion of data structures inspired