virtus 1.0.2 → 1.0.3
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/.ruby-version +1 -1
- data/.travis.yml +2 -2
- data/Changelog.md +11 -0
- data/Gemfile +4 -2
- data/Gemfile.devtools +25 -19
- data/README.md +56 -4
- data/lib/virtus.rb +26 -5
- data/lib/virtus/attribute/builder.rb +2 -2
- data/lib/virtus/attribute/collection.rb +7 -3
- data/lib/virtus/attribute/hash.rb +3 -3
- data/lib/virtus/attribute/strict.rb +1 -1
- data/lib/virtus/builder.rb +1 -1
- data/lib/virtus/configuration.rb +7 -36
- data/lib/virtus/instance_methods.rb +1 -0
- data/lib/virtus/module_extensions.rb +8 -2
- data/lib/virtus/support/options.rb +1 -0
- data/lib/virtus/support/type_lookup.rb +1 -1
- data/lib/virtus/version.rb +1 -1
- 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 +11 -7
- 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 +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/virtus/attribute/class_methods/build_spec.rb +9 -1
- data/spec/unit/virtus/attribute/collection/class_methods/build_spec.rb +13 -2
- data/spec/unit/virtus/attribute/collection/coerce_spec.rb +21 -0
- data/spec/unit/virtus/attribute/hash/class_methods/build_spec.rb +14 -2
- data/spec/unit/virtus/attribute_set/each_spec.rb +21 -16
- data/spec/unit/virtus/attribute_set/element_reference_spec.rb +1 -1
- data/spec/unit/virtus/attribute_set/reset_spec.rb +5 -3
- data/spec/unit/virtus/attribute_spec.rb +4 -3
- data/spec/unit/virtus/attributes_reader_spec.rb +1 -1
- data/spec/unit/virtus/attributes_writer_spec.rb +1 -1
- data/spec/unit/virtus/model_spec.rb +3 -3
- data/spec/unit/virtus/module_spec.rb +59 -2
- data/spec/unit/virtus/value_object_spec.rb +2 -2
- data/virtus.gemspec +2 -2
- metadata +34 -32
@@ -61,6 +61,7 @@ module Virtus
|
|
61
61
|
def define_option_method(option)
|
62
62
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
63
63
|
def self.#{option}(value = Undefined) # def self.primitive(value = Undefined)
|
64
|
+
@#{option} = nil unless defined?(@#{option}) # @primitive = nil unless defined?(@primitive)
|
64
65
|
return @#{option} if value.equal?(Undefined) # return @primitive if value.equal?(Undefined)
|
65
66
|
@#{option} = value # @primitive = value
|
66
67
|
self # self
|
data/lib/virtus/version.rb
CHANGED
@@ -31,12 +31,12 @@ describe 'custom attributes' do
|
|
31
31
|
specify 'allows you to define custom attributes' do
|
32
32
|
regexp = /awesome/
|
33
33
|
subject.expression = regexp
|
34
|
-
subject.expression.
|
34
|
+
expect(subject.expression).to eq(regexp)
|
35
35
|
end
|
36
36
|
|
37
37
|
specify 'allows you to define coercion methods' do
|
38
38
|
subject.scream = 'welcome'
|
39
|
-
subject.scream.
|
39
|
+
expect(subject.scream).to eq('WELCOME')
|
40
40
|
end
|
41
41
|
|
42
42
|
end
|
@@ -36,7 +36,7 @@ describe 'custom collection attributes' do
|
|
36
36
|
shared_examples_for 'a collection' do
|
37
37
|
it 'can be used as Virtus attributes' do
|
38
38
|
attribute = Examples::Library.attribute_set[:books]
|
39
|
-
attribute.
|
39
|
+
expect(attribute).to be_kind_of(Examples::BookCollectionAttribute)
|
40
40
|
end
|
41
41
|
|
42
42
|
it 'defaults to an empty collection' do
|
@@ -55,18 +55,18 @@ describe 'custom collection attributes' do
|
|
55
55
|
|
56
56
|
it 'coerces an array of attribute hashes' do
|
57
57
|
library.books = [{ :title => 'Foo' }]
|
58
|
-
books.
|
58
|
+
expect(books).to be_kind_of(Examples::BookCollection)
|
59
59
|
end
|
60
60
|
|
61
61
|
it 'coerces its members' do
|
62
62
|
library.books = [{ :title => 'Foo' }]
|
63
|
-
books.count.
|
64
|
-
books.first.
|
63
|
+
expect(books.count).to eq(1)
|
64
|
+
expect(books.first).to be_kind_of(Examples::Book)
|
65
65
|
end
|
66
66
|
|
67
67
|
def books_should_be_an_empty_collection
|
68
|
-
books.
|
69
|
-
books.count.
|
68
|
+
expect(books).to be_kind_of(Examples::BookCollection)
|
69
|
+
expect(books.count).to eq(0)
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
@@ -35,21 +35,21 @@ describe "default values" do
|
|
35
35
|
subject { Examples::Page.new }
|
36
36
|
|
37
37
|
specify 'without a default the value is nil' do
|
38
|
-
subject.title.
|
38
|
+
expect(subject.title).to be_nil
|
39
39
|
end
|
40
40
|
|
41
41
|
specify 'can be supplied with the :default option' do
|
42
|
-
subject.view_count.
|
42
|
+
expect(subject.view_count).to eq(0)
|
43
43
|
end
|
44
44
|
|
45
45
|
specify "you can pass a 'callable-object' to the :default option" do
|
46
46
|
subject.title = 'Example Blog Post'
|
47
|
-
subject.slug.
|
47
|
+
expect(subject.slug).to eq('example-blog-post')
|
48
48
|
end
|
49
49
|
|
50
50
|
specify 'you can set defaults for private attributes' do
|
51
51
|
subject.title = 'Top Secret'
|
52
|
-
subject.editor_title.
|
52
|
+
expect(subject.editor_title).to eq('UNPUBLISHED: Top Secret')
|
53
53
|
end
|
54
54
|
|
55
55
|
specify 'you can reset attribute to its default' do
|
@@ -63,25 +63,25 @@ describe "default values" do
|
|
63
63
|
it 'does not duplicate the ValueObject' do
|
64
64
|
page1 = Examples::Page.new
|
65
65
|
page2 = Examples::Page.new
|
66
|
-
page1.reference.
|
66
|
+
expect(page1.reference).to equal(page2.reference)
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
70
|
context 'an Array' do
|
71
71
|
specify 'without a default the value is an empty Array' do
|
72
|
-
subject.revisions.
|
72
|
+
expect(subject.revisions).to eql([])
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
76
|
context 'a Hash' do
|
77
77
|
specify 'without a default the value is an empty Hash' do
|
78
|
-
subject.index.
|
78
|
+
expect(subject.index).to eql({})
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
82
|
context 'a Set' do
|
83
83
|
specify 'without a default the value is an empty Set' do
|
84
|
-
subject.authors.
|
84
|
+
expect(subject.authors).to eql(Set.new)
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
@@ -19,61 +19,68 @@ describe "virtus attribute definitions" do
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
subject { Examples::Person.new }
|
22
|
+
subject(:person) { Examples::Person.new(attributes) }
|
23
|
+
|
24
|
+
let(:attributes) { {} }
|
23
25
|
|
24
26
|
specify 'virtus creates accessor methods' do
|
25
|
-
|
26
|
-
|
27
|
+
person.name = 'Peter'
|
28
|
+
expect(person.name).to eq('Peter')
|
27
29
|
end
|
28
30
|
|
29
31
|
specify 'the constructor accepts a hash for mass-assignment' do
|
30
32
|
john = Examples::Person.new(:name => 'John', :age => 13)
|
31
|
-
john.name.
|
32
|
-
john.age.
|
33
|
+
expect(john.name).to eq('John')
|
34
|
+
expect(john.age).to eq(13)
|
33
35
|
end
|
34
36
|
|
35
|
-
specify 'Boolean attributes have a
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
specify 'Boolean attributes have a predicate method' do
|
38
|
+
expect(person).not_to be_doctor
|
39
|
+
person.doctor = true
|
40
|
+
expect(person).to be_doctor
|
39
41
|
end
|
40
42
|
|
41
43
|
context 'with attributes' do
|
42
44
|
let(:attributes) { {:name => 'Jane', :age => 45, :doctor => true, :salary => 4500} }
|
43
|
-
subject { Examples::Person.new(attributes) }
|
44
45
|
|
45
46
|
specify "#attributes returns the object's attributes as a hash" do
|
46
|
-
|
47
|
+
expect(person.attributes).to eq(attributes)
|
47
48
|
end
|
48
49
|
|
49
50
|
specify "#to_hash returns the object's attributes as a hash" do
|
50
|
-
|
51
|
+
expect(person.to_hash).to eq(attributes)
|
52
|
+
end
|
53
|
+
|
54
|
+
specify "#to_h returns the object's attributes as a hash" do
|
55
|
+
expect(person.to_h).to eql(attributes)
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
54
59
|
context 'inheritance' do
|
55
60
|
specify 'inherits all the attributes from the base class' do
|
56
61
|
fred = Examples::Manager.new(:name => 'Fred', :age => 29)
|
57
|
-
fred.name.
|
58
|
-
fred.age.
|
62
|
+
expect(fred.name).to eq('Fred')
|
63
|
+
expect(fred.age).to eq(29)
|
59
64
|
end
|
60
65
|
|
61
66
|
specify 'lets you add attributes to the base class at runtime' do
|
62
67
|
frank = Examples::Manager.new(:name => 'Frank')
|
63
68
|
Examples::Person.attribute :just_added, String
|
64
69
|
frank.just_added = 'it works!'
|
65
|
-
frank.just_added.
|
70
|
+
expect(frank.just_added).to eq('it works!')
|
66
71
|
end
|
67
72
|
|
68
73
|
specify 'lets you add attributes to the subclass at runtime' do
|
69
74
|
person_jack = Examples::Person.new(:name => 'Jack')
|
70
75
|
manager_frank = Examples::Manager.new(:name => 'Frank')
|
76
|
+
|
71
77
|
Examples::Manager.attribute :just_added, String
|
72
78
|
|
73
79
|
manager_frank.just_added = 'awesome!'
|
74
|
-
|
75
|
-
|
76
|
-
person_jack.
|
80
|
+
|
81
|
+
expect(manager_frank.just_added).to eq('awesome!')
|
82
|
+
expect(person_jack).not_to respond_to(:just_added)
|
83
|
+
expect(person_jack).not_to respond_to(:just_added=)
|
77
84
|
end
|
78
85
|
end
|
79
86
|
end
|
@@ -33,18 +33,18 @@ describe 'embedded values' do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
specify '#attributes returns instances of the embedded values' do
|
36
|
-
subject.attributes.
|
36
|
+
expect(subject.attributes).to eq({
|
37
37
|
:name => 'the guy',
|
38
38
|
:address => subject.address
|
39
|
-
}
|
39
|
+
})
|
40
40
|
end
|
41
41
|
|
42
42
|
specify 'allows you to pass a hash for the embedded value' do
|
43
43
|
user = Examples::User.new
|
44
44
|
user.address = address_attributes
|
45
|
-
user.address.street.
|
46
|
-
user.address.zipcode.
|
47
|
-
user.address.city.name.
|
45
|
+
expect(user.address.street).to eq('Street 1/2')
|
46
|
+
expect(user.address.zipcode).to eq('12345')
|
47
|
+
expect(user.address.city.name).to eq('NYC')
|
48
48
|
end
|
49
49
|
|
50
50
|
end
|
@@ -21,15 +21,15 @@ describe 'I can extend objects' do
|
|
21
21
|
admin.name = 'John'
|
22
22
|
admin.age = 29
|
23
23
|
|
24
|
-
admin.name.
|
25
|
-
admin.age.
|
24
|
+
expect(admin.name).to eql('John')
|
25
|
+
expect(admin.age).to eql(29)
|
26
26
|
|
27
|
-
admin.attributes.
|
27
|
+
expect(admin.attributes).to eql(attributes)
|
28
28
|
|
29
29
|
new_attributes = { :name => 'Jane', :age => 28 }
|
30
30
|
admin.attributes = new_attributes
|
31
31
|
|
32
|
-
admin.name.
|
33
|
-
admin.age.
|
32
|
+
expect(admin.name).to eql('Jane')
|
33
|
+
expect(admin.age).to eql(28)
|
34
34
|
end
|
35
35
|
end
|
@@ -23,28 +23,32 @@ describe Package do
|
|
23
23
|
describe '#dimensions' do
|
24
24
|
subject { dimensions }
|
25
25
|
|
26
|
-
it
|
26
|
+
it 'has 3 keys' do
|
27
|
+
expect(subject.keys.size).to eq(3)
|
28
|
+
end
|
27
29
|
it { should have_key :width }
|
28
30
|
it { should have_key :height }
|
29
31
|
it { should 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
|
43
|
+
it 'has 2 keys' do
|
44
|
+
expect(subject.keys.size).to eq(2)
|
45
|
+
end
|
42
46
|
it { should have_key 'from' }
|
43
47
|
it { should 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
|