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
@@ -0,0 +1,125 @@
|
|
1
|
+
# Master class
|
2
|
+
|
3
|
+
module Typero
|
4
|
+
class Type
|
5
|
+
ERRORS = {
|
6
|
+
en: {
|
7
|
+
# errors shared between various types
|
8
|
+
min_length_error: 'min lenght is %s, you have %s',
|
9
|
+
max_length_error: 'max lenght is %s, you have %s',
|
10
|
+
min_value_error: 'min is %s, got %s',
|
11
|
+
max_value_error: 'max is %s, got %s',
|
12
|
+
unallowed_characters_error: 'is having unallowed characters',
|
13
|
+
not_in_range: 'Value in not in allowed range (%s)'
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
# default shared allowed opts keys
|
18
|
+
OPTS = {}
|
19
|
+
OPTS_KEYS = [
|
20
|
+
:allow,
|
21
|
+
:allowed,
|
22
|
+
:array,
|
23
|
+
:default,
|
24
|
+
:description,
|
25
|
+
:max_count,
|
26
|
+
:meta,
|
27
|
+
:min_count,
|
28
|
+
:model,
|
29
|
+
:name,
|
30
|
+
:req,
|
31
|
+
:required,
|
32
|
+
:type,
|
33
|
+
:values
|
34
|
+
]
|
35
|
+
|
36
|
+
attr_reader :opts
|
37
|
+
|
38
|
+
class << self
|
39
|
+
def load name
|
40
|
+
klass = 'Typero::%sType' % name.to_s.gsub(/[^\w]/,'').classify
|
41
|
+
|
42
|
+
if const_defined? klass
|
43
|
+
klass.constantize
|
44
|
+
else
|
45
|
+
raise ArgumentError, 'Typero type "%s" is not defined (%s)' % [name, klass]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def error locale, key, message
|
50
|
+
locale = locale.to_sym
|
51
|
+
ERRORS[locale] ||= {}
|
52
|
+
ERRORS[locale][key.to_sym] = message
|
53
|
+
end
|
54
|
+
|
55
|
+
def opts key, desc
|
56
|
+
OPTS_KEYS.push key unless OPTS_KEYS.include?(key)
|
57
|
+
|
58
|
+
OPTS[self] ||= {}
|
59
|
+
OPTS[self][key] = desc
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
###
|
64
|
+
|
65
|
+
def initialize value, opts={}, &block
|
66
|
+
value = value.strip.rstrip if value.is_a?(String)
|
67
|
+
|
68
|
+
@value = value
|
69
|
+
@opts = opts
|
70
|
+
@block = block
|
71
|
+
end
|
72
|
+
|
73
|
+
def value &block
|
74
|
+
if block_given?
|
75
|
+
@value = block.call @value
|
76
|
+
else
|
77
|
+
@value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def get
|
82
|
+
if value.nil?
|
83
|
+
opts[:default].nil? ? default : opts[:default]
|
84
|
+
else
|
85
|
+
set
|
86
|
+
error_for(:not_in_range, opts[:values].join(', ')) if opts[:values] && !opts[:values].include?(@value)
|
87
|
+
value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def default
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def db_field
|
96
|
+
out = db_schema
|
97
|
+
out[1] ||= {}
|
98
|
+
out[1][:default] ||= opts[:default] unless opts[:default].nil?
|
99
|
+
out[1][:null] = false if !opts[:array] && opts[:required]
|
100
|
+
out
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
# get error from option or the default one
|
106
|
+
def error_for name, *args
|
107
|
+
locale =
|
108
|
+
if defined?(Lux)
|
109
|
+
Lux.current.locale.to_s
|
110
|
+
elsif defined?(I18n)
|
111
|
+
I18n.locale
|
112
|
+
end
|
113
|
+
|
114
|
+
locale = :en if locale.to_s == ''
|
115
|
+
pointer = ERRORS[locale.to_sym] || ERRORS[:en]
|
116
|
+
error = @opts.dig(:meta, locale, name) || @opts.dig(:meta, name) || pointer[name]
|
117
|
+
error = error % args if args.first
|
118
|
+
|
119
|
+
raise 'Type error :%s not defined' % name unless error
|
120
|
+
raise TypeError.new(error)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
|
@@ -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
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Typero::DateType < Typero::Type
|
2
|
+
error :en, :min_date, 'Minimal allowed date is %s'
|
3
|
+
error :en, :max_date, 'Maximal allowed date is %s'
|
4
|
+
|
5
|
+
def set
|
6
|
+
unless [Date].include?(value.class)
|
7
|
+
value { |data| DateTime.parse(data) }
|
8
|
+
end
|
9
|
+
|
10
|
+
value { |data| DateTime.new(data.year, data.month, data.day) }
|
11
|
+
|
12
|
+
check_date_min_max
|
13
|
+
end
|
14
|
+
|
15
|
+
def db_schema
|
16
|
+
[:date, {}]
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def check_date_min_max
|
22
|
+
if min = opts[:min]
|
23
|
+
min = DateTime.parse(min)
|
24
|
+
error_for(:min_date, min) % min if min > value
|
25
|
+
end
|
26
|
+
|
27
|
+
if max = opts[:max]
|
28
|
+
max = DateTime.parse(max)
|
29
|
+
error_for(:max_date, max) % max if value > max
|
30
|
+
end
|
31
|
+
|
32
|
+
value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative 'date_type'
|
2
|
+
|
3
|
+
class Typero::DatetimeType < Typero::DateType
|
4
|
+
def set
|
5
|
+
unless [Time, DateTime].include?(value.class)
|
6
|
+
value { |data| DateTime.parse(data) }
|
7
|
+
end
|
8
|
+
|
9
|
+
check_date_min_max
|
10
|
+
end
|
11
|
+
|
12
|
+
def db_schema
|
13
|
+
[:datetime]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Typero::EmailType < Typero::Type
|
2
|
+
error :en, :not_8_chars_error, 'is not having at least 8 characters'
|
3
|
+
error :en, :missing_monkey_error, 'is missing @'
|
4
|
+
|
5
|
+
def set
|
6
|
+
value do |email|
|
7
|
+
email.downcase.gsub(/\s+/,'+')
|
8
|
+
end
|
9
|
+
|
10
|
+
error_for(:not_8_chars_error) unless value.to_s.length > 7
|
11
|
+
error_for(:missing_monkey_error) unless value.include?('@')
|
12
|
+
end
|
13
|
+
|
14
|
+
def db_schema
|
15
|
+
[:string, {
|
16
|
+
limit: @opts[:max] || 120
|
17
|
+
}]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Typero::FloatType < Typero::Type
|
2
|
+
opts :min, 'Minimum value'
|
3
|
+
opts :max, 'Maximun value'
|
4
|
+
opts :round, 'Round to (decimal spaces)'
|
5
|
+
|
6
|
+
def set
|
7
|
+
@value =
|
8
|
+
if opts[:round]
|
9
|
+
value.to_f.round(opts[:round])
|
10
|
+
else
|
11
|
+
value.to_f
|
12
|
+
end
|
13
|
+
|
14
|
+
error_for(:min_length_error, opts[:min], value) if opts[:min] && value < opts[:min]
|
15
|
+
error_for(:max_length_error, opts[:max], value) if opts[:max] && value > opts[:max]
|
16
|
+
end
|
17
|
+
|
18
|
+
def db_schema
|
19
|
+
opts = {}
|
20
|
+
opts[:null] = false if opts[:required]
|
21
|
+
[:float, opts]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Typero::HashType < Typero::Type
|
2
|
+
error :en, :not_hash_type_error, 'value is not hash type'
|
3
|
+
|
4
|
+
def set
|
5
|
+
if value.is_a?(String) && value[0,1] == '{'
|
6
|
+
@value = JSON.load(value)
|
7
|
+
end
|
8
|
+
|
9
|
+
@value ||= {}
|
10
|
+
|
11
|
+
error_for(:not_hash_type_error) unless @value.respond_to?(:keys) && @value.respond_to?(:values)
|
12
|
+
|
13
|
+
if opts[:allow]
|
14
|
+
for key in @value.keys
|
15
|
+
@value.delete(key) unless opts[:allow].include?(key)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def default
|
21
|
+
{}
|
22
|
+
end
|
23
|
+
|
24
|
+
def db_schema
|
25
|
+
[:jsonb, {
|
26
|
+
null: false,
|
27
|
+
default: '{}'
|
28
|
+
}]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Typero::ImageType < Typero::Type
|
2
|
+
FORMATS = %w[jpg jpeg gif png svg webp]
|
3
|
+
|
4
|
+
error :en, :image_not_starting_error, 'URL is not starting with http'
|
5
|
+
error :en, :image_not_image_format, 'URL is not ending with %s' % FORMATS.join(', ')
|
6
|
+
|
7
|
+
opts :strict, 'Force image to have known extension (%s)' % FORMATS.join(', ')
|
8
|
+
|
9
|
+
def set
|
10
|
+
error_for(:image_not_starting_error) unless value =~ /^https?:\/\/./
|
11
|
+
|
12
|
+
if opts[:strict]
|
13
|
+
ext = value.split('.').last.downcase
|
14
|
+
error_for(:image_not_image_format) unless FORMATS.include?(ext)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def db_schema
|
19
|
+
[:string]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Typero::IntegerType < Typero::Type
|
2
|
+
opts :min, 'Minimum value'
|
3
|
+
opts :max, 'Maximun value'
|
4
|
+
|
5
|
+
def set
|
6
|
+
value(&:to_i)
|
7
|
+
|
8
|
+
error_for(:min_value_error, opts[:min], value) if opts[:min] && value < opts[:min]
|
9
|
+
error_for(:max_value_error, opts[:max], value) if opts[:max] && value > opts[:max]
|
10
|
+
end
|
11
|
+
|
12
|
+
def db_schema
|
13
|
+
[:integer, {}]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Typero::LabelType < Typero::Type
|
2
|
+
def set
|
3
|
+
value do |data|
|
4
|
+
data
|
5
|
+
.to_s
|
6
|
+
.gsub(/\s+/,'-')
|
7
|
+
.gsub(/[^\w\-]/,'')
|
8
|
+
.gsub(/\-+/, '-')[0,30]
|
9
|
+
.downcase
|
10
|
+
end
|
11
|
+
|
12
|
+
error_for(:unallowed_characters_error) unless value =~ /^[\w\-]+$/
|
13
|
+
end
|
14
|
+
|
15
|
+
def db_schema
|
16
|
+
[:string, {
|
17
|
+
limit: 30
|
18
|
+
}]
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Typero::LocaleType < Typero::Type
|
2
|
+
error :en, :locale_bad_format, 'Locale "%s" is in bad format (should be xx or xx-xx)'
|
3
|
+
|
4
|
+
def set
|
5
|
+
error_for(:locale_bad_format, value) unless value =~ /^[\w\-]{2,5}$/
|
6
|
+
end
|
7
|
+
|
8
|
+
def db_schema
|
9
|
+
[:string, { limit: 5 }]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Typero::ModelType < Typero::Type
|
2
|
+
def set
|
3
|
+
value(&:to_h)
|
4
|
+
|
5
|
+
errors = {}
|
6
|
+
|
7
|
+
schema = opts[:model].is_a?(Typero::Schema) ? opts[:model] : Typero.schema(opts[:model])
|
8
|
+
|
9
|
+
# by default models in schems are strict true (remove undefined keys)
|
10
|
+
schema.validate value, strict: true do |field, error|
|
11
|
+
errors[field] = error
|
12
|
+
end
|
13
|
+
|
14
|
+
raise TypeError.new errors.to_json if errors.keys.first
|
15
|
+
end
|
16
|
+
|
17
|
+
def db_schema
|
18
|
+
[:jsonb, {
|
19
|
+
null: false
|
20
|
+
}]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -1,4 +1,20 @@
|
|
1
1
|
class Typero::OibType < Typero::Type
|
2
|
+
error :en, :not_an_oib_error, 'not in an OIB format'
|
3
|
+
|
4
|
+
def set
|
5
|
+
value do |data|
|
6
|
+
check?(data) ? data.to_i : error_for(:not_an_oib_error)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def db_schema
|
11
|
+
[:string, {
|
12
|
+
limit: 11
|
13
|
+
}]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
2
18
|
# http://domagoj.eu/oib/
|
3
19
|
def check? oib
|
4
20
|
oib = oib.to_s
|
@@ -19,23 +35,5 @@ class Typero::OibType < Typero::Type
|
|
19
35
|
return control_sum == oib.at(10).to_i
|
20
36
|
end
|
21
37
|
|
22
|
-
def set
|
23
|
-
@value = check?(@value) ? @value.to_i : nil
|
24
|
-
end
|
25
|
-
|
26
|
-
def validate
|
27
|
-
raise TypeError.new(error_for(:not_an_oib_error)) unless check?(@value)
|
28
|
-
end
|
29
|
-
|
30
|
-
def not_an_oib_error
|
31
|
-
'not in an OIB format'
|
32
|
-
end
|
33
|
-
|
34
|
-
def db_field
|
35
|
-
opts = {}
|
36
|
-
opts[:null] = false if @opts[:req]
|
37
|
-
opts[:limit] = 11
|
38
|
-
[:string, opts]
|
39
|
-
end
|
40
38
|
end
|
41
39
|
|