jouba 0.0.1 → 0.1.0
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/.rspec +1 -0
- data/Gemfile +7 -7
- data/Gemfile.lock +19 -19
- data/VERSION +1 -1
- data/jouba.gemspec +26 -24
- data/lib/jouba.rb +31 -21
- data/lib/jouba/aggregate.rb +28 -4
- data/lib/jouba/exceptions.rb +3 -0
- data/lib/jouba/stores.rb +23 -0
- data/spec/lib/jouba/aggregate_spec.rb +37 -6
- data/spec/lib/jouba/event_spec.rb +21 -0
- data/spec/lib/jouba_spec.rb +168 -27
- data/spec/spec_helper.rb +4 -3
- metadata +20 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94a0e68b0a8935c5a7b34943bae5e8fa8c978f3d
|
4
|
+
data.tar.gz: b09485abe09d0965c75fb8f5dfdc33ac05a23b87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a6681a756a9d6d08d6087891c6d93a53102656e3d9ca61c393e089702dfd89e7229ecc167371e8a58de067874cd518f33e46ed29cd1b58a849f25b0f1c10c5d
|
7
|
+
data.tar.gz: 7909d8679c12b9ffaee9778a96b59fa61116d2708501ed2659bff4f3f34e6d6c9b5e1b6f50090ff36c849f936b307b3ea4932d0ce61971a586464bb7335a7459
|
data/.rspec
CHANGED
data/Gemfile
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gem 'hashie', '~> 3.3
|
4
|
-
gem 'wisper', '~>1.3
|
3
|
+
gem 'hashie', '~> 3.3'
|
4
|
+
gem 'wisper', '~>1.3'
|
5
5
|
|
6
6
|
group :development do
|
7
|
-
gem 'pry'
|
8
|
-
gem "rspec", "~> 2.14
|
7
|
+
gem 'pry', '~> 0'
|
8
|
+
gem "rspec", "~> 2.14"
|
9
9
|
gem "rdoc", "~> 3.12"
|
10
10
|
gem "bundler", "~> 1.0"
|
11
|
-
gem "jeweler"
|
12
|
-
gem "simplecov", "
|
13
|
-
gem 'rubocop', '~> 0.23
|
11
|
+
gem "jeweler", ' ~> 2.0'
|
12
|
+
gem "simplecov", "~> 0"
|
13
|
+
gem 'rubocop', '~> 0.23'
|
14
14
|
end
|
data/Gemfile.lock
CHANGED
@@ -3,7 +3,7 @@ GEM
|
|
3
3
|
specs:
|
4
4
|
addressable (2.3.6)
|
5
5
|
ast (2.0.0)
|
6
|
-
builder (3.
|
6
|
+
builder (3.2.2)
|
7
7
|
coderay (1.1.0)
|
8
8
|
descendants_tracker (0.0.4)
|
9
9
|
thread_safe (~> 0.3, >= 0.3.1)
|
@@ -11,14 +11,14 @@ GEM
|
|
11
11
|
docile (1.1.3)
|
12
12
|
faraday (0.9.0)
|
13
13
|
multipart-post (>= 1.2, < 3)
|
14
|
-
git (1.2.
|
15
|
-
github_api (0.
|
14
|
+
git (1.2.8)
|
15
|
+
github_api (0.12.2)
|
16
16
|
addressable (~> 2.3)
|
17
|
-
descendants_tracker (~> 0.0.
|
17
|
+
descendants_tracker (~> 0.0.4)
|
18
18
|
faraday (~> 0.8, < 0.10)
|
19
|
-
hashie (>=
|
19
|
+
hashie (>= 3.3)
|
20
20
|
multi_json (>= 1.7.5, < 2.0)
|
21
|
-
nokogiri (~> 1.6.
|
21
|
+
nokogiri (~> 1.6.3)
|
22
22
|
oauth2
|
23
23
|
hashie (3.3.2)
|
24
24
|
highline (1.6.21)
|
@@ -32,15 +32,15 @@ GEM
|
|
32
32
|
rake
|
33
33
|
rdoc
|
34
34
|
json (1.8.1)
|
35
|
-
jwt (1.
|
35
|
+
jwt (1.2.0)
|
36
36
|
method_source (0.8.2)
|
37
|
-
mini_portile (0.6.
|
37
|
+
mini_portile (0.6.1)
|
38
38
|
multi_json (1.10.1)
|
39
39
|
multi_xml (0.5.5)
|
40
40
|
multipart-post (2.0.0)
|
41
|
-
nokogiri (1.6.
|
42
|
-
mini_portile (
|
43
|
-
oauth2 (0.
|
41
|
+
nokogiri (1.6.5)
|
42
|
+
mini_portile (~> 0.6.0)
|
43
|
+
oauth2 (1.0.0)
|
44
44
|
faraday (>= 0.8, < 0.10)
|
45
45
|
jwt (~> 1.0)
|
46
46
|
multi_json (~> 1.3)
|
@@ -54,7 +54,7 @@ GEM
|
|
54
54
|
coderay (~> 1.0)
|
55
55
|
method_source (~> 0.8)
|
56
56
|
slop (~> 3.4)
|
57
|
-
rack (1.
|
57
|
+
rack (1.6.0)
|
58
58
|
rainbow (2.0.0)
|
59
59
|
rake (10.4.2)
|
60
60
|
rdoc (3.12.2)
|
@@ -88,11 +88,11 @@ PLATFORMS
|
|
88
88
|
|
89
89
|
DEPENDENCIES
|
90
90
|
bundler (~> 1.0)
|
91
|
-
hashie (~> 3.3
|
92
|
-
jeweler
|
93
|
-
pry
|
91
|
+
hashie (~> 3.3)
|
92
|
+
jeweler (~> 2.0)
|
93
|
+
pry (~> 0)
|
94
94
|
rdoc (~> 3.12)
|
95
|
-
rspec (~> 2.14
|
96
|
-
rubocop (~> 0.23
|
97
|
-
simplecov
|
98
|
-
wisper (~> 1.3
|
95
|
+
rspec (~> 2.14)
|
96
|
+
rubocop (~> 0.23)
|
97
|
+
simplecov (~> 0)
|
98
|
+
wisper (~> 1.3)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/jouba.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: jouba 0.0
|
5
|
+
# stub: jouba 0.1.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "jouba"
|
9
|
-
s.version = "0.0
|
9
|
+
s.version = "0.1.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["gregory"]
|
14
|
-
s.date = "
|
14
|
+
s.date = "2015-01-02"
|
15
15
|
s.description = "Jouba is a tool set for event sourcing: aggregate root, entities and storage"
|
16
16
|
s.email = "greg2502@gmail.com"
|
17
17
|
s.extra_rdoc_files = [
|
@@ -32,9 +32,11 @@ Gem::Specification.new do |s|
|
|
32
32
|
"lib/jouba.rb",
|
33
33
|
"lib/jouba/aggregate.rb",
|
34
34
|
"lib/jouba/event.rb",
|
35
|
+
"lib/jouba/exceptions.rb",
|
35
36
|
"lib/jouba/stores.rb",
|
36
37
|
"lib/jouba/version.rb",
|
37
38
|
"spec/lib/jouba/aggregate_spec.rb",
|
39
|
+
"spec/lib/jouba/event_spec.rb",
|
38
40
|
"spec/lib/jouba_spec.rb",
|
39
41
|
"spec/spec_helper.rb"
|
40
42
|
]
|
@@ -47,36 +49,36 @@ Gem::Specification.new do |s|
|
|
47
49
|
s.specification_version = 4
|
48
50
|
|
49
51
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
|
-
s.add_runtime_dependency(%q<hashie>, ["~> 3.3
|
51
|
-
s.add_runtime_dependency(%q<wisper>, ["~> 1.3
|
52
|
-
s.add_development_dependency(%q<pry>, ["
|
53
|
-
s.add_development_dependency(%q<rspec>, ["~> 2.14
|
52
|
+
s.add_runtime_dependency(%q<hashie>, ["~> 3.3"])
|
53
|
+
s.add_runtime_dependency(%q<wisper>, ["~> 1.3"])
|
54
|
+
s.add_development_dependency(%q<pry>, ["~> 0"])
|
55
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.14"])
|
54
56
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
55
57
|
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
56
|
-
s.add_development_dependency(%q<jeweler>, ["
|
57
|
-
s.add_development_dependency(%q<simplecov>, ["
|
58
|
-
s.add_development_dependency(%q<rubocop>, ["~> 0.23
|
58
|
+
s.add_development_dependency(%q<jeweler>, ["~> 2.0"])
|
59
|
+
s.add_development_dependency(%q<simplecov>, ["~> 0"])
|
60
|
+
s.add_development_dependency(%q<rubocop>, ["~> 0.23"])
|
59
61
|
else
|
60
|
-
s.add_dependency(%q<hashie>, ["~> 3.3
|
61
|
-
s.add_dependency(%q<wisper>, ["~> 1.3
|
62
|
-
s.add_dependency(%q<pry>, ["
|
63
|
-
s.add_dependency(%q<rspec>, ["~> 2.14
|
62
|
+
s.add_dependency(%q<hashie>, ["~> 3.3"])
|
63
|
+
s.add_dependency(%q<wisper>, ["~> 1.3"])
|
64
|
+
s.add_dependency(%q<pry>, ["~> 0"])
|
65
|
+
s.add_dependency(%q<rspec>, ["~> 2.14"])
|
64
66
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
65
67
|
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
66
|
-
s.add_dependency(%q<jeweler>, ["
|
67
|
-
s.add_dependency(%q<simplecov>, ["
|
68
|
-
s.add_dependency(%q<rubocop>, ["~> 0.23
|
68
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0"])
|
69
|
+
s.add_dependency(%q<simplecov>, ["~> 0"])
|
70
|
+
s.add_dependency(%q<rubocop>, ["~> 0.23"])
|
69
71
|
end
|
70
72
|
else
|
71
|
-
s.add_dependency(%q<hashie>, ["~> 3.3
|
72
|
-
s.add_dependency(%q<wisper>, ["~> 1.3
|
73
|
-
s.add_dependency(%q<pry>, ["
|
74
|
-
s.add_dependency(%q<rspec>, ["~> 2.14
|
73
|
+
s.add_dependency(%q<hashie>, ["~> 3.3"])
|
74
|
+
s.add_dependency(%q<wisper>, ["~> 1.3"])
|
75
|
+
s.add_dependency(%q<pry>, ["~> 0"])
|
76
|
+
s.add_dependency(%q<rspec>, ["~> 2.14"])
|
75
77
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
76
78
|
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
77
|
-
s.add_dependency(%q<jeweler>, ["
|
78
|
-
s.add_dependency(%q<simplecov>, ["
|
79
|
-
s.add_dependency(%q<rubocop>, ["~> 0.23
|
79
|
+
s.add_dependency(%q<jeweler>, ["~> 2.0"])
|
80
|
+
s.add_dependency(%q<simplecov>, ["~> 0"])
|
81
|
+
s.add_dependency(%q<rubocop>, ["~> 0.23"])
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
data/lib/jouba.rb
CHANGED
@@ -2,6 +2,7 @@ require 'hashie'
|
|
2
2
|
require 'wisper'
|
3
3
|
|
4
4
|
require 'jouba/version'
|
5
|
+
require 'jouba/exceptions'
|
5
6
|
require 'jouba/event'
|
6
7
|
require 'jouba/aggregate'
|
7
8
|
require 'jouba/stores'
|
@@ -9,46 +10,55 @@ require 'jouba/stores'
|
|
9
10
|
module Jouba
|
10
11
|
module_function
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def adapters_map
|
14
|
+
@adapters_map ||= Hashie::Mash.new do |_, k|
|
15
|
+
fail("Unknown adapter #{k}, valids are: #{@adapters_map.keys.join(' ')}")
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
attr_reader :adapters_map
|
19
|
+
def alias_store(alias_name, target)
|
20
|
+
stores[alias_name] = stores[target]
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
|
23
|
+
def commit(aggregate, event)
|
24
|
+
yield if stores[:events].append_events(aggregate, event)
|
25
25
|
end
|
26
26
|
|
27
27
|
def config
|
28
|
-
@config ||=
|
28
|
+
@config ||= Hashie::Mash.new { |_, k| fail("Unknown key #{k}, please use configure to set it up") }
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
32
|
-
|
31
|
+
def find(aggregate_class, aggregate_id)
|
32
|
+
stores[:events].find(aggregate_class, aggregate_id)
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
36
|
-
|
35
|
+
def locked?(key)
|
36
|
+
stores[:lock].locked?(key)
|
37
37
|
end
|
38
38
|
|
39
|
-
def
|
40
|
-
|
39
|
+
def register_adapter(key, klass)
|
40
|
+
adapters_map[key] = klass
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
|
43
|
+
def register_store(name)
|
44
|
+
yield(config.stores!.send("#{name}!"))
|
45
|
+
store_config = config.stores[name]
|
46
|
+
adapter = adapters_map[store_config.adapter]
|
47
|
+
stores[name] = adapter.new(store_config)
|
45
48
|
end
|
46
49
|
|
47
|
-
def
|
48
|
-
|
50
|
+
def stores
|
51
|
+
@stores ||= Hashie::Mash.new { |_, k| fail("Unknown store #{k}, valids are: #{@stores.keys.join(' ')}") }
|
49
52
|
end
|
50
53
|
|
51
|
-
def
|
52
|
-
|
54
|
+
def with_lock(key)
|
55
|
+
fail(LockException, "#{key} has been locked") if Jouba.locked?(key)
|
56
|
+
|
57
|
+
begin
|
58
|
+
stores[:lock].lock!(key)
|
59
|
+
yield
|
60
|
+
ensure
|
61
|
+
stores[:lock].unlock!(key)
|
62
|
+
end
|
53
63
|
end
|
54
64
|
end
|
data/lib/jouba/aggregate.rb
CHANGED
@@ -13,8 +13,25 @@ module Jouba
|
|
13
13
|
Jouba.find(self, id)
|
14
14
|
end
|
15
15
|
|
16
|
-
def build_from_events(uuid, events)
|
17
|
-
new
|
16
|
+
def build_from_events(uuid, events = [])
|
17
|
+
new.tap do |aggregate|
|
18
|
+
aggregate[:uuid] = uuid
|
19
|
+
aggregate.apply_events(events)
|
20
|
+
|
21
|
+
after_initialize_blocks.each do |block|
|
22
|
+
block.call(aggregate)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def after_initialize(&block)
|
28
|
+
after_initialize_blocks.push(block)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def after_initialize_blocks
|
34
|
+
@after_initialize_blocks ||= []
|
18
35
|
end
|
19
36
|
end
|
20
37
|
|
@@ -26,8 +43,15 @@ module Jouba
|
|
26
43
|
event = Event.build(event_name, args)
|
27
44
|
|
28
45
|
apply_events(event)
|
29
|
-
Jouba.commit(self, event)
|
30
|
-
|
46
|
+
Jouba.commit(self, event) do
|
47
|
+
publish(event_name, args)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def commit_with_lock(event_name, args, lock_key)
|
52
|
+
Jouba.with_lock(lock_key) do
|
53
|
+
commit(event_name, args)
|
54
|
+
end
|
31
55
|
end
|
32
56
|
|
33
57
|
def apply_events(events)
|
data/lib/jouba/stores.rb
CHANGED
@@ -1,4 +1,27 @@
|
|
1
1
|
module Jouba
|
2
2
|
module Stores
|
3
|
+
def self.append_events(_, _)
|
4
|
+
fail NotImplementedError
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.find(_)
|
8
|
+
fail NotImplementedError
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.count
|
12
|
+
fail NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.locked?(_)
|
16
|
+
fail NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.lock!(_)
|
20
|
+
fail NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.unlock!(_)
|
24
|
+
fail NotImplementedError
|
25
|
+
end
|
3
26
|
end
|
4
27
|
end
|
@@ -2,11 +2,7 @@ require 'ostruct'
|
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
4
|
describe Jouba::Aggregate do
|
5
|
-
let(:aggregate_class)
|
6
|
-
Class.new do
|
7
|
-
include Jouba::Aggregate
|
8
|
-
end
|
9
|
-
end
|
5
|
+
let(:aggregate_class) { Class.new { include Jouba::Aggregate } }
|
10
6
|
|
11
7
|
subject { aggregate_class }
|
12
8
|
|
@@ -19,6 +15,41 @@ describe Jouba::Aggregate do
|
|
19
15
|
end
|
20
16
|
end
|
21
17
|
|
18
|
+
describe '.build_from_events(uuid, events)' do
|
19
|
+
let(:aggregate) { aggregate_class.new }
|
20
|
+
let(:uuid) { '123' }
|
21
|
+
let(:events) { [double(:event)] }
|
22
|
+
|
23
|
+
it 'build the aggregate by applying the events' do
|
24
|
+
expect(aggregate_class).to receive(:new).and_return(aggregate)
|
25
|
+
expect(aggregate).to receive(:[]=).with(:uuid, uuid)
|
26
|
+
expect(aggregate).to receive(:apply_events).with(events)
|
27
|
+
aggregate_class.build_from_events(uuid, events)
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when after_initialize_blocks is not empty' do
|
31
|
+
let(:observer) { double(:observer) }
|
32
|
+
|
33
|
+
before do
|
34
|
+
aggregate_class.after_initialize do |aggregate|
|
35
|
+
aggregate.subscribe(observer)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'apply the blocks once initialized' do
|
40
|
+
expect(aggregate_class).to receive(:new).and_return(aggregate)
|
41
|
+
expect(aggregate).to receive(:apply_events).with(events)
|
42
|
+
expect(aggregate).to receive(:[]=).with(:uuid, uuid)
|
43
|
+
expect(aggregate).to receive(:subscribe).with(observer)
|
44
|
+
aggregate_class.build_from_events(uuid, events)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '.after_initialize(&block)' do
|
51
|
+
end
|
52
|
+
|
22
53
|
describe '#uuid' do
|
23
54
|
let(:uuids) { (1..3).map { aggregate_class.new.uuid } }
|
24
55
|
|
@@ -34,7 +65,7 @@ describe Jouba::Aggregate do
|
|
34
65
|
let(:event) { Jouba::Event.new(name: event_name, data: data) }
|
35
66
|
|
36
67
|
it 'append the event to the store' do
|
37
|
-
expect(Jouba.
|
68
|
+
expect(Jouba.stores[:events]).to receive(:append_events).with(aggregate, event)
|
38
69
|
expect(Jouba::Event).to receive(:build).with(event_name, data).and_return(event)
|
39
70
|
expect(aggregate).to receive(event_name).with(data)
|
40
71
|
aggregate.commit(event_name, data)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Jouba::Event do
|
4
|
+
let(:event_name) { 'event_name' }
|
5
|
+
let(:data) { [:foo, 1, 'bar', { foo: 'bar' }, [1, 2]] }
|
6
|
+
let(:occured_at) { double(:time) }
|
7
|
+
|
8
|
+
describe '.build(event_name, data)' do
|
9
|
+
before do
|
10
|
+
Time.stub_chain(:now, :utc).and_return(occured_at)
|
11
|
+
end
|
12
|
+
|
13
|
+
subject { described_class.build(event_name, data) }
|
14
|
+
|
15
|
+
it 'build an event' do
|
16
|
+
expect(subject.name).to eq event_name
|
17
|
+
expect(subject.data).to eq data
|
18
|
+
expect(subject.occured_at).to eq occured_at
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/spec/lib/jouba_spec.rb
CHANGED
@@ -4,49 +4,112 @@ describe Jouba do
|
|
4
4
|
describe '.config' do
|
5
5
|
subject { described_class.config }
|
6
6
|
|
7
|
-
it { should be_a
|
7
|
+
it { should be_a Hashie::Mash }
|
8
8
|
|
9
|
-
it 'has a
|
10
|
-
expect(subject.
|
9
|
+
it 'has a stores reader' do
|
10
|
+
expect(subject.stores).to be_a Hashie::Mash
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'when we try to access an unknown key' do
|
14
|
+
let(:unkwown_key) { :foo }
|
15
|
+
|
16
|
+
it 'fails' do
|
17
|
+
expect { subject[unkwown_key] }.to raise_error
|
18
|
+
end
|
11
19
|
end
|
12
20
|
end
|
13
21
|
|
14
|
-
describe '.
|
15
|
-
|
22
|
+
describe '.adapters_map' do
|
23
|
+
subject { described_class.adapters_map }
|
24
|
+
let(:existing_adapter) { :sql }
|
25
|
+
let(:unknown_adapter) { :foo }
|
26
|
+
|
27
|
+
before do
|
28
|
+
Jouba.register_adapter(existing_adapter, Class)
|
29
|
+
end
|
16
30
|
|
17
|
-
|
31
|
+
after do
|
32
|
+
Jouba.adapters_map.delete(existing_adapter)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'fail when we try to access an unknown adapter' do
|
36
|
+
expect { subject[existing_adapter] }.not_to raise_error
|
37
|
+
expect { subject[unknown_adapter] }.to raise_error
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'register_adapter(key, class)' do
|
42
|
+
let(:key) { :adapter }
|
43
|
+
let(:adapter_class) { double(:adapter_class) }
|
18
44
|
|
19
45
|
before do
|
20
|
-
Jouba.
|
46
|
+
expect { Jouba.adapters_map[key] }.to raise_error
|
47
|
+
Jouba.register_adapter(key, Class)
|
21
48
|
end
|
22
49
|
|
23
50
|
after do
|
24
|
-
Jouba.
|
51
|
+
Jouba.adapters_map.delete(key)
|
25
52
|
end
|
26
53
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
54
|
+
it 'assign the class to the key in the adapters_map' do
|
55
|
+
expect { Jouba.adapters_map[key] }.not_to raise_error
|
56
|
+
end
|
57
|
+
end
|
31
58
|
|
32
|
-
|
33
|
-
|
34
|
-
|
59
|
+
describe 'register_store(name)' do
|
60
|
+
let(:store_name) { :foo }
|
61
|
+
let(:adapter_name) { :sql }
|
62
|
+
let(:adapter_class) { double(:adapter_class) }
|
63
|
+
let(:adapter_instance) { double(:adapter_instance) }
|
64
|
+
let(:config_h) { double(:config_h) }
|
35
65
|
|
36
|
-
|
37
|
-
|
66
|
+
before do
|
67
|
+
Jouba.register_adapter(adapter_name, adapter_class)
|
68
|
+
expect { Jouba.stores[store_name] }.to raise_error
|
69
|
+
|
70
|
+
expect(described_class.config.stores).to receive(:[]).with(store_name).and_return(config_h)
|
71
|
+
config_h.stub(:adapter).and_return(adapter_name)
|
72
|
+
expect(adapter_class).to receive(:new).with(config_h).and_return(adapter_instance)
|
73
|
+
Jouba.register_store(store_name) do |c|
|
74
|
+
c.adapter = adapter_name
|
38
75
|
end
|
76
|
+
end
|
39
77
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
78
|
+
after do
|
79
|
+
Jouba.stores.delete(store_name)
|
80
|
+
Jouba.adapters_map.delete(adapter_name)
|
81
|
+
end
|
44
82
|
|
45
|
-
|
46
|
-
|
47
|
-
|
83
|
+
subject { described_class.stores[store_name] }
|
84
|
+
|
85
|
+
it 'sets the store in the Jouba.stores' do
|
86
|
+
expect(subject).to eq adapter_instance
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '.stores' do
|
91
|
+
subject { described_class.stores }
|
92
|
+
let(:existing_store) { :existing }
|
93
|
+
let(:unknown_store) { :foo }
|
94
|
+
|
95
|
+
before do
|
96
|
+
Jouba.register_store(existing_store) do |config|
|
97
|
+
config.adapter = :random # Check spec_helper
|
48
98
|
end
|
49
99
|
end
|
100
|
+
|
101
|
+
after do
|
102
|
+
Jouba.stores.delete(existing_store)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'fail when we try to access an unknown adapter' do
|
106
|
+
expect { subject[existing_store] }.not_to raise_error
|
107
|
+
expect { subject[unknown_store] }.to raise_error
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'returns the same instance' do
|
111
|
+
expect(subject[existing_store].object_id).to eq Jouba.stores[existing_store].object_id
|
112
|
+
end
|
50
113
|
end
|
51
114
|
|
52
115
|
describe '.commit(aggregate, event)' do
|
@@ -54,8 +117,18 @@ describe Jouba do
|
|
54
117
|
let(:event) { double(:event) }
|
55
118
|
|
56
119
|
it 'commit the event to the store' do
|
57
|
-
expect(described_class.
|
58
|
-
described_class.commit(aggregate, event)
|
120
|
+
expect(described_class.stores[:events]).to receive(:append_events).with(aggregate, event).and_return(true)
|
121
|
+
expect { |b| described_class.commit(aggregate, event, &b) }.to yield_with_no_args
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when store hasnt been able to append the events' do
|
125
|
+
before do
|
126
|
+
expect(described_class.stores[:events]).to receive(:append_events).with(aggregate, event).and_return(false)
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'doesnt yield' do
|
130
|
+
expect { |b| described_class.commit(aggregate, event, &b) }.not_to yield_with_no_args
|
131
|
+
end
|
59
132
|
end
|
60
133
|
end
|
61
134
|
|
@@ -65,8 +138,76 @@ describe Jouba do
|
|
65
138
|
let(:aggregate) { double(:aggregate) }
|
66
139
|
|
67
140
|
it 'retrieve an aggregate from the store' do
|
68
|
-
expect(described_class.
|
141
|
+
expect(described_class.stores[:events]).to receive(:find)
|
142
|
+
.with(aggregate_class, aggregate_id).and_return(aggregate)
|
69
143
|
expect(described_class.find(aggregate_class, aggregate_id)).to eq aggregate
|
70
144
|
end
|
71
145
|
end
|
146
|
+
|
147
|
+
describe '.alias_store(alias_name, target)' do
|
148
|
+
let(:alias_name) { :alias_name }
|
149
|
+
let(:target) { :target }
|
150
|
+
|
151
|
+
before do
|
152
|
+
Jouba.register_store(target) do |config|
|
153
|
+
config.adapter = :random # Check spec_helper
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
after do
|
158
|
+
Jouba.stores.delete(target)
|
159
|
+
Jouba.stores.delete(alias_name)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'alias the two stores' do
|
163
|
+
expect { Jouba.stores[alias_name] }.to raise_error
|
164
|
+
Jouba.alias_store(alias_name, target)
|
165
|
+
expect { Jouba.stores[alias_name] }.not_to raise_error
|
166
|
+
expect(Jouba.stores[alias_name].object_id).to eq Jouba.stores[target].object_id
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe '.locked?(key)' do
|
172
|
+
let(:key) { 'key' }
|
173
|
+
it 'asks the lock store if a key is locked' do
|
174
|
+
expect(Jouba.stores[:lock]).to receive(:locked?).with(key)
|
175
|
+
described_class.locked?(key)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe '.with_lock(key)' do
|
180
|
+
let(:key) { 'key' }
|
181
|
+
|
182
|
+
context 'when the key is not locked' do
|
183
|
+
before do
|
184
|
+
expect(Jouba.stores[:lock]).to receive(:lock!).with(key)
|
185
|
+
expect(Jouba.stores[:lock]).to receive(:unlock!).with(key)
|
186
|
+
expect(Jouba).to receive(:locked?).with(key).and_return(false)
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'yield with lock' do
|
190
|
+
expect { |b| described_class.with_lock(key, &b) }.to yield_with_no_args
|
191
|
+
end
|
192
|
+
|
193
|
+
context 'when yield fails' do
|
194
|
+
let(:exception) { StandardError.new }
|
195
|
+
|
196
|
+
it 'make sure to release the lock' do
|
197
|
+
expect { described_class.with_lock(key) { fail(exception) } }.to raise_error
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context 'when the key is locked' do
|
203
|
+
before do
|
204
|
+
expect(Jouba).to receive(:locked?).with(key).and_return(true)
|
205
|
+
expect(Jouba.stores[:lock]).not_to receive(:unlock!).with(key)
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'fails with a LockException' do
|
209
|
+
expect { |b| described_class.with_lock(key, &b) }.to raise_error(Jouba::LockException)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
72
213
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -22,11 +22,12 @@ RSpec.configure do |config|
|
|
22
22
|
config.run_all_when_everything_filtered = true
|
23
23
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
24
24
|
|
25
|
-
Jouba.register_adapter(:random, Struct.new('RandomAdapter'))
|
25
|
+
Jouba.register_adapter(:random, Struct.new('RandomAdapter', :config))
|
26
26
|
|
27
|
-
Jouba.
|
28
|
-
|
27
|
+
Jouba.register_store(:events) do |store_config|
|
28
|
+
store_config.adapter = :random
|
29
29
|
end
|
30
|
+
Jouba.alias_store(:lock, :events)
|
30
31
|
|
31
32
|
config.order = 'random'
|
32
33
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jouba
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- gregory
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hashie
|
@@ -16,40 +16,40 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 3.3
|
19
|
+
version: '3.3'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 3.3
|
26
|
+
version: '3.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: wisper
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.3
|
33
|
+
version: '1.3'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 1.3
|
40
|
+
version: '1.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: pry
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 2.14
|
61
|
+
version: '2.14'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 2.14
|
68
|
+
version: '2.14'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rdoc
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,28 +98,28 @@ dependencies:
|
|
98
98
|
name: jeweler
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
103
|
+
version: '2.0'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
110
|
+
version: '2.0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: simplecov
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - "
|
115
|
+
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: '0'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- - "
|
122
|
+
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
@@ -128,14 +128,14 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 0.23
|
131
|
+
version: '0.23'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 0.23
|
138
|
+
version: '0.23'
|
139
139
|
description: 'Jouba is a tool set for event sourcing: aggregate root, entities and
|
140
140
|
storage'
|
141
141
|
email: greg2502@gmail.com
|
@@ -158,9 +158,11 @@ files:
|
|
158
158
|
- lib/jouba.rb
|
159
159
|
- lib/jouba/aggregate.rb
|
160
160
|
- lib/jouba/event.rb
|
161
|
+
- lib/jouba/exceptions.rb
|
161
162
|
- lib/jouba/stores.rb
|
162
163
|
- lib/jouba/version.rb
|
163
164
|
- spec/lib/jouba/aggregate_spec.rb
|
165
|
+
- spec/lib/jouba/event_spec.rb
|
164
166
|
- spec/lib/jouba_spec.rb
|
165
167
|
- spec/spec_helper.rb
|
166
168
|
homepage: http://github.com/gregory/jouba
|