attributor 5.0.2 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +30 -0
- data/.travis.yml +6 -4
- data/CHANGELOG.md +6 -1
- data/Gemfile +1 -1
- data/Guardfile +14 -8
- data/Rakefile +4 -5
- data/attributor.gemspec +34 -29
- data/lib/attributor.rb +23 -29
- data/lib/attributor/attribute.rb +108 -127
- data/lib/attributor/attribute_resolver.rb +12 -26
- data/lib/attributor/dsl_compiler.rb +17 -21
- data/lib/attributor/dumpable.rb +1 -2
- data/lib/attributor/example_mixin.rb +5 -8
- data/lib/attributor/exceptions.rb +5 -6
- data/lib/attributor/extensions/randexp.rb +3 -5
- data/lib/attributor/extras/field_selector.rb +4 -4
- data/lib/attributor/extras/field_selector/transformer.rb +6 -7
- data/lib/attributor/families/numeric.rb +0 -2
- data/lib/attributor/families/temporal.rb +1 -4
- data/lib/attributor/hash_dsl_compiler.rb +22 -25
- data/lib/attributor/type.rb +24 -32
- data/lib/attributor/types/bigdecimal.rb +7 -14
- data/lib/attributor/types/boolean.rb +5 -8
- data/lib/attributor/types/class.rb +9 -10
- data/lib/attributor/types/collection.rb +34 -44
- data/lib/attributor/types/container.rb +9 -15
- data/lib/attributor/types/csv.rb +7 -10
- data/lib/attributor/types/date.rb +20 -25
- data/lib/attributor/types/date_time.rb +7 -14
- data/lib/attributor/types/float.rb +4 -6
- data/lib/attributor/types/hash.rb +171 -196
- data/lib/attributor/types/ids.rb +2 -6
- data/lib/attributor/types/integer.rb +12 -17
- data/lib/attributor/types/model.rb +39 -48
- data/lib/attributor/types/object.rb +2 -4
- data/lib/attributor/types/polymorphic.rb +118 -0
- data/lib/attributor/types/regexp.rb +4 -5
- data/lib/attributor/types/string.rb +6 -7
- data/lib/attributor/types/struct.rb +8 -15
- data/lib/attributor/types/symbol.rb +3 -6
- data/lib/attributor/types/tempfile.rb +5 -6
- data/lib/attributor/types/time.rb +11 -11
- data/lib/attributor/types/uri.rb +9 -10
- data/lib/attributor/version.rb +1 -1
- data/spec/attribute_resolver_spec.rb +57 -78
- data/spec/attribute_spec.rb +174 -216
- data/spec/attributor_spec.rb +11 -15
- data/spec/dsl_compiler_spec.rb +19 -33
- data/spec/dumpable_spec.rb +6 -7
- data/spec/extras/field_selector/field_selector_spec.rb +1 -1
- data/spec/families_spec.rb +1 -3
- data/spec/hash_dsl_compiler_spec.rb +65 -74
- data/spec/spec_helper.rb +9 -3
- data/spec/support/hashes.rb +2 -3
- data/spec/support/models.rb +30 -36
- data/spec/support/polymorphics.rb +10 -0
- data/spec/type_spec.rb +38 -61
- data/spec/types/bigdecimal_spec.rb +11 -15
- data/spec/types/boolean_spec.rb +12 -39
- data/spec/types/class_spec.rb +10 -11
- data/spec/types/collection_spec.rb +72 -81
- data/spec/types/container_spec.rb +22 -26
- data/spec/types/csv_spec.rb +15 -16
- data/spec/types/date_spec.rb +16 -33
- data/spec/types/date_time_spec.rb +16 -33
- data/spec/types/file_upload_spec.rb +1 -2
- data/spec/types/float_spec.rb +7 -14
- data/spec/types/hash_spec.rb +285 -289
- data/spec/types/ids_spec.rb +5 -7
- data/spec/types/integer_spec.rb +37 -46
- data/spec/types/model_spec.rb +111 -128
- data/spec/types/polymorphic_spec.rb +134 -0
- data/spec/types/regexp_spec.rb +4 -7
- data/spec/types/string_spec.rb +17 -21
- data/spec/types/struct_spec.rb +40 -47
- data/spec/types/tempfile_spec.rb +1 -2
- data/spec/types/temporal_spec.rb +9 -0
- data/spec/types/time_spec.rb +16 -32
- data/spec/types/type_spec.rb +15 -0
- data/spec/types/uri_spec.rb +6 -7
- metadata +77 -25
data/spec/attributor_spec.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
2
|
|
3
|
-
|
4
3
|
describe Attributor do
|
5
4
|
context '.resolve_type' do
|
6
5
|
context 'given valid types' do
|
@@ -12,12 +11,12 @@ describe Attributor do
|
|
12
11
|
::Attributor::DateTime => Attributor::DateTime,
|
13
12
|
# FIXME: Boolean doesn't exist in Ruby, thus this causes and error
|
14
13
|
# https://github.com/rightscale/attributor/issues/25
|
15
|
-
#Boolean => Attributor::Boolean,
|
14
|
+
# Boolean => Attributor::Boolean,
|
16
15
|
Attributor::Boolean => Attributor::Boolean,
|
17
16
|
Attributor::Struct => Attributor::Struct
|
18
17
|
}.each do |type, expected_type|
|
19
18
|
it "resolves #{type} as #{expected_type}" do
|
20
|
-
Attributor.resolve_type(type).
|
19
|
+
expect(Attributor.resolve_type(type)).to eq expected_type
|
21
20
|
end
|
22
21
|
end
|
23
22
|
end
|
@@ -29,35 +28,32 @@ describe Attributor do
|
|
29
28
|
subject(:humanized) { Attributor.humanize_context(context) }
|
30
29
|
|
31
30
|
context 'with string value' do
|
32
|
-
let(:context) { 'some-context'}
|
33
|
-
it { should eq('some-context')}
|
31
|
+
let(:context) { 'some-context' }
|
32
|
+
it { should eq('some-context') }
|
34
33
|
end
|
35
34
|
|
36
35
|
context 'with array value' do
|
37
|
-
let(:context) {
|
36
|
+
let(:context) { %w(a b) }
|
38
37
|
it { should eq('a.b') }
|
39
38
|
end
|
40
|
-
|
41
39
|
end
|
42
40
|
|
43
|
-
|
44
41
|
context '.type_name' do
|
45
42
|
it 'accepts arbtirary classes' do
|
46
|
-
Attributor.type_name(File).
|
43
|
+
expect(Attributor.type_name(File)).to eq 'File'
|
47
44
|
end
|
48
45
|
|
49
46
|
it 'accepts instances' do
|
50
|
-
Attributor.type_name('a string').
|
47
|
+
expect(Attributor.type_name('a string')).to eq 'String'
|
51
48
|
end
|
52
49
|
|
53
50
|
it 'accepts instances of anonymous types' do
|
54
|
-
type = Class.new(Attributor::Struct)
|
55
|
-
Attributor.type_name(type).
|
51
|
+
type = Class.new(Attributor::Struct)
|
52
|
+
expect(Attributor.type_name(type)).to eq 'Attributor::Struct'
|
56
53
|
end
|
57
54
|
|
58
55
|
it 'accepts Attributor types' do
|
59
|
-
Attributor.type_name(Attributor::String).
|
56
|
+
expect(Attributor.type_name(Attributor::String)).to eq 'Attributor::String'
|
60
57
|
end
|
61
|
-
|
62
58
|
end
|
63
|
-
end
|
59
|
+
end
|
data/spec/dsl_compiler_spec.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
2
|
|
3
|
-
|
4
3
|
describe Attributor::DSLCompiler do
|
5
|
-
|
6
|
-
let(:target) { double("model", attributes: {}) }
|
4
|
+
let(:target) { double('model', attributes: {}) }
|
7
5
|
|
8
6
|
let(:dsl_compiler_options) { {} }
|
9
7
|
subject(:dsl_compiler) { Attributor::DSLCompiler.new(target, dsl_compiler_options) }
|
@@ -14,7 +12,7 @@ describe Attributor::DSLCompiler do
|
|
14
12
|
let!(:reference_attributes) { Turducken.attributes }
|
15
13
|
let(:reference_type) { reference_attribute.type }
|
16
14
|
let(:reference_attribute_options) { reference_attribute.options }
|
17
|
-
let(:reference_attribute) {reference_attributes[attribute_name] }
|
15
|
+
let(:reference_attribute) { reference_attributes[attribute_name] }
|
18
16
|
|
19
17
|
context '#attribute' do
|
20
18
|
let(:attribute_options) { {} }
|
@@ -25,44 +23,40 @@ describe Attributor::DSLCompiler do
|
|
25
23
|
context 'when not not given a block for a sub-definition' do
|
26
24
|
context 'without a reference' do
|
27
25
|
it 'raises an error for a missing type' do
|
28
|
-
expect
|
26
|
+
expect do
|
29
27
|
dsl_compiler.attribute(attribute_name)
|
30
|
-
|
31
|
-
|
28
|
+
end.to raise_error(/type for attribute/)
|
32
29
|
end
|
33
30
|
|
34
31
|
it 'creates an attribute given a name and type' do
|
35
|
-
Attributor::Attribute.
|
32
|
+
expect(Attributor::Attribute).to receive(:new).with(expected_type, expected_options)
|
36
33
|
dsl_compiler.attribute(attribute_name, type)
|
37
34
|
end
|
38
35
|
|
39
|
-
|
40
36
|
it 'creates an attribute given a name, type, and options' do
|
41
|
-
Attributor::Attribute.
|
37
|
+
expect(Attributor::Attribute).to receive(:new).with(expected_type, expected_options)
|
42
38
|
dsl_compiler.attribute(attribute_name, type, attribute_options)
|
43
39
|
end
|
44
|
-
|
45
40
|
end
|
46
41
|
|
47
|
-
|
48
42
|
context 'with a reference' do
|
49
|
-
let(:dsl_compiler_options) { {:
|
43
|
+
let(:dsl_compiler_options) { { reference: Turducken } }
|
50
44
|
|
51
45
|
context 'with no options' do
|
52
46
|
let(:expected_options) { reference_attribute_options }
|
53
47
|
|
54
48
|
it 'creates an attribute with the inherited type' do
|
55
|
-
Attributor::Attribute.
|
49
|
+
expect(Attributor::Attribute).to receive(:new).with(expected_type, expected_options)
|
56
50
|
dsl_compiler.attribute(attribute_name)
|
57
51
|
end
|
58
52
|
end
|
59
53
|
|
60
54
|
context 'with options' do
|
61
|
-
let(:attribute_options) { {:
|
55
|
+
let(:attribute_options) { { description: 'some new description', required: true } }
|
62
56
|
let(:expected_options) { reference_attribute_options.merge(attribute_options) }
|
63
57
|
|
64
58
|
before do
|
65
|
-
Attributor::Attribute.
|
59
|
+
expect(Attributor::Attribute).to receive(:new).with(expected_type, expected_options)
|
66
60
|
end
|
67
61
|
|
68
62
|
it 'creates an attribute with the inherited type and merged options' do
|
@@ -72,7 +66,6 @@ describe Attributor::DSLCompiler do
|
|
72
66
|
it 'accepts explicit nil type' do
|
73
67
|
dsl_compiler.attribute(attribute_name, nil, attribute_options)
|
74
68
|
end
|
75
|
-
|
76
69
|
end
|
77
70
|
|
78
71
|
context 'for a referenced Model attribute' do
|
@@ -81,50 +74,43 @@ describe Attributor::DSLCompiler do
|
|
81
74
|
let(:expected_options) { reference_attribute_options.merge(attribute_options) }
|
82
75
|
|
83
76
|
it 'creates an attribute with the inherited type' do
|
84
|
-
Attributor::Attribute.
|
77
|
+
expect(Attributor::Attribute).to receive(:new).with(expected_type, expected_options)
|
85
78
|
dsl_compiler.attribute(attribute_name)
|
86
79
|
end
|
87
80
|
end
|
88
|
-
|
89
81
|
end
|
90
|
-
|
91
82
|
end
|
92
83
|
|
93
|
-
|
94
84
|
context 'when given a block for sub-attributes' do
|
95
|
-
let(:attribute_block) {
|
85
|
+
let(:attribute_block) { proc {} }
|
96
86
|
let(:attribute_name) { :turkey }
|
97
87
|
let(:type) { Attributor::Struct }
|
98
88
|
let(:expected_type) { Attributor::Struct }
|
99
89
|
|
100
90
|
context 'without a reference' do
|
101
91
|
it 'defaults type to Struct' do
|
102
|
-
Attributor::Attribute.
|
92
|
+
expect(Attributor::Attribute).to receive(:new).with(expected_type, expected_options)
|
103
93
|
dsl_compiler.attribute(attribute_name, &attribute_block)
|
104
94
|
end
|
105
95
|
end
|
106
96
|
|
107
97
|
context 'with a reference' do
|
108
|
-
let(:dsl_compiler_options) { {:
|
98
|
+
let(:dsl_compiler_options) { { reference: Turducken } }
|
109
99
|
let(:expected_options) do
|
110
|
-
attribute_options.merge(:
|
100
|
+
attribute_options.merge(reference: reference_type)
|
111
101
|
end
|
112
102
|
|
113
103
|
it 'sets the type of the attribute to Struct' do
|
114
|
-
Attributor::Attribute.
|
115
|
-
with(expected_type,
|
104
|
+
expect(Attributor::Attribute).to receive(:new)
|
105
|
+
.with(expected_type, description: 'The turkey', reference: Turkey)
|
116
106
|
dsl_compiler.attribute(attribute_name, attribute_options, &attribute_block)
|
117
107
|
end
|
118
108
|
|
119
109
|
it 'passes the correct reference to the created attribute' do
|
120
|
-
Attributor::Attribute.
|
121
|
-
dsl_compiler.attribute(attribute_name, type,
|
110
|
+
expect(Attributor::Attribute).to receive(:new).with(expected_type, expected_options)
|
111
|
+
dsl_compiler.attribute(attribute_name, type, attribute_options, &attribute_block)
|
122
112
|
end
|
123
|
-
|
124
113
|
end
|
125
|
-
|
126
114
|
end
|
127
|
-
|
128
115
|
end
|
129
|
-
|
130
116
|
end
|
data/spec/dumpable_spec.rb
CHANGED
@@ -1,30 +1,29 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
2
|
|
3
3
|
describe 'Dumpable' do
|
4
|
-
|
5
4
|
context 'for classes forgetting to implement #dump' do
|
6
|
-
let(:type)
|
5
|
+
let(:type) do
|
7
6
|
Class.new do
|
8
7
|
include Attributor::Dumpable
|
9
8
|
end
|
10
|
-
|
9
|
+
end
|
11
10
|
|
12
11
|
it 'gets an exception' do
|
13
|
-
expect{ type.new.dump }.to raise_exception(NotImplementedError)
|
12
|
+
expect { type.new.dump }.to raise_exception(NotImplementedError)
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
17
16
|
context 'for classes properly implementing #dump' do
|
18
|
-
let(:type)
|
17
|
+
let(:type) do
|
19
18
|
Class.new do
|
20
19
|
include Attributor::Dumpable
|
21
20
|
def dump
|
22
21
|
end
|
23
22
|
end
|
24
|
-
|
23
|
+
end
|
25
24
|
|
26
25
|
it 'do not get the base exception' do
|
27
|
-
expect{ type.new.dump }.to_not
|
26
|
+
expect { type.new.dump }.to_not raise_error
|
28
27
|
end
|
29
28
|
end
|
30
29
|
end
|
data/spec/families_spec.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
2
|
|
3
3
|
describe 'Type families' do
|
4
|
-
|
5
4
|
let(:types) { ObjectSpace.each_object(Class).select { |k| k < Attributor::Type } }
|
6
5
|
|
7
6
|
it 'are set on all types' do
|
8
7
|
types.each do |type|
|
9
8
|
next if type == Attributor::Object # object has no set family
|
10
|
-
type.
|
9
|
+
expect(type).not_to be_in_family('attributor')
|
11
10
|
end
|
12
11
|
end
|
13
|
-
|
14
12
|
end
|
@@ -1,176 +1,167 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
2
|
|
3
|
-
|
4
3
|
describe Attributor::HashDSLCompiler do
|
5
|
-
|
6
|
-
let(:target) { double("model", attributes: {}) }
|
4
|
+
let(:target) { double('model', attributes: {}) }
|
7
5
|
|
8
6
|
let(:dsl_compiler_options) { {} }
|
9
7
|
subject(:dsl_compiler) { Attributor::HashDSLCompiler.new(target, dsl_compiler_options) }
|
10
8
|
|
11
9
|
it 'returns the requirements DSL attached to the right target' do
|
12
10
|
req_dsl = dsl_compiler._requirements_dsl
|
13
|
-
req_dsl.
|
14
|
-
req_dsl.target.
|
11
|
+
expect(req_dsl).to be_kind_of(Attributor::HashDSLCompiler::RequiresDSL)
|
12
|
+
expect(req_dsl.target).to be(target)
|
15
13
|
end
|
16
14
|
|
17
15
|
context 'requires' do
|
18
|
-
|
19
16
|
context 'without any arguments' do
|
20
17
|
it 'without params returns the underlying compiler to chain internal methods' do
|
21
|
-
subject.requires.
|
18
|
+
expect(subject.requires).to be_kind_of(Attributor::HashDSLCompiler::RequiresDSL)
|
22
19
|
end
|
23
20
|
end
|
24
21
|
|
25
22
|
context 'with params only (and some options)' do
|
26
23
|
it 'takes then array to mean all attributes are required' do
|
27
|
-
target.
|
28
|
-
requirement = subject.requires :one, :two
|
29
|
-
requirement.
|
30
|
-
requirement.type.
|
24
|
+
expect(target).to receive(:add_requirement)
|
25
|
+
requirement = subject.requires :one, :two, description: 'These are very required'
|
26
|
+
expect(requirement).to be_kind_of(Attributor::HashDSLCompiler::Requirement)
|
27
|
+
expect(requirement.type).to be(:all)
|
31
28
|
end
|
32
29
|
end
|
33
30
|
context 'with a block only (and some options)' do
|
34
31
|
it 'evals it in the context of the Compiler' do
|
35
|
-
proc =
|
32
|
+
proc = proc {}
|
36
33
|
dsl = dsl_compiler._requirements_dsl
|
37
|
-
dsl.
|
38
|
-
subject.requires description:
|
34
|
+
expect(dsl).to receive(:instance_eval) # .with(&proc) << Does rspec 2.99 support block args?
|
35
|
+
subject.requires description: 'These are very required', &proc
|
39
36
|
end
|
40
37
|
end
|
41
|
-
|
42
|
-
|
43
38
|
end
|
44
39
|
|
45
40
|
context 'RequiresDSL' do
|
46
|
-
|
47
|
-
subject(:dsl){ Attributor::HashDSLCompiler::RequiresDSL.new(target) }
|
41
|
+
subject(:dsl) { Attributor::HashDSLCompiler::RequiresDSL.new(target) }
|
48
42
|
it 'stores the received target' do
|
49
|
-
subject.target.
|
43
|
+
expect(subject.target).to be(target)
|
50
44
|
end
|
51
45
|
|
52
46
|
context 'has DSL methods' do
|
53
|
-
let(:req){ double(
|
54
|
-
let(:attr_names){ [:one, :two, :tree] }
|
55
|
-
let(:number){ 2 }
|
56
|
-
let(:req_class){ Attributor::HashDSLCompiler::Requirement }
|
47
|
+
let(:req) { double('requirement') }
|
48
|
+
let(:attr_names) { [:one, :two, :tree] }
|
49
|
+
let(:number) { 2 }
|
50
|
+
let(:req_class) { Attributor::HashDSLCompiler::Requirement }
|
57
51
|
before do
|
58
|
-
target.
|
52
|
+
expect(target).to receive(:add_requirement).with(req)
|
59
53
|
end
|
60
54
|
it 'responds to .all' do
|
61
|
-
req_class.
|
55
|
+
expect(req_class).to receive(:new).with(all: attr_names).and_return(req)
|
62
56
|
subject.all(*attr_names)
|
63
57
|
end
|
64
58
|
it 'responds to .at_most(n)' do
|
65
|
-
req_class.
|
59
|
+
expect(req_class).to receive(:new).with(at_most: number).and_return(req)
|
66
60
|
subject.at_most(number)
|
67
61
|
end
|
68
62
|
it 'responds to .at_least(n)' do
|
69
|
-
req_class.
|
63
|
+
expect(req_class).to receive(:new).with(at_least: number).and_return(req)
|
70
64
|
subject.at_least(number)
|
71
65
|
end
|
72
66
|
it 'responds to .exactly(n)' do
|
73
|
-
req_class.
|
67
|
+
expect(req_class).to receive(:new).with(exactly: number).and_return(req)
|
74
68
|
subject.exactly(number)
|
75
69
|
end
|
76
70
|
it 'responds to .exclusive' do
|
77
|
-
req_class.
|
71
|
+
expect(req_class).to receive(:new).with(exclusive: attr_names).and_return(req)
|
78
72
|
subject.exclusive(*attr_names)
|
79
73
|
end
|
80
|
-
|
81
74
|
end
|
82
75
|
end
|
83
76
|
|
84
77
|
context 'Requirement' do
|
85
|
-
|
86
|
-
let(:
|
87
|
-
let(:req_class){ Attributor::HashDSLCompiler::Requirement }
|
78
|
+
let(:attr_names) { [:one, :two, :tree] }
|
79
|
+
let(:req_class) { Attributor::HashDSLCompiler::Requirement }
|
88
80
|
|
89
81
|
context 'initialization' do
|
90
82
|
it 'calls .of for exclusive' do
|
91
|
-
req_class.
|
83
|
+
expect_any_instance_of(req_class).to receive(:of).with(*attr_names)
|
92
84
|
req_class.new(exclusive: attr_names)
|
93
85
|
end
|
94
86
|
it 'calls .of for all' do
|
95
|
-
req_class.
|
87
|
+
expect_any_instance_of(req_class).to receive(:of).with(*attr_names)
|
96
88
|
req_class.new(all: attr_names)
|
97
89
|
end
|
98
90
|
it 'saves the number for the rest' do
|
99
|
-
req_class.new(exactly: 1).number.
|
100
|
-
req_class.new(exactly: 1).type.
|
101
|
-
req_class.new(at_most: 2).number.
|
102
|
-
req_class.new(at_most: 2).type.
|
103
|
-
req_class.new(at_least: 3).number.
|
104
|
-
req_class.new(at_least: 3).type.
|
91
|
+
expect(req_class.new(exactly: 1).number).to be(1)
|
92
|
+
expect(req_class.new(exactly: 1).type).to be(:exactly)
|
93
|
+
expect(req_class.new(at_most: 2).number).to be(2)
|
94
|
+
expect(req_class.new(at_most: 2).type).to be(:at_most)
|
95
|
+
expect(req_class.new(at_least: 3).number).to be(3)
|
96
|
+
expect(req_class.new(at_least: 3).type).to be(:at_least)
|
105
97
|
end
|
106
98
|
it 'understands and saves a :description' do
|
107
|
-
req = req_class.new(exactly: 1, description:
|
108
|
-
req.number.
|
109
|
-
req.description.
|
99
|
+
req = req_class.new(exactly: 1, description: 'Hello')
|
100
|
+
expect(req.number).to be(1)
|
101
|
+
expect(req.description).to eq('Hello')
|
110
102
|
end
|
111
103
|
end
|
112
104
|
|
113
105
|
context 'Requirement#validate' do
|
114
|
-
let(:requirement){ req_class.new(arguments) }
|
115
|
-
let(:subject){ requirement.validate(value,[
|
106
|
+
let(:requirement) { req_class.new(arguments) }
|
107
|
+
let(:subject) { requirement.validate(value, ['$'], nil) }
|
116
108
|
|
117
109
|
context 'for :all' do
|
118
|
-
let(:arguments){ { all: [:one, :two, :three] } }
|
119
|
-
let(:value){ [:one] }
|
120
|
-
let(:validation_error){ [
|
121
|
-
it { subject.
|
110
|
+
let(:arguments) { { all: [:one, :two, :three] } }
|
111
|
+
let(:value) { [:one] }
|
112
|
+
let(:validation_error) { ['Key two is required for $.', 'Key three is required for $.'] }
|
113
|
+
it { expect(subject).to include(*validation_error) }
|
122
114
|
end
|
123
115
|
context 'for :exactly' do
|
124
|
-
let(:requirement) { req_class.new(exactly: 1).of(:one
|
125
|
-
let(:value){ [:one, :two] }
|
126
|
-
let(:validation_error){
|
127
|
-
it { subject.
|
116
|
+
let(:requirement) { req_class.new(exactly: 1).of(:one, :two) }
|
117
|
+
let(:value) { [:one, :two] }
|
118
|
+
let(:validation_error) { 'Exactly 1 of the following keys [:one, :two] are required for $. Found 2 instead: [:one, :two]' }
|
119
|
+
it { expect(subject).to include(validation_error) }
|
128
120
|
end
|
129
121
|
context 'for :at_least' do
|
130
|
-
let(:requirement) { req_class.new(at_least: 2).of(:one
|
131
|
-
let(:value){ [:one] }
|
132
|
-
let(:validation_error){
|
133
|
-
it { subject.
|
122
|
+
let(:requirement) { req_class.new(at_least: 2).of(:one, :two, :three) }
|
123
|
+
let(:value) { [:one] }
|
124
|
+
let(:validation_error) { 'At least 2 keys out of [:one, :two, :three] are required to be passed in for $. Found [:one]' }
|
125
|
+
it { expect(subject).to include(validation_error) }
|
134
126
|
end
|
135
127
|
context 'for :at_most' do
|
136
|
-
let(:requirement) { req_class.new(at_most: 1).of(:one
|
137
|
-
let(:value){ [:one, :two] }
|
138
|
-
let(:validation_error){
|
139
|
-
it { subject.
|
128
|
+
let(:requirement) { req_class.new(at_most: 1).of(:one, :two, :three) }
|
129
|
+
let(:value) { [:one, :two] }
|
130
|
+
let(:validation_error) { 'At most 1 keys out of [:one, :two, :three] can be passed in for $. Found [:one, :two]' }
|
131
|
+
it { expect(subject).to include(validation_error) }
|
140
132
|
end
|
141
133
|
context 'for :exclusive' do
|
142
|
-
let(:arguments){ { exclusive: [:one, :two] } }
|
143
|
-
let(:value){ [:one, :two] }
|
144
|
-
let(:validation_error){
|
145
|
-
it { subject.
|
134
|
+
let(:arguments) { { exclusive: [:one, :two] } }
|
135
|
+
let(:value) { [:one, :two] }
|
136
|
+
let(:validation_error) { 'keys [:one, :two] are mutually exclusive for $.' }
|
137
|
+
it { expect(subject).to include(validation_error) }
|
146
138
|
end
|
147
139
|
end
|
148
140
|
|
149
141
|
context 'Requirement#describe' do
|
150
|
-
|
151
142
|
it 'should work for :all' do
|
152
143
|
req = req_class.new(all: attr_names).describe
|
153
|
-
req.
|
144
|
+
expect(req).to eq(type: :all, attributes: [:one, :two, :tree])
|
154
145
|
end
|
155
146
|
it 'should work for :exclusive n' do
|
156
147
|
req = req_class.new(exclusive: attr_names).describe
|
157
|
-
req.
|
148
|
+
expect(req).to eq(type: :exclusive, attributes: [:one, :two, :tree])
|
158
149
|
end
|
159
150
|
it 'should work for :exactly' do
|
160
151
|
req = req_class.new(exactly: 1).of(*attr_names).describe
|
161
|
-
req.
|
152
|
+
expect(req).to include(type: :exactly, count: 1, attributes: [:one, :two, :tree])
|
162
153
|
end
|
163
154
|
it 'should work for :at_most n' do
|
164
155
|
req = req_class.new(at_most: 1).of(*attr_names).describe
|
165
|
-
req.
|
156
|
+
expect(req).to include(type: :at_most, count: 1, attributes: [:one, :two, :tree])
|
166
157
|
end
|
167
158
|
it 'should work for :at_least n' do
|
168
159
|
req = req_class.new(at_least: 1).of(*attr_names).describe
|
169
|
-
req.
|
160
|
+
expect(req).to include(type: :at_least, count: 1, attributes: [:one, :two, :tree])
|
170
161
|
end
|
171
162
|
it 'should report a description' do
|
172
|
-
req = req_class.new(at_least: 1, description:
|
173
|
-
req.
|
163
|
+
req = req_class.new(at_least: 1, description: 'no more than 1').of(*attr_names).describe
|
164
|
+
expect(req).to include(type: :at_least, count: 1, attributes: [:one, :two, :tree], description: 'no more than 1')
|
174
165
|
end
|
175
166
|
end
|
176
167
|
end
|