rest_my_case 1.10.9 → 1.11.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 (31) hide show
  1. checksums.yaml +5 -13
  2. data/README.md +330 -2
  3. data/lib/rest_my_case/base.rb +46 -21
  4. data/lib/rest_my_case/context/base.rb +11 -0
  5. data/lib/rest_my_case/context/schema_validator/base.rb +27 -0
  6. data/lib/rest_my_case/context/schema_validator/compel.rb +36 -0
  7. data/lib/rest_my_case/context/status.rb +2 -0
  8. data/lib/rest_my_case/defense_attorney/base.rb +1 -1
  9. data/lib/rest_my_case/http_status.rb +5 -8
  10. data/lib/rest_my_case/judge/base.rb +19 -14
  11. data/lib/rest_my_case/status.rb +13 -12
  12. data/lib/rest_my_case/trial/case.rb +3 -3
  13. data/lib/rest_my_case/validator.rb +3 -8
  14. data/lib/rest_my_case/version.rb +1 -1
  15. data/lib/rest_my_case.rb +0 -4
  16. data/rest_my_case.gemspec +1 -1
  17. data/spec/rest_my_case/accusation_attorneys/base_spec.rb +1 -1
  18. data/spec/rest_my_case/accusation_attorneys/each_spec.rb +1 -1
  19. data/spec/rest_my_case/accusation_attorneys/format_spec.rb +2 -2
  20. data/spec/rest_my_case/base/context_accessor_spec.rb +29 -0
  21. data/spec/rest_my_case/base/context_reader_spec.rb +21 -0
  22. data/spec/rest_my_case/base/context_writer_spec.rb +23 -0
  23. data/spec/rest_my_case/base/dependencies_spec.rb +14 -0
  24. data/spec/rest_my_case/base/invoke!_spec.rb +140 -0
  25. data/spec/rest_my_case/base/invoke_spec.rb +29 -0
  26. data/spec/rest_my_case/{base_spec.rb → base/perform_spec.rb} +0 -226
  27. data/spec/rest_my_case/base/required_context_spec.rb +33 -0
  28. data/spec/rest_my_case/context/status_spec.rb +2 -2
  29. data/spec/rest_my_case/status_spec.rb +6 -6
  30. data/spec/support/required_context.rb +49 -0
  31. metadata +42 -24
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NDg4NmJlMDBmZjRiMzBlZjg4MWE1ZDUxMzc1MGQwZThlNmI3MmViNw==
5
- data.tar.gz: !binary |-
6
- Yjk3MjkxNzg0MzU4ODA4OTVhYmFmMGM4Zjg0ZWYyZWUxY2RmZTQ5NQ==
2
+ SHA1:
3
+ metadata.gz: a0f32849ac70e42eea144b0fc564245bd76afa3a
4
+ data.tar.gz: 78ed4d4e6833243cfce284be8ec5d22407084111
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NzhlMmU3MDMyYWQwYjQ4NjA0Y2VkMzhjZTJiOGNkNGE0YTEwOWE1MTRjYzg0
10
- OThkMzI3Njg0MzFlYzc2OWI4OGZjOWYxZjM3MGUyOTBkYzgzZGU5MDY5YjI2
11
- MTg1MTBmNjExZDY5M2MyNzVlZTRkMjVlNTQyY2U5MmY2NTk2Yjg=
12
- data.tar.gz: !binary |-
13
- ODIxZmI2NTNmZWU4NWEwNzE3ODUxY2E2N2EyZjA2ODNlMGY3ODA1OWQ3Y2I0
14
- MDNlZTExZjUzOGEyZTAyNjM4NDZhMGQ1ODgyNTYxN2JlYzNlODc2MGFhNDE2
15
- MmIzMTRhYjM0YWEzZDg4M2UyODQ4ZjY1OWUxY2M3ODQ0MWYyMzQ=
6
+ metadata.gz: c3725d52e75e29c2b9b3724ac38522a95a45a48e282a1560e4ce39245094fbc6718911378f67810c3055aff84eef9a7f57da215a0a5e0da982641da4f67e0878
7
+ data.tar.gz: 470adc3bfef70af304db5be018f7f57b5adb2d10eed7a17b325110148feccad8887d97fe258743e11f825982029bae19d9e2df5f4811fc430d0342f01cfa8cd1
data/README.md CHANGED
@@ -1,4 +1,332 @@
1
1
  # RestMyCase [![Code Climate](https://codeclimate.com/github/goncalvesjoao/rest_my_case/badges/gpa.svg)](https://codeclimate.com/github/goncalvesjoao/rest_my_case) [![Build Status](https://travis-ci.org/goncalvesjoao/rest_my_case.svg?branch=master)](https://travis-ci.org/goncalvesjoao/rest_my_case) [![Test Coverage](https://codeclimate.com/github/goncalvesjoao/rest_my_case/badges/coverage.svg)](https://codeclimate.com/github/goncalvesjoao/rest_my_case) [![Gem Version](https://badge.fury.io/rb/rest_my_case.svg)](http://badge.fury.io/rb/rest_my_case)
2
2
 
3
- Very light Ruby gem with everything you need in a "The Clean Architecture" use case scenario.
4
- Props to [@tdantas](https://github.com/tdantas) and [@junhanamaki](https://github.com/junhanamaki)
3
+ Light Ruby gem with everything you need in a "The Clean Architecture" use case scenario.
4
+
5
+ Many thanks to [@tdantas](https://github.com/tdantas) and [@junhanamaki](https://github.com/junhanamaki) and a shout-out to [@joaquimadraz](https://github.com/joaquimadraz) and his [compel](https://github.com/joaquimadraz/compel) ruby validations gem.
6
+
7
+ ---
8
+
9
+ ## 1) Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'rest_my_case'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install rest_my_case
22
+
23
+ ---
24
+
25
+ ## 2) Ideology
26
+ Your business logic goes into separated use cases...
27
+ ```ruby
28
+ class FindPost < RestMyCase::Base
29
+
30
+ def perform
31
+ context.post = Post.find(context.id)
32
+ end
33
+
34
+ end
35
+
36
+ class ArchivePost < RestMyCase::Base
37
+
38
+ depends FindPost
39
+
40
+ def perform
41
+ context.post.status = 'archived'
42
+
43
+ context.result = context.post.save
44
+ end
45
+
46
+ end
47
+ ```
48
+
49
+ web framework should only act as a bridge between the user and your business logic.
50
+ ```ruby
51
+ class PostsController < ApplicationController
52
+
53
+ def archive
54
+ @context = ArchivePost.perform id: params[:id]
55
+
56
+ if @context.result
57
+ redirect_to @context.post
58
+ else
59
+ render "archive" #view post.errors
60
+ end
61
+ end
62
+
63
+ end
64
+ ```
65
+
66
+ Ideally your business logic should be a ruby gem that can be tested independently from your framework.
67
+
68
+ Checkout this step by step tutorial: (WIP) on how to isolate your code into a ruby gem and connect it to your rails or sinatra api.
69
+
70
+ ---
71
+
72
+ ## 3) Basic usage
73
+
74
+ ```ruby
75
+ class BuildPost < RestMyCase::Base
76
+ def perform
77
+ puts context.id
78
+ puts context.post_attributes
79
+ end
80
+ end
81
+ ```
82
+
83
+ ```
84
+ irb> params = { id: 1, post: { title: 'my first post' } }
85
+ irb> context = BuildPost.perform id: params[:id], post_attributes: params[:post]
86
+ 1
87
+ {:title=>"my first post"}
88
+ irb> context.id
89
+ 1
90
+ ```
91
+
92
+ The Hash passed down to **BuildPost.perform** will be available through an instance method called **#context** that will return an OpenStruct object initialized with that Hash (see more in section 7).
93
+
94
+ Executing **BuildPost.perform** will instantiate your use case and all of its **dependencies**, build a **context** with the contents of **params**, run your use case (and its dependencies) with that context and return it at the end.
95
+
96
+ ## 3.1) Normal usage
97
+ Organize your use cases by single responsibilities and establish your use case flow through "dependencies".
98
+
99
+ ```ruby
100
+ class FindPost < RestMyCase::Base
101
+ def perform
102
+ context.post = Post.find(context.id)
103
+ end
104
+ end
105
+
106
+ class BuildPost < RestMyCase::Base
107
+ depends FindPost
108
+
109
+ def perform
110
+ context.post.assign_attributes context.post_attributes
111
+ end
112
+ end
113
+ ```
114
+ The class method **.depends** will make **BuildPost** dependent of **FindPost** which means that calling **BuildPost.perform** will run **FindPost#perform** first and **BuildPost#perform** last. Both use cases will share the same context.
115
+
116
+ ```
117
+ irb> params = { id: 1, post: { title: 'my first post' } }
118
+ irb> context = BuildPost.perform id: params[:id], post_attributes: params[:post]
119
+ irb> context.post.name
120
+ "my first post"
121
+ ```
122
+
123
+ ---
124
+
125
+ ## 4) Lifecycle
126
+
127
+ ## 4.1) Waiting to be implemented methods
128
+ Methods: **#setup**, **#perform**, **#rollback** and **#final**
129
+ ```ruby
130
+ class UseCase1 < RestMyCase::Base
131
+ def setup
132
+ puts 'UseCase1#setup'
133
+ end
134
+ def perform
135
+ puts 'UseCase1#perform'
136
+ error if context.should_fail
137
+ end
138
+ def rollback
139
+ puts 'UseCase1#rollback'
140
+ end
141
+ def final
142
+ puts 'UseCase1#final'
143
+ end
144
+ end
145
+ ```
146
+
147
+ ```
148
+ irb> UseCase1.perform #will print
149
+ "UseCase1#setup"
150
+ "UseCase1#perform"
151
+ "UseCase1#final"
152
+ ```
153
+
154
+ Method **#rollback** will be called after **#perform** and before **#final** if **#error** is invoked inside a **#setup** of **#perform** (see more in section 5).
155
+ ```
156
+ irb> UseCase1.perform(should_fail: true) #will print
157
+ "UseCase1#setup"
158
+ "UseCase1#perform"
159
+ "UseCase1#rollback"
160
+ "UseCase1#final"
161
+ ```
162
+
163
+ Method **#final** will run last and always, no matter how many times **#error** was called.
164
+
165
+ ---
166
+
167
+ ### 4.2) Dependencies
168
+ Default behaviour is to run your dependencies (**#setup**, **#perform**, **#rollback** and **#final**) methods, first.
169
+ ```ruby
170
+ class UseCase2 < RestMyCase::Base
171
+ def perform
172
+ puts 'UseCase2#perform'
173
+ end
174
+ end
175
+
176
+ class UseCase3 < RestMyCase::Base
177
+ def perform
178
+ puts 'UseCase3#perform'
179
+ end
180
+ end
181
+
182
+ class UseCase1 < RestMyCase::Base
183
+ depends UseCase2,
184
+ UseCase3
185
+
186
+ def perform
187
+ puts 'UseCase1#perform'
188
+ end
189
+ end
190
+ ```
191
+
192
+ ```
193
+ irb> UseCase1.perform #will print
194
+ "UseCase2#perform"
195
+ "UseCase3#perform"
196
+ "UseCase1#perform"
197
+ ```
198
+
199
+ See section 8 for more examples.
200
+
201
+ ---
202
+
203
+ ## 5) Flow control methods
204
+
205
+ Methods | Behaviour
206
+ ------- | ---------
207
+ **#abort** | Stops other remaining use cases from running and triggers **#rollback** on already executed use cases (in reverse order).
208
+ **#skip** | Will prevent **#perform** (of the use case that called **#skip**) from running and will not stop other use cases from running nor trigger a **#rollback** (only works by being used inside a **#setup** method).
209
+ **#error(error_message = '')** | Will do the same as **#abort** but will also push **error_message** to **#context.errors** array so you can track down what happen in what use case (see more in section 7).
210
+ **#invoke(*use_case_classes)** | Does the same as the class method **.depends** but executes the use cases on demand. Shares the context to them and if they call **#abort** on their side, the use case that **invoked** will also **abort**.
211
+
212
+ **#skip**, **#abort**, **#error** and **#invoke** have a "bang!" version that will raise a controlled exception, preventing the remaining lines of code from running.
213
+ ```ruby
214
+ class UseCase1 < RestMyCase::Base
215
+ def perform
216
+ puts 'before #error!'
217
+ error!
218
+ puts 'after #error!'
219
+ end
220
+ end
221
+ ```
222
+
223
+ ```
224
+ irb> UseCase1.perform #will print only
225
+ "before #error!"
226
+ ```
227
+
228
+ ---
229
+
230
+ ## 6) Configuration methods
231
+
232
+ Methods | Behaviour
233
+ ------- | ---------
234
+ **.depends(*use_case_classes)** | Adds the **use_case_classes** array to the use case's **dependencies** list, that will be executed by order before the actual use case (see more in section 4).
235
+ **.required_context(*attributes)** | WIP.
236
+ **.context_reader(*methods)** | Defines getter methods that return **context.send method**, to help reduce the **context.method** boilerplate.
237
+ **.context_writer(*methods)** | Defines setter methods that set **context.send "#{method}=", value**, to help reduce the **context.method = value** boilerplate.
238
+ **.context_accessor(*methods)** | Calls both **.context_reader** and **.context_writer** methods.
239
+ **.silence_dependencies_abort=** | If **false** once a dependency calls **#abort(!)** the next in line dependencies will not be called (and **#rollback** will be called in reverse order) but if **true** all dependencies will run no matter how many times **#abort(!)** was called (usefull when you want to run multiple validations (see more in section 9).
240
+
241
+ ---
242
+
243
+ ## 7) **#context** methods
244
+ The returning object is an instance of **RestMyCase::Context::Base** class that inherits from **OpenStruct** and implements the following methods:
245
+
246
+ Methods | Behaviour
247
+ ------- | ---------
248
+ **#attributes** | Alias to **#marshal_dump**, returns all of the context's stored data.
249
+ **#to_hash** | Serializes and unserializes **#attributes** turning any existing ruby objects into serialized strings.
250
+ **#valid?** | Checks if **#errors** is empty
251
+ **#ok?** | Alias to **#valid?**
252
+ **#success?** | Alias to **#ok?**
253
+ **#errors** | Array that gets 'pushed' with **{ message: error_message, class_name: UseCase.class.name }** (or **error_message** itself if **error_message** already a Hash) every time **UseCase#error(error_message)** is called.
254
+
255
+ If **defined?(ActiveModel)** is true, **ActiveModel::Serialization** will be included and in turn methods like **#to_json(options = {})** and **#serializable_hash(options = nil)** will become available.
256
+
257
+ ---
258
+
259
+ ### 8) Examples
260
+ If **UseCase1** depends on **UseCase2** and **UseCase3** in that respective order.
261
+
262
+ Running **UseCase1.perform** will pass down the context to each use case in the following manner:
263
+
264
+ #### 8.1) Given that no use case called the method(s) **#error(!)**
265
+ ```
266
+ UseCase2#setup -> UseCase3#setup -> UseCase1#setup ->
267
+ UseCase2#perform -> UseCase3#perform -> UseCase1#perform ->
268
+ UseCase2#final -> UseCase3#final -> UseCase1#final
269
+ ```
270
+
271
+ #### 8.2) Given that **UseCase3#setup** calls **#skip(!)**
272
+ ```
273
+ UseCase2#setup -> UseCase3#setup -> UseCase1#setup ->
274
+ UseCase2#perform -> UseCase1#perform ->
275
+ UseCase2#final -> UseCase3#final -> UseCase1#final
276
+ ```
277
+
278
+ #### 8.3) Given that **UseCase3#setup** calls **#error(!)**
279
+ ```
280
+ UseCase2#setup -> UseCase3#setup ->
281
+ UseCase3#rollback -> UseCase2#rollback ->
282
+ UseCase2#final -> UseCase3#final -> UseCase1#final
283
+ ```
284
+
285
+ #### 8.4) Given that **UseCase3#perform** calls **#error(!)**
286
+ ```
287
+ UseCase2#setup -> UseCase3#setup -> UseCase1#setup ->
288
+ UseCase2#perform -> UseCase3#perform ->
289
+ UseCase3#rollback -> UseCase2#rollback ->
290
+ UseCase2#final -> UseCase3#final -> UseCase1#final
291
+ ```
292
+
293
+ ---
294
+
295
+ ## 9) RestMyCase::Validator class
296
+ WIP
297
+
298
+ ---
299
+
300
+ ## 10) RestMyCase::Status module
301
+ ```ruby
302
+ class UseCase1 < RestMyCase::Base
303
+ include RestMyCase::Status
304
+ end
305
+ ```
306
+
307
+ Adds following methods:
308
+
309
+ Methods | Behaviour
310
+ ------- | ---------
311
+ **#context** | Returns an instance of **RestMyCase::Context::Status**
312
+ **#status** | Returns **context.status** (see more in section 10.1)
313
+ **#failure(status, error_message = nil)** | WIP
314
+
315
+ **#failure!** is also present and does the same as the other flow control "bang!" methods (see section 5).
316
+
317
+ ### 10.1) RestMyCase::Context::Status
318
+ WIP
319
+
320
+ ---
321
+
322
+ ## 11) RestMyCase::HttpStatus module (for seamless API integration)
323
+ ```ruby
324
+ class UseCase1 < RestMyCase::Base
325
+ include RestMyCase::HttpStatus
326
+ end
327
+ ```
328
+
329
+ Includes the module **RestMyCase::Status** and **#context** becomes an instance of **RestMyCase::Context::HttpStatus**.
330
+
331
+ ### 11.1) RestMyCase::Context::HttpStatus
332
+ WIP
@@ -9,6 +9,18 @@ module RestMyCase
9
9
  Judge::Base, DefenseAttorney::Base, RestMyCase::Base, Context::Base
10
10
  end
11
11
 
12
+ def self.required_context(*schema)
13
+ if schema.length == 1 && (schema[0].is_a?(Hash) || schema[0].is_a?(Array))
14
+ @required_context_schema = schema[0]
15
+ else
16
+ @required_context_schema = schema
17
+ end
18
+ end
19
+
20
+ def self.required_context_schema
21
+ @required_context_schema ||= {}
22
+ end
23
+
12
24
  def self.depends(*use_case_classes)
13
25
  dependencies.push(*use_case_classes)
14
26
  end
@@ -44,42 +56,56 @@ module RestMyCase
44
56
 
45
57
  ######################## INSTANCE METHODS BELLOW ###########################
46
58
 
47
- attr_reader :context, :dependent_use_case, :options
59
+ attr_reader :context, :options
48
60
 
49
61
  def initialize(context, dependent_use_case = nil)
50
- @options = {}
51
- @context = context
52
- @dependent_use_case = dependent_use_case
62
+ @context = context
63
+ @options = { dependent_use_case: dependent_use_case }
64
+
65
+ return unless dependent_use_case
66
+
67
+ @options[:silent_abort] = RestMyCase.get_config \
68
+ :silence_dependencies_abort, dependent_use_case.class
53
69
  end
54
70
 
55
- def setup; end
71
+ def setup; end
56
72
 
57
- def perform; end
73
+ def perform; end
58
74
 
59
75
  def rollback; end
60
76
 
61
77
  def final; end
62
78
 
63
79
  def invoke(*use_case_classes)
64
- trial_court.execute(use_case_classes, context.to_hash).context
80
+ self.class.trial_court.execute(use_case_classes, context.to_hash).context
65
81
  end
66
82
 
67
83
  def invoke!(*use_case_classes)
68
- trial_court.execute(use_case_classes, context).tap do |trial_case|
69
- abort! if trial_case.aborted
70
- end.context
84
+ trial_case = self.class.trial_court.execute(use_case_classes, context)
85
+
86
+ abort! if trial_case.aborted
87
+
88
+ trial_case.context
71
89
  end
72
90
 
73
91
  def abort
74
- silent_abort? ? dependent_use_case.abort : (options[:should_abort] = true)
92
+ if options[:silent_abort]
93
+ options[:dependent_use_case].abort
94
+ else
95
+ options[:should_abort] = true
96
+ end
75
97
  end
76
98
 
77
99
  def abort!
78
100
  abort && fail(Errors::Abort)
79
101
  end
80
102
 
81
- def error(error_data = '')
82
- error_data = { message: error_data } unless error_data.is_a?(Hash)
103
+ def error(error_message = '')
104
+ if error_message.is_a?(Hash)
105
+ error_data = error_message
106
+ else
107
+ error_data = { message: error_message }
108
+ end
83
109
 
84
110
  error_data[:class_name] = self.class.name
85
111
 
@@ -98,17 +124,16 @@ module RestMyCase
98
124
  skip && fail(Errors::Skip)
99
125
  end
100
126
 
101
- protected ######################## PROTECTED ###############################
127
+ def validate_context(schema = self.class.required_context_schema)
128
+ errors = context.validate_schema(schema)
102
129
 
103
- def trial_court
104
- self.class.trial_court
105
- end
130
+ error(context_errors: errors, message: 'invalid context') if errors
106
131
 
107
- def silent_abort?
108
- return false if dependent_use_case.nil?
132
+ Helpers.blank? errors
133
+ end
109
134
 
110
- RestMyCase.get_config \
111
- :silence_dependencies_abort, dependent_use_case.class
135
+ def validate_context!(schema = self.class.required_context)
136
+ validate_context(schema) && fail(Errors::Abort)
112
137
  end
113
138
 
114
139
  end
@@ -1,3 +1,6 @@
1
+ require 'rest_my_case/context/errors/base'
2
+ require 'rest_my_case/context/schema_validator/base'
3
+
1
4
  module RestMyCase
2
5
  module Context
3
6
 
@@ -11,10 +14,18 @@ module RestMyCase
11
14
  Errors::Base
12
15
  end
13
16
 
17
+ def self.schema_validator_class
18
+ SchemaValidator::Base
19
+ end
20
+
14
21
  def to_hash
15
22
  Marshal.load Marshal.dump(attributes)
16
23
  end
17
24
 
25
+ def validate_schema(schema)
26
+ self.class.schema_validator_class.new(self).validate(schema)
27
+ end
28
+
18
29
  def errors
19
30
  @errors ||= self.class.error_class.new(self)
20
31
  end
@@ -0,0 +1,27 @@
1
+ module RestMyCase
2
+ module Context
3
+ module SchemaValidator
4
+
5
+ class Base
6
+
7
+ def initialize(context)
8
+ @context = context
9
+ end
10
+
11
+ def validate(schema)
12
+ errors = {}
13
+
14
+ schema.each do |required_attribute|
15
+ if Helpers.blank?(@context.send(required_attribute))
16
+ errors[required_attribute] = 'is required'
17
+ end
18
+ end
19
+
20
+ Helpers.blank?(errors) ? nil : errors
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ require 'compel'
2
+
3
+ module RestMyCase
4
+ module Context
5
+ module SchemaValidator
6
+
7
+ class Base
8
+
9
+ def initialize(context)
10
+ @context = context
11
+ end
12
+
13
+ def validate(schema)
14
+ result = ::Compel.run(@context, build_schema(schema))
15
+
16
+ result.valid? ? nil : result.errors
17
+ end
18
+
19
+ protected ###################### PROTECTED #############################
20
+
21
+ def build_schema(schema)
22
+ ::Compel.hash.keys \
23
+ schema.is_a?(Hash) ? schema : all_attributes_required(schema)
24
+ end
25
+
26
+ def all_attributes_required(schema)
27
+ {}.tap do |new_schema|
28
+ schema.each { |key| new_schema[key] = Compel.any.required }
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -1,3 +1,5 @@
1
+ require 'rest_my_case/context/errors/status'
2
+
1
3
  module RestMyCase
2
4
  module Context
3
5
 
@@ -4,7 +4,7 @@ module RestMyCase
4
4
  class Base
5
5
 
6
6
  def initialize(trial_case)
7
- @trial_case = trial_case
7
+ @trial_case = trial_case
8
8
  @trial_case.use_cases = []
9
9
  end
10
10
 
@@ -1,18 +1,15 @@
1
+ require 'rest_my_case/context/http_status'
2
+
1
3
  module RestMyCase
2
4
 
3
5
  module HttpStatus
4
6
 
5
7
  include Status
6
8
 
7
- module ClassMethods
8
- def trial_court
9
- @trial_court ||= Trial::Court.new \
10
- Judge::Base, DefenseAttorney::Base, Base, Context::HttpStatus
11
- end
12
- end
13
-
14
9
  def self.included(parent_class)
15
- parent_class.extend ClassMethods
10
+ return unless parent_class.respond_to? :trial_court
11
+
12
+ parent_class.trial_court.context_class = Context::HttpStatus
16
13
  end
17
14
 
18
15
  end
@@ -4,8 +4,8 @@ module RestMyCase
4
4
  class Base
5
5
 
6
6
  def initialize(trial_case)
7
- @trial_case = trial_case
8
- @performed_use_cases = []
7
+ @trial_case = trial_case
8
+ @performed_use_cases = []
9
9
  @use_case_that_aborted = nil
10
10
  end
11
11
 
@@ -22,16 +22,21 @@ module RestMyCase
22
22
 
23
23
  def run_setup_methods
24
24
  @trial_case.use_cases.each do |use_case|
25
- break if method_setup_has_aborted use_case
25
+ break if method_aborts?(:setup, use_case)
26
26
  end
27
27
  end
28
28
 
29
29
  def run_perform_methods
30
- return nil if @use_case_that_aborted
31
-
32
30
  @trial_case.use_cases.each do |use_case|
33
- break if method_perform_has_aborted use_case
31
+ validate_context_aborts?(use_case)
32
+
33
+ next if use_case.options[:should_skip] || @use_case_that_aborted
34
+
35
+ @performed_use_cases.push use_case
36
+
37
+ method_aborts?(:perform, use_case)
34
38
  end
39
+
35
40
  end
36
41
 
37
42
  def run_rollback_methods
@@ -50,16 +55,16 @@ module RestMyCase
50
55
 
51
56
  private ########################### PRIVATE ##############################
52
57
 
53
- def method_setup_has_aborted(use_case)
54
- method_aborts?(:setup, use_case)
55
- end
56
-
57
- def method_perform_has_aborted(use_case)
58
- return false if use_case.options[:should_skip]
58
+ def validate_context_aborts?(use_case)
59
+ should_abort_before = use_case.options[:should_abort]
59
60
 
60
- @performed_use_cases.push use_case
61
+ use_case.validate_context
61
62
 
62
- method_aborts?(:perform, use_case)
63
+ if !should_abort_before && use_case.options[:should_abort]
64
+ @use_case_that_aborted = use_case
65
+ end
66
+ rescue Errors::Abort
67
+ @use_case_that_aborted = use_case
63
68
  end
64
69
 
65
70
  def method_aborts?(method_name, use_case)