rohbau 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +18 -0
- data/.rubocop_todo.yml +149 -0
- data/.travis.yml +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +1 -1
- data/README.md +404 -20
- data/README.md.template +104 -20
- data/Rakefile +1 -1
- data/bin/build_readme +3 -1
- data/examples/email_service/email_service.rb +5 -0
- data/examples/event_tube.rb +9 -0
- data/examples/my_application.rb +13 -0
- data/examples/runtime.rb +7 -24
- data/examples/service_factory_validation.rb +4 -4
- data/examples/use_case.rb +10 -0
- data/examples/user_entity.rb +20 -0
- data/examples/user_service/create_user_use_case.rb +14 -0
- data/examples/user_service/event_tube.rb +6 -0
- data/examples/user_service/request.rb +16 -0
- data/examples/user_service/runtime.rb +13 -0
- data/examples/user_service/service_factory.rb +10 -0
- data/examples/user_service/user_gateway.rb +16 -0
- data/examples/user_service.rb +1 -0
- data/examples/verify/examples.txt +31 -0
- data/examples/verify/examples_spec.rb +25 -0
- data/lib/rohbau/application.rb +5 -8
- data/lib/rohbau/default_memory_gateway.rb +0 -2
- data/lib/rohbau/entity.rb +1 -3
- data/lib/rohbau/event_tube.rb +2 -1
- data/lib/rohbau/index.rb +4 -5
- data/lib/rohbau/interface.rb +130 -0
- data/lib/rohbau/it_behaves_like.rb +0 -2
- data/lib/rohbau/minitest/exclude.rb +0 -6
- data/lib/rohbau/registry.rb +4 -6
- data/lib/rohbau/request.rb +2 -4
- data/lib/rohbau/request_cache.rb +19 -0
- data/lib/rohbau/require.rb +0 -1
- data/lib/rohbau/runtime.rb +0 -2
- data/lib/rohbau/service_factory.rb +1 -2
- data/lib/rohbau/shared_spec.rb +0 -2
- data/lib/rohbau/shared_specs/default_gateway.rb +2 -6
- data/lib/rohbau/use_case.rb +0 -3
- data/lib/rohbau/version.rb +1 -1
- data/lib/rohbau.rb +19 -1
- data/rakelib/build_readme.rake +23 -0
- data/rakelib/ci.rake +5 -0
- data/rakelib/examples.rake +16 -0
- data/rakelib/rubocop.rake +18 -0
- data/spec/event_tube_spec.rb +2 -3
- data/spec/interface_spec.rb +111 -0
- data/spec/runtime_loader_spec.rb +1 -2
- data/spec/service_factory_spec.rb +6 -9
- data/spec/shared_spec_spec.rb +0 -2
- metadata +43 -20
- data/etc/build_readme.rb +0 -14
data/README.md.template
CHANGED
@@ -24,7 +24,7 @@
|
|
24
24
|
|
25
25
|
## Description
|
26
26
|
|
27
|
-
|
27
|
+
_Rohbau_ provides a set of patterns used in Domain Driven Design.
|
28
28
|
|
29
29
|
## Installation
|
30
30
|
|
@@ -52,20 +52,23 @@ By this a place is made where for example memories for in-memory gateway backend
|
|
52
52
|
|
53
53
|
Inject a user service to your application
|
54
54
|
|
55
|
+
`examples/my_application.rb`
|
56
|
+
|
55
57
|
```ruby
|
56
|
-
include_example
|
58
|
+
include_example 'my_application'
|
57
59
|
```
|
58
60
|
|
59
|
-
|
61
|
+
`examples/user_service/runtime.rb`
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
-
|
63
|
+
```ruby
|
64
|
+
include_example 'user_service/runtime'
|
65
|
+
```
|
64
66
|
|
65
|
-
|
67
|
+
`examples/runtime.rb`
|
66
68
|
|
67
|
-
|
68
|
-
|
69
|
+
```ruby
|
70
|
+
include_example 'runtime'
|
71
|
+
```
|
69
72
|
|
70
73
|
### ServiceFactory
|
71
74
|
|
@@ -76,39 +79,120 @@ It follows partly the service locator / registry pattern.
|
|
76
79
|
|
77
80
|
Register and unregister default service and override with specific service.
|
78
81
|
|
82
|
+
`examples/user_service/service_factory.rb`
|
83
|
+
|
79
84
|
```ruby
|
80
|
-
include_example service_factory
|
85
|
+
include_example 'service_factory'
|
81
86
|
```
|
82
87
|
|
83
88
|
Validate registered dependencies
|
84
89
|
|
90
|
+
`examples/user_service/service_factory_validation.rb`
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
include_example 'service_factory_validation'
|
94
|
+
```
|
95
|
+
|
96
|
+
### Request
|
97
|
+
|
98
|
+
It ensures an initialized runtime and builds up a new the service factory instance.
|
99
|
+
|
100
|
+
`examples/user_service/request.rb`
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
include_example 'user_service/request'
|
104
|
+
```
|
105
|
+
|
106
|
+
### Entity
|
107
|
+
|
108
|
+
Entities are low level, logic-less, data structures.
|
109
|
+
|
110
|
+
`examples/user_entity.rb`
|
111
|
+
|
85
112
|
```ruby
|
86
|
-
|
87
|
-
|
88
|
-
|
113
|
+
include_example 'user_entity'
|
114
|
+
```
|
115
|
+
|
116
|
+
### Gateway
|
117
|
+
|
118
|
+
Provides an interface to persist entities.
|
119
|
+
|
120
|
+
`examples/user_service/user_gateway.rb`
|
89
121
|
|
90
|
-
|
91
|
-
|
92
|
-
|
122
|
+
```ruby
|
123
|
+
include_example 'user_service/user_gateway'
|
124
|
+
```
|
125
|
+
|
126
|
+
### UseCase
|
127
|
+
|
128
|
+
`UseCases` define the interface for the end user who interacts with the system.
|
129
|
+
|
130
|
+
#### Examples
|
131
|
+
|
132
|
+
`examples/user_service/create_user_use_case.rb`
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
include_example 'user_service/create_user_use_case'
|
136
|
+
```
|
137
|
+
|
138
|
+
`examples/use_case.rb`
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
include_example 'use_case'
|
142
|
+
```
|
143
|
+
|
144
|
+
### EventTube
|
145
|
+
|
146
|
+
The `EventTube` implements the `Publish-subscribe` pattern. You can subscribe to events and publish them.
|
147
|
+
|
148
|
+
#### Examples
|
149
|
+
|
150
|
+
`examples/email_service/email_service.rb`
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
include_example 'email_service/email_service'
|
154
|
+
```
|
155
|
+
|
156
|
+
`examples/user_service/event_tube.rb`
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
include_example 'user_service/event_tube'
|
93
160
|
```
|
94
161
|
|
95
162
|
## Build README
|
96
163
|
|
97
|
-
Make changes to README.md.template
|
164
|
+
Make changes to `README.md.template`, not to `README.md`
|
98
165
|
|
99
166
|
Include examples with
|
100
167
|
|
101
168
|
```bash
|
102
|
-
include_example example_file_name
|
169
|
+
include_example 'example_file_name'
|
103
170
|
```
|
104
171
|
|
105
172
|
Build README.md with
|
106
173
|
|
107
174
|
```bash
|
108
|
-
|
175
|
+
rake build_readme
|
176
|
+
```
|
177
|
+
|
178
|
+
Always commit `README.md.template` and `README.md` together.
|
179
|
+
|
180
|
+
## Examples
|
181
|
+
|
182
|
+
Run all examples via
|
183
|
+
|
184
|
+
```bash
|
185
|
+
rake examples
|
109
186
|
```
|
110
187
|
|
111
|
-
|
188
|
+
To verify all examples run:
|
189
|
+
|
190
|
+
```bash
|
191
|
+
rake examples:verify
|
192
|
+
```
|
193
|
+
|
194
|
+
Note: Examples will be verified during CI run.
|
195
|
+
|
112
196
|
|
113
197
|
## Contributing
|
114
198
|
|
data/Rakefile
CHANGED
data/bin/build_readme
CHANGED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'user_service/event_tube'
|
2
|
+
require 'user_service/user_gateway'
|
3
|
+
require 'email_service/email_service'
|
4
|
+
|
5
|
+
UserService::EventTube.subscribe :user_registered do |event|
|
6
|
+
EmailService.send_user_registration_email_to event.user # => 'Send out email to Bob'
|
7
|
+
end
|
8
|
+
|
9
|
+
UserService::UserGateway.new.create(:nickname => 'Bob')
|
data/examples/runtime.rb
CHANGED
@@ -1,32 +1,15 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
|
4
|
-
module MyApplication
|
5
|
-
class RuntimeLoader < Rohbau::RuntimeLoader
|
6
|
-
def initialize
|
7
|
-
super(Runtime)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
class Runtime < Rohbau::Runtime
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
module UserService
|
16
|
-
class RuntimeLoader < Rohbau::RuntimeLoader
|
17
|
-
def initialize
|
18
|
-
super(Runtime)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class Runtime < Rohbau::Runtime
|
23
|
-
end
|
24
|
-
end
|
1
|
+
require 'my_application'
|
2
|
+
require 'user_service/runtime'
|
25
3
|
|
26
4
|
# Register user service on my application runtime
|
27
5
|
MyApplication::Runtime.register :user_service, UserService::RuntimeLoader
|
6
|
+
|
7
|
+
# My application runtime knowns about the registered plugins
|
28
8
|
MyApplication::Runtime.plugins # => {:user_service=>UserService::RuntimeLoader}
|
29
9
|
|
10
|
+
# The registered plugin knows his registrar
|
11
|
+
UserService::RuntimeLoader.registrar # => MyApplication::Runtime
|
12
|
+
|
30
13
|
# Runtimes are not initialized yet
|
31
14
|
MyApplication::RuntimeLoader.instance # => nil
|
32
15
|
MyApplication::Runtime.plugins[:user_service].instance # => nil
|
@@ -3,9 +3,9 @@ require 'rohbau/service_factory'
|
|
3
3
|
MyServiceFactory = Class.new(Rohbau::ServiceFactory)
|
4
4
|
|
5
5
|
MyServiceFactory.external_dependencies :user_service
|
6
|
-
MyServiceFactory.missing_dependencies # => [:user_service]
|
6
|
+
MyServiceFactory.missing_dependencies # => [:user_service]
|
7
7
|
MyServiceFactory.external_dependencies_complied? # => false
|
8
8
|
|
9
|
-
MyServiceFactory.register(:user_service) { Object.new } # => :user_service
|
10
|
-
MyServiceFactory.external_dependencies_complied? # => true
|
11
|
-
MyServiceFactory.missing_dependencies # => []
|
9
|
+
MyServiceFactory.register(:user_service) { Object.new } # => :user_service
|
10
|
+
MyServiceFactory.external_dependencies_complied? # => true
|
11
|
+
MyServiceFactory.missing_dependencies # => []
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'user_service/runtime'
|
2
|
+
require 'user_service/request'
|
3
|
+
require 'user_service/create_user_use_case'
|
4
|
+
|
5
|
+
# Boot up user service
|
6
|
+
UserService::RuntimeLoader.new
|
7
|
+
|
8
|
+
request = UserService::Request.new
|
9
|
+
|
10
|
+
UserService::CreateUser.new(request, :nickname => 'Bob').call # => 'Created user Bob'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rohbau/entity'
|
2
|
+
|
3
|
+
class User < Rohbau::Entity
|
4
|
+
attributes :uid, :nickname
|
5
|
+
|
6
|
+
def initialize(user_data = {})
|
7
|
+
self.nickname = user_data[:nickname]
|
8
|
+
super()
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
bob = User.new
|
13
|
+
bob.nickname = 'Bob'
|
14
|
+
bob.nickname # => 'Bob'
|
15
|
+
|
16
|
+
other_bob = User.new
|
17
|
+
other_bob.nickname = 'Bob'
|
18
|
+
other_bob.nickname # => 'Bob'
|
19
|
+
|
20
|
+
bob == other_bob # => true
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rohbau/request'
|
2
|
+
require 'user_service/service_factory'
|
3
|
+
|
4
|
+
module UserService
|
5
|
+
class Request < Rohbau::Request
|
6
|
+
def initialize(runtime = RuntimeLoader.instance)
|
7
|
+
super(runtime)
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def build_service_factory
|
13
|
+
ServiceFactory.new(@runtime)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'user_service/event_tube'
|
2
|
+
require 'user_entity'
|
3
|
+
require 'rohbau/default_memory_gateway'
|
4
|
+
|
5
|
+
module UserService
|
6
|
+
class UserGateway < Rohbau::DefaultMemoryGateway
|
7
|
+
def create(user_data)
|
8
|
+
user = User.new(user_data)
|
9
|
+
add(user)
|
10
|
+
EventTube.publish :user_registered, UserRegisteredEvent.new(user)
|
11
|
+
end
|
12
|
+
|
13
|
+
class UserRegisteredEvent < Struct.new(:user)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
examples/email_service/email_service.rb
|
2
|
+
|
3
|
+
examples/event_tube.rb
|
4
|
+
Send out email to Bob
|
5
|
+
examples/my_application.rb
|
6
|
+
|
7
|
+
examples/runtime.rb
|
8
|
+
|
9
|
+
examples/service_factory.rb
|
10
|
+
examples/service_factory.rb:21:in `<main>': undefined method `user_service' for #<MyServiceFactory:0xa12e7b0> (NoMethodError)
|
11
|
+
|
12
|
+
examples/service_factory_validation.rb
|
13
|
+
|
14
|
+
examples/use_case.rb
|
15
|
+
|
16
|
+
examples/user_entity.rb
|
17
|
+
|
18
|
+
examples/user_service.rb
|
19
|
+
|
20
|
+
examples/user_service/create_user_use_case.rb
|
21
|
+
|
22
|
+
examples/user_service/event_tube.rb
|
23
|
+
|
24
|
+
examples/user_service/request.rb
|
25
|
+
|
26
|
+
examples/user_service/runtime.rb
|
27
|
+
|
28
|
+
examples/user_service/service_factory.rb
|
29
|
+
|
30
|
+
examples/user_service/user_gateway.rb
|
31
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
|
3
|
+
describe 'Verify examples' do
|
4
|
+
let(:fixture_dir) do
|
5
|
+
Pathname.new(File.dirname(__FILE__))
|
6
|
+
end
|
7
|
+
let(:expected_output) do
|
8
|
+
File.read(fixture_dir.join('examples.txt'))
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'verifies examples' do
|
12
|
+
actual, error = capture_subprocess_io do
|
13
|
+
system 'rake examples'
|
14
|
+
end
|
15
|
+
|
16
|
+
assert_possibly_equal actual, expected_output
|
17
|
+
assert_equal '', error
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def assert_possibly_equal(exp, act)
|
23
|
+
assert_equal mu_pp_for_diff(exp), mu_pp_for_diff(act)
|
24
|
+
end
|
25
|
+
end
|
data/lib/rohbau/application.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
module Rohbau
|
2
2
|
module Application
|
3
|
-
|
4
3
|
class RuntimeWrapper
|
5
4
|
def self.wrap(&constructor)
|
6
5
|
wrapper = Class.new do
|
@@ -37,12 +36,12 @@ module Rohbau
|
|
37
36
|
end
|
38
37
|
|
39
38
|
def domain_requests
|
40
|
-
domains.map{|d| d.const_get :Request }
|
39
|
+
domains.map { |d| d.const_get :Request }
|
41
40
|
end
|
42
41
|
|
43
42
|
def use_case_domains
|
44
43
|
domains.select do |domain|
|
45
|
-
domain.const_defined?(
|
44
|
+
domain.const_defined?(:UseCases)
|
46
45
|
end
|
47
46
|
end
|
48
47
|
|
@@ -54,17 +53,15 @@ module Rohbau
|
|
54
53
|
end
|
55
54
|
|
56
55
|
domains.inject([]) do |use_cases, domain|
|
57
|
-
|
58
|
-
|
59
|
-
use_case_namespace = domain.const_get('UseCases')
|
56
|
+
if domain.const_defined?(:UseCases)
|
57
|
+
use_case_namespace = domain.const_get(:UseCases)
|
60
58
|
use_case_namespace.constants.each do |use_case_class_name|
|
61
|
-
use_cases << use_case_namespace
|
59
|
+
use_cases << use_case_namespace.const_get(use_case_class_name)
|
62
60
|
end
|
63
61
|
end
|
64
62
|
|
65
63
|
use_cases
|
66
64
|
end
|
67
65
|
end
|
68
|
-
|
69
66
|
end
|
70
67
|
end
|
@@ -2,7 +2,6 @@ require 'rohbau/index'
|
|
2
2
|
|
3
3
|
module Rohbau
|
4
4
|
class DefaultMemoryGateway
|
5
|
-
|
6
5
|
def initialize(memory = Index.new, services = {})
|
7
6
|
@memory = memory
|
8
7
|
@services = services
|
@@ -73,6 +72,5 @@ module Rohbau
|
|
73
72
|
def gateway_for_entity(entity_name)
|
74
73
|
service(:"#{entity_name}_gateway")
|
75
74
|
end
|
76
|
-
|
77
75
|
end
|
78
76
|
end
|
data/lib/rohbau/entity.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
module Rohbau
|
2
|
-
|
3
2
|
class Entity
|
4
3
|
class << self; attr_accessor :__attributes__ end
|
5
4
|
def self.attributes(*attributes)
|
6
5
|
@__attributes__ ||= []
|
7
6
|
@__attributes__ += attributes
|
8
7
|
|
9
|
-
|
10
8
|
predicate_attributes = attributes.select do |attr|
|
11
9
|
attr =~ /\?$/
|
12
10
|
end
|
@@ -33,9 +31,9 @@ module Rohbau
|
|
33
31
|
end
|
34
32
|
|
35
33
|
protected
|
34
|
+
|
36
35
|
def __attributes__
|
37
36
|
self.class.__attributes__ || []
|
38
37
|
end
|
39
38
|
end
|
40
|
-
|
41
39
|
end
|
data/lib/rohbau/event_tube.rb
CHANGED
@@ -3,6 +3,7 @@ module Rohbau
|
|
3
3
|
def self.reset
|
4
4
|
@subscriptions = nil
|
5
5
|
end
|
6
|
+
|
6
7
|
def self.publish(name, event)
|
7
8
|
subscription_handler.handle(name, event)
|
8
9
|
end
|
@@ -17,7 +18,7 @@ module Rohbau
|
|
17
18
|
|
18
19
|
class SubscriptionHandler
|
19
20
|
def initialize
|
20
|
-
@subscriptions = Hash.new do |h,k|
|
21
|
+
@subscriptions = Hash.new do |h, k|
|
21
22
|
h[k] = []
|
22
23
|
end
|
23
24
|
end
|
data/lib/rohbau/index.rb
CHANGED
@@ -18,7 +18,6 @@ module Rohbau
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def add(entity)
|
21
|
-
|
22
21
|
if option?(:uid_generation)
|
23
22
|
validate :add, entity
|
24
23
|
|
@@ -154,8 +153,8 @@ module Rohbau
|
|
154
153
|
ensure_uid_exists!(uid)
|
155
154
|
end
|
156
155
|
|
157
|
-
|
158
156
|
private
|
157
|
+
|
159
158
|
def ensure_uid!(uid)
|
160
159
|
if uid.nil?
|
161
160
|
raise argument_error('uid is missing')
|
@@ -175,7 +174,7 @@ module Rohbau
|
|
175
174
|
end
|
176
175
|
|
177
176
|
def ensure_entity_has_uid!(entity)
|
178
|
-
|
177
|
+
unless entity.uid
|
179
178
|
raise argument_error('entity has no uid', entity)
|
180
179
|
end
|
181
180
|
end
|
@@ -187,13 +186,13 @@ module Rohbau
|
|
187
186
|
end
|
188
187
|
|
189
188
|
def ensure_entity_exists!(entity)
|
190
|
-
|
189
|
+
unless @memory.has_uid?(entity.uid)
|
191
190
|
raise argument_error('entity is unknown', entity)
|
192
191
|
end
|
193
192
|
end
|
194
193
|
|
195
194
|
def ensure_uid_exists!(uid)
|
196
|
-
|
195
|
+
unless @memory.has_uid?(uid)
|
197
196
|
raise argument_error('uid is unknown', uid)
|
198
197
|
end
|
199
198
|
end
|