parameters_schema 0.42
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 +7 -0
- data/Gemfile +4 -0
- data/README.md +286 -0
- data/Rakefile +8 -0
- data/lib/parameters_schema/core_ext.rb +21 -0
- data/lib/parameters_schema/exceptions.rb +23 -0
- data/lib/parameters_schema/options.rb +80 -0
- data/lib/parameters_schema/schema.rb +296 -0
- data/lib/parameters_schema.rb +8 -0
- data/test/helpers.rb +56 -0
- data/test/test_options.rb +74 -0
- data/test/test_schema_allow.rb +114 -0
- data/test/test_schema_allow_empty.rb +30 -0
- data/test/test_schema_allow_nil.rb +34 -0
- data/test/test_schema_hash.rb +90 -0
- data/test/test_schema_required.rb +74 -0
- data/test/test_schema_simple.rb +58 -0
- data/test/test_schema_types.rb +452 -0
- data/test/test_schema_types_complex.rb +126 -0
- metadata +77 -0
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'active_support/core_ext/object/try'
|
4
|
+
require 'date'
|
5
|
+
require 'parameters_schema/core_ext'
|
6
|
+
require 'parameters_schema/options'
|
7
|
+
require 'parameters_schema/exceptions'
|
8
|
+
require 'parameters_schema/schema'
|
data/test/helpers.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module ActiveSupport
|
2
|
+
class HashWithIndifferentAccess < Hash
|
3
|
+
def must_equal_hash(other)
|
4
|
+
self.must_equal(other.with_indifferent_access)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module ParametersSchema
|
10
|
+
class Schema
|
11
|
+
def must_allow(values)
|
12
|
+
[values].flatten.each do |value|
|
13
|
+
if value.kind_of?(Range)
|
14
|
+
value.each do |v|
|
15
|
+
execute_must_allow(v)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
execute_must_allow(value)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def must_deny(values, error_code = ParametersSchema::ErrorCode::DISALLOWED)
|
26
|
+
[values].flatten.each do |value|
|
27
|
+
if value.kind_of?(Range)
|
28
|
+
value.each do |v|
|
29
|
+
execute_must_deny(v, error_code)
|
30
|
+
end
|
31
|
+
else
|
32
|
+
execute_must_deny(value, error_code)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def execute_must_allow(value)
|
42
|
+
self
|
43
|
+
.validate!(potatoe: value)
|
44
|
+
.must_equal_hash(potatoe: value)
|
45
|
+
end
|
46
|
+
|
47
|
+
def execute_must_deny(value, error_code)
|
48
|
+
Proc.new do
|
49
|
+
self
|
50
|
+
.validate!(potatoe: value)
|
51
|
+
end
|
52
|
+
.must_raise(ParametersSchema::InvalidParameters)
|
53
|
+
.errors.must_equal_hash(potatoe: error_code)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'parameters_schema'
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
describe 'Skipping parameters' do
|
6
|
+
before do
|
7
|
+
ParametersSchema::Options.reset_defaults
|
8
|
+
|
9
|
+
@schema = ParametersSchema::Schema.new do
|
10
|
+
param :potatoe
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'skip default parameters in a Rails context' do
|
15
|
+
@schema
|
16
|
+
.validate!(potatoe: 'Ac Belmont', controller: 'potatoes', action: 'create', format: 'json')
|
17
|
+
.must_equal_hash(potatoe: 'Ac Belmont')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'redefines parameters to skip' do
|
21
|
+
ParametersSchema::Options.skip_parameters = [:banana]
|
22
|
+
|
23
|
+
@schema
|
24
|
+
.validate!(potatoe: 'Ac Belmont', banana: 'Cavendish')
|
25
|
+
.must_equal_hash(potatoe: 'Ac Belmont')
|
26
|
+
|
27
|
+
Proc
|
28
|
+
.new{ @schema.validate!(potatoe: 'Ac Belmont', controller: 'potatoes', action: 'create', format: 'json') }
|
29
|
+
.must_raise(ParametersSchema::InvalidParameters)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'augments parameters to skip' do
|
33
|
+
ParametersSchema::Options.skip_parameters = ParametersSchema::Options.skip_parameters + [:banana]
|
34
|
+
@schema
|
35
|
+
.validate!(potatoe: 'Ac Belmont', banana: 'Cavendish', controller: 'potatoes', action: 'create', format: 'json')
|
36
|
+
.must_equal_hash(potatoe: 'Ac Belmont')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'Empty keyword' do
|
41
|
+
before do
|
42
|
+
ParametersSchema::Options.reset_defaults
|
43
|
+
|
44
|
+
@schema = ParametersSchema::Schema.new do
|
45
|
+
param :potatoe, allow: :empty
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'uses the default value' do
|
50
|
+
ParametersSchema::Schema.new do
|
51
|
+
param :potatoe, allow: :empty
|
52
|
+
end
|
53
|
+
.validate!(potatoe: '')
|
54
|
+
.must_equal_hash(potatoe: '')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'redefines the value' do
|
58
|
+
ParametersSchema::Options.empty_keyword = :allow_empty
|
59
|
+
|
60
|
+
ParametersSchema::Schema.new do
|
61
|
+
param :potatoe, allow: :allow_empty
|
62
|
+
end
|
63
|
+
.validate!(potatoe: '')
|
64
|
+
.must_equal_hash(potatoe: '')
|
65
|
+
|
66
|
+
Proc.new do
|
67
|
+
ParametersSchema::Schema.new do
|
68
|
+
param :potatoe, allow: :empty
|
69
|
+
end.validate!(potatoe: '')
|
70
|
+
end
|
71
|
+
.must_raise(ParametersSchema::InvalidParameters)
|
72
|
+
.errors.must_equal_hash(potatoe: ParametersSchema::ErrorCode::EMPTY)
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'parameters_schema'
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
describe 'Allow and Deny' do
|
6
|
+
before do
|
7
|
+
ParametersSchema::Options.reset_defaults
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'allows :any and denies :none by default' do
|
11
|
+
[{}, { allow: :any }, { deny: :none }, { allow: :any, deny: :none }].each do |options|
|
12
|
+
schema = ParametersSchema::Schema.new do
|
13
|
+
param :potatoe, options.merge(type: Fixnum)
|
14
|
+
end
|
15
|
+
.must_allow((-10..10))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'allows multiple :allow values' do
|
20
|
+
schema = ParametersSchema::Schema.new do
|
21
|
+
param :potatoe, type: Fixnum, allow: [(1..2), (4..5)]
|
22
|
+
end
|
23
|
+
.must_allow([1, 2, 4, 5])
|
24
|
+
.must_deny(3)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'allows multiple :deny values' do
|
28
|
+
schema = ParametersSchema::Schema.new do
|
29
|
+
param :potatoe, type: Fixnum, deny: [(1..2), (4..5)]
|
30
|
+
end
|
31
|
+
.must_allow([-1, 0, 3, 6, 7])
|
32
|
+
.must_deny([1, 2, 4, 5])
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'gives priority to :any and :none in multiple :allow values' do
|
36
|
+
schema = ParametersSchema::Schema.new do
|
37
|
+
param :potatoe, type: Fixnum, allow: [(1..2), :any]
|
38
|
+
end
|
39
|
+
.must_allow((-10..10))
|
40
|
+
|
41
|
+
schema = ParametersSchema::Schema.new do
|
42
|
+
param :potatoe, type: Fixnum, allow: [(1..2), :none]
|
43
|
+
end
|
44
|
+
.must_deny((-10..10))
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'gives priority to :any and :none in multiple :deny values' do
|
48
|
+
schema = ParametersSchema::Schema.new do
|
49
|
+
param :potatoe, type: Fixnum, deny: [(1..2), :none]
|
50
|
+
end
|
51
|
+
.must_allow((-10..10))
|
52
|
+
|
53
|
+
schema = ParametersSchema::Schema.new do
|
54
|
+
param :potatoe, type: Fixnum, deny: [(1..2), :any]
|
55
|
+
end
|
56
|
+
.must_deny((-10..10))
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'when using an array, the :allow is applied on the array values' do
|
60
|
+
schema = ParametersSchema::Schema.new do
|
61
|
+
param :potatoe, type: Fixnum, array: true, allow: (1..3)
|
62
|
+
end
|
63
|
+
|
64
|
+
schema
|
65
|
+
.validate!(potatoe: [1, 2, 3, 2, 1])
|
66
|
+
.must_equal_hash(potatoe: [1, 2, 3, 2, 1])
|
67
|
+
|
68
|
+
Proc.new do
|
69
|
+
schema.validate!(potatoe: [1, 2, 3, 2, 1, 0])
|
70
|
+
end
|
71
|
+
.must_raise(ParametersSchema::InvalidParameters)
|
72
|
+
.errors.must_equal_hash(potatoe: ParametersSchema::ErrorCode::DISALLOWED)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'when using an array, the :deny is applied on the array values' do
|
76
|
+
schema = ParametersSchema::Schema.new do
|
77
|
+
param :potatoe, type: Fixnum, array: true, deny: (1..3)
|
78
|
+
end
|
79
|
+
|
80
|
+
schema
|
81
|
+
.validate!(potatoe: [-1, 0, 4, 5, 6])
|
82
|
+
.must_equal_hash(potatoe: [-1, 0, 4, 5, 6])
|
83
|
+
|
84
|
+
Proc.new do
|
85
|
+
schema.validate!(potatoe: [-1, 0, 4, 5, 6, 1])
|
86
|
+
end
|
87
|
+
.must_raise(ParametersSchema::InvalidParameters)
|
88
|
+
.errors.must_equal_hash(potatoe: ParametersSchema::ErrorCode::DISALLOWED)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'allows a subset of values defined by a range' do
|
92
|
+
schema = ParametersSchema::Schema.new do
|
93
|
+
param :potatoe, type: Fixnum, allow: (1..10)
|
94
|
+
end
|
95
|
+
.must_allow((1..10))
|
96
|
+
.must_deny(((-10..0).to_a + (11..20).to_a))
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'allows a subset of values by choices' do
|
100
|
+
schema = ParametersSchema::Schema.new do
|
101
|
+
param :potatoe, allow: ['a', 'b', 'c']
|
102
|
+
end
|
103
|
+
.must_allow(['a', 'b', 'c'])
|
104
|
+
.must_deny('d')
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'allows a subset of values by regex' do
|
108
|
+
schema = ParametersSchema::Schema.new do
|
109
|
+
param :potatoe, allow: /^[A-Z]+$/
|
110
|
+
end
|
111
|
+
.must_allow(['A', 'BB', 'CDE'])
|
112
|
+
.must_deny(['a', 'Aa', 'F1'])
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'parameters_schema'
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
describe 'Allow empty' do
|
6
|
+
before do
|
7
|
+
ParametersSchema::Options.reset_defaults
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'requires a non-empty value by default' do
|
11
|
+
ParametersSchema::Schema.new do
|
12
|
+
param :potatoe
|
13
|
+
end
|
14
|
+
.must_deny('', ParametersSchema::ErrorCode::EMPTY)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can be set to accept empty value' do
|
18
|
+
ParametersSchema::Schema.new do
|
19
|
+
param :potatoe, allow: :empty
|
20
|
+
end
|
21
|
+
.must_allow('')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'when set to accept empty, it still reject nil value' do
|
25
|
+
ParametersSchema::Schema.new do
|
26
|
+
param :potatoe, allow: :empty
|
27
|
+
end
|
28
|
+
.must_deny(nil, ParametersSchema::ErrorCode::NIL)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'parameters_schema'
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
describe 'Allow nil' do
|
6
|
+
before do
|
7
|
+
ParametersSchema::Options.reset_defaults
|
8
|
+
|
9
|
+
@schema = ParametersSchema::Schema.new do
|
10
|
+
param :potatoe
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'requires a non-nil value by default' do
|
15
|
+
ParametersSchema::Schema.new do
|
16
|
+
param :potatoe
|
17
|
+
end
|
18
|
+
.must_deny(nil, ParametersSchema::ErrorCode::NIL)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'can be set to accept nil' do
|
22
|
+
ParametersSchema::Schema.new do
|
23
|
+
param :potatoe, allow: :nil
|
24
|
+
end
|
25
|
+
.must_allow(nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'when set to accept nil, it still reject empty value' do
|
29
|
+
ParametersSchema::Schema.new do
|
30
|
+
param :potatoe, allow: :nil
|
31
|
+
end
|
32
|
+
.must_deny('', ParametersSchema::ErrorCode::EMPTY)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'parameters_schema'
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
describe 'Object' do
|
6
|
+
it 'creates a sub-schema for objects' do
|
7
|
+
ParametersSchema::Schema.new do
|
8
|
+
param :potatoe do
|
9
|
+
param :name
|
10
|
+
end
|
11
|
+
end
|
12
|
+
.must_allow({ name: 'Eramosa' })
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'creates a as many sub-schemas as needed' do
|
16
|
+
schema = ParametersSchema::Schema.new do
|
17
|
+
param :potatoe do
|
18
|
+
param :quantity, type: Fixnum
|
19
|
+
param :description do
|
20
|
+
param :name
|
21
|
+
param :local, type: :boolean
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
schema
|
27
|
+
.validate!(potatoe: { quantity: '10', description: { name: 'Eramosa', local: 't' } })
|
28
|
+
.must_equal_hash(potatoe: { quantity: 10, description: { name: 'Eramosa', local: true } })
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'allows an empty sub-schema' do
|
32
|
+
schema = ParametersSchema::Schema.new do
|
33
|
+
param :potatoe do end
|
34
|
+
end
|
35
|
+
.must_deny(nil, ParametersSchema::ErrorCode::NIL)
|
36
|
+
.must_deny({}, ParametersSchema::ErrorCode::EMPTY)
|
37
|
+
|
38
|
+
Proc
|
39
|
+
.new{ schema.validate!(potatoe: { name: 'Eramosa' }) }
|
40
|
+
.must_raise(ParametersSchema::InvalidParameters)
|
41
|
+
.errors.must_equal_hash(potatoe: { name: ParametersSchema::ErrorCode::UNKNOWN })
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'can be embeded in array' do
|
45
|
+
[{ array: true}, type: { Array => Hash }].each do |array_format|
|
46
|
+
schema = ParametersSchema::Schema.new do
|
47
|
+
param :potatoes, array_format do
|
48
|
+
param :name
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
schema
|
53
|
+
.validate!(potatoes: [{ name: 'Ac Belmont' }, { name: 'Eramosa' }])
|
54
|
+
.must_equal_hash(potatoes: [{ name: 'Ac Belmont' }, { name: 'Eramosa' }])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'can be embeded in array - complex' do
|
59
|
+
schema = ParametersSchema::Schema.new do
|
60
|
+
param :potatoes, array: true do
|
61
|
+
param :quantity, type: Fixnum
|
62
|
+
param :description do
|
63
|
+
param :name
|
64
|
+
param :local, type: :boolean
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
potatoes = [
|
70
|
+
{
|
71
|
+
quantity: 10,
|
72
|
+
description: {
|
73
|
+
name: 'Eramosa',
|
74
|
+
local: true
|
75
|
+
}
|
76
|
+
},
|
77
|
+
{
|
78
|
+
quantity: 1000,
|
79
|
+
description: {
|
80
|
+
name: 'Eramosa II',
|
81
|
+
local: false
|
82
|
+
}
|
83
|
+
}
|
84
|
+
]
|
85
|
+
|
86
|
+
schema
|
87
|
+
.validate!(potatoes: potatoes)
|
88
|
+
.must_equal_hash(potatoes: potatoes)
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'parameters_schema'
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
describe 'Required' do
|
6
|
+
before do
|
7
|
+
ParametersSchema::Options.reset_defaults
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'is required by default' do
|
11
|
+
Proc.new do
|
12
|
+
ParametersSchema::Schema.new do
|
13
|
+
param :potatoe
|
14
|
+
end.validate!({})
|
15
|
+
end
|
16
|
+
.must_raise(ParametersSchema::InvalidParameters)
|
17
|
+
.errors.must_equal_hash(potatoe: ParametersSchema::ErrorCode::MISSING)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'can be explicitly stated as required' do
|
21
|
+
Proc.new do
|
22
|
+
ParametersSchema::Schema.new do
|
23
|
+
param :potatoe, required: true
|
24
|
+
end.validate!({})
|
25
|
+
end
|
26
|
+
.must_raise(ParametersSchema::InvalidParameters)
|
27
|
+
.errors.must_equal_hash(potatoe: ParametersSchema::ErrorCode::MISSING)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'can be set to be not required' do
|
31
|
+
ParametersSchema::Schema.new do
|
32
|
+
param :potatoe, required: false
|
33
|
+
end
|
34
|
+
.validate!({})
|
35
|
+
.must_equal_hash({})
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'applies to object params - validation successful' do
|
39
|
+
ParametersSchema::Schema.new do
|
40
|
+
param :potatoe do
|
41
|
+
param :name
|
42
|
+
param :type, required: false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
.validate!(potatoe: { name: 'Eramosa' })
|
46
|
+
.must_equal_hash(potatoe: { name: 'Eramosa' })
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'applies to object params - validation failed on name' do
|
50
|
+
Proc.new do
|
51
|
+
ParametersSchema::Schema.new do
|
52
|
+
param :potatoe do
|
53
|
+
param :name
|
54
|
+
param :type, required: false
|
55
|
+
end
|
56
|
+
end.validate!(potatoe: {})
|
57
|
+
end
|
58
|
+
.must_raise(ParametersSchema::InvalidParameters)
|
59
|
+
.errors.must_equal_hash(potatoe: { name: ParametersSchema::ErrorCode::MISSING })
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'applies to object params - validation failed on potatoe' do
|
63
|
+
Proc.new do
|
64
|
+
ParametersSchema::Schema.new do
|
65
|
+
param :potatoe do
|
66
|
+
param :name
|
67
|
+
param :type, required: false
|
68
|
+
end
|
69
|
+
end.validate!({})
|
70
|
+
end
|
71
|
+
.must_raise(ParametersSchema::InvalidParameters)
|
72
|
+
.errors.must_equal_hash(potatoe: ParametersSchema::ErrorCode::MISSING)
|
73
|
+
end
|
74
|
+
end
|