virtus 1.0.3 → 1.0.4
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/.travis.yml +8 -5
- data/Changelog.md +7 -1
- data/Gemfile +14 -5
- data/README.md +40 -19
- data/Rakefile +13 -3
- data/lib/virtus/configuration.rb +10 -5
- data/lib/virtus/version.rb +1 -1
- data/spec/integration/collection_member_coercion_spec.rb +34 -13
- data/spec/integration/hash_attributes_coercion_spec.rb +5 -5
- data/spec/shared/freeze_method_behavior.rb +5 -2
- data/spec/shared/idempotent_method_behaviour.rb +1 -1
- data/spec/shared/options_class_method.rb +3 -3
- data/spec/spec_helper.rb +3 -18
- data/spec/unit/virtus/attribute/boolean/coerce_spec.rb +3 -3
- data/spec/unit/virtus/attribute/boolean/value_coerced_predicate_spec.rb +3 -3
- data/spec/unit/virtus/attribute/class_methods/build_spec.rb +48 -24
- data/spec/unit/virtus/attribute/class_methods/coerce_spec.rb +2 -2
- data/spec/unit/virtus/attribute/coerce_spec.rb +9 -9
- data/spec/unit/virtus/attribute/coercible_predicate_spec.rb +2 -2
- data/spec/unit/virtus/attribute/collection/class_methods/build_spec.rb +2 -2
- data/spec/unit/virtus/attribute/collection/coerce_spec.rb +5 -5
- data/spec/unit/virtus/attribute/custom_collection_spec.rb +8 -2
- data/spec/unit/virtus/attribute/defined_spec.rb +2 -2
- data/spec/unit/virtus/attribute/embedded_value/class_methods/build_spec.rb +30 -15
- data/spec/unit/virtus/attribute/embedded_value/coerce_spec.rb +25 -11
- data/spec/unit/virtus/attribute/get_spec.rb +2 -2
- data/spec/unit/virtus/attribute/hash/class_methods/build_spec.rb +7 -7
- data/spec/unit/virtus/attribute/hash/coerce_spec.rb +9 -9
- data/spec/unit/virtus/attribute/lazy_predicate_spec.rb +2 -2
- data/spec/unit/virtus/attribute/rename_spec.rb +6 -3
- data/spec/unit/virtus/attribute/required_predicate_spec.rb +2 -2
- data/spec/unit/virtus/attribute/set_default_value_spec.rb +43 -10
- data/spec/unit/virtus/attribute/set_spec.rb +1 -1
- data/spec/unit/virtus/attribute/value_coerced_predicate_spec.rb +2 -2
- data/spec/unit/virtus/attribute_set/append_spec.rb +2 -2
- data/spec/unit/virtus/attribute_set/define_reader_method_spec.rb +12 -11
- data/spec/unit/virtus/attribute_set/define_writer_method_spec.rb +13 -12
- data/spec/unit/virtus/attribute_set/each_spec.rb +3 -3
- data/spec/unit/virtus/attribute_set/element_reference_spec.rb +1 -1
- data/spec/unit/virtus/attribute_set/element_set_spec.rb +2 -2
- data/spec/unit/virtus/attribute_set/merge_spec.rb +2 -2
- data/spec/unit/virtus/attribute_set/reset_spec.rb +17 -8
- data/spec/unit/virtus/attribute_spec.rb +4 -4
- data/spec/unit/virtus/element_reader_spec.rb +1 -1
- data/spec/unit/virtus/freeze_spec.rb +10 -3
- data/spec/unit/virtus/model_spec.rb +35 -4
- data/spec/unit/virtus/set_default_attributes_spec.rb +10 -3
- data/spec/unit/virtus/value_object_spec.rb +13 -3
- data/virtus.gemspec +6 -4
- metadata +16 -8
- data/Gemfile.devtools +0 -71
- data/config/flay.yml +0 -3
- data/config/flog.yml +0 -2
- data/config/mutant.yml +0 -15
- data/config/reek.yml +0 -146
- data/config/yardstick.yml +0 -2
@@ -16,13 +16,13 @@ describe Virtus::Attribute, '#get' do
|
|
16
16
|
instance.test = value
|
17
17
|
end
|
18
18
|
|
19
|
-
it {
|
19
|
+
it { is_expected.to be(value) }
|
20
20
|
end
|
21
21
|
|
22
22
|
context 'with :lazy is set to true' do
|
23
23
|
let(:options) { { :lazy => true, :default => value } }
|
24
24
|
|
25
|
-
it {
|
25
|
+
it { is_expected.to eql(value) }
|
26
26
|
|
27
27
|
it 'sets default only on first access' do
|
28
28
|
expect(object.get(instance)).to eql(value)
|
@@ -6,15 +6,15 @@ describe Virtus::Attribute::Hash, '.build' do
|
|
6
6
|
let(:options) { {} }
|
7
7
|
|
8
8
|
shared_examples_for 'a valid hash attribute instance' do
|
9
|
-
it {
|
9
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::Hash) }
|
10
10
|
|
11
|
-
it {
|
11
|
+
it { is_expected.to be_frozen }
|
12
12
|
end
|
13
13
|
|
14
14
|
context 'when type is Hash' do
|
15
15
|
let(:type) { Hash }
|
16
16
|
|
17
|
-
it {
|
17
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::Hash) }
|
18
18
|
|
19
19
|
it 'sets default key type' do
|
20
20
|
expect(subject.type.key_type).to be(Axiom::Types::Object)
|
@@ -28,7 +28,7 @@ describe Virtus::Attribute::Hash, '.build' do
|
|
28
28
|
context 'when type is Hash[String => Integer]' do
|
29
29
|
let(:type) { Hash[String => Integer] }
|
30
30
|
|
31
|
-
it {
|
31
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::Hash) }
|
32
32
|
|
33
33
|
it 'sets key type' do
|
34
34
|
expect(subject.type.key_type).to be(Axiom::Types::String)
|
@@ -42,7 +42,7 @@ describe Virtus::Attribute::Hash, '.build' do
|
|
42
42
|
context 'when type is Hash[Virtus::Attribute::Hash => Virtus::Attribute::Boolean]' do
|
43
43
|
let(:type) { Hash[Virtus::Attribute::Hash => Virtus::Attribute::Boolean] }
|
44
44
|
|
45
|
-
it {
|
45
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::Hash) }
|
46
46
|
|
47
47
|
it 'sets key type' do
|
48
48
|
expect(subject.type.key_type).to be(Axiom::Types::Hash)
|
@@ -57,7 +57,7 @@ describe Virtus::Attribute::Hash, '.build' do
|
|
57
57
|
let(:type) { Hash[key_type => Integer] }
|
58
58
|
let(:key_type) { Struct.new(:id) }
|
59
59
|
|
60
|
-
it {
|
60
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::Hash) }
|
61
61
|
|
62
62
|
it 'sets key type' do
|
63
63
|
expect(subject.type.key_type).to be(key_type)
|
@@ -72,7 +72,7 @@ describe Virtus::Attribute::Hash, '.build' do
|
|
72
72
|
let(:type) { Hash[String => value_type] }
|
73
73
|
let(:value_type) { Struct.new(:id) }
|
74
74
|
|
75
|
-
it {
|
75
|
+
it { is_expected.to be_instance_of(Virtus::Attribute::Hash) }
|
76
76
|
|
77
77
|
it 'sets key type' do
|
78
78
|
expect(subject.type.key_type).to be(Axiom::Types::String)
|
@@ -17,14 +17,14 @@ describe Virtus::Attribute::Hash, '#coerce' do
|
|
17
17
|
let(:input) { Class.new { def to_hash; { :hello => 'World' }; end }.new }
|
18
18
|
let(:object) { described_class.build(Hash) }
|
19
19
|
|
20
|
-
it {
|
20
|
+
it { is_expected.to eq(:hello => 'World') }
|
21
21
|
end
|
22
22
|
|
23
23
|
context 'when input is not coercible to hash' do
|
24
24
|
let(:input) { 'not really a hash' }
|
25
25
|
let(:object) { described_class.build(Hash) }
|
26
26
|
|
27
|
-
it {
|
27
|
+
it { is_expected.to be(input) }
|
28
28
|
end
|
29
29
|
|
30
30
|
context 'when input is a hash' do
|
@@ -39,15 +39,15 @@ describe Virtus::Attribute::Hash, '#coerce' do
|
|
39
39
|
let(:input) { Hash[1 => '1', 2 => '2'] }
|
40
40
|
|
41
41
|
it 'uses coercer to coerce key and value' do
|
42
|
-
|
42
|
+
mock(coercer).call(input) { input }
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
mock(key_type).finalize { key_type }
|
45
|
+
mock(key_type).coerce(1) { '1' }
|
46
|
+
mock(key_type).coerce(2) { '2' }
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
mock(value_type).finalize { value_type }
|
49
|
+
mock(value_type).coerce('1') { 1 }
|
50
|
+
mock(value_type).coerce('2') { 2 }
|
51
51
|
|
52
52
|
expect(subject).to eq(Hash['1' => 1, '2' => 2])
|
53
53
|
|
@@ -9,12 +9,12 @@ describe Virtus::Attribute, '#lazy?' do
|
|
9
9
|
context 'when :lazy is set to true' do
|
10
10
|
let(:lazy) { true }
|
11
11
|
|
12
|
-
it {
|
12
|
+
it { is_expected.to be(true) }
|
13
13
|
end
|
14
14
|
|
15
15
|
context 'when :lazy is set to false' do
|
16
16
|
let(:lazy) { false }
|
17
17
|
|
18
|
-
it {
|
18
|
+
it { is_expected.to be(false) }
|
19
19
|
end
|
20
20
|
end
|
@@ -6,8 +6,11 @@ describe Virtus::Attribute, '#rename' do
|
|
6
6
|
let(:object) { described_class.build(String, :name => :foo, :strict => true) }
|
7
7
|
let(:other) { described_class.build(String, :name => :bar, :strict => true) }
|
8
8
|
|
9
|
-
|
9
|
+
describe '#name' do
|
10
|
+
subject { super().name }
|
11
|
+
it { is_expected.to be(:bar) }
|
12
|
+
end
|
10
13
|
|
11
|
-
it {
|
12
|
-
it {
|
14
|
+
it { is_expected.not_to be(object) }
|
15
|
+
it { is_expected.to be_strict }
|
13
16
|
end
|
@@ -8,12 +8,12 @@ describe Virtus::Attribute, '#required?' do
|
|
8
8
|
context 'when required option is true' do
|
9
9
|
let(:required) { true }
|
10
10
|
|
11
|
-
it {
|
11
|
+
it { is_expected.to be(true) }
|
12
12
|
end
|
13
13
|
|
14
14
|
context 'when required option is false' do
|
15
15
|
let(:required) { false }
|
16
16
|
|
17
|
-
it {
|
17
|
+
it { is_expected.to be(false) }
|
18
18
|
end
|
19
19
|
end
|
@@ -15,8 +15,15 @@ describe Virtus::Attribute, '#set_default_value' do
|
|
15
15
|
|
16
16
|
let(:default) { nil }
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
describe '#test' do
|
19
|
+
subject { super().test }
|
20
|
+
it { is_expected.to be(nil) }
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#instance_variables' do
|
24
|
+
subject { super().instance_variables }
|
25
|
+
it { is_expected.to include(:'@test') }
|
26
|
+
end
|
20
27
|
end
|
21
28
|
|
22
29
|
context 'with a non-clonable object' do
|
@@ -25,8 +32,15 @@ describe Virtus::Attribute, '#set_default_value' do
|
|
25
32
|
let(:object) { described_class.build('Boolean', options.merge(:name => name, :default => default)) }
|
26
33
|
let(:default) { true }
|
27
34
|
|
28
|
-
|
29
|
-
|
35
|
+
describe '#test' do
|
36
|
+
subject { super().test }
|
37
|
+
it { is_expected.to be(true) }
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#instance_variables' do
|
41
|
+
subject { super().instance_variables }
|
42
|
+
it { is_expected.to include(:'@test') }
|
43
|
+
end
|
30
44
|
end
|
31
45
|
|
32
46
|
context 'with a clonable' do
|
@@ -34,8 +48,15 @@ describe Virtus::Attribute, '#set_default_value' do
|
|
34
48
|
|
35
49
|
let(:default) { [] }
|
36
50
|
|
37
|
-
|
38
|
-
|
51
|
+
describe '#test' do
|
52
|
+
subject { super().test }
|
53
|
+
it { is_expected.to eq(default) }
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#test' do
|
57
|
+
subject { super().test }
|
58
|
+
it { is_expected.not_to be(default) }
|
59
|
+
end
|
39
60
|
end
|
40
61
|
|
41
62
|
context 'with a callable' do
|
@@ -43,7 +64,10 @@ describe Virtus::Attribute, '#set_default_value' do
|
|
43
64
|
|
44
65
|
let(:default) { lambda { |model, attribute| "#{model.name}-#{attribute.name}" } }
|
45
66
|
|
46
|
-
|
67
|
+
describe '#test' do
|
68
|
+
subject { super().test }
|
69
|
+
it { is_expected.to eq('model-test') }
|
70
|
+
end
|
47
71
|
end
|
48
72
|
|
49
73
|
context 'with a symbol' do
|
@@ -55,20 +79,29 @@ describe Virtus::Attribute, '#set_default_value' do
|
|
55
79
|
context 'when method is public' do
|
56
80
|
let(:model) { Class.new { attr_reader :test; def set_test; @test = 'hello world'; end } }
|
57
81
|
|
58
|
-
|
82
|
+
describe '#test' do
|
83
|
+
subject { super().test }
|
84
|
+
it { is_expected.to eq('hello world') }
|
85
|
+
end
|
59
86
|
end
|
60
87
|
|
61
88
|
context 'when method is private' do
|
62
89
|
let(:model) { Class.new { attr_reader :test; private; def set_test; @test = 'hello world'; end } }
|
63
90
|
|
64
|
-
|
91
|
+
describe '#test' do
|
92
|
+
subject { super().test }
|
93
|
+
it { is_expected.to eq('hello world') }
|
94
|
+
end
|
65
95
|
end
|
66
96
|
end
|
67
97
|
|
68
98
|
context 'when it is not a method name' do
|
69
99
|
let(:default) { :hello_world }
|
70
100
|
|
71
|
-
|
101
|
+
describe '#test' do
|
102
|
+
subject { super().test }
|
103
|
+
it { is_expected.to eq('hello_world') }
|
104
|
+
end
|
72
105
|
end
|
73
106
|
end
|
74
107
|
end
|
@@ -8,12 +8,12 @@ describe Virtus::Attribute, '#value_coerced?' do
|
|
8
8
|
context 'when input is coerced' do
|
9
9
|
let(:input) { '1' }
|
10
10
|
|
11
|
-
it {
|
11
|
+
it { is_expected.to be(true) }
|
12
12
|
end
|
13
13
|
|
14
14
|
context 'when input is not coerced' do
|
15
15
|
let(:input) { 1 }
|
16
16
|
|
17
|
-
it {
|
17
|
+
it { is_expected.to be(false) }
|
18
18
|
end
|
19
19
|
end
|
@@ -11,7 +11,7 @@ describe Virtus::AttributeSet, '#<<' do
|
|
11
11
|
context 'with a new attribute' do
|
12
12
|
let(:attribute) { Virtus::Attribute.build(String, :name => name) }
|
13
13
|
|
14
|
-
it {
|
14
|
+
it { is_expected.to equal(object) }
|
15
15
|
|
16
16
|
it 'adds an attribute' do
|
17
17
|
expect { subject }.to change { object.to_a }.
|
@@ -36,7 +36,7 @@ describe Virtus::AttributeSet, '#<<' do
|
|
36
36
|
let(:attributes) { [Virtus::Attribute.build(String, :name => name)] }
|
37
37
|
let(:attribute) { Virtus::Attribute.build(String, :name => name) }
|
38
38
|
|
39
|
-
it {
|
39
|
+
it { is_expected.to equal(object) }
|
40
40
|
|
41
41
|
it 'replaces the original attribute' do
|
42
42
|
expect { subject }.to change { object.to_a }.
|
@@ -1,35 +1,36 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Virtus::AttributeSet, '#define_reader_method' do
|
4
|
-
subject { described_class.new }
|
4
|
+
subject(:attribute_set) { described_class.new }
|
5
5
|
|
6
6
|
let(:attribute) { Virtus::Attribute.build(String, :name => method_name) }
|
7
|
-
|
8
|
-
if RUBY_VERSION < '1.9'
|
9
|
-
let(:method_name) { 'foo_bar' }
|
10
|
-
else
|
11
|
-
let(:method_name) { :foo_bar }
|
12
|
-
end
|
7
|
+
let(:method_name) { :foo_bar }
|
13
8
|
|
14
9
|
before do
|
15
|
-
|
10
|
+
attribute_set.define_reader_method(attribute, method_name, visibility)
|
16
11
|
end
|
17
12
|
|
18
13
|
context "with public visibility" do
|
19
14
|
let(:visibility) { :public }
|
20
15
|
|
21
|
-
|
16
|
+
it "defines public writer" do
|
17
|
+
expect(attribute_set.public_instance_methods).to include(method_name)
|
18
|
+
end
|
22
19
|
end
|
23
20
|
|
24
21
|
context "with private visibility" do
|
25
22
|
let(:visibility) { :private }
|
26
23
|
|
27
|
-
|
24
|
+
it "defines public writer" do
|
25
|
+
expect(attribute_set.private_instance_methods).to include(method_name)
|
26
|
+
end
|
28
27
|
end
|
29
28
|
|
30
29
|
context "with protected visibility" do
|
31
30
|
let(:visibility) { :protected }
|
32
31
|
|
33
|
-
|
32
|
+
it "defines protected writer" do
|
33
|
+
expect(attribute_set.protected_instance_methods).to include(method_name)
|
34
|
+
end
|
34
35
|
end
|
35
36
|
end
|
@@ -1,35 +1,36 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Virtus::AttributeSet, '#define_writer_method' do
|
4
|
-
subject { described_class.new }
|
4
|
+
subject(:attribute_set) { described_class.new }
|
5
5
|
|
6
|
-
let(:attribute) { Virtus::Attribute.build(String, :name =>
|
7
|
-
|
8
|
-
if RUBY_VERSION < '1.9'
|
9
|
-
let(:method_name) { 'foo_bar=' }
|
10
|
-
else
|
11
|
-
let(:method_name) { :foo_bar= }
|
12
|
-
end
|
6
|
+
let(:attribute) { Virtus::Attribute.build(String, :name => method_name) }
|
7
|
+
let(:method_name) { :foo_bar }
|
13
8
|
|
14
9
|
before do
|
15
|
-
|
10
|
+
attribute_set.define_writer_method(attribute, method_name, visibility)
|
16
11
|
end
|
17
12
|
|
18
13
|
context "with public visibility" do
|
19
14
|
let(:visibility) { :public }
|
20
15
|
|
21
|
-
|
16
|
+
it "defines public writer" do
|
17
|
+
expect(attribute_set.public_instance_methods).to include(method_name)
|
18
|
+
end
|
22
19
|
end
|
23
20
|
|
24
21
|
context "with private visibility" do
|
25
22
|
let(:visibility) { :private }
|
26
23
|
|
27
|
-
|
24
|
+
it "defines private writer" do
|
25
|
+
expect(attribute_set.private_instance_methods).to include(method_name)
|
26
|
+
end
|
28
27
|
end
|
29
28
|
|
30
29
|
context "with protected visibility" do
|
31
30
|
let(:visibility) { :protected }
|
32
31
|
|
33
|
-
|
32
|
+
it "defines protected writer" do
|
33
|
+
expect(attribute_set.protected_instance_methods).to include(method_name)
|
34
|
+
end
|
34
35
|
end
|
35
36
|
end
|
@@ -25,7 +25,7 @@ describe Virtus::AttributeSet, '#each' do
|
|
25
25
|
subject { attribute_set.each { |attribute| yields << attribute } }
|
26
26
|
|
27
27
|
context 'when the parent has no attributes' do
|
28
|
-
it {
|
28
|
+
it { is_expected.to equal(attribute_set) }
|
29
29
|
|
30
30
|
it 'yields the expected attributes' do
|
31
31
|
expect { subject }.to change { yields.dup }.
|
@@ -38,7 +38,7 @@ describe Virtus::AttributeSet, '#each' do
|
|
38
38
|
let(:parent_attribute) { Virtus::Attribute.build(String, :name => :parent_name) }
|
39
39
|
let(:parent) { described_class.new([ parent_attribute ]) }
|
40
40
|
|
41
|
-
it {
|
41
|
+
it { is_expected.to equal(attribute_set) }
|
42
42
|
|
43
43
|
it 'yields the expected attributes' do
|
44
44
|
result = []
|
@@ -53,7 +53,7 @@ describe Virtus::AttributeSet, '#each' do
|
|
53
53
|
let(:parent_attribute) { Virtus::Attribute.build(String, :name => name) }
|
54
54
|
let(:parent) { described_class.new([ parent_attribute ]) }
|
55
55
|
|
56
|
-
it {
|
56
|
+
it { is_expected.to equal(attribute_set) }
|
57
57
|
|
58
58
|
it 'yields the expected attributes' do
|
59
59
|
expect { subject }.to change { yields.dup }.
|
@@ -9,7 +9,7 @@ describe Virtus::AttributeSet, '#[]' do
|
|
9
9
|
let(:parent) { described_class.new }
|
10
10
|
let(:object) { described_class.new(parent, attributes) }
|
11
11
|
|
12
|
-
it {
|
12
|
+
it { is_expected.to equal(attribute) }
|
13
13
|
|
14
14
|
it 'allows indexed access to attributes by the string representation of their name' do
|
15
15
|
expect(object[name.to_s]).to equal(attribute)
|
@@ -11,7 +11,7 @@ describe Virtus::AttributeSet, '#[]=' do
|
|
11
11
|
context 'with a new attribute' do
|
12
12
|
let(:attribute) { Virtus::Attribute.build(String, :name => name) }
|
13
13
|
|
14
|
-
it {
|
14
|
+
it { is_expected.to equal(attribute) }
|
15
15
|
|
16
16
|
it 'adds an attribute' do
|
17
17
|
expect { subject }.to change { object.to_a }.from(attributes).to([ attribute ])
|
@@ -35,7 +35,7 @@ describe Virtus::AttributeSet, '#[]=' do
|
|
35
35
|
let(:attributes) { [ original ] }
|
36
36
|
let(:attribute) { Virtus::Attribute.build(String, :name => name) }
|
37
37
|
|
38
|
-
it {
|
38
|
+
it { is_expected.to equal(attribute) }
|
39
39
|
|
40
40
|
it 'replaces the original attribute' do
|
41
41
|
expect { subject }.to change { object.to_a }.from(attributes).to([ attribute ])
|