rasti-form 2.2.0 → 4.0.0
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 +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +7 -10
- data/README.md +1 -1
- data/lib/rasti/form.rb +34 -129
- data/lib/rasti/form/errors.rb +7 -47
- data/lib/rasti/form/validable.rb +9 -3
- data/rasti-form.gemspec +3 -14
- data/spec/coverage_helper.rb +1 -3
- data/spec/minitest_helper.rb +1 -7
- data/spec/validations_spec.rb +301 -0
- metadata +11 -54
- data/lib/rasti/form/castable.rb +0 -25
- data/lib/rasti/form/formatable.rb +0 -19
- data/lib/rasti/form/types/array.rb +0 -54
- data/lib/rasti/form/types/boolean.rb +0 -42
- data/lib/rasti/form/types/enum.rb +0 -48
- data/lib/rasti/form/types/float.rb +0 -33
- data/lib/rasti/form/types/form.rb +0 -40
- data/lib/rasti/form/types/hash.rb +0 -39
- data/lib/rasti/form/types/integer.rb +0 -21
- data/lib/rasti/form/types/io.rb +0 -23
- data/lib/rasti/form/types/regexp.rb +0 -28
- data/lib/rasti/form/types/string.rb +0 -23
- data/lib/rasti/form/types/symbol.rb +0 -23
- data/lib/rasti/form/types/time.rb +0 -40
- data/lib/rasti/form/types/uuid.rb +0 -19
- data/lib/rasti/form/version.rb +0 -5
- data/spec/form_spec.rb +0 -350
- data/spec/types/array_spec.rb +0 -54
- data/spec/types/boolean_spec.rb +0 -24
- data/spec/types/enum_spec.rb +0 -28
- data/spec/types/float_spec.rb +0 -18
- data/spec/types/form_spec.rb +0 -41
- data/spec/types/hash_spec.rb +0 -20
- data/spec/types/integer_spec.rb +0 -18
- data/spec/types/io_spec.rb +0 -18
- data/spec/types/regexp_spec.rb +0 -20
- data/spec/types/string_spec.rb +0 -16
- data/spec/types/symbol_spec.rb +0 -16
- data/spec/types/time_spec.rb +0 -25
- data/spec/types/uuid_spec.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f480a81f5d023100e579147654b5026d29f6d00d43099756ec80304e96fbd71d
|
4
|
+
data.tar.gz: 31c790f10607e20335262383955d7919d33aa6f54aa4fe0d7a9caa75c1bc973c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83aaf5a613afd59afc64486b0228226dd9122e2096cdb38f8b8faad6fb07a19c8ac427bc677cc90bb804d63d2a39cef37b05f6215658ea1867d96c8e5ddf50ef
|
7
|
+
data.tar.gz: 55ba10cfb9a398999f928c5a803ad751c32989416c1bc2a164f105d436a46fe63ff75a47893e29436ec8cf85b93a51b49f09aa94e2a6ac8481ce6b628c39e4ab
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.
|
1
|
+
ruby-2.5.7
|
data/.travis.yml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
language: ruby
|
2
2
|
|
3
3
|
rvm:
|
4
|
-
- 1.9.3
|
5
4
|
- 2.0
|
6
5
|
- 2.1
|
7
6
|
- 2.2
|
8
|
-
- 2.3
|
9
|
-
- 2.4
|
10
|
-
- 2.5
|
11
|
-
-
|
12
|
-
-
|
7
|
+
- 2.3
|
8
|
+
- 2.4
|
9
|
+
- 2.5
|
10
|
+
- 2.6
|
11
|
+
- 2.7
|
12
|
+
- jruby-9.2.9.0
|
13
13
|
- ruby-head
|
14
14
|
- jruby-head
|
15
15
|
|
@@ -17,7 +17,4 @@ matrix:
|
|
17
17
|
fast_finish: true
|
18
18
|
allow_failures:
|
19
19
|
- rvm: ruby-head
|
20
|
-
- rvm: jruby-head
|
21
|
-
|
22
|
-
before_install:
|
23
|
-
- gem install bundler
|
20
|
+
- rvm: jruby-head
|
data/README.md
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
[](https://travis-ci.org/gabynaiman/rasti-form)
|
5
5
|
[](https://coveralls.io/github/gabynaiman/rasti-form?branch=master)
|
6
6
|
[](https://codeclimate.com/github/gabynaiman/rasti-form)
|
7
|
-
[](https://gemnasium.com/gabynaiman/rasti-form)
|
8
7
|
|
9
8
|
Forms validations and type casting
|
10
9
|
|
@@ -94,6 +93,7 @@ form.to # => 2016-10-28 00:00:00 -0300
|
|
94
93
|
- Form
|
95
94
|
- Hash
|
96
95
|
- Integer
|
96
|
+
- IO
|
97
97
|
- Regexp
|
98
98
|
- String
|
99
99
|
- Symbol
|
data/lib/rasti/form.rb
CHANGED
@@ -1,167 +1,72 @@
|
|
1
|
-
require '
|
1
|
+
require 'rasti-model'
|
2
2
|
require 'multi_require'
|
3
3
|
|
4
4
|
module Rasti
|
5
|
-
class Form
|
5
|
+
class Form < Rasti::Model
|
6
6
|
|
7
7
|
extend MultiRequire
|
8
8
|
|
9
9
|
require_relative_pattern 'form/*'
|
10
|
-
require_relative_pattern 'form/types/*'
|
11
10
|
|
12
11
|
include Validable
|
13
12
|
|
14
|
-
|
13
|
+
def initialize(attributes={})
|
14
|
+
begin
|
15
|
+
super attributes
|
15
16
|
|
16
|
-
|
17
|
-
Class.new(self) do
|
18
|
-
attributes.each do |name, type, options={}|
|
19
|
-
attribute name, type, options
|
20
|
-
end
|
17
|
+
cast_attributes!
|
21
18
|
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
rescue Rasti::Model::UnexpectedAttributesError => ex
|
20
|
+
ex.attributes.each do |attr_name|
|
21
|
+
errors[attr_name] << 'unexpected attribute'
|
25
22
|
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def attribute(name, type, options={})
|
29
|
-
attributes[name.to_sym] = options.merge(type: type)
|
30
|
-
attr_reader name
|
31
|
-
end
|
32
|
-
|
33
|
-
def attributes
|
34
|
-
@attributes ||= {}
|
35
|
-
end
|
36
23
|
|
37
|
-
|
38
|
-
|
39
|
-
|
24
|
+
rescue Rasti::Types::CompoundError => ex
|
25
|
+
ex.errors.each do |key, messages|
|
26
|
+
errors[key] += messages
|
27
|
+
end
|
40
28
|
|
41
|
-
def to_s
|
42
|
-
"#{name || self.superclass.name}[#{attribute_names.map(&:inspect).join(', ')}]"
|
43
29
|
end
|
44
|
-
alias_method :inspect, :to_s
|
45
|
-
|
46
|
-
end
|
47
30
|
|
48
|
-
def initialize(attrs={})
|
49
|
-
assign_attributes attrs
|
50
|
-
set_defaults
|
51
31
|
validate!
|
52
32
|
end
|
53
33
|
|
54
|
-
def
|
55
|
-
|
56
|
-
end
|
57
|
-
alias_method :inspect, :to_s
|
58
|
-
|
59
|
-
def attributes(options={})
|
60
|
-
attributes_filter = {only: assigned_attribute_names, except: []}.merge(options)
|
61
|
-
(attributes_filter[:only] - attributes_filter[:except]).each_with_object({}) do |name, hash|
|
62
|
-
hash[name] = serialize(read_attribute(name))
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def to_h
|
67
|
-
attributes
|
68
|
-
end
|
69
|
-
|
70
|
-
def assigned?(name)
|
71
|
-
assigned_attribute_names.include? name
|
72
|
-
end
|
73
|
-
|
74
|
-
def ==(other)
|
75
|
-
other.kind_of?(self.class) && other.attributes == attributes
|
76
|
-
end
|
77
|
-
|
78
|
-
def eql?(other)
|
79
|
-
other.instance_of?(self.class) && other.attributes == attributes
|
80
|
-
end
|
81
|
-
|
82
|
-
def hash
|
83
|
-
[self.class, attributes].hash
|
34
|
+
def assigned?(attr_name)
|
35
|
+
assigned_attribute? attr_name.to_sym
|
84
36
|
end
|
85
37
|
|
86
38
|
private
|
87
39
|
|
88
|
-
def
|
89
|
-
|
90
|
-
attr_name
|
91
|
-
begin
|
92
|
-
if self.class.attributes.key? attr_name
|
93
|
-
write_attribute attr_name, value
|
94
|
-
else
|
95
|
-
errors[attr_name] << 'unexpected attribute'
|
96
|
-
end
|
97
|
-
|
98
|
-
rescue CastError => error
|
99
|
-
errors[attr_name] << error.message
|
100
|
-
|
101
|
-
rescue MultiCastError, ValidationError => error
|
102
|
-
error.errors.each do |inner_name, inner_errors|
|
103
|
-
inner_errors.each { |message| errors["#{attr_name}.#{inner_name}"] << message }
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def set_defaults
|
110
|
-
(self.class.attribute_names - attributes.keys).each do |name|
|
111
|
-
if self.class.attributes[name].key? :default
|
112
|
-
value = self.class.attributes[name][:default]
|
113
|
-
write_attribute name, value.is_a?(Proc) ? value.call(self) : value
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def assigned_attribute_names
|
119
|
-
self.class.attribute_names & instance_variables.map { |v| v.to_s[1..-1].to_sym }
|
120
|
-
end
|
121
|
-
|
122
|
-
def serialize(value)
|
123
|
-
if value.kind_of? Array
|
124
|
-
value.map { |v| serialize v }
|
125
|
-
elsif value.kind_of? Form
|
126
|
-
value.attributes
|
127
|
-
else
|
128
|
-
value
|
40
|
+
def assert_present(attr_name)
|
41
|
+
if !errors.key?(attr_name)
|
42
|
+
assert attr_name, assigned?(attr_name) && !public_send(attr_name).nil?, 'not present'
|
129
43
|
end
|
44
|
+
rescue Types::Error
|
45
|
+
assert attr_name, false, 'not present'
|
130
46
|
end
|
131
47
|
|
132
|
-
def
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
def write_attribute(name, value)
|
137
|
-
typed_value = value.nil? ? nil : self.class.attributes[name][:type].cast(value)
|
138
|
-
instance_variable_set "@#{name}", typed_value
|
48
|
+
def assert_not_present(attr_name)
|
49
|
+
assert attr_name, !assigned?(attr_name) || public_send(attr_name).nil?, 'is present'
|
50
|
+
rescue Types::Error
|
51
|
+
assert attr_name, false, 'is present'
|
139
52
|
end
|
140
53
|
|
141
|
-
def
|
142
|
-
|
143
|
-
|
54
|
+
def assert_not_empty(attr_name)
|
55
|
+
if assert_present attr_name
|
56
|
+
value = public_send attr_name
|
57
|
+
assert attr_name, value.is_a?(String) ? !value.strip.empty? : !value.empty?, 'is empty'
|
144
58
|
end
|
145
59
|
end
|
146
60
|
|
147
|
-
def
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
def assert_not_empty(attribute)
|
152
|
-
if assert_present attribute
|
153
|
-
value = fetch attribute
|
154
|
-
assert attribute, value.is_a?(String) ? !value.strip.empty? : !value.empty?, 'is empty'
|
61
|
+
def assert_included_in(attr_name, set)
|
62
|
+
if assert_present attr_name
|
63
|
+
assert attr_name, set.include?(public_send(attr_name)), "not included in #{set.map(&:inspect).join(', ')}"
|
155
64
|
end
|
156
65
|
end
|
157
66
|
|
158
|
-
def
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
def assert_included_in(attribute, set)
|
163
|
-
if assert_present attribute
|
164
|
-
assert attribute, set.include?(fetch(attribute)), "not included in #{set.map { |e| e.is_a?(::String) ? "'#{e}'" : e.inspect }.join(', ')}"
|
67
|
+
def assert_range(attr_name_from, attr_name_to)
|
68
|
+
if assert_present(attr_name_from) && assert_present(attr_name_to)
|
69
|
+
assert attr_name_from, public_send(attr_name_from) <= public_send(attr_name_to), 'invalid range'
|
165
70
|
end
|
166
71
|
end
|
167
72
|
|
data/lib/rasti/form/errors.rb
CHANGED
@@ -1,59 +1,19 @@
|
|
1
1
|
module Rasti
|
2
2
|
class Form
|
3
|
-
|
4
|
-
class CastError < StandardError
|
5
3
|
|
6
|
-
|
4
|
+
class ValidationError < Rasti::Types::CompoundError
|
7
5
|
|
8
|
-
|
9
|
-
@type = type
|
10
|
-
@value = value
|
11
|
-
end
|
12
|
-
|
13
|
-
def message
|
14
|
-
"Invalid cast: #{display_value} -> #{type}"
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def display_value
|
20
|
-
value.is_a?(::String) ? "'#{value}'" : value.inspect
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
class MultiCastError < StandardError
|
6
|
+
attr_reader :scope
|
27
7
|
|
28
|
-
attr_reader :type, :value, :errors
|
29
|
-
|
30
|
-
def initialize(type, value, errors)
|
31
|
-
@type = type
|
32
|
-
@value = value
|
33
|
-
@errors = errors
|
34
|
-
end
|
35
|
-
|
36
|
-
def message
|
37
|
-
"Invalid cast: #{display_value} -> #{type} - #{JSON.dump(errors)}"
|
38
|
-
end
|
39
|
-
|
40
|
-
def display_value
|
41
|
-
value.is_a?(::String) ? "'#{value}'" : value.inspect
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
class ValidationError < StandardError
|
47
|
-
|
48
|
-
attr_reader :scope, :errors
|
49
|
-
|
50
8
|
def initialize(scope, errors)
|
51
9
|
@scope = scope
|
52
|
-
|
10
|
+
super errors
|
53
11
|
end
|
54
12
|
|
55
|
-
|
56
|
-
|
13
|
+
private
|
14
|
+
|
15
|
+
def message_title
|
16
|
+
'Validation errors:'
|
57
17
|
end
|
58
18
|
|
59
19
|
end
|
data/lib/rasti/form/validable.rb
CHANGED
@@ -17,9 +17,15 @@ module Rasti
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def assert(key, condition, message)
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
errors[key] << message unless condition
|
21
|
+
condition
|
22
|
+
end
|
23
|
+
|
24
|
+
def assert_not_error(key)
|
25
|
+
yield
|
26
|
+
true
|
27
|
+
rescue => ex
|
28
|
+
errors[key] << ex.message
|
23
29
|
false
|
24
30
|
end
|
25
31
|
|
data/rasti-form.gemspec
CHANGED
@@ -1,11 +1,6 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'rasti/form/version'
|
5
|
-
|
6
1
|
Gem::Specification.new do |spec|
|
7
2
|
spec.name = 'rasti-form'
|
8
|
-
spec.version =
|
3
|
+
spec.version = '4.0.0'
|
9
4
|
spec.authors = ['Gabriel Naiman']
|
10
5
|
spec.email = ['gabynaiman@gmail.com']
|
11
6
|
spec.summary = 'Forms validations and type casting'
|
@@ -19,19 +14,13 @@ Gem::Specification.new do |spec|
|
|
19
14
|
spec.require_paths = ['lib']
|
20
15
|
|
21
16
|
spec.add_runtime_dependency 'multi_require', '~> 1.0'
|
17
|
+
spec.add_runtime_dependency 'rasti-model', '~> 1.0'
|
22
18
|
|
23
|
-
spec.add_development_dependency '
|
24
|
-
spec.add_development_dependency 'rake', '~> 11.0'
|
19
|
+
spec.add_development_dependency 'rake', '~> 12.0'
|
25
20
|
spec.add_development_dependency 'minitest', '~> 5.0', '< 5.11'
|
26
21
|
spec.add_development_dependency 'minitest-colorin', '~> 0.1'
|
27
22
|
spec.add_development_dependency 'minitest-line', '~> 0.6'
|
28
23
|
spec.add_development_dependency 'simplecov', '~> 0.12'
|
29
24
|
spec.add_development_dependency 'coveralls', '~> 0.8'
|
30
25
|
spec.add_development_dependency 'pry-nav', '~> 0.2'
|
31
|
-
|
32
|
-
if RUBY_VERSION < '2'
|
33
|
-
spec.add_development_dependency 'term-ansicolor', '~> 1.3.0'
|
34
|
-
spec.add_development_dependency 'tins', '~> 1.6.0'
|
35
|
-
spec.add_development_dependency 'json', '~> 1.8'
|
36
|
-
end
|
37
26
|
end
|
data/spec/coverage_helper.rb
CHANGED
data/spec/minitest_helper.rb
CHANGED
@@ -0,0 +1,301 @@
|
|
1
|
+
require 'minitest_helper'
|
2
|
+
|
3
|
+
describe Rasti::Form, 'Validations' do
|
4
|
+
|
5
|
+
def build_form(&block)
|
6
|
+
Class.new(Rasti::Form) do
|
7
|
+
class_eval(&block)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def assert_validation_error(expected_errors, &block)
|
12
|
+
error = proc { block.call }.must_raise Rasti::Form::ValidationError
|
13
|
+
error.errors.must_equal expected_errors
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'Validation error message' do
|
17
|
+
scope = Object.new
|
18
|
+
errors = {
|
19
|
+
x: ['not present'],
|
20
|
+
y: ['error 1', 'error 2']
|
21
|
+
}
|
22
|
+
|
23
|
+
error = Rasti::Form::ValidationError.new scope, errors
|
24
|
+
|
25
|
+
error.scope.must_equal scope
|
26
|
+
error.errors.must_equal errors
|
27
|
+
error.message.must_equal "Validation errors:\n- x: [\"not present\"]\n- y: [\"error 1\", \"error 2\"]"
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'Invalid attributes' do
|
31
|
+
assert_validation_error(z: ['unexpected attribute']) do
|
32
|
+
Rasti::Form[:x, :y].new z: 3
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'Not error' do
|
37
|
+
form = build_form do
|
38
|
+
attribute :text, T::String
|
39
|
+
|
40
|
+
def validate
|
41
|
+
assert_not_error :text do
|
42
|
+
raise 'invalid text' unless assigned? :text
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
proc { form.new text: 'text' }.must_be_silent
|
48
|
+
|
49
|
+
assert_validation_error(text: ['invalid text']) do
|
50
|
+
form.new
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'Present' do
|
55
|
+
|
56
|
+
let :form do
|
57
|
+
build_form do
|
58
|
+
attribute :number, T::Integer
|
59
|
+
|
60
|
+
def validate
|
61
|
+
assert_present :number
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'Success' do
|
67
|
+
proc { form.new number: 1 }.must_be_silent
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'Not assigned' do
|
71
|
+
assert_validation_error(number: ['not present']) do
|
72
|
+
form.new
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'Nil' do
|
77
|
+
assert_validation_error(number: ['not present']) do
|
78
|
+
form.new number: nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'Invalid cast' do
|
83
|
+
assert_validation_error(number: ['Invalid cast: true -> Rasti::Types::Integer']) do
|
84
|
+
form.new number: true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'Invalid nested cast' do
|
89
|
+
range = build_form do
|
90
|
+
attribute :min, T::Integer
|
91
|
+
attribute :max, T::Integer
|
92
|
+
|
93
|
+
def validate
|
94
|
+
assert_range :min, :max
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
form = build_form do
|
99
|
+
attribute :range, T::Model[range]
|
100
|
+
|
101
|
+
def validate
|
102
|
+
assert_present :range
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
assert_validation_error('range.max' => ['not present'], range: ['not present']) do
|
107
|
+
form.new range: {min: 1}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'With default' do
|
112
|
+
form = build_form do
|
113
|
+
attribute :number, T::Integer, default: 1
|
114
|
+
|
115
|
+
def validate
|
116
|
+
assert_present :number
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
proc { form.new }.must_be_silent
|
121
|
+
|
122
|
+
assert_validation_error(number: ['not present']) do
|
123
|
+
form.new number: nil
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
describe 'Not present' do
|
130
|
+
|
131
|
+
let :form do
|
132
|
+
range = build_form do
|
133
|
+
attribute :min, T::Integer
|
134
|
+
attribute :max, T::Integer
|
135
|
+
|
136
|
+
def validate
|
137
|
+
assert_range :min, :max
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
build_form do
|
142
|
+
attribute :range, T::Model[range]
|
143
|
+
|
144
|
+
def validate
|
145
|
+
assert_not_present :range
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'Success not assigned' do
|
151
|
+
proc { form.new }.must_be_silent
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'Success with nil' do
|
155
|
+
proc { form.new range: nil }.must_be_silent
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'Assigned' do
|
159
|
+
assert_validation_error(range: ['is present']) do
|
160
|
+
form.new range: {min: 1, max: 2}
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'Invalid nested cast' do
|
165
|
+
assert_validation_error('range.max' => ['not present'], range: ['is present']) do
|
166
|
+
form.new range: {min: 1}
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
describe 'Not empty' do
|
173
|
+
|
174
|
+
it 'Must be present' do
|
175
|
+
form = build_form do
|
176
|
+
attribute :text, T::String
|
177
|
+
|
178
|
+
def validate
|
179
|
+
assert_not_empty :text
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
proc { form.new text: 'text' }.must_be_silent
|
184
|
+
|
185
|
+
assert_validation_error(text: ['not present']) do
|
186
|
+
form.new text: nil
|
187
|
+
end
|
188
|
+
|
189
|
+
assert_validation_error(text: ['not present']) do
|
190
|
+
form.new
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'String' do
|
195
|
+
form = build_form do
|
196
|
+
attribute :text, T::String
|
197
|
+
|
198
|
+
def validate
|
199
|
+
assert_not_empty :text
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
proc { form.new text: 'text' }.must_be_silent
|
204
|
+
|
205
|
+
assert_validation_error(text: ['is empty']) do
|
206
|
+
form.new text: ' '
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'Array' do
|
211
|
+
form = build_form do
|
212
|
+
attribute :array, T::Array[T::String]
|
213
|
+
|
214
|
+
def validate
|
215
|
+
assert_not_empty :array
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
proc { form.new array: ['text'] }.must_be_silent
|
220
|
+
|
221
|
+
assert_validation_error(array: ['is empty']) do
|
222
|
+
form.new array: []
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'Hash' do
|
227
|
+
form = build_form do
|
228
|
+
attribute :hash, T::Hash[T::String, T::String]
|
229
|
+
|
230
|
+
def validate
|
231
|
+
assert_not_empty :hash
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
proc { form.new hash: {key: 'value'} }.must_be_silent
|
236
|
+
|
237
|
+
assert_validation_error(hash: ['is empty']) do
|
238
|
+
form.new hash: {}
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'Included in values list' do
|
245
|
+
form = build_form do
|
246
|
+
attribute :text, T::String
|
247
|
+
|
248
|
+
def validate
|
249
|
+
assert_included_in :text, %w(value_1 value_2)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
proc { form.new text: 'value_1' }.must_be_silent
|
254
|
+
|
255
|
+
assert_validation_error(text: ['not included in "value_1", "value_2"']) do
|
256
|
+
form.new text: 'xyz'
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'Time range' do
|
261
|
+
form = build_form do
|
262
|
+
attribute :from, T::Time['%Y-%m-%d %H:%M:%S']
|
263
|
+
attribute :to, T::Time['%Y-%m-%d %H:%M:%S']
|
264
|
+
|
265
|
+
def validate
|
266
|
+
assert_range :from, :to
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
from = '2018-01-01 03:10:00'
|
271
|
+
to = '2018-01-01 15:30:00'
|
272
|
+
|
273
|
+
proc { form.new from: from, to: to }.must_be_silent
|
274
|
+
|
275
|
+
assert_validation_error(from: ['invalid range']) do
|
276
|
+
form.new from: to, to: from
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'Nested validation' do
|
281
|
+
range = build_form do
|
282
|
+
attribute :min, T::Integer
|
283
|
+
attribute :max, T::Integer
|
284
|
+
|
285
|
+
def validate
|
286
|
+
assert_range :min, :max
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
form = build_form do
|
291
|
+
attribute :range, T::Model[range]
|
292
|
+
end
|
293
|
+
|
294
|
+
proc { form.new range: {min: 1, max: 2} }.must_be_silent
|
295
|
+
|
296
|
+
assert_validation_error('range.min' => ['invalid range']) do
|
297
|
+
form.new range: {min: 2, max: 1}
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
end
|