dynamicschema 2.0.0 → 2.2.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.
@@ -40,44 +40,69 @@ module DynamicSchema
40
40
  end
41
41
 
42
42
  __compiled_schema.each do | property, criteria |
43
-
43
+
44
44
  key = ( criteria[ :as ] || property ).to_sym
45
45
  type = criteria[ :type ]
46
46
  default = criteria[ :default ]
47
+ has_multiple_types = type.is_a?( ::Array ) && criteria[ :compiler ]
47
48
 
48
- if type == ::Object
49
+ if has_multiple_types
50
+ _criteria = criteria
51
+ define_method( property ) do
52
+ @converted_attributes.fetch( key ) do
53
+ value = @attributes[ key ]
54
+ value = default if value.nil?
55
+ schema = _criteria[ :schema ] ||= ( _criteria[ :compiler ]&.compiled )
56
+ klass = _criteria[ :class ] ||= ( schema ? ::DynamicSchema::Struct.new( schema ) : nil )
57
+ @converted_attributes[ key ] =
58
+ if _criteria[ :array ]
59
+ __convert_types_array( Array( value ), klass, _criteria )
60
+ else
61
+ __normalize( __convert_types( value, klass, _criteria ), _criteria )
62
+ end
63
+ end
64
+ end
65
+ elsif type == ::Object
66
+ _criteria = criteria
49
67
  define_method( property ) do
50
68
  @converted_attributes.fetch( key ) do
51
69
  value = @attributes[ key ]
52
- schema = criteria[ :schema ] ||= ( criteria[ :compiler ]&.compiled )
70
+ schema = _criteria[ :schema ] ||= ( _criteria[ :compiler ]&.compiled )
53
71
  return value unless schema
54
- klass = criteria[ :class ] ||= ::DynamicSchema::Struct.new( schema )
55
- @converted_attributes[ key ] =
56
- if criteria[ :array ]
57
- Array( value || default ).map { | v | klass.build( v || {} ) }
72
+ klass = _criteria[ :class ] ||= ::DynamicSchema::Struct.new( schema )
73
+ @converted_attributes[ key ] =
74
+ if _criteria[ :array ]
75
+ Array( value || default ).map { | v | __normalize( klass.build( v || {} ), _criteria ) }
58
76
  else
59
- klass.build( value || default )
77
+ __normalize( klass.build( value || default ), _criteria )
60
78
  end
61
79
  end
62
80
  end
63
81
  elsif type
64
- define_method( property ) do
65
- @converted_attributes.fetch( key ) do
66
- value = @attributes[ key ]
67
- @converted_attributes[ key ] = criteria[ :array ] ?
68
- Array( value || default ).map { | v | __convert( v, to: type ) } :
69
- __convert( value || default, to: type )
82
+ _criteria = criteria
83
+ define_method( property ) do
84
+ @converted_attributes.fetch( key ) do
85
+ value = @attributes[ key ]
86
+ @converted_attributes[ key ] = _criteria[ :array ] ?
87
+ Array( value || default ).map { | v | __normalize( __coerce( v, to: type ), _criteria ) } :
88
+ __normalize( __coerce( value || default, to: type ), _criteria )
70
89
  end
71
90
  end
72
91
  else
92
+ _criteria = criteria
73
93
  define_method( property ) do
74
- @attributes[ key ] || default
75
- end
94
+ value = @attributes[ key ] || default
95
+ if _criteria[ :array ]
96
+ Array( value ).map { | v | __normalize( v, _criteria ) }
97
+ else
98
+ __normalize( value, _criteria )
99
+ end
100
+ end
76
101
  end
77
102
 
78
- define_method( :"#{ property }=" ) do | value |
103
+ define_method( :"#{ property }=" ) do | value |
79
104
  @converted_attributes.delete( key )
80
- @attributes[ key ] = value
105
+ @attributes[ key ] = value
81
106
  end
82
107
 
83
108
  end
@@ -96,7 +121,7 @@ module DynamicSchema
96
121
  result
97
122
  end
98
123
 
99
- private
124
+ private
100
125
 
101
126
  def compiled_schema
102
127
  self.class.compiled_schema
@@ -119,10 +144,36 @@ module DynamicSchema
119
144
  end
120
145
  end
121
146
 
122
- def __convert( value, to: )
147
+ def __coerce( value, to: )
123
148
  self.class.converter.convert( value, to: to ) { | v | to.new( v ) rescue nil }
124
149
  end
125
150
 
151
+ def __convert_types( value, klass, criteria )
152
+ return nil if value.nil?
153
+ if value.is_a?( ::Hash )
154
+ klass ? klass.build( value ) : value
155
+ else
156
+ scalar_types = __non_object_types( criteria[ :type ] )
157
+ __coerce( value, to: scalar_types )
158
+ end
159
+ end
160
+
161
+ def __convert_types_array( values, klass, criteria )
162
+ values.map { | v | __normalize( __convert_types( v, klass, criteria ), criteria ) }
163
+ end
164
+
165
+ def __non_object_types( types )
166
+ types_array = types.is_a?( ::Array ) ? types : [ types ]
167
+ result = types_array.reject { | type | type == ::Object }
168
+ result.length == 1 ? result.first : result
169
+ end
170
+
171
+ def __normalize( value, criteria )
172
+ normalize = criteria[ :normalize ]
173
+ return value unless normalize && !value.nil?
174
+ normalize.call( value )
175
+ end
176
+
126
177
  end
127
178
  __klass.instance_variable_set( :@__compiled_schema, __compiled_schema.dup )
128
179
  __klass.instance_variable_set( :@__converter, __converter )
@@ -40,6 +40,33 @@ module DynamicSchema
40
40
  type_match
41
41
  end
42
42
 
43
+ def __validate_types( value, criteria, path, key, &block )
44
+ if value.is_a?( ::Hash )
45
+ traverse_and_validate_values(
46
+ value,
47
+ schema: criteria[ :schema ] ||= criteria[ :compiler ].compiled,
48
+ path: "#{ ( path || '' ) + ( path ? '/' : '' ) + key.to_s }",
49
+ &block
50
+ )
51
+ else
52
+ scalar_types = __non_object_types( criteria[ :type ] )
53
+ unless value_matches_types?( value, scalar_types )
54
+ block.call( IncompatibleTypeError.new( path: path, key: key, type: criteria[ :type ], value: value ) )
55
+ end
56
+ end
57
+ end
58
+
59
+ def __validate_types_array( values, criteria, path, key, &block )
60
+ values.each do | value |
61
+ __validate_types( value, criteria, path, key, &block )
62
+ end
63
+ end
64
+
65
+ def __non_object_types( types )
66
+ types_array = types.is_a?( ::Array ) ? types : [ types ]
67
+ types_array.reject { | type | type == ::Object }
68
+ end
69
+
43
70
  def traverse_and_validate_values( values, schema:, path: nil, options: nil, &block )
44
71
  path.chomp( '/' ) if path
45
72
  unless values.respond_to?( :[] )
@@ -59,8 +86,13 @@ module DynamicSchema
59
86
  end
60
87
  end
61
88
  elsif !criteria[ :default_assigned ] && !value.nil?
89
+ type = criteria[ :type ]
90
+ has_multiple_types = type.is_a?( ::Array ) && criteria[ :compiler ]
91
+
62
92
  unless criteria[ :array ]
63
- if criteria[ :type ] == Object
93
+ if has_multiple_types
94
+ __validate_types( value, criteria, path, key, &block )
95
+ elsif type == Object
64
96
  traverse_and_validate_values(
65
97
  values[ name ],
66
98
  schema: criteria[ :schema ] ||= criteria[ :compiler ].compiled,
@@ -68,14 +100,16 @@ module DynamicSchema
68
100
  &block
69
101
  )
70
102
  else
71
- if criteria[ :type ] && value && !criteria[ :default_assigned ]
72
- unless value_matches_types?( value, criteria[ :type ] )
73
- block.call( IncompatibleTypeError.new( path: path, key: key, type: criteria[ :type ], value: value ) )
103
+ if type && value && !criteria[ :default_assigned ]
104
+ unless value_matches_types?( value, type )
105
+ block.call( IncompatibleTypeError.new( path: path, key: key, type: type, value: value ) )
74
106
  end
75
107
  end
76
108
  end
77
109
  else
78
- if criteria[ :type ] == Object
110
+ if has_multiple_types
111
+ __validate_types_array( Array( value ), criteria, path, key, &block )
112
+ elsif type == Object
79
113
  groups = Array( value )
80
114
  groups.each do | group |
81
115
  traverse_and_validate_values(
metadata CHANGED
@@ -1,29 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynamicschema
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kristoph Cichocki-Romanov
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-09-06 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: rspec
13
+ name: minitest
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '3.13'
18
+ version: '6.0'
20
19
  type: :development
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '3.13'
25
+ version: '6.0'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: debug
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -76,7 +75,6 @@ licenses:
76
75
  metadata:
77
76
  source_code_uri: https://github.com/EndlessInternational/dynamic_schema
78
77
  bug_tracker_uri: https://github.com/EndlessInternational/dynamic_schema/issues
79
- post_install_message:
80
78
  rdoc_options: []
81
79
  require_paths:
82
80
  - lib
@@ -91,8 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
89
  - !ruby/object:Gem::Version
92
90
  version: '0'
93
91
  requirements: []
94
- rubygems_version: 3.5.22
95
- signing_key:
92
+ rubygems_version: 3.6.7
96
93
  specification_version: 4
97
94
  summary: DynamicSchema is a lightweight and simple yet powerful gem that enables flexible
98
95
  semantic schema definitions for constructing and validating complex configurations