typero 0.9.0 → 0.9.5
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 +12 -29
- data/lib/typero/params.rb +39 -9
- data/lib/typero/schema.rb +49 -18
- data/lib/typero/type/type.rb +39 -5
- data/lib/typero/type/types/date_type.rb +7 -1
- data/lib/typero/type/types/datetime_type.rb +6 -1
- data/lib/typero/type/types/hash_type.rb +10 -3
- data/lib/typero/type/types/locale_type.rb +13 -0
- data/lib/typero/type/types/model_type.rb +8 -5
- data/lib/typero/type/types/point_type.rb +2 -1
- data/lib/typero/type/types/simple_point_type.rb +20 -0
- data/lib/typero/type/types/string_type.rb +3 -0
- data/lib/typero/type/types/time_type.rb +5 -0
- data/lib/typero/type/types/timezone_type.rb +15 -0
- data/lib/typero/typero.rb +66 -32
- data/lib/typero.rb +2 -1
- metadata +10 -7
- data/lib/typero/exporter.rb +0 -93
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0bcd151d7d7b875c6db7aec28c85c3abcf10596a4f596622050d7e18cdb81e9e
|
4
|
+
data.tar.gz: d54b9c76d6587e5872f19deba20febd7430e19022fe869a1360339c8156205d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b639372e86d329ef150809f52f964a459c3faf369a86d219292a2af6b8364ed5c2745079d409944472ec59316cae690e0f1d554cecdeacb625bb5ccf4b39f29
|
7
|
+
data.tar.gz: 0e887a10b853325c7b27f3c90ab57b3c1987d38576e3f1128fb27eb4982d2aaefdbf6e5ded9e80a75c7085c5674686196b13653eed62db853d6d50fe0c15ad39
|
data/.version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.5
|
data/lib/adapters/sequel.rb
CHANGED
@@ -1,62 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Sequel::Plugins::
|
3
|
+
module Sequel::Plugins::Typero
|
4
4
|
module ClassMethods
|
5
5
|
def typero
|
6
|
-
Typero.
|
6
|
+
Typero.schema self
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
10
|
module InstanceMethods
|
11
11
|
# calling typero! on any object will validate all fields
|
12
|
-
def
|
13
|
-
|
12
|
+
def validate
|
13
|
+
super
|
14
14
|
|
15
|
-
|
15
|
+
schema = Typero.schema(self.class) || return
|
16
16
|
|
17
|
-
|
17
|
+
schema.validate(self) do |name, err|
|
18
18
|
errors.add(name, err) unless (errors.on(name) || []).include?(err)
|
19
19
|
end
|
20
20
|
|
21
21
|
# this are rules unique to database, so we check them here
|
22
|
-
|
23
|
-
self[field] ||= {} if rule[:type] == 'hash'
|
24
|
-
|
22
|
+
schema.rules.each do |field, rule|
|
25
23
|
# check uniqe fields
|
26
|
-
if rule
|
24
|
+
if unique = rule.dig(:meta, :unique)
|
27
25
|
id = self[:id] || 0
|
28
26
|
value = self[field]
|
29
27
|
|
30
28
|
# we only check if field is changed
|
31
29
|
if value.present? && column_changed?(field) && self.class.xwhere('LOWER(%s)=LOWER(?) and id<>?' % field, value, id).first
|
32
|
-
error =
|
30
|
+
error = unique.class == TrueClass ? %[Value "#{value}" for field "#{field}" has been already used, please chose another value.] : unique
|
33
31
|
errors.add(field, error) unless (errors.on(field) || []).include?(error)
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
35
|
# check protected fields
|
38
|
-
if rule
|
36
|
+
if prot = rule.dig(:meta, :protected) && self[:id]
|
39
37
|
if column_changed?(field)
|
40
|
-
error =
|
38
|
+
error = prot.class == TrueClass ? "value once defined can't be overwritten." : prot
|
41
39
|
errors.add(field, error) unless (errors.on(field) || []).include?(error)
|
42
40
|
end
|
43
41
|
end
|
44
42
|
end
|
45
|
-
|
46
|
-
# check single field if single field given
|
47
|
-
if field_name
|
48
|
-
raise ArgumentError.new 'Field :%s not found in %s' % [field_name, self] unless self[field_name]
|
49
|
-
return unless errors.on(field_name)
|
50
|
-
|
51
|
-
errors.on(field_name).join(', ')
|
52
|
-
end
|
53
|
-
|
54
|
-
true
|
55
|
-
end
|
56
|
-
|
57
|
-
def validate
|
58
|
-
typero!
|
59
|
-
super
|
60
43
|
end
|
61
44
|
end
|
62
45
|
|
@@ -65,5 +48,5 @@ module Sequel::Plugins::TyperoAttributes
|
|
65
48
|
end
|
66
49
|
end
|
67
50
|
|
68
|
-
Sequel::Model.plugin :
|
51
|
+
# Sequel::Model.plugin :typero
|
69
52
|
|
data/lib/typero/params.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Typero
|
4
4
|
class Params
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :db_rules
|
6
6
|
|
7
7
|
def initialize &block
|
8
8
|
@db_rules = []
|
@@ -10,10 +10,14 @@ module Typero
|
|
10
10
|
instance_exec &block
|
11
11
|
end
|
12
12
|
|
13
|
+
def rules
|
14
|
+
@rules.dup
|
15
|
+
end
|
16
|
+
|
13
17
|
private
|
14
18
|
|
15
19
|
# used in dsl to define schema field options
|
16
|
-
def set field, *args
|
20
|
+
def set field, *args, &block
|
17
21
|
raise "Field name not given (Typero)" unless field
|
18
22
|
|
19
23
|
if args.first.is_a?(Hash)
|
@@ -27,12 +31,25 @@ module Typero
|
|
27
31
|
|
28
32
|
field = field.to_s
|
29
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
|
+
|
30
46
|
# name? - opional name
|
31
47
|
if field.include?('?')
|
32
48
|
field = field.sub('?', '')
|
33
49
|
opts[:required] = false
|
34
50
|
end
|
35
51
|
|
52
|
+
opts[:required] = opts.delete(:req) unless opts[:req].nil?
|
36
53
|
opts[:required] = true if opts[:required].nil?
|
37
54
|
|
38
55
|
# array that allows duplicates
|
@@ -47,28 +64,41 @@ module Typero
|
|
47
64
|
opts[:array] = true
|
48
65
|
end
|
49
66
|
|
67
|
+
opts[:type] = @block_type if @block_type
|
68
|
+
|
50
69
|
# Boolean
|
51
|
-
if opts[:type].is_a?(TrueClass)
|
70
|
+
if opts[:type].is_a?(TrueClass) || opts[:type] == :true
|
52
71
|
opts[:required] = false
|
53
72
|
opts[:default] = true
|
54
73
|
opts[:type] = :boolean
|
55
|
-
elsif opts[:type].is_a?(FalseClass)
|
56
|
-
opts[:required] = false
|
57
|
-
opts[:default] = false
|
74
|
+
elsif opts[:type].is_a?(FalseClass) || opts[:type] == :false || opts[:type] == :boolean
|
75
|
+
opts[:required] = false if opts[:required].nil?
|
76
|
+
opts[:default] = false if opts[:default].nil?
|
58
77
|
opts[:type] = :boolean
|
59
78
|
end
|
60
79
|
|
80
|
+
# model / schema
|
81
|
+
if opts[:type].class.ancestors.include?(Typero::Schema)
|
82
|
+
opts[:model] = opts.delete(:type)
|
83
|
+
end
|
61
84
|
opts[:model] = opts.delete(:schema) if opts[:schema]
|
62
85
|
opts[:type] = :model if opts[:model]
|
63
86
|
|
87
|
+
if block_given?
|
88
|
+
opts[:type] = :model
|
89
|
+
opts[:model] = Typero.schema &block
|
90
|
+
end
|
91
|
+
|
64
92
|
opts[:type] ||= 'string'
|
65
93
|
opts[:type] = opts[:type].to_s.downcase.to_sym
|
66
94
|
|
67
95
|
opts[:description] = opts.delete(:desc) unless opts[:desc].nil?
|
68
96
|
|
69
97
|
# chek alloed params, all optional should go in meta
|
70
|
-
|
71
|
-
|
98
|
+
opts.keys.each do |key|
|
99
|
+
type = Typero::Type.load opts[:type]
|
100
|
+
type.allowed_opt?(key) {|err| raise ArgumentError, err }
|
101
|
+
end
|
72
102
|
|
73
103
|
field = field.to_sym
|
74
104
|
|
@@ -93,7 +123,7 @@ module Typero
|
|
93
123
|
# set :emails, Array[:email]
|
94
124
|
# email Array[:emails]
|
95
125
|
def method_missing field, *args, &block
|
96
|
-
set field, *args
|
126
|
+
set field, *args, &block
|
97
127
|
end
|
98
128
|
end
|
99
129
|
end
|
data/lib/typero/schema.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module Typero
|
2
2
|
class Schema
|
3
|
-
SCHEMAS = {}
|
4
|
-
|
5
3
|
# accepts dsl block to
|
6
4
|
def initialize &block
|
7
5
|
raise "Params not defined" unless block_given?
|
@@ -10,42 +8,69 @@ module Typero
|
|
10
8
|
|
11
9
|
# validates any instance object with hash variable interface
|
12
10
|
# it also coarces values
|
13
|
-
def validate object
|
14
|
-
@
|
15
|
-
@
|
11
|
+
def validate object, options=nil
|
12
|
+
@options = options || {}
|
13
|
+
@object = object
|
14
|
+
@errors = {}
|
15
|
+
|
16
|
+
# remove undefined keys if Hash provided
|
17
|
+
if @options[:strict] && object.is_a?(Hash)
|
18
|
+
undefined = object.keys.map(&:to_s) - @schema.rules.keys.map(&:to_s)
|
19
|
+
object.delete_if { |k, _| undefined.include?(k.to_s) }
|
20
|
+
end
|
16
21
|
|
17
22
|
@schema.rules.each do |field, opts|
|
23
|
+
# force filed as a symbol
|
24
|
+
field = field.to_sym
|
25
|
+
|
26
|
+
for k in opts.keys
|
27
|
+
opts[k] = @object.instance_exec(&opts[k]) if opts[k].is_a?(Proc)
|
28
|
+
end
|
29
|
+
|
18
30
|
# set value to default if value is blank and default given
|
19
31
|
@object[field] = opts[:default] if opts[:default] && @object[field].blank?
|
20
32
|
|
21
|
-
|
22
|
-
|
33
|
+
if @object.respond_to?(:key?)
|
34
|
+
if @object.key?(field)
|
35
|
+
value = @object[field]
|
36
|
+
elsif @object.key?(field.to_s)
|
37
|
+
# invalid string key, needs fix
|
38
|
+
value = @object[field] = @object.delete(field.to_s)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
value = @object[field]
|
42
|
+
end
|
23
43
|
|
24
44
|
if opts[:array]
|
25
|
-
unless value.
|
26
|
-
opts[:delimiter] ||= /\s
|
45
|
+
unless value.respond_to?(:each)
|
46
|
+
opts[:delimiter] ||= /\s*[,\n]\s*/
|
27
47
|
value = value.to_s.split(opts[:delimiter])
|
28
48
|
end
|
29
49
|
|
30
50
|
value = value
|
31
|
-
.
|
32
|
-
.map { |el| el.to_s == '' ? nil : el }
|
51
|
+
.flatten
|
52
|
+
.map { |el| el.to_s == '' ? nil : check_filed_value(field, el, opts) }
|
33
53
|
.compact
|
34
54
|
|
35
55
|
value = Set.new(value).to_a unless opts[:duplicates]
|
36
56
|
|
37
57
|
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]
|
58
|
+
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]
|
59
|
+
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]
|
39
60
|
|
40
61
|
add_required_error field, value.first, opts
|
41
62
|
else
|
63
|
+
value = nil if value.to_s == ''
|
64
|
+
|
65
|
+
# if value is not list of allowed values, raise error
|
66
|
+
allowed = opts[:allow] || opts[:allowed] || opts[:values]
|
67
|
+
if value && allowed && !allowed.map(&:to_s).include?(value.to_s)
|
68
|
+
add_error field, 'Value "%s" is not allowed' % value, opts
|
69
|
+
end
|
70
|
+
|
42
71
|
value = check_filed_value field, value, opts
|
43
|
-
add_required_error field, value, opts
|
44
|
-
end
|
45
72
|
|
46
|
-
|
47
|
-
if opts[:allowed] && !opts[:values].include?(value)
|
48
|
-
add_error field, 'Value "%s" is not allowed' % value, opts
|
73
|
+
add_required_error field, value, opts
|
49
74
|
end
|
50
75
|
|
51
76
|
# present empty string values as nil
|
@@ -126,7 +151,13 @@ module Typero
|
|
126
151
|
check = klass.constantize.new value, opts
|
127
152
|
check.get
|
128
153
|
rescue TypeError => e
|
129
|
-
|
154
|
+
if e.message[0] == '{'
|
155
|
+
for key, msg in JSON.parse(e.message)
|
156
|
+
add_error [field, key].join('.'), msg, opts
|
157
|
+
end
|
158
|
+
else
|
159
|
+
add_error field, e.message, opts
|
160
|
+
end
|
130
161
|
end
|
131
162
|
end
|
132
163
|
end
|
data/lib/typero/type/type.rb
CHANGED
@@ -15,8 +15,24 @@ module Typero
|
|
15
15
|
}
|
16
16
|
|
17
17
|
# default shared allowed opts keys
|
18
|
-
OPTS_KEYS = [:type, :required, :array, :max_count, :default, :name, :meta, :model]
|
19
18
|
OPTS = {}
|
19
|
+
OPTS_KEYS = [
|
20
|
+
:allow,
|
21
|
+
:allowed,
|
22
|
+
:array,
|
23
|
+
:default,
|
24
|
+
:description,
|
25
|
+
:delimiter,
|
26
|
+
:max_count,
|
27
|
+
:meta,
|
28
|
+
:min_count,
|
29
|
+
:model,
|
30
|
+
:name,
|
31
|
+
:req,
|
32
|
+
:required,
|
33
|
+
:type,
|
34
|
+
:values
|
35
|
+
]
|
20
36
|
|
21
37
|
attr_reader :opts
|
22
38
|
|
@@ -38,17 +54,31 @@ module Typero
|
|
38
54
|
end
|
39
55
|
|
40
56
|
def opts key, desc
|
41
|
-
OPTS_KEYS.push key unless OPTS_KEYS.include?(key)
|
42
|
-
|
43
57
|
OPTS[self] ||= {}
|
44
58
|
OPTS[self][key] = desc
|
45
59
|
end
|
60
|
+
|
61
|
+
def allowed_opt? name
|
62
|
+
return true if OPTS_KEYS.include?(name)
|
63
|
+
|
64
|
+
OPTS[self] ||= {}
|
65
|
+
return true if OPTS[self][name]
|
66
|
+
|
67
|
+
msg = %[Unallowed param "#{name}" for type "#{to_s}" found. Allowed are "#{OPTS_KEYS.join(', ')}"]
|
68
|
+
msg += %[ + "#{OPTS[self].keys.join(', ')}"] if OPTS[self].keys.first
|
69
|
+
|
70
|
+
block_given? ? yield(msg) : raise(ArgumentError, msg)
|
71
|
+
|
72
|
+
false
|
73
|
+
end
|
46
74
|
end
|
47
75
|
|
48
76
|
###
|
49
77
|
|
50
78
|
def initialize value, opts={}, &block
|
51
|
-
value = value.
|
79
|
+
value = value.strip.rstrip if value.is_a?(String)
|
80
|
+
|
81
|
+
opts.keys.each {|key| self.class.allowed_opt?(key) }
|
52
82
|
|
53
83
|
@value = value
|
54
84
|
@opts = opts
|
@@ -68,7 +98,11 @@ module Typero
|
|
68
98
|
opts[:default].nil? ? default : opts[:default]
|
69
99
|
else
|
70
100
|
set
|
71
|
-
|
101
|
+
|
102
|
+
if opts[:values] && !opts[:values].map(&:to_s).include?(@value.to_s)
|
103
|
+
error_for(:not_in_range, opts[:values].join(', '))
|
104
|
+
end
|
105
|
+
|
72
106
|
value
|
73
107
|
end
|
74
108
|
end
|
@@ -1,9 +1,15 @@
|
|
1
1
|
class Typero::DateType < Typero::Type
|
2
|
+
opts :min, 'Smallest date-time allowed'
|
3
|
+
opts :max, 'Maximal date-time allowed'
|
4
|
+
|
2
5
|
error :en, :min_date, 'Minimal allowed date is %s'
|
3
6
|
error :en, :max_date, 'Maximal allowed date is %s'
|
4
7
|
|
5
8
|
def set
|
6
|
-
|
9
|
+
unless [Date].include?(value.class)
|
10
|
+
value { |data| DateTime.parse(data) }
|
11
|
+
end
|
12
|
+
|
7
13
|
value { |data| DateTime.new(data.year, data.month, data.day) }
|
8
14
|
|
9
15
|
check_date_min_max
|
@@ -1,8 +1,13 @@
|
|
1
1
|
require_relative 'date_type'
|
2
2
|
|
3
3
|
class Typero::DatetimeType < Typero::DateType
|
4
|
+
opts :min, 'Smallest date allowed'
|
5
|
+
opts :max, 'Maximal date allowed'
|
6
|
+
|
4
7
|
def set
|
5
|
-
|
8
|
+
unless [Time, DateTime].include?(value.class)
|
9
|
+
value { |data| DateTime.parse(data) }
|
10
|
+
end
|
6
11
|
|
7
12
|
check_date_min_max
|
8
13
|
end
|
@@ -2,11 +2,18 @@ class Typero::HashType < Typero::Type
|
|
2
2
|
error :en, :not_hash_type_error, 'value is not hash type'
|
3
3
|
|
4
4
|
def set
|
5
|
-
|
5
|
+
if value.is_a?(String) && value[0,1] == '{'
|
6
|
+
@value = JSON.load(value)
|
7
|
+
end
|
8
|
+
|
9
|
+
@value ||= {}
|
10
|
+
@value.delete_if {|_, v| v.empty? }
|
11
|
+
|
12
|
+
error_for(:not_hash_type_error) unless @value.respond_to?(:keys) && @value.respond_to?(:values)
|
6
13
|
|
7
14
|
if opts[:allow]
|
8
|
-
for key in value.keys
|
9
|
-
value.delete(key) unless opts[:allow].include?(key)
|
15
|
+
for key in @value.keys
|
16
|
+
@value.delete(key) unless opts[:allow].include?(key)
|
10
17
|
end
|
11
18
|
end
|
12
19
|
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
|
+
|
@@ -2,14 +2,17 @@ class Typero::ModelType < Typero::Type
|
|
2
2
|
def set
|
3
3
|
value(&:to_h)
|
4
4
|
|
5
|
-
errors =
|
5
|
+
errors = {}
|
6
|
+
schema = opts[:model].is_a?(Typero::Schema) ? opts[:model] : Typero.schema(opts[:model])
|
6
7
|
|
7
|
-
|
8
|
-
schema.validate
|
9
|
-
errors
|
8
|
+
# by default models in schems are strict true (remove undefined keys)
|
9
|
+
schema.validate value, strict: true do |field, error|
|
10
|
+
errors[field] = error
|
10
11
|
end
|
11
12
|
|
12
|
-
|
13
|
+
@value.delete_if {|_, v| v.empty? }
|
14
|
+
|
15
|
+
raise TypeError.new errors.to_json if errors.keys.first
|
13
16
|
end
|
14
17
|
|
15
18
|
def db_schema
|
@@ -4,12 +4,13 @@
|
|
4
4
|
class Typero::PointType < Typero::Type
|
5
5
|
def set
|
6
6
|
if value.include?('/@')
|
7
|
+
# extract value from google maps link
|
7
8
|
point = value.split('/@', 2).last.split(',')
|
8
9
|
value { [point[0], point[1]].join(',') }
|
9
10
|
end
|
10
11
|
|
11
12
|
if !value.include?('POINT') && value.include?(',')
|
12
|
-
point = value.sub(
|
13
|
+
point = value.sub(/\s*,\s*/, ' ')
|
13
14
|
value { 'SRID=4326;POINT(%s)' % point }
|
14
15
|
end
|
15
16
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Same as point, but we keep data as a float in Array
|
2
|
+
|
3
|
+
class Typero::SimplePointType < Typero::Type
|
4
|
+
def set
|
5
|
+
if value.include?('/@')
|
6
|
+
# extract value from google maps link
|
7
|
+
point = value.split('/@', 2).last.split(',')[0,2]
|
8
|
+
value { point }
|
9
|
+
end
|
10
|
+
|
11
|
+
if !value.include?('POINT') && value.include?(',')
|
12
|
+
value { value.split(/\s*,\s*/)[0,2] }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def db_schema
|
17
|
+
[:float, { array: true }]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -7,6 +7,9 @@ class Typero::StringType < Typero::Type
|
|
7
7
|
value(&:to_s)
|
8
8
|
value(&:downcase) if opts[:downcase]
|
9
9
|
|
10
|
+
# this is database default for string type and it is good to define default unless defined
|
11
|
+
opts[:max] ||= 255
|
12
|
+
|
10
13
|
error_for(:min_length_error, opts[:min], value.length) if opts[:min] && value.length < opts[:min]
|
11
14
|
error_for(:max_length_error, opts[:max], value.length) if opts[:max] && value.length > opts[:max]
|
12
15
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Typero::TimezoneType < Typero::Type
|
2
|
+
error :en, :invalid_time_zone, 'Invalid time zone'
|
3
|
+
|
4
|
+
def set
|
5
|
+
TZInfo::Timezone.get(value)
|
6
|
+
rescue TZInfo::InvalidTimezoneIdentifier
|
7
|
+
error_for :invalid_time_zone
|
8
|
+
end
|
9
|
+
|
10
|
+
def db_schema
|
11
|
+
[:string, { length: 50 }]
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
data/lib/typero/typero.rb
CHANGED
@@ -19,45 +19,82 @@
|
|
19
19
|
module Typero
|
20
20
|
extend self
|
21
21
|
|
22
|
-
VERSION
|
22
|
+
VERSION ||= File.read File.expand_path "../../.version", File.dirname(__FILE__)
|
23
|
+
SCHEMAS ||= {}
|
23
24
|
|
24
25
|
# check and coerce value
|
25
|
-
# Typero.
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if
|
31
|
-
|
32
|
-
false
|
26
|
+
# Typero.type(:label) -> Typero::LabelType
|
27
|
+
# Typero.type(:label, 'Foo bar') -> "foo-bar"
|
28
|
+
def type klass_name, value = :_undefined, opts = {}, &block
|
29
|
+
klass = Typero::Type.load(klass_name)
|
30
|
+
|
31
|
+
if value == :_undefined
|
32
|
+
klass
|
33
33
|
else
|
34
|
-
|
34
|
+
begin
|
35
|
+
check = klass.new value, opts
|
36
|
+
check.get
|
37
|
+
rescue TypeError => error
|
38
|
+
if block
|
39
|
+
block.call error
|
40
|
+
false
|
41
|
+
else
|
42
|
+
raise error
|
43
|
+
end
|
44
|
+
end
|
35
45
|
end
|
36
46
|
end
|
47
|
+
alias :set :type
|
48
|
+
|
49
|
+
# type schema
|
50
|
+
# Typero.schema(:blog) { ... }
|
51
|
+
|
52
|
+
# type schema with option
|
53
|
+
# Typero.schema(:blog, type: :model) { ... }
|
37
54
|
|
38
|
-
#
|
39
|
-
|
40
|
-
|
41
|
-
|
55
|
+
# get schema
|
56
|
+
# Typero.schema(:blog)
|
57
|
+
|
58
|
+
# get schema with options (as array)
|
59
|
+
# Typero.schema(:blog, :with_schema)
|
60
|
+
|
61
|
+
# get all schema names with type: model
|
62
|
+
# Typero.schema(type: :model)
|
63
|
+
def schema name = nil, opts = nil, &block
|
64
|
+
klass = name.to_s.classify if name && !name.is_a?(Hash)
|
42
65
|
|
43
66
|
if block_given?
|
44
67
|
Typero::Schema.new(&block).tap do |schema|
|
45
|
-
|
68
|
+
if klass
|
69
|
+
SCHEMAS[klass] = [schema, opts || {}]
|
70
|
+
end
|
46
71
|
end
|
47
72
|
else
|
48
|
-
|
73
|
+
# Schema not given, get schema
|
74
|
+
if name.is_a?(Hash)
|
75
|
+
# Typero.schema type: :model
|
76
|
+
out = []
|
49
77
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
78
|
+
for key, _ in SCHEMAS
|
79
|
+
schema, opts = _
|
80
|
+
next unless opts[name.keys.first] == name.values.first
|
81
|
+
out.push key.classify
|
82
|
+
end
|
55
83
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
84
|
+
out
|
85
|
+
elsif klass
|
86
|
+
# Typero.schema :user
|
87
|
+
schema = SCHEMAS[klass]
|
88
|
+
schema ||= class_finder klass, :schema
|
89
|
+
|
90
|
+
if opts
|
91
|
+
schema
|
92
|
+
else
|
93
|
+
schema.respond_to?(:[]) ? schema[0] : schema
|
94
|
+
end
|
95
|
+
else
|
96
|
+
raise ArgumentError, 'Schema type not defined.'
|
97
|
+
end
|
61
98
|
end
|
62
99
|
end
|
63
100
|
|
@@ -78,13 +115,10 @@ module Typero
|
|
78
115
|
for el in args
|
79
116
|
for separator in ['_','/']
|
80
117
|
klass = [name, el].join(separator).classify
|
81
|
-
|
82
|
-
begin
|
83
|
-
return klass.constantize
|
84
|
-
rescue NameError => e
|
85
|
-
nil
|
86
|
-
end
|
118
|
+
return klass.constantize if const_defined? klass
|
87
119
|
end
|
88
120
|
end
|
121
|
+
|
122
|
+
nil
|
89
123
|
end
|
90
124
|
end
|
data/lib/typero.rb
CHANGED
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.9.
|
4
|
+
version: 0.9.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dino Reic
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fast_blank
|
@@ -34,7 +34,6 @@ files:
|
|
34
34
|
- "./.version"
|
35
35
|
- "./lib/adapters/sequel.rb"
|
36
36
|
- "./lib/typero.rb"
|
37
|
-
- "./lib/typero/exporter.rb"
|
38
37
|
- "./lib/typero/params.rb"
|
39
38
|
- "./lib/typero/schema.rb"
|
40
39
|
- "./lib/typero/type/type.rb"
|
@@ -48,18 +47,22 @@ files:
|
|
48
47
|
- "./lib/typero/type/types/image_type.rb"
|
49
48
|
- "./lib/typero/type/types/integer_type.rb"
|
50
49
|
- "./lib/typero/type/types/label_type.rb"
|
50
|
+
- "./lib/typero/type/types/locale_type.rb"
|
51
51
|
- "./lib/typero/type/types/model_type.rb"
|
52
52
|
- "./lib/typero/type/types/oib_type.rb"
|
53
53
|
- "./lib/typero/type/types/point_type.rb"
|
54
|
+
- "./lib/typero/type/types/simple_point_type.rb"
|
54
55
|
- "./lib/typero/type/types/string_type.rb"
|
55
56
|
- "./lib/typero/type/types/text_type.rb"
|
57
|
+
- "./lib/typero/type/types/time_type.rb"
|
58
|
+
- "./lib/typero/type/types/timezone_type.rb"
|
56
59
|
- "./lib/typero/type/types/url_type.rb"
|
57
60
|
- "./lib/typero/typero.rb"
|
58
61
|
homepage: https://github.com/dux/typero
|
59
62
|
licenses:
|
60
63
|
- MIT
|
61
64
|
metadata: {}
|
62
|
-
post_install_message:
|
65
|
+
post_install_message:
|
63
66
|
rdoc_options: []
|
64
67
|
require_paths:
|
65
68
|
- lib
|
@@ -74,8 +77,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
77
|
- !ruby/object:Gem::Version
|
75
78
|
version: '0'
|
76
79
|
requirements: []
|
77
|
-
rubygems_version: 3.
|
78
|
-
signing_key:
|
80
|
+
rubygems_version: 3.2.3
|
81
|
+
signing_key:
|
79
82
|
specification_version: 4
|
80
83
|
summary: Ruby type system
|
81
84
|
test_files: []
|
data/lib/typero/exporter.rb
DELETED
@@ -1,93 +0,0 @@
|
|
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
|
-
|