perpetuity 0.4.4 → 0.4.5
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.
- data/.travis.yml +0 -1
- data/CHANGELOG.md +9 -0
- data/README.md +52 -23
- data/lib/perpetuity/data_injectable.rb +6 -4
- data/lib/perpetuity/mapper.rb +9 -9
- data/lib/perpetuity/mongodb.rb +50 -35
- data/lib/perpetuity/persisted_object.rb +7 -0
- data/lib/perpetuity/retrieval.rb +6 -34
- data/lib/perpetuity/serializer.rb +62 -6
- data/lib/perpetuity/version.rb +1 -1
- data/perpetuity.gemspec +1 -2
- data/spec/integration/associations_spec.rb +65 -0
- data/spec/integration/deletion_spec.rb +24 -0
- data/spec/integration/indexing_spec.rb +38 -0
- data/spec/integration/pagination_spec.rb +27 -0
- data/spec/integration/persistence_spec.rb +97 -0
- data/spec/integration/retrieval_spec.rb +114 -0
- data/spec/integration/serialization_spec.rb +60 -0
- data/spec/integration/update_spec.rb +30 -0
- data/spec/integration/validations_spec.rb +17 -0
- data/spec/perpetuity/mapper_spec.rb +3 -2
- data/spec/perpetuity/mongodb_spec.rb +9 -6
- data/spec/perpetuity/persisted_object_spec.rb +16 -0
- data/spec/perpetuity/retrieval_spec.rb +3 -1
- data/spec/perpetuity/serializer_spec.rb +31 -7
- data/spec/perpetuity_spec.rb +1 -427
- data/spec/spec_helper.rb +6 -0
- metadata +29 -22
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/test_classes'
|
3
|
+
|
4
|
+
describe "deletion" do
|
5
|
+
it 'deletes an object' do
|
6
|
+
2.times { Perpetuity[Article].insert Article.new }
|
7
|
+
expect { Perpetuity[Article].delete Perpetuity[Article].first }.to change { Perpetuity[Article].count }.by(-1)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'deletes an object with a given id' do
|
11
|
+
article_id = Perpetuity[Article].insert Article.new
|
12
|
+
expect {
|
13
|
+
Perpetuity[Article].delete article_id
|
14
|
+
}.to change { Perpetuity[Article].count }.by(-1)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#delete_all" do
|
18
|
+
it "should delete all objects of a certain class" do
|
19
|
+
Perpetuity[Article].insert Article.new
|
20
|
+
Perpetuity[Article].delete_all
|
21
|
+
Perpetuity[Article].count.should eq 0
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'indexing' do
|
4
|
+
let(:mapper_class) do
|
5
|
+
Class.new(Perpetuity::Mapper) do
|
6
|
+
map Object
|
7
|
+
attribute :name
|
8
|
+
index :name, unique: true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
let(:mapper) { mapper_class.new }
|
12
|
+
let(:name_index) do
|
13
|
+
mapper.indexes.find do |index|
|
14
|
+
index.attribute.to_s == :name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
after { mapper.data_source.drop_collection Object }
|
19
|
+
|
20
|
+
it 'adds indexes to database collections/tables' do
|
21
|
+
name_index.attribute.name.should be == :name
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'verifies that indexes are inactive' do
|
25
|
+
name_index.should be_inactive
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'creates indexes' do
|
29
|
+
mapper.reindex!
|
30
|
+
name_index.should be_active
|
31
|
+
mapper.remove_index! name_index
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'specifies uniqueness of the index' do
|
35
|
+
name_index.should be_unique
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/test_classes'
|
3
|
+
|
4
|
+
describe 'pagination' do
|
5
|
+
it 'specifies the page we want' do
|
6
|
+
Perpetuity[Article].all.should respond_to :page
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'specify the quantity per page' do
|
10
|
+
Perpetuity[Article].all.should respond_to :per_page
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'returns an empty set when there is no data for that page' do
|
14
|
+
mapper = Perpetuity[Article]
|
15
|
+
mapper.delete_all
|
16
|
+
data = mapper.all.page(2)
|
17
|
+
data.should be_empty
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'specifies per-page quantity' do
|
21
|
+
Perpetuity[Article].delete_all
|
22
|
+
5.times { |i| Perpetuity[Article].insert Article.new i }
|
23
|
+
data = Perpetuity[Article].all.page(3).per_page(2)
|
24
|
+
data.should have(1).item
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/test_classes'
|
3
|
+
|
4
|
+
describe 'Persistence' do
|
5
|
+
it "persists an object" do
|
6
|
+
article = Article.new 'I have a title'
|
7
|
+
expect { Perpetuity[Article].insert article }.
|
8
|
+
to change { Perpetuity[Article].count }.by 1
|
9
|
+
Perpetuity[Article].find(article.id).title.should eq 'I have a title'
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'returns the id of the persisted object' do
|
13
|
+
article = Article.new
|
14
|
+
Perpetuity[Article].insert(article).should eq article.id
|
15
|
+
end
|
16
|
+
|
17
|
+
it "gives an id to objects" do
|
18
|
+
article = Article.new
|
19
|
+
Perpetuity[Article].give_id_to article, 1
|
20
|
+
|
21
|
+
article.id.should eq 1
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'persists referenced objects if they are not persisted' do
|
25
|
+
article = Article.new
|
26
|
+
article.author = User.new
|
27
|
+
Perpetuity[Article].insert article
|
28
|
+
|
29
|
+
Perpetuity[Article].find(article.id).author.id.should be == article.author.id
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'persists arrays of referenced objects if they are not persisted' do
|
33
|
+
authors = [User.new('Dave'), User.new('Andy')]
|
34
|
+
book = Book.new
|
35
|
+
book.authors = authors
|
36
|
+
Perpetuity[Book].insert book
|
37
|
+
|
38
|
+
Perpetuity[Book].find(book.id).authors.first.id.should be == authors.first.id
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'id injection' do
|
42
|
+
let(:article) { Article.new }
|
43
|
+
|
44
|
+
it 'assigns an id to the inserted object' do
|
45
|
+
Perpetuity[Article].insert article
|
46
|
+
article.should respond_to :id
|
47
|
+
end
|
48
|
+
|
49
|
+
it "assigns an id using Mapper.first" do
|
50
|
+
Perpetuity[Article].first.should respond_to :id
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'assigns an id using Mapper.all.first' do
|
54
|
+
Perpetuity[Article].all.first.should respond_to :id
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'persisting arrays' do
|
59
|
+
let(:article) { Article.new }
|
60
|
+
|
61
|
+
it 'persists arrays' do
|
62
|
+
article.comments << 1 << 2 << 3
|
63
|
+
Perpetuity[Article].insert article
|
64
|
+
Perpetuity[Article].find(article.id).comments.should eq [1, 2, 3]
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'persists arrays with unserializable objects in them' do
|
68
|
+
comment = Comment.new('my comment')
|
69
|
+
article.comments << comment
|
70
|
+
Perpetuity[Article].insert article
|
71
|
+
Perpetuity[Article].find(article.id).comments.first.tap do |persisted_comment|
|
72
|
+
persisted_comment.should be_a Comment
|
73
|
+
persisted_comment.body.should eq comment.body
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'persisting hashes' do
|
79
|
+
let(:name_hash) { { 'first_name' => 'Jamie', 'last_name' => 'Gaskins' } }
|
80
|
+
let(:user) { User.new(name_hash) }
|
81
|
+
let(:user_mapper) { Perpetuity[User] }
|
82
|
+
|
83
|
+
it 'saves and retrieves hashes' do
|
84
|
+
user_mapper.insert user
|
85
|
+
user_mapper.find(user.id).name.should be == name_hash
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it "allows mappers to set the id field" do
|
90
|
+
noise = Time.now.to_f.to_s.sub('.', '')
|
91
|
+
book = Book.new("My Title #{noise}")
|
92
|
+
|
93
|
+
Perpetuity[Book].insert book
|
94
|
+
book.id.should eq "my-title-#{noise}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/test_classes'
|
3
|
+
|
4
|
+
describe "retrieval" do
|
5
|
+
it "gets all the objects of a class" do
|
6
|
+
expect { Perpetuity[Article].insert Article.new }.
|
7
|
+
to change { Perpetuity[Article].all.count }.by 1
|
8
|
+
end
|
9
|
+
|
10
|
+
it "has an ID when retrieved" do
|
11
|
+
Perpetuity[Article].insert Article.new
|
12
|
+
Perpetuity[Article].first.should respond_to :id
|
13
|
+
end
|
14
|
+
|
15
|
+
it "gets an item with a specific ID" do
|
16
|
+
article = Article.new
|
17
|
+
Perpetuity[Article].insert article
|
18
|
+
retrieved = Perpetuity[Article].find(article.id)
|
19
|
+
|
20
|
+
retrieved.id.should eq article.id
|
21
|
+
retrieved.title.should eq article.title
|
22
|
+
retrieved.body.should eq article.body
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'sorting' do
|
26
|
+
let(:first) { Article.new('First', '', nil, Time.now - 20) }
|
27
|
+
let(:second) { Article.new('Second', '', nil, Time.now - 10) }
|
28
|
+
let(:third) { Article.new('Third', '', nil, Time.now) }
|
29
|
+
|
30
|
+
before do
|
31
|
+
Perpetuity[Article].delete_all
|
32
|
+
[second, third, first].each { |article| Perpetuity[Article].insert article }
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'sorts results' do
|
36
|
+
titles = Perpetuity[Article].all.sort(:published_at).map(&:title)
|
37
|
+
titles.should be == %w(First Second Third)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'reverse-sorts results' do
|
41
|
+
titles = Perpetuity[Article].all.sort(:published_at).reverse.map(&:title)
|
42
|
+
titles.should be == %w(Third Second First)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'limits result set' do
|
47
|
+
5.times { Perpetuity[Article].insert Article.new }
|
48
|
+
Perpetuity[Article].all.limit(4).should have(4).items
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "Array-like syntax" do
|
52
|
+
let(:draft) { Article.new 'Draft', 'draft content', nil, Time.now + 30 }
|
53
|
+
let(:published) { Article.new 'Published', 'content', nil, Time.now - 30, 3 }
|
54
|
+
before do
|
55
|
+
Perpetuity[Article].insert draft
|
56
|
+
Perpetuity[Article].insert published
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'selects objects using equality' do
|
60
|
+
selected = Perpetuity[Article].select { |article| article.title == 'Published' }
|
61
|
+
selected.map(&:id).should include published.id
|
62
|
+
selected.map(&:id).should_not include draft.id
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'selects objects using greater-than' do
|
66
|
+
selected = Perpetuity[Article].select { |article| article.published_at < Time.now }
|
67
|
+
ids = selected.map(&:id)
|
68
|
+
ids.should include published.id
|
69
|
+
ids.should_not include draft.id
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'selects objects using greater-than-or-equal' do
|
73
|
+
selected = Perpetuity[Article].select { |article| article.views >= 3 }
|
74
|
+
ids = selected.map(&:id)
|
75
|
+
ids.should include published.id
|
76
|
+
ids.should_not include draft.id
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'selects objects using less-than' do
|
80
|
+
selected = Perpetuity[Article].select { |article| article.views < 3 }
|
81
|
+
ids = selected.map(&:id)
|
82
|
+
ids.should include draft.id
|
83
|
+
ids.should_not include published.id
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'selects objects using less-than-or-equal' do
|
87
|
+
selected = Perpetuity[Article].select { |article| article.views <= 0 }
|
88
|
+
ids = selected.map(&:id)
|
89
|
+
ids.should include draft.id
|
90
|
+
ids.should_not include published.id
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'selects objects using inequality' do
|
94
|
+
selected = Perpetuity[Article].select { |article| article.title.not_equal? 'Draft' }
|
95
|
+
ids = selected.map(&:id)
|
96
|
+
ids.should_not include draft.id
|
97
|
+
ids.should include published.id
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'selects objects using regular expressions' do
|
101
|
+
selected = Perpetuity[Article].select { |article| article.title =~ /Pub/ }
|
102
|
+
ids = selected.map(&:id)
|
103
|
+
ids.should include published.id
|
104
|
+
ids.should_not include draft.id
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'selects objects using inclusion' do
|
108
|
+
selected = Perpetuity[Article].select { |article| article.title.in %w( Published ) }
|
109
|
+
ids = selected.map(&:id)
|
110
|
+
ids.should include published.id
|
111
|
+
ids.should_not include draft.id
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/test_classes'
|
3
|
+
|
4
|
+
describe 'serialization' do
|
5
|
+
let(:author) { User.new 'username' }
|
6
|
+
let(:comment) { Comment.new }
|
7
|
+
let(:article) { Article.new }
|
8
|
+
let(:mapper) { Perpetuity[Article] }
|
9
|
+
let(:serialized_value) do
|
10
|
+
{
|
11
|
+
'title' => article.title,
|
12
|
+
'body' => article.body,
|
13
|
+
'author' => {
|
14
|
+
'__metadata__' => {
|
15
|
+
'class' => author.class.to_s,
|
16
|
+
'id' => author.id
|
17
|
+
}
|
18
|
+
},
|
19
|
+
'comments' => [
|
20
|
+
{
|
21
|
+
'__metadata__' => {
|
22
|
+
'class' => comment.class.to_s
|
23
|
+
},
|
24
|
+
'body' => comment.body,
|
25
|
+
'author' => {
|
26
|
+
'__metadata__' => {
|
27
|
+
'class' => author.class.to_s,
|
28
|
+
'id' => author.id
|
29
|
+
}
|
30
|
+
}
|
31
|
+
},
|
32
|
+
],
|
33
|
+
'published_at' => article.published_at,
|
34
|
+
'views' => article.views
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
before do
|
39
|
+
article.author = author
|
40
|
+
article.comments = [comment]
|
41
|
+
comment.author = author
|
42
|
+
|
43
|
+
Perpetuity[User].insert author
|
44
|
+
Perpetuity[Article].insert article
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'serializes objects into hashes' do
|
48
|
+
mapper.serialize(article).should be == serialized_value
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'deserializes hashes into proper objects' do
|
52
|
+
unserialized = mapper.find article.id
|
53
|
+
unserialized.should be_a Article
|
54
|
+
unserialized.title.should be == article.title
|
55
|
+
unserialized.body.should be == article.body
|
56
|
+
unserialized.comments.first.tap do |unserialized_comment|
|
57
|
+
unserialized_comment.body.should be == comment.body
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/test_classes'
|
3
|
+
|
4
|
+
describe 'updating' do
|
5
|
+
let(:article) { Article.new }
|
6
|
+
let(:mapper) { Perpetuity[Article] }
|
7
|
+
let(:new_title) { 'I has a new title!' }
|
8
|
+
|
9
|
+
before do
|
10
|
+
mapper.insert article
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'updates an object in the database' do
|
14
|
+
mapper.update article, title: new_title
|
15
|
+
mapper.find(article.id).title.should eq new_title
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'updates the object in memory' do
|
19
|
+
mapper.update article, title: new_title
|
20
|
+
article.title.should eq new_title
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'resaves the object in the database' do
|
24
|
+
article.title = new_title
|
25
|
+
mapper.save article
|
26
|
+
mapper.find(article.id).title.should eq new_title
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/test_classes'
|
3
|
+
|
4
|
+
describe 'validations' do
|
5
|
+
let(:car_mapper) { Perpetuity[Car] }
|
6
|
+
|
7
|
+
it 'raises an exception when inserting an invalid object' do
|
8
|
+
car = Car.new
|
9
|
+
expect { car_mapper.insert car }.to raise_error
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'does not raise an exception when validations are met' do
|
13
|
+
car = Car.new
|
14
|
+
car.make = "Volkswagen"
|
15
|
+
expect { car_mapper.insert car }.not_to raise_error
|
16
|
+
end
|
17
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'perpetuity/mapper_registry'
|
2
2
|
require 'perpetuity/mapper'
|
3
|
+
require 'perpetuity/mongodb'
|
3
4
|
|
4
5
|
module Perpetuity
|
5
6
|
describe Mapper do
|
@@ -49,7 +50,7 @@ module Perpetuity
|
|
49
50
|
end
|
50
51
|
|
51
52
|
describe 'talking to the data source' do
|
52
|
-
let(:data_source) {
|
53
|
+
let(:data_source) { MongoDB.new(db: nil) }
|
53
54
|
before do
|
54
55
|
mapper_class.stub(data_source: data_source)
|
55
56
|
mapper_class.map Object, registry
|
@@ -78,7 +79,7 @@ module Perpetuity
|
|
78
79
|
end
|
79
80
|
|
80
81
|
it 'finds an object by ID' do
|
81
|
-
returned_object = double
|
82
|
+
returned_object = double('Retrieved Object')
|
82
83
|
criteria = { id: 1 }
|
83
84
|
options = {:attribute=>nil, :direction=>nil, :limit=>nil, :page=>nil}
|
84
85
|
data_source.should_receive(:retrieve)
|
@@ -12,11 +12,8 @@ module Perpetuity
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'connects to its host' do
|
15
|
-
connection = double('connection')
|
16
|
-
Mongo::MongoClient.should_receive(:new).and_return connection
|
17
15
|
mongo.connect
|
18
16
|
mongo.should be_connected
|
19
|
-
mongo.connection.should == connection
|
20
17
|
end
|
21
18
|
|
22
19
|
it 'connects automatically when accessing the database' do
|
@@ -85,8 +82,10 @@ module Perpetuity
|
|
85
82
|
it 'retrieves by id if the id is a string' do
|
86
83
|
time = Time.now.utc
|
87
84
|
id = mongo.insert Object, {inserted: time}
|
88
|
-
|
89
|
-
|
85
|
+
|
86
|
+
object = mongo.retrieve(Object, id: id.to_s).first
|
87
|
+
retrieved_time = object["inserted"]
|
88
|
+
retrieved_time.to_f.should be_within(0.001).of time.to_f
|
90
89
|
end
|
91
90
|
|
92
91
|
describe 'serializable objects' do
|
@@ -94,12 +93,16 @@ module Perpetuity
|
|
94
93
|
|
95
94
|
it 'can insert serializable values' do
|
96
95
|
serializable_values.each do |value|
|
97
|
-
mongo.insert(Object, {value: value}).should be_a BSON::ObjectId
|
96
|
+
mongo.insert(Object, {value: value}).should be_a Moped::BSON::ObjectId
|
98
97
|
mongo.can_serialize?(value).should be_true
|
99
98
|
end
|
100
99
|
end
|
101
100
|
end
|
102
101
|
|
102
|
+
it 'generates a new query DSL object' do
|
103
|
+
mongo.query { |object| object.whatever == 1 }.should respond_to :to_db
|
104
|
+
end
|
105
|
+
|
103
106
|
describe 'indexing' do
|
104
107
|
let(:collection) { Object }
|
105
108
|
let(:key) { 'object_id' }
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'perpetuity/persisted_object'
|
2
|
+
|
3
|
+
module Perpetuity
|
4
|
+
describe PersistedObject do
|
5
|
+
let(:object) { Object.new }
|
6
|
+
|
7
|
+
before do
|
8
|
+
object.instance_variable_set '@id', :fake_id
|
9
|
+
object.extend PersistedObject
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'gives an object an ID method' do
|
13
|
+
object.id.should be == :fake_id
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -3,7 +3,9 @@ require 'perpetuity/retrieval'
|
|
3
3
|
module Perpetuity
|
4
4
|
describe Retrieval do
|
5
5
|
let(:data_source) { double('data_source') }
|
6
|
-
let(:
|
6
|
+
let(:registry) { double('mapper_registry') }
|
7
|
+
let(:mapper) { double(mapped_class: Object, data_source: data_source, mapper_registry: registry) }
|
8
|
+
let(:retrieval) { Perpetuity::Retrieval.new mapper, {} }
|
7
9
|
subject { retrieval }
|
8
10
|
|
9
11
|
it "sorts the results" do
|
@@ -11,7 +11,7 @@ module Perpetuity
|
|
11
11
|
let(:authors) { [dave, andy] }
|
12
12
|
let(:book) { Book.new('The Pragmatic Programmer', authors) }
|
13
13
|
let(:mapper_registry) { MapperRegistry.new }
|
14
|
-
let!(:
|
14
|
+
let!(:book_mapper_class) do
|
15
15
|
registry = mapper_registry
|
16
16
|
Class.new(Perpetuity::Mapper) do
|
17
17
|
map Book, registry
|
@@ -19,7 +19,7 @@ module Perpetuity
|
|
19
19
|
attribute :authors
|
20
20
|
end
|
21
21
|
end
|
22
|
-
let!(:
|
22
|
+
let!(:user_mapper_class) do
|
23
23
|
registry = mapper_registry
|
24
24
|
Class.new(Perpetuity::Mapper) do
|
25
25
|
map User, registry
|
@@ -27,13 +27,13 @@ module Perpetuity
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
let(:data_source) { double('Data Source') }
|
30
|
-
let(:serializer) { Serializer.new(mapper_registry[Book]
|
30
|
+
let(:serializer) { Serializer.new(mapper_registry[Book]) }
|
31
31
|
|
32
32
|
before do
|
33
|
-
dave.
|
34
|
-
andy.
|
35
|
-
|
36
|
-
|
33
|
+
dave.extend PersistedObject
|
34
|
+
andy.extend PersistedObject
|
35
|
+
user_mapper_class.stub(data_source: data_source)
|
36
|
+
book_mapper_class.stub(data_source: data_source)
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'serializes an array of non-embedded attributes as references' do
|
@@ -58,5 +58,29 @@ module Perpetuity
|
|
58
58
|
]
|
59
59
|
}
|
60
60
|
end
|
61
|
+
|
62
|
+
context 'with objects that have hashes as attributes' do
|
63
|
+
let(:name_data) { {first_name: 'Jamie', last_name: 'Gaskins'} }
|
64
|
+
let(:serialized_data) do
|
65
|
+
{
|
66
|
+
'name' => name_data
|
67
|
+
}
|
68
|
+
end
|
69
|
+
let(:user) { User.new(name_data) }
|
70
|
+
let(:user_mapper) { mapper_registry[User] }
|
71
|
+
let(:user_serializer) { Serializer.new(user_mapper) }
|
72
|
+
|
73
|
+
before do
|
74
|
+
data_source.stub(:can_serialize?).with(name_data) { true }
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'serializes' do
|
78
|
+
user_serializer.serialize(user).should be == serialized_data
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'unserializes' do
|
82
|
+
user_serializer.unserialize(serialized_data).name.should be == user.name
|
83
|
+
end
|
84
|
+
end
|
61
85
|
end
|
62
86
|
end
|