store 0.0.1 → 0.0.2
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 +4 -4
- data/.gitignore +3 -0
- data/README.md +2 -2
- data/example.rb +90 -0
- data/lib/store.rb +68 -34
- data/lib/store/version.rb +1 -1
- data/spec/helper.rb +6 -0
- data/spec/store_spec.rb +158 -30
- data/store.gemspec +2 -1
- metadata +18 -3
- data/spec.rb +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05c439b9355bde8a092b4bfea3d5d95630177d3b
|
4
|
+
data.tar.gz: 459439d12096f896eea821d5e57a6a57e7b28217
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 575737d172c70e5338cffe8c85d3b6361a14b775e06ae061f285746832a358f9e9c871c80b80ed1708fdfcd49cc1bca31e431bd5af8e6fe15b3c9f1ab168e9f3
|
7
|
+
data.tar.gz: c5e233707425ffd8c367c7f4beea0c12748820c893fe1bfb08597f182df19bad000efdd376fed4d47c87eaeaa69f569012ed974080d7f062a80c847e5849a9a8
|
data/.gitignore
ADDED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Store
|
2
2
|
|
3
|
-
|
3
|
+
Implementations for using the Repository- and Data Mapper Pattern in ruby
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,7 +18,7 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
See example.rb for capabilities of the current implementation.
|
22
22
|
|
23
23
|
## Contributing
|
24
24
|
|
data/example.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'store'
|
2
|
+
|
3
|
+
class Catalog
|
4
|
+
attr_accessor :name, :products
|
5
|
+
|
6
|
+
def products
|
7
|
+
@products ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_product(product)
|
11
|
+
products << product
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Product
|
16
|
+
attr_accessor :name, :price
|
17
|
+
end
|
18
|
+
|
19
|
+
class CatalogEntityMapper < Struct.new(:store, :catalog)
|
20
|
+
def mapped
|
21
|
+
{
|
22
|
+
'name' => catalog.name,
|
23
|
+
'products' => store.save(*catalog.products)
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class ProductEntityMapper < Struct.new(:store, :product)
|
29
|
+
def mapped
|
30
|
+
{
|
31
|
+
'name' => product.name,
|
32
|
+
'price' => product.price
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class CatalogDataMapper
|
38
|
+
def insert(data)
|
39
|
+
reference = :"catalog_#{rand 100}"
|
40
|
+
puts "catalog_insert[#{reference.inspect}] => #{data.inspect}"
|
41
|
+
reference
|
42
|
+
end
|
43
|
+
|
44
|
+
def update(reference, data)
|
45
|
+
puts "catalog_update[#{reference.inspect}] => #{data.inspect}"
|
46
|
+
reference
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class ProductDataMapper
|
51
|
+
def insert(data)
|
52
|
+
reference = :"product_#{rand 100}"
|
53
|
+
puts "product_insert[#{reference.inspect}] => #{data.inspect}"
|
54
|
+
reference
|
55
|
+
end
|
56
|
+
|
57
|
+
def update(reference, data)
|
58
|
+
puts "product_update[#{reference.inspect}] => #{data.inspect}"
|
59
|
+
reference
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
entities = {
|
65
|
+
'Catalog' => Catalog,
|
66
|
+
'Product' => Product
|
67
|
+
}
|
68
|
+
|
69
|
+
data_mappers = {
|
70
|
+
'Catalog' => CatalogDataMapper.new,
|
71
|
+
'Product' => ProductDataMapper.new
|
72
|
+
}
|
73
|
+
|
74
|
+
entity_mappers = {
|
75
|
+
'Catalog' => CatalogEntityMapper,
|
76
|
+
'Product' => ProductEntityMapper
|
77
|
+
}
|
78
|
+
|
79
|
+
store = Store.new(entities, data_mappers, entity_mappers)
|
80
|
+
|
81
|
+
catalog = store.build('Catalog', :name => 'Catalog 1')
|
82
|
+
|
83
|
+
catalog.add_product store.build('Product', :name => 'Pickaxe', :price => 100)
|
84
|
+
catalog.add_product store.build('Product', :name => 'Scredriver', :price => 400)
|
85
|
+
|
86
|
+
store.save(catalog)
|
87
|
+
|
88
|
+
catalog.products[0].price = 24
|
89
|
+
|
90
|
+
store.save(catalog)
|
data/lib/store.rb
CHANGED
@@ -1,73 +1,107 @@
|
|
1
1
|
require 'set'
|
2
2
|
|
3
3
|
class Store
|
4
|
-
def initialize(
|
5
|
-
@
|
4
|
+
def initialize(entity_classes, data_mapping, entity_mapping = {})
|
5
|
+
@entity_classes = entity_classes
|
6
|
+
@data_mapping = data_mapping
|
7
|
+
@entity_mapping = entity_mapping
|
6
8
|
@existing_entities = Set.new
|
9
|
+
@entity_references = Hash.new
|
7
10
|
end
|
8
11
|
|
9
|
-
def
|
10
|
-
|
12
|
+
def build(entity_class_name, attributes = {})
|
13
|
+
entity = @entity_classes[entity_class_name].new
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
attributes.each do |attribute, value|
|
16
|
+
entity.public_send :"#{attribute}=", value
|
17
|
+
end
|
18
|
+
|
19
|
+
entity
|
20
|
+
end
|
21
|
+
|
22
|
+
def save(*entities)
|
23
|
+
entities.map do |entity|
|
24
|
+
data_mapper = data_mapper_for_entity(entity)
|
25
|
+
raise_unless_data_mapper_found(entity, data_mapper)
|
26
|
+
|
27
|
+
reference = find_entity_reference(entity)
|
28
|
+
if reference.nil?
|
29
|
+
reference = data_mapper.insert(map_entity entity)
|
30
|
+
save_entity_reference(reference, entity)
|
31
|
+
else
|
32
|
+
data_mapper.update(reference, map_entity(entity))
|
33
|
+
end
|
17
34
|
end
|
18
35
|
end
|
19
36
|
|
20
37
|
def remove(entity)
|
21
|
-
|
38
|
+
data_mapper = data_mapper_for_entity(entity)
|
39
|
+
|
40
|
+
reference = find_entity_reference(entity)
|
41
|
+
data_mapper.delete(reference)
|
22
42
|
|
23
|
-
|
24
|
-
mark_entity_as_remove(entity)
|
43
|
+
remove_entity_reference entity
|
25
44
|
end
|
26
45
|
|
27
46
|
def query(query)
|
28
|
-
|
47
|
+
data_mapper = data_mapper_for_query(query)
|
29
48
|
|
30
|
-
|
31
|
-
mark_entities_as_existing(entities)
|
49
|
+
entities_with_references = data_mapper.select(query) || {}
|
32
50
|
|
33
|
-
|
51
|
+
entities_with_references.map do |reference, entity|
|
52
|
+
save_entity_reference reference, entity
|
53
|
+
entity
|
54
|
+
end
|
34
55
|
end
|
35
56
|
|
36
57
|
private
|
37
|
-
def
|
58
|
+
def raise_unless_data_mapper_found(entity, data_mapper)
|
59
|
+
raise "No data_mapper for #{entity.inspect} found" unless data_mapper
|
60
|
+
end
|
61
|
+
|
62
|
+
def map_entity(entity)
|
63
|
+
entity_mapper = entity_mapper_for_entity(entity)
|
64
|
+
entity_mapper.new(self, entity).mapped
|
65
|
+
end
|
66
|
+
|
67
|
+
def entity_mapper_for_entity(entity)
|
38
68
|
type = entity_type(entity)
|
39
|
-
|
69
|
+
entity_mapper_for_type(type)
|
70
|
+
end
|
71
|
+
|
72
|
+
def entity_mapper_for_type(type)
|
73
|
+
@entity_mapping[type]
|
40
74
|
end
|
41
75
|
|
42
76
|
def entity_type(entity)
|
43
77
|
entity_class = entity.class
|
44
|
-
entity_class.
|
78
|
+
entity_class.name
|
45
79
|
end
|
46
80
|
|
47
|
-
def
|
48
|
-
type =
|
49
|
-
|
81
|
+
def data_mapper_for_entity(entity)
|
82
|
+
type = entity_type(entity)
|
83
|
+
data_mapper_for_type type
|
50
84
|
end
|
51
85
|
|
52
|
-
def
|
53
|
-
|
86
|
+
def data_mapper_for_query(query)
|
87
|
+
type = query.target
|
88
|
+
data_mapper_for_type type
|
54
89
|
end
|
55
90
|
|
56
|
-
def
|
57
|
-
|
91
|
+
def data_mapper_for_type(type)
|
92
|
+
@data_mapping[type]
|
58
93
|
end
|
59
94
|
|
60
|
-
def
|
61
|
-
@
|
95
|
+
def find_entity_reference(entity)
|
96
|
+
@entity_references[entity.object_id]
|
62
97
|
end
|
63
98
|
|
64
|
-
def
|
65
|
-
|
66
|
-
@existing_entities << entity.object_id
|
67
|
-
end
|
99
|
+
def save_entity_reference(reference, entity)
|
100
|
+
@entity_references[entity.object_id] = reference
|
68
101
|
end
|
69
102
|
|
70
|
-
def
|
71
|
-
@
|
103
|
+
def remove_entity_reference(entity)
|
104
|
+
@entity_references.delete entity.object_id
|
72
105
|
end
|
106
|
+
|
73
107
|
end
|
data/lib/store/version.rb
CHANGED
data/spec/helper.rb
CHANGED
data/spec/store_spec.rb
CHANGED
@@ -1,107 +1,235 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
describe 'store' do
|
4
|
-
let(:store)
|
5
|
-
let(:
|
4
|
+
let(:store) { Store.new({}, data_mapping, entity_mapping) }
|
5
|
+
let(:data_mapping) {
|
6
6
|
{
|
7
|
-
|
7
|
+
entity_class.name => data_mapper
|
8
8
|
}
|
9
9
|
}
|
10
|
-
let(:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
let(:entity_mapping) {
|
11
|
+
{
|
12
|
+
entity_class.name => entity_mapper
|
13
|
+
}
|
14
|
+
}
|
15
|
+
let(:data_mapper) { MiniTest::Mock.new }
|
16
|
+
let(:entity_mapper) { Struct.new(:store, :entity) do
|
17
|
+
def mapped
|
18
|
+
{
|
19
|
+
'email' => entity.email,
|
20
|
+
'gender' => entity.gender
|
21
|
+
}
|
15
22
|
end
|
16
23
|
end }
|
17
24
|
|
18
|
-
let(:
|
25
|
+
let(:entity_class) { Struct.new(:email, :gender) }
|
26
|
+
let(:entity) { entity_class.new("me@foo.bar", "w") }
|
27
|
+
let(:entity_hash) { {'email' => entity.email, 'gender' => entity.gender} }
|
19
28
|
|
20
|
-
let(:query)
|
29
|
+
let(:query) { OpenStruct.new(:target => entity_class.name) }
|
21
30
|
|
22
31
|
it 'delegates save to insert' do
|
23
|
-
|
32
|
+
data_mapper.expect(:insert, nil, [entity_hash])
|
24
33
|
store.save(entity)
|
25
34
|
|
26
|
-
assert
|
35
|
+
assert data_mapper.verify
|
27
36
|
end
|
28
37
|
|
29
38
|
it 'delegates second save to update' do
|
30
|
-
|
39
|
+
data_mapper.expect(:insert, :ref1, [entity_hash])
|
31
40
|
|
32
41
|
store.save(entity)
|
33
42
|
|
34
|
-
|
43
|
+
data_mapper.expect(:update, nil, [:ref1, entity_hash])
|
35
44
|
|
36
45
|
store.save(entity)
|
37
46
|
|
38
|
-
assert
|
47
|
+
assert data_mapper.verify
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'fails save if data_mapper not found' do
|
51
|
+
entity = OpenStruct.new(:test => 42)
|
52
|
+
error = assert_raises RuntimeError do
|
53
|
+
store.save(entity)
|
54
|
+
end
|
55
|
+
|
56
|
+
assert_match(/no data_mapper .* found/i, error.message)
|
39
57
|
end
|
40
58
|
|
41
59
|
it 'delegates query to select' do
|
42
|
-
|
60
|
+
data_mapper.expect(:select, nil, [query])
|
43
61
|
|
44
62
|
store.query(query)
|
45
63
|
|
46
|
-
assert
|
64
|
+
assert data_mapper.verify
|
47
65
|
end
|
48
66
|
|
49
67
|
it 'returns query result' do
|
50
|
-
|
68
|
+
data_mapper.expect(:select, {:ref1 => :e1, :ref2 => :e2}, [query])
|
51
69
|
assert_equal [:e1, :e2], store.query(query)
|
52
70
|
end
|
53
71
|
|
54
72
|
it 'maps nil query result to empty collection' do
|
55
|
-
|
73
|
+
data_mapper.expect(:select, nil, [query])
|
56
74
|
assert_equal [], store.query(query)
|
57
75
|
end
|
58
76
|
|
59
77
|
it 'only calls update for queried results' do
|
60
78
|
e1 = entity_class.new('e1', 'e1')
|
79
|
+
e1_hash = {'email' => 'e1', 'gender' => 'e1'}
|
61
80
|
e2 = entity_class.new('e2', 'e2')
|
81
|
+
e2_hash = {'email' => 'e2', 'gender' => 'e2'}
|
62
82
|
e3 = entity_class.new('e3', 'e3')
|
83
|
+
e3_hash = {'email' => 'e3', 'gender' => 'e3'}
|
63
84
|
|
64
|
-
|
85
|
+
data_mapper.expect(:select, {:ref1 => e1, :ref2 => e2}, [query])
|
65
86
|
store.query(query)
|
66
87
|
|
67
|
-
|
88
|
+
data_mapper.expect(:update, nil, [:ref1, e1_hash])
|
68
89
|
store.save(e1)
|
69
90
|
|
70
|
-
|
91
|
+
data_mapper.expect(:update, nil, [:ref2, e2_hash])
|
71
92
|
store.save(e2)
|
72
93
|
|
73
|
-
|
94
|
+
data_mapper.expect(:insert, :ref1, [e3_hash])
|
74
95
|
store.save(e3)
|
75
96
|
|
76
|
-
assert
|
97
|
+
assert data_mapper.verify
|
77
98
|
end
|
78
99
|
|
79
100
|
it 'identifies entity as existent if changed' do
|
80
101
|
entity.gender = 'm'
|
81
102
|
|
82
|
-
|
103
|
+
data_mapper.expect(:insert, :ref1, [entity_hash])
|
83
104
|
store.save(entity)
|
84
105
|
|
85
106
|
entity.gender = 'w'
|
86
107
|
|
87
|
-
|
108
|
+
data_mapper.expect(:update, nil, [:ref1, entity_hash.merge('gender' => 'w')])
|
88
109
|
store.save(entity)
|
89
110
|
end
|
90
111
|
|
91
112
|
it 'delegates remove to delete' do
|
92
|
-
|
113
|
+
data_mapper.expect(:insert, :ref1, [entity_hash])
|
114
|
+
store.save(entity)
|
115
|
+
|
116
|
+
data_mapper.expect(:delete, nil, [:ref1])
|
93
117
|
store.remove(entity)
|
94
118
|
end
|
95
119
|
|
96
120
|
it 'treats entity as new after delete' do
|
97
|
-
|
121
|
+
data_mapper.expect(:insert, :ref22, [entity_hash])
|
98
122
|
store.save(entity)
|
99
123
|
|
100
|
-
|
124
|
+
data_mapper.expect(:delete, nil, [:ref22])
|
101
125
|
store.remove(entity)
|
102
126
|
|
103
|
-
|
127
|
+
data_mapper.expect(:insert, :ref23, [entity_hash])
|
104
128
|
store.save(entity)
|
105
129
|
end
|
106
130
|
|
131
|
+
describe 'building' do
|
132
|
+
Project = Struct.new(:name, :due_date)
|
133
|
+
|
134
|
+
let(:store) { Store.new({'Project' => Project}, {}, {}) }
|
135
|
+
|
136
|
+
it 'should instanciate an empty object' do
|
137
|
+
project = store.build 'Project'
|
138
|
+
|
139
|
+
assert_nil project.name
|
140
|
+
assert_nil project.due_date
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should prepopulate attributes' do
|
144
|
+
due_date = Time.now
|
145
|
+
project = store.build 'Project', :name => 'foo', :due_date => due_date
|
146
|
+
|
147
|
+
assert_equal 'foo', project.name
|
148
|
+
assert_equal due_date, project.due_date
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe 'nesting' do
|
153
|
+
User = Struct.new(:name)
|
154
|
+
Group = Struct.new(:name, :users)
|
155
|
+
|
156
|
+
let(:store) { Store.new({}, data_mapping, entity_mapping) }
|
157
|
+
let(:data_mapping) do
|
158
|
+
{
|
159
|
+
'User' => user_data_mapper,
|
160
|
+
'Group' => group_data_mapper
|
161
|
+
}
|
162
|
+
end
|
163
|
+
let(:entity_mapping) do
|
164
|
+
{
|
165
|
+
'User' => user_entity_mapper,
|
166
|
+
'Group' => group_entity_mapper
|
167
|
+
}
|
168
|
+
end
|
169
|
+
let(:user_data_mapper) { MiniTest::Mock.new }
|
170
|
+
let(:group_data_mapper) { MiniTest::Mock.new }
|
171
|
+
let(:user_entity_mapper) { Class.new do
|
172
|
+
def initialize(store, entity)
|
173
|
+
@entity = entity
|
174
|
+
end
|
175
|
+
|
176
|
+
def mapped
|
177
|
+
{
|
178
|
+
'name' => @entity.name
|
179
|
+
}
|
180
|
+
end
|
181
|
+
end
|
182
|
+
}
|
183
|
+
let(:group_entity_mapper) { Class.new do
|
184
|
+
def initialize(store, entity)
|
185
|
+
@store = store
|
186
|
+
@entity = entity
|
187
|
+
end
|
188
|
+
|
189
|
+
def mapped
|
190
|
+
{
|
191
|
+
'name' => @entity.name,
|
192
|
+
'users' => @store.save(*@entity.users)
|
193
|
+
}
|
194
|
+
end
|
195
|
+
end
|
196
|
+
}
|
197
|
+
|
198
|
+
it 'should map saves for nested users' do
|
199
|
+
users = [
|
200
|
+
User.new('u1'),
|
201
|
+
User.new('u2')
|
202
|
+
]
|
203
|
+
group = Group.new('g1', users)
|
204
|
+
|
205
|
+
group_data_mapper.expect :insert, nil, [{'name' => 'g1', 'users' => [:ref1, :ref2]}]
|
206
|
+
user_data_mapper.expect :insert, :ref1, [{'name' => 'u1'}]
|
207
|
+
user_data_mapper.expect :insert, :ref2, [{'name' => 'u2'}]
|
208
|
+
|
209
|
+
store.save(group)
|
210
|
+
|
211
|
+
assert group_data_mapper.verify
|
212
|
+
assert user_data_mapper.verify
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'should map insert and update separated' do
|
216
|
+
users = [
|
217
|
+
User.new('u1'),
|
218
|
+
User.new('u2')
|
219
|
+
]
|
220
|
+
group = Group.new('g1', users)
|
221
|
+
|
222
|
+
user_data_mapper.expect :insert, :uref1, [{'name' => 'u1'}]
|
223
|
+
store.save(users[0])
|
224
|
+
|
225
|
+
group_data_mapper.expect :insert, nil, [{'name' => 'g1', 'users' => [:ref1, :ref2]}]
|
226
|
+
user_data_mapper.expect :update, :ref1, [:uref1, {'name' => 'u1'}]
|
227
|
+
user_data_mapper.expect :insert, :ref2, [{'name' => 'u2'}]
|
228
|
+
|
229
|
+
store.save(group)
|
230
|
+
|
231
|
+
assert group_data_mapper.verify
|
232
|
+
assert user_data_mapper.verify
|
233
|
+
end
|
234
|
+
end
|
107
235
|
end
|
data/store.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Jakob Holderbaum"]
|
10
10
|
spec.email = ["jakob@featurefabrik.de"]
|
11
11
|
spec.summary = %q{Repository Pattern and Data-Mapper Pattern}
|
12
|
-
spec.homepage = ""
|
12
|
+
spec.homepage = "https://github.com/holderbaum/store"
|
13
13
|
spec.license = "MIT"
|
14
14
|
|
15
15
|
spec.files = `git ls-files`.split($/)
|
@@ -19,4 +19,5 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.add_development_dependency "bundler", "~> 1.3"
|
21
21
|
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "simplecov"
|
22
23
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jakob Holderbaum
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: simplecov
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description:
|
42
56
|
email:
|
43
57
|
- jakob@featurefabrik.de
|
@@ -45,16 +59,17 @@ executables: []
|
|
45
59
|
extensions: []
|
46
60
|
extra_rdoc_files: []
|
47
61
|
files:
|
62
|
+
- .gitignore
|
48
63
|
- Gemfile
|
49
64
|
- README.md
|
50
65
|
- Rakefile
|
66
|
+
- example.rb
|
51
67
|
- lib/store.rb
|
52
68
|
- lib/store/version.rb
|
53
|
-
- spec.rb
|
54
69
|
- spec/helper.rb
|
55
70
|
- spec/store_spec.rb
|
56
71
|
- store.gemspec
|
57
|
-
homepage:
|
72
|
+
homepage: https://github.com/holderbaum/store
|
58
73
|
licenses:
|
59
74
|
- MIT
|
60
75
|
metadata: {}
|
data/spec.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
class Store
|
2
|
-
def catalog
|
3
|
-
@catalog ||= CatalogStore.new
|
4
|
-
end
|
5
|
-
|
6
|
-
def product
|
7
|
-
@product ||= ProductStore.new
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
class CatalogStore
|
12
|
-
def build(attrs = {})
|
13
|
-
Catalog.new(attrs)
|
14
|
-
end
|
15
|
-
|
16
|
-
def save(catalog)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class ProductStore
|
21
|
-
def build(attrs = {})
|
22
|
-
Product.new(attrs)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
class Entity
|
28
|
-
def initialize(attrs = {})
|
29
|
-
attrs.each do |attr, value|
|
30
|
-
self.public_send :"#{attr}=", value
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class Catalog < Entity
|
36
|
-
attr_accessor :name, :products
|
37
|
-
|
38
|
-
def products
|
39
|
-
@products ||= []
|
40
|
-
end
|
41
|
-
|
42
|
-
def add_product(product)
|
43
|
-
products << product
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class Product < Entity
|
48
|
-
attr_accessor :name, :price
|
49
|
-
end
|
50
|
-
|
51
|
-
|
52
|
-
catalog = store.catalog.build(:name => 'Catalog 1')
|
53
|
-
|
54
|
-
catalog.add_product store.product.build(:name => 'Pickaxe', :price => 100)
|
55
|
-
catalog.add_product store.product.build(:name => 'Scredriver', :price => 400)
|
56
|
-
|
57
|
-
p catalog
|
58
|
-
|
59
|
-
store.save(catalog)
|