rohbau 0.1.0 → 0.2.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.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8d05d28272851e7d359b3640cdb9e4a21250f704
4
- data.tar.gz: 183ca9c967b841d7dc8e4bc6dbdd57e222eab5fc
3
+ metadata.gz: aba07a5627f76c6095247bcbfbd5ef8f4cc3e221
4
+ data.tar.gz: 79c36065afca542bc02b79a77eca590e4b9bdde4
5
5
  SHA512:
6
- metadata.gz: 9b144522c39a33baa618b912f17e3f9a2a6f743a910194cc052409cd890992a0994eb629da418eb5b5d8cb1816f64159f944c9daada4b55546b1b58f71a86529
7
- data.tar.gz: 9e6e8cd4e34c668c81172180d3ca99b64af7d5b32e9b1d19a35a72c420e2ad15eda820b0c122f6529bb2a946fe56c0a1d7dbc854bb5b4e458791edfd661e96f7
6
+ metadata.gz: f3951dabbee7a5af8d4e279935b33bed6475ec31a4b90ed8446ad03b6b89c93496ddcc26f6c1feaf849aee1316bf8ef0b9b6eda065a071e40bf6e34347459ed7
7
+ data.tar.gz: 54b582e38ce22964cdc44b87f0b3a2f2aa776bd6241b0bd74f5dcbe7180970635c8cbff8b72ed15256ff9197f9d4f12391790567e6a4ffeca0171c95d14b456c
data/.rubocop.yml ADDED
@@ -0,0 +1,18 @@
1
+ # Generated by `rubocop --auto-gen-config`
2
+ inherit_from: .rubocop_todo.yml
3
+
4
+ Metrics/LineLength:
5
+ Exclude:
6
+ - rohbau.gemspec
7
+ - examples/**/*.rb
8
+
9
+ Style/AlignParameters:
10
+ EnforcedStyle: with_fixed_indentation
11
+
12
+ # Prefer foo: :bar
13
+ Style/HashSyntax:
14
+ EnforcedStyle: hash_rockets
15
+
16
+ # Let Inch check that
17
+ Style/Documentation:
18
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,149 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2015-03-08 22:50:04 +0100 using RuboCop version 0.29.1.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 1
9
+ Lint/HandleExceptions:
10
+ Enabled: false
11
+
12
+ # Offense count: 1
13
+ # Cop supports --auto-correct.
14
+ Lint/UnusedBlockArgument:
15
+ Enabled: false
16
+
17
+ # Offense count: 2
18
+ # Cop supports --auto-correct.
19
+ Lint/UnusedMethodArgument:
20
+ Enabled: false
21
+
22
+ # Offense count: 2
23
+ Lint/UselessComparison:
24
+ Enabled: false
25
+
26
+ # Offense count: 2
27
+ Lint/Void:
28
+ Enabled: false
29
+
30
+ # Offense count: 1
31
+ Metrics/AbcSize:
32
+ Max: 20
33
+
34
+ # Offense count: 3
35
+ # Configuration parameters: CountComments.
36
+ Metrics/MethodLength:
37
+ Max: 14
38
+
39
+ # Offense count: 2
40
+ Style/AccessorMethodName:
41
+ Enabled: false
42
+
43
+ # Offense count: 2
44
+ Style/CaseEquality:
45
+ Enabled: false
46
+
47
+ # Offense count: 2
48
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
49
+ Style/ClassAndModuleChildren:
50
+ Enabled: false
51
+
52
+ # Offense count: 2
53
+ # Cop supports --auto-correct.
54
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
55
+ Style/ClassCheck:
56
+ Enabled: false
57
+
58
+ # Offense count: 3
59
+ Style/DoubleNegation:
60
+ Enabled: false
61
+
62
+ # Offense count: 1
63
+ Style/EachWithObject:
64
+ Enabled: false
65
+
66
+ # Offense count: 8
67
+ # Configuration parameters: MinBodyLength.
68
+ Style/GuardClause:
69
+ Enabled: false
70
+
71
+ # Offense count: 6
72
+ # Configuration parameters: MaxLineLength.
73
+ Style/IfUnlessModifier:
74
+ Enabled: false
75
+
76
+ # Offense count: 1
77
+ # Cop supports --auto-correct.
78
+ # Configuration parameters: IncludeSemanticChanges.
79
+ Style/NonNilCheck:
80
+ Enabled: false
81
+
82
+ # Offense count: 2
83
+ # Cop supports --auto-correct.
84
+ # Configuration parameters: PreferredDelimiters.
85
+ Style/PercentLiteralDelimiters:
86
+ Enabled: false
87
+
88
+ # Offense count: 1
89
+ # Cop supports --auto-correct.
90
+ Style/PerlBackrefs:
91
+ Enabled: false
92
+
93
+ # Offense count: 1
94
+ # Configuration parameters: NamePrefix, NamePrefixBlacklist.
95
+ Style/PredicateName:
96
+ Enabled: false
97
+
98
+ # Offense count: 1
99
+ # Cop supports --auto-correct.
100
+ Style/Proc:
101
+ Enabled: false
102
+
103
+ # Offense count: 3
104
+ # Cop supports --auto-correct.
105
+ Style/RedundantSelf:
106
+ Enabled: false
107
+
108
+ # Offense count: 3
109
+ # Configuration parameters: MaxSlashes.
110
+ Style/RegexpLiteral:
111
+ Enabled: false
112
+
113
+ # Offense count: 12
114
+ # Cop supports --auto-correct.
115
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
116
+ Style/SignalException:
117
+ Enabled: false
118
+
119
+ # Offense count: 1
120
+ # Cop supports --auto-correct.
121
+ Style/SpecialGlobalVars:
122
+ Enabled: false
123
+
124
+ # Offense count: 31
125
+ # Cop supports --auto-correct.
126
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
127
+ Style/StringLiterals:
128
+ Enabled: false
129
+
130
+ # Offense count: 1
131
+ Style/StructInheritance:
132
+ Enabled: false
133
+
134
+ # Offense count: 7
135
+ # Cop supports --auto-correct.
136
+ # Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, Whitelist.
137
+ Style/TrivialAccessors:
138
+ Enabled: false
139
+
140
+ # Offense count: 1
141
+ # Cop supports --auto-correct.
142
+ Style/UnneededPercentQ:
143
+ Enabled: false
144
+
145
+ # Offense count: 1
146
+ # Cop supports --auto-correct.
147
+ # Configuration parameters: WordRegex.
148
+ Style/WordArray:
149
+ MinSize: 2
data/.travis.yml CHANGED
@@ -1,6 +1,7 @@
1
1
  language: ruby
2
2
  sudo: false
3
3
  cache: bundler
4
+ script: "bundle exec rake ci"
4
5
  rvm:
5
6
  - ruby-head
6
7
  - 2.2
@@ -12,6 +13,7 @@ rvm:
12
13
  - jruby-19mode # JRuby in 1.9 mode
13
14
  env:
14
15
  global:
16
+ - CODECLIMATE_REPO_TOKEN=bff5110004e542a78ce5dd5fb7f154ac06cdc5a564d54957656a56e79bf1a031
15
17
  - JRUBY_OPTS='--dev -J-Xmx1024M'
16
18
  matrix:
17
19
  fast_finish: true
data/Gemfile CHANGED
@@ -6,3 +6,7 @@ gemspec
6
6
  if ENV['CODECLIMATE_REPO_TOKEN']
7
7
  gem "codeclimate-test-reporter", :group => :test, :require => nil
8
8
  end
9
+
10
+ group :tools do
11
+ gem 'rubocop'
12
+ end
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 TODO: Write your name
1
+ Copyright (c) 2013-2015 Neopoly GmbH
2
2
 
3
3
  MIT License
4
4
 
data/README.md 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,6 +52,8 @@ 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
58
  require 'rohbau/runtime'
57
59
  require 'rohbau/runtime_loader'
@@ -67,6 +69,14 @@ module MyApplication
67
69
  end
68
70
  end
69
71
 
72
+ ```
73
+
74
+ `examples/user_service/runtime.rb`
75
+
76
+ ```ruby
77
+ require 'rohbau/runtime'
78
+ require 'rohbau/runtime_loader'
79
+
70
80
  module UserService
71
81
  class RuntimeLoader < Rohbau::RuntimeLoader
72
82
  def initialize
@@ -78,10 +88,23 @@ module UserService
78
88
  end
79
89
  end
80
90
 
91
+ ```
92
+
93
+ `examples/runtime.rb`
94
+
95
+ ```ruby
96
+ require 'my_application'
97
+ require 'user_service/runtime'
98
+
81
99
  # Register user service on my application runtime
82
100
  MyApplication::Runtime.register :user_service, UserService::RuntimeLoader
101
+
102
+ # My application runtime knowns about the registered plugins
83
103
  MyApplication::Runtime.plugins # => {:user_service=>UserService::RuntimeLoader}
84
104
 
105
+ # The registered plugin knows his registrar
106
+ UserService::RuntimeLoader.registrar # => MyApplication::Runtime
107
+
85
108
  # Runtimes are not initialized yet
86
109
  MyApplication::RuntimeLoader.instance # => nil
87
110
  MyApplication::Runtime.plugins[:user_service].instance # => nil
@@ -105,17 +128,6 @@ MyApplication::RuntimeLoader.running? # => false
105
128
 
106
129
  ```
107
130
 
108
- ##### Registrar
109
-
110
- Every injected `RuntimeLoader` knows about it's registrar.
111
- In the example above `UserService::RuntimeLoader` has been injected to `MyApplication::RuntimeLoader`.
112
- `UserService::RuntimeLoader.registrar` therefore returns `MyApplication::RuntimeLoader`.
113
-
114
- ##### List of plugins
115
-
116
- Accordingly to the sample above `MyApplication::RuntimeLoader` knows about it's registered plugins.
117
- `MyApplication::RuntimeLoader.plugins` therefore returns `{:user_service => UserService::RuntimeLoader}`.
118
-
119
131
  ### ServiceFactory
120
132
 
121
133
  The `ServiceFactory` is considered the authority for retrieval of service instances.
@@ -125,6 +137,8 @@ It follows partly the service locator / registry pattern.
125
137
 
126
138
  Register and unregister default service and override with specific service.
127
139
 
140
+ `examples/user_service/service_factory.rb`
141
+
128
142
  ```ruby
129
143
  require 'rohbau/service_factory'
130
144
 
@@ -152,33 +166,403 @@ registry.user_service # => NoMethodError: undefined method `user_service'
152
166
 
153
167
  Validate registered dependencies
154
168
 
169
+ `examples/user_service/service_factory_validation.rb`
170
+
155
171
  ```ruby
172
+ require 'rohbau/service_factory'
173
+
174
+ MyServiceFactory = Class.new(Rohbau::ServiceFactory)
175
+
156
176
  MyServiceFactory.external_dependencies :user_service
157
- MyServiceFactory.missing_dependencies # => [:user_service]
177
+ MyServiceFactory.missing_dependencies # => [:user_service]
158
178
  MyServiceFactory.external_dependencies_complied? # => false
159
179
 
160
- MyServiceFactory.register(:user_service) { Object.new } # => :user_service
161
- MyServiceFactory.external_dependencies_complied? # => true
162
- MyServiceFactory.missing_dependencies # => []
180
+ MyServiceFactory.register(:user_service) { Object.new } # => :user_service
181
+ MyServiceFactory.external_dependencies_complied? # => true
182
+ MyServiceFactory.missing_dependencies # => []
183
+
184
+ ```
185
+
186
+ ### Request
187
+
188
+ It ensures an initialized runtime and builds up a new the service factory instance.
189
+
190
+ `examples/user_service/request.rb`
191
+
192
+ ```ruby
193
+ require 'rohbau/request'
194
+ require 'user_service/service_factory'
195
+
196
+ module UserService
197
+ class Request < Rohbau::Request
198
+ def initialize(runtime = RuntimeLoader.instance)
199
+ super(runtime)
200
+ end
201
+
202
+ protected
203
+
204
+ def build_service_factory
205
+ ServiceFactory.new(@runtime)
206
+ end
207
+ end
208
+ end
209
+
210
+ ```
211
+
212
+ ### Entity
213
+
214
+ Entities are low level, logic-less, data structures.
215
+
216
+ `examples/user_entity.rb`
217
+
218
+ ```ruby
219
+ require 'rohbau/entity'
220
+
221
+ class User < Rohbau::Entity
222
+ attributes :uid, :nickname
223
+
224
+ def initialize(user_data = {})
225
+ self.nickname = user_data[:nickname]
226
+ super()
227
+ end
228
+ end
229
+
230
+ bob = User.new
231
+ bob.nickname = 'Bob'
232
+ bob.nickname # => 'Bob'
233
+
234
+ other_bob = User.new
235
+ other_bob.nickname = 'Bob'
236
+ other_bob.nickname # => 'Bob'
237
+
238
+ bob == other_bob # => true
239
+
240
+ ```
241
+
242
+ ### Gateway
243
+
244
+ Provides an interface to persist entities.
245
+
246
+ `examples/user_service/user_gateway.rb`
247
+
248
+ ```ruby
249
+ require 'user_service/event_tube'
250
+ require 'user_entity'
251
+ require 'rohbau/default_memory_gateway'
252
+
253
+ module UserService
254
+ class UserGateway < Rohbau::DefaultMemoryGateway
255
+ def create(user_data)
256
+ user = User.new(user_data)
257
+ add(user)
258
+ EventTube.publish :user_registered, UserRegisteredEvent.new(user)
259
+ end
260
+
261
+ class UserRegisteredEvent < Struct.new(:user)
262
+ end
263
+ end
264
+ end
265
+
266
+ ```
267
+
268
+ ### UseCase
269
+
270
+ `UseCases` define the interface for the end user who interacts with the system.
271
+
272
+ #### Examples
273
+
274
+ Define a class that inherits from `Rohbau::UseCase` which has a `#call` method:
275
+
276
+ `examples/user_service/create_user_use_case.rb`
277
+
278
+ ```ruby
279
+ require 'rohbau/use_case'
280
+
281
+ module UserService
282
+ class CreateUser < Rohbau::UseCase
283
+ def initialize(request, user_data)
284
+ super(request)
285
+ @user_data = user_data
286
+ end
287
+
288
+ def call
289
+ service(:user_service).create(@user_data)
290
+ end
291
+ end
292
+ end
293
+
294
+ ```
295
+
296
+ And call the CreateUser use case as follows:
297
+
298
+ `examples/use_case.rb`
299
+
300
+ ```ruby
301
+ require 'user_service/runtime'
302
+ require 'user_service/request'
303
+ require 'user_service/create_user_use_case'
304
+
305
+ # Boot up user service
306
+ UserService::RuntimeLoader.new
307
+
308
+ request = UserService::Request.new
309
+ UserService::CreateUser.new(request, {:nickname => 'Bob'}).call # => 'Created user Bob'
310
+
311
+ ```
312
+
313
+ Alternately, use cases can be called using `Interface`, which is detailed in the next section.
314
+
315
+ ### Interface
316
+
317
+ `Interface` allows for simpler and more semantic use case calling, with the additional benefit of fine grain control of return values and spy-like access in a test context.
318
+
319
+ **Please note**: `Interface` requires an `Input` class in your use case, as well as a `Success` class if you are using the stub features.
320
+
321
+ In a nutshell, `Interface` allows your use case calls to go from this:
322
+
323
+ ```ruby
324
+ require 'user_service/runtime'
325
+ require 'user_service/request'
326
+ require 'user_service/create_user_use_case'
327
+
328
+ # Boot up user service
329
+ UserService::RuntimeLoader.new
330
+
331
+ request = UserService::Request.new
332
+ input = {
333
+ :user_data => {
334
+ :nickname => 'Bob'
335
+ }
336
+ }
337
+ UserService::CreateUser.new(request, input).call
338
+
339
+ ```
340
+
341
+ To this:
342
+
343
+ ```ruby
344
+ require 'rohbau/interface'
345
+ require 'user_service/create_user_use_case'
346
+
347
+ interface = Rohbau::Interface.new
348
+ interface.user_service :create_user, :user_data => {
349
+ :nickname => 'Bob'
350
+ }
351
+ ```
352
+
353
+ This increased simplicity is very helpful, but the majority of `Interface`'s usefulness becomes accessible while testing. Assume the following use case:
354
+
355
+ ```ruby
356
+ module UserService
357
+ module UseCases
358
+ class CreateUser
359
+ Input = Bound.required :user_data
360
+ Success = Bound.required :user_uid
361
+ Error = Bound.required :message
362
+
363
+ def initialize(request, input)
364
+ @request = request
365
+ @user_data = input.user_data
366
+ end
367
+
368
+ def call
369
+ result = service(:user_service).create(@user_data)
370
+
371
+ if result.nil?
372
+ Error.new :message => "Something went wrong"
373
+ else
374
+ Success.new :user_uid => "uid_for_#{user_data.nickname}"
375
+ end
376
+ end
377
+ end
378
+ end
379
+ end
380
+ ```
381
+ #### Stubbing use case return values
382
+
383
+ Let's assume this use case will be called, along with many other use cases, by the frontend framework of your choosing.
384
+
385
+ Frontend tests should be implemented with the actual objects they would use in production, but since test isolation is an important concept in DDD, the `UserService` domain, which is outside of the scope of the frontend, should never actually be called.
386
+
387
+ Beyond this, we will also want to stub return values to create the various test cases we may have - when there is no user present, for example.
388
+
389
+ These requirements can be realized by passing the following keys to your use case:
390
+
391
+ * `:stub_result`
392
+ When the `stub_result` key is present, its value will be passed to the called use case and returned in subsequent calls to that same use case as a `Success` object.
393
+ * `:stub_type`
394
+ Much like the `stub_result` key, the `stub_type` key allows the type of return value to be overwritten, provided, of course, that it is a type which is defined by your use case.
395
+
396
+ ```ruby
397
+ require 'rohbau/interface'
398
+
399
+ describe 'stubbing use case return values' do
400
+ let(:interface) { Rohbau::Interface.new }
401
+
402
+ it 'returns subsequent calls to the same use case as stubs' do
403
+ interface.user_service :create_user, :stub_result => {
404
+ :user_data => { :user_uid => "definitely NOT bob's uid" }
405
+ }
406
+
407
+ result = interface.user_service :create_user, :user_data => {
408
+ :nickname => 'bob'
409
+ }
410
+
411
+ assert_kind_of UserService::UseCases::CreateUser::Success, result
412
+ assert_equal "definitely NOT bob's uid", result.user_uid
413
+ end
414
+
415
+ it 'can also return other result types' do
416
+ interface.user_service :create_user,
417
+ :stub_type => :Error,
418
+ :stub_result => {
419
+ :message => "error"
420
+ }
421
+
422
+ result = interface.user_service :create_user
423
+
424
+ assert_kind_of UserService::UseCases::CreateUser::Error, result
425
+ assert_equal 'error', result.message
426
+ end
427
+ end
428
+ ```
429
+ #### Test spying
430
+
431
+ Sometimes it's helpful to look into the use case and see some details about how it has been called. There are two methods to this end, each of which returns a hash with keys corresponding to each use case which has been called:
432
+
433
+ * `interface.calls` is further keyed by argument and returns the value passed to the given argument.
434
+ * `interface.call_count` returns the number of times a given use case has been called.
435
+
436
+ ```ruby
437
+ require 'rohbau/interface'
438
+
439
+ describe 'spying on tests' do
440
+ let(:interface) { Rohbau::Interface.new }
441
+
442
+ it 'records passed arguments by use_case' do
443
+ interface.user_service :create_user, :user_data => {
444
+ :nickname => 'bob'
445
+ }
446
+
447
+ result = interface.calls[:create_user][:user_uid]
448
+
449
+ assert_equal "23", result
450
+ end
451
+
452
+ it 'records number of unstubbed calls to each use_case' do
453
+ interface.user_service :create_user, :stub_result => {
454
+ :user_data => { :user_uid => 'something else' }
455
+ }
456
+
457
+ interface.user_service :create_user, :user_data => {
458
+ :nickname => 'bob'
459
+ }
460
+
461
+ interface.user_service :create_user, :user_data => {
462
+ :nickname => 'bob'
463
+ }
464
+
465
+ assert_equal 2, interface.call_count[:create_user]
466
+ end
467
+ end
468
+ ```
469
+
470
+ #### Cleaning up
471
+
472
+ `Interface` provides the following two convenience methods for cleaning up your test environment:
473
+
474
+ * `interface.clear_stubs` does what it says on the tin - All recorded arguments, call counts, stubbed results and stubbed types are cleared.
475
+ * `interface.clear_cached_requests` empties the request cache.
476
+
477
+ ```ruby
478
+ require 'rohbau/interface'
479
+
480
+ let(:interface) { Rohbau::Interface.new }
481
+ it 'can clear all stubbed results' do
482
+ interface.user_service :create_user, :stub_result => {
483
+ :user_data => { :user_uid => 'something else' }
484
+ }
485
+
486
+ result = interface.user_service :create_user, :user_data => {
487
+ :nickname => 'bob'
488
+ }
489
+
490
+ assert_equal 'something else', result.user_uid
491
+
492
+ interface.clear_stubs
493
+
494
+ result = interface.user_service :create_user, :user_data => {
495
+ :nickname => 'bob'
496
+ }
497
+
498
+ refute_equal 'something else', result.user_uid
499
+ assert_equal 'uid_for_bob', result.user_uid
500
+ end
501
+ ```
502
+
503
+ ### EventTube
504
+
505
+ The `EventTube` implements the `Publish-subscribe` pattern. You can subscribe to events and publish them.
506
+
507
+ #### Examples
508
+
509
+ `examples/email_service/email_service.rb`
510
+
511
+ ```ruby
512
+ class EmailService
513
+ def self.send_user_registration_email_to(user)
514
+ print "Send out email to #{user.nickname}"
515
+ end
516
+ end
517
+
518
+ ```
519
+
520
+ `examples/user_service/event_tube.rb`
521
+
522
+ ```ruby
523
+ require 'rohbau/event_tube'
524
+
525
+ module UserService
526
+ class EventTube < Rohbau::EventTube
527
+ end
528
+ end
529
+
163
530
  ```
164
531
 
165
532
  ## Build README
166
533
 
167
- Make changes to README.md.template, not to README.md
534
+ Make changes to `README.md.template`, not to `README.md`
168
535
 
169
536
  Include examples with
170
537
 
171
538
  ```bash
172
- include_example example_file_name
539
+ include_example 'example_file_name'
173
540
  ```
174
541
 
175
542
  Build README.md with
176
543
 
177
544
  ```bash
178
- ./bin/build_readme
545
+ rake build_readme
546
+ ```
547
+
548
+ Always commit `README.md.template` and `README.md` together.
549
+
550
+ ## Examples
551
+
552
+ Run all examples via
553
+
554
+ ```bash
555
+ rake examples
556
+ ```
557
+
558
+ To verify all examples run:
559
+
560
+ ```bash
561
+ rake examples:verify
179
562
  ```
180
563
 
181
- Always commit README.md.template and README.md together.
564
+ Note: Examples will be verified during CI run.
565
+
182
566
 
183
567
  ## Contributing
184
568