schema-model 0.2.0 → 0.3.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/lib/schema/associations/base.rb +29 -0
- data/lib/schema/associations/dynamic_types.rb +48 -0
- data/lib/schema/associations/has_many.rb +9 -5
- data/lib/schema/associations/has_one.rb +9 -5
- data/lib/schema/associations/schema_creator.rb +88 -0
- data/lib/schema/parsers/array.rb +41 -0
- data/lib/schema/parsers/common.rb +1 -1
- data/lib/schema/parsers/hash.rb +18 -0
- data/lib/schema/parsers/json.rb +24 -0
- data/lib/schema/utils.rb +26 -38
- data/lib/schema.rb +6 -0
- data/lib/schema_validator.rb +8 -0
- metadata +10 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75daea073072722da9fb5e80565a35fe6861ab6293d757a2d91b76769835c119
|
4
|
+
data.tar.gz: ed1036610bf036e2bf96baf3f39561cd91063ca48cecace447b80129f7409db2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e5475f9dc0c8b844083619584376988a8d7dabe763fd2abe67929c472093a2bb5e2a6bbb4d42cc1400cdbb5a7c8d8532bc7f3733d44fc66f4cd07b63debe365
|
7
|
+
data.tar.gz: 5a214b983dd1c2fbf298ddbc74667cda767ee20fb29c735e2dfc1ca4a8e44f3f1df208412b518b76314ca0c12b0d59e90ba66b7f7b2ba96a6b1f1b1793ef1ab0
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Schema
|
4
|
+
module Associations
|
5
|
+
# Schema::Associations::Base common class methods between associations
|
6
|
+
module Base
|
7
|
+
def self.included(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
# no-doc
|
12
|
+
module ClassMethods
|
13
|
+
attr_accessor :schema_name
|
14
|
+
|
15
|
+
def base_schema_class=(kls)
|
16
|
+
@base_schema_class_name = kls.name
|
17
|
+
end
|
18
|
+
|
19
|
+
def base_schema_class
|
20
|
+
Object.const_get(@base_schema_class_name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def schema_options
|
24
|
+
base_schema_class.schema[schema_name]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Schema
|
4
|
+
module Associations
|
5
|
+
# Schema::Associations::DynamicTypes adds support for adding dynamic types to associations
|
6
|
+
module DynamicTypes
|
7
|
+
def self.included(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
# no-doc
|
12
|
+
module ClassMethods
|
13
|
+
def add_type(type, options = {}, &block)
|
14
|
+
class_name = options[:class_name] || schema_dynamic_type_class_name(type)
|
15
|
+
kls = Class.new(self)
|
16
|
+
kls = base_schema_class.const_set(class_name, kls)
|
17
|
+
schema_add_dynamic_type(type, class_name)
|
18
|
+
kls.class_eval(&block) if block
|
19
|
+
kls
|
20
|
+
end
|
21
|
+
|
22
|
+
def dynamic_types
|
23
|
+
schema_options[:types]
|
24
|
+
end
|
25
|
+
|
26
|
+
def dynamic_type_names
|
27
|
+
dynamic_types.keys
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def schema_dynamic_type_class_name(type)
|
33
|
+
::Schema::Utils.classify_name(schema_name.to_s) +
|
34
|
+
'AssociationType' +
|
35
|
+
::Schema::Utils.classify_name(type.to_s)
|
36
|
+
end
|
37
|
+
|
38
|
+
def schema_add_dynamic_type(type, class_name)
|
39
|
+
new_schema_options = schema_options.dup
|
40
|
+
new_schema_options[:types] ||= {}
|
41
|
+
new_schema_options[:types][type] = class_name
|
42
|
+
base_schema_class.add_value_to_class_method(:schema, schema_name => new_schema_options)
|
43
|
+
new_schema_options
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -12,7 +12,7 @@ module Schema
|
|
12
12
|
module ClassMethods
|
13
13
|
# rubocop:disable Naming/PredicateName
|
14
14
|
def has_many(name, options = {}, &block)
|
15
|
-
options = ::Schema::Utils.add_association_class(self, name, :has_many, options
|
15
|
+
options = ::Schema::Utils.add_association_class(self, name, :has_many, options)
|
16
16
|
|
17
17
|
class_eval(
|
18
18
|
<<~STR, __FILE__, __LINE__ + 1
|
@@ -20,15 +20,19 @@ module Schema
|
|
20
20
|
#{options[:instance_variable]}
|
21
21
|
end
|
22
22
|
|
23
|
+
def #{name}_schema_creator
|
24
|
+
@#{name}_schema_creator ||= ::Schema::Associations::SchemaCreator.new(self, #{name.inspect})
|
25
|
+
end
|
26
|
+
|
23
27
|
def #{options[:setter]}(v)
|
24
|
-
|
25
|
-
#{options[:instance_variable]} = schemas
|
26
|
-
end
|
28
|
+
#{options[:instance_variable]} = #{name}_schema_creator.create_schemas(self, v)
|
27
29
|
end
|
28
30
|
STR
|
29
31
|
)
|
30
32
|
|
31
|
-
const_get(options[:class_name])
|
33
|
+
kls = const_get(options[:class_name])
|
34
|
+
kls.class_eval(&block) if block
|
35
|
+
kls
|
32
36
|
end
|
33
37
|
# rubocop:enable Naming/PredicateName
|
34
38
|
end
|
@@ -12,7 +12,7 @@ module Schema
|
|
12
12
|
module ClassMethods
|
13
13
|
# rubocop:disable Naming/PredicateName
|
14
14
|
def has_one(name, options = {}, &block)
|
15
|
-
options = ::Schema::Utils.add_association_class(self, name, :has_one, options
|
15
|
+
options = ::Schema::Utils.add_association_class(self, name, :has_one, options)
|
16
16
|
|
17
17
|
class_eval(
|
18
18
|
<<~STR, __FILE__, __LINE__ + 1
|
@@ -20,15 +20,19 @@ module Schema
|
|
20
20
|
#{options[:instance_variable]}
|
21
21
|
end
|
22
22
|
|
23
|
+
def #{name}_schema_creator
|
24
|
+
@#{name}_schema_creator ||= ::Schema::Associations::SchemaCreator.new(self, #{name.inspect})
|
25
|
+
end
|
26
|
+
|
23
27
|
def #{options[:setter]}(v)
|
24
|
-
|
25
|
-
#{options[:instance_variable]} = schema
|
26
|
-
end
|
28
|
+
#{options[:instance_variable]} = #{name}_schema_creator.create_schema(self, v)
|
27
29
|
end
|
28
30
|
STR
|
29
31
|
)
|
30
32
|
|
31
|
-
const_get(options[:class_name])
|
33
|
+
kls = const_get(options[:class_name])
|
34
|
+
kls.class_eval(&block) if block
|
35
|
+
kls
|
32
36
|
end
|
33
37
|
# rubocop:enable Naming/PredicateName
|
34
38
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Schema
|
4
|
+
module Associations
|
5
|
+
# Schema::Associations::SchemaCreator is used to create schema objects for associations
|
6
|
+
class SchemaCreator
|
7
|
+
def initialize(base_schema, name)
|
8
|
+
options = base_schema.class.schema[name]
|
9
|
+
@schema_name = name
|
10
|
+
@schema_class = base_schema.class.const_get(options[:class_name])
|
11
|
+
@aliases = options[:aliases] || []
|
12
|
+
@type_field = options[:type_field]
|
13
|
+
@external_type_field = options[:external_type_field]
|
14
|
+
@types = options[:types]
|
15
|
+
@ignorecase = !options[:type_ignorecase].nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_schema(base_schema, data, error_name = nil)
|
19
|
+
if data.is_a?(Hash)
|
20
|
+
unless (schema_class = get_schema_class(base_schema, data))
|
21
|
+
add_parsing_error(base_schema, error_name, :unknown)
|
22
|
+
return nil
|
23
|
+
end
|
24
|
+
schema = schema_class.from_hash(data)
|
25
|
+
add_parsing_error(base_schema, error_name, :invalid) unless schema.parsing_errors.empty?
|
26
|
+
schema
|
27
|
+
elsif !data.nil?
|
28
|
+
add_parsing_error(base_schema, error_name, :incompatable)
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_schemas(base_schema, list)
|
34
|
+
if list.is_a?(Array)
|
35
|
+
list.each_with_index.map { |data, idx| create_schema(base_schema, data, "#{@schema_name}:#{idx}") }
|
36
|
+
elsif !list.nil?
|
37
|
+
add_parsing_error(base_schema, @schema_name, :incompatable)
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_schema_class(base_schema, data)
|
43
|
+
if dynamic?
|
44
|
+
get_dynamic_schema_class(base_schema, data)
|
45
|
+
else
|
46
|
+
@schema_class
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def dynamic?
|
51
|
+
!@type_field.nil? || !@external_type_field.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_dynamic_schema_class(base_schema, data)
|
55
|
+
type = get_dynamic_type(base_schema, data)
|
56
|
+
type = type.to_s.downcase if @ignorecase
|
57
|
+
@types.each do |name, class_name|
|
58
|
+
name = name.downcase if @ignorecase
|
59
|
+
return base_schema.class.const_get(class_name) if name == type
|
60
|
+
end
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_dynamic_type(base_schema, data)
|
65
|
+
if @type_field
|
66
|
+
type_fields.each do |name|
|
67
|
+
type = data[name]
|
68
|
+
return type if type
|
69
|
+
end
|
70
|
+
nil
|
71
|
+
elsif @external_type_field
|
72
|
+
base_schema.public_send(@external_type_field)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def type_fields
|
77
|
+
@type_fields ||= [
|
78
|
+
@type_field,
|
79
|
+
@type_field.to_s
|
80
|
+
] + @aliases
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_parsing_error(base_schema, error_name, error_msg)
|
84
|
+
base_schema.parsing_errors.add(error_name || @schema_name, error_msg)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Schema
|
4
|
+
module Parsers
|
5
|
+
# Schema::Parsers::Array adds the array type to schemas
|
6
|
+
module Array
|
7
|
+
def parse_array(field_name, parsing_errors, value)
|
8
|
+
case value
|
9
|
+
when ::Array
|
10
|
+
value
|
11
|
+
when String
|
12
|
+
schema_options = self.class.schema[field_name]
|
13
|
+
if (data = Array.parse_string_array(self, field_name, parsing_errors, value, schema_options))
|
14
|
+
return data
|
15
|
+
end
|
16
|
+
|
17
|
+
parsing_errors.add(field_name, :incompatable)
|
18
|
+
nil
|
19
|
+
else
|
20
|
+
parsing_errors.add(field_name, :incompatable)
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.parse_string_array(model, field_name, parsing_errors, value, schema_options)
|
26
|
+
return nil unless (separator = schema_options[:separator])
|
27
|
+
|
28
|
+
convert_array_values(model, field_name, parsing_errors, value.split(separator), schema_options)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.convert_array_values(model, field_name, parsing_errors, data, schema_options)
|
32
|
+
return data unless (data_type = schema_options[:data_type])
|
33
|
+
|
34
|
+
parser_method = "parse_#{data_type}"
|
35
|
+
data.each_with_index.map do |datum, idx|
|
36
|
+
model.send(parser_method, "#{field_name}:#{idx}", parsing_errors, datum)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Schema
|
4
|
+
module Parsers
|
5
|
+
# Schema::Parsers::Hash adds the hash type to schemas
|
6
|
+
module Hash
|
7
|
+
def parse_hash(field_name, parsing_errors, value)
|
8
|
+
case value
|
9
|
+
when ::Hash
|
10
|
+
value
|
11
|
+
else
|
12
|
+
parsing_errors.add(field_name, :incompatable)
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Schema
|
5
|
+
module Parsers
|
6
|
+
# Schema::Parsers::Json parse the string as json
|
7
|
+
module Json
|
8
|
+
def parse_json(field_name, parsing_errors, value)
|
9
|
+
case value
|
10
|
+
when String
|
11
|
+
begin
|
12
|
+
::JSON.parse(value)
|
13
|
+
rescue ::JSON::ParserError
|
14
|
+
parsing_errors.add(field_name, :invalid)
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
else
|
18
|
+
parsing_errors.add(field_name, :incompatable)
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/schema/utils.rb
CHANGED
@@ -9,15 +9,11 @@ module Schema
|
|
9
9
|
name.gsub(/[^\da-z_-]/, '').gsub(/(^.|[_|-].)/) { |m| m[-1].upcase }
|
10
10
|
end
|
11
11
|
|
12
|
-
def create_schema_class(base_schema_class,
|
13
|
-
|
14
|
-
|
15
|
-
kls = base_schema_class.
|
16
|
-
|
17
|
-
include_schema_modules(kls, base_schema_class.schema_config) if base_class == Object
|
18
|
-
|
19
|
-
kls.class_eval(&block) if block
|
20
|
-
|
12
|
+
def create_schema_class(base_schema_class, schema_name, options)
|
13
|
+
base_schema_class.add_value_to_class_method(:schema, schema_name => options)
|
14
|
+
kls = Class.new(options[:base_class] || Object)
|
15
|
+
kls = base_schema_class.const_set(options[:class_name], kls)
|
16
|
+
include_schema_modules(kls, base_schema_class.schema_config) unless options[:base_class]
|
21
17
|
kls
|
22
18
|
end
|
23
19
|
|
@@ -28,41 +24,33 @@ module Schema
|
|
28
24
|
end
|
29
25
|
end
|
30
26
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
base_schema.parsing_errors.add(schema_name, :invalid) unless schema.parsing_errors.empty?
|
35
|
-
schema
|
36
|
-
elsif !data.nil?
|
37
|
-
base_schema.parsing_errors.add(schema_name, :incompatable)
|
38
|
-
nil
|
39
|
-
end
|
27
|
+
def association_options(schema_name, schema_type, options)
|
28
|
+
options[:class_name] ||= 'Schema' + classify_name(schema_type.to_s) + classify_name(schema_name.to_s)
|
29
|
+
::Schema::Model.default_attribute_options(schema_name, schema_type).merge(options)
|
40
30
|
end
|
41
31
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
32
|
+
def add_association_class(base_schema_class, schema_name, schema_type, options)
|
33
|
+
options = ::Schema::Utils.association_options(schema_name, schema_type, options)
|
34
|
+
kls = ::Schema::Utils.create_schema_class(
|
35
|
+
base_schema_class,
|
36
|
+
schema_name,
|
37
|
+
options
|
38
|
+
)
|
39
|
+
add_association_defaults(kls, base_schema_class, schema_name)
|
40
|
+
add_association_dynamic_types(kls, options)
|
41
|
+
options
|
49
42
|
end
|
50
43
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
44
|
+
def add_association_defaults(kls, base_schema_class, schema_name)
|
45
|
+
kls.include ::Schema::Associations::Base
|
46
|
+
kls.base_schema_class = base_schema_class
|
47
|
+
kls.schema_name = schema_name
|
54
48
|
end
|
55
49
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
options[:class_name],
|
61
|
-
options[:base_class] || Object,
|
62
|
-
&block
|
63
|
-
)
|
64
|
-
base_schema_class.add_value_to_class_method(:schema, name => options)
|
65
|
-
options
|
50
|
+
def add_association_dynamic_types(kls, options)
|
51
|
+
return if !options[:type_field] && !options[:external_type_field]
|
52
|
+
|
53
|
+
kls.include ::Schema::Associations::DynamicTypes
|
66
54
|
end
|
67
55
|
end
|
68
56
|
end
|
data/lib/schema.rb
CHANGED
@@ -12,12 +12,18 @@ module Schema
|
|
12
12
|
|
13
13
|
# Schema::Parsers are used to convert values into the correct data type
|
14
14
|
module Parsers
|
15
|
+
autoload :Array, 'schema/parsers/array'
|
15
16
|
autoload :Common, 'schema/parsers/common'
|
17
|
+
autoload :Hash, 'schema/parsers/hash'
|
18
|
+
autoload :Json, 'schema/parsers/json'
|
16
19
|
end
|
17
20
|
|
18
21
|
# Schema::Associations mange the associations between schema models
|
19
22
|
module Associations
|
23
|
+
autoload :Base, 'schema/associations/base'
|
24
|
+
autoload :DynamicTypes, 'schema/associations/dynamic_types'
|
20
25
|
autoload :HasMany, 'schema/associations/has_many'
|
21
26
|
autoload :HasOne, 'schema/associations/has_one'
|
27
|
+
autoload :SchemaCreator, 'schema/associations/schema_creator'
|
22
28
|
end
|
23
29
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# SchemaValidator validates nested schemas
|
4
|
+
class SchemaValidator < ActiveModel::EachValidator
|
5
|
+
def validate_each(record, attribute, value)
|
6
|
+
record.errors.add(attribute, options.fetch(:message, :invalid)) if value && !value.valid?
|
7
|
+
end
|
8
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: schema-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Doug Youch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: inheritance-helper
|
@@ -33,13 +33,20 @@ files:
|
|
33
33
|
- lib/schema.rb
|
34
34
|
- lib/schema/array_headers.rb
|
35
35
|
- lib/schema/arrays.rb
|
36
|
+
- lib/schema/associations/base.rb
|
37
|
+
- lib/schema/associations/dynamic_types.rb
|
36
38
|
- lib/schema/associations/has_many.rb
|
37
39
|
- lib/schema/associations/has_one.rb
|
40
|
+
- lib/schema/associations/schema_creator.rb
|
38
41
|
- lib/schema/csv_parser.rb
|
39
42
|
- lib/schema/errors.rb
|
40
43
|
- lib/schema/model.rb
|
44
|
+
- lib/schema/parsers/array.rb
|
41
45
|
- lib/schema/parsers/common.rb
|
46
|
+
- lib/schema/parsers/hash.rb
|
47
|
+
- lib/schema/parsers/json.rb
|
42
48
|
- lib/schema/utils.rb
|
49
|
+
- lib/schema_validator.rb
|
43
50
|
homepage: https://github.com/dougyouch/schema
|
44
51
|
licenses:
|
45
52
|
- MIT
|
@@ -59,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
66
|
- !ruby/object:Gem::Version
|
60
67
|
version: '0'
|
61
68
|
requirements: []
|
62
|
-
rubygems_version: 3.0.
|
69
|
+
rubygems_version: 3.0.4
|
63
70
|
signing_key:
|
64
71
|
specification_version: 4
|
65
72
|
summary: Schema Model
|