typero 0.5.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.version +1 -1
  3. data/lib/adapters/sequel.rb +11 -33
  4. data/lib/typero.rb +8 -189
  5. data/lib/typero/params.rb +126 -0
  6. data/lib/typero/schema.rb +154 -0
  7. data/lib/typero/type/type.rb +125 -0
  8. data/lib/typero/type/types/boolean_type.rb +26 -0
  9. data/lib/typero/type/types/currency_type.rb +21 -0
  10. data/lib/typero/type/types/date_type.rb +35 -0
  11. data/lib/typero/type/types/datetime_type.rb +16 -0
  12. data/lib/typero/type/types/email_type.rb +20 -0
  13. data/lib/typero/type/types/float_type.rb +24 -0
  14. data/lib/typero/type/types/hash_type.rb +31 -0
  15. data/lib/typero/type/types/image_type.rb +22 -0
  16. data/lib/typero/type/types/integer_type.rb +16 -0
  17. data/lib/typero/type/types/label_type.rb +20 -0
  18. data/lib/typero/type/types/locale_type.rb +13 -0
  19. data/lib/typero/type/types/model_type.rb +23 -0
  20. data/lib/typero/type/{oib.rb → types/oib_type.rb} +16 -18
  21. data/lib/typero/type/types/point_type.rb +25 -0
  22. data/lib/typero/type/types/string_type.rb +20 -0
  23. data/lib/typero/type/types/text_type.rb +10 -0
  24. data/lib/typero/type/types/time_type.rb +5 -0
  25. data/lib/typero/type/types/timezone_type.rb +15 -0
  26. data/lib/typero/type/types/url_type.rb +13 -0
  27. data/lib/typero/typero.rb +98 -0
  28. metadata +33 -27
  29. data/lib/typero/type.rb +0 -32
  30. data/lib/typero/type/array.rb +0 -55
  31. data/lib/typero/type/boolean.rb +0 -16
  32. data/lib/typero/type/currency.rb +0 -17
  33. data/lib/typero/type/date.rb +0 -6
  34. data/lib/typero/type/datetime.rb +0 -6
  35. data/lib/typero/type/email.rb +0 -27
  36. data/lib/typero/type/float.rb +0 -27
  37. data/lib/typero/type/geography.rb +0 -13
  38. data/lib/typero/type/hash.rb +0 -18
  39. data/lib/typero/type/integer.rb +0 -25
  40. data/lib/typero/type/label.rb +0 -20
  41. data/lib/typero/type/point.rb +0 -25
  42. data/lib/typero/type/string.rb +0 -29
  43. data/lib/typero/type/text.rb +0 -7
  44. 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