virtus2 2.0.1
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/.gitignore +39 -0
- data/.rspec +2 -0
- data/.yardopts +1 -0
- data/CONTRIBUTING.md +18 -0
- data/Changelog.md +258 -0
- data/Gemfile +10 -0
- data/Guardfile +19 -0
- data/LICENSE +20 -0
- data/README.md +630 -0
- data/Rakefile +15 -0
- data/TODO.md +6 -0
- data/lib/virtus/attribute/accessor.rb +103 -0
- data/lib/virtus/attribute/boolean.rb +55 -0
- data/lib/virtus/attribute/builder.rb +182 -0
- data/lib/virtus/attribute/coercer.rb +45 -0
- data/lib/virtus/attribute/coercible.rb +20 -0
- data/lib/virtus/attribute/collection.rb +103 -0
- data/lib/virtus/attribute/default_value/from_callable.rb +35 -0
- data/lib/virtus/attribute/default_value/from_clonable.rb +35 -0
- data/lib/virtus/attribute/default_value/from_symbol.rb +35 -0
- data/lib/virtus/attribute/default_value.rb +51 -0
- data/lib/virtus/attribute/embedded_value.rb +67 -0
- data/lib/virtus/attribute/enum.rb +45 -0
- data/lib/virtus/attribute/hash.rb +130 -0
- data/lib/virtus/attribute/lazy_default.rb +18 -0
- data/lib/virtus/attribute/nullify_blank.rb +24 -0
- data/lib/virtus/attribute/strict.rb +26 -0
- data/lib/virtus/attribute.rb +245 -0
- data/lib/virtus/attribute_set.rb +240 -0
- data/lib/virtus/builder/hook_context.rb +51 -0
- data/lib/virtus/builder.rb +133 -0
- data/lib/virtus/class_inclusions.rb +48 -0
- data/lib/virtus/class_methods.rb +90 -0
- data/lib/virtus/coercer.rb +41 -0
- data/lib/virtus/configuration.rb +72 -0
- data/lib/virtus/const_missing_extensions.rb +18 -0
- data/lib/virtus/extensions.rb +105 -0
- data/lib/virtus/instance_methods.rb +218 -0
- data/lib/virtus/model.rb +68 -0
- data/lib/virtus/module_extensions.rb +88 -0
- data/lib/virtus/support/equalizer.rb +128 -0
- data/lib/virtus/support/options.rb +113 -0
- data/lib/virtus/support/type_lookup.rb +109 -0
- data/lib/virtus/value_object.rb +150 -0
- data/lib/virtus/version.rb +3 -0
- data/lib/virtus.rb +310 -0
- data/spec/integration/attributes_attribute_spec.rb +28 -0
- data/spec/integration/building_module_spec.rb +90 -0
- data/spec/integration/collection_member_coercion_spec.rb +96 -0
- data/spec/integration/custom_attributes_spec.rb +42 -0
- data/spec/integration/custom_collection_attributes_spec.rb +101 -0
- data/spec/integration/default_values_spec.rb +87 -0
- data/spec/integration/defining_attributes_spec.rb +86 -0
- data/spec/integration/embedded_value_spec.rb +50 -0
- data/spec/integration/extending_objects_spec.rb +35 -0
- data/spec/integration/hash_attributes_coercion_spec.rb +54 -0
- data/spec/integration/inheritance_spec.rb +42 -0
- data/spec/integration/injectible_coercers_spec.rb +48 -0
- data/spec/integration/mass_assignment_with_accessors_spec.rb +44 -0
- data/spec/integration/overriding_virtus_spec.rb +46 -0
- data/spec/integration/required_attributes_spec.rb +25 -0
- data/spec/integration/struct_as_embedded_value_spec.rb +28 -0
- data/spec/integration/using_modules_spec.rb +55 -0
- data/spec/integration/value_object_with_custom_constructor_spec.rb +42 -0
- data/spec/integration/virtus/instance_level_attributes_spec.rb +23 -0
- data/spec/integration/virtus/value_object_spec.rb +99 -0
- data/spec/shared/constants_helpers.rb +9 -0
- data/spec/shared/freeze_method_behavior.rb +40 -0
- data/spec/shared/idempotent_method_behaviour.rb +5 -0
- data/spec/shared/options_class_method.rb +19 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/unit/virtus/attribute/boolean/coerce_spec.rb +43 -0
- data/spec/unit/virtus/attribute/boolean/value_coerced_predicate_spec.rb +25 -0
- data/spec/unit/virtus/attribute/class_methods/build_spec.rb +180 -0
- data/spec/unit/virtus/attribute/class_methods/coerce_spec.rb +32 -0
- data/spec/unit/virtus/attribute/coerce_spec.rb +129 -0
- data/spec/unit/virtus/attribute/coercible_predicate_spec.rb +20 -0
- data/spec/unit/virtus/attribute/collection/class_methods/build_spec.rb +105 -0
- data/spec/unit/virtus/attribute/collection/coerce_spec.rb +74 -0
- data/spec/unit/virtus/attribute/collection/value_coerced_predicate_spec.rb +31 -0
- data/spec/unit/virtus/attribute/comparison_spec.rb +20 -0
- data/spec/unit/virtus/attribute/custom_collection_spec.rb +29 -0
- data/spec/unit/virtus/attribute/defined_spec.rb +20 -0
- data/spec/unit/virtus/attribute/embedded_value/class_methods/build_spec.rb +70 -0
- data/spec/unit/virtus/attribute/embedded_value/coerce_spec.rb +91 -0
- data/spec/unit/virtus/attribute/get_spec.rb +32 -0
- data/spec/unit/virtus/attribute/hash/class_methods/build_spec.rb +106 -0
- data/spec/unit/virtus/attribute/hash/coerce_spec.rb +92 -0
- data/spec/unit/virtus/attribute/lazy_predicate_spec.rb +20 -0
- data/spec/unit/virtus/attribute/rename_spec.rb +16 -0
- data/spec/unit/virtus/attribute/required_predicate_spec.rb +19 -0
- data/spec/unit/virtus/attribute/set_default_value_spec.rb +107 -0
- data/spec/unit/virtus/attribute/set_spec.rb +29 -0
- data/spec/unit/virtus/attribute/value_coerced_predicate_spec.rb +19 -0
- data/spec/unit/virtus/attribute_set/append_spec.rb +47 -0
- data/spec/unit/virtus/attribute_set/define_reader_method_spec.rb +36 -0
- data/spec/unit/virtus/attribute_set/define_writer_method_spec.rb +36 -0
- data/spec/unit/virtus/attribute_set/each_spec.rb +65 -0
- data/spec/unit/virtus/attribute_set/element_reference_spec.rb +17 -0
- data/spec/unit/virtus/attribute_set/element_set_spec.rb +64 -0
- data/spec/unit/virtus/attribute_set/merge_spec.rb +34 -0
- data/spec/unit/virtus/attribute_set/reset_spec.rb +71 -0
- data/spec/unit/virtus/attribute_spec.rb +229 -0
- data/spec/unit/virtus/attributes_reader_spec.rb +41 -0
- data/spec/unit/virtus/attributes_writer_spec.rb +51 -0
- data/spec/unit/virtus/class_methods/finalize_spec.rb +67 -0
- data/spec/unit/virtus/class_methods/new_spec.rb +39 -0
- data/spec/unit/virtus/config_spec.rb +13 -0
- data/spec/unit/virtus/element_reader_spec.rb +21 -0
- data/spec/unit/virtus/element_writer_spec.rb +19 -0
- data/spec/unit/virtus/freeze_spec.rb +41 -0
- data/spec/unit/virtus/model_spec.rb +197 -0
- data/spec/unit/virtus/module_spec.rb +174 -0
- data/spec/unit/virtus/set_default_attributes_spec.rb +32 -0
- data/spec/unit/virtus/value_object_spec.rb +138 -0
- data/virtus2.gemspec +26 -0
- metadata +225 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
shared_examples_for 'a #freeze method' do
|
2
|
+
let(:sample_exception) do
|
3
|
+
begin
|
4
|
+
object.dup.freeze.instance_variable_set(:@foo, :bar)
|
5
|
+
rescue => exception
|
6
|
+
exception
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:expected_exception_class) do
|
11
|
+
# Ruby 1.8 blows up with TypeError Ruby 1.9 with RuntimeError
|
12
|
+
sample_exception.class
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:expected_exception_message) do
|
16
|
+
# Ruby 1.8 blows up with a different message than Ruby 1.9
|
17
|
+
sample_exception.message
|
18
|
+
end
|
19
|
+
|
20
|
+
it_should_behave_like 'an idempotent method'
|
21
|
+
|
22
|
+
it 'returns object' do
|
23
|
+
is_expected.to be(object)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'prevents future modifications' do
|
27
|
+
subject
|
28
|
+
expectation = raise_error(expected_exception_class,expected_exception_message)
|
29
|
+
expect { object.instance_variable_set(:@foo, :bar) }.to(expectation)
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#frozen?' do
|
33
|
+
subject { super().frozen? }
|
34
|
+
it { is_expected.to be(true) }
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'allows to access attribute' do
|
38
|
+
expect(subject.name).to eql('John')
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
shared_examples_for 'an options class method' do
|
2
|
+
context 'with no argument' do
|
3
|
+
subject { object.send(method) }
|
4
|
+
|
5
|
+
it { is_expected.to be(default) }
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'with a default value' do
|
9
|
+
subject { object.send(method, value) }
|
10
|
+
|
11
|
+
let(:value) { mock('value') }
|
12
|
+
|
13
|
+
it { is_expected.to equal(object) }
|
14
|
+
|
15
|
+
it 'sets the default value for the class method' do
|
16
|
+
expect { subject }.to change { object.send(method) }.from(default).to(value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
if RUBY_ENGINE == 'ruby' && RUBY_VERSION >= '3.0'
|
2
|
+
require 'simplecov'
|
3
|
+
SimpleCov.start
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'rspec'
|
7
|
+
require 'bogus/rspec'
|
8
|
+
require 'virtus'
|
9
|
+
|
10
|
+
module Virtus
|
11
|
+
def self.warn(*)
|
12
|
+
# shut up in tests
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ENV['TZ'] = 'UTC'
|
17
|
+
|
18
|
+
# require spec support files and shared behavior
|
19
|
+
Dir[File.expand_path('../shared/**/*.rb', __FILE__)].each { |file| require file }
|
20
|
+
|
21
|
+
RSpec.configure do |config|
|
22
|
+
# Remove anonymous- and example- Attribute classes from Attribute descendants
|
23
|
+
config.after :all do
|
24
|
+
stack = [ Virtus::Attribute ]
|
25
|
+
while klass = stack.pop
|
26
|
+
klass.descendants.delete_if do |descendant|
|
27
|
+
descendant.name.nil? || descendant.name.empty? || descendant.name.start_with?('Examples::')
|
28
|
+
end
|
29
|
+
stack.concat(klass.descendants)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Remove constants in the Example-Module
|
34
|
+
config.after :each do
|
35
|
+
if defined?(Examples)
|
36
|
+
Examples.constants.each do |const_name|
|
37
|
+
ConstantsHelpers.undef_constant(Examples, const_name)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute::Boolean, '#coerce' do
|
4
|
+
subject { object.coerce(input) }
|
5
|
+
|
6
|
+
let(:object) { described_class.build('Boolean', options) }
|
7
|
+
let(:options) { {} }
|
8
|
+
|
9
|
+
context 'when strict is turned off' do
|
10
|
+
context 'with a truthy value' do
|
11
|
+
let(:input) { 1 }
|
12
|
+
|
13
|
+
it { is_expected.to be(true) }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with a falsy value' do
|
17
|
+
let(:input) { 0 }
|
18
|
+
|
19
|
+
it { is_expected.to be(false) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when strict is turned on' do
|
24
|
+
let(:options) { { :strict => true } }
|
25
|
+
|
26
|
+
context 'with a coercible input' do
|
27
|
+
let(:input) { 1 }
|
28
|
+
|
29
|
+
it { is_expected.to be(true) }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with a non-coercible input' do
|
33
|
+
let(:input) { 'no idea if true or false' }
|
34
|
+
|
35
|
+
it 'raises coercion error' do
|
36
|
+
expect { subject }.to raise_error(
|
37
|
+
Virtus::CoercionError,
|
38
|
+
/Failed to coerce "no idea if true or false"/
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute::Boolean, '#value_coerced?' do
|
4
|
+
subject { object.value_coerced?(input) }
|
5
|
+
|
6
|
+
let(:object) { described_class.build('Boolean') }
|
7
|
+
|
8
|
+
context 'when input is true' do
|
9
|
+
let(:input) { true }
|
10
|
+
|
11
|
+
it { is_expected.to be(true) }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when input is false' do
|
15
|
+
let(:input) { false }
|
16
|
+
|
17
|
+
it { is_expected.to be(true) }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when input is not coerced' do
|
21
|
+
let(:input) { 1 }
|
22
|
+
|
23
|
+
it { is_expected.to be(false) }
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute, '.build' do
|
4
|
+
subject { described_class.build(type, options.merge(:name => name)) }
|
5
|
+
|
6
|
+
let(:name) { :test }
|
7
|
+
let(:type) { String }
|
8
|
+
let(:options) { {} }
|
9
|
+
|
10
|
+
shared_examples_for 'a valid attribute instance' do
|
11
|
+
it { is_expected.to be_instance_of(Virtus::Attribute) }
|
12
|
+
|
13
|
+
it { is_expected.to be_frozen }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'without options' do
|
17
|
+
it_behaves_like 'a valid attribute instance'
|
18
|
+
|
19
|
+
it { is_expected.to be_coercible }
|
20
|
+
it { is_expected.to be_public_reader }
|
21
|
+
it { is_expected.to be_public_writer }
|
22
|
+
it { is_expected.not_to be_lazy }
|
23
|
+
|
24
|
+
it 'sets up a coercer' do
|
25
|
+
expect(subject.options[:coerce]).to be(true)
|
26
|
+
expect(subject.coercer).to be_instance_of(Virtus::Attribute::Coercer)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when name is passed as a string' do
|
31
|
+
let(:name) { 'something' }
|
32
|
+
|
33
|
+
describe '#name' do
|
34
|
+
subject { super().name }
|
35
|
+
it { is_expected.to be(:something) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when coercion is turned off in options' do
|
40
|
+
let(:options) { { :coerce => false } }
|
41
|
+
|
42
|
+
it_behaves_like 'a valid attribute instance'
|
43
|
+
|
44
|
+
it { is_expected.not_to be_coercible }
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when options specify reader visibility' do
|
48
|
+
let(:options) { { :reader => :private } }
|
49
|
+
|
50
|
+
it_behaves_like 'a valid attribute instance'
|
51
|
+
|
52
|
+
it { is_expected.not_to be_public_reader }
|
53
|
+
it { is_expected.to be_public_writer }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when options specify writer visibility' do
|
57
|
+
let(:options) { { :writer => :private } }
|
58
|
+
|
59
|
+
it_behaves_like 'a valid attribute instance'
|
60
|
+
|
61
|
+
it { is_expected.to be_public_reader }
|
62
|
+
it { is_expected.not_to be_public_writer }
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when options specify lazy accessor' do
|
66
|
+
let(:options) { { :lazy => true } }
|
67
|
+
|
68
|
+
it_behaves_like 'a valid attribute instance'
|
69
|
+
|
70
|
+
it { is_expected.to be_lazy }
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when options specify strict mode' do
|
74
|
+
let(:options) { { :strict => true } }
|
75
|
+
|
76
|
+
it_behaves_like 'a valid attribute instance'
|
77
|
+
|
78
|
+
it { is_expected.to be_strict }
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when options specify nullify blank mode' do
|
82
|
+
let(:options) { { :nullify_blank => true } }
|
83
|
+
|
84
|
+
it_behaves_like 'a valid attribute instance'
|
85
|
+
|
86
|
+
it { is_expected.to be_nullify_blank }
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when type is a string' do
|
90
|
+
let(:type) { 'Integer' }
|
91
|
+
|
92
|
+
it_behaves_like 'a valid attribute instance'
|
93
|
+
|
94
|
+
describe '#type' do
|
95
|
+
subject { super().type }
|
96
|
+
it { is_expected.to be(Axiom::Types::Integer) }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when type is a range' do
|
101
|
+
let(:type) { 0..10 }
|
102
|
+
|
103
|
+
it_behaves_like 'a valid attribute instance'
|
104
|
+
|
105
|
+
describe '#type' do
|
106
|
+
subject { super().type }
|
107
|
+
it { is_expected.to be(Axiom::Types.infer(Range)) }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'when type is a symbol of an existing class constant' do
|
112
|
+
let(:type) { :String }
|
113
|
+
|
114
|
+
it_behaves_like 'a valid attribute instance'
|
115
|
+
|
116
|
+
describe '#type' do
|
117
|
+
subject { super().type }
|
118
|
+
it { is_expected.to be(Axiom::Types::String) }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'when type is an axiom type' do
|
123
|
+
let(:type) { Axiom::Types::Integer }
|
124
|
+
|
125
|
+
it_behaves_like 'a valid attribute instance'
|
126
|
+
|
127
|
+
describe '#type' do
|
128
|
+
subject { super().type }
|
129
|
+
it { is_expected.to be(type) }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'when custom attribute class exists for a given primitive' do
|
134
|
+
let(:type) { Class.new }
|
135
|
+
let(:attribute) { Class.new(Virtus::Attribute) }
|
136
|
+
|
137
|
+
before do
|
138
|
+
attribute.primitive(type)
|
139
|
+
end
|
140
|
+
|
141
|
+
it { is_expected.to be_instance_of(attribute) }
|
142
|
+
|
143
|
+
describe '#type' do
|
144
|
+
subject { super().type }
|
145
|
+
it { is_expected.to be(Axiom::Types::Object) }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'when custom attribute class exists for a given array with member coercion defined' do
|
150
|
+
let(:type) { Class.new(Array)[String] }
|
151
|
+
let(:attribute) { Class.new(Virtus::Attribute) }
|
152
|
+
|
153
|
+
before do
|
154
|
+
attribute.primitive(type.class)
|
155
|
+
end
|
156
|
+
|
157
|
+
it { is_expected.to be_instance_of(attribute) }
|
158
|
+
|
159
|
+
describe '#type' do
|
160
|
+
subject { super().type }
|
161
|
+
it { is_expected.to be < Axiom::Types::Collection }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'when custom collection-like attribute class exists for a given enumerable primitive' do
|
166
|
+
let(:type) { Class.new { include Enumerable } }
|
167
|
+
let(:attribute) { Class.new(Virtus::Attribute::Collection) }
|
168
|
+
|
169
|
+
before do
|
170
|
+
attribute.primitive(type)
|
171
|
+
end
|
172
|
+
|
173
|
+
it { is_expected.to be_instance_of(attribute) }
|
174
|
+
|
175
|
+
describe '#type' do
|
176
|
+
subject { super().type }
|
177
|
+
it { is_expected.to be < Axiom::Types::Collection }
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute, '.coerce' do
|
4
|
+
subject { described_class.coerce }
|
5
|
+
|
6
|
+
after :all do
|
7
|
+
described_class.coerce(true)
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'with a value' do
|
11
|
+
it 'sets the value and return self' do
|
12
|
+
expect(described_class.coerce(false)).to be(described_class)
|
13
|
+
expect(subject).to be(false)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when it is set to true' do
|
18
|
+
before do
|
19
|
+
described_class.coerce(true)
|
20
|
+
end
|
21
|
+
|
22
|
+
it { is_expected.to be(true) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when it is set to false' do
|
26
|
+
before do
|
27
|
+
described_class.coerce(false)
|
28
|
+
end
|
29
|
+
|
30
|
+
it { is_expected.to be(false) }
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute, '#coerce' do
|
4
|
+
subject { object.coerce(input) }
|
5
|
+
|
6
|
+
fake(:coercer) { Virtus::Attribute::Coercer }
|
7
|
+
|
8
|
+
let(:object) {
|
9
|
+
described_class.build(String,
|
10
|
+
:coercer => coercer, :strict => strict, :required => required, :nullify_blank => nullify_blank)
|
11
|
+
}
|
12
|
+
|
13
|
+
let(:required) { true }
|
14
|
+
let(:nullify_blank) { false }
|
15
|
+
let(:input) { 1 }
|
16
|
+
let(:output) { '1' }
|
17
|
+
|
18
|
+
context 'when strict mode is turned off' do
|
19
|
+
let(:strict) { false }
|
20
|
+
|
21
|
+
it 'uses coercer to coerce the input value' do
|
22
|
+
mock(coercer).call(input) { output }
|
23
|
+
|
24
|
+
expect(subject).to be(output)
|
25
|
+
|
26
|
+
expect(coercer).to have_received.call(input)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when strict mode is turned on' do
|
31
|
+
let(:strict) { true }
|
32
|
+
|
33
|
+
it 'uses coercer to coerce the input value' do
|
34
|
+
mock(coercer).call(input) { output }
|
35
|
+
mock(coercer).success?(String, output) { true }
|
36
|
+
|
37
|
+
expect(subject).to be(output)
|
38
|
+
|
39
|
+
expect(coercer).to have_received.call(input)
|
40
|
+
expect(coercer).to have_received.success?(String, output)
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when attribute is not required and input is nil' do
|
44
|
+
let(:required) { false }
|
45
|
+
let(:input) { nil }
|
46
|
+
|
47
|
+
it 'returns nil' do
|
48
|
+
mock(coercer).call(input) { input }
|
49
|
+
mock(coercer).success?(String, input) { false }
|
50
|
+
|
51
|
+
expect(subject).to be(nil)
|
52
|
+
|
53
|
+
expect(coercer).to have_received.call(input)
|
54
|
+
expect(coercer).to have_received.success?(String, input)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when attribute is required and input is nil' do
|
59
|
+
let(:input) { nil }
|
60
|
+
|
61
|
+
it 'returns raises error' do
|
62
|
+
mock(coercer).call(input) { input }
|
63
|
+
mock(coercer).success?(String, input) { false }
|
64
|
+
|
65
|
+
expect { subject }.to raise_error(Virtus::CoercionError)
|
66
|
+
|
67
|
+
expect(coercer).to have_received.call(input)
|
68
|
+
expect(coercer).to have_received.success?(String, input)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'raises error when input was not coerced' do
|
73
|
+
mock(coercer).call(input) { input }
|
74
|
+
mock(coercer).success?(String, input) { false }
|
75
|
+
|
76
|
+
expect { subject }.to raise_error(Virtus::CoercionError)
|
77
|
+
|
78
|
+
expect(coercer).to have_received.call(input)
|
79
|
+
expect(coercer).to have_received.success?(String, input)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when the input is an empty String' do
|
84
|
+
let(:input) { '' }
|
85
|
+
let(:output) { '' }
|
86
|
+
|
87
|
+
context 'when nullify_blank is turned on' do
|
88
|
+
let(:nullify_blank) { true }
|
89
|
+
let(:strict) { false }
|
90
|
+
let(:require) { false }
|
91
|
+
|
92
|
+
it 'returns nil' do
|
93
|
+
mock(coercer).call(input) { input }
|
94
|
+
mock(coercer).success?(String, input) { false }
|
95
|
+
|
96
|
+
expect(subject).to be_nil
|
97
|
+
|
98
|
+
expect(coercer).to have_received.call(input)
|
99
|
+
expect(coercer).to have_received.success?(String, input)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'returns the ouput if it was coerced' do
|
103
|
+
mock(coercer).call(input) { output }
|
104
|
+
mock(coercer).success?(String, output) { true }
|
105
|
+
|
106
|
+
expect(subject).to be(output)
|
107
|
+
|
108
|
+
expect(coercer).to have_received.call(input)
|
109
|
+
expect(coercer).to have_received.success?(String, output)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when both nullify_blank and strict are turned on' do
|
114
|
+
let(:nullify_blank) { true }
|
115
|
+
let(:strict) { true }
|
116
|
+
|
117
|
+
it 'does not raises an coercion error' do
|
118
|
+
mock(coercer).call(input) { input }
|
119
|
+
mock(coercer).success?(String, input) { false }
|
120
|
+
|
121
|
+
expect { subject }.not_to raise_error
|
122
|
+
expect(subject).to be_nil
|
123
|
+
|
124
|
+
expect(coercer).to have_received.call(input)
|
125
|
+
expect(coercer).to have_received.success?(String, input)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|