typero 0.4.0 → 0.5.2

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 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