u-case 3.0.0.rc3 → 3.0.0.rc8
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.
- checksums.yaml +4 -4
- data/.travis.sh +8 -4
- data/Gemfile +3 -2
- data/README.md +281 -262
- data/README.pt-BR.md +1420 -0
- data/lib/micro/case.rb +58 -36
- data/lib/micro/case/config.rb +1 -1
- data/lib/micro/case/error.rb +4 -2
- data/lib/micro/case/result.rb +92 -36
- data/lib/micro/case/safe.rb +2 -2
- data/lib/micro/case/utils.rb +7 -0
- data/lib/micro/case/version.rb +1 -1
- data/lib/micro/case/with_activemodel_validation.rb +1 -1
- data/lib/micro/cases/flow.rb +24 -40
- data/lib/micro/cases/safe/flow.rb +2 -2
- data/u-case.gemspec +2 -2
- metadata +5 -4
data/lib/micro/case.rb
CHANGED
@@ -18,26 +18,45 @@ module Micro
|
|
18
18
|
|
19
19
|
include Micro::Attributes.without(:strict_initialize)
|
20
20
|
|
21
|
-
def self.
|
22
|
-
|
21
|
+
def self.call(options = Kind::Empty::HASH)
|
22
|
+
new(options).__call__
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.
|
26
|
-
|
25
|
+
def self.then(use_case = nil, &block)
|
26
|
+
can_yield_self = respond_to?(:yield_self)
|
27
|
+
|
28
|
+
if block
|
29
|
+
raise Error::InvalidInvocationOfTheThenMethod if use_case
|
30
|
+
raise NotImplementedError if !can_yield_self
|
31
|
+
|
32
|
+
yield_self(&block)
|
33
|
+
else
|
34
|
+
return yield_self if !use_case && can_yield_self
|
35
|
+
|
36
|
+
self.call.then(use_case)
|
37
|
+
end
|
27
38
|
end
|
28
39
|
|
29
40
|
def self.to_proc
|
30
41
|
Proc.new { |arg| call(arg) }
|
31
42
|
end
|
32
43
|
|
33
|
-
def self.call!
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
44
|
def self.flow(*args)
|
38
45
|
@__flow_use_cases = args
|
39
46
|
end
|
40
47
|
|
48
|
+
class << self
|
49
|
+
alias __call__ call
|
50
|
+
|
51
|
+
def config
|
52
|
+
yield(Config.instance)
|
53
|
+
end
|
54
|
+
|
55
|
+
def call!
|
56
|
+
self
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
41
60
|
def self.inherited(subclass)
|
42
61
|
subclass.attributes(self.attributes_data({}))
|
43
62
|
subclass.extend ::Micro::Attributes.const_get('Macros::ForSubclasses'.freeze)
|
@@ -51,41 +70,34 @@ module Micro
|
|
51
70
|
end
|
52
71
|
|
53
72
|
def self.__new__(result, arg)
|
54
|
-
|
55
|
-
instance.__set_result__(result)
|
56
|
-
instance
|
57
|
-
end
|
73
|
+
input = result.__set_transitions_accessible_attributes__(arg)
|
58
74
|
|
59
|
-
|
60
|
-
input =
|
61
|
-
arg.is_a?(Hash) ? result.__set_transitions_accessible_attributes__(arg) : arg
|
62
|
-
|
63
|
-
__new__(result, input).call
|
75
|
+
new(input).__set_result__(result)
|
64
76
|
end
|
65
77
|
|
66
|
-
def self.
|
78
|
+
def self.__flow_builder__
|
67
79
|
Cases::Flow
|
68
80
|
end
|
69
81
|
|
70
|
-
def self.
|
82
|
+
def self.__flow_get__
|
71
83
|
return @__flow if defined?(@__flow)
|
72
84
|
end
|
73
85
|
|
74
86
|
private_class_method def self.__flow_set(args)
|
75
|
-
return if
|
87
|
+
return if __flow_get__
|
76
88
|
|
77
|
-
def self.use_cases;
|
89
|
+
def self.use_cases; __flow_get__.use_cases; end
|
78
90
|
|
79
91
|
self.class_eval('def use_cases; self.class.use_cases; end')
|
80
92
|
|
81
|
-
@__flow =
|
93
|
+
@__flow = __flow_builder__.build(args)
|
82
94
|
end
|
83
95
|
|
84
|
-
FLOW_STEP = '
|
96
|
+
FLOW_STEP = 'Self'.freeze
|
85
97
|
|
86
98
|
private_constant :FLOW_STEP
|
87
99
|
|
88
|
-
def self.
|
100
|
+
def self.__call__!
|
89
101
|
return const_get(FLOW_STEP) if const_defined?(FLOW_STEP, false)
|
90
102
|
|
91
103
|
class_eval("class #{FLOW_STEP} < #{self.name}; private def __call; __call_use_case; end; end")
|
@@ -97,11 +109,11 @@ module Micro
|
|
97
109
|
|
98
110
|
private_class_method def self.__flow_use_cases_get
|
99
111
|
Array(__flow_use_cases)
|
100
|
-
.map { |use_case| use_case == self ? self.
|
112
|
+
.map { |use_case| use_case == self ? self.__call__! : use_case }
|
101
113
|
end
|
102
114
|
|
103
|
-
def self.
|
104
|
-
__flow_set(__flow_use_cases_get) if !
|
115
|
+
def self.__flow_set__!
|
116
|
+
__flow_set(__flow_use_cases_get) if !__flow_get__ && __flow_use_cases
|
105
117
|
end
|
106
118
|
|
107
119
|
def initialize(input)
|
@@ -112,8 +124,8 @@ module Micro
|
|
112
124
|
raise NotImplementedError
|
113
125
|
end
|
114
126
|
|
115
|
-
def
|
116
|
-
__call
|
127
|
+
def __call__
|
128
|
+
__call!
|
117
129
|
end
|
118
130
|
|
119
131
|
def __set_result__(result)
|
@@ -121,19 +133,25 @@ module Micro
|
|
121
133
|
raise Error::ResultIsAlreadyDefined if defined?(@__result)
|
122
134
|
|
123
135
|
@__result = result
|
136
|
+
|
137
|
+
self
|
124
138
|
end
|
125
139
|
|
126
140
|
private
|
127
141
|
|
142
|
+
# This method was reserved for a new feature
|
143
|
+
def call
|
144
|
+
end
|
145
|
+
|
128
146
|
def __setup_use_case(input)
|
129
|
-
self.class.
|
147
|
+
self.class.__flow_set__!
|
130
148
|
|
131
149
|
@__input = input
|
132
150
|
|
133
151
|
self.attributes = input
|
134
152
|
end
|
135
153
|
|
136
|
-
def __call
|
154
|
+
def __call!
|
137
155
|
return __call_use_case_flow if __call_use_case_flow?
|
138
156
|
|
139
157
|
__call_use_case
|
@@ -144,15 +162,15 @@ module Micro
|
|
144
162
|
|
145
163
|
return result if result.is_a?(Result)
|
146
164
|
|
147
|
-
raise Error::UnexpectedResult.new(self.class)
|
165
|
+
raise Error::UnexpectedResult.new("#{self.class.name}#call!")
|
148
166
|
end
|
149
167
|
|
150
168
|
def __call_use_case_flow?
|
151
|
-
self.class.
|
169
|
+
self.class.__flow_get__
|
152
170
|
end
|
153
171
|
|
154
172
|
def __call_use_case_flow
|
155
|
-
self.class.
|
173
|
+
self.class.__flow_get__.call(@__input)
|
156
174
|
end
|
157
175
|
|
158
176
|
def Success(type = :ok, result: nil)
|
@@ -177,14 +195,18 @@ module Micro
|
|
177
195
|
__get_result(false, value, type)
|
178
196
|
end
|
179
197
|
|
180
|
-
def
|
198
|
+
def __result
|
181
199
|
@__result ||= Result.new
|
182
200
|
end
|
183
201
|
|
184
202
|
def __get_result(is_success, value, type)
|
185
|
-
|
203
|
+
__result.__set__(is_success, value, type, self)
|
186
204
|
end
|
187
205
|
|
188
206
|
private_constant :MapFailureType
|
189
207
|
end
|
208
|
+
|
209
|
+
def self.case_or_flow?(arg)
|
210
|
+
(arg.is_a?(Class) && arg < Case) || arg.is_a?(Cases::Flow)
|
211
|
+
end
|
190
212
|
end
|
data/lib/micro/case/config.rb
CHANGED
data/lib/micro/case/error.rb
CHANGED
@@ -4,9 +4,11 @@ module Micro
|
|
4
4
|
class Case
|
5
5
|
module Error
|
6
6
|
class UnexpectedResult < TypeError
|
7
|
-
MESSAGE = '
|
7
|
+
MESSAGE = 'must return an instance of Micro::Case::Result'.freeze
|
8
8
|
|
9
|
-
def initialize(
|
9
|
+
def initialize(context)
|
10
|
+
super("#{context} #{MESSAGE}")
|
11
|
+
end
|
10
12
|
end
|
11
13
|
|
12
14
|
class ResultIsAlreadyDefined < ArgumentError
|
data/lib/micro/case/result.rb
CHANGED
@@ -7,15 +7,20 @@ module Micro
|
|
7
7
|
class Result
|
8
8
|
Kind::Types.add(self)
|
9
9
|
|
10
|
-
@@
|
10
|
+
@@transitions_enabled = true
|
11
|
+
|
12
|
+
def self.transitions_enabled?
|
13
|
+
@@transitions_enabled
|
14
|
+
end
|
11
15
|
|
12
16
|
attr_reader :type, :data, :use_case
|
13
17
|
|
14
|
-
|
18
|
+
alias value data
|
15
19
|
|
16
20
|
def initialize
|
17
|
-
@
|
18
|
-
@
|
21
|
+
@__transitions = []
|
22
|
+
@__transitions_accumulated_data = {}
|
23
|
+
@__transitions_accessible_attributes = {}
|
19
24
|
end
|
20
25
|
|
21
26
|
def to_ary
|
@@ -30,6 +35,18 @@ module Micro
|
|
30
35
|
data.values_at(*keys)
|
31
36
|
end
|
32
37
|
|
38
|
+
def key?(key)
|
39
|
+
data.key?(key)
|
40
|
+
end
|
41
|
+
|
42
|
+
def value?(value)
|
43
|
+
data.value?(value)
|
44
|
+
end
|
45
|
+
|
46
|
+
def slice(*keys)
|
47
|
+
Utils.slice_hash(data, keys)
|
48
|
+
end
|
49
|
+
|
33
50
|
def success?
|
34
51
|
@success
|
35
52
|
end
|
@@ -39,7 +56,7 @@ module Micro
|
|
39
56
|
end
|
40
57
|
|
41
58
|
def on_success(expected_type = nil)
|
42
|
-
return self unless
|
59
|
+
return self unless __success_type?(expected_type)
|
43
60
|
|
44
61
|
hook_data = expected_type.nil? ? self : data
|
45
62
|
|
@@ -49,7 +66,7 @@ module Micro
|
|
49
66
|
end
|
50
67
|
|
51
68
|
def on_failure(expected_type = nil)
|
52
|
-
return self unless
|
69
|
+
return self unless __failure_type?(expected_type)
|
53
70
|
|
54
71
|
hook_data = expected_type.nil? ? self : data
|
55
72
|
|
@@ -59,7 +76,7 @@ module Micro
|
|
59
76
|
end
|
60
77
|
|
61
78
|
def on_exception(expected_exception = nil)
|
62
|
-
return self unless
|
79
|
+
return self unless __failure_type?(:exception)
|
63
80
|
|
64
81
|
if !expected_exception || (Kind.is(Exception, expected_exception) && data.fetch(:exception).is_a?(expected_exception))
|
65
82
|
yield(data, @use_case)
|
@@ -68,29 +85,46 @@ module Micro
|
|
68
85
|
self
|
69
86
|
end
|
70
87
|
|
71
|
-
def then(
|
88
|
+
def then(use_case = nil, attributes = nil, &block)
|
72
89
|
can_yield_self = respond_to?(:yield_self)
|
73
90
|
|
74
91
|
if block
|
75
|
-
raise Error::InvalidInvocationOfTheThenMethod if
|
92
|
+
raise Error::InvalidInvocationOfTheThenMethod if use_case
|
76
93
|
raise NotImplementedError if !can_yield_self
|
77
94
|
|
78
95
|
yield_self(&block)
|
79
96
|
else
|
80
|
-
return yield_self if !
|
97
|
+
return yield_self if !use_case && can_yield_self
|
98
|
+
return failure? ? self : __call_proc(use_case, 'then(-> {})'.freeze) if use_case.is_a?(Proc)
|
99
|
+
return failure? ? self : __call_method(use_case, attributes) if use_case.is_a?(Method)
|
81
100
|
|
82
|
-
raise Error::InvalidInvocationOfTheThenMethod
|
101
|
+
raise Error::InvalidInvocationOfTheThenMethod unless ::Micro.case_or_flow?(use_case)
|
83
102
|
|
84
103
|
return self if failure?
|
85
104
|
|
86
105
|
input = attributes.is_a?(Hash) ? self.data.merge(attributes) : self.data
|
87
106
|
|
88
|
-
|
107
|
+
if use_case.is_a?(::Micro::Cases::Flow)
|
108
|
+
use_case.call!(input: input, result: self)
|
109
|
+
else
|
110
|
+
use_case.__new__(self, input).__call__
|
111
|
+
end
|
89
112
|
end
|
90
113
|
end
|
91
114
|
|
115
|
+
def |(arg)
|
116
|
+
return self if failure?
|
117
|
+
|
118
|
+
return __call_proc(arg, '| -> {}'.freeze) if arg.is_a?(Proc)
|
119
|
+
return __call_method(arg) if arg.is_a?(Method)
|
120
|
+
|
121
|
+
raise Error::InvalidInvocationOfTheThenMethod unless ::Micro.case_or_flow?(arg)
|
122
|
+
|
123
|
+
failure? ? self : arg.__new__(self, data).__call__
|
124
|
+
end
|
125
|
+
|
92
126
|
def transitions
|
93
|
-
@
|
127
|
+
@__transitions.clone
|
94
128
|
end
|
95
129
|
|
96
130
|
FetchData = -> (data) do
|
@@ -102,7 +136,7 @@ module Micro
|
|
102
136
|
|
103
137
|
def __set__(is_success, data, type, use_case)
|
104
138
|
raise Error::InvalidResultType unless type.is_a?(Symbol)
|
105
|
-
raise Error::InvalidUseCase
|
139
|
+
raise Error::InvalidUseCase unless use_case.is_a?(::Micro::Case)
|
106
140
|
|
107
141
|
@success, @type, @use_case = is_success, type, use_case
|
108
142
|
|
@@ -110,54 +144,76 @@ module Micro
|
|
110
144
|
|
111
145
|
raise Micro::Case::Error::InvalidResult.new(is_success, type, use_case) unless @data
|
112
146
|
|
113
|
-
|
147
|
+
@__transitions_accumulated_data.merge!(@data)
|
148
|
+
|
149
|
+
use_case_attributes = Utils.symbolize_hash_keys(@use_case.attributes)
|
150
|
+
|
151
|
+
__update_transitions_accessible_attributes(use_case_attributes)
|
152
|
+
|
153
|
+
__set_transition(use_case_attributes) if @@transitions_enabled
|
114
154
|
|
115
155
|
self
|
116
156
|
end
|
117
157
|
|
118
|
-
def __set_transitions_accessible_attributes__(
|
119
|
-
return
|
158
|
+
def __set_transitions_accessible_attributes__(arg)
|
159
|
+
return arg unless arg.is_a?(Hash)
|
160
|
+
|
161
|
+
attributes = Utils.symbolize_hash_keys(arg)
|
120
162
|
|
121
|
-
|
163
|
+
__update_transitions_accessible_attributes(attributes)
|
122
164
|
end
|
123
165
|
|
124
166
|
private
|
125
167
|
|
126
|
-
def
|
127
|
-
|
168
|
+
def __call_with_accumulated_data(fn, opt = nil)
|
169
|
+
input =
|
170
|
+
__update_transitions_accessible_attributes(
|
171
|
+
opt ? opt.merge(@__transitions_accumulated_data) : @__transitions_accumulated_data
|
172
|
+
)
|
173
|
+
|
174
|
+
return fn.call if fn.arity.zero?
|
175
|
+
|
176
|
+
opt ? fn.call(**input) : fn.call(input)
|
128
177
|
end
|
129
178
|
|
130
|
-
def
|
131
|
-
|
179
|
+
def __call_proc(fn, expected)
|
180
|
+
result = __call_with_accumulated_data(fn)
|
181
|
+
|
182
|
+
return self if result === self
|
183
|
+
|
184
|
+
raise Error::UnexpectedResult.new("#{Result.name}##{expected}")
|
132
185
|
end
|
133
186
|
|
134
|
-
def
|
135
|
-
|
187
|
+
def __call_method(methd, attributes = nil)
|
188
|
+
result = __call_with_accumulated_data(methd, attributes)
|
189
|
+
|
190
|
+
return self if result === self
|
191
|
+
|
192
|
+
raise Error::UnexpectedResult.new("#{use_case.class.name}#method(:#{methd.name})")
|
136
193
|
end
|
137
194
|
|
138
|
-
def
|
139
|
-
|
195
|
+
def __success_type?(expected_type)
|
196
|
+
success? && (expected_type.nil? || expected_type == type)
|
197
|
+
end
|
140
198
|
|
141
|
-
|
199
|
+
def __failure_type?(expected_type)
|
200
|
+
failure? && (expected_type.nil? || expected_type == type)
|
142
201
|
end
|
143
202
|
|
144
|
-
def
|
145
|
-
@
|
146
|
-
@
|
203
|
+
def __update_transitions_accessible_attributes(attributes)
|
204
|
+
@__transitions_accessible_attributes.merge!(attributes)
|
205
|
+
@__transitions_accessible_attributes
|
147
206
|
end
|
148
207
|
|
149
|
-
def
|
208
|
+
def __set_transition(use_case_attributes)
|
150
209
|
use_case_class = @use_case.class
|
151
|
-
use_case_attributes = Utils.symbolize_hash_keys(@use_case.attributes)
|
152
|
-
|
153
|
-
__update_transitions_accessible_attributes__(use_case_attributes)
|
154
210
|
|
155
211
|
result = @success ? :success : :failure
|
156
212
|
|
157
|
-
@
|
213
|
+
@__transitions << {
|
158
214
|
use_case: { class: use_case_class, attributes: use_case_attributes },
|
159
215
|
result => { type: @type, result: data },
|
160
|
-
accessible_attributes: @
|
216
|
+
accessible_attributes: @__transitions_accessible_attributes.keys
|
161
217
|
}
|
162
218
|
end
|
163
219
|
|