u-case 3.0.0.rc8 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.sh +4 -4
- data/Gemfile +9 -1
- data/README.md +183 -142
- data/README.pt-BR.md +203 -163
- data/lib/micro/case.rb +56 -26
- data/lib/micro/case/config.rb +16 -4
- data/lib/micro/case/error.rb +7 -2
- data/lib/micro/case/result.rb +80 -44
- data/lib/micro/case/result/transitions.rb +17 -0
- data/lib/micro/case/result/wrapper.rb +45 -0
- data/lib/micro/case/safe.rb +2 -2
- data/lib/micro/case/strict.rb +2 -2
- data/lib/micro/case/utils.rb +20 -10
- data/lib/micro/case/version.rb +1 -1
- data/lib/micro/case/with_activemodel_validation.rb +3 -1
- data/lib/micro/cases.rb +7 -0
- data/lib/micro/cases/error.rb +13 -0
- data/lib/micro/cases/flow.rb +37 -24
- data/lib/micro/cases/map.rb +39 -0
- data/lib/micro/cases/safe/flow.rb +2 -2
- data/lib/micro/cases/utils.rb +21 -0
- data/u-case.gemspec +3 -3
- metadata +15 -8
data/lib/micro/case.rb
CHANGED
@@ -7,32 +7,42 @@ require 'micro/case/version'
|
|
7
7
|
|
8
8
|
module Micro
|
9
9
|
class Case
|
10
|
+
require 'micro/cases/utils'
|
10
11
|
require 'micro/case/utils'
|
11
|
-
require 'micro/case/result'
|
12
12
|
require 'micro/case/error'
|
13
|
+
require 'micro/case/result'
|
13
14
|
require 'micro/case/safe'
|
14
15
|
require 'micro/case/strict'
|
15
16
|
require 'micro/case/config'
|
16
17
|
|
17
18
|
require 'micro/cases'
|
18
19
|
|
19
|
-
include Micro::Attributes
|
20
|
+
include Micro::Attributes
|
21
|
+
|
22
|
+
def self.call(input = Kind::Empty::HASH)
|
23
|
+
result = __new__(Result.new, input).__call__
|
24
|
+
|
25
|
+
return result unless block_given?
|
20
26
|
|
21
|
-
|
22
|
-
new(options).__call__
|
27
|
+
yield Result::Wrapper.new(result)
|
23
28
|
end
|
24
29
|
|
30
|
+
INVALID_INVOCATION_OF_THE_THEN_METHOD =
|
31
|
+
Error::InvalidInvocationOfTheThenMethod.new("#{self.name}.")
|
32
|
+
|
25
33
|
def self.then(use_case = nil, &block)
|
26
34
|
can_yield_self = respond_to?(:yield_self)
|
27
35
|
|
28
36
|
if block
|
29
|
-
raise
|
37
|
+
raise INVALID_INVOCATION_OF_THE_THEN_METHOD if use_case
|
30
38
|
raise NotImplementedError if !can_yield_self
|
31
39
|
|
32
40
|
yield_self(&block)
|
33
41
|
else
|
34
42
|
return yield_self if !use_case && can_yield_self
|
35
43
|
|
44
|
+
raise INVALID_INVOCATION_OF_THE_THEN_METHOD unless ::Micro.case_or_flow?(use_case)
|
45
|
+
|
36
46
|
self.call.then(use_case)
|
37
47
|
end
|
38
48
|
end
|
@@ -42,7 +52,7 @@ module Micro
|
|
42
52
|
end
|
43
53
|
|
44
54
|
def self.flow(*args)
|
45
|
-
@__flow_use_cases = args
|
55
|
+
@__flow_use_cases = Cases::Utils.map_use_cases(args)
|
46
56
|
end
|
47
57
|
|
48
58
|
class << self
|
@@ -58,7 +68,8 @@ module Micro
|
|
58
68
|
end
|
59
69
|
|
60
70
|
def self.inherited(subclass)
|
61
|
-
subclass.
|
71
|
+
subclass.__attributes_set_after_inherit__(self.__attributes_data__)
|
72
|
+
|
62
73
|
subclass.extend ::Micro::Attributes.const_get('Macros::ForSubclasses'.freeze)
|
63
74
|
|
64
75
|
if self.send(:__flow_use_cases) && !subclass.name.to_s.end_with?(FLOW_STEP)
|
@@ -70,11 +81,13 @@ module Micro
|
|
70
81
|
end
|
71
82
|
|
72
83
|
def self.__new__(result, arg)
|
73
|
-
input = result.
|
84
|
+
input = result.__set_accessible_attributes__(arg)
|
74
85
|
|
75
86
|
new(input).__set_result__(result)
|
76
87
|
end
|
77
88
|
|
89
|
+
private_class_method :new
|
90
|
+
|
78
91
|
def self.__flow_builder__
|
79
92
|
Cases::Flow
|
80
93
|
end
|
@@ -116,6 +129,14 @@ module Micro
|
|
116
129
|
__flow_set(__flow_use_cases_get) if !__flow_get__ && __flow_use_cases
|
117
130
|
end
|
118
131
|
|
132
|
+
def self.inspect
|
133
|
+
if __flow_use_cases
|
134
|
+
'<%s (%s) use_cases=%s>' % [self, __flow_builder__, @__flow_use_cases]
|
135
|
+
else
|
136
|
+
'<%s (%s) attributes=%s>' % [self, self.superclass, attributes]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
119
140
|
def initialize(input)
|
120
141
|
__setup_use_case(input)
|
121
142
|
end
|
@@ -125,7 +146,7 @@ module Micro
|
|
125
146
|
end
|
126
147
|
|
127
148
|
def __call__
|
128
|
-
|
149
|
+
__call_the_use_case_or_its_flow
|
129
150
|
end
|
130
151
|
|
131
152
|
def __set_result__(result)
|
@@ -139,8 +160,23 @@ module Micro
|
|
139
160
|
|
140
161
|
private
|
141
162
|
|
142
|
-
|
143
|
-
|
163
|
+
def call(use_case, defaults = Kind::Empty::HASH)
|
164
|
+
raise Error::InvalidUseCase unless ::Micro.case_or_flow?(use_case)
|
165
|
+
|
166
|
+
input =
|
167
|
+
defaults.empty? ? attributes : attributes.merge(Utils::Hashes.stringify_keys(defaults))
|
168
|
+
|
169
|
+
use_case.__new__(@__result, input).__call__
|
170
|
+
end
|
171
|
+
|
172
|
+
def apply(name)
|
173
|
+
method(name)
|
174
|
+
end
|
175
|
+
|
176
|
+
def __call_the_use_case_or_its_flow
|
177
|
+
return __call_the_use_case_flow if __call_the_use_case_flow?
|
178
|
+
|
179
|
+
__call_use_case
|
144
180
|
end
|
145
181
|
|
146
182
|
def __setup_use_case(input)
|
@@ -151,12 +187,6 @@ module Micro
|
|
151
187
|
self.attributes = input
|
152
188
|
end
|
153
189
|
|
154
|
-
def __call!
|
155
|
-
return __call_use_case_flow if __call_use_case_flow?
|
156
|
-
|
157
|
-
__call_use_case
|
158
|
-
end
|
159
|
-
|
160
190
|
def __call_use_case
|
161
191
|
result = call!
|
162
192
|
|
@@ -165,11 +195,11 @@ module Micro
|
|
165
195
|
raise Error::UnexpectedResult.new("#{self.class.name}#call!")
|
166
196
|
end
|
167
197
|
|
168
|
-
def
|
198
|
+
def __call_the_use_case_flow?
|
169
199
|
self.class.__flow_get__
|
170
200
|
end
|
171
201
|
|
172
|
-
def
|
202
|
+
def __call_the_use_case_flow
|
173
203
|
self.class.__flow_get__.call(@__input)
|
174
204
|
end
|
175
205
|
|
@@ -195,18 +225,18 @@ module Micro
|
|
195
225
|
__get_result(false, value, type)
|
196
226
|
end
|
197
227
|
|
198
|
-
def __result
|
199
|
-
@__result ||= Result.new
|
200
|
-
end
|
201
|
-
|
202
228
|
def __get_result(is_success, value, type)
|
203
|
-
__result.__set__(is_success, value, type, self)
|
229
|
+
@__result.__set__(is_success, value, type, self)
|
204
230
|
end
|
205
231
|
|
206
|
-
|
232
|
+
private_constant :MapFailureType, :INVALID_INVOCATION_OF_THE_THEN_METHOD
|
233
|
+
end
|
234
|
+
|
235
|
+
def self.case?(arg)
|
236
|
+
arg.is_a?(Class) && arg < Case
|
207
237
|
end
|
208
238
|
|
209
239
|
def self.case_or_flow?(arg)
|
210
|
-
|
240
|
+
case?(arg) || arg.is_a?(Cases::Flow)
|
211
241
|
end
|
212
242
|
end
|
data/lib/micro/case/config.rb
CHANGED
@@ -7,16 +7,28 @@ module Micro
|
|
7
7
|
class Config
|
8
8
|
include Singleton
|
9
9
|
|
10
|
+
def enable_transitions=(value)
|
11
|
+
Micro::Case::Result.class_variable_set(
|
12
|
+
:@@transitions_enabled, Kind::Of::Boolean(value)
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
10
16
|
def enable_activemodel_validation=(value)
|
11
17
|
return unless Kind::Of::Boolean(value)
|
12
18
|
|
13
19
|
require 'micro/case/with_activemodel_validation'
|
14
20
|
end
|
15
21
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
)
|
22
|
+
def set_activemodel_validation_errors_failure=(value)
|
23
|
+
return unless value
|
24
|
+
|
25
|
+
@activemodel_validation_errors_failure = Kind.of(Symbol, value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def activemodel_validation_errors_failure
|
29
|
+
return @activemodel_validation_errors_failure if defined?(@activemodel_validation_errors_failure)
|
30
|
+
|
31
|
+
@activemodel_validation_errors_failure = :invalid_attributes
|
20
32
|
end
|
21
33
|
end
|
22
34
|
end
|
data/lib/micro/case/error.rb
CHANGED
@@ -46,11 +46,16 @@ module Micro
|
|
46
46
|
end
|
47
47
|
|
48
48
|
class InvalidInvocationOfTheThenMethod < StandardError
|
49
|
-
def initialize
|
49
|
+
def initialize(class_name)
|
50
|
+
super("Invalid invocation of the #{class_name}then method")
|
51
|
+
end
|
50
52
|
end
|
51
53
|
|
52
54
|
def self.by_wrong_usage?(exception)
|
53
|
-
|
55
|
+
case exception
|
56
|
+
when Kind::Error, ArgumentError, InvalidResult, UnexpectedResult then true
|
57
|
+
else false
|
58
|
+
end
|
54
59
|
end
|
55
60
|
end
|
56
61
|
end
|
data/lib/micro/case/result.rb
CHANGED
@@ -5,8 +5,14 @@ require 'set'
|
|
5
5
|
module Micro
|
6
6
|
class Case
|
7
7
|
class Result
|
8
|
+
require 'micro/case/result/wrapper'
|
9
|
+
require 'micro/case/result/transitions'
|
10
|
+
|
8
11
|
Kind::Types.add(self)
|
9
12
|
|
13
|
+
INVALID_INVOCATION_OF_THE_THEN_METHOD =
|
14
|
+
Error::InvalidInvocationOfTheThenMethod.new("#{self.name}#")
|
15
|
+
|
10
16
|
@@transitions_enabled = true
|
11
17
|
|
12
18
|
def self.transitions_enabled?
|
@@ -17,16 +23,35 @@ module Micro
|
|
17
23
|
|
18
24
|
alias value data
|
19
25
|
|
20
|
-
def initialize
|
21
|
-
|
22
|
-
|
23
|
-
@
|
26
|
+
def initialize(transitions_mapper = Transitions::MapEverything)
|
27
|
+
enable_transitions = @@transitions_enabled
|
28
|
+
|
29
|
+
@__is_unknown = true
|
30
|
+
@__accumulated_data = {}
|
31
|
+
@__tracked_use_cases = Set.new
|
32
|
+
@__accessible_attributes = {}
|
33
|
+
|
34
|
+
@__transitions = enable_transitions ? [] : Kind::Empty::ARRAY
|
35
|
+
@__transitions_mapper = transitions_mapper if enable_transitions
|
36
|
+
end
|
37
|
+
|
38
|
+
def inspect
|
39
|
+
pretty_type = @__success ? 'Success' : 'Failure'
|
40
|
+
|
41
|
+
instance_info = '%s (%s) type=:%s data=%s' % [pretty_type, self.class, @type, data]
|
42
|
+
transitions_info = ' transitions=%d' % [@__transitions.size] if Micro::Case::Result.transitions_enabled?
|
43
|
+
|
44
|
+
"<#{instance_info}#{transitions_info}>"
|
24
45
|
end
|
25
46
|
|
26
47
|
def to_ary
|
27
48
|
[data, type]
|
28
49
|
end
|
29
50
|
|
51
|
+
def to_sym
|
52
|
+
@__success ? :success : :failure
|
53
|
+
end
|
54
|
+
|
30
55
|
def [](key)
|
31
56
|
data[key]
|
32
57
|
end
|
@@ -44,20 +69,29 @@ module Micro
|
|
44
69
|
end
|
45
70
|
|
46
71
|
def slice(*keys)
|
47
|
-
Utils.
|
72
|
+
Utils::Hashes.slice(data, keys)
|
48
73
|
end
|
49
74
|
|
50
75
|
def success?
|
51
|
-
@
|
76
|
+
@__success
|
52
77
|
end
|
53
78
|
|
54
79
|
def failure?
|
55
80
|
!success?
|
56
81
|
end
|
57
82
|
|
83
|
+
def unknown?
|
84
|
+
@__is_unknown
|
85
|
+
end
|
86
|
+
|
87
|
+
def accessible_attributes
|
88
|
+
@__accessible_attributes.keys
|
89
|
+
end
|
90
|
+
|
58
91
|
def on_success(expected_type = nil)
|
59
92
|
return self unless __success_type?(expected_type)
|
60
93
|
|
94
|
+
@__is_unknown = false
|
61
95
|
hook_data = expected_type.nil? ? self : data
|
62
96
|
|
63
97
|
yield(hook_data, @use_case)
|
@@ -68,6 +102,7 @@ module Micro
|
|
68
102
|
def on_failure(expected_type = nil)
|
69
103
|
return self unless __failure_type?(expected_type)
|
70
104
|
|
105
|
+
@__is_unknown = false
|
71
106
|
hook_data = expected_type.nil? ? self : data
|
72
107
|
|
73
108
|
yield(hook_data, @use_case)
|
@@ -85,11 +120,19 @@ module Micro
|
|
85
120
|
self
|
86
121
|
end
|
87
122
|
|
123
|
+
def on_unknown
|
124
|
+
return self unless unknown?
|
125
|
+
|
126
|
+
yield(self, @use_case)
|
127
|
+
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
88
131
|
def then(use_case = nil, attributes = nil, &block)
|
89
132
|
can_yield_self = respond_to?(:yield_self)
|
90
133
|
|
91
134
|
if block
|
92
|
-
raise
|
135
|
+
raise INVALID_INVOCATION_OF_THE_THEN_METHOD if use_case
|
93
136
|
raise NotImplementedError if !can_yield_self
|
94
137
|
|
95
138
|
yield_self(&block)
|
@@ -98,7 +141,7 @@ module Micro
|
|
98
141
|
return failure? ? self : __call_proc(use_case, 'then(-> {})'.freeze) if use_case.is_a?(Proc)
|
99
142
|
return failure? ? self : __call_method(use_case, attributes) if use_case.is_a?(Method)
|
100
143
|
|
101
|
-
raise
|
144
|
+
raise INVALID_INVOCATION_OF_THE_THEN_METHOD unless ::Micro.case_or_flow?(use_case)
|
102
145
|
|
103
146
|
return self if failure?
|
104
147
|
|
@@ -118,13 +161,13 @@ module Micro
|
|
118
161
|
return __call_proc(arg, '| -> {}'.freeze) if arg.is_a?(Proc)
|
119
162
|
return __call_method(arg) if arg.is_a?(Method)
|
120
163
|
|
121
|
-
raise
|
164
|
+
raise INVALID_INVOCATION_OF_THE_THEN_METHOD unless ::Micro.case_or_flow?(arg)
|
122
165
|
|
123
166
|
failure? ? self : arg.__new__(self, data).__call__
|
124
167
|
end
|
125
168
|
|
126
169
|
def transitions
|
127
|
-
@__transitions.
|
170
|
+
@__transitions.dup
|
128
171
|
end
|
129
172
|
|
130
173
|
FetchData = -> (data) do
|
@@ -138,46 +181,50 @@ module Micro
|
|
138
181
|
raise Error::InvalidResultType unless type.is_a?(Symbol)
|
139
182
|
raise Error::InvalidUseCase unless use_case.is_a?(::Micro::Case)
|
140
183
|
|
141
|
-
@
|
184
|
+
@__success, @type, @use_case = is_success, type, use_case
|
142
185
|
|
143
|
-
@data = FetchData.call(data)
|
186
|
+
@data = FetchData.call(data).freeze
|
144
187
|
|
145
188
|
raise Micro::Case::Error::InvalidResult.new(is_success, type, use_case) unless @data
|
146
189
|
|
147
|
-
@
|
190
|
+
@__accumulated_data.merge!(@data)
|
148
191
|
|
149
|
-
use_case_attributes = Utils.
|
192
|
+
use_case_attributes = Utils::Hashes.symbolize_keys(@use_case.attributes)
|
150
193
|
|
151
|
-
|
194
|
+
unless @__tracked_use_cases.member?(use_case_class = @use_case.class)
|
195
|
+
@__tracked_use_cases.add(use_case_class)
|
152
196
|
|
153
|
-
|
197
|
+
__update_accessible_attributes(use_case_attributes)
|
198
|
+
end
|
199
|
+
|
200
|
+
__set_transition(use_case_attributes) unless @__transitions.frozen?
|
154
201
|
|
155
202
|
self
|
156
203
|
end
|
157
204
|
|
158
|
-
def
|
205
|
+
def __set_accessible_attributes__(arg)
|
159
206
|
return arg unless arg.is_a?(Hash)
|
160
207
|
|
161
|
-
attributes = Utils.
|
208
|
+
attributes = Utils::Hashes.symbolize_keys(arg)
|
162
209
|
|
163
|
-
|
210
|
+
__update_accessible_attributes(attributes)
|
211
|
+
__fetch_accessible_attributes
|
164
212
|
end
|
165
213
|
|
166
214
|
private
|
167
215
|
|
168
|
-
def
|
169
|
-
|
170
|
-
|
171
|
-
opt ? opt.merge(@__transitions_accumulated_data) : @__transitions_accumulated_data
|
172
|
-
)
|
173
|
-
|
174
|
-
return fn.call if fn.arity.zero?
|
216
|
+
def __update_accessible_attributes(attributes)
|
217
|
+
@__accessible_attributes.merge!(attributes)
|
218
|
+
end
|
175
219
|
|
176
|
-
|
220
|
+
def __fetch_accessible_attributes
|
221
|
+
@__accessible_attributes.dup
|
177
222
|
end
|
178
223
|
|
179
224
|
def __call_proc(fn, expected)
|
180
|
-
|
225
|
+
__update_accessible_attributes(@__accumulated_data)
|
226
|
+
|
227
|
+
result = fn.arity.zero? ? fn.call : fn.call(__fetch_accessible_attributes)
|
181
228
|
|
182
229
|
return self if result === self
|
183
230
|
|
@@ -185,7 +232,9 @@ module Micro
|
|
185
232
|
end
|
186
233
|
|
187
234
|
def __call_method(methd, attributes = nil)
|
188
|
-
|
235
|
+
__update_accessible_attributes(attributes ? attributes.merge(@__accumulated_data) : @__accumulated_data)
|
236
|
+
|
237
|
+
result = methd.arity.zero? ? methd.call : methd.call(**__fetch_accessible_attributes)
|
189
238
|
|
190
239
|
return self if result === self
|
191
240
|
|
@@ -200,24 +249,11 @@ module Micro
|
|
200
249
|
failure? && (expected_type.nil? || expected_type == type)
|
201
250
|
end
|
202
251
|
|
203
|
-
def __update_transitions_accessible_attributes(attributes)
|
204
|
-
@__transitions_accessible_attributes.merge!(attributes)
|
205
|
-
@__transitions_accessible_attributes
|
206
|
-
end
|
207
|
-
|
208
252
|
def __set_transition(use_case_attributes)
|
209
|
-
|
210
|
-
|
211
|
-
result = @success ? :success : :failure
|
212
|
-
|
213
|
-
@__transitions << {
|
214
|
-
use_case: { class: use_case_class, attributes: use_case_attributes },
|
215
|
-
result => { type: @type, result: data },
|
216
|
-
accessible_attributes: @__transitions_accessible_attributes.keys
|
217
|
-
}
|
253
|
+
@__transitions << @__transitions_mapper.call(self, use_case_attributes)
|
218
254
|
end
|
219
255
|
|
220
|
-
|
256
|
+
private_constant :FetchData, :INVALID_INVOCATION_OF_THE_THEN_METHOD
|
221
257
|
end
|
222
258
|
end
|
223
259
|
end
|