typero 0.4.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2abbf2baf5e54e738a8144eba2aa35218d88faaf1f26032a041474df61ebc393
4
- data.tar.gz: 5d0eed00df648f251b43148b185dab5f05b07068ed225d831584e5a831d41b8a
3
+ metadata.gz: 3abfc7ee1372098804789576ac4fb36dbfb33a2cce2e48cd2dda70b975a2a1f6
4
+ data.tar.gz: 9ed9618bde6dd268b39f516428c63c07a3aa86006323a0dd0b231a421e6a4c68
5
5
  SHA512:
6
- metadata.gz: 78c673d3df0f2a968f44f9fab440c11831de686684d505ac3224ac937a470b0a773c1353a4c37eeb703fdf00fa13dab0a799f59e5ff5596ef75ab32860c0a9b4
7
- data.tar.gz: 735f2eea8437315bf330e9d31f7e3fd9b910b3da8b7c9a3792e9b06f4628789798a4aeef089064baac2db412a0fefbeb948908c50bccb4ee6fdfba9497c8f0d4
6
+ metadata.gz: 3ab235a93802052f17166cf1bda8a3cd75ee20def1c669c9b5ccf7bb4d7633ae2ddffec6cc01f57e3bf2c98aaf652731a1deb7c2450e658da76ae8092e3790a1
7
+ data.tar.gz: 4430507594bdecbb95aff494ed0e8dc1a71d22111abecafec19a801d3d4445d1a32dfe5fd861b330515d7b63ba0a9867d53e088e1c2a3d206b13cf9147a09cd1
data/.version CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.5.2
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'typero'
4
+
5
+ module Sequel::Plugins::TyperoAttributes
6
+ module ClassMethods
7
+ def attributes opts={}, &block
8
+ instance_variable_set :@typero, Typero.new(&block)
9
+
10
+ # attributes migrate: true do ...
11
+ AutoMigrate.typero to_s.tableize.to_sym if opts[:migrate] && Lux.config.migrate
12
+ end
13
+
14
+ def typero
15
+ instance_variable_get :@typero
16
+ end
17
+ end
18
+
19
+ module InstanceMethods
20
+ # calling typero! on any object will validate all fields
21
+ def typero! field_name=nil
22
+ typero = self.class.typero || return
23
+
24
+ typero.validate(self) do |name, err|
25
+ errors.add(name, err) unless (errors.on(name) || []).include?(err)
26
+ end
27
+
28
+ # this are rules unique to database, so we check them here
29
+ typero.rules.each do |field, rule|
30
+ # check uniqe fields
31
+ if rule[:unique]
32
+ id = self[:id] || 0
33
+ value = self[field]
34
+
35
+ # we only check if field is changed
36
+ if value.present? && column_changed?(field) && self.class.xwhere('LOWER(%s)=LOWER(?) and id<>?' % field, value, id).first
37
+ error = rule[:unique].class == TrueClass ? %[Value '"#{value}"' for #{field} allready exists] : rule[:unique]
38
+ errors.add(field, error) unless (errors.on(field) || []).include?(error)
39
+ end
40
+ end
41
+
42
+ # check protected fields
43
+ if rule[:protected] && self[:id]
44
+ if column_changed?(field)
45
+ error = rule[:protected].class == TrueClass ? "value once defined can't be overwritten." : rule[:protected]
46
+ errors.add(field, error) unless (errors.on(field) || []).include?(error)
47
+ end
48
+ end
49
+ end
50
+
51
+ # check single field if single field given
52
+ if field_name
53
+ raise ArgumentError.new 'Field :%s not found in %s' % [field_name, self] unless self[field_name]
54
+ return unless errors.on(field_name)
55
+
56
+ errors.on(field_name).join(', ')
57
+ end
58
+
59
+ true
60
+ end
61
+
62
+ def validate
63
+ typero!
64
+ super
65
+ end
66
+ end
67
+
68
+ module DatasetMethods
69
+
70
+ end
71
+ end
72
+
73
+ Sequel::Model.plugin :typero_attributes
74
+
data/lib/typero.rb CHANGED
@@ -43,7 +43,7 @@ class Typero
43
43
  # Typero.set(:label, 'Foo bar') -> "foo-bar"
44
44
  def set type, value, opts={}
45
45
  check = Typero::Type.load(type).new value, opts
46
- check.set
46
+ check.value
47
47
  end
48
48
  end
49
49
 
@@ -52,76 +52,11 @@ class Typero
52
52
  # accepts dsl block to
53
53
  def initialize hash={}, &block
54
54
  @rules = {}
55
+ @db = []
55
56
  hash.each { |k, v| set(k, v) }
56
57
  instance_exec &block if block
57
58
  end
58
59
 
59
- # set :age, type: :integer -> integer :age
60
- # email :email
61
- # set :email, [:emails]
62
- # email [:emails]
63
- def method_missing name, *args, &block
64
- field = args.shift
65
-
66
- if field.class == Array
67
- field = field.first
68
- name = [name]
69
- end
70
-
71
- set field, type=name, *args
72
- end
73
-
74
- # coerce opts values
75
- def parse_option opts
76
- opts[:type] ||= 'string'
77
- opts[:req] = opts.delete(:required) unless opts[:required].nil?
78
-
79
- if opts[:type].is_a?(Array)
80
- opts[:array_type] = opts[:type][0] if opts[:type][0]
81
- opts[:type] = 'array'
82
- end
83
-
84
- opts[:type] = opts[:type].to_s.downcase
85
-
86
- opts[:required] = opts[:req] unless opts[:req].nil?
87
- opts[:unique] = opts[:uniq] unless opts[:uniq].nil?
88
- opts[:description] = opts[:desc] unless opts[:desc].nil?
89
-
90
- # allowed_names = [:req, :uniq, :protected, :type, :min, :max, :array_type, :default, :downcase, :desc, :label]
91
- # opts.keys.each do |key|
92
- # raise ArgumentError.new('%s is not allowed as typero option' % key) unless allowed_names.index(key)
93
- # end
94
-
95
- opts
96
- end
97
-
98
- # used in dsl to define value
99
- def set field, type=String, opts={}
100
- opts = type.is_a?(Hash) ? type : opts.merge(type: type)
101
-
102
- opts[:type] ||= :string
103
- klass = Typero::Type.load opts[:type]
104
- @rules[field] = parse_option opts
105
- end
106
-
107
- def safe_type type
108
- type.to_s.gsub(/[^\w]/,'').classify
109
- end
110
-
111
- # adds error to array or prefixes with field name
112
- def add_error field, msg
113
- if @errors[field]
114
- @errors[field] += ', %s' % msg
115
- else
116
- if msg[0,1].downcase == msg[0,1]
117
- field_name = field.to_s.sub(/_id$/,'').humanize
118
- msg = '%s %s' % [field_name, msg]
119
- end
120
-
121
- @errors[field] = msg
122
- end
123
- end
124
-
125
60
  # validates any instance object or object with hash variable interface
126
61
  # it also coarces values
127
62
  def validate instance
@@ -165,8 +100,97 @@ class Typero
165
100
  errors = validate instance
166
101
  errors.keys.length == 0
167
102
  end
103
+
104
+ # returns field, db_type, db_opts
105
+ def db_schema
106
+ out = @rules.inject([]) do |total, (field, opts)|
107
+ type, opts = Typero::Type.load(opts[:type]).new(nil, opts).db_field
108
+ total << [type, field, opts]
109
+ end
110
+
111
+ out += @db if @db[0]
112
+
113
+ out
114
+ end
115
+
116
+ private
117
+
118
+ # adds error to array or prefixes with field name
119
+ def add_error field, msg
120
+ if @errors[field]
121
+ @errors[field] += ', %s' % msg
122
+ else
123
+ if msg[0,1].downcase == msg[0,1]
124
+ field_name = field.to_s.sub(/_id$/,'').humanize
125
+ msg = '%s %s' % [field_name, msg]
126
+ end
127
+
128
+ @errors[field] = msg
129
+ end
130
+ end
131
+
132
+ # used in dsl to define value
133
+ def set field, type=String, opts={}
134
+ opts = type.is_a?(Hash) ? type : opts.merge(type: type)
135
+ opts[:type] ||= :string
136
+ opts[:req] = true if opts[:null].class == FalseClass
137
+ klass = Typero::Type.load opts[:type]
138
+ @rules[field] = parse_option opts
139
+ end
140
+
141
+ def safe_type type
142
+ type.to_s.gsub(/[^\w]/,'').classify
143
+ end
144
+
145
+ # coerce opts values
146
+ def parse_option opts
147
+ opts[:type] ||= 'string'
148
+
149
+ if opts[:type].is_a?(Array)
150
+ opts[:array_type] = opts[:type][0] if opts[:type][0]
151
+ opts[:type] = 'array'
152
+ end
153
+
154
+ opts[:type] = opts[:type].to_s.downcase
155
+
156
+ opts[:required] = opts.delete(:req) unless opts[:req].nil?
157
+ opts[:unique] = opts.delete(:uniq) unless opts[:uniq].nil?
158
+ opts[:description] = opts.delete(:desc) unless opts[:desc].nil?
159
+
160
+ opts
161
+ end
162
+
163
+
164
+ # pass values for db_schema only
165
+ # db :timestamps
166
+ # db :add_index, :code -> t.add_index :code
167
+ def db *args
168
+ @db.push args
169
+ end
170
+
171
+ # set :age, type: :integer -> integer :age
172
+ # email :email
173
+ # set :email, [:emails]
174
+ # email [:emails]
175
+ def method_missing name, *args, &block
176
+ field = args.shift
177
+
178
+ if field.class == Array
179
+ field = field.first
180
+ name = [name]
181
+ end
182
+
183
+ name = args.shift if name == :set
184
+
185
+ set field, type=name, *args
186
+ end
168
187
  end
169
188
 
170
189
  require_relative 'typero/type'
171
190
 
172
- Dir['%s/typero/type/*.rb' % File.dirname(__FILE__)].each { |file| require file }
191
+ Dir['%s/typero/type/*.rb' % __dir__].each do |file|
192
+ require file
193
+ end
194
+
195
+ # load Sequel adapter is Sequel is available
196
+ require_relative './adapters/sequel' if defined?(Sequel)
data/lib/typero/type.rb CHANGED
@@ -9,28 +9,21 @@ class Typero::Type
9
9
 
10
10
  ###
11
11
 
12
- def initialize(value, opts={})
12
+ def initialize value, opts={}
13
13
  @value = value
14
14
  @opts = opts
15
15
  end
16
16
 
17
17
  # default validation for any type
18
- def validate(what)
18
+ def validate
19
19
  true
20
20
  end
21
21
 
22
+ # get error from option or the default one
22
23
  def error_for name
23
24
  @opts[name] || send(name)
24
25
  end
25
26
 
26
- def get
27
- @value
28
- end
29
-
30
- def set
31
- @value
32
- end
33
-
34
27
  def default
35
28
  nil
36
29
  end
@@ -5,7 +5,10 @@ class Typero::ArrayType < Typero::Type
5
5
 
6
6
  def set
7
7
  unless @value.class.to_s.index('Array')
8
- @value = @value.to_s.sub(/^\{/,'').sub(/\}$/,'').split(/\s*,\s*/)
8
+ @value = @value.to_s.sub(/^\{/,'').sub(/\}$/,'')
9
+
10
+ # split on new line and comma by default
11
+ @value = @value.split(/\s*[,\n]\s*/)
9
12
  end
10
13
 
11
14
  @value.uniq!
@@ -40,5 +43,13 @@ class Typero::ArrayType < Typero::Type
40
43
  def value_in_list_error
41
44
  'value in list'
42
45
  end
46
+
47
+ def db_field
48
+ check = Typero::Type.load(@opts[:array_type]).new nil, {}
49
+ schema = check.db_field
50
+ schema[1] ||= {}
51
+ schema[1].merge! array: true
52
+ schema
53
+ end
43
54
  end
44
55
 
@@ -6,5 +6,11 @@ class Typero::BooleanType < Typero::Type
6
6
  def set
7
7
  @value = [true, 1, '1', 'true', 'on'].include?(@value) ? true : false
8
8
  end
9
+
10
+ def db_field
11
+ opts = {}
12
+ opts[:default] = @opts[:default] || false
13
+ [:boolean, opts]
14
+ end
9
15
  end
10
16
 
@@ -0,0 +1,17 @@
1
+ require_relative './float'
2
+
3
+ class Typero::CurrencyType < Typero::FloatType
4
+
5
+ def set
6
+ @value = @value.to_f.round(2)
7
+ end
8
+
9
+ def db_field
10
+ opts = {}
11
+ opts[:precision] = 8
12
+ opts[:scale] = 2
13
+ [:decimal, opts]
14
+ end
15
+
16
+ end
17
+
@@ -0,0 +1,6 @@
1
+ class Typero::DateType < Typero::Type
2
+ def set
3
+ @value = @value.to_s.downcase.gsub(/[^\d\-\.\s]/, '')
4
+ end
5
+ end
6
+
@@ -0,0 +1,6 @@
1
+ class Typero::DatetimeType < Typero::Type
2
+ def set
3
+ @value = @value.to_s.downcase.gsub(/[^\d\-\.\s\:]/, '')
4
+ end
5
+ end
6
+
@@ -17,5 +17,11 @@ class Typero::EmailType < Typero::Type
17
17
  'is missing @'
18
18
  end
19
19
 
20
+ def db_field
21
+ opts = {}
22
+ opts[:limit] = @opts[:max] || 120
23
+ opts[:null] = false if @opts[:req]
24
+ [:string, opts]
25
+ end
20
26
  end
21
27
 
@@ -17,5 +17,11 @@ class Typero::FloatType < Typero::Type
17
17
  "max lenght is %s"
18
18
  end
19
19
 
20
+ def db_field
21
+ opts = {}
22
+ opts[:null] = false if @opts[:req]
23
+ [:float, opts]
24
+ end
25
+
20
26
  end
21
27
 
@@ -0,0 +1,13 @@
1
+ # Posrgre geography data type
2
+ # covert google loc to field, auto fix other values
3
+
4
+ class Typero::GeographyType < Typero::Type
5
+ def default
6
+ false
7
+ end
8
+
9
+ def db_field
10
+ [:geography]
11
+ end
12
+ end
13
+
@@ -10,5 +10,9 @@ class Typero::HashType < Typero::Type
10
10
  def not_hash_type_error
11
11
  'value is not hash type'
12
12
  end
13
+
14
+ def db_field
15
+ [:jsonb, {}]
16
+ end
13
17
  end
14
18
 
@@ -15,5 +15,11 @@ class Typero::IntegerType < Typero::Type
15
15
  def max_value_error
16
16
  'max is %s, got %s'
17
17
  end
18
+
19
+ def db_field
20
+ opts = {}
21
+ opts[:null] = false if @opts[:req]
22
+ [:integer, opts]
23
+ end
18
24
  end
19
25
 
@@ -10,4 +10,11 @@ class Typero::LabelType < Typero::Type
10
10
  def unallowed_characters_error
11
11
  'label is having unallowed characters'
12
12
  end
13
+
14
+ def db_field
15
+ opts = {}
16
+ opts[:null] = false if @opts[:req]
17
+ opts[:limit] = 30
18
+ [:string, opts]
19
+ end
13
20
  end
@@ -30,5 +30,12 @@ class Typero::OibType < Typero::Type
30
30
  def not_an_oib_error
31
31
  'not in an OIB format'
32
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
33
40
  end
34
41
 
@@ -0,0 +1,25 @@
1
+ class Typero::PointType < Typero::Type
2
+ def set
3
+ if @value.present?
4
+ if @value.include?('/@')
5
+ point = @value.split('/@', 2).last.split(',')
6
+ @value = [point[0], point[1]].join(',')
7
+ end
8
+
9
+ unless @value.include?('POINT')
10
+ point = @value.sub(/,\s*/, ' ')
11
+ @value = 'SRID=4326;POINT(%s)' % point
12
+ end
13
+ end
14
+ end
15
+
16
+ def validate
17
+ raise TypeError, error_for(:unallowed_characters_error) unless @value =~ /^SRID=4326;POINT\(/
18
+ end
19
+
20
+ def db_field
21
+ [:geography, {}]
22
+ end
23
+
24
+ end
25
+
@@ -18,5 +18,12 @@ class Typero::StringType < Typero::Type
18
18
  def max_length_error
19
19
  'max lenght is %s, you have %s'
20
20
  end
21
+
22
+ def db_field
23
+ opts = {}
24
+ opts[:limit] = @opts[:max] || 255
25
+ opts[:null] = false if @opts[:req]
26
+ [:string, opts]
27
+ end
21
28
  end
22
29
 
@@ -0,0 +1,7 @@
1
+ class Typero::TextType < Typero::StringType
2
+ def db_field
3
+ opts = {}
4
+ opts[:null] = false if @opts[:req]
5
+ [:text, opts]
6
+ end
7
+ end
@@ -10,5 +10,11 @@ class Typero::UrlType < Typero::Type
10
10
  def not_starting_error
11
11
  'URL is not starting with http'
12
12
  end
13
+
14
+ def db_field
15
+ opts = {}
16
+ opts[:null] = false if @opts[:req]
17
+ [:string, opts]
18
+ end
13
19
  end
14
20
 
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.4.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dino Reic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-11 00:00:00.000000000 Z
11
+ date: 2019-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fast_blank
@@ -32,17 +32,24 @@ extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
34
  - "./.version"
35
+ - "./lib/adapters/sequel.rb"
35
36
  - "./lib/typero.rb"
36
37
  - "./lib/typero/type.rb"
37
38
  - "./lib/typero/type/array.rb"
38
39
  - "./lib/typero/type/boolean.rb"
40
+ - "./lib/typero/type/currency.rb"
41
+ - "./lib/typero/type/date.rb"
42
+ - "./lib/typero/type/datetime.rb"
39
43
  - "./lib/typero/type/email.rb"
40
44
  - "./lib/typero/type/float.rb"
45
+ - "./lib/typero/type/geography.rb"
41
46
  - "./lib/typero/type/hash.rb"
42
47
  - "./lib/typero/type/integer.rb"
43
48
  - "./lib/typero/type/label.rb"
44
49
  - "./lib/typero/type/oib.rb"
50
+ - "./lib/typero/type/point.rb"
45
51
  - "./lib/typero/type/string.rb"
52
+ - "./lib/typero/type/text.rb"
46
53
  - "./lib/typero/type/url.rb"
47
54
  homepage: https://github.com/dux/typero
48
55
  licenses:
@@ -63,8 +70,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
70
  - !ruby/object:Gem::Version
64
71
  version: '0'
65
72
  requirements: []
66
- rubyforge_project:
67
- rubygems_version: 2.7.5
73
+ rubygems_version: 3.0.3
68
74
  signing_key:
69
75
  specification_version: 4
70
76
  summary: Ruby type system