rasti-form 2.2.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +5 -5
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +7 -10
  4. data/README.md +1 -1
  5. data/lib/rasti/form.rb +34 -129
  6. data/lib/rasti/form/errors.rb +7 -47
  7. data/lib/rasti/form/validable.rb +9 -3
  8. data/rasti-form.gemspec +3 -14
  9. data/spec/coverage_helper.rb +1 -3
  10. data/spec/minitest_helper.rb +1 -7
  11. data/spec/validations_spec.rb +301 -0
  12. metadata +11 -54
  13. data/lib/rasti/form/castable.rb +0 -25
  14. data/lib/rasti/form/formatable.rb +0 -19
  15. data/lib/rasti/form/types/array.rb +0 -54
  16. data/lib/rasti/form/types/boolean.rb +0 -42
  17. data/lib/rasti/form/types/enum.rb +0 -48
  18. data/lib/rasti/form/types/float.rb +0 -33
  19. data/lib/rasti/form/types/form.rb +0 -40
  20. data/lib/rasti/form/types/hash.rb +0 -39
  21. data/lib/rasti/form/types/integer.rb +0 -21
  22. data/lib/rasti/form/types/io.rb +0 -23
  23. data/lib/rasti/form/types/regexp.rb +0 -28
  24. data/lib/rasti/form/types/string.rb +0 -23
  25. data/lib/rasti/form/types/symbol.rb +0 -23
  26. data/lib/rasti/form/types/time.rb +0 -40
  27. data/lib/rasti/form/types/uuid.rb +0 -19
  28. data/lib/rasti/form/version.rb +0 -5
  29. data/spec/form_spec.rb +0 -350
  30. data/spec/types/array_spec.rb +0 -54
  31. data/spec/types/boolean_spec.rb +0 -24
  32. data/spec/types/enum_spec.rb +0 -28
  33. data/spec/types/float_spec.rb +0 -18
  34. data/spec/types/form_spec.rb +0 -41
  35. data/spec/types/hash_spec.rb +0 -20
  36. data/spec/types/integer_spec.rb +0 -18
  37. data/spec/types/io_spec.rb +0 -18
  38. data/spec/types/regexp_spec.rb +0 -20
  39. data/spec/types/string_spec.rb +0 -16
  40. data/spec/types/symbol_spec.rb +0 -16
  41. data/spec/types/time_spec.rb +0 -25
  42. data/spec/types/uuid_spec.rb +0 -18
@@ -1,23 +0,0 @@
1
- module Rasti
2
- class Form
3
- module Types
4
- class IO
5
- class << self
6
-
7
- include Castable
8
-
9
- private
10
-
11
- def valid?(value)
12
- value.respond_to?(:read) && value.respond_to?(:write)
13
- end
14
-
15
- def transform(value)
16
- value
17
- end
18
-
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,28 +0,0 @@
1
- module Rasti
2
- class Form
3
- module Types
4
- class Regexp
5
-
6
- include Formatable
7
-
8
- def self.[](format)
9
- new format
10
- end
11
-
12
- def to_s
13
- "#{self.class}[#{format.inspect}]"
14
- end
15
- alias_method :inspect, :to_s
16
-
17
- private
18
-
19
- attr_reader :format
20
-
21
- def initialize(format)
22
- @format = format.is_a?(String) ? ::Regexp.new(format) : format
23
- end
24
-
25
- end
26
- end
27
- end
28
- end
@@ -1,23 +0,0 @@
1
- module Rasti
2
- class Form
3
- module Types
4
- class String
5
- class << self
6
-
7
- include Castable
8
-
9
- private
10
-
11
- def valid?(value)
12
- !value.nil? && value.respond_to?(:to_s)
13
- end
14
-
15
- def transform(value)
16
- value.to_s
17
- end
18
-
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,23 +0,0 @@
1
- module Rasti
2
- class Form
3
- module Types
4
- class Symbol
5
- class << self
6
-
7
- include Castable
8
-
9
- private
10
-
11
- def valid?(value)
12
- !value.nil? && (value.respond_to?(:to_sym) || value.respond_to?(:to_s))
13
- end
14
-
15
- def transform(value)
16
- value.respond_to?(:to_sym) ? value.to_sym : value.to_s.to_sym
17
- end
18
-
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,40 +0,0 @@
1
- module Rasti
2
- class Form
3
- module Types
4
- class Time
5
-
6
- include Castable
7
-
8
- attr_reader :format
9
-
10
- def self.[](format)
11
- new format
12
- end
13
-
14
- def to_s
15
- "#{self.class}['#{format}']"
16
- end
17
- alias_method :inspect, :to_s
18
-
19
- private
20
-
21
- def initialize(format)
22
- @format = format
23
- end
24
-
25
- def valid?(value)
26
- value.is_a?(::String) || value.respond_to?(:to_time)
27
- end
28
-
29
- def transform(value)
30
- value.is_a?(::String) ? string_to_time(value) : value.to_time
31
- end
32
-
33
- def string_to_time(value)
34
- ::Time.strptime(value, format)
35
- end
36
-
37
- end
38
- end
39
- end
40
- end
@@ -1,19 +0,0 @@
1
- module Rasti
2
- class Form
3
- module Types
4
- class UUID
5
- class << self
6
-
7
- include Formatable
8
-
9
- private
10
-
11
- def format
12
- /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}+$/
13
- end
14
-
15
- end
16
- end
17
- end
18
- end
19
- end
@@ -1,5 +0,0 @@
1
- module Rasti
2
- class Form
3
- VERSION = '2.2.0'
4
- end
5
- end
data/spec/form_spec.rb DELETED
@@ -1,350 +0,0 @@
1
- require 'minitest_helper'
2
-
3
- describe Rasti::Form do
4
-
5
- let(:point_class) { Rasti::Form[x: Rasti::Form::Types::Integer, y: Rasti::Form::Types::Integer] }
6
-
7
- let(:point_subclass) { Class.new point_class }
8
-
9
- def build_form(&block)
10
- Class.new(Rasti::Form) do
11
- class_eval &block
12
- end
13
- end
14
-
15
- describe 'Initialization' do
16
-
17
- it 'All attributes' do
18
- point = point_class.new x: 1, y: 2
19
- point.x.must_equal 1
20
- point.y.must_equal 2
21
- point.assigned?(:x).must_equal true
22
- point.assigned?(:y).must_equal true
23
- end
24
-
25
- it 'Some attributes' do
26
- point = point_class.new x: 1
27
- point.x.must_equal 1
28
- point.y.must_be_nil
29
- point.assigned?(:x).must_equal true
30
- point.assigned?(:y).must_equal false
31
- end
32
-
33
- it 'Whitout attributes' do
34
- point = point_class.new
35
- point.x.must_be_nil
36
- point.y.must_be_nil
37
- point.assigned?(:x).must_equal false
38
- point.assigned?(:y).must_equal false
39
- end
40
-
41
- it 'Invalid attributes' do
42
- error = proc { point_class.new z: 3 }.must_raise Rasti::Form::ValidationError
43
- error.message.must_equal 'Validation error: #<Rasti::Form[]> {"z":["unexpected attribute"]}'
44
- end
45
-
46
- describe 'Casting' do
47
-
48
- it 'Attribute' do
49
- form = build_form do
50
- attribute :text, Rasti::Form::Types::String
51
- end
52
-
53
- f = form.new text: 123
54
- f.text.must_equal "123"
55
- end
56
-
57
- it 'Nested attributes' do
58
- form = build_form do
59
- attribute :range, Rasti::Form::Types::Form[min: Rasti::Form::Types::Integer, max: Rasti::Form::Types::Integer]
60
- end
61
-
62
- f = form.new range: {min: '1', max: '10'}
63
- f.range.min.must_equal 1
64
- f.range.max.must_equal 10
65
- end
66
-
67
- it 'Nested form' do
68
- range = build_form do
69
- attribute :min, Rasti::Form::Types::Integer
70
- attribute :max, Rasti::Form::Types::Integer
71
- end
72
-
73
- form = build_form do
74
- attribute :range, Rasti::Form::Types::Form[range]
75
- end
76
-
77
- f = form.new range: {min: '1', max: '10'}
78
- f.range.min.must_equal 1
79
- f.range.max.must_equal 10
80
- end
81
-
82
- it 'Invalid attributes' do
83
- form = build_form do
84
- attribute :boolean, Rasti::Form::Types::Boolean
85
- attribute :number, Rasti::Form::Types::Integer
86
- end
87
-
88
- error = proc { form.new boolean: 'x', number: 'y' }.must_raise Rasti::Form::ValidationError
89
- error.message.must_equal 'Validation error: #<Rasti::Form[]> {"boolean":["Invalid cast: \'x\' -> Rasti::Form::Types::Boolean"],"number":["Invalid cast: \'y\' -> Rasti::Form::Types::Integer"]}'
90
- end
91
-
92
- it 'Invalid nested attributes' do
93
- form = build_form do
94
- attribute :range, Rasti::Form::Types::Form[min: Rasti::Form::Types::Integer, max: Rasti::Form::Types::Integer]
95
- end
96
-
97
- error = proc { form.new range: {min: 'x', max: 'y'} }.must_raise Rasti::Form::ValidationError
98
- error.message.must_equal "Validation error: #<Rasti::Form[]> {\"range.min\":[\"Invalid cast: 'x' -> Rasti::Form::Types::Integer\"],\"range.max\":[\"Invalid cast: 'y' -> Rasti::Form::Types::Integer\"]}"
99
- end
100
-
101
- it 'Invalid form attributes' do
102
- range = build_form do
103
- attribute :min, Rasti::Form::Types::Integer
104
- attribute :max, Rasti::Form::Types::Integer
105
- end
106
-
107
- form = build_form do
108
- attribute :range, Rasti::Form::Types::Form[range]
109
- end
110
-
111
- error = proc { form.new range: {min: 'x', max: 'y'} }.must_raise Rasti::Form::ValidationError
112
- error.message.must_equal "Validation error: #<Rasti::Form[]> {\"range.min\":[\"Invalid cast: 'x' -> Rasti::Form::Types::Integer\"],\"range.max\":[\"Invalid cast: 'y' -> Rasti::Form::Types::Integer\"]}"
113
- end
114
-
115
- end
116
-
117
- end
118
-
119
- describe 'Defaults' do
120
-
121
- it 'Value' do
122
- form = build_form do
123
- attribute :text, Rasti::Form::Types::String, default: 'xyz'
124
- end
125
-
126
- f = form.new
127
- f.text.must_equal 'xyz'
128
- end
129
-
130
- it 'Block' do
131
- form = build_form do
132
- attribute :time_1, Rasti::Form::Types::Time['%F']
133
- attribute :time_2, Rasti::Form::Types::Time['%F'], default: ->(f) { f.time_1 }
134
- end
135
-
136
- f = form.new time_1: Time.now
137
- f.time_2.must_equal f.time_1
138
- end
139
-
140
- end
141
-
142
- describe 'Validations' do
143
-
144
- it 'Required' do
145
- form = build_form do
146
- attribute :text, Rasti::Form::Types::String
147
-
148
- def validate
149
- assert_present :text
150
- end
151
- end
152
-
153
- error = proc { form.new }.must_raise Rasti::Form::ValidationError
154
- error.message.must_equal 'Validation error: #<Rasti::Form[]> {"text":["not present"]}'
155
- end
156
-
157
- it 'Not empty string' do
158
- form = build_form do
159
- attribute :text, Rasti::Form::Types::String
160
-
161
- def validate
162
- assert_not_empty :text
163
- end
164
- end
165
-
166
- error = proc { form.new text: ' ' }.must_raise Rasti::Form::ValidationError
167
- error.message.must_equal 'Validation error: #<Rasti::Form[text: " "]> {"text":["is empty"]}'
168
- end
169
-
170
- it 'Not empty array' do
171
- form = build_form do
172
- attribute :array, Rasti::Form::Types::Array[Rasti::Form::Types::String]
173
-
174
- def validate
175
- assert_not_empty :array
176
- end
177
- end
178
-
179
- error = proc { form.new array: [] }.must_raise Rasti::Form::ValidationError
180
- error.message.must_equal 'Validation error: #<Rasti::Form[array: []]> {"array":["is empty"]}'
181
- end
182
-
183
- it 'Included in values list' do
184
- form = build_form do
185
- attribute :text, Rasti::Form::Types::String
186
-
187
- def validate
188
- assert_included_in :text, %w(value_1 value_2)
189
- end
190
- end
191
-
192
- error = proc { form.new text: 'xyz' }.must_raise Rasti::Form::ValidationError
193
- error.message.must_equal 'Validation error: #<Rasti::Form[text: "xyz"]> {"text":["not included in \'value_1\', \'value_2\'"]}'
194
- end
195
-
196
- it 'Time range' do
197
- form = build_form do
198
- attribute :from, Rasti::Form::Types::Time['%Y-%m-%d %H:%M:%S %Z']
199
- attribute :to, Rasti::Form::Types::Time['%Y-%m-%d %H:%M:%S %Z']
200
-
201
- def validate
202
- assert_time_range :from, :to
203
- end
204
- end
205
-
206
- from = '2018-01-01 15:30:00 +0000'
207
- to = '2018-01-01 03:10:00 +0000'
208
-
209
- error = proc { form.new from: from, to: to }.must_raise Rasti::Form::ValidationError
210
- error.message.must_equal "Validation error: #<Rasti::Form[from: #{from}, to: #{to}]> {\"from\":[\"invalid time range\"]}"
211
- end
212
-
213
- it 'Nested form' do
214
- form = build_form do
215
- attribute :range, Rasti::Form::Types::Form[min: Rasti::Form::Types::Integer, max: Rasti::Form::Types::Integer]
216
-
217
- def validate
218
- assert_present 'range.min'
219
- assert_present 'range.max'
220
- end
221
- end
222
-
223
- error = proc { form.new }.must_raise Rasti::Form::ValidationError
224
- error.message.must_equal 'Validation error: #<Rasti::Form[]> {"range.min":["not present"],"range.max":["not present"]}'
225
- end
226
-
227
- it 'Nested validation' do
228
- range = build_form do
229
- attribute :min, Rasti::Form::Types::Integer
230
- attribute :max, Rasti::Form::Types::Integer
231
-
232
- def validate
233
- assert :min, min < max, 'Min must be less than Max' if min && max
234
- end
235
- end
236
-
237
- form = build_form do
238
- attribute :range, Rasti::Form::Types::Form[range]
239
- end
240
-
241
- error = proc { form.new range: {min: 2, max: 1} }.must_raise Rasti::Form::ValidationError
242
- error.message.must_equal 'Validation error: #<Rasti::Form[]> {"range.min":["Min must be less than Max"]}'
243
- end
244
-
245
- end
246
-
247
- describe 'Comparable' do
248
-
249
- it 'Equivalency (==)' do
250
- point_1 = point_class.new x: 1, y: 2
251
- point_2 = point_subclass.new x: 1, y: 2
252
- point_3 = point_class.new x: 2, y: 1
253
-
254
- assert point_1 == point_2
255
- refute point_1 == point_3
256
- end
257
-
258
- it 'Equality (eql?)' do
259
- point_1 = point_class.new x: 1, y: 2
260
- point_2 = point_class.new x: 1, y: 2
261
- point_3 = point_subclass.new x: 1, y: 2
262
- point_4 = point_class.new x: 2, y: 1
263
-
264
- assert point_1.eql?(point_2)
265
- refute point_1.eql?(point_3)
266
- refute point_1.eql?(point_4)
267
- end
268
-
269
- it 'hash' do
270
- point_1 = point_class.new x: 1, y: 2
271
- point_2 = point_class.new x: 1, y: 2
272
- point_3 = point_subclass.new x: 1, y: 2
273
- point_4 = point_class.new x: 2, y: 1
274
-
275
- point_1.hash.must_equal point_2.hash
276
- point_1.hash.wont_equal point_3.hash
277
- point_1.hash.wont_equal point_4.hash
278
- end
279
-
280
- end
281
-
282
- describe 'Attributes' do
283
-
284
- let :address_class do
285
- Rasti::Form[
286
- street: Rasti::Form::Types::String,
287
- number: Rasti::Form::Types::Integer
288
- ]
289
- end
290
-
291
- let :contact_class do
292
- Rasti::Form[
293
- name: Rasti::Form::Types::String,
294
- age: Rasti::Form::Types::Integer,
295
- phones: Rasti::Form::Types::Hash[Rasti::Form::Types::Symbol, Rasti::Form::Types::Integer],
296
- addresses: Rasti::Form::Types::Array[Rasti::Form::Types::Form[address_class]],
297
- hobbies: Rasti::Form::Types::Array[Rasti::Form::Types::String]
298
- ]
299
- end
300
-
301
- let :attributes do
302
- {
303
- name: 'John',
304
- age: 24,
305
- phones: {
306
- office: 1234567890,
307
- house: 456456456
308
- },
309
- addresses: [
310
- {street: 'Lexington Avenue', number: 123},
311
- {street: 'Park Avenue', number: 456}
312
- ]
313
- }
314
- end
315
-
316
- it 'All (to_h)' do
317
- contact = contact_class.new attributes
318
-
319
- contact.attributes.must_equal attributes
320
- contact.to_h.must_equal attributes
321
- end
322
-
323
- it 'Only' do
324
- contact = contact_class.new attributes
325
-
326
- contact.attributes(only: [:name, :age]).must_equal name: attributes[:name],
327
- age: attributes[:age]
328
- end
329
-
330
- it 'Except' do
331
- contact = contact_class.new attributes
332
-
333
- contact.attributes(except: [:age, :addresses]).must_equal name: attributes[:name],
334
- phones: attributes[:phones]
335
- end
336
-
337
- end
338
-
339
- it 'to_s' do
340
- point_class.to_s.must_equal 'Rasti::Form[:x, :y]'
341
- point_class.new(x: '1', y: '2').to_s.must_equal '#<Rasti::Form[x: 1, y: 2]>'
342
- end
343
-
344
- it 'Subclass' do
345
- point = point_subclass.new x: 1, y: 2
346
- point.x.must_equal 1
347
- point.y.must_equal 2
348
- end
349
-
350
- end