typero 0.5.2 → 0.9.3
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 +11 -33
- data/lib/typero.rb +8 -189
- data/lib/typero/params.rb +126 -0
- data/lib/typero/schema.rb +154 -0
- data/lib/typero/type/type.rb +125 -0
- data/lib/typero/type/types/boolean_type.rb +26 -0
- data/lib/typero/type/types/currency_type.rb +21 -0
- data/lib/typero/type/types/date_type.rb +35 -0
- data/lib/typero/type/types/datetime_type.rb +16 -0
- data/lib/typero/type/types/email_type.rb +20 -0
- data/lib/typero/type/types/float_type.rb +24 -0
- data/lib/typero/type/types/hash_type.rb +31 -0
- data/lib/typero/type/types/image_type.rb +22 -0
- data/lib/typero/type/types/integer_type.rb +16 -0
- data/lib/typero/type/types/label_type.rb +20 -0
- data/lib/typero/type/types/locale_type.rb +13 -0
- data/lib/typero/type/types/model_type.rb +23 -0
- data/lib/typero/type/{oib.rb → types/oib_type.rb} +16 -18
- data/lib/typero/type/types/point_type.rb +25 -0
- data/lib/typero/type/types/string_type.rb +20 -0
- data/lib/typero/type/types/text_type.rb +10 -0
- data/lib/typero/type/types/time_type.rb +5 -0
- data/lib/typero/type/types/timezone_type.rb +15 -0
- data/lib/typero/type/types/url_type.rb +13 -0
- data/lib/typero/typero.rb +98 -0
- metadata +33 -27
- data/lib/typero/type.rb +0 -32
- data/lib/typero/type/array.rb +0 -55
- data/lib/typero/type/boolean.rb +0 -16
- data/lib/typero/type/currency.rb +0 -17
- data/lib/typero/type/date.rb +0 -6
- data/lib/typero/type/datetime.rb +0 -6
- data/lib/typero/type/email.rb +0 -27
- data/lib/typero/type/float.rb +0 -27
- data/lib/typero/type/geography.rb +0 -13
- data/lib/typero/type/hash.rb +0 -18
- data/lib/typero/type/integer.rb +0 -25
- data/lib/typero/type/label.rb +0 -20
- data/lib/typero/type/point.rb +0 -25
- data/lib/typero/type/string.rb +0 -29
- data/lib/typero/type/text.rb +0 -7
- data/lib/typero/type/url.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b0ee2233c2ba484ec5ff98778a8da24a876b7b22eb4d24cc6b3ba3a8886e714
|
4
|
+
data.tar.gz: 4a96d10f9c6d0e75e8ae36965d34a6cda8853684974f799e2cf5e32d6a7003c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 880c3e4e551ab660f85530454ad9007ae383118677ea209ffaf0efff54bcd38da220579dc42d87618bd9ea50790b04a46c63dfe3cfd6252508b2bbec6ba1d711
|
7
|
+
data.tar.gz: 6f10437b894c91f3c7f723da03b426218d60b21c8bd161111d8ae7a745bdf35565f4fba84f26552fc75aa9b40211f3902d1cc2418fc420a5e3bce912ac676bc2
|
data/.version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.3
|
data/lib/adapters/sequel.rb
CHANGED
@@ -1,67 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'typero'
|
4
|
-
|
5
3
|
module Sequel::Plugins::TyperoAttributes
|
6
4
|
module ClassMethods
|
7
|
-
def attributes opts={}, &block
|
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
5
|
def typero
|
15
|
-
|
6
|
+
Typero.schema self
|
16
7
|
end
|
17
8
|
end
|
18
9
|
|
19
10
|
module InstanceMethods
|
20
11
|
# calling typero! on any object will validate all fields
|
21
|
-
def
|
22
|
-
|
12
|
+
def validate
|
13
|
+
super
|
23
14
|
|
24
|
-
|
15
|
+
schema = Typero.schema(self.class) || return
|
16
|
+
|
17
|
+
schema.validate(self) do |name, err|
|
25
18
|
errors.add(name, err) unless (errors.on(name) || []).include?(err)
|
26
19
|
end
|
27
20
|
|
28
21
|
# this are rules unique to database, so we check them here
|
29
|
-
|
22
|
+
schema.rules.each do |field, rule|
|
30
23
|
# check uniqe fields
|
31
|
-
if rule
|
24
|
+
if unique = rule.dig(:meta, :unique)
|
32
25
|
id = self[:id] || 0
|
33
26
|
value = self[field]
|
34
27
|
|
35
28
|
# we only check if field is changed
|
36
29
|
if value.present? && column_changed?(field) && self.class.xwhere('LOWER(%s)=LOWER(?) and id<>?' % field, value, id).first
|
37
|
-
error =
|
30
|
+
error = unique.class == TrueClass ? %[Value '"#{value}"' for #{field} allready exists] : unique
|
38
31
|
errors.add(field, error) unless (errors.on(field) || []).include?(error)
|
39
32
|
end
|
40
33
|
end
|
41
34
|
|
42
35
|
# check protected fields
|
43
|
-
if rule
|
36
|
+
if prot = rule.dig(:meta, :protected) && self[:id]
|
44
37
|
if column_changed?(field)
|
45
|
-
error =
|
38
|
+
error = prot.class == TrueClass ? "value once defined can't be overwritten." : prot
|
46
39
|
errors.add(field, error) unless (errors.on(field) || []).include?(error)
|
47
40
|
end
|
48
41
|
end
|
49
42
|
end
|
50
|
-
|
51
|
-
# check single field if single field given
|
52
|
-
if field_name
|
53
|
-
raise ArgumentError.new 'Field :%s not found in %s' % [field_name, self] unless self[field_name]
|
54
|
-
return unless errors.on(field_name)
|
55
|
-
|
56
|
-
errors.on(field_name).join(', ')
|
57
|
-
end
|
58
|
-
|
59
|
-
true
|
60
|
-
end
|
61
|
-
|
62
|
-
def validate
|
63
|
-
typero!
|
64
|
-
super
|
65
43
|
end
|
66
44
|
end
|
67
45
|
|
data/lib/typero.rb
CHANGED
@@ -1,194 +1,13 @@
|
|
1
|
-
#
|
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| ... }
|
1
|
+
# require 'hash_wia'
|
18
2
|
|
19
|
-
|
20
|
-
|
3
|
+
# base libs
|
4
|
+
require_relative 'typero/typero'
|
5
|
+
require_relative 'typero/schema'
|
6
|
+
require_relative 'typero/params'
|
7
|
+
require_relative 'typero/type/type'
|
21
8
|
|
22
|
-
|
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
|
-
|
189
|
-
require_relative 'typero/type'
|
190
|
-
|
191
|
-
Dir['%s/typero/type/*.rb' % __dir__].each do |file|
|
9
|
+
# checker types
|
10
|
+
Dir['%s/typero/type/types/*.rb' % __dir__].each do |file|
|
192
11
|
require file
|
193
12
|
end
|
194
13
|
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# Base class for schema validation
|
2
|
+
|
3
|
+
module Typero
|
4
|
+
class Params
|
5
|
+
attr_reader :db_rules
|
6
|
+
|
7
|
+
def initialize &block
|
8
|
+
@db_rules = []
|
9
|
+
@rules = {}
|
10
|
+
instance_exec &block
|
11
|
+
end
|
12
|
+
|
13
|
+
def rules
|
14
|
+
@rules.dup
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# used in dsl to define schema field options
|
20
|
+
def set field, *args, &block
|
21
|
+
raise "Field name not given (Typero)" unless field
|
22
|
+
|
23
|
+
if args.first.is_a?(Hash)
|
24
|
+
opts = args.first || {}
|
25
|
+
else
|
26
|
+
opts = args[1] || {}
|
27
|
+
opts[:type] ||= args[0]
|
28
|
+
end
|
29
|
+
|
30
|
+
opts[:type] = :string if opts[:type].nil?
|
31
|
+
|
32
|
+
field = field.to_s
|
33
|
+
|
34
|
+
if field.include?('!')
|
35
|
+
if block
|
36
|
+
field = field.sub('!', '')
|
37
|
+
@block_type = field.to_sym
|
38
|
+
instance_exec &block
|
39
|
+
@block_type = nil
|
40
|
+
return
|
41
|
+
else
|
42
|
+
raise ArgumentError.new 'If you use ! you have to provide a block'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# name? - opional name
|
47
|
+
if field.include?('?')
|
48
|
+
field = field.sub('?', '')
|
49
|
+
opts[:required] = false
|
50
|
+
end
|
51
|
+
|
52
|
+
if value = opts.delete(:req)
|
53
|
+
opts[:required] = value
|
54
|
+
else
|
55
|
+
opts[:required] = true if opts[:required].nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
# array that allows duplicates
|
59
|
+
if opts[:type].is_a?(Array)
|
60
|
+
opts[:type] = opts[:type].first
|
61
|
+
opts[:array] = true
|
62
|
+
end
|
63
|
+
|
64
|
+
# no duplicates array
|
65
|
+
if opts[:type].is_a?(Set)
|
66
|
+
opts[:type] = opts[:type].to_a.first
|
67
|
+
opts[:array] = true
|
68
|
+
end
|
69
|
+
|
70
|
+
opts[:type] = @block_type if @block_type
|
71
|
+
|
72
|
+
# Boolean
|
73
|
+
if opts[:type].is_a?(TrueClass) || opts[:type] == :true
|
74
|
+
opts[:required] = false
|
75
|
+
opts[:default] = true
|
76
|
+
opts[:type] = :boolean
|
77
|
+
elsif opts[:type].is_a?(FalseClass) || opts[:type] == :false
|
78
|
+
opts[:required] = false
|
79
|
+
opts[:default] = false
|
80
|
+
opts[:type] = :boolean
|
81
|
+
end
|
82
|
+
|
83
|
+
opts[:model] = opts.delete(:schema) if opts[:schema]
|
84
|
+
opts[:type] = :model if opts[:model]
|
85
|
+
|
86
|
+
if block_given?
|
87
|
+
opts[:type] = :model
|
88
|
+
opts[:model] = Typero.schema &block
|
89
|
+
end
|
90
|
+
|
91
|
+
opts[:type] ||= 'string'
|
92
|
+
opts[:type] = opts[:type].to_s.downcase.to_sym
|
93
|
+
|
94
|
+
opts[:description] = opts.delete(:desc) unless opts[:desc].nil?
|
95
|
+
|
96
|
+
# chek alloed params, all optional should go in meta
|
97
|
+
result = opts.keys - Typero::Type::OPTS_KEYS
|
98
|
+
raise ArgumentError.new('Unallowed Type params found: "%s", allowed: %s' % [result.join(' and '), Typero::Type::OPTS_KEYS.sort]) if result.length > 0
|
99
|
+
|
100
|
+
field = field.to_sym
|
101
|
+
|
102
|
+
db :add_index, field if opts.delete(:index)
|
103
|
+
|
104
|
+
# trigger error if type not found
|
105
|
+
Typero::Type.load opts[:type]
|
106
|
+
|
107
|
+
@rules[field] = opts
|
108
|
+
end
|
109
|
+
|
110
|
+
# pass values for db_schema only
|
111
|
+
# db :timestamps
|
112
|
+
# db :add_index, :code -> t.add_index :code
|
113
|
+
def db *args
|
114
|
+
@db_rules.push args
|
115
|
+
end
|
116
|
+
|
117
|
+
# set :age, type: :integer -> integer :age
|
118
|
+
# email :email
|
119
|
+
#
|
120
|
+
# set :emails, Array[:email]
|
121
|
+
# email Array[:emails]
|
122
|
+
def method_missing field, *args, &block
|
123
|
+
set field, *args, &block
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module Typero
|
2
|
+
class Schema
|
3
|
+
SCHEMAS = {}
|
4
|
+
TYPES = {}
|
5
|
+
|
6
|
+
# accepts dsl block to
|
7
|
+
def initialize &block
|
8
|
+
raise "Params not defined" unless block_given?
|
9
|
+
@schema = Params.new &block
|
10
|
+
end
|
11
|
+
|
12
|
+
# validates any instance object with hash variable interface
|
13
|
+
# it also coarces values
|
14
|
+
def validate object, options=nil
|
15
|
+
@options = options || {}
|
16
|
+
@object = object
|
17
|
+
@errors = {}
|
18
|
+
|
19
|
+
# remove undefined keys if Hash provided
|
20
|
+
if @options[:strict] && object.is_a?(Hash)
|
21
|
+
undefined = object.keys.map(&:to_s) - @schema.rules.keys.map(&:to_s)
|
22
|
+
object.delete_if { |k, _| undefined.include?(k.to_s) }
|
23
|
+
end
|
24
|
+
|
25
|
+
@schema.rules.each do |field, opts|
|
26
|
+
for k in opts.keys
|
27
|
+
opts[k] = @object.instance_exec(&opts[k]) if opts[k].is_a?(Proc)
|
28
|
+
end
|
29
|
+
|
30
|
+
# set value to default if value is blank and default given
|
31
|
+
@object[field] = opts[:default] if opts[:default] && @object[field].blank?
|
32
|
+
|
33
|
+
# get field value
|
34
|
+
value = @object[field]
|
35
|
+
|
36
|
+
if opts[:array]
|
37
|
+
unless value.respond_to?(:each)
|
38
|
+
opts[:delimiter] ||= /\s*[,\n]\s*/
|
39
|
+
value = value.to_s.split(opts[:delimiter])
|
40
|
+
end
|
41
|
+
|
42
|
+
value = value
|
43
|
+
.flatten
|
44
|
+
.map { |el| el.to_s == '' ? nil : check_filed_value(field, el, opts) }
|
45
|
+
.compact
|
46
|
+
|
47
|
+
value = Set.new(value).to_a unless opts[:duplicates]
|
48
|
+
|
49
|
+
opts[:max_count] ||= 100
|
50
|
+
add_error(field, 'Max number of array elements is %d, you have %d' % [opts[:max_count], value.length], opts) if value && value.length > opts[:max_count]
|
51
|
+
add_error(field, 'Min number of array elements is %d, you have %d' % [opts[:min_count], value.length], opts) if value && opts[:min_count] && value.length < opts[:min_count]
|
52
|
+
|
53
|
+
add_required_error field, value.first, opts
|
54
|
+
else
|
55
|
+
value = nil if value.to_s == ''
|
56
|
+
|
57
|
+
# if value is not list of allowed values, raise error
|
58
|
+
allowed = opts[:allow] || opts[:allowed] || opts[:values]
|
59
|
+
if value && allowed && !allowed.include?(value)
|
60
|
+
add_error field, 'Value "%s" is not allowed' % value, opts
|
61
|
+
end
|
62
|
+
|
63
|
+
value = check_filed_value field, value, opts
|
64
|
+
add_required_error field, value, opts
|
65
|
+
end
|
66
|
+
|
67
|
+
# present empty string values as nil
|
68
|
+
@object[field] = value.to_s.sub(/\s+/, '') == '' ? nil : value
|
69
|
+
end
|
70
|
+
|
71
|
+
if @errors.keys.length > 0 && block_given?
|
72
|
+
@errors.each { |k, v| yield(k, v) }
|
73
|
+
end
|
74
|
+
|
75
|
+
@errors
|
76
|
+
end
|
77
|
+
|
78
|
+
def valid? object
|
79
|
+
errors = validate object
|
80
|
+
errors.keys.length == 0
|
81
|
+
end
|
82
|
+
|
83
|
+
# returns field, db_type, db_opts
|
84
|
+
def db_schema
|
85
|
+
out = @schema.rules.inject([]) do |total, (field, opts)|
|
86
|
+
# get db filed schema
|
87
|
+
type, opts = Typero::Type.load(opts[:type]).new(nil, opts).db_field
|
88
|
+
|
89
|
+
# add array true to field it ont defined in schema
|
90
|
+
schema_opts = @schema.rules[field]
|
91
|
+
opts[:array] = true if schema_opts[:array]
|
92
|
+
|
93
|
+
total << [type, field, opts]
|
94
|
+
end
|
95
|
+
|
96
|
+
out += @schema.db_rules
|
97
|
+
|
98
|
+
out
|
99
|
+
end
|
100
|
+
|
101
|
+
# iterate trough all the ruels via block interface
|
102
|
+
# schema.rules do |field, opts|
|
103
|
+
# schema.rules(:url) do |field, opts|
|
104
|
+
def rules filter = nil, &block
|
105
|
+
return @schema.rules unless filter
|
106
|
+
out = @schema.rules
|
107
|
+
out = out.select { |k, v| v[:type].to_s == filter.to_s || v[:array_type].to_s == filter.to_s } if filter
|
108
|
+
return out unless block_given?
|
109
|
+
|
110
|
+
out.each { |k, v| yield k, v }
|
111
|
+
end
|
112
|
+
alias :to_h :rules
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
# adds error to array or prefixes with field name
|
117
|
+
def add_error field, msg, opts
|
118
|
+
if @errors[field]
|
119
|
+
@errors[field] += ", %s" % msg
|
120
|
+
else
|
121
|
+
if msg && msg[0, 1].downcase == msg[0, 1]
|
122
|
+
field_name = opts[:name] || field.to_s.sub(/_id$/, "").capitalize
|
123
|
+
msg = "%s %s" % [field_name, msg]
|
124
|
+
end
|
125
|
+
|
126
|
+
@errors[field] = msg
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def safe_type type
|
131
|
+
type.to_s.gsub(/[^\w]/, "").classify
|
132
|
+
end
|
133
|
+
|
134
|
+
def add_required_error field, value, opts
|
135
|
+
return unless opts[:required] && value.nil?
|
136
|
+
msg = opts[:required].class == TrueClass ? "is required" : opts[:required]
|
137
|
+
add_error field, msg, opts
|
138
|
+
end
|
139
|
+
|
140
|
+
def check_filed_value field, value, opts
|
141
|
+
klass = "Typero::%sType" % safe_type(opts[:type])
|
142
|
+
check = klass.constantize.new value, opts
|
143
|
+
check.get
|
144
|
+
rescue TypeError => e
|
145
|
+
if e.message[0] == '{'
|
146
|
+
for key, msg in JSON.parse(e.message)
|
147
|
+
add_error [field, key].join('.'), msg, opts
|
148
|
+
end
|
149
|
+
else
|
150
|
+
add_error field, e.message, opts
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|