virtus2 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 'custom attributes' do
|
4
|
+
|
5
|
+
before do
|
6
|
+
module Examples
|
7
|
+
class NoisyString < Virtus::Attribute
|
8
|
+
lazy true
|
9
|
+
|
10
|
+
def coerce(input)
|
11
|
+
input.to_s.upcase
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class RegularExpression < Virtus::Attribute
|
16
|
+
primitive Regexp
|
17
|
+
end
|
18
|
+
|
19
|
+
class User
|
20
|
+
include Virtus
|
21
|
+
|
22
|
+
attribute :name, String
|
23
|
+
attribute :scream, NoisyString
|
24
|
+
attribute :expression, RegularExpression
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
subject { Examples::User.new }
|
30
|
+
|
31
|
+
specify 'allows you to define custom attributes' do
|
32
|
+
regexp = /awesome/
|
33
|
+
subject.expression = regexp
|
34
|
+
expect(subject.expression).to eq(regexp)
|
35
|
+
end
|
36
|
+
|
37
|
+
specify 'allows you to define coercion methods' do
|
38
|
+
subject.scream = 'welcome'
|
39
|
+
expect(subject.scream).to eq('WELCOME')
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'custom collection attributes' do
|
4
|
+
let(:library) { Examples::Library.new }
|
5
|
+
let(:books) { library.books }
|
6
|
+
|
7
|
+
before do
|
8
|
+
module Examples end
|
9
|
+
Examples.const_set 'BookCollection', book_collection_class
|
10
|
+
|
11
|
+
module Examples
|
12
|
+
class Book
|
13
|
+
include Virtus
|
14
|
+
|
15
|
+
attribute :title, String
|
16
|
+
end
|
17
|
+
|
18
|
+
class BookCollectionAttribute < Virtus::Attribute::Collection
|
19
|
+
primitive BookCollection
|
20
|
+
end
|
21
|
+
|
22
|
+
class Library
|
23
|
+
include Virtus
|
24
|
+
|
25
|
+
attribute :books, BookCollection[Book]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
after do
|
31
|
+
[:BookCollectionAttribute, :BookCollection, :Book, :Library].each do |const|
|
32
|
+
Examples.send(:remove_const, const)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
shared_examples_for 'a collection' do
|
37
|
+
it 'can be used as Virtus attributes' do
|
38
|
+
attribute = Examples::Library.attribute_set[:books]
|
39
|
+
expect(attribute).to be_kind_of(Examples::BookCollectionAttribute)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'defaults to an empty collection' do
|
43
|
+
books_should_be_an_empty_collection
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'coerces nil' do
|
47
|
+
library.books = nil
|
48
|
+
books_should_be_an_empty_collection
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'coerces an empty array' do
|
52
|
+
library.books = []
|
53
|
+
books_should_be_an_empty_collection
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'coerces an array of attribute hashes' do
|
57
|
+
library.books = [{ :title => 'Foo' }]
|
58
|
+
expect(books).to be_kind_of(Examples::BookCollection)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'coerces its members' do
|
62
|
+
library.books = [{ :title => 'Foo' }]
|
63
|
+
expect(books.count).to eq(1)
|
64
|
+
expect(books.first).to be_kind_of(Examples::Book)
|
65
|
+
end
|
66
|
+
|
67
|
+
def books_should_be_an_empty_collection
|
68
|
+
expect(books).to be_kind_of(Examples::BookCollection)
|
69
|
+
expect(books.count).to eq(0)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with an array subclass' do
|
74
|
+
let(:book_collection_class) { Class.new(Array) }
|
75
|
+
|
76
|
+
it_behaves_like 'a collection'
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'with an enumerable' do
|
80
|
+
require 'forwardable'
|
81
|
+
|
82
|
+
let(:book_collection_class) {
|
83
|
+
Class.new do
|
84
|
+
extend Forwardable
|
85
|
+
include Enumerable
|
86
|
+
|
87
|
+
def_delegators :@array, :each, :<<
|
88
|
+
|
89
|
+
def initialize(*args)
|
90
|
+
@array = Array[*args]
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.[](*args)
|
94
|
+
new(*args)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
}
|
98
|
+
|
99
|
+
it_behaves_like 'a collection'
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "default values" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
module Examples
|
7
|
+
|
8
|
+
class Reference
|
9
|
+
include Virtus::ValueObject
|
10
|
+
|
11
|
+
attribute :ref, String
|
12
|
+
end
|
13
|
+
|
14
|
+
class Page
|
15
|
+
include Virtus
|
16
|
+
|
17
|
+
attribute :title, String
|
18
|
+
attribute :slug, String, :default => lambda { |post, attribute| post.title.downcase.gsub(' ', '-') }, :lazy => true
|
19
|
+
attribute :view_count, Integer, :default => 0
|
20
|
+
attribute :published, Boolean, :default => false, :accessor => :private
|
21
|
+
attribute :editor_title, String, :default => :default_editor_title, :lazy => true
|
22
|
+
attribute :reference, String, :default => Reference.new
|
23
|
+
attribute :revisions, Array
|
24
|
+
attribute :index, Hash
|
25
|
+
attribute :authors, Set
|
26
|
+
|
27
|
+
def default_editor_title
|
28
|
+
published? ? title : "UNPUBLISHED: #{title}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
subject { Examples::Page.new }
|
36
|
+
|
37
|
+
specify 'without a default the value is nil' do
|
38
|
+
expect(subject.title).to be_nil
|
39
|
+
end
|
40
|
+
|
41
|
+
specify 'can be supplied with the :default option' do
|
42
|
+
expect(subject.view_count).to eq(0)
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "you can pass a 'callable-object' to the :default option" do
|
46
|
+
subject.title = 'Example Blog Post'
|
47
|
+
expect(subject.slug).to eq('example-blog-post')
|
48
|
+
end
|
49
|
+
|
50
|
+
specify 'you can set defaults for private attributes' do
|
51
|
+
subject.title = 'Top Secret'
|
52
|
+
expect(subject.editor_title).to eq('UNPUBLISHED: Top Secret')
|
53
|
+
end
|
54
|
+
|
55
|
+
specify 'you can reset attribute to its default' do
|
56
|
+
subject.view_count = 10
|
57
|
+
expect do
|
58
|
+
subject.reset_attribute(:view_count)
|
59
|
+
end.to change { subject.view_count }.to(0)
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'a ValueObject' do
|
63
|
+
it 'does not duplicate the ValueObject' do
|
64
|
+
page1 = Examples::Page.new
|
65
|
+
page2 = Examples::Page.new
|
66
|
+
expect(page1.reference).to equal(page2.reference)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'an Array' do
|
71
|
+
specify 'without a default the value is an empty Array' do
|
72
|
+
expect(subject.revisions).to eql([])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'a Hash' do
|
77
|
+
specify 'without a default the value is an empty Hash' do
|
78
|
+
expect(subject.index).to eql({})
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'a Set' do
|
83
|
+
specify 'without a default the value is an empty Set' do
|
84
|
+
expect(subject.authors).to eql(Set.new)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "virtus attribute definitions" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
module Examples
|
7
|
+
class Person
|
8
|
+
include Virtus
|
9
|
+
|
10
|
+
attribute :name, String
|
11
|
+
attribute :age, Integer
|
12
|
+
attribute :doctor, Boolean
|
13
|
+
attribute :salary, Decimal
|
14
|
+
end
|
15
|
+
|
16
|
+
class Manager < Person
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
subject(:person) { Examples::Person.new(attributes) }
|
23
|
+
|
24
|
+
let(:attributes) { {} }
|
25
|
+
|
26
|
+
specify 'virtus creates accessor methods' do
|
27
|
+
person.name = 'Peter'
|
28
|
+
expect(person.name).to eq('Peter')
|
29
|
+
end
|
30
|
+
|
31
|
+
specify 'the constructor accepts a hash for mass-assignment' do
|
32
|
+
john = Examples::Person.new(:name => 'John', :age => 13)
|
33
|
+
expect(john.name).to eq('John')
|
34
|
+
expect(john.age).to eq(13)
|
35
|
+
end
|
36
|
+
|
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
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with attributes' do
|
44
|
+
let(:attributes) { {:name => 'Jane', :age => 45, :doctor => true, :salary => 4500} }
|
45
|
+
|
46
|
+
specify "#attributes returns the object's attributes as a hash" do
|
47
|
+
expect(person.attributes).to eq(attributes)
|
48
|
+
end
|
49
|
+
|
50
|
+
specify "#to_hash returns the object's attributes as a hash" do
|
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)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'inheritance' do
|
60
|
+
specify 'inherits all the attributes from the base class' do
|
61
|
+
fred = Examples::Manager.new(:name => 'Fred', :age => 29)
|
62
|
+
expect(fred.name).to eq('Fred')
|
63
|
+
expect(fred.age).to eq(29)
|
64
|
+
end
|
65
|
+
|
66
|
+
specify 'lets you add attributes to the base class at runtime' do
|
67
|
+
frank = Examples::Manager.new(:name => 'Frank')
|
68
|
+
Examples::Person.attribute :just_added, String
|
69
|
+
frank.just_added = 'it works!'
|
70
|
+
expect(frank.just_added).to eq('it works!')
|
71
|
+
end
|
72
|
+
|
73
|
+
specify 'lets you add attributes to the subclass at runtime' do
|
74
|
+
person_jack = Examples::Person.new(:name => 'Jack')
|
75
|
+
manager_frank = Examples::Manager.new(:name => 'Frank')
|
76
|
+
|
77
|
+
Examples::Manager.attribute :just_added, String
|
78
|
+
|
79
|
+
manager_frank.just_added = 'awesome!'
|
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=)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'embedded values' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
class City
|
7
|
+
include Virtus.model
|
8
|
+
|
9
|
+
attribute :name, String
|
10
|
+
end
|
11
|
+
|
12
|
+
class Address
|
13
|
+
include Virtus.model
|
14
|
+
|
15
|
+
attribute :street, String
|
16
|
+
attribute :zipcode, String
|
17
|
+
attribute :city, City
|
18
|
+
end
|
19
|
+
|
20
|
+
class User
|
21
|
+
include Virtus.model
|
22
|
+
|
23
|
+
attribute :name, String
|
24
|
+
attribute :address, Address
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
subject { Examples::User.new(:name => 'the guy',
|
30
|
+
:address => address_attributes) }
|
31
|
+
let(:address_attributes) do
|
32
|
+
{ :street => 'Street 1/2', :zipcode => '12345', :city => { :name => 'NYC' } }
|
33
|
+
end
|
34
|
+
|
35
|
+
specify '#attributes returns instances of the embedded values' do
|
36
|
+
expect(subject.attributes).to eq({
|
37
|
+
:name => 'the guy',
|
38
|
+
:address => subject.address
|
39
|
+
})
|
40
|
+
end
|
41
|
+
|
42
|
+
specify 'allows you to pass a hash for the embedded value' do
|
43
|
+
user = Examples::User.new
|
44
|
+
user.address = address_attributes
|
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
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'I can extend objects' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
class User; end
|
7
|
+
|
8
|
+
class Admin; end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
specify 'defining attributes on an object' do
|
13
|
+
attributes = { :name => 'John', :age => 29 }
|
14
|
+
|
15
|
+
admin = Examples::Admin.new
|
16
|
+
admin.extend(Virtus)
|
17
|
+
|
18
|
+
admin.attribute :name, String
|
19
|
+
admin.attribute :age, Integer
|
20
|
+
|
21
|
+
admin.name = 'John'
|
22
|
+
admin.age = 29
|
23
|
+
|
24
|
+
expect(admin.name).to eql('John')
|
25
|
+
expect(admin.age).to eql(29)
|
26
|
+
|
27
|
+
expect(admin.attributes).to eql(attributes)
|
28
|
+
|
29
|
+
new_attributes = { :name => 'Jane', :age => 28 }
|
30
|
+
admin.attributes = new_attributes
|
31
|
+
|
32
|
+
expect(admin.name).to eql('Jane')
|
33
|
+
expect(admin.age).to eql(28)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
class Package
|
5
|
+
include Virtus
|
6
|
+
|
7
|
+
attribute :dimensions, Hash[Symbol => Float]
|
8
|
+
attribute :meta_info , Hash[String => String]
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
describe Package do
|
13
|
+
let(:instance) do
|
14
|
+
described_class.new(
|
15
|
+
:dimensions => { 'width' => "2.2", :height => 2, "length" => 4.5 },
|
16
|
+
:meta_info => { 'from' => :Me , :to => 'You' }
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:dimensions) { instance.dimensions }
|
21
|
+
let(:meta_info) { instance.meta_info }
|
22
|
+
|
23
|
+
describe '#dimensions' do
|
24
|
+
subject { dimensions }
|
25
|
+
|
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 }
|
32
|
+
|
33
|
+
it 'should be coerced to [Symbol => Float] format' do
|
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)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#meta_info' do
|
41
|
+
subject { meta_info }
|
42
|
+
|
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' }
|
48
|
+
|
49
|
+
it 'should be coerced to [String => String] format' do
|
50
|
+
expect(meta_info['from']).to eq('Me')
|
51
|
+
expect(meta_info['to']).to eq('You')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|