store 0.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/Gemfile +3 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/store/version.rb +3 -0
- data/lib/store.rb +73 -0
- data/spec/helper.rb +6 -0
- data/spec/store_spec.rb +107 -0
- data/spec.rb +59 -0
- data/store.gemspec +22 -0
- metadata +83 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2fb59e3196b45ee40cb5849579674cbfa39f774b
|
4
|
+
data.tar.gz: 7ca7cd693fd58a40ced7e5b8aa2b47fa13ba0aef
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dacc4c3b8bda6ec9d4cb7cc7276ff99f760c25e564a07d3ee1a0b82a032ff7d971ea199a8cb9264c8aefc4afbed8c70a36e0db17d621d13cd65c9e56ed17baa2
|
7
|
+
data.tar.gz: 7b33a857f9250a3391a2873872448ad2cc112e562b57ad44d317717910972132b3ecfb8b9b4b670437e445b9146cc004461726519161255e8f98d2f9e43821c3
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Store
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'store'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install store
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/store.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
class Store
|
4
|
+
def initialize(mapping)
|
5
|
+
@mapping = mapping
|
6
|
+
@existing_entities = Set.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def save(entity)
|
10
|
+
mapper = mapper_for_entity(entity)
|
11
|
+
|
12
|
+
if new_entity?(entity)
|
13
|
+
mapper.insert(entity)
|
14
|
+
mark_entities_as_existing([entity])
|
15
|
+
else
|
16
|
+
mapper.update(entity)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def remove(entity)
|
21
|
+
mapper = mapper_for_entity(entity)
|
22
|
+
|
23
|
+
mapper.delete(entity)
|
24
|
+
mark_entity_as_remove(entity)
|
25
|
+
end
|
26
|
+
|
27
|
+
def query(query)
|
28
|
+
mapper = mapper_for_query(query)
|
29
|
+
|
30
|
+
entities = mapper.select(query) || []
|
31
|
+
mark_entities_as_existing(entities)
|
32
|
+
|
33
|
+
entities
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def mapper_for_entity(entity)
|
38
|
+
type = entity_type(entity)
|
39
|
+
mapper_for_type type
|
40
|
+
end
|
41
|
+
|
42
|
+
def entity_type(entity)
|
43
|
+
entity_class = entity.class
|
44
|
+
entity_class.entity_type
|
45
|
+
end
|
46
|
+
|
47
|
+
def mapper_for_query(query)
|
48
|
+
type = query.target
|
49
|
+
mapper_for_type type
|
50
|
+
end
|
51
|
+
|
52
|
+
def mapper_for_type(type)
|
53
|
+
@mapping[type]
|
54
|
+
end
|
55
|
+
|
56
|
+
def new_entity?(entity)
|
57
|
+
!existing_entity?(entity)
|
58
|
+
end
|
59
|
+
|
60
|
+
def existing_entity?(entity)
|
61
|
+
@existing_entities.include? entity.object_id
|
62
|
+
end
|
63
|
+
|
64
|
+
def mark_entities_as_existing(entities)
|
65
|
+
entities.each do |entity|
|
66
|
+
@existing_entities << entity.object_id
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def mark_entity_as_remove(entity)
|
71
|
+
@existing_entities.delete entity.object_id
|
72
|
+
end
|
73
|
+
end
|
data/spec/helper.rb
ADDED
data/spec/store_spec.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe 'store' do
|
4
|
+
let(:store) { Store.new(mapping) }
|
5
|
+
let(:mapping) {
|
6
|
+
{
|
7
|
+
:entity1 => entity1_mapper
|
8
|
+
}
|
9
|
+
}
|
10
|
+
let(:entity1_mapper) { MiniTest::Mock.new }
|
11
|
+
|
12
|
+
let(:entity_class) { Struct.new(:email, :gender) do
|
13
|
+
def self.entity_type
|
14
|
+
:entity1
|
15
|
+
end
|
16
|
+
end }
|
17
|
+
|
18
|
+
let(:entity) { entity_class.new(nil, nil) }
|
19
|
+
|
20
|
+
let(:query) { OpenStruct.new(:target => :entity1) }
|
21
|
+
|
22
|
+
it 'delegates save to insert' do
|
23
|
+
entity1_mapper.expect(:insert, nil, [entity])
|
24
|
+
store.save(entity)
|
25
|
+
|
26
|
+
assert entity1_mapper.verify
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'delegates second save to update' do
|
30
|
+
entity1_mapper.expect(:insert, nil, [entity])
|
31
|
+
|
32
|
+
store.save(entity)
|
33
|
+
|
34
|
+
entity1_mapper.expect(:update, nil, [entity])
|
35
|
+
|
36
|
+
store.save(entity)
|
37
|
+
|
38
|
+
assert entity1_mapper.verify
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'delegates query to select' do
|
42
|
+
entity1_mapper.expect(:select, nil, [query])
|
43
|
+
|
44
|
+
store.query(query)
|
45
|
+
|
46
|
+
assert entity1_mapper.verify
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'returns query result' do
|
50
|
+
entity1_mapper.expect(:select, [:e1, :e2], [query])
|
51
|
+
assert_equal [:e1, :e2], store.query(query)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'maps nil query result to empty collection' do
|
55
|
+
entity1_mapper.expect(:select, nil, [query])
|
56
|
+
assert_equal [], store.query(query)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'only calls update for queried results' do
|
60
|
+
e1 = entity_class.new('e1', 'e1')
|
61
|
+
e2 = entity_class.new('e2', 'e2')
|
62
|
+
e3 = entity_class.new('e3', 'e3')
|
63
|
+
|
64
|
+
entity1_mapper.expect(:select, [e1, e2], [query])
|
65
|
+
store.query(query)
|
66
|
+
|
67
|
+
entity1_mapper.expect(:update, nil, [e1])
|
68
|
+
store.save(e1)
|
69
|
+
|
70
|
+
entity1_mapper.expect(:update, nil, [e2])
|
71
|
+
store.save(e2)
|
72
|
+
|
73
|
+
entity1_mapper.expect(:insert, nil, [e3])
|
74
|
+
store.save(e3)
|
75
|
+
|
76
|
+
assert entity1_mapper.verify
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'identifies entity as existent if changed' do
|
80
|
+
entity.gender = 'm'
|
81
|
+
|
82
|
+
entity1_mapper.expect(:insert, nil, [entity])
|
83
|
+
store.save(entity)
|
84
|
+
|
85
|
+
entity.gender = 'w'
|
86
|
+
|
87
|
+
entity1_mapper.expect(:update, nil, [entity])
|
88
|
+
store.save(entity)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'delegates remove to delete' do
|
92
|
+
entity1_mapper.expect(:delete, nil, [entity])
|
93
|
+
store.remove(entity)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'treats entity as new after delete' do
|
97
|
+
entity1_mapper.expect(:insert, nil, [entity])
|
98
|
+
store.save(entity)
|
99
|
+
|
100
|
+
entity1_mapper.expect(:delete, nil, [entity])
|
101
|
+
store.remove(entity)
|
102
|
+
|
103
|
+
entity1_mapper.expect(:insert, nil, [entity])
|
104
|
+
store.save(entity)
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
data/spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
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)
|
data/store.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'store/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "store"
|
8
|
+
spec.version = Store::VERSION
|
9
|
+
spec.authors = ["Jakob Holderbaum"]
|
10
|
+
spec.email = ["jakob@featurefabrik.de"]
|
11
|
+
spec.summary = %q{Repository Pattern and Data-Mapper Pattern}
|
12
|
+
spec.homepage = ""
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: store
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jakob Holderbaum
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-07-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description:
|
42
|
+
email:
|
43
|
+
- jakob@featurefabrik.de
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- Gemfile
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- lib/store.rb
|
52
|
+
- lib/store/version.rb
|
53
|
+
- spec.rb
|
54
|
+
- spec/helper.rb
|
55
|
+
- spec/store_spec.rb
|
56
|
+
- store.gemspec
|
57
|
+
homepage: ''
|
58
|
+
licenses:
|
59
|
+
- MIT
|
60
|
+
metadata: {}
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 2.0.0
|
78
|
+
signing_key:
|
79
|
+
specification_version: 4
|
80
|
+
summary: Repository Pattern and Data-Mapper Pattern
|
81
|
+
test_files:
|
82
|
+
- spec/helper.rb
|
83
|
+
- spec/store_spec.rb
|