rohbau 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +18 -0
  3. data/.rubocop_todo.yml +149 -0
  4. data/.travis.yml +2 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +1 -1
  7. data/README.md +404 -20
  8. data/README.md.template +104 -20
  9. data/Rakefile +1 -1
  10. data/bin/build_readme +3 -1
  11. data/examples/email_service/email_service.rb +5 -0
  12. data/examples/event_tube.rb +9 -0
  13. data/examples/my_application.rb +13 -0
  14. data/examples/runtime.rb +7 -24
  15. data/examples/service_factory_validation.rb +4 -4
  16. data/examples/use_case.rb +10 -0
  17. data/examples/user_entity.rb +20 -0
  18. data/examples/user_service/create_user_use_case.rb +14 -0
  19. data/examples/user_service/event_tube.rb +6 -0
  20. data/examples/user_service/request.rb +16 -0
  21. data/examples/user_service/runtime.rb +13 -0
  22. data/examples/user_service/service_factory.rb +10 -0
  23. data/examples/user_service/user_gateway.rb +16 -0
  24. data/examples/user_service.rb +1 -0
  25. data/examples/verify/examples.txt +31 -0
  26. data/examples/verify/examples_spec.rb +25 -0
  27. data/lib/rohbau/application.rb +5 -8
  28. data/lib/rohbau/default_memory_gateway.rb +0 -2
  29. data/lib/rohbau/entity.rb +1 -3
  30. data/lib/rohbau/event_tube.rb +2 -1
  31. data/lib/rohbau/index.rb +4 -5
  32. data/lib/rohbau/interface.rb +130 -0
  33. data/lib/rohbau/it_behaves_like.rb +0 -2
  34. data/lib/rohbau/minitest/exclude.rb +0 -6
  35. data/lib/rohbau/registry.rb +4 -6
  36. data/lib/rohbau/request.rb +2 -4
  37. data/lib/rohbau/request_cache.rb +19 -0
  38. data/lib/rohbau/require.rb +0 -1
  39. data/lib/rohbau/runtime.rb +0 -2
  40. data/lib/rohbau/service_factory.rb +1 -2
  41. data/lib/rohbau/shared_spec.rb +0 -2
  42. data/lib/rohbau/shared_specs/default_gateway.rb +2 -6
  43. data/lib/rohbau/use_case.rb +0 -3
  44. data/lib/rohbau/version.rb +1 -1
  45. data/lib/rohbau.rb +19 -1
  46. data/rakelib/build_readme.rake +23 -0
  47. data/rakelib/ci.rake +5 -0
  48. data/rakelib/examples.rake +16 -0
  49. data/rakelib/rubocop.rake +18 -0
  50. data/spec/event_tube_spec.rb +2 -3
  51. data/spec/interface_spec.rb +111 -0
  52. data/spec/runtime_loader_spec.rb +1 -2
  53. data/spec/service_factory_spec.rb +6 -9
  54. data/spec/shared_spec_spec.rb +0 -2
  55. metadata +43 -20
  56. data/etc/build_readme.rb +0 -14
data/README.md.template CHANGED
@@ -24,7 +24,7 @@
24
24
 
25
25
  ## Description
26
26
 
27
- Rohbau provides a set of patterns used in Domain Driven Design.
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 runtime
58
+ include_example 'my_application'
57
59
  ```
58
60
 
59
- ##### Registrar
61
+ `examples/user_service/runtime.rb`
60
62
 
61
- Every injected `RuntimeLoader` knows about it's registrar.
62
- In the example above `UserService::RuntimeLoader` has been injected to `MyApplication::RuntimeLoader`.
63
- `UserService::RuntimeLoader.registrar` therefore returns `MyApplication::RuntimeLoader`.
63
+ ```ruby
64
+ include_example 'user_service/runtime'
65
+ ```
64
66
 
65
- ##### List of plugins
67
+ `examples/runtime.rb`
66
68
 
67
- Accordingly to the sample above `MyApplication::RuntimeLoader` knows about it's registered plugins.
68
- `MyApplication::RuntimeLoader.plugins` therefore returns `{:user_service => UserService::RuntimeLoader}`.
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
- MyServiceFactory.external_dependencies :user_service
87
- MyServiceFactory.missing_dependencies # => [:user_service]
88
- MyServiceFactory.external_dependencies_complied? # => false
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
- MyServiceFactory.register(:user_service) { Object.new } # => :user_service
91
- MyServiceFactory.external_dependencies_complied? # => true
92
- MyServiceFactory.missing_dependencies # => []
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, not to README.md
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
- ./bin/build_readme
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
- Always commit README.md.template and README.md together.
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
@@ -1,5 +1,5 @@
1
1
  require 'bundler/gem_tasks'
2
- require "rake/testtask"
2
+ require 'rake/testtask'
3
3
 
4
4
  Rake::TestTask.new(:spec) do |t|
5
5
  t.libs += ['spec', 'lib']
data/bin/build_readme CHANGED
@@ -1 +1,3 @@
1
- cat README.md.template | etc/build_readme.rb > README.md
1
+ #!/bin/bash
2
+
3
+ echo 'Please use `rake build_readme`'
@@ -0,0 +1,5 @@
1
+ class EmailService
2
+ def self.send_user_registration_email_to(user)
3
+ print "Send out email to #{user.nickname}"
4
+ end
5
+ end
@@ -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')
@@ -0,0 +1,13 @@
1
+ require 'rohbau/runtime'
2
+ require 'rohbau/runtime_loader'
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
data/examples/runtime.rb CHANGED
@@ -1,32 +1,15 @@
1
- require 'rohbau/runtime'
2
- require 'rohbau/runtime_loader'
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,14 @@
1
+ require 'rohbau/use_case'
2
+
3
+ module UserService
4
+ class CreateUser < Rohbau::UseCase
5
+ def initialize(request, user_data)
6
+ super(request)
7
+ @user_data = user_data
8
+ end
9
+
10
+ def call
11
+ service(:user_service).create(@user_data)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,6 @@
1
+ require 'rohbau/event_tube'
2
+
3
+ module UserService
4
+ class EventTube < Rohbau::EventTube
5
+ end
6
+ end
@@ -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,13 @@
1
+ require 'rohbau/runtime'
2
+ require 'rohbau/runtime_loader'
3
+
4
+ module UserService
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
@@ -0,0 +1,10 @@
1
+ require 'rohbau/service_factory'
2
+ require 'user_service/user_gateway'
3
+
4
+ module UserService
5
+ class ServiceFactory < Rohbau::ServiceFactory
6
+ register :user_service do
7
+ UserGateway.new
8
+ end
9
+ end
10
+ 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
@@ -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?('UseCases')
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
- if domain.const_defined?('UseCases')
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::const_get(use_case_class_name)
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
@@ -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
- if !entity.uid
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
- if !@memory.has_uid?(entity.uid)
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
- if !@memory.has_uid?(uid)
195
+ unless @memory.has_uid?(uid)
197
196
  raise argument_error('uid is unknown', uid)
198
197
  end
199
198
  end