typero 0.9.0 → 0.9.5
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/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
|
-
|