attributor 5.0.2 → 5.1.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 +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
|