virtus 1.0.1 → 2.0.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 +5 -5
- data/.travis.yml +19 -15
- data/Changelog.md +43 -2
- data/Gemfile +5 -5
- data/README.md +113 -78
- data/Rakefile +13 -3
- data/lib/virtus.rb +46 -6
- data/lib/virtus/attribute.rb +21 -3
- data/lib/virtus/attribute/accessor.rb +11 -0
- data/lib/virtus/attribute/builder.rb +8 -13
- data/lib/virtus/attribute/collection.rb +12 -3
- data/lib/virtus/attribute/default_value.rb +2 -0
- data/lib/virtus/attribute/hash.rb +3 -3
- data/lib/virtus/attribute/nullify_blank.rb +24 -0
- data/lib/virtus/attribute/strict.rb +1 -1
- data/lib/virtus/attribute_set.rb +2 -2
- data/lib/virtus/builder.rb +2 -6
- data/lib/virtus/class_inclusions.rb +0 -1
- data/lib/virtus/coercer.rb +1 -0
- data/lib/virtus/configuration.rb +17 -36
- data/lib/virtus/extensions.rb +13 -21
- data/lib/virtus/instance_methods.rb +3 -2
- data/lib/virtus/model.rb +1 -3
- data/lib/virtus/module_extensions.rb +8 -2
- data/lib/virtus/support/equalizer.rb +1 -1
- data/lib/virtus/support/options.rb +2 -1
- data/lib/virtus/support/type_lookup.rb +1 -1
- data/lib/virtus/version.rb +1 -1
- data/spec/integration/attributes_attribute_spec.rb +28 -0
- data/spec/integration/building_module_spec.rb +22 -0
- data/spec/integration/collection_member_coercion_spec.rb +34 -13
- data/spec/integration/custom_attributes_spec.rb +2 -2
- data/spec/integration/custom_collection_attributes_spec.rb +6 -6
- data/spec/integration/default_values_spec.rb +8 -8
- data/spec/integration/defining_attributes_spec.rb +25 -18
- data/spec/integration/embedded_value_spec.rb +5 -5
- data/spec/integration/extending_objects_spec.rb +5 -5
- data/spec/integration/hash_attributes_coercion_spec.rb +16 -12
- data/spec/integration/mass_assignment_with_accessors_spec.rb +5 -5
- data/spec/integration/overriding_virtus_spec.rb +4 -4
- data/spec/integration/required_attributes_spec.rb +1 -1
- data/spec/integration/struct_as_embedded_value_spec.rb +4 -4
- data/spec/integration/using_modules_spec.rb +8 -8
- data/spec/integration/value_object_with_custom_constructor_spec.rb +4 -4
- data/spec/integration/virtus/instance_level_attributes_spec.rb +1 -1
- data/spec/integration/virtus/value_object_spec.rb +14 -14
- data/spec/shared/freeze_method_behavior.rb +6 -3
- data/spec/shared/idempotent_method_behaviour.rb +1 -1
- data/spec/shared/options_class_method.rb +3 -3
- data/spec/spec_helper.rb +2 -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 +64 -24
- data/spec/unit/virtus/attribute/class_methods/coerce_spec.rb +2 -2
- data/spec/unit/virtus/attribute/coerce_spec.rb +58 -10
- data/spec/unit/virtus/attribute/coercible_predicate_spec.rb +2 -2
- data/spec/unit/virtus/attribute/collection/class_methods/build_spec.rb +15 -4
- data/spec/unit/virtus/attribute/collection/coerce_spec.rb +25 -4
- 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 +8 -2
- data/spec/unit/virtus/attribute/defined_spec.rb +20 -0
- 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 +21 -9
- 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 +6 -6
- 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 +21 -16
- data/spec/unit/virtus/attribute_set/element_reference_spec.rb +2 -2
- data/spec/unit/virtus/attribute_set/element_set_spec.rb +17 -9
- data/spec/unit/virtus/attribute_set/merge_spec.rb +7 -5
- data/spec/unit/virtus/attribute_set/reset_spec.rb +22 -11
- data/spec/unit/virtus/attribute_spec.rb +8 -7
- data/spec/unit/virtus/attributes_reader_spec.rb +1 -1
- data/spec/unit/virtus/attributes_writer_spec.rb +1 -1
- data/spec/unit/virtus/element_reader_spec.rb +1 -1
- data/spec/unit/virtus/freeze_spec.rb +23 -3
- data/spec/unit/virtus/model_spec.rb +38 -7
- data/spec/unit/virtus/module_spec.rb +59 -2
- data/spec/unit/virtus/set_default_attributes_spec.rb +10 -3
- data/spec/unit/virtus/value_object_spec.rb +15 -5
- data/virtus.gemspec +7 -5
- metadata +46 -44
- data/.ruby-version +0 -1
- data/Gemfile.devtools +0 -54
- 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
@@ -23,28 +23,32 @@ describe Package do
|
|
23
23
|
describe '#dimensions' do
|
24
24
|
subject { dimensions }
|
25
25
|
|
26
|
-
it
|
27
|
-
|
28
|
-
|
29
|
-
it {
|
26
|
+
it 'has 3 keys' do
|
27
|
+
expect(subject.keys.size).to eq(3)
|
28
|
+
end
|
29
|
+
it { is_expected.to have_key :width }
|
30
|
+
it { is_expected.to have_key :height }
|
31
|
+
it { is_expected.to have_key :length }
|
30
32
|
|
31
33
|
it 'should be coerced to [Symbol => Float] format' do
|
32
|
-
dimensions[:width].
|
33
|
-
dimensions[:height].
|
34
|
-
dimensions[:length].
|
34
|
+
expect(dimensions[:width]).to be_eql(2.2)
|
35
|
+
expect(dimensions[:height]).to be_eql(2.0)
|
36
|
+
expect(dimensions[:length]).to be_eql(4.5)
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
40
|
describe '#meta_info' do
|
39
41
|
subject { meta_info }
|
40
42
|
|
41
|
-
it
|
42
|
-
|
43
|
-
|
43
|
+
it 'has 2 keys' do
|
44
|
+
expect(subject.keys.size).to eq(2)
|
45
|
+
end
|
46
|
+
it { is_expected.to have_key 'from' }
|
47
|
+
it { is_expected.to have_key 'to' }
|
44
48
|
|
45
49
|
it 'should be coerced to [String => String] format' do
|
46
|
-
meta_info['from'].
|
47
|
-
meta_info['to'].
|
50
|
+
expect(meta_info['from']).to eq('Me')
|
51
|
+
expect(meta_info['to']).to eq('You')
|
48
52
|
end
|
49
53
|
end
|
50
54
|
end
|
@@ -28,17 +28,17 @@ describe "mass assignment with accessors" do
|
|
28
28
|
subject { Examples::Product.new(:categories => ['Office', 'Printers'], :_id => 100) }
|
29
29
|
|
30
30
|
specify 'works uppon instantiation' do
|
31
|
-
subject.category.
|
32
|
-
subject.subcategory.
|
31
|
+
expect(subject.category).to eq('Office')
|
32
|
+
expect(subject.subcategory).to eq('Printers')
|
33
33
|
end
|
34
34
|
|
35
35
|
specify 'can be set with #attributes=' do
|
36
36
|
subject.attributes = {:categories => ['Home', 'Furniture']}
|
37
|
-
subject.category.
|
38
|
-
subject.subcategory.
|
37
|
+
expect(subject.category).to eq('Home')
|
38
|
+
expect(subject.subcategory).to eq('Furniture')
|
39
39
|
end
|
40
40
|
|
41
41
|
specify 'respects accessor visibility' do
|
42
|
-
subject.id.
|
42
|
+
expect(subject.id).not_to eq(100)
|
43
43
|
end
|
44
44
|
end
|
@@ -22,11 +22,11 @@ describe 'overriding virtus behavior' do
|
|
22
22
|
|
23
23
|
describe 'overriding an attribute getter' do
|
24
24
|
specify 'calls the defined getter' do
|
25
|
-
Examples::Article.new.title.
|
25
|
+
expect(Examples::Article.new.title).to eq('<unknown>')
|
26
26
|
end
|
27
27
|
|
28
28
|
specify 'super can be used to access the getter defined by virtus' do
|
29
|
-
Examples::Article.new(:title => 'example article').title.
|
29
|
+
expect(Examples::Article.new(:title => 'example article').title).to eq('example article')
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -34,13 +34,13 @@ describe 'overriding virtus behavior' do
|
|
34
34
|
specify 'calls the defined setter' do
|
35
35
|
article = Examples::Article.new(:title => "can't be changed")
|
36
36
|
article.title = 'this will never be assigned'
|
37
|
-
article.title.
|
37
|
+
expect(article.title).to eq("can't be changed")
|
38
38
|
end
|
39
39
|
|
40
40
|
specify 'super can be used to access the setter defined by virtus' do
|
41
41
|
article = Examples::Article.new(:title => 'example article')
|
42
42
|
article.title = 'my new title'
|
43
|
-
article.title.
|
43
|
+
expect(article.title).to eq('my new title')
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -13,7 +13,7 @@ describe 'Using required attributes' do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'raises coercion error when required attribute is nil' do
|
16
|
-
expect { Examples::User.new(:name => nil) }.to raise_error(Virtus::CoercionError)
|
16
|
+
expect { Examples::User.new(:name => nil) }.to raise_error(Virtus::CoercionError, "Failed to coerce attribute `name' from nil into String")
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'does not raise coercion error when not required attribute is nil' do
|
@@ -19,10 +19,10 @@ describe 'Using Struct as an embedded value attribute' do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
specify 'initialize a struct object with correct attributes' do
|
22
|
-
subject.top_left.x.
|
23
|
-
subject.top_left.y.
|
22
|
+
expect(subject.top_left.x).to be(3)
|
23
|
+
expect(subject.top_left.y).to be(5)
|
24
24
|
|
25
|
-
subject.bottom_right.x.
|
26
|
-
subject.bottom_right.y.
|
25
|
+
expect(subject.bottom_right.x).to be(8)
|
26
|
+
expect(subject.bottom_right.y).to be(7)
|
27
27
|
end
|
28
28
|
end
|
@@ -33,15 +33,15 @@ describe 'I can define attributes within a module' do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
specify 'including a module with attributes into a class' do
|
36
|
-
Examples::User.attribute_set[:name].
|
37
|
-
Examples::User.attribute_set[:gamer].
|
36
|
+
expect(Examples::User.attribute_set[:name]).to be_instance_of(Virtus::Attribute)
|
37
|
+
expect(Examples::User.attribute_set[:gamer]).to be_instance_of(Virtus::Attribute::Boolean)
|
38
38
|
|
39
|
-
Examples::Admin.attribute_set[:name].
|
40
|
-
Examples::Admin.attribute_set[:age].
|
39
|
+
expect(Examples::Admin.attribute_set[:name]).to be_instance_of(Virtus::Attribute)
|
40
|
+
expect(Examples::Admin.attribute_set[:age]).to be_instance_of(Virtus::Attribute)
|
41
41
|
|
42
42
|
user = Examples::Admin.new(:name => 'Piotr', :age => 29)
|
43
|
-
user.name.
|
44
|
-
user.age.
|
43
|
+
expect(user.name).to eql('Piotr')
|
44
|
+
expect(user.age).to eql(29)
|
45
45
|
end
|
46
46
|
|
47
47
|
specify 'including a module with attributes into an instance' do
|
@@ -49,7 +49,7 @@ describe 'I can define attributes within a module' do
|
|
49
49
|
moderator.extend(Examples::Name, Examples::Age)
|
50
50
|
|
51
51
|
moderator.attributes = { :name => 'John', :age => 21 }
|
52
|
-
moderator.name.
|
53
|
-
moderator.age.
|
52
|
+
expect(moderator.name).to eql('John')
|
53
|
+
expect(moderator.age).to eql(21)
|
54
54
|
end
|
55
55
|
end
|
@@ -33,10 +33,10 @@ describe "Defining a ValueObject with a custom constructor" do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
specify "initialize a value object attribute with correct attributes" do
|
36
|
-
subject.top_left.x.
|
37
|
-
subject.top_left.y.
|
36
|
+
expect(subject.top_left.x).to be(3)
|
37
|
+
expect(subject.top_left.y).to be(4)
|
38
38
|
|
39
|
-
subject.bottom_right.x.
|
40
|
-
subject.bottom_right.y.
|
39
|
+
expect(subject.bottom_right.x).to be(5)
|
40
|
+
expect(subject.bottom_right.y).to be(8)
|
41
41
|
end
|
42
42
|
end
|
@@ -26,21 +26,21 @@ describe Virtus::ValueObject do
|
|
26
26
|
|
27
27
|
describe 'initialization' do
|
28
28
|
it 'sets the attribute values provided to Class.new' do
|
29
|
-
class_under_test.new(:latitude => 10000.001).latitude.
|
30
|
-
subject.latitude.
|
29
|
+
expect(class_under_test.new(:latitude => 10000.001).latitude).to eq(10000.001)
|
30
|
+
expect(subject.latitude).to eql(attribute_values[:latitude])
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
34
|
describe 'writer visibility' do
|
35
35
|
it 'attributes are configured for private writers' do
|
36
|
-
class_under_test.attribute_set[:latitude].public_reader
|
37
|
-
class_under_test.attribute_set[:longitude].public_writer
|
36
|
+
expect(class_under_test.attribute_set[:latitude].public_reader?).to be(true)
|
37
|
+
expect(class_under_test.attribute_set[:longitude].public_writer?).to be(false)
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'writer methods are set to private' do
|
41
41
|
private_methods = class_under_test.private_instance_methods
|
42
42
|
private_methods.map! { |m| m.to_s }
|
43
|
-
private_methods.
|
43
|
+
expect(private_methods).to include('latitude=', 'longitude=', 'attributes=')
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'attempts to call attribute writer methods raises NameError' do
|
@@ -52,48 +52,48 @@ describe Virtus::ValueObject do
|
|
52
52
|
describe 'equality' do
|
53
53
|
describe '#==' do
|
54
54
|
it 'returns true for different objects with the same state' do
|
55
|
-
subject.
|
55
|
+
expect(subject).to eq(instance_with_equal_state)
|
56
56
|
end
|
57
57
|
|
58
58
|
it 'returns false for different objects with different state' do
|
59
|
-
subject.
|
59
|
+
expect(subject).not_to eq(instance_with_different_state)
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
63
|
describe '#eql?' do
|
64
64
|
it 'returns true for different objects with the same state' do
|
65
|
-
subject.
|
65
|
+
expect(subject).to eql(instance_with_equal_state)
|
66
66
|
end
|
67
67
|
|
68
68
|
it 'returns false for different objects with different state' do
|
69
|
-
subject.
|
69
|
+
expect(subject).not_to eql(instance_with_different_state)
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
73
|
describe '#equal?' do
|
74
74
|
it 'returns false for different objects with the same state' do
|
75
|
-
subject.
|
75
|
+
expect(subject).not_to equal(instance_with_equal_state)
|
76
76
|
end
|
77
77
|
|
78
78
|
it 'returns false for different objects with different state' do
|
79
|
-
subject.
|
79
|
+
expect(subject).not_to equal(instance_with_different_state)
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
83
|
describe '#hash' do
|
84
84
|
it 'returns the same value for different objects with the same state' do
|
85
|
-
subject.hash.
|
85
|
+
expect(subject.hash).to eql(instance_with_equal_state.hash)
|
86
86
|
end
|
87
87
|
|
88
88
|
it 'returns different values for different objects with different state' do
|
89
|
-
subject.hash.
|
89
|
+
expect(subject.hash).not_to eql(instance_with_different_state.hash)
|
90
90
|
end
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
94
|
describe '#inspect' do
|
95
95
|
it 'includes the class name and attribute values' do
|
96
|
-
subject.inspect.
|
96
|
+
expect(subject.inspect).to eq('#<GeoLocation latitude=10.0 longitude=20.0>')
|
97
97
|
end
|
98
98
|
end
|
99
99
|
end
|
@@ -20,7 +20,7 @@ shared_examples_for 'a #freeze method' do
|
|
20
20
|
it_should_behave_like 'an idempotent method'
|
21
21
|
|
22
22
|
it 'returns object' do
|
23
|
-
|
23
|
+
is_expected.to be(object)
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'prevents future modifications' do
|
@@ -29,9 +29,12 @@ shared_examples_for 'a #freeze method' do
|
|
29
29
|
expect { object.instance_variable_set(:@foo, :bar) }.to(expectation)
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
describe '#frozen?' do
|
33
|
+
subject { super().frozen? }
|
34
|
+
it { is_expected.to be(true) }
|
35
|
+
end
|
33
36
|
|
34
37
|
it 'allows to access attribute' do
|
35
|
-
subject.name.
|
38
|
+
expect(subject.name).to eql('John')
|
36
39
|
end
|
37
40
|
end
|
@@ -2,15 +2,15 @@ shared_examples_for 'an options class method' do
|
|
2
2
|
context 'with no argument' do
|
3
3
|
subject { object.send(method) }
|
4
4
|
|
5
|
-
it {
|
5
|
+
it { is_expected.to be(default) }
|
6
6
|
end
|
7
7
|
|
8
8
|
context 'with a default value' do
|
9
9
|
subject { object.send(method, value) }
|
10
10
|
|
11
|
-
let(:value) {
|
11
|
+
let(:value) { mock('value') }
|
12
12
|
|
13
|
-
it {
|
13
|
+
it { is_expected.to equal(object) }
|
14
14
|
|
15
15
|
it 'sets the default value for the class method' do
|
16
16
|
expect { subject }.to change { object.send(method) }.from(default).to(value)
|
data/spec/spec_helper.rb
CHANGED
@@ -1,25 +1,11 @@
|
|
1
|
-
if
|
1
|
+
if RUBY_ENGINE == 'ruby' && RUBY_VERSION >= '3.0'
|
2
2
|
require 'simplecov'
|
3
|
-
|
4
|
-
|
5
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
6
|
-
SimpleCov::Formatter::HTMLFormatter,
|
7
|
-
Coveralls::SimpleCov::Formatter
|
8
|
-
]
|
9
|
-
|
10
|
-
SimpleCov.start do
|
11
|
-
command_name 'spec:unit'
|
12
|
-
add_filter 'config/'
|
13
|
-
add_filter 'spec'
|
14
|
-
add_filter '.bundle'
|
15
|
-
minimum_coverage 98
|
16
|
-
end
|
3
|
+
SimpleCov.start
|
17
4
|
end
|
18
5
|
|
19
6
|
require 'rspec'
|
20
7
|
require 'bogus/rspec'
|
21
8
|
require 'virtus'
|
22
|
-
require 'inflecto' # for resolving namespaced constant names
|
23
9
|
|
24
10
|
module Virtus
|
25
11
|
def self.warn(*)
|
@@ -33,7 +19,6 @@ ENV['TZ'] = 'UTC'
|
|
33
19
|
Dir[File.expand_path('../shared/**/*.rb', __FILE__)].each { |file| require file }
|
34
20
|
|
35
21
|
RSpec.configure do |config|
|
36
|
-
|
37
22
|
# Remove anonymous- and example- Attribute classes from Attribute descendants
|
38
23
|
config.after :all do
|
39
24
|
stack = [ Virtus::Attribute ]
|
@@ -53,5 +38,4 @@ RSpec.configure do |config|
|
|
53
38
|
end
|
54
39
|
end
|
55
40
|
end
|
56
|
-
|
57
41
|
end
|
@@ -10,13 +10,13 @@ describe Virtus::Attribute::Boolean, '#coerce' do
|
|
10
10
|
context 'with a truthy value' do
|
11
11
|
let(:input) { 1 }
|
12
12
|
|
13
|
-
it {
|
13
|
+
it { is_expected.to be(true) }
|
14
14
|
end
|
15
15
|
|
16
16
|
context 'with a falsy value' do
|
17
17
|
let(:input) { 0 }
|
18
18
|
|
19
|
-
it {
|
19
|
+
it { is_expected.to be(false) }
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -26,7 +26,7 @@ describe Virtus::Attribute::Boolean, '#coerce' do
|
|
26
26
|
context 'with a coercible input' do
|
27
27
|
let(:input) { 1 }
|
28
28
|
|
29
|
-
it {
|
29
|
+
it { is_expected.to be(true) }
|
30
30
|
end
|
31
31
|
|
32
32
|
context 'with a non-coercible input' do
|
@@ -8,18 +8,18 @@ describe Virtus::Attribute::Boolean, '#value_coerced?' do
|
|
8
8
|
context 'when input is true' do
|
9
9
|
let(:input) { true }
|
10
10
|
|
11
|
-
it {
|
11
|
+
it { is_expected.to be(true) }
|
12
12
|
end
|
13
13
|
|
14
14
|
context 'when input is false' do
|
15
15
|
let(:input) { false }
|
16
16
|
|
17
|
-
it {
|
17
|
+
it { is_expected.to be(true) }
|
18
18
|
end
|
19
19
|
|
20
20
|
context 'when input is not coerced' do
|
21
21
|
let(:input) { 1 }
|
22
22
|
|
23
|
-
it {
|
23
|
+
it { is_expected.to be(false) }
|
24
24
|
end
|
25
25
|
end
|
@@ -7,19 +7,19 @@ describe Virtus::Attribute, '.build' do
|
|
7
7
|
let(:type) { String }
|
8
8
|
let(:options) { {} }
|
9
9
|
|
10
|
-
|
11
|
-
it {
|
10
|
+
shared_examples_for 'a valid attribute instance' do
|
11
|
+
it { is_expected.to be_instance_of(Virtus::Attribute) }
|
12
12
|
|
13
|
-
it {
|
13
|
+
it { is_expected.to be_frozen }
|
14
14
|
end
|
15
15
|
|
16
16
|
context 'without options' do
|
17
17
|
it_behaves_like 'a valid attribute instance'
|
18
18
|
|
19
|
-
it {
|
20
|
-
it {
|
21
|
-
it {
|
22
|
-
it {
|
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
23
|
|
24
24
|
it 'sets up a coercer' do
|
25
25
|
expect(subject.options[:coerce]).to be(true)
|
@@ -30,7 +30,10 @@ describe Virtus::Attribute, '.build' do
|
|
30
30
|
context 'when name is passed as a string' do
|
31
31
|
let(:name) { 'something' }
|
32
32
|
|
33
|
-
|
33
|
+
describe '#name' do
|
34
|
+
subject { super().name }
|
35
|
+
it { is_expected.to be(:something) }
|
36
|
+
end
|
34
37
|
end
|
35
38
|
|
36
39
|
context 'when coercion is turned off in options' do
|
@@ -38,7 +41,7 @@ describe Virtus::Attribute, '.build' do
|
|
38
41
|
|
39
42
|
it_behaves_like 'a valid attribute instance'
|
40
43
|
|
41
|
-
it {
|
44
|
+
it { is_expected.not_to be_coercible }
|
42
45
|
end
|
43
46
|
|
44
47
|
context 'when options specify reader visibility' do
|
@@ -46,8 +49,8 @@ describe Virtus::Attribute, '.build' do
|
|
46
49
|
|
47
50
|
it_behaves_like 'a valid attribute instance'
|
48
51
|
|
49
|
-
it {
|
50
|
-
it {
|
52
|
+
it { is_expected.not_to be_public_reader }
|
53
|
+
it { is_expected.to be_public_writer }
|
51
54
|
end
|
52
55
|
|
53
56
|
context 'when options specify writer visibility' do
|
@@ -55,8 +58,8 @@ describe Virtus::Attribute, '.build' do
|
|
55
58
|
|
56
59
|
it_behaves_like 'a valid attribute instance'
|
57
60
|
|
58
|
-
it {
|
59
|
-
it {
|
61
|
+
it { is_expected.to be_public_reader }
|
62
|
+
it { is_expected.not_to be_public_writer }
|
60
63
|
end
|
61
64
|
|
62
65
|
context 'when options specify lazy accessor' do
|
@@ -64,7 +67,7 @@ describe Virtus::Attribute, '.build' do
|
|
64
67
|
|
65
68
|
it_behaves_like 'a valid attribute instance'
|
66
69
|
|
67
|
-
it {
|
70
|
+
it { is_expected.to be_lazy }
|
68
71
|
end
|
69
72
|
|
70
73
|
context 'when options specify strict mode' do
|
@@ -72,7 +75,15 @@ describe Virtus::Attribute, '.build' do
|
|
72
75
|
|
73
76
|
it_behaves_like 'a valid attribute instance'
|
74
77
|
|
75
|
-
it {
|
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 }
|
76
87
|
end
|
77
88
|
|
78
89
|
context 'when type is a string' do
|
@@ -80,7 +91,21 @@ describe Virtus::Attribute, '.build' do
|
|
80
91
|
|
81
92
|
it_behaves_like 'a valid attribute instance'
|
82
93
|
|
83
|
-
|
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
|
84
109
|
end
|
85
110
|
|
86
111
|
context 'when type is a symbol of an existing class constant' do
|
@@ -88,7 +113,10 @@ describe Virtus::Attribute, '.build' do
|
|
88
113
|
|
89
114
|
it_behaves_like 'a valid attribute instance'
|
90
115
|
|
91
|
-
|
116
|
+
describe '#type' do
|
117
|
+
subject { super().type }
|
118
|
+
it { is_expected.to be(Axiom::Types::String) }
|
119
|
+
end
|
92
120
|
end
|
93
121
|
|
94
122
|
context 'when type is an axiom type' do
|
@@ -96,7 +124,10 @@ describe Virtus::Attribute, '.build' do
|
|
96
124
|
|
97
125
|
it_behaves_like 'a valid attribute instance'
|
98
126
|
|
99
|
-
|
127
|
+
describe '#type' do
|
128
|
+
subject { super().type }
|
129
|
+
it { is_expected.to be(type) }
|
130
|
+
end
|
100
131
|
end
|
101
132
|
|
102
133
|
context 'when custom attribute class exists for a given primitive' do
|
@@ -107,9 +138,12 @@ describe Virtus::Attribute, '.build' do
|
|
107
138
|
attribute.primitive(type)
|
108
139
|
end
|
109
140
|
|
110
|
-
it {
|
141
|
+
it { is_expected.to be_instance_of(attribute) }
|
111
142
|
|
112
|
-
|
143
|
+
describe '#type' do
|
144
|
+
subject { super().type }
|
145
|
+
it { is_expected.to be(Axiom::Types::Object) }
|
146
|
+
end
|
113
147
|
end
|
114
148
|
|
115
149
|
context 'when custom attribute class exists for a given array with member coercion defined' do
|
@@ -120,9 +154,12 @@ describe Virtus::Attribute, '.build' do
|
|
120
154
|
attribute.primitive(type.class)
|
121
155
|
end
|
122
156
|
|
123
|
-
it {
|
157
|
+
it { is_expected.to be_instance_of(attribute) }
|
124
158
|
|
125
|
-
|
159
|
+
describe '#type' do
|
160
|
+
subject { super().type }
|
161
|
+
it { is_expected.to be < Axiom::Types::Collection }
|
162
|
+
end
|
126
163
|
end
|
127
164
|
|
128
165
|
context 'when custom collection-like attribute class exists for a given enumerable primitive' do
|
@@ -133,8 +170,11 @@ describe Virtus::Attribute, '.build' do
|
|
133
170
|
attribute.primitive(type)
|
134
171
|
end
|
135
172
|
|
136
|
-
it {
|
173
|
+
it { is_expected.to be_instance_of(attribute) }
|
137
174
|
|
138
|
-
|
175
|
+
describe '#type' do
|
176
|
+
subject { super().type }
|
177
|
+
it { is_expected.to be < Axiom::Types::Collection }
|
178
|
+
end
|
139
179
|
end
|
140
180
|
end
|