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,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Inheritance' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
class Base
|
7
|
+
include Virtus.model
|
8
|
+
end
|
9
|
+
|
10
|
+
class First < Base
|
11
|
+
attribute :id, Fixnum
|
12
|
+
attribute :name, String, default: ->(first, _) { "Named: #{first.id}" }
|
13
|
+
attribute :description, String
|
14
|
+
end
|
15
|
+
|
16
|
+
class Second < Base
|
17
|
+
attribute :something, String
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'inherits model from the base class' do
|
23
|
+
expect(Examples::First.attribute_set.map(&:name)).to eql([:id, :name, :description])
|
24
|
+
expect(Examples::Second.attribute_set.map(&:name)).to eql([:something])
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'sets correct attributes on the descendant classes' do
|
28
|
+
first = Examples::First.new(:id => 1, :description => 'hello world')
|
29
|
+
|
30
|
+
expect(first.id).to be(1)
|
31
|
+
expect(first.name).to eql('Named: 1')
|
32
|
+
expect(first.description).to eql('hello world')
|
33
|
+
|
34
|
+
second = Examples::Second.new
|
35
|
+
|
36
|
+
expect(second.something).to be(nil)
|
37
|
+
|
38
|
+
second.something = 'foo bar'
|
39
|
+
|
40
|
+
expect(second.something).to eql('foo bar')
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'virtus'
|
2
|
+
|
3
|
+
describe 'Injectible coercer' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
class EmailAddress
|
7
|
+
include Virtus.value_object
|
8
|
+
|
9
|
+
values do
|
10
|
+
attribute :address, String, :coercer => lambda { |add| add.downcase }
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.coerce(input)
|
14
|
+
if input.is_a?(String)
|
15
|
+
new(:address => input)
|
16
|
+
else
|
17
|
+
new(input)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class User
|
23
|
+
include Virtus.model
|
24
|
+
|
25
|
+
attribute :email, EmailAddress,
|
26
|
+
:coercer => lambda { |input| Examples::EmailAddress.coerce(input) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
after do
|
32
|
+
Examples.send(:remove_const, :EmailAddress)
|
33
|
+
Examples.send(:remove_const, :User)
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:doe) { Examples::EmailAddress.new(:address => 'john.doe@example.com') }
|
37
|
+
|
38
|
+
it 'accepts an email hash' do
|
39
|
+
user = Examples::User.new :email => { :address => 'John.Doe@Example.Com' }
|
40
|
+
expect(user.email).to eq(doe)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'coerces an embedded string' do
|
44
|
+
user = Examples::User.new :email => 'John.Doe@Example.Com'
|
45
|
+
expect(user.email).to eq(doe)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "mass assignment with accessors" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
module Examples
|
7
|
+
class Product
|
8
|
+
include Virtus
|
9
|
+
|
10
|
+
attribute :id, Integer
|
11
|
+
attribute :category, String
|
12
|
+
attribute :subcategory, String
|
13
|
+
|
14
|
+
def categories=(categories)
|
15
|
+
self.category = categories.first
|
16
|
+
self.subcategory = categories.last
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def _id=(value)
|
22
|
+
self.id = value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
subject { Examples::Product.new(:categories => ['Office', 'Printers'], :_id => 100) }
|
29
|
+
|
30
|
+
specify 'works uppon instantiation' do
|
31
|
+
expect(subject.category).to eq('Office')
|
32
|
+
expect(subject.subcategory).to eq('Printers')
|
33
|
+
end
|
34
|
+
|
35
|
+
specify 'can be set with #attributes=' do
|
36
|
+
subject.attributes = {:categories => ['Home', 'Furniture']}
|
37
|
+
expect(subject.category).to eq('Home')
|
38
|
+
expect(subject.subcategory).to eq('Furniture')
|
39
|
+
end
|
40
|
+
|
41
|
+
specify 'respects accessor visibility' do
|
42
|
+
expect(subject.id).not_to eq(100)
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'overriding virtus behavior' do
|
4
|
+
|
5
|
+
before do
|
6
|
+
module Examples
|
7
|
+
class Article
|
8
|
+
include Virtus
|
9
|
+
|
10
|
+
attribute :title, String
|
11
|
+
|
12
|
+
def title
|
13
|
+
super || '<unknown>'
|
14
|
+
end
|
15
|
+
|
16
|
+
def title=(name)
|
17
|
+
super unless self.title == "can't be changed"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'overriding an attribute getter' do
|
24
|
+
specify 'calls the defined getter' do
|
25
|
+
expect(Examples::Article.new.title).to eq('<unknown>')
|
26
|
+
end
|
27
|
+
|
28
|
+
specify 'super can be used to access the getter defined by virtus' do
|
29
|
+
expect(Examples::Article.new(:title => 'example article').title).to eq('example article')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'overriding an attribute setter' do
|
34
|
+
specify 'calls the defined setter' do
|
35
|
+
article = Examples::Article.new(:title => "can't be changed")
|
36
|
+
article.title = 'this will never be assigned'
|
37
|
+
expect(article.title).to eq("can't be changed")
|
38
|
+
end
|
39
|
+
|
40
|
+
specify 'super can be used to access the setter defined by virtus' do
|
41
|
+
article = Examples::Article.new(:title => 'example article')
|
42
|
+
article.title = 'my new title'
|
43
|
+
expect(article.title).to eq('my new title')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Using required attributes' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
class User
|
7
|
+
include Virtus.model(:strict => true)
|
8
|
+
|
9
|
+
attribute :name, String
|
10
|
+
attribute :age, Integer, :required => false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'raises coercion error when required attribute is nil' do
|
16
|
+
expect { Examples::User.new(:name => nil) }.to raise_error(Virtus::CoercionError, "Failed to coerce attribute `name' from nil into String")
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'does not raise coercion error when not required attribute is nil' do
|
20
|
+
user = Examples::User.new(:name => 'Jane', :age => nil)
|
21
|
+
|
22
|
+
expect(user.name).to eql('Jane')
|
23
|
+
expect(user.age).to be(nil)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Using Struct as an embedded value attribute' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
Point = Struct.new(:x, :y)
|
7
|
+
|
8
|
+
class Rectangle
|
9
|
+
include Virtus
|
10
|
+
|
11
|
+
attribute :top_left, Point
|
12
|
+
attribute :bottom_right, Point
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
subject do
|
18
|
+
Examples::Rectangle.new(:top_left => [ 3, 5 ], :bottom_right => [ 8, 7 ])
|
19
|
+
end
|
20
|
+
|
21
|
+
specify 'initialize a struct object with correct attributes' do
|
22
|
+
expect(subject.top_left.x).to be(3)
|
23
|
+
expect(subject.top_left.y).to be(5)
|
24
|
+
|
25
|
+
expect(subject.bottom_right.x).to be(8)
|
26
|
+
expect(subject.bottom_right.y).to be(7)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'I can define attributes within a module' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
module Common
|
7
|
+
include Virtus
|
8
|
+
end
|
9
|
+
|
10
|
+
module Name
|
11
|
+
include Common
|
12
|
+
|
13
|
+
attribute :name, String
|
14
|
+
attribute :gamer, Boolean
|
15
|
+
end
|
16
|
+
|
17
|
+
module Age
|
18
|
+
include Common
|
19
|
+
|
20
|
+
attribute :age, Integer
|
21
|
+
end
|
22
|
+
|
23
|
+
class User
|
24
|
+
include Name
|
25
|
+
end
|
26
|
+
|
27
|
+
class Admin < User
|
28
|
+
include Age
|
29
|
+
end
|
30
|
+
|
31
|
+
class Moderator; end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
specify 'including a module with attributes into a class' do
|
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
|
+
|
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
|
+
|
42
|
+
user = Examples::Admin.new(:name => 'Piotr', :age => 29)
|
43
|
+
expect(user.name).to eql('Piotr')
|
44
|
+
expect(user.age).to eql(29)
|
45
|
+
end
|
46
|
+
|
47
|
+
specify 'including a module with attributes into an instance' do
|
48
|
+
moderator = Examples::Moderator.new
|
49
|
+
moderator.extend(Examples::Name, Examples::Age)
|
50
|
+
|
51
|
+
moderator.attributes = { :name => 'John', :age => 21 }
|
52
|
+
expect(moderator.name).to eql('John')
|
53
|
+
expect(moderator.age).to eql(21)
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Defining a ValueObject with a custom constructor" do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
class Point
|
7
|
+
include Virtus::ValueObject
|
8
|
+
|
9
|
+
attribute :x, Integer
|
10
|
+
attribute :y, Integer
|
11
|
+
|
12
|
+
def initialize(attributes)
|
13
|
+
if attributes.kind_of?(Array)
|
14
|
+
self.x = attributes.first
|
15
|
+
self.y = attributes.last
|
16
|
+
else
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Rectangle
|
23
|
+
include Virtus
|
24
|
+
|
25
|
+
attribute :top_left, Point
|
26
|
+
attribute :bottom_right, Point
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
subject do
|
32
|
+
Examples::Rectangle.new(:top_left => [ 3, 4 ], :bottom_right => [ 5, 8 ])
|
33
|
+
end
|
34
|
+
|
35
|
+
specify "initialize a value object attribute with correct attributes" do
|
36
|
+
expect(subject.top_left.x).to be(3)
|
37
|
+
expect(subject.top_left.y).to be(4)
|
38
|
+
|
39
|
+
expect(subject.bottom_right.x).to be(5)
|
40
|
+
expect(subject.bottom_right.y).to be(8)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus, 'instance level attributes' do
|
4
|
+
subject do
|
5
|
+
subject = Object.new
|
6
|
+
subject.singleton_class.send(:include, Virtus)
|
7
|
+
subject
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:attribute) { subject.singleton_class.attribute(:name, String) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
pending if RUBY_VERSION < '1.9'
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'adding an attribute' do
|
17
|
+
it 'allows setting the attribute value on the instance' do
|
18
|
+
attribute
|
19
|
+
subject.name = 'foo'
|
20
|
+
expect(subject.name).to eql('foo')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::ValueObject do
|
4
|
+
let(:class_under_test) do
|
5
|
+
Class.new do
|
6
|
+
def self.name
|
7
|
+
'GeoLocation'
|
8
|
+
end
|
9
|
+
|
10
|
+
include Virtus::ValueObject
|
11
|
+
|
12
|
+
attribute :latitude, Float
|
13
|
+
attribute :longitude, Float
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:attribute_values) { { :latitude => 10.0, :longitude => 20.0 } }
|
18
|
+
|
19
|
+
let(:instance_with_equal_state) { class_under_test.new(attribute_values) }
|
20
|
+
|
21
|
+
let(:instance_with_different_state) do
|
22
|
+
class_under_test.new(:latitude => attribute_values[:latitude])
|
23
|
+
end
|
24
|
+
|
25
|
+
subject { class_under_test.new(attribute_values) }
|
26
|
+
|
27
|
+
describe 'initialization' do
|
28
|
+
it 'sets the attribute values provided to Class.new' do
|
29
|
+
expect(class_under_test.new(:latitude => 10000.001).latitude).to eq(10000.001)
|
30
|
+
expect(subject.latitude).to eql(attribute_values[:latitude])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'writer visibility' do
|
35
|
+
it 'attributes are configured for private writers' do
|
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
|
+
end
|
39
|
+
|
40
|
+
it 'writer methods are set to private' do
|
41
|
+
private_methods = class_under_test.private_instance_methods
|
42
|
+
private_methods.map! { |m| m.to_s }
|
43
|
+
expect(private_methods).to include('latitude=', 'longitude=', 'attributes=')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'attempts to call attribute writer methods raises NameError' do
|
47
|
+
expect { subject.latitude = 5.0 }.to raise_exception(NameError)
|
48
|
+
expect { subject.longitude = 5.0 }.to raise_exception(NameError)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'equality' do
|
53
|
+
describe '#==' do
|
54
|
+
it 'returns true for different objects with the same state' do
|
55
|
+
expect(subject).to eq(instance_with_equal_state)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns false for different objects with different state' do
|
59
|
+
expect(subject).not_to eq(instance_with_different_state)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#eql?' do
|
64
|
+
it 'returns true for different objects with the same state' do
|
65
|
+
expect(subject).to eql(instance_with_equal_state)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'returns false for different objects with different state' do
|
69
|
+
expect(subject).not_to eql(instance_with_different_state)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#equal?' do
|
74
|
+
it 'returns false for different objects with the same state' do
|
75
|
+
expect(subject).not_to equal(instance_with_equal_state)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns false for different objects with different state' do
|
79
|
+
expect(subject).not_to equal(instance_with_different_state)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '#hash' do
|
84
|
+
it 'returns the same value for different objects with the same state' do
|
85
|
+
expect(subject.hash).to eql(instance_with_equal_state.hash)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns different values for different objects with different state' do
|
89
|
+
expect(subject.hash).not_to eql(instance_with_different_state.hash)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#inspect' do
|
95
|
+
it 'includes the class name and attribute values' do
|
96
|
+
expect(subject.inspect).to eq('#<GeoLocation latitude=10.0 longitude=20.0>')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|