schema-model 0.6.10 → 0.7.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +53 -0
- data/.rubocop.yml +70 -8
- data/.ruby-version +1 -1
- data/ARCHITECTURE.md +135 -0
- data/CLAUDE.md +74 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +75 -43
- data/README.md +426 -124
- data/lib/schema/active_model_validations.rb +14 -14
- data/lib/schema/array_headers.rb +6 -4
- data/lib/schema/arrays.rb +11 -13
- data/lib/schema/associations/dynamic_types.rb +3 -5
- data/lib/schema/associations/has_many.rb +6 -8
- data/lib/schema/associations/has_one.rb +5 -7
- data/lib/schema/associations/schema_creator.rb +7 -7
- data/lib/schema/csv_parser.rb +1 -1
- data/lib/schema/model.rb +37 -29
- data/lib/schema/parsers/array.rb +2 -2
- data/lib/schema/parsers/common.rb +6 -8
- data/lib/schema/parsers/hash.rb +1 -1
- data/lib/schema/parsers/json.rb +1 -1
- data/lib/schema/parsing_errors.rb +1 -1
- data/lib/schema/utils.rb +5 -5
- data/lib/schema-model.rb +1 -0
- data/schema-model.gemspec +6 -4
- metadata +11 -13
- data/.travis.yml +0 -14
- data/Rakefile +0 -11
- data/script/bundle_install_all_versions +0 -8
- data/script/rspec_all_versions +0 -5
data/lib/schema/arrays.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Schema
|
|
|
15
15
|
|
|
16
16
|
def to_empty_array
|
|
17
17
|
data = []
|
|
18
|
-
schema.
|
|
18
|
+
schema.each_value do |field_options|
|
|
19
19
|
next if field_options[:alias_of]
|
|
20
20
|
|
|
21
21
|
data <<
|
|
@@ -24,8 +24,6 @@ module Schema
|
|
|
24
24
|
const_get(field_options[:class_name]).to_empty_array
|
|
25
25
|
when :has_many
|
|
26
26
|
field_options[:size].times.map { const_get(field_options[:class_name]).to_empty_array }
|
|
27
|
-
else
|
|
28
|
-
nil
|
|
29
27
|
end
|
|
30
28
|
end
|
|
31
29
|
data
|
|
@@ -33,16 +31,16 @@ module Schema
|
|
|
33
31
|
|
|
34
32
|
def to_headers(prefix = nil)
|
|
35
33
|
headers = []
|
|
36
|
-
schema.
|
|
34
|
+
schema.each_value do |field_options|
|
|
37
35
|
next if field_options[:alias_of]
|
|
38
36
|
|
|
39
37
|
headers <<
|
|
40
38
|
case field_options[:type]
|
|
41
39
|
when :has_one
|
|
42
|
-
const_get(field_options[:class_name]).to_headers(prefix
|
|
40
|
+
const_get(field_options[:class_name]).to_headers("#{prefix}#{field_options[:key]}.")
|
|
43
41
|
when :has_many
|
|
44
42
|
field_options[:size].times.map do |i|
|
|
45
|
-
const_get(field_options[:class_name]).to_headers(prefix.to_s + field_options[:key] + "[#{i +1}].")
|
|
43
|
+
const_get(field_options[:class_name]).to_headers(prefix.to_s + field_options[:key] + "[#{i + 1}].")
|
|
46
44
|
end
|
|
47
45
|
else
|
|
48
46
|
prefix.to_s + field_options[:key]
|
|
@@ -54,7 +52,7 @@ module Schema
|
|
|
54
52
|
|
|
55
53
|
def to_a
|
|
56
54
|
data = []
|
|
57
|
-
self.class.schema.
|
|
55
|
+
self.class.schema.each_value do |field_options|
|
|
58
56
|
next if field_options[:alias_of]
|
|
59
57
|
|
|
60
58
|
value = public_send(field_options[:getter])
|
|
@@ -76,7 +74,7 @@ module Schema
|
|
|
76
74
|
end
|
|
77
75
|
|
|
78
76
|
def update_attributes_with_array(array, mapped_headers, offset = nil)
|
|
79
|
-
self.class.schema.
|
|
77
|
+
self.class.schema.each_value do |field_options|
|
|
80
78
|
next unless (mapped_field = mapped_headers[field_options[:name]])
|
|
81
79
|
|
|
82
80
|
if offset
|
|
@@ -103,7 +101,7 @@ module Schema
|
|
|
103
101
|
end
|
|
104
102
|
|
|
105
103
|
def update_nested_has_one_associations_from_array(array, mapped_headers, current_offset = nil)
|
|
106
|
-
self.class.schema.
|
|
104
|
+
self.class.schema.each_value do |field_options|
|
|
107
105
|
next unless field_options[:type] == :has_one
|
|
108
106
|
next unless (mapped_model = mapped_headers[field_options[:name]])
|
|
109
107
|
|
|
@@ -115,7 +113,7 @@ module Schema
|
|
|
115
113
|
end
|
|
116
114
|
|
|
117
115
|
def update_nested_has_many_associations_from_array(array, mapped_headers)
|
|
118
|
-
self.class.schema.
|
|
116
|
+
self.class.schema.each_value do |field_options|
|
|
119
117
|
next unless field_options[:type] == :has_many
|
|
120
118
|
next unless (mapped_model = mapped_headers[field_options[:name]])
|
|
121
119
|
|
|
@@ -136,10 +134,10 @@ module Schema
|
|
|
136
134
|
|
|
137
135
|
def largest_number_of_indexes_from_map(mapped_model)
|
|
138
136
|
size = 0
|
|
139
|
-
mapped_model.
|
|
137
|
+
mapped_model.each_value do |info|
|
|
140
138
|
if info[:indexes]
|
|
141
|
-
size = info[:indexes].size if info[:indexes]
|
|
142
|
-
|
|
139
|
+
size = info[:indexes].size if info[:indexes].size > size
|
|
140
|
+
elsif info.is_a?(Hash)
|
|
143
141
|
new_size = largest_number_of_indexes_from_map(info)
|
|
144
142
|
size = new_size if new_size > size
|
|
145
143
|
end
|
|
@@ -19,8 +19,8 @@ module Schema
|
|
|
19
19
|
kls
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def default_type(options = {}, &
|
|
23
|
-
add_type(:default, options, &
|
|
22
|
+
def default_type(options = {}, &)
|
|
23
|
+
add_type(:default, options, &)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def dynamic_types
|
|
@@ -34,9 +34,7 @@ module Schema
|
|
|
34
34
|
private
|
|
35
35
|
|
|
36
36
|
def schema_dynamic_type_class_name(type)
|
|
37
|
-
::Schema::Utils.classify_name(schema_name.to_s)
|
|
38
|
-
'AssociationType' +
|
|
39
|
-
::Schema::Utils.classify_name(type.to_s)
|
|
37
|
+
"#{::Schema::Utils.classify_name(schema_name.to_s)}AssociationType#{::Schema::Utils.classify_name(type.to_s)}"
|
|
40
38
|
end
|
|
41
39
|
|
|
42
40
|
def schema_add_dynamic_type(type, class_name)
|
|
@@ -10,12 +10,11 @@ module Schema
|
|
|
10
10
|
|
|
11
11
|
# no-doc
|
|
12
12
|
module ClassMethods
|
|
13
|
-
# rubocop:disable Naming/PredicateName
|
|
14
13
|
def has_many(name, options = {}, &block)
|
|
15
14
|
options = ::Schema::Utils.add_association_class(self, name, :has_many, options)
|
|
16
15
|
|
|
17
16
|
class_eval(
|
|
18
|
-
<<-STR, __FILE__, __LINE__ + 1
|
|
17
|
+
<<-STR, __FILE__, __LINE__ + 1
|
|
19
18
|
def #{options[:getter]}
|
|
20
19
|
#{options[:instance_variable]}
|
|
21
20
|
end
|
|
@@ -24,15 +23,15 @@ module Schema
|
|
|
24
23
|
@#{name}_schema_creator ||= ::Schema::Associations::SchemaCreator.new(self, #{name.inspect})
|
|
25
24
|
end
|
|
26
25
|
|
|
27
|
-
def #{options[:setter]}(v)
|
|
28
|
-
#{options[:instance_variable]} = #{name}_schema_creator.create_schemas(self, v)
|
|
26
|
+
def #{options[:setter]}(v, skip_fields = [])
|
|
27
|
+
#{options[:instance_variable]} = #{name}_schema_creator.create_schemas(self, v, skip_fields)
|
|
29
28
|
end
|
|
30
29
|
|
|
31
|
-
def append_to_#{options[:getter]}(v)
|
|
30
|
+
def append_to_#{options[:getter]}(v, skip_fields = [])
|
|
32
31
|
#{options[:instance_variable]} ||= []
|
|
33
|
-
#{options[:instance_variable]} << #{name}_schema_creator.create_schema(self, v)
|
|
32
|
+
#{options[:instance_variable]} << #{name}_schema_creator.create_schema(self, v, nil, skip_fields)
|
|
34
33
|
end
|
|
35
|
-
STR
|
|
34
|
+
STR
|
|
36
35
|
)
|
|
37
36
|
|
|
38
37
|
kls = const_get(options[:class_name])
|
|
@@ -44,7 +43,6 @@ STR
|
|
|
44
43
|
add_aliases(name, options)
|
|
45
44
|
kls
|
|
46
45
|
end
|
|
47
|
-
# rubocop:enable Naming/PredicateName
|
|
48
46
|
end
|
|
49
47
|
end
|
|
50
48
|
end
|
|
@@ -10,12 +10,11 @@ module Schema
|
|
|
10
10
|
|
|
11
11
|
# no-doc
|
|
12
12
|
module ClassMethods
|
|
13
|
-
# rubocop:disable Naming/PredicateName
|
|
14
13
|
def has_one(name, options = {}, &block)
|
|
15
14
|
options = ::Schema::Utils.add_association_class(self, name, :has_one, options)
|
|
16
15
|
|
|
17
16
|
class_eval(
|
|
18
|
-
<<-STR, __FILE__, __LINE__ + 1
|
|
17
|
+
<<-STR, __FILE__, __LINE__ + 1
|
|
19
18
|
def #{options[:getter]}
|
|
20
19
|
#{options[:instance_variable]}
|
|
21
20
|
end
|
|
@@ -24,22 +23,21 @@ module Schema
|
|
|
24
23
|
@#{name}_schema_creator ||= ::Schema::Associations::SchemaCreator.new(self, #{name.inspect})
|
|
25
24
|
end
|
|
26
25
|
|
|
27
|
-
def #{options[:setter]}(v)
|
|
28
|
-
#{options[:instance_variable]} = #{name}_schema_creator.create_schema(self, v)
|
|
26
|
+
def #{options[:setter]}(v, skip_fields = [])
|
|
27
|
+
#{options[:instance_variable]} = #{name}_schema_creator.create_schema(self, v, nil, skip_fields)
|
|
29
28
|
end
|
|
30
|
-
STR
|
|
29
|
+
STR
|
|
31
30
|
)
|
|
32
31
|
|
|
33
32
|
kls = const_get(options[:class_name])
|
|
34
33
|
kls.class_eval(&block) if block
|
|
35
34
|
if options[:default]
|
|
36
|
-
options[:default_code] = options[:class_name]
|
|
35
|
+
options[:default_code] = "#{options[:class_name]}.new"
|
|
37
36
|
::Schema::Utils.add_association_default_methods(self, options)
|
|
38
37
|
end
|
|
39
38
|
add_aliases(name, options)
|
|
40
39
|
kls
|
|
41
40
|
end
|
|
42
|
-
# rubocop:enable Naming/PredicateName
|
|
43
41
|
end
|
|
44
42
|
end
|
|
45
43
|
end
|
|
@@ -17,32 +17,32 @@ module Schema
|
|
|
17
17
|
configure_dynamic_schema_options(options)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
def create_schema(base_schema, data, error_name = nil)
|
|
20
|
+
def create_schema(base_schema, data, error_name = nil, skip_fields = [])
|
|
21
21
|
if data.is_a?(Hash)
|
|
22
22
|
unless (schema_class = get_schema_class(base_schema, data))
|
|
23
23
|
add_parsing_error(base_schema, error_name, UNKNOWN) if base_schema.class.capture_unknown_attributes?
|
|
24
24
|
return nil
|
|
25
25
|
end
|
|
26
|
-
schema = schema_class.from_hash(data)
|
|
26
|
+
schema = schema_class.from_hash(data, skip_fields)
|
|
27
27
|
add_parsing_error(base_schema, error_name, INVALID) unless schema.parsing_errors.empty?
|
|
28
28
|
schema
|
|
29
29
|
elsif !data.nil?
|
|
30
|
-
add_parsing_error(base_schema, error_name,
|
|
30
|
+
add_parsing_error(base_schema, error_name, INCOMPATIBLE)
|
|
31
31
|
nil
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
def create_schemas(base_schema, list)
|
|
35
|
+
def create_schemas(base_schema, list, skip_fields = [])
|
|
36
36
|
if is_list? && list.is_a?(Array)
|
|
37
|
-
list.each_with_index.map { |data, idx| create_schema(base_schema, data, "#{@schema_name}:#{idx}") }
|
|
37
|
+
list.each_with_index.map { |data, idx| create_schema(base_schema, data, "#{@schema_name}:#{idx}", skip_fields) }
|
|
38
38
|
elsif !is_list? && list.is_a?(Hash)
|
|
39
39
|
list.map do |(key, data)|
|
|
40
|
-
schema = create_schema(base_schema, data, "#{@schema_name}:#{key}")
|
|
40
|
+
schema = create_schema(base_schema, data, "#{@schema_name}:#{key}", skip_fields)
|
|
41
41
|
schema.send(schema.class.schema[@hash_key_field][:setter], key)
|
|
42
42
|
schema
|
|
43
43
|
end
|
|
44
44
|
elsif !list.nil?
|
|
45
|
-
add_parsing_error(base_schema, @schema_name,
|
|
45
|
+
add_parsing_error(base_schema, @schema_name, INCOMPATIBLE)
|
|
46
46
|
nil
|
|
47
47
|
end
|
|
48
48
|
end
|
data/lib/schema/csv_parser.rb
CHANGED
|
@@ -32,7 +32,7 @@ module Schema
|
|
|
32
32
|
|
|
33
33
|
def get_mapped_headers(mapped_headers)
|
|
34
34
|
indexed_headers = []
|
|
35
|
-
mapped_headers.
|
|
35
|
+
mapped_headers.each_value do |info|
|
|
36
36
|
if (index = info[:index])
|
|
37
37
|
indexed_headers << @headers[index]
|
|
38
38
|
elsif (indexes = info[:indexes])
|
data/lib/schema/model.rb
CHANGED
|
@@ -69,12 +69,12 @@ module Schema
|
|
|
69
69
|
|
|
70
70
|
add_value_to_class_method(:schema, name => options)
|
|
71
71
|
add_attribute_methods(name, options)
|
|
72
|
-
::Schema::Utils.add_attribute_default_methods(self, options) if options.
|
|
72
|
+
::Schema::Utils.add_attribute_default_methods(self, options) if options.key?(:default)
|
|
73
73
|
add_aliases(name, options)
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
-
def from_hash(data)
|
|
77
|
-
new.update_attributes(data)
|
|
76
|
+
def from_hash(data = nil, skip_fields = [])
|
|
77
|
+
new.update_attributes(data, skip_fields)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def schema_include(mod)
|
|
@@ -82,7 +82,8 @@ module Schema
|
|
|
82
82
|
config[:schema_includes] = config[:schema_includes] + [mod]
|
|
83
83
|
redefine_class_method(:schema_config, config.freeze)
|
|
84
84
|
include mod
|
|
85
|
-
|
|
85
|
+
|
|
86
|
+
schema.each_value do |field_options|
|
|
86
87
|
next unless field_options[:association]
|
|
87
88
|
|
|
88
89
|
const_get(field_options[:class_name]).schema_include(mod)
|
|
@@ -91,7 +92,7 @@ module Schema
|
|
|
91
92
|
|
|
92
93
|
def add_attribute_methods(name, options)
|
|
93
94
|
class_eval(
|
|
94
|
-
<<-STR, __FILE__, __LINE__ + 1
|
|
95
|
+
<<-STR, __FILE__, __LINE__ + 1
|
|
95
96
|
def #{options[:getter]}
|
|
96
97
|
#{options[:instance_variable]}
|
|
97
98
|
end
|
|
@@ -99,7 +100,11 @@ module Schema
|
|
|
99
100
|
def #{options[:setter]}(v)
|
|
100
101
|
#{options[:instance_variable]} = #{options[:parser]}(#{name.inspect}, parsing_errors, v)
|
|
101
102
|
end
|
|
102
|
-
|
|
103
|
+
|
|
104
|
+
def #{options[:getter]}_was_set?
|
|
105
|
+
instance_variable_defined?(:#{options[:instance_variable]})
|
|
106
|
+
end
|
|
107
|
+
STR
|
|
103
108
|
)
|
|
104
109
|
end
|
|
105
110
|
|
|
@@ -114,27 +119,27 @@ STR
|
|
|
114
119
|
end
|
|
115
120
|
end
|
|
116
121
|
|
|
117
|
-
def update_attributes(data)
|
|
122
|
+
def update_attributes(data = nil, skip_fields = [])
|
|
118
123
|
schema = get_schema(data)
|
|
119
|
-
update_model_attributes(schema, data)
|
|
120
|
-
update_associations(schema, data)
|
|
124
|
+
update_model_attributes(schema, data, skip_fields)
|
|
125
|
+
update_associations(schema, data, skip_fields)
|
|
121
126
|
self
|
|
122
127
|
end
|
|
123
128
|
|
|
124
129
|
def as_json(opts = {})
|
|
125
130
|
self.class.schema.each_with_object({}) do |(field_name, field_options), memo|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
131
|
+
next if field_options[:alias_of]
|
|
132
|
+
|
|
133
|
+
value = public_send(field_options[:getter])
|
|
134
|
+
next if value.nil? && !opts[:include_nils]
|
|
135
|
+
next if opts[:select_filter] && !opts[:select_filter].call(field_name, value, field_options)
|
|
136
|
+
next if opts[:reject_filter]&.call(field_name, value, field_options)
|
|
137
|
+
|
|
138
|
+
memo[field_name] = if value.is_a?(Array)
|
|
139
|
+
value.map { |e| e.as_json(opts) }
|
|
140
|
+
else
|
|
141
|
+
value.respond_to?(:as_json) ? value.as_json(opts) : value
|
|
142
|
+
end
|
|
138
143
|
end
|
|
139
144
|
end
|
|
140
145
|
|
|
@@ -156,15 +161,15 @@ STR
|
|
|
156
161
|
private
|
|
157
162
|
|
|
158
163
|
def get_schema(data)
|
|
159
|
-
|
|
160
|
-
break unless key.is_a?(Symbol)
|
|
164
|
+
return self.class.schema_with_string_keys unless data.is_a?(Hash)
|
|
161
165
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
166
|
+
first_key = data.each_key.first
|
|
167
|
+
return self.class.schema_with_string_keys unless first_key.is_a?(Symbol)
|
|
168
|
+
|
|
169
|
+
self.class.schema
|
|
165
170
|
end
|
|
166
171
|
|
|
167
|
-
def update_model_attributes(schema, data)
|
|
172
|
+
def update_model_attributes(schema, data, skip_fields)
|
|
168
173
|
data.each do |key, value|
|
|
169
174
|
unless schema.key?(key)
|
|
170
175
|
parsing_errors.add(key, ::Schema::ParsingErrors::UNKNOWN_ATTRIBUTE) if self.class.capture_unknown_attributes?
|
|
@@ -172,17 +177,20 @@ STR
|
|
|
172
177
|
end
|
|
173
178
|
|
|
174
179
|
next if schema[key][:association]
|
|
180
|
+
next if skip_fields.include?(key)
|
|
175
181
|
|
|
176
182
|
public_send(schema[key][:setter], value)
|
|
177
183
|
end
|
|
178
184
|
end
|
|
179
185
|
|
|
180
|
-
def update_associations(schema, data)
|
|
186
|
+
def update_associations(schema, data, skip_fields)
|
|
181
187
|
data.each do |key, value|
|
|
182
188
|
next unless schema.key?(key)
|
|
183
189
|
next unless schema[key][:association]
|
|
184
190
|
|
|
185
|
-
|
|
191
|
+
association_skip_fields = skip_fields.detect { |f| f.is_a?(Hash) && f.include?(key) }
|
|
192
|
+
association_skip_fields = association_skip_fields ? association_skip_fields[key] : []
|
|
193
|
+
public_send(schema[key][:setter], value, association_skip_fields)
|
|
186
194
|
end
|
|
187
195
|
end
|
|
188
196
|
end
|
data/lib/schema/parsers/array.rb
CHANGED
|
@@ -15,10 +15,10 @@ module Schema
|
|
|
15
15
|
return data
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
parsing_errors.add(field_name, ::Schema::ParsingErrors::
|
|
18
|
+
parsing_errors.add(field_name, ::Schema::ParsingErrors::INCOMPATIBLE)
|
|
19
19
|
nil
|
|
20
20
|
else
|
|
21
|
-
parsing_errors.add(field_name, ::Schema::ParsingErrors::
|
|
21
|
+
parsing_errors.add(field_name, ::Schema::ParsingErrors::INCOMPATIBLE)
|
|
22
22
|
nil
|
|
23
23
|
end
|
|
24
24
|
end
|
|
@@ -6,11 +6,10 @@ module Schema
|
|
|
6
6
|
module Parsers
|
|
7
7
|
# Schema::Parsers::Common are parser methods for basic types
|
|
8
8
|
module Common
|
|
9
|
-
INTEGER_REGEX = /^[-+]?(?:[1-9]\d*|0)(?:\.0+)
|
|
10
|
-
FLOAT_REGEX = /^[-+]?(?:[1-9]\d*|0)(?:\.\d+)?([Ee]-?\d+)
|
|
11
|
-
BOOLEAN_REGEX = /^(?:1|t|true|on|y|yes)$/i
|
|
9
|
+
INTEGER_REGEX = /^[-+]?(?:[1-9]\d*|0)(?:\.0+)?$/
|
|
10
|
+
FLOAT_REGEX = /^[-+]?(?:[1-9]\d*|0)(?:\.\d+)?([Ee]-?\d+)?$/
|
|
11
|
+
BOOLEAN_REGEX = /^(?:1|t|true|on|y|yes)$/i
|
|
12
12
|
|
|
13
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
|
14
13
|
def parse_integer(field_name, parsing_errors, value)
|
|
15
14
|
case value
|
|
16
15
|
when Integer
|
|
@@ -23,7 +22,7 @@ module Schema
|
|
|
23
22
|
nil
|
|
24
23
|
end
|
|
25
24
|
when Float
|
|
26
|
-
parsing_errors.add(field_name, ::Schema::ParsingErrors::
|
|
25
|
+
parsing_errors.add(field_name, ::Schema::ParsingErrors::INCOMPATIBLE) if (value % 1) > 0.0
|
|
27
26
|
value.to_i
|
|
28
27
|
when nil
|
|
29
28
|
nil
|
|
@@ -32,14 +31,13 @@ module Schema
|
|
|
32
31
|
nil
|
|
33
32
|
end
|
|
34
33
|
end
|
|
35
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
|
36
34
|
|
|
37
35
|
def parse_string(field_name, parsing_errors, value)
|
|
38
36
|
case value
|
|
39
37
|
when String
|
|
40
38
|
value
|
|
41
39
|
when ::Hash, ::Array
|
|
42
|
-
parsing_errors.add(field_name, ::Schema::ParsingErrors::
|
|
40
|
+
parsing_errors.add(field_name, ::Schema::ParsingErrors::INCOMPATIBLE)
|
|
43
41
|
nil
|
|
44
42
|
when nil
|
|
45
43
|
nil
|
|
@@ -54,7 +52,7 @@ module Schema
|
|
|
54
52
|
when String
|
|
55
53
|
value.empty? ? nil : value
|
|
56
54
|
when ::Hash, ::Array
|
|
57
|
-
parsing_errors.add(field_name, ::Schema::ParsingErrors::
|
|
55
|
+
parsing_errors.add(field_name, ::Schema::ParsingErrors::INCOMPATIBLE)
|
|
58
56
|
nil
|
|
59
57
|
when nil
|
|
60
58
|
nil
|
data/lib/schema/parsers/hash.rb
CHANGED
data/lib/schema/parsers/json.rb
CHANGED
|
@@ -4,7 +4,7 @@ module Schema
|
|
|
4
4
|
# Schema::ParsingErrors is a collection of parsing error messages
|
|
5
5
|
module ParsingErrors
|
|
6
6
|
INVALID = 'invalid'
|
|
7
|
-
|
|
7
|
+
INCOMPATIBLE = 'incompatible'
|
|
8
8
|
UNKNOWN = 'unknown'
|
|
9
9
|
UNKNOWN_ATTRIBUTE = 'unknown_attribute'
|
|
10
10
|
UNHANDLED_TYPE = 'unhandled_type'
|
data/lib/schema/utils.rb
CHANGED
|
@@ -25,7 +25,7 @@ module Schema
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def association_options(schema_name, schema_type, options)
|
|
28
|
-
options[:class_name] ||=
|
|
28
|
+
options[:class_name] ||= "Schema#{classify_name(schema_type.to_s)}#{classify_name(schema_name.to_s)}"
|
|
29
29
|
options[:association] = true
|
|
30
30
|
options[:aliases] = [options[:alias]] if options.key?(:alias)
|
|
31
31
|
options[:hash_key_field] ||= :id if options[:from] == :hash
|
|
@@ -58,7 +58,7 @@ module Schema
|
|
|
58
58
|
|
|
59
59
|
def add_attribute_default_methods(kls, options)
|
|
60
60
|
kls.class_eval(
|
|
61
|
-
|
|
61
|
+
<<-STR, __FILE__, __LINE__ + 1
|
|
62
62
|
def #{options[:default_method]}
|
|
63
63
|
#{options[:default].inspect}
|
|
64
64
|
end
|
|
@@ -70,13 +70,13 @@ module Schema
|
|
|
70
70
|
#{options[:instance_variable]}
|
|
71
71
|
end
|
|
72
72
|
end
|
|
73
|
-
STR
|
|
73
|
+
STR
|
|
74
74
|
)
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def add_association_default_methods(kls, options)
|
|
78
78
|
kls.class_eval(
|
|
79
|
-
|
|
79
|
+
<<-STR, __FILE__, __LINE__ + 1
|
|
80
80
|
def #{options[:default_method]}
|
|
81
81
|
#{options[:default_code]}
|
|
82
82
|
end
|
|
@@ -84,7 +84,7 @@ STR
|
|
|
84
84
|
def #{options[:getter]}
|
|
85
85
|
#{options[:instance_variable]} ||= #{options[:default_method]}
|
|
86
86
|
end
|
|
87
|
-
STR
|
|
87
|
+
STR
|
|
88
88
|
)
|
|
89
89
|
end
|
|
90
90
|
end
|
data/lib/schema-model.rb
CHANGED
data/schema-model.gemspec
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |s|
|
|
4
4
|
s.name = 'schema-model'
|
|
5
|
-
s.version = '0.
|
|
5
|
+
s.version = '0.7.0'
|
|
6
6
|
s.licenses = ['MIT']
|
|
7
|
-
s.summary = '
|
|
8
|
-
s.description = '
|
|
7
|
+
s.summary = 'Data transformation, validation, and type safety for Ruby'
|
|
8
|
+
s.description = 'A flexible DSL for defining strongly-typed data models with automatic parsing, ' \
|
|
9
|
+
'nested associations, dynamic types, and ActiveModel validations'
|
|
9
10
|
s.authors = ['Doug Youch']
|
|
10
11
|
s.email = 'dougyouch@gmail.com'
|
|
11
12
|
s.homepage = 'https://github.com/dougyouch/schema'
|
|
@@ -13,5 +14,6 @@ Gem::Specification.new do |s|
|
|
|
13
14
|
s.bindir = 'bin'
|
|
14
15
|
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
15
16
|
|
|
16
|
-
s.
|
|
17
|
+
s.add_dependency 'inheritance-helper'
|
|
18
|
+
s.metadata['rubygems_mfa_required'] = 'true'
|
|
17
19
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: schema-model
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Doug Youch
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 2026-02-01 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: inheritance-helper
|
|
@@ -24,23 +23,25 @@ dependencies:
|
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
25
|
version: '0'
|
|
27
|
-
description:
|
|
26
|
+
description: A flexible DSL for defining strongly-typed data models with automatic
|
|
27
|
+
parsing, nested associations, dynamic types, and ActiveModel validations
|
|
28
28
|
email: dougyouch@gmail.com
|
|
29
29
|
executables:
|
|
30
30
|
- schema-json2csv
|
|
31
31
|
extensions: []
|
|
32
32
|
extra_rdoc_files: []
|
|
33
33
|
files:
|
|
34
|
+
- ".github/workflows/ci.yml"
|
|
34
35
|
- ".gitignore"
|
|
35
36
|
- ".rubocop.yml"
|
|
36
37
|
- ".ruby-gemset"
|
|
37
38
|
- ".ruby-version"
|
|
38
|
-
-
|
|
39
|
+
- ARCHITECTURE.md
|
|
40
|
+
- CLAUDE.md
|
|
39
41
|
- Gemfile
|
|
40
42
|
- Gemfile.lock
|
|
41
43
|
- LICENSE.txt
|
|
42
44
|
- README.md
|
|
43
|
-
- Rakefile
|
|
44
45
|
- bin/schema-json2csv
|
|
45
46
|
- lib/schema-model.rb
|
|
46
47
|
- lib/schema/active_model_validations.rb
|
|
@@ -64,14 +65,12 @@ files:
|
|
|
64
65
|
- lib/schema/utils.rb
|
|
65
66
|
- lib/schema_validator.rb
|
|
66
67
|
- schema-model.gemspec
|
|
67
|
-
- script/bundle_install_all_versions
|
|
68
68
|
- script/console
|
|
69
|
-
- script/rspec_all_versions
|
|
70
69
|
homepage: https://github.com/dougyouch/schema
|
|
71
70
|
licenses:
|
|
72
71
|
- MIT
|
|
73
|
-
metadata:
|
|
74
|
-
|
|
72
|
+
metadata:
|
|
73
|
+
rubygems_mfa_required: 'true'
|
|
75
74
|
rdoc_options: []
|
|
76
75
|
require_paths:
|
|
77
76
|
- lib
|
|
@@ -86,8 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
86
85
|
- !ruby/object:Gem::Version
|
|
87
86
|
version: '0'
|
|
88
87
|
requirements: []
|
|
89
|
-
rubygems_version: 3.
|
|
90
|
-
signing_key:
|
|
88
|
+
rubygems_version: 3.6.2
|
|
91
89
|
specification_version: 4
|
|
92
|
-
summary:
|
|
90
|
+
summary: Data transformation, validation, and type safety for Ruby
|
|
93
91
|
test_files: []
|
data/.travis.yml
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
env:
|
|
2
|
-
global:
|
|
3
|
-
- CC_TEST_REPORTER_ID=f06234974aa4c4c52d14cb9ef800df79de52013c38e1d149fd04f2284e722f57
|
|
4
|
-
rvm:
|
|
5
|
-
- 3.1.0
|
|
6
|
-
language: ruby
|
|
7
|
-
before_script:
|
|
8
|
-
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
|
9
|
-
- chmod +x ./cc-test-reporter
|
|
10
|
-
- ./cc-test-reporter before-build
|
|
11
|
-
script:
|
|
12
|
-
- bundle exec rspec
|
|
13
|
-
after_script:
|
|
14
|
-
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
data/Rakefile
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rubygems'
|
|
4
|
-
require 'bundler/setup'
|
|
5
|
-
require 'rake'
|
|
6
|
-
require 'rspec/core/rake_task'
|
|
7
|
-
RSpec::Core::RakeTask.new(:spec) do |t|
|
|
8
|
-
t.pattern = Dir.glob('spec/**/*_spec.rb')
|
|
9
|
-
t.rspec_opts = '--format documentation'
|
|
10
|
-
end
|
|
11
|
-
task default: :spec
|