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.
Files changed (118) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +39 -0
  3. data/.rspec +2 -0
  4. data/.yardopts +1 -0
  5. data/CONTRIBUTING.md +18 -0
  6. data/Changelog.md +258 -0
  7. data/Gemfile +10 -0
  8. data/Guardfile +19 -0
  9. data/LICENSE +20 -0
  10. data/README.md +630 -0
  11. data/Rakefile +15 -0
  12. data/TODO.md +6 -0
  13. data/lib/virtus/attribute/accessor.rb +103 -0
  14. data/lib/virtus/attribute/boolean.rb +55 -0
  15. data/lib/virtus/attribute/builder.rb +182 -0
  16. data/lib/virtus/attribute/coercer.rb +45 -0
  17. data/lib/virtus/attribute/coercible.rb +20 -0
  18. data/lib/virtus/attribute/collection.rb +103 -0
  19. data/lib/virtus/attribute/default_value/from_callable.rb +35 -0
  20. data/lib/virtus/attribute/default_value/from_clonable.rb +35 -0
  21. data/lib/virtus/attribute/default_value/from_symbol.rb +35 -0
  22. data/lib/virtus/attribute/default_value.rb +51 -0
  23. data/lib/virtus/attribute/embedded_value.rb +67 -0
  24. data/lib/virtus/attribute/enum.rb +45 -0
  25. data/lib/virtus/attribute/hash.rb +130 -0
  26. data/lib/virtus/attribute/lazy_default.rb +18 -0
  27. data/lib/virtus/attribute/nullify_blank.rb +24 -0
  28. data/lib/virtus/attribute/strict.rb +26 -0
  29. data/lib/virtus/attribute.rb +245 -0
  30. data/lib/virtus/attribute_set.rb +240 -0
  31. data/lib/virtus/builder/hook_context.rb +51 -0
  32. data/lib/virtus/builder.rb +133 -0
  33. data/lib/virtus/class_inclusions.rb +48 -0
  34. data/lib/virtus/class_methods.rb +90 -0
  35. data/lib/virtus/coercer.rb +41 -0
  36. data/lib/virtus/configuration.rb +72 -0
  37. data/lib/virtus/const_missing_extensions.rb +18 -0
  38. data/lib/virtus/extensions.rb +105 -0
  39. data/lib/virtus/instance_methods.rb +218 -0
  40. data/lib/virtus/model.rb +68 -0
  41. data/lib/virtus/module_extensions.rb +88 -0
  42. data/lib/virtus/support/equalizer.rb +128 -0
  43. data/lib/virtus/support/options.rb +113 -0
  44. data/lib/virtus/support/type_lookup.rb +109 -0
  45. data/lib/virtus/value_object.rb +150 -0
  46. data/lib/virtus/version.rb +3 -0
  47. data/lib/virtus.rb +310 -0
  48. data/spec/integration/attributes_attribute_spec.rb +28 -0
  49. data/spec/integration/building_module_spec.rb +90 -0
  50. data/spec/integration/collection_member_coercion_spec.rb +96 -0
  51. data/spec/integration/custom_attributes_spec.rb +42 -0
  52. data/spec/integration/custom_collection_attributes_spec.rb +101 -0
  53. data/spec/integration/default_values_spec.rb +87 -0
  54. data/spec/integration/defining_attributes_spec.rb +86 -0
  55. data/spec/integration/embedded_value_spec.rb +50 -0
  56. data/spec/integration/extending_objects_spec.rb +35 -0
  57. data/spec/integration/hash_attributes_coercion_spec.rb +54 -0
  58. data/spec/integration/inheritance_spec.rb +42 -0
  59. data/spec/integration/injectible_coercers_spec.rb +48 -0
  60. data/spec/integration/mass_assignment_with_accessors_spec.rb +44 -0
  61. data/spec/integration/overriding_virtus_spec.rb +46 -0
  62. data/spec/integration/required_attributes_spec.rb +25 -0
  63. data/spec/integration/struct_as_embedded_value_spec.rb +28 -0
  64. data/spec/integration/using_modules_spec.rb +55 -0
  65. data/spec/integration/value_object_with_custom_constructor_spec.rb +42 -0
  66. data/spec/integration/virtus/instance_level_attributes_spec.rb +23 -0
  67. data/spec/integration/virtus/value_object_spec.rb +99 -0
  68. data/spec/shared/constants_helpers.rb +9 -0
  69. data/spec/shared/freeze_method_behavior.rb +40 -0
  70. data/spec/shared/idempotent_method_behaviour.rb +5 -0
  71. data/spec/shared/options_class_method.rb +19 -0
  72. data/spec/spec_helper.rb +41 -0
  73. data/spec/unit/virtus/attribute/boolean/coerce_spec.rb +43 -0
  74. data/spec/unit/virtus/attribute/boolean/value_coerced_predicate_spec.rb +25 -0
  75. data/spec/unit/virtus/attribute/class_methods/build_spec.rb +180 -0
  76. data/spec/unit/virtus/attribute/class_methods/coerce_spec.rb +32 -0
  77. data/spec/unit/virtus/attribute/coerce_spec.rb +129 -0
  78. data/spec/unit/virtus/attribute/coercible_predicate_spec.rb +20 -0
  79. data/spec/unit/virtus/attribute/collection/class_methods/build_spec.rb +105 -0
  80. data/spec/unit/virtus/attribute/collection/coerce_spec.rb +74 -0
  81. data/spec/unit/virtus/attribute/collection/value_coerced_predicate_spec.rb +31 -0
  82. data/spec/unit/virtus/attribute/comparison_spec.rb +20 -0
  83. data/spec/unit/virtus/attribute/custom_collection_spec.rb +29 -0
  84. data/spec/unit/virtus/attribute/defined_spec.rb +20 -0
  85. data/spec/unit/virtus/attribute/embedded_value/class_methods/build_spec.rb +70 -0
  86. data/spec/unit/virtus/attribute/embedded_value/coerce_spec.rb +91 -0
  87. data/spec/unit/virtus/attribute/get_spec.rb +32 -0
  88. data/spec/unit/virtus/attribute/hash/class_methods/build_spec.rb +106 -0
  89. data/spec/unit/virtus/attribute/hash/coerce_spec.rb +92 -0
  90. data/spec/unit/virtus/attribute/lazy_predicate_spec.rb +20 -0
  91. data/spec/unit/virtus/attribute/rename_spec.rb +16 -0
  92. data/spec/unit/virtus/attribute/required_predicate_spec.rb +19 -0
  93. data/spec/unit/virtus/attribute/set_default_value_spec.rb +107 -0
  94. data/spec/unit/virtus/attribute/set_spec.rb +29 -0
  95. data/spec/unit/virtus/attribute/value_coerced_predicate_spec.rb +19 -0
  96. data/spec/unit/virtus/attribute_set/append_spec.rb +47 -0
  97. data/spec/unit/virtus/attribute_set/define_reader_method_spec.rb +36 -0
  98. data/spec/unit/virtus/attribute_set/define_writer_method_spec.rb +36 -0
  99. data/spec/unit/virtus/attribute_set/each_spec.rb +65 -0
  100. data/spec/unit/virtus/attribute_set/element_reference_spec.rb +17 -0
  101. data/spec/unit/virtus/attribute_set/element_set_spec.rb +64 -0
  102. data/spec/unit/virtus/attribute_set/merge_spec.rb +34 -0
  103. data/spec/unit/virtus/attribute_set/reset_spec.rb +71 -0
  104. data/spec/unit/virtus/attribute_spec.rb +229 -0
  105. data/spec/unit/virtus/attributes_reader_spec.rb +41 -0
  106. data/spec/unit/virtus/attributes_writer_spec.rb +51 -0
  107. data/spec/unit/virtus/class_methods/finalize_spec.rb +67 -0
  108. data/spec/unit/virtus/class_methods/new_spec.rb +39 -0
  109. data/spec/unit/virtus/config_spec.rb +13 -0
  110. data/spec/unit/virtus/element_reader_spec.rb +21 -0
  111. data/spec/unit/virtus/element_writer_spec.rb +19 -0
  112. data/spec/unit/virtus/freeze_spec.rb +41 -0
  113. data/spec/unit/virtus/model_spec.rb +197 -0
  114. data/spec/unit/virtus/module_spec.rb +174 -0
  115. data/spec/unit/virtus/set_default_attributes_spec.rb +32 -0
  116. data/spec/unit/virtus/value_object_spec.rb +138 -0
  117. data/virtus2.gemspec +26 -0
  118. metadata +225 -0
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::AttributeSet, '#<<' do
4
+ subject { object << attribute }
5
+
6
+ let(:attributes) { [] }
7
+ let(:parent) { described_class.new }
8
+ let(:object) { described_class.new(parent, attributes) }
9
+ let(:name) { :name }
10
+
11
+ context 'with a new attribute' do
12
+ let(:attribute) { Virtus::Attribute.build(String, :name => name) }
13
+
14
+ it { is_expected.to equal(object) }
15
+
16
+ it 'adds an attribute' do
17
+ expect { subject }.to change { object.to_a }.
18
+ from(attributes).
19
+ to([ attribute ])
20
+ end
21
+
22
+ it 'indexes the new attribute under its #name property' do
23
+ expect { subject }.to change { object[name] }.
24
+ from(nil).
25
+ to(attribute)
26
+ end
27
+
28
+ it 'indexes the new attribute under the string version of its #name property' do
29
+ expect { subject }.to change { object[name.to_s] }.
30
+ from(nil).
31
+ to(attribute)
32
+ end
33
+ end
34
+
35
+ context 'with a duplicate attribute' do
36
+ let(:attributes) { [Virtus::Attribute.build(String, :name => name)] }
37
+ let(:attribute) { Virtus::Attribute.build(String, :name => name) }
38
+
39
+ it { is_expected.to equal(object) }
40
+
41
+ it "replaces the original attribute object" do
42
+ expect { subject }.to change { object.to_a.map(&:__id__) }.
43
+ from(attributes.map(&:__id__)).
44
+ to([attribute.__id__])
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::AttributeSet, '#define_reader_method' do
4
+ subject(:attribute_set) { described_class.new }
5
+
6
+ let(:attribute) { Virtus::Attribute.build(String, :name => method_name) }
7
+ let(:method_name) { :foo_bar }
8
+
9
+ before do
10
+ attribute_set.define_reader_method(attribute, method_name, visibility)
11
+ end
12
+
13
+ context "with public visibility" do
14
+ let(:visibility) { :public }
15
+
16
+ it "defines public writer" do
17
+ expect(attribute_set.public_instance_methods).to include(method_name)
18
+ end
19
+ end
20
+
21
+ context "with private visibility" do
22
+ let(:visibility) { :private }
23
+
24
+ it "defines public writer" do
25
+ expect(attribute_set.private_instance_methods).to include(method_name)
26
+ end
27
+ end
28
+
29
+ context "with protected visibility" do
30
+ let(:visibility) { :protected }
31
+
32
+ it "defines protected writer" do
33
+ expect(attribute_set.protected_instance_methods).to include(method_name)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::AttributeSet, '#define_writer_method' do
4
+ subject(:attribute_set) { described_class.new }
5
+
6
+ let(:attribute) { Virtus::Attribute.build(String, :name => method_name) }
7
+ let(:method_name) { :foo_bar }
8
+
9
+ before do
10
+ attribute_set.define_writer_method(attribute, method_name, visibility)
11
+ end
12
+
13
+ context "with public visibility" do
14
+ let(:visibility) { :public }
15
+
16
+ it "defines public writer" do
17
+ expect(attribute_set.public_instance_methods).to include(method_name)
18
+ end
19
+ end
20
+
21
+ context "with private visibility" do
22
+ let(:visibility) { :private }
23
+
24
+ it "defines private writer" do
25
+ expect(attribute_set.private_instance_methods).to include(method_name)
26
+ end
27
+ end
28
+
29
+ context "with protected visibility" do
30
+ let(:visibility) { :protected }
31
+
32
+ it "defines protected writer" do
33
+ expect(attribute_set.protected_instance_methods).to include(method_name)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::AttributeSet, '#each' do
4
+ subject(:attribute_set) { described_class.new(parent, attributes) }
5
+
6
+ let(:name) { :name }
7
+ let(:attribute) { Virtus::Attribute.build(String, :name => :name) }
8
+ let(:attributes) { [ attribute ] }
9
+ let(:parent) { described_class.new }
10
+ let(:yields) { Set[] }
11
+
12
+ context 'with no block' do
13
+ it 'returns an enumerator when block is not provided' do
14
+ expect(attribute_set.each).to be_kind_of(Enumerator)
15
+ end
16
+
17
+ it 'yields the expected attributes' do
18
+ result = []
19
+ attribute_set.each { |attribute| result << attribute }
20
+ expect(result).to eql(attributes)
21
+ end
22
+ end
23
+
24
+ context 'with a block' do
25
+ subject { attribute_set.each { |attribute| yields << attribute } }
26
+
27
+ context 'when the parent has no attributes' do
28
+ it { is_expected.to equal(attribute_set) }
29
+
30
+ it 'yields the expected attributes' do
31
+ expect { subject }.to change { yields.dup }.
32
+ from(Set[]).
33
+ to(attributes.to_set)
34
+ end
35
+ end
36
+
37
+ context 'when the parent has attributes that are not duplicates' do
38
+ let(:parent_attribute) { Virtus::Attribute.build(String, :name => :parent_name) }
39
+ let(:parent) { described_class.new([ parent_attribute ]) }
40
+
41
+ it { is_expected.to equal(attribute_set) }
42
+
43
+ it 'yields the expected attributes' do
44
+ result = []
45
+
46
+ attribute_set.each { |attribute| result << attribute }
47
+
48
+ expect(result).to eql([parent_attribute, attribute])
49
+ end
50
+ end
51
+
52
+ context 'when the parent has attributes that are duplicates' do
53
+ let(:parent_attribute) { Virtus::Attribute.build(String, :name => name) }
54
+ let(:parent) { described_class.new([ parent_attribute ]) }
55
+
56
+ it { is_expected.to equal(attribute_set) }
57
+
58
+ it 'yields the expected attributes' do
59
+ expect { subject }.to change { yields.dup }.
60
+ from(Set[]).
61
+ to(Set[ attribute ])
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::AttributeSet, '#[]' do
4
+ subject { object[name] }
5
+
6
+ let(:name) { :name }
7
+ let(:attribute) { Virtus::Attribute.build(String, :name => :name) }
8
+ let(:attributes) { [ attribute ] }
9
+ let(:parent) { described_class.new }
10
+ let(:object) { described_class.new(parent, attributes) }
11
+
12
+ it { is_expected.to equal(attribute) }
13
+
14
+ it 'allows indexed access to attributes by the string representation of their name' do
15
+ expect(object[name.to_s]).to equal(attribute)
16
+ end
17
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::AttributeSet, '#[]=' do
4
+ subject { object[name] = attribute }
5
+
6
+ let(:attributes) { [] }
7
+ let(:parent) { described_class.new }
8
+ let(:object) { described_class.new(parent, attributes) }
9
+ let(:name) { :name }
10
+
11
+ context 'with a new attribute' do
12
+ let(:attribute) { Virtus::Attribute.build(String, :name => name) }
13
+
14
+ it { is_expected.to equal(attribute) }
15
+
16
+ it 'adds an attribute' do
17
+ expect { subject }.to change { object.to_a }.from(attributes).to([ attribute ])
18
+ end
19
+
20
+ it 'allows #[] to access the attribute with a symbol' do
21
+ expect { subject }.to change { object['name'] }.from(nil).to(attribute)
22
+ end
23
+
24
+ it 'allows #[] to access the attribute with a string' do
25
+ expect { subject }.to change { object[:name] }.from(nil).to(attribute)
26
+ end
27
+
28
+ it 'allows #reset to track overridden attributes' do
29
+ expect { subject }.to change { object.reset.to_a }.from(attributes).to([ attribute ])
30
+ end
31
+ end
32
+
33
+ context 'with a duplicate attribute' do
34
+ let(:original) { Virtus::Attribute.build(String, :name => name) }
35
+ let(:attributes) { [ original ] }
36
+ let(:attribute) { Virtus::Attribute.build(String, :name => name) }
37
+
38
+ it { is_expected.to equal(attribute) }
39
+
40
+ it "replaces the original attribute object" do
41
+ expect { subject }.to change { object.to_a.map(&:__id__) }.
42
+ from(attributes.map(&:__id__)).
43
+ to([attribute.__id__])
44
+ end
45
+
46
+ it 'allows #[] to access the attribute with a string' do
47
+ expect { subject }.to change { object['name'].__id__ }.
48
+ from(original.__id__).
49
+ to(attribute.__id__)
50
+ end
51
+
52
+ it 'allows #[] to access the attribute with a symbol' do
53
+ expect { subject }.to change { object[:name].__id__ }.
54
+ from(original.__id__).
55
+ to(attribute.__id__)
56
+ end
57
+
58
+ it 'allows #reset to track overridden attributes' do
59
+ expect { subject }.to change { object.reset.to_a.map(&:__id__) }.
60
+ from(attributes.map(&:__id__)).
61
+ to([attribute.__id__])
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::AttributeSet, '#merge' do
4
+ subject { object.merge(other) }
5
+
6
+ let(:parent) { described_class.new }
7
+ let(:object) { described_class.new(parent, attributes) }
8
+ let(:name) { :name }
9
+ let(:other) { [attribute] }
10
+
11
+ context 'with a new attribute' do
12
+ let(:attributes) { [] }
13
+ let(:attribute) { Virtus::Attribute.build(String, :name => name) }
14
+
15
+ it { is_expected.to equal(object) }
16
+
17
+ it 'adds an attribute' do
18
+ expect { subject }.to change { object.to_a }.from(attributes).to([attribute])
19
+ end
20
+ end
21
+
22
+ context 'with a duplicate attribute' do
23
+ let(:attributes) { [Virtus::Attribute.build(String, :name => name)] }
24
+ let(:attribute) { Virtus::Attribute.build(String, :name => name) }
25
+
26
+ it { is_expected.to equal(object) }
27
+
28
+ it "replaces the original attribute object" do
29
+ expect { subject }.to change { object.to_a.map(&:__id__) }.
30
+ from(attributes.map(&:__id__)).
31
+ to([attribute.__id__])
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::AttributeSet, '#reset' do
4
+ subject { object.reset }
5
+
6
+ let(:name) { :name }
7
+ let(:attribute) { Virtus::Attribute.build(String, :name => :name) }
8
+ let(:attributes) { [ attribute ] }
9
+ let(:object) { described_class.new(parent, attributes) }
10
+
11
+ context 'when the parent has no attributes' do
12
+ let(:parent) { described_class.new }
13
+
14
+ it { is_expected.to equal(object) }
15
+
16
+ describe '#to_set' do
17
+ subject { super().to_set }
18
+ it { is_expected.to eq(Set[ attribute ]) }
19
+ end
20
+ end
21
+
22
+ context 'when the parent has attributes that are not duplicates' do
23
+ let(:parent_attribute) { Virtus::Attribute.build(String, :name => :parent_name) }
24
+ let(:parent) { described_class.new([ parent_attribute ]) }
25
+
26
+ it { is_expected.to equal(object) }
27
+
28
+ describe '#to_set' do
29
+ subject { super().to_set }
30
+ it { is_expected.to eq(Set[ attribute, parent_attribute ]) }
31
+ end
32
+ end
33
+
34
+ context 'when the parent has attributes that are duplicates' do
35
+ let(:parent_attribute) { Virtus::Attribute.build(String, :name => name) }
36
+ let(:parent) { described_class.new([ parent_attribute ]) }
37
+
38
+ it { is_expected.to equal(object) }
39
+
40
+ describe '#to_set' do
41
+ subject { super().to_set }
42
+ it { is_expected.to eq(Set[ attribute ]) }
43
+ end
44
+ end
45
+
46
+ context 'when the parent has changed' do
47
+ let(:parent_attribute) { Virtus::Attribute.build(String, :name => :parent_name) }
48
+ let(:parent) { described_class.new([ parent_attribute ]) }
49
+ let(:new_attribute) { Virtus::Attribute.build(String, :name => :parent_name) }
50
+
51
+ it { is_expected.to equal(object) }
52
+
53
+ it 'includes changes from the parent' do
54
+ expect(object.to_set).to eql(Set[attribute, parent_attribute])
55
+
56
+ parent << new_attribute
57
+
58
+ expect(subject.to_set).to eql(Set[attribute, new_attribute])
59
+ end
60
+ end
61
+
62
+ context 'when the parent is nil' do
63
+ let(:parent) { nil }
64
+
65
+ it { is_expected.to equal(object) }
66
+
67
+ it 'includes changes from the parent' do
68
+ expect { subject }.to_not change { object.to_set }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,229 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus, '#attribute' do
4
+ let(:name) { :test }
5
+ let(:options) { {} }
6
+
7
+ shared_examples_for 'a class with boolean attribute' do
8
+ subject { Test }
9
+
10
+ let(:object) { subject.new }
11
+
12
+ it 'defines reader and writer' do
13
+ object.test = true
14
+
15
+ expect(object).to be_test
16
+ end
17
+
18
+ it 'defines predicate method' do
19
+ object.test = false
20
+
21
+ expect(object).to_not be_test
22
+ end
23
+ end
24
+
25
+ shared_examples_for 'an object with string attribute' do
26
+ it { is_expected.to respond_to(:test) }
27
+ it { is_expected.to respond_to(:test=) }
28
+
29
+ it 'can write and read the attribute' do
30
+ subject.test = :foo
31
+ expect(subject.test).to eql('foo')
32
+ end
33
+ end
34
+
35
+ it 'returns self' do
36
+ klass = Class.new { include Virtus }
37
+ expect(klass.attribute(:test, String)).to be(klass)
38
+ end
39
+
40
+ it 'raises error when :name is a reserved name on a class' do
41
+ klass = Class.new { include Virtus }
42
+ expect { klass.attribute(:attributes, Set) }.to raise_error(
43
+ ArgumentError, ':attributes is not allowed as an attribute name'
44
+ )
45
+ end
46
+
47
+ it 'raises error when :name is a reserved name on an instance' do
48
+ object = Class.new.new.extend(Virtus)
49
+ expect { object.attribute(:attributes, Set) }.to raise_error(
50
+ ArgumentError, ':attributes is not allowed as an attribute name'
51
+ )
52
+ end
53
+
54
+ it 'allows :attributes as an attribute name when mass-assignment is not included' do
55
+ klass = Class.new { include Virtus::Model::Core }
56
+ klass.attribute(:attributes, Set)
57
+ expect(klass.attribute_set[:attributes]).to be_instance_of(Virtus::Attribute::Collection)
58
+ end
59
+
60
+ it 'allows specifying attribute without type' do
61
+ klass = Class.new { include Virtus::Model::Core }
62
+ klass.attribute(:name)
63
+ expect(klass.attribute_set[:name]).to be_instance_of(Virtus::Attribute)
64
+ end
65
+
66
+ context 'with a class' do
67
+ context 'when type is Boolean' do
68
+ before :all do
69
+ class Test
70
+ include Virtus
71
+
72
+ attribute :test, Boolean
73
+ end
74
+ end
75
+
76
+ after :all do
77
+ Object.send(:remove_const, :Test)
78
+ end
79
+
80
+ it_behaves_like 'a class with boolean attribute'
81
+ end
82
+
83
+ context 'when type is "Boolean"' do
84
+ before :all do
85
+ class Test
86
+ include Virtus
87
+
88
+ attribute :test, 'Boolean'
89
+ end
90
+ end
91
+
92
+ after :all do
93
+ Object.send(:remove_const, :Test)
94
+ end
95
+
96
+ it_behaves_like 'a class with boolean attribute'
97
+ end
98
+
99
+ context 'when type is Axiom::Types::Boolean' do
100
+ before :all do
101
+ class Test
102
+ include Virtus
103
+
104
+ attribute :test, Axiom::Types::Boolean
105
+ end
106
+ end
107
+
108
+ after :all do
109
+ Object.send(:remove_const, :Test)
110
+ end
111
+
112
+ it_behaves_like 'a class with boolean attribute' do
113
+ before do
114
+ pending 'this will be fixed once Attribute::Boolean subclass is gone'
115
+ end
116
+ end
117
+ end
118
+
119
+ context 'when type is :Boolean' do
120
+ before :all do
121
+ class Test
122
+ include Virtus
123
+
124
+ attribute :test, 'Boolean'
125
+ end
126
+ end
127
+
128
+ after :all do
129
+ Object.send(:remove_const, :Test)
130
+ end
131
+
132
+ it_behaves_like 'a class with boolean attribute'
133
+
134
+ context 'with a subclass' do
135
+ it_behaves_like 'a class with boolean attribute' do
136
+ subject { Class.new(Test) }
137
+
138
+ it 'gets attributes from the parent class' do
139
+ Test.attribute :other, Integer
140
+ expect(subject.attribute_set[:other]).to eql(Test.attribute_set[:other])
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ context 'when type is Decimal' do
147
+ before :all do
148
+ class Test
149
+ include Virtus
150
+
151
+ attribute :test, Decimal
152
+ end
153
+ end
154
+
155
+ after :all do
156
+ Object.send(:remove_const, :Test)
157
+ end
158
+
159
+ it 'maps type to the corresponding axiom type' do
160
+ expect(Test.attribute_set[:test].type).to be(Axiom::Types::Decimal)
161
+ end
162
+ end
163
+ end
164
+
165
+ context 'with a module' do
166
+ let(:mod) {
167
+ Module.new {
168
+ include Virtus
169
+
170
+ attribute :test, String
171
+ }
172
+ }
173
+
174
+ let(:model) { Class.new }
175
+
176
+ context 'included in the class' do
177
+ before do
178
+ model.send(:include, mod)
179
+ end
180
+
181
+ it 'adds attributes from the module to a class that includes it' do
182
+ expect(model.attribute_set[:test]).to be_instance_of(Virtus::Attribute)
183
+ end
184
+
185
+ it_behaves_like 'an object with string attribute' do
186
+ subject { model.new }
187
+ end
188
+ end
189
+
190
+ context 'included in the class' do
191
+ it_behaves_like 'an object with string attribute' do
192
+ subject { model.new.extend(mod) }
193
+ end
194
+ end
195
+ end
196
+
197
+ context 'with an instance' do
198
+ subject { model.new }
199
+
200
+ let(:model) { Class.new }
201
+
202
+ before do
203
+ subject.extend(Virtus)
204
+ subject.attribute(:test, String)
205
+ end
206
+
207
+ it_behaves_like 'an object with string attribute'
208
+ end
209
+
210
+ context 'using custom module' do
211
+ subject { model.new }
212
+
213
+ let(:model) {
214
+ Class.new {
215
+ include Virtus.model { |config| config.coerce = false }
216
+
217
+ attribute :test, String
218
+ }
219
+ }
220
+
221
+ it { is_expected.to respond_to(:test) }
222
+ it { is_expected.to respond_to(:test=) }
223
+
224
+ it 'writes and reads attributes' do
225
+ subject.test = :foo
226
+ expect(subject.test).to be(:foo)
227
+ end
228
+ end
229
+ end