typero 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.version +1 -1
- data/lib/typero.rb +2 -1
- data/lib/typero/exporter.rb +93 -0
- data/lib/typero/params.rb +24 -9
- data/lib/typero/schema.rb +132 -0
- data/lib/typero/type/type.rb +37 -9
- 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 +32 -0
- data/lib/typero/type/types/datetime_type.rb +14 -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 +25 -0
- data/lib/typero/type/types/{image.rb → image_type.rb} +4 -10
- 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/model_type.rb +21 -0
- data/lib/typero/type/types/{oib.rb → oib_type.rb} +7 -10
- 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.rb → text_type.rb} +3 -5
- data/lib/typero/type/types/url_type.rb +13 -0
- data/lib/typero/typero.rb +50 -137
- metadata +20 -18
- data/lib/typero/func.rb +0 -14
- data/lib/typero/type/types/boolean.rb +0 -16
- data/lib/typero/type/types/currency.rb +0 -19
- data/lib/typero/type/types/date.rb +0 -10
- data/lib/typero/type/types/datetime.rb +0 -10
- data/lib/typero/type/types/email.rb +0 -21
- data/lib/typero/type/types/float.rb +0 -21
- data/lib/typero/type/types/hash.rb +0 -22
- data/lib/typero/type/types/integer.rb +0 -21
- data/lib/typero/type/types/label.rb +0 -15
- data/lib/typero/type/types/point.rb +0 -29
- data/lib/typero/type/types/string.rb +0 -23
- data/lib/typero/type/types/url.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e78c338c182793ab2bffd1b4c5469d5285f57f55697402b6e80fb1881a3f7a8
|
4
|
+
data.tar.gz: 18a803b38ef8a24cb3756a43e5b5704082a08f4d805be57239cb054c28e6f132
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c02d8cec42f465c5cf34b0b69c856cf193f1c5e289898af0aefdebf1d61ed91c95148a1fa9ca1c047a07810c99bd518946dbfe323e0e53c4502b66b08910c85
|
7
|
+
data.tar.gz: de185fca3ac80a4e7e9d6b87778872b3b352f89678f334e24b0047480d401cbd0abf95bb8940ba0e29d9d3f485ef62521b38335f1f6cc3a7d1f59194383f4a67
|
data/.version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.0
|
data/lib/typero.rb
CHANGED
@@ -0,0 +1,93 @@
|
|
1
|
+
module Typero
|
2
|
+
class Exporter
|
3
|
+
EXPORTERS ||= {}
|
4
|
+
|
5
|
+
attr_accessor :response
|
6
|
+
|
7
|
+
def initialize model, opts={}
|
8
|
+
opts = { user: opts } unless opts.is_a?(Hash)
|
9
|
+
|
10
|
+
opts[:exporter] ||= model.class
|
11
|
+
opts[:depth] ||= 1
|
12
|
+
opts[:current_depth] ||= 0
|
13
|
+
|
14
|
+
exporter = opts.delete(:exporter).to_s.classify
|
15
|
+
|
16
|
+
@model = model
|
17
|
+
@opts = opts
|
18
|
+
@block = EXPORTERS[exporter] || raise('Exporter "%s" (:%s) not found' % [block, block.underscore])
|
19
|
+
@response = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def render
|
23
|
+
instance_exec &@block
|
24
|
+
@response
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def export object, opts={}
|
30
|
+
if object.is_a?(Symbol)
|
31
|
+
return property object, export(model.send(object))
|
32
|
+
end
|
33
|
+
|
34
|
+
return if @opts[:current_depth] >= @opts[:depth]
|
35
|
+
|
36
|
+
@opts[:current_depth] += 1
|
37
|
+
out = self.class.new(object, @opts.merge(opts)).render
|
38
|
+
@opts[:current_depth] -= 1
|
39
|
+
out
|
40
|
+
end
|
41
|
+
|
42
|
+
def property name, data=:_undefined
|
43
|
+
if block_given?
|
44
|
+
data = yield if data == :_undefined
|
45
|
+
@response[name] = data
|
46
|
+
else
|
47
|
+
data = data == :_undefined ? model.send(name) : data
|
48
|
+
|
49
|
+
if data.respond_to?(:export_json)
|
50
|
+
data = data.export_json
|
51
|
+
elsif data.respond_to?(:to_h)
|
52
|
+
data = data.to_h
|
53
|
+
end
|
54
|
+
|
55
|
+
@response[name] = data
|
56
|
+
end
|
57
|
+
end
|
58
|
+
alias :prop :property
|
59
|
+
|
60
|
+
def hproperty name
|
61
|
+
@response[name] = model[name]
|
62
|
+
end
|
63
|
+
alias :hprop :hproperty
|
64
|
+
|
65
|
+
def namespace name, &block
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def meta &block
|
70
|
+
namespace :meta, &block
|
71
|
+
end
|
72
|
+
|
73
|
+
def model
|
74
|
+
@model
|
75
|
+
end
|
76
|
+
|
77
|
+
# get current user from globals if globals defined
|
78
|
+
def user
|
79
|
+
if @opts[:user]
|
80
|
+
@opts[:user]
|
81
|
+
elsif defined?(User) && User.respond_to?(:current)
|
82
|
+
User.current
|
83
|
+
elsif defined?(Current) && Current.respond_to?(:user)
|
84
|
+
Current.user
|
85
|
+
elsif current_user = Thread.current[:current_user]
|
86
|
+
current_user
|
87
|
+
else
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
data/lib/typero/params.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
# Base class for schema validation
|
2
2
|
|
3
|
-
|
3
|
+
module Typero
|
4
4
|
class Params
|
5
|
-
ALLOWED = %i(name min max default allowed delimiter max_count req required type array meta desc description duplicates unique)
|
6
|
-
|
7
5
|
attr_reader :rules, :db_rules
|
8
6
|
|
9
7
|
def initialize &block
|
@@ -25,8 +23,7 @@ class Typero
|
|
25
23
|
opts[:type] ||= args[0]
|
26
24
|
end
|
27
25
|
|
28
|
-
opts[:type]
|
29
|
-
opts[:required] = true unless opts[:required].is_a?(FalseClass) || opts[:req].is_a?(FalseClass)
|
26
|
+
opts[:type] = :string if opts[:type].nil?
|
30
27
|
|
31
28
|
field = field.to_s
|
32
29
|
|
@@ -36,6 +33,8 @@ class Typero
|
|
36
33
|
opts[:required] = false
|
37
34
|
end
|
38
35
|
|
36
|
+
opts[:required] = true if opts[:required].nil?
|
37
|
+
|
39
38
|
# array that allows duplicates
|
40
39
|
if opts[:type].is_a?(Array)
|
41
40
|
opts[:type] = opts[:type].first
|
@@ -48,20 +47,36 @@ class Typero
|
|
48
47
|
opts[:array] = true
|
49
48
|
end
|
50
49
|
|
50
|
+
# Boolean
|
51
|
+
if opts[:type].is_a?(TrueClass)
|
52
|
+
opts[:required] = false
|
53
|
+
opts[:default] = true
|
54
|
+
opts[:type] = :boolean
|
55
|
+
elsif opts[:type].is_a?(FalseClass)
|
56
|
+
opts[:required] = false
|
57
|
+
opts[:default] = false
|
58
|
+
opts[:type] = :boolean
|
59
|
+
end
|
60
|
+
|
61
|
+
opts[:model] = opts.delete(:schema) if opts[:schema]
|
62
|
+
opts[:type] = :model if opts[:model]
|
63
|
+
|
51
64
|
opts[:type] ||= 'string'
|
52
|
-
opts[:type] = opts[:type].to_s.downcase
|
65
|
+
opts[:type] = opts[:type].to_s.downcase.to_sym
|
53
66
|
|
54
67
|
opts[:description] = opts.delete(:desc) unless opts[:desc].nil?
|
55
68
|
|
56
69
|
# chek alloed params, all optional should go in meta
|
57
|
-
result = opts.keys -
|
58
|
-
raise ArgumentError.new('Unallowed Type params found: %s, allowed: %s' % [result.join('
|
70
|
+
result = opts.keys - Typero::Type::OPTS_KEYS
|
71
|
+
raise ArgumentError.new('Unallowed Type params found: "%s", allowed: %s' % [result.join(' and '), Typero::Type::OPTS_KEYS.sort]) if result.length > 0
|
59
72
|
|
60
73
|
field = field.to_sym
|
61
74
|
|
62
75
|
db :add_index, field if opts.delete(:index)
|
63
76
|
|
64
|
-
|
77
|
+
# trigger error if type not found
|
78
|
+
Typero::Type.load opts[:type]
|
79
|
+
|
65
80
|
@rules[field] = opts
|
66
81
|
end
|
67
82
|
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Typero
|
2
|
+
class Schema
|
3
|
+
SCHEMAS = {}
|
4
|
+
|
5
|
+
# accepts dsl block to
|
6
|
+
def initialize &block
|
7
|
+
raise "Params not defined" unless block_given?
|
8
|
+
@schema = Params.new &block
|
9
|
+
end
|
10
|
+
|
11
|
+
# validates any instance object with hash variable interface
|
12
|
+
# it also coarces values
|
13
|
+
def validate object
|
14
|
+
@object = object
|
15
|
+
@errors = {}
|
16
|
+
|
17
|
+
@schema.rules.each do |field, opts|
|
18
|
+
# set value to default if value is blank and default given
|
19
|
+
@object[field] = opts[:default] if opts[:default] && @object[field].blank?
|
20
|
+
|
21
|
+
# get field value
|
22
|
+
value = @object[field]
|
23
|
+
|
24
|
+
if opts[:array]
|
25
|
+
unless value.is_a?(Array)
|
26
|
+
opts[:delimiter] ||= /\s*,\s*/
|
27
|
+
value = value.to_s.split(opts[:delimiter])
|
28
|
+
end
|
29
|
+
|
30
|
+
value = value
|
31
|
+
.map { |el| check_filed_value field, el, opts }
|
32
|
+
.map { |el| el.to_s == '' ? nil : el }
|
33
|
+
.compact
|
34
|
+
|
35
|
+
value = Set.new(value).to_a unless opts[:duplicates]
|
36
|
+
|
37
|
+
opts[:max_count] ||= 100
|
38
|
+
add_error(field, 'Max number of array elements is %d, you have %d' % [opts[:max_count], value.length], opts) if value.length > opts[:max_count]
|
39
|
+
|
40
|
+
add_required_error field, value.first, opts
|
41
|
+
else
|
42
|
+
value = check_filed_value field, value, opts
|
43
|
+
add_required_error field, value, opts
|
44
|
+
end
|
45
|
+
|
46
|
+
# if value is not list of allowed values, raise error
|
47
|
+
if opts[:allowed] && !opts[:values].include?(value)
|
48
|
+
add_error field, 'Value "%s" is not allowed' % value, opts
|
49
|
+
end
|
50
|
+
|
51
|
+
# present empty string values as nil
|
52
|
+
@object[field] = value.to_s.sub(/\s+/, '') == '' ? nil : value
|
53
|
+
end
|
54
|
+
|
55
|
+
if @errors.keys.length > 0 && block_given?
|
56
|
+
@errors.each { |k, v| yield(k, v) }
|
57
|
+
end
|
58
|
+
|
59
|
+
@errors
|
60
|
+
end
|
61
|
+
|
62
|
+
def valid? object
|
63
|
+
errors = validate object
|
64
|
+
errors.keys.length == 0
|
65
|
+
end
|
66
|
+
|
67
|
+
# returns field, db_type, db_opts
|
68
|
+
def db_schema
|
69
|
+
out = @schema.rules.inject([]) do |total, (field, opts)|
|
70
|
+
# get db filed schema
|
71
|
+
type, opts = Typero::Type.load(opts[:type]).new(nil, opts).db_field
|
72
|
+
|
73
|
+
# add array true to field it ont defined in schema
|
74
|
+
schema_opts = @schema.rules[field]
|
75
|
+
opts[:array] = true if schema_opts[:array]
|
76
|
+
|
77
|
+
total << [type, field, opts]
|
78
|
+
end
|
79
|
+
|
80
|
+
out += @schema.db_rules
|
81
|
+
|
82
|
+
out
|
83
|
+
end
|
84
|
+
|
85
|
+
# iterate trough all the ruels via block interface
|
86
|
+
# schema.rules do |field, opts|
|
87
|
+
# schema.rules(:url) do |field, opts|
|
88
|
+
def rules filter = nil, &block
|
89
|
+
return @schema.rules unless filter
|
90
|
+
out = @schema.rules
|
91
|
+
out = out.select { |k, v| v[:type].to_s == filter.to_s || v[:array_type].to_s == filter.to_s } if filter
|
92
|
+
return out unless block_given?
|
93
|
+
|
94
|
+
out.each { |k, v| yield k, v }
|
95
|
+
end
|
96
|
+
alias :to_h :rules
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# adds error to array or prefixes with field name
|
101
|
+
def add_error field, msg, opts
|
102
|
+
if @errors[field]
|
103
|
+
@errors[field] += ", %s" % msg
|
104
|
+
else
|
105
|
+
if msg && msg[0, 1].downcase == msg[0, 1]
|
106
|
+
field_name = opts[:name] || field.to_s.sub(/_id$/, "").capitalize
|
107
|
+
msg = "%s %s" % [field_name, msg]
|
108
|
+
end
|
109
|
+
|
110
|
+
@errors[field] = msg
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def safe_type type
|
115
|
+
type.to_s.gsub(/[^\w]/, "").classify
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_required_error field, value, opts
|
119
|
+
return unless opts[:required] && value.nil?
|
120
|
+
msg = opts[:required].class == TrueClass ? "is required" : opts[:required]
|
121
|
+
add_error field, msg, opts
|
122
|
+
end
|
123
|
+
|
124
|
+
def check_filed_value field, value, opts
|
125
|
+
klass = "Typero::%sType" % safe_type(opts[:type])
|
126
|
+
check = klass.constantize.new value, opts
|
127
|
+
check.get
|
128
|
+
rescue TypeError => e
|
129
|
+
add_error field, e.message, opts
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/lib/typero/type/type.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Master class
|
2
2
|
|
3
|
-
|
3
|
+
module Typero
|
4
4
|
class Type
|
5
5
|
ERRORS = {
|
6
6
|
en: {
|
@@ -9,14 +9,16 @@ class Typero
|
|
9
9
|
max_length_error: 'max lenght is %s, you have %s',
|
10
10
|
min_value_error: 'min is %s, got %s',
|
11
11
|
max_value_error: 'max is %s, got %s',
|
12
|
-
unallowed_characters_error: 'is having unallowed characters'
|
12
|
+
unallowed_characters_error: 'is having unallowed characters',
|
13
|
+
not_in_range: 'Value in not in allowed range (%s)'
|
13
14
|
}
|
14
15
|
}
|
15
16
|
|
16
|
-
|
17
|
+
# default shared allowed opts keys
|
18
|
+
OPTS_KEYS = [:type, :required, :array, :max_count, :default, :name, :meta, :model]
|
19
|
+
OPTS = {}
|
17
20
|
|
18
|
-
|
19
|
-
attr_accessor :value
|
21
|
+
attr_reader :opts
|
20
22
|
|
21
23
|
class << self
|
22
24
|
def load name
|
@@ -36,6 +38,8 @@ class Typero
|
|
36
38
|
end
|
37
39
|
|
38
40
|
def opts key, desc
|
41
|
+
OPTS_KEYS.push key unless OPTS_KEYS.include?(key)
|
42
|
+
|
39
43
|
OPTS[self] ||= {}
|
40
44
|
OPTS[self][key] = desc
|
41
45
|
end
|
@@ -43,20 +47,44 @@ class Typero
|
|
43
47
|
|
44
48
|
###
|
45
49
|
|
46
|
-
def initialize value, opts={}
|
50
|
+
def initialize value, opts={}, &block
|
51
|
+
value = value.sub(/^\s+/, '').sub(/\s+$/, '') if value.is_a?(String)
|
52
|
+
|
47
53
|
@value = value
|
48
54
|
@opts = opts
|
55
|
+
@block = block
|
56
|
+
end
|
57
|
+
|
58
|
+
def value &block
|
59
|
+
if block_given?
|
60
|
+
@value = block.call @value
|
61
|
+
else
|
62
|
+
@value
|
63
|
+
end
|
49
64
|
end
|
50
65
|
|
51
|
-
|
52
|
-
|
53
|
-
|
66
|
+
def get
|
67
|
+
if value.nil?
|
68
|
+
opts[:default].nil? ? default : opts[:default]
|
69
|
+
else
|
70
|
+
set
|
71
|
+
error_for(:not_in_range, opts[:values].join(', ')) if opts[:values] && !opts[:values].include?(@value)
|
72
|
+
value
|
73
|
+
end
|
54
74
|
end
|
55
75
|
|
56
76
|
def default
|
57
77
|
nil
|
58
78
|
end
|
59
79
|
|
80
|
+
def db_field
|
81
|
+
out = db_schema
|
82
|
+
out[1] ||= {}
|
83
|
+
out[1][:default] ||= opts[:default] unless opts[:default].nil?
|
84
|
+
out[1][:null] = false if !opts[:array] && opts[:required]
|
85
|
+
out
|
86
|
+
end
|
87
|
+
|
60
88
|
private
|
61
89
|
|
62
90
|
# get error from option or the default one
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Typero::BooleanType < Typero::Type
|
2
|
+
error :en, :unsupported_boolean, 'Unsupported boolean param value: %s'
|
3
|
+
|
4
|
+
def set
|
5
|
+
value do |_|
|
6
|
+
bool = _.to_s
|
7
|
+
|
8
|
+
if value == ''
|
9
|
+
false
|
10
|
+
elsif %w(true 1 on).include?(bool)
|
11
|
+
true
|
12
|
+
elsif %w(false 0 off).include?(bool)
|
13
|
+
false
|
14
|
+
else
|
15
|
+
error_for :unsupported_boolean, bool
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def db_schema
|
21
|
+
[:boolean, {
|
22
|
+
default: opts[:default] || false
|
23
|
+
}]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# you should not use this filed for currency calculations
|
2
|
+
# use integer and covert in code
|
3
|
+
# Example: use cents and divide by 100 for $
|
4
|
+
|
5
|
+
require_relative './float_type'
|
6
|
+
|
7
|
+
class Typero::CurrencyType < Typero::FloatType
|
8
|
+
|
9
|
+
def set
|
10
|
+
value { |data| data.to_f.round(2) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def db_schema
|
14
|
+
[:decimal, {
|
15
|
+
precision: 8,
|
16
|
+
scale: 2
|
17
|
+
}]
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|