typero 0.5.2 → 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/.version +1 -1
- data/lib/adapters/sequel.rb +3 -12
- data/lib/typero.rb +4 -188
- data/lib/typero/schema.rb +84 -0
- data/lib/typero/type.rb +39 -28
- data/lib/typero/type/array.rb +2 -2
- data/lib/typero/type/date.rb +4 -0
- data/lib/typero/type/datetime.rb +4 -0
- data/lib/typero/type/email.rb +1 -1
- data/lib/typero/type/float.rb +1 -1
- data/lib/typero/type/hash.rb +7 -1
- data/lib/typero/type/image.rb +28 -0
- data/lib/typero/type/integer.rb +2 -1
- data/lib/typero/type/label.rb +1 -2
- data/lib/typero/type/oib.rb +1 -1
- data/lib/typero/type/point.rb +8 -2
- data/lib/typero/type/string.rb +3 -2
- data/lib/typero/type/text.rb +3 -1
- data/lib/typero/type/url.rb +1 -1
- data/lib/typero/typero.rb +191 -0
- metadata +6 -4
- data/lib/typero/type/geography.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 448ffb9631eeb66159f13e45da0e28e600f91f3ed58684789740f2ad351a317b
|
4
|
+
data.tar.gz: 41feafdf4c139e47c02dc71c0c5dbdea154b6e75e0b8a746e1b7f41c6beb89d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 28c28657d7a0c7c5e71b5cfac08eb314a857c9b4e01337666ab38f65c64aa99f1c07a56d3276f8446e0134bc28968b7b34fb13232769c97ed01c6847cdab657e
|
7
|
+
data.tar.gz: 65f56f37df4731adad738862fdb79ed540bdd22a3a85744f519370e4ae5d905bafa74ab4720d17d6916c068a4f9508225d20cde64a6735c29a9f9e978a9ef145
|
data/.version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
data/lib/adapters/sequel.rb
CHANGED
@@ -1,19 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'typero'
|
4
|
-
|
5
3
|
module Sequel::Plugins::TyperoAttributes
|
6
4
|
module ClassMethods
|
7
|
-
|
8
|
-
instance_variable_set :@typero, Typero.new(&block)
|
9
|
-
|
10
|
-
# attributes migrate: true do ...
|
11
|
-
AutoMigrate.typero to_s.tableize.to_sym if opts[:migrate] && Lux.config.migrate
|
12
|
-
end
|
13
|
-
|
14
|
-
def typero
|
15
|
-
instance_variable_get :@typero
|
16
|
-
end
|
5
|
+
attr_accessor :typero
|
17
6
|
end
|
18
7
|
|
19
8
|
module InstanceMethods
|
@@ -27,6 +16,8 @@ module Sequel::Plugins::TyperoAttributes
|
|
27
16
|
|
28
17
|
# this are rules unique to database, so we check them here
|
29
18
|
typero.rules.each do |field, rule|
|
19
|
+
self[field] ||= {} if rule[:type] == 'hash'
|
20
|
+
|
30
21
|
# check uniqe fields
|
31
22
|
if rule[:unique]
|
32
23
|
id = self[:id] || 0
|
data/lib/typero.rb
CHANGED
@@ -1,193 +1,9 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
# set :skills, [:email], min: 2
|
5
|
-
# end
|
6
|
-
#
|
7
|
-
# or
|
8
|
-
#
|
9
|
-
# rules = Typero.new do
|
10
|
-
# string :name, req: true
|
11
|
-
# email :email, req: true
|
12
|
-
# email [:skills], min: 2
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
# errors = rules.validate @object
|
16
|
-
# rules.valid?
|
17
|
-
# rules.validate(@object) { |errors| ... }
|
18
|
-
|
19
|
-
class Typero
|
20
|
-
attr_reader :rules
|
21
|
-
|
22
|
-
VERSION = File.read File.expand_path '../.version', File.dirname(__FILE__)
|
23
|
-
|
24
|
-
class << self
|
25
|
-
# validate single value in type
|
26
|
-
def validate type, value, opts={}
|
27
|
-
field = type.to_s.tableize.singularize.to_sym
|
28
|
-
|
29
|
-
# we need to have pointer to hash, so value can be changed (coerced) if needed
|
30
|
-
h = { field => value }
|
31
|
-
|
32
|
-
rule = new
|
33
|
-
rule.set field, type, opts
|
34
|
-
|
35
|
-
if error = rule.validate(h)[field]
|
36
|
-
block_given? ? yield(error) : raise(TypeError.new(error))
|
37
|
-
end
|
38
|
-
|
39
|
-
h[field]
|
40
|
-
end
|
41
|
-
|
42
|
-
# check and coerce value
|
43
|
-
# Typero.set(:label, 'Foo bar') -> "foo-bar"
|
44
|
-
def set type, value, opts={}
|
45
|
-
check = Typero::Type.load(type).new value, opts
|
46
|
-
check.value
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
###
|
51
|
-
|
52
|
-
# accepts dsl block to
|
53
|
-
def initialize hash={}, &block
|
54
|
-
@rules = {}
|
55
|
-
@db = []
|
56
|
-
hash.each { |k, v| set(k, v) }
|
57
|
-
instance_exec &block if block
|
58
|
-
end
|
59
|
-
|
60
|
-
# validates any instance object or object with hash variable interface
|
61
|
-
# it also coarces values
|
62
|
-
def validate instance
|
63
|
-
@errors = {}
|
64
|
-
|
65
|
-
@rules.each do |field, opts|
|
66
|
-
# set value to default if value is blank and default given
|
67
|
-
instance[field] = opts[:default] if opts[:default] && instance[field].blank?
|
68
|
-
|
69
|
-
# get field value
|
70
|
-
value = instance[field]
|
71
|
-
|
72
|
-
if value.present?
|
73
|
-
klass = 'Typero::%sType' % safe_type(opts[:type])
|
74
|
-
check = klass.constantize.new value, opts
|
75
|
-
check.value = check.default if check.value.nil?
|
76
|
-
|
77
|
-
unless check.value.nil?
|
78
|
-
begin
|
79
|
-
check.set
|
80
|
-
check.validate
|
81
|
-
instance[field] = check.value
|
82
|
-
rescue TypeError => e
|
83
|
-
add_error field, e.message
|
84
|
-
end
|
85
|
-
end
|
86
|
-
elsif opts[:required]
|
87
|
-
msg = opts[:required].class == TrueClass ? 'is required' : opts[:req]
|
88
|
-
add_error field, msg
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
if @errors.keys.length > 0 && block_given?
|
93
|
-
@errors.each { |k,v| yield(k, v) }
|
94
|
-
end
|
95
|
-
|
96
|
-
@errors
|
97
|
-
end
|
98
|
-
|
99
|
-
def valid? instance
|
100
|
-
errors = validate instance
|
101
|
-
errors.keys.length == 0
|
102
|
-
end
|
103
|
-
|
104
|
-
# returns field, db_type, db_opts
|
105
|
-
def db_schema
|
106
|
-
out = @rules.inject([]) do |total, (field, opts)|
|
107
|
-
type, opts = Typero::Type.load(opts[:type]).new(nil, opts).db_field
|
108
|
-
total << [type, field, opts]
|
109
|
-
end
|
110
|
-
|
111
|
-
out += @db if @db[0]
|
112
|
-
|
113
|
-
out
|
114
|
-
end
|
115
|
-
|
116
|
-
private
|
117
|
-
|
118
|
-
# adds error to array or prefixes with field name
|
119
|
-
def add_error field, msg
|
120
|
-
if @errors[field]
|
121
|
-
@errors[field] += ', %s' % msg
|
122
|
-
else
|
123
|
-
if msg[0,1].downcase == msg[0,1]
|
124
|
-
field_name = field.to_s.sub(/_id$/,'').humanize
|
125
|
-
msg = '%s %s' % [field_name, msg]
|
126
|
-
end
|
127
|
-
|
128
|
-
@errors[field] = msg
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
# used in dsl to define value
|
133
|
-
def set field, type=String, opts={}
|
134
|
-
opts = type.is_a?(Hash) ? type : opts.merge(type: type)
|
135
|
-
opts[:type] ||= :string
|
136
|
-
opts[:req] = true if opts[:null].class == FalseClass
|
137
|
-
klass = Typero::Type.load opts[:type]
|
138
|
-
@rules[field] = parse_option opts
|
139
|
-
end
|
140
|
-
|
141
|
-
def safe_type type
|
142
|
-
type.to_s.gsub(/[^\w]/,'').classify
|
143
|
-
end
|
144
|
-
|
145
|
-
# coerce opts values
|
146
|
-
def parse_option opts
|
147
|
-
opts[:type] ||= 'string'
|
148
|
-
|
149
|
-
if opts[:type].is_a?(Array)
|
150
|
-
opts[:array_type] = opts[:type][0] if opts[:type][0]
|
151
|
-
opts[:type] = 'array'
|
152
|
-
end
|
153
|
-
|
154
|
-
opts[:type] = opts[:type].to_s.downcase
|
155
|
-
|
156
|
-
opts[:required] = opts.delete(:req) unless opts[:req].nil?
|
157
|
-
opts[:unique] = opts.delete(:uniq) unless opts[:uniq].nil?
|
158
|
-
opts[:description] = opts.delete(:desc) unless opts[:desc].nil?
|
159
|
-
|
160
|
-
opts
|
161
|
-
end
|
162
|
-
|
163
|
-
|
164
|
-
# pass values for db_schema only
|
165
|
-
# db :timestamps
|
166
|
-
# db :add_index, :code -> t.add_index :code
|
167
|
-
def db *args
|
168
|
-
@db.push args
|
169
|
-
end
|
170
|
-
|
171
|
-
# set :age, type: :integer -> integer :age
|
172
|
-
# email :email
|
173
|
-
# set :email, [:emails]
|
174
|
-
# email [:emails]
|
175
|
-
def method_missing name, *args, &block
|
176
|
-
field = args.shift
|
177
|
-
|
178
|
-
if field.class == Array
|
179
|
-
field = field.first
|
180
|
-
name = [name]
|
181
|
-
end
|
182
|
-
|
183
|
-
name = args.shift if name == :set
|
184
|
-
|
185
|
-
set field, type=name, *args
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
1
|
+
# base libs
|
2
|
+
require_relative 'typero/typero'
|
3
|
+
require_relative 'typero/schema'
|
189
4
|
require_relative 'typero/type'
|
190
5
|
|
6
|
+
# checker types
|
191
7
|
Dir['%s/typero/type/*.rb' % __dir__].each do |file|
|
192
8
|
require file
|
193
9
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Base class for schema validation
|
2
|
+
|
3
|
+
class Typero
|
4
|
+
class Schema
|
5
|
+
attr_reader :rules, :db_rules
|
6
|
+
|
7
|
+
def initialize &block
|
8
|
+
@db_rules = []
|
9
|
+
@rules = {}
|
10
|
+
instance_exec &block
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# used in dsl to define value
|
16
|
+
def set field, type=String, opts={}
|
17
|
+
raise "Field name not given (Typero)" unless field
|
18
|
+
|
19
|
+
field = field.to_sym
|
20
|
+
opts = type.is_a?(Hash) ? type : opts.merge(type: type)
|
21
|
+
opts[:type] ||= :string
|
22
|
+
opts[:required] = true if opts[:null].class == FalseClass
|
23
|
+
|
24
|
+
db :add_index, field if opts.delete(:index)
|
25
|
+
|
26
|
+
klass = Typero::Type.load opts[:type]
|
27
|
+
@rules[field] = parse_option opts
|
28
|
+
end
|
29
|
+
|
30
|
+
# coerce opts values
|
31
|
+
def parse_option opts
|
32
|
+
opts[:type] ||= 'string'
|
33
|
+
|
34
|
+
if opts[:type].is_a?(Array)
|
35
|
+
opts[:array_type] = opts[:type][0] if opts[:type][0]
|
36
|
+
opts[:type] = 'array'
|
37
|
+
end
|
38
|
+
|
39
|
+
opts[:type] = opts[:type].to_s.downcase
|
40
|
+
|
41
|
+
opts[:required] = opts.delete(:req) unless opts[:req].nil?
|
42
|
+
opts[:unique] = opts.delete(:uniq) unless opts[:uniq].nil?
|
43
|
+
opts[:description] = opts.delete(:desc) unless opts[:desc].nil?
|
44
|
+
|
45
|
+
opts
|
46
|
+
end
|
47
|
+
|
48
|
+
# pass values for db_schema only
|
49
|
+
# db :timestamps
|
50
|
+
# db :add_index, :code -> t.add_index :code
|
51
|
+
def db *args
|
52
|
+
@db_rules.push args
|
53
|
+
end
|
54
|
+
|
55
|
+
def link klass, opts={}
|
56
|
+
klass.is! Class
|
57
|
+
|
58
|
+
# TODO: Add can? update check before save
|
59
|
+
integer '%s_id' % klass.to_s.tableize.singularize, opts
|
60
|
+
end
|
61
|
+
|
62
|
+
def hash name
|
63
|
+
set name, :hash
|
64
|
+
end
|
65
|
+
|
66
|
+
# set :age, type: :integer -> integer :age
|
67
|
+
# email :email
|
68
|
+
# set :email, [:emails]
|
69
|
+
# email [:emails]
|
70
|
+
def method_missing name, *args, &block
|
71
|
+
field = args.shift
|
72
|
+
|
73
|
+
if field.class == Array
|
74
|
+
field = field.first
|
75
|
+
name = [name]
|
76
|
+
end
|
77
|
+
|
78
|
+
name = args.shift if name == :set
|
79
|
+
|
80
|
+
set field, type=name, *args
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
data/lib/typero/type.rb
CHANGED
@@ -1,31 +1,42 @@
|
|
1
|
-
class
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
1
|
+
# Master class
|
2
|
+
|
3
|
+
class Typero
|
4
|
+
class Type
|
5
|
+
attr_accessor :opts
|
6
|
+
attr_accessor :value
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def load name
|
10
|
+
klass = 'Typero::%sType' % name.to_s.gsub(/[^\w]/,'').classify
|
11
|
+
|
12
|
+
if const_defined? klass
|
13
|
+
klass.constantize
|
14
|
+
else
|
15
|
+
raise ArgumentError, 'Typero type "%s" is not defined (%s)' % [name, klass]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
###
|
21
|
+
|
22
|
+
def initialize value, opts={}
|
23
|
+
@value = value
|
24
|
+
@opts = opts
|
25
|
+
end
|
26
|
+
|
27
|
+
# default validation for any type
|
28
|
+
def validate
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
# get error from option or the default one
|
33
|
+
def error_for name
|
34
|
+
@opts[name] || send(name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def default
|
38
|
+
nil
|
39
|
+
end
|
29
40
|
end
|
30
41
|
end
|
31
42
|
|
data/lib/typero/type/array.rb
CHANGED
@@ -27,8 +27,8 @@ class Typero::ArrayType < Typero::Type
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def validate
|
30
|
-
raise TypeError, error_for(:
|
31
|
-
raise TypeError, error_for(:
|
30
|
+
raise TypeError, error_for(:min_error) % @opts[:min] if @opts[:min] && @value.length < @opts[:min]
|
31
|
+
raise TypeError, error_for(:max_error) % @opts[:max] if @opts[:max] && @value.length > @opts[:max]
|
32
32
|
true
|
33
33
|
end
|
34
34
|
|
data/lib/typero/type/date.rb
CHANGED
data/lib/typero/type/datetime.rb
CHANGED
data/lib/typero/type/email.rb
CHANGED
data/lib/typero/type/float.rb
CHANGED
data/lib/typero/type/hash.rb
CHANGED
@@ -3,6 +3,10 @@ class Typero::HashType < Typero::Type
|
|
3
3
|
{}
|
4
4
|
end
|
5
5
|
|
6
|
+
def set
|
7
|
+
@value = @value.to_h
|
8
|
+
end
|
9
|
+
|
6
10
|
def validate
|
7
11
|
raise TypeError, error_for(:not_hash_type_error) unless @value.is_a?(Hash)
|
8
12
|
end
|
@@ -12,7 +16,9 @@ class Typero::HashType < Typero::Type
|
|
12
16
|
end
|
13
17
|
|
14
18
|
def db_field
|
15
|
-
[:jsonb, {
|
19
|
+
[:jsonb, {
|
20
|
+
null: false
|
21
|
+
}]
|
16
22
|
end
|
17
23
|
end
|
18
24
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Typero::ImageType < Typero::Type
|
2
|
+
# FORMATS = %w[jpg jpeg gif png svg]
|
3
|
+
|
4
|
+
def set
|
5
|
+
@value = 'https://%s' % @value unless @value.include?('://')
|
6
|
+
end
|
7
|
+
|
8
|
+
def validate
|
9
|
+
raise TypeError, error_for(:not_starting_error) unless @value =~ /^https?:\/\/./
|
10
|
+
# ext = @value.split('.').last.downcase
|
11
|
+
# raise TypeError, error_for(:not_image_format) unless FORMATS.include?(ext)
|
12
|
+
end
|
13
|
+
|
14
|
+
def not_starting_error
|
15
|
+
'URL is not starting with http'
|
16
|
+
end
|
17
|
+
|
18
|
+
# def not_image_format
|
19
|
+
# 'URL is not ending with %s' % FORMATS.join(', ')
|
20
|
+
# end
|
21
|
+
|
22
|
+
def db_field
|
23
|
+
opts = {}
|
24
|
+
opts[:null] = false if @opts[:required]
|
25
|
+
[:string, opts]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
data/lib/typero/type/integer.rb
CHANGED
data/lib/typero/type/label.rb
CHANGED
data/lib/typero/type/oib.rb
CHANGED
data/lib/typero/type/point.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
|
+
# for postgres - select st_asewkt(lon_lat) || st_astext(lon_lat)
|
2
|
+
# point = @object.class.xselect("ST_AsText(#{field}) as #{field}").where(id: @object.id).first[field.to_sym]
|
3
|
+
|
1
4
|
class Typero::PointType < Typero::Type
|
2
5
|
def set
|
6
|
+
ap @value
|
3
7
|
if @value.present?
|
4
8
|
if @value.include?('/@')
|
5
9
|
point = @value.split('/@', 2).last.split(',')
|
6
10
|
@value = [point[0], point[1]].join(',')
|
7
11
|
end
|
8
12
|
|
9
|
-
|
13
|
+
if !@value.include?('POINT') && @value.include?(',')
|
10
14
|
point = @value.sub(/,\s*/, ' ')
|
11
15
|
@value = 'SRID=4326;POINT(%s)' % point
|
12
16
|
end
|
@@ -14,7 +18,9 @@ class Typero::PointType < Typero::Type
|
|
14
18
|
end
|
15
19
|
|
16
20
|
def validate
|
17
|
-
|
21
|
+
if @value && @value.include?(',') && !@value =~ /^SRID=4326;POINT\(/
|
22
|
+
raise TypeError, error_for(:unallowed_characters_error)
|
23
|
+
end
|
18
24
|
end
|
19
25
|
|
20
26
|
def db_field
|
data/lib/typero/type/string.rb
CHANGED
@@ -21,8 +21,9 @@ class Typero::StringType < Typero::Type
|
|
21
21
|
|
22
22
|
def db_field
|
23
23
|
opts = {}
|
24
|
-
opts[:limit]
|
25
|
-
opts[:null]
|
24
|
+
opts[:limit] = @opts[:max] || 255
|
25
|
+
opts[:null] = false if @opts[:required]
|
26
|
+
opts[:default] = @opts[:default]
|
26
27
|
[:string, opts]
|
27
28
|
end
|
28
29
|
end
|
data/lib/typero/type/text.rb
CHANGED
data/lib/typero/type/url.rb
CHANGED
@@ -0,0 +1,191 @@
|
|
1
|
+
# rules = Typero.new do
|
2
|
+
# set :name, String, req: true
|
3
|
+
# set :email, :email, req: true
|
4
|
+
# set :skills, [:email], min: 2
|
5
|
+
# end
|
6
|
+
#
|
7
|
+
# or
|
8
|
+
#
|
9
|
+
# rules = Typero.new do
|
10
|
+
# string :name, req: true
|
11
|
+
# email :email, req: true
|
12
|
+
# email [:skills], min: 2
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# errors = rules.validate @object
|
16
|
+
# rules.valid?
|
17
|
+
# rules.validate(@object) { |errors| ... }
|
18
|
+
|
19
|
+
class Typero
|
20
|
+
SCHEMAS = {}
|
21
|
+
VERSION = File.read File.expand_path '../../.version', File.dirname(__FILE__)
|
22
|
+
|
23
|
+
class << self
|
24
|
+
# validate single value in type
|
25
|
+
def validate type, value, opts={}
|
26
|
+
field = type.to_s.tableize.singularize.to_sym
|
27
|
+
|
28
|
+
# we need to have pointer to hash, so value can be changed (coerced) if needed
|
29
|
+
h = { field => value }
|
30
|
+
|
31
|
+
rule = new do
|
32
|
+
set field, type, opts
|
33
|
+
end
|
34
|
+
|
35
|
+
if error = rule.validate(h)[field]
|
36
|
+
block_given? ? yield(error) : raise(TypeError.new(error))
|
37
|
+
end
|
38
|
+
|
39
|
+
h[field]
|
40
|
+
end
|
41
|
+
|
42
|
+
# check and coerce value
|
43
|
+
# Typero.set(:label, 'Foo bar') -> "foo-bar"
|
44
|
+
def set type, value, opts={}
|
45
|
+
check = Typero::Type.load(type).new value, opts
|
46
|
+
check.value
|
47
|
+
end
|
48
|
+
|
49
|
+
# list loaded classes
|
50
|
+
def list type=nil
|
51
|
+
SCHEMAS
|
52
|
+
.select { |k, v| type ? v[1] == type : true; }
|
53
|
+
.keys
|
54
|
+
end
|
55
|
+
|
56
|
+
# def schema table_name, &block
|
57
|
+
# schema = Typero.new(&block)
|
58
|
+
|
59
|
+
# if Lux.config.migrate
|
60
|
+
# AutoMigrate.typero table_name, schema
|
61
|
+
# else
|
62
|
+
# klass = table_name.to_s.classify.constantize
|
63
|
+
# klass.typero = schema
|
64
|
+
# end
|
65
|
+
# end
|
66
|
+
end
|
67
|
+
|
68
|
+
###
|
69
|
+
|
70
|
+
# accepts dsl block to
|
71
|
+
def initialize name=nil, &block
|
72
|
+
type = :default
|
73
|
+
|
74
|
+
if name.is_a?(Hash)
|
75
|
+
type = name.keys.first
|
76
|
+
name = name.values.first
|
77
|
+
end
|
78
|
+
|
79
|
+
if block_given?
|
80
|
+
@schema = Schema.new &block
|
81
|
+
|
82
|
+
if name
|
83
|
+
SCHEMAS[name_fix(name)] = [@schema, type]
|
84
|
+
end
|
85
|
+
elsif name
|
86
|
+
schema_name = name_fix(name)
|
87
|
+
@schema = SCHEMAS[schema_name][0] || raise(ArgumentError.new('Schema nemed "%s" not found (%s)' % [schema_name, name]))
|
88
|
+
else
|
89
|
+
raise ArgumentError, 'No block or schema name given'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# validates any instance object or object with hash variable interface
|
94
|
+
# it also coarces values
|
95
|
+
def validate instance
|
96
|
+
@errors = {}
|
97
|
+
|
98
|
+
@schema.rules.each do |field, opts|
|
99
|
+
# set value to default if value is blank and default given
|
100
|
+
instance[field] = opts[:default] if opts[:default] && instance[field].blank?
|
101
|
+
|
102
|
+
# get field value
|
103
|
+
value = instance[field]
|
104
|
+
|
105
|
+
if value.present?
|
106
|
+
klass = 'Typero::%sType' % safe_type(opts[:type])
|
107
|
+
check = klass.constantize.new value, opts
|
108
|
+
check.value = check.default if check.value.nil?
|
109
|
+
|
110
|
+
unless check.value.nil?
|
111
|
+
begin
|
112
|
+
check.set
|
113
|
+
check.validate
|
114
|
+
instance[field] = check.value
|
115
|
+
rescue TypeError => e
|
116
|
+
add_error field, e.message
|
117
|
+
end
|
118
|
+
end
|
119
|
+
elsif opts[:required]
|
120
|
+
msg = opts[:required].class == TrueClass ? 'is required' : opts[:required]
|
121
|
+
add_error field, msg
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
if @errors.keys.length > 0 && block_given?
|
126
|
+
@errors.each { |k,v| yield(k, v) }
|
127
|
+
end
|
128
|
+
|
129
|
+
@errors
|
130
|
+
end
|
131
|
+
|
132
|
+
def valid? instance
|
133
|
+
errors = validate instance
|
134
|
+
errors.keys.length == 0
|
135
|
+
end
|
136
|
+
|
137
|
+
# returns field, db_type, db_opts
|
138
|
+
def db_schema
|
139
|
+
out = @schema.rules.inject([]) do |total, (field, opts)|
|
140
|
+
type, opts = Typero::Type.load(opts[:type]).new(nil, opts).db_field
|
141
|
+
total << [type, field, opts]
|
142
|
+
end
|
143
|
+
|
144
|
+
out += @schema.db_rules
|
145
|
+
|
146
|
+
out
|
147
|
+
end
|
148
|
+
|
149
|
+
# iterate trough all the ruels via block interface
|
150
|
+
# schema.rules do |field, opts|
|
151
|
+
# schema.rules(:url) do |field, opts|
|
152
|
+
def rules filter=nil, &block
|
153
|
+
return @schema.rules unless filter
|
154
|
+
out = @schema.rules
|
155
|
+
out = out.select { |k,v| v[:type].to_s == filter.to_s || v[:array_type].to_s == filter.to_s } if filter
|
156
|
+
return out unless block_given?
|
157
|
+
|
158
|
+
for k, v in out
|
159
|
+
yield k, v
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
private
|
164
|
+
|
165
|
+
# adds error to array or prefixes with field name
|
166
|
+
def add_error field, msg
|
167
|
+
if @errors[field]
|
168
|
+
@errors[field] += ', %s' % msg
|
169
|
+
else
|
170
|
+
if msg && msg[0,1].downcase == msg[0,1]
|
171
|
+
field_name = field.to_s.sub(/_id$/,'').humanize
|
172
|
+
msg = '%s %s' % [field_name, msg]
|
173
|
+
end
|
174
|
+
|
175
|
+
@errors[field] = msg
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def safe_type type
|
180
|
+
type.to_s.gsub(/[^\w]/,'').classify
|
181
|
+
end
|
182
|
+
|
183
|
+
def name_fix name
|
184
|
+
if name.is_a?(Symbol)
|
185
|
+
name.to_s.classify if name.is_a?(Symbol)
|
186
|
+
else
|
187
|
+
name.to_s
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: typero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dino Reic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-02-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fast_blank
|
@@ -34,6 +34,7 @@ files:
|
|
34
34
|
- "./.version"
|
35
35
|
- "./lib/adapters/sequel.rb"
|
36
36
|
- "./lib/typero.rb"
|
37
|
+
- "./lib/typero/schema.rb"
|
37
38
|
- "./lib/typero/type.rb"
|
38
39
|
- "./lib/typero/type/array.rb"
|
39
40
|
- "./lib/typero/type/boolean.rb"
|
@@ -42,8 +43,8 @@ files:
|
|
42
43
|
- "./lib/typero/type/datetime.rb"
|
43
44
|
- "./lib/typero/type/email.rb"
|
44
45
|
- "./lib/typero/type/float.rb"
|
45
|
-
- "./lib/typero/type/geography.rb"
|
46
46
|
- "./lib/typero/type/hash.rb"
|
47
|
+
- "./lib/typero/type/image.rb"
|
47
48
|
- "./lib/typero/type/integer.rb"
|
48
49
|
- "./lib/typero/type/label.rb"
|
49
50
|
- "./lib/typero/type/oib.rb"
|
@@ -51,6 +52,7 @@ files:
|
|
51
52
|
- "./lib/typero/type/string.rb"
|
52
53
|
- "./lib/typero/type/text.rb"
|
53
54
|
- "./lib/typero/type/url.rb"
|
55
|
+
- "./lib/typero/typero.rb"
|
54
56
|
homepage: https://github.com/dux/typero
|
55
57
|
licenses:
|
56
58
|
- MIT
|
@@ -70,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
72
|
- !ruby/object:Gem::Version
|
71
73
|
version: '0'
|
72
74
|
requirements: []
|
73
|
-
rubygems_version: 3.0.
|
75
|
+
rubygems_version: 3.0.6
|
74
76
|
signing_key:
|
75
77
|
specification_version: 4
|
76
78
|
summary: Ruby type system
|