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