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,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute, '#coercible?' do
|
4
|
+
subject { object.coercible? }
|
5
|
+
|
6
|
+
let(:object) { described_class.build(String, options) }
|
7
|
+
let(:options) { Hash[:coerce => coerce] }
|
8
|
+
|
9
|
+
context 'when :coerce is set to true' do
|
10
|
+
let(:coerce) { true }
|
11
|
+
|
12
|
+
it { is_expected.to be(true) }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when :coerce is set to false' do
|
16
|
+
let(:coerce) { false }
|
17
|
+
|
18
|
+
it { is_expected.to be(false) }
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute, '.build' do
|
4
|
+
subject { described_class.build(type, options) }
|
5
|
+
|
6
|
+
let(:options) { {} }
|
7
|
+
|
8
|
+
shared_examples_for 'a valid collection attribute instance' do
|
9
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::Collection) }
|
10
|
+
|
11
|
+
it { is_expected.to be_frozen }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when type is Array' do
|
15
|
+
let(:type) { Array }
|
16
|
+
|
17
|
+
it_behaves_like 'a valid collection attribute instance'
|
18
|
+
|
19
|
+
it 'sets default member type' do
|
20
|
+
expect(subject.type.member_type).to be(Axiom::Types::Object)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when type is Array[Virtus::Attribute::Boolean]' do
|
25
|
+
let(:type) { Array[Virtus::Attribute::Boolean] }
|
26
|
+
|
27
|
+
it_behaves_like 'a valid collection attribute instance'
|
28
|
+
|
29
|
+
it 'sets member type' do
|
30
|
+
expect(subject.type.member_type).to be(Axiom::Types::Boolean)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when type is Array[Float]' do
|
35
|
+
let(:type) { Array[Float] }
|
36
|
+
|
37
|
+
it_behaves_like 'a valid collection attribute instance'
|
38
|
+
|
39
|
+
it 'sets member type' do
|
40
|
+
expect(subject.type.member_type).to be(Axiom::Types::Float)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when type is Array[String, Integer]' do
|
45
|
+
let(:type) { Array[String, Integer] }
|
46
|
+
|
47
|
+
specify do
|
48
|
+
expect { subject }.to raise_error(
|
49
|
+
NotImplementedError,
|
50
|
+
"build SumType from list of types (#{type.inspect})"
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when type is Set' do
|
56
|
+
let(:type) { Set }
|
57
|
+
|
58
|
+
it_behaves_like 'a valid collection attribute instance'
|
59
|
+
|
60
|
+
it 'sets default member type' do
|
61
|
+
expect(subject.type.member_type).to be(Axiom::Types::Object)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when type is Set[Float]' do
|
66
|
+
let(:type) { Set[Float] }
|
67
|
+
|
68
|
+
it_behaves_like 'a valid collection attribute instance'
|
69
|
+
|
70
|
+
it 'sets member type' do
|
71
|
+
expect(subject.type.member_type).to be(Axiom::Types::Float)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when type is an Enumerable' do
|
76
|
+
let(:type) { Class.new { include Enumerable } }
|
77
|
+
|
78
|
+
it_behaves_like 'a valid collection attribute instance'
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when type is Array subclass' do
|
82
|
+
let(:type) { Class.new(Array) }
|
83
|
+
|
84
|
+
it_behaves_like 'a valid collection attribute instance'
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'when type is a custom collection instance' do
|
88
|
+
let(:type) { Class.new(Array)[String] }
|
89
|
+
|
90
|
+
it_behaves_like 'a valid collection attribute instance'
|
91
|
+
|
92
|
+
it 'sets member type' do
|
93
|
+
expect(subject.type.member_type).to be(Axiom::Types::String)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when strict mode is used' do
|
98
|
+
let(:type) { Array[String] }
|
99
|
+
let(:options) { { strict: true } }
|
100
|
+
|
101
|
+
it 'sets strict mode for member type' do
|
102
|
+
expect(subject.member_type).to be_strict
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute::Collection, '#coerce' do
|
4
|
+
subject { object.coerce(input) }
|
5
|
+
|
6
|
+
context 'when input is an array' do
|
7
|
+
context 'when member type is a primitive' do
|
8
|
+
fake(:coercer) { Virtus::Attribute::Coercer }
|
9
|
+
fake(:member_type) { Virtus::Attribute }
|
10
|
+
|
11
|
+
let(:member_primitive) { Integer }
|
12
|
+
let(:input) { ['1', '2'] }
|
13
|
+
|
14
|
+
let(:object) {
|
15
|
+
described_class.build(Array[member_primitive], :coercer => coercer, :member_type => member_type)
|
16
|
+
}
|
17
|
+
|
18
|
+
it 'uses coercer to coerce members' do
|
19
|
+
mock(coercer).call(input) { input }
|
20
|
+
mock(member_type).finalize { member_type }
|
21
|
+
mock(member_type).coerce('1') { 1 }
|
22
|
+
mock(member_type).coerce('2') { 2 }
|
23
|
+
|
24
|
+
expect(subject).to eq([1, 2])
|
25
|
+
|
26
|
+
expect(member_type).to have_received.coerce('1')
|
27
|
+
expect(member_type).to have_received.coerce('2')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when member type is an EV' do
|
32
|
+
let(:member_primitive) { Struct.new(:id) }
|
33
|
+
let(:input) { [1, 2] }
|
34
|
+
let(:object) { described_class.build(Array[member_primitive]) }
|
35
|
+
|
36
|
+
it 'coerces members' do
|
37
|
+
expect(subject).to eq([member_primitive.new(1), member_primitive.new(2)])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when member type is a hash with key/value coercion' do
|
42
|
+
let(:member_primitive) { Hash[String => Integer] }
|
43
|
+
let(:member_attribute) { Virtus::Attribute.build(member_primitive) }
|
44
|
+
let(:input) { [{:one => '1'}, {:two => '2'}] }
|
45
|
+
let(:output) { [member_attribute.coerce(input.first), member_attribute.coerce(input.last)] }
|
46
|
+
let(:object) { described_class.build(Array[member_primitive]) }
|
47
|
+
|
48
|
+
it 'coerces members' do
|
49
|
+
expect(subject).to eq(output)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when input is nil' do
|
55
|
+
let(:input) { nil }
|
56
|
+
|
57
|
+
fake(:coercer) { Virtus::Attribute::Coercer }
|
58
|
+
fake(:member_type) { Virtus::Attribute }
|
59
|
+
|
60
|
+
let(:member_primitive) { Integer }
|
61
|
+
|
62
|
+
let(:object) {
|
63
|
+
described_class.build(
|
64
|
+
Array[member_primitive], coercer: coercer, member_type: member_type
|
65
|
+
)
|
66
|
+
}
|
67
|
+
|
68
|
+
it 'returns nil' do
|
69
|
+
mock(coercer).call(input) { input }
|
70
|
+
|
71
|
+
expect(subject).to be(input)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
describe Virtus::Attribute::Collection, '#value_coerced?' do
|
5
|
+
subject { object.value_coerced?(input) }
|
6
|
+
|
7
|
+
let(:object) { described_class.build(Array[Integer]) }
|
8
|
+
|
9
|
+
context 'when input has correctly typed members' do
|
10
|
+
let(:input) { [1, 2, 3] }
|
11
|
+
|
12
|
+
it { is_expected.to be(true) }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when input has incorrectly typed members' do
|
16
|
+
let(:input) { [1, 2, '3'] }
|
17
|
+
|
18
|
+
it { is_expected.to be(false) }
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when the collection type is incorrect' do
|
22
|
+
let(:input) { Set[1, 2, 3] }
|
23
|
+
|
24
|
+
it { is_expected.to be(false) }
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when the input is empty' do
|
28
|
+
let(:input) { [] }
|
29
|
+
it { is_expected.to be(true) }
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute, '#== (defined by including Virtus::Equalizer)' do
|
4
|
+
let(:attribute) { described_class.build(String, :name => :name) }
|
5
|
+
|
6
|
+
it 'returns true when attributes have same type and options' do
|
7
|
+
equal_attribute = described_class.build(String, :name => :name)
|
8
|
+
expect(attribute == equal_attribute).to be_truthy
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns false when attributes have different type' do
|
12
|
+
different_attribute = described_class.build(Integer, :name => :name)
|
13
|
+
expect(attribute == different_attribute).to be_falsey
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns false when attributes have different options' do
|
17
|
+
different_attribute = described_class.build(Integer, :name => :name_two)
|
18
|
+
expect(attribute == different_attribute).to be_falsey
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute::Collection, 'custom subclass' do
|
4
|
+
subject { attribute_class.build(primitive) }
|
5
|
+
|
6
|
+
let(:primitive) { Class.new { include Enumerable } }
|
7
|
+
|
8
|
+
after do
|
9
|
+
described_class.descendants.delete(attribute_class)
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when primitive is set on the attribute subclass' do
|
13
|
+
let(:attribute_class) { Class.new(described_class).primitive(primitive) }
|
14
|
+
|
15
|
+
describe '#primitive' do
|
16
|
+
subject { super().primitive }
|
17
|
+
it { is_expected.to be(primitive) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when primitive is not set on the attribute subclass' do
|
22
|
+
let(:attribute_class) { Class.new(described_class) }
|
23
|
+
|
24
|
+
describe '#primitive' do
|
25
|
+
subject { super().primitive }
|
26
|
+
it { is_expected.to be(primitive) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute, '#defined?' do
|
4
|
+
subject { object.defined?(instance) }
|
5
|
+
|
6
|
+
let(:object) { described_class.build(String, :name => name) }
|
7
|
+
|
8
|
+
let(:model) { Class.new { attr_accessor :test } }
|
9
|
+
let(:name) { :test }
|
10
|
+
let(:instance) { model.new }
|
11
|
+
|
12
|
+
context 'when the attribute value has not been defined' do
|
13
|
+
it { is_expected.to be(false) }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when the attribute value has been defined' do
|
17
|
+
before { instance.test = nil }
|
18
|
+
it { is_expected.to be(true) }
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute::EmbeddedValue, '.build' do
|
4
|
+
subject { described_class.build(type) }
|
5
|
+
|
6
|
+
context 'when type is a Virtus.model' do
|
7
|
+
let(:type) { Class.new { include Virtus.model } }
|
8
|
+
|
9
|
+
it { is_expected.to be_frozen }
|
10
|
+
|
11
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::EmbeddedValue) }
|
12
|
+
|
13
|
+
describe '#coercer' do
|
14
|
+
subject { super().coercer }
|
15
|
+
it { is_expected.to be_instance_of(described_class::FromOpenStruct) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when type includes Virtus' do
|
20
|
+
let(:type) { Class.new { include Virtus } }
|
21
|
+
|
22
|
+
it { is_expected.to be_frozen }
|
23
|
+
|
24
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::EmbeddedValue) }
|
25
|
+
|
26
|
+
describe '#coercer' do
|
27
|
+
subject { super().coercer }
|
28
|
+
it { is_expected.to be_instance_of(described_class::FromOpenStruct) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when type is an OpenStruct subclass' do
|
33
|
+
let(:type) { Class.new(OpenStruct) }
|
34
|
+
|
35
|
+
it { is_expected.to be_frozen }
|
36
|
+
|
37
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::EmbeddedValue) }
|
38
|
+
|
39
|
+
describe '#coercer' do
|
40
|
+
subject { super().coercer }
|
41
|
+
it { is_expected.to be_instance_of(described_class::FromOpenStruct) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when type is OpenStruct' do
|
46
|
+
let(:type) { OpenStruct }
|
47
|
+
|
48
|
+
it { is_expected.to be_frozen }
|
49
|
+
|
50
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::EmbeddedValue) }
|
51
|
+
|
52
|
+
describe '#coercer' do
|
53
|
+
subject { super().coercer }
|
54
|
+
it { is_expected.to be_instance_of(described_class::FromOpenStruct) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when type is Struct' do
|
59
|
+
let(:type) { Struct.new(:test) }
|
60
|
+
|
61
|
+
it { is_expected.to be_frozen }
|
62
|
+
|
63
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::EmbeddedValue) }
|
64
|
+
|
65
|
+
describe '#coercer' do
|
66
|
+
subject { super().coercer }
|
67
|
+
it { is_expected.to be_instance_of(described_class::FromStruct) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute::EmbeddedValue, '#coerce' do
|
4
|
+
subject { object.coerce(input) }
|
5
|
+
|
6
|
+
let(:object) { described_class.build(model, options) }
|
7
|
+
let(:options) { {} }
|
8
|
+
|
9
|
+
context 'when primitive is OpenStruct' do
|
10
|
+
let(:model) { OpenStruct }
|
11
|
+
|
12
|
+
context 'when input is an attribute hash' do
|
13
|
+
let(:input) { Hash[name: 'Piotr', age: 30] }
|
14
|
+
|
15
|
+
it { is_expected.to be_instance_of(model) }
|
16
|
+
|
17
|
+
describe '#name' do
|
18
|
+
subject { super().name }
|
19
|
+
it { is_expected.to eql('Piotr') }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#age' do
|
23
|
+
subject { super().age }
|
24
|
+
it { is_expected.to eql(30) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when input is nil' do
|
29
|
+
let(:input) { nil }
|
30
|
+
|
31
|
+
it { is_expected.to be(nil) }
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when input is a model instance' do
|
35
|
+
let(:input) { OpenStruct.new }
|
36
|
+
|
37
|
+
it { is_expected.to be(input) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when primitive is Struct' do
|
42
|
+
let(:model) { Struct.new(:name, :age) }
|
43
|
+
|
44
|
+
context 'when input is an attribute hash' do
|
45
|
+
let(:input) { ['Piotr', 30] }
|
46
|
+
|
47
|
+
it { is_expected.to be_instance_of(model) }
|
48
|
+
|
49
|
+
describe '#name' do
|
50
|
+
subject { super().name }
|
51
|
+
it { is_expected.to eql('Piotr') }
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#age' do
|
55
|
+
subject { super().age }
|
56
|
+
it { is_expected.to eql(30) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when input is nil' do
|
61
|
+
let(:input) { nil }
|
62
|
+
|
63
|
+
it { is_expected.to be(nil) }
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when input is a model instance' do
|
67
|
+
let(:input) { model.new('Piotr', 30) }
|
68
|
+
|
69
|
+
it { is_expected.to be(input) }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when :strict mode is enabled' do
|
74
|
+
let(:model) { Struct.new(:name) }
|
75
|
+
let(:options) { { :strict => true } }
|
76
|
+
|
77
|
+
context 'when input is coercible' do
|
78
|
+
let(:input) { ['Piotr'] }
|
79
|
+
|
80
|
+
it { is_expected.to eql(model.new('Piotr')) }
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when input is not coercible' do
|
84
|
+
let(:input) { nil }
|
85
|
+
|
86
|
+
it 'raises error' do
|
87
|
+
expect { subject }.to raise_error(Virtus::CoercionError)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|