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.
@@ -18,26 +18,45 @@ module Micro
18
18
 
19
19
  include Micro::Attributes.without(:strict_initialize)
20
20
 
21
- def self.config
22
- yield(Config.instance)
21
+ def self.call(options = Kind::Empty::HASH)
22
+ new(options).__call__
23
23
  end
24
24
 
25
- def self.call(options = {})
26
- new(options).call
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
- instance = new(arg)
55
- instance.__set_result__(result)
56
- instance
57
- end
73
+ input = result.__set_transitions_accessible_attributes__(arg)
58
74
 
59
- def self.__call_and_set_transition__(result, arg)
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.__flow_builder
78
+ def self.__flow_builder__
67
79
  Cases::Flow
68
80
  end
69
81
 
70
- def self.__flow_get
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 __flow_get
87
+ return if __flow_get__
76
88
 
77
- def self.use_cases; __flow_get.use_cases; end
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 = __flow_builder.build(args)
93
+ @__flow = __flow_builder__.build(args)
82
94
  end
83
95
 
84
- FLOW_STEP = 'Flow_Step'.freeze
96
+ FLOW_STEP = 'Self'.freeze
85
97
 
86
98
  private_constant :FLOW_STEP
87
99
 
88
- def self.__call!
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.__call! : use_case }
112
+ .map { |use_case| use_case == self ? self.__call__! : use_case }
101
113
  end
102
114
 
103
- def self.__flow_set!
104
- __flow_set(__flow_use_cases_get) if !__flow_get && __flow_use_cases
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 call
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.__flow_set!
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.__flow_get
169
+ self.class.__flow_get__
152
170
  end
153
171
 
154
172
  def __call_use_case_flow
155
- self.class.__flow_get.call(@__input)
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 __result__
198
+ def __result
181
199
  @__result ||= Result.new
182
200
  end
183
201
 
184
202
  def __get_result(is_success, value, type)
185
- __result__.__set__(is_success, value, type, self)
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
@@ -15,7 +15,7 @@ module Micro
15
15
 
16
16
  def enable_transitions=(value)
17
17
  Micro::Case::Result.class_variable_set(
18
- :@@transition_tracking_disabled, !Kind::Of::Boolean(value)
18
+ :@@transitions_enabled, Kind::Of::Boolean(value)
19
19
  )
20
20
  end
21
21
  end
@@ -4,9 +4,11 @@ module Micro
4
4
  class Case
5
5
  module Error
6
6
  class UnexpectedResult < TypeError
7
- MESSAGE = '#call! must return an instance of Micro::Case::Result'.freeze
7
+ MESSAGE = 'must return an instance of Micro::Case::Result'.freeze
8
8
 
9
- def initialize(klass); super(klass.name + MESSAGE); end
9
+ def initialize(context)
10
+ super("#{context} #{MESSAGE}")
11
+ end
10
12
  end
11
13
 
12
14
  class ResultIsAlreadyDefined < ArgumentError
@@ -7,15 +7,20 @@ module Micro
7
7
  class Result
8
8
  Kind::Types.add(self)
9
9
 
10
- @@transition_tracking_disabled = false
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
- alias_method :value, :data
18
+ alias value data
15
19
 
16
20
  def initialize
17
- @__transitions__ = []
18
- @__transitions_accessible_attributes__ = {}
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 success_type?(expected_type)
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 failure_type?(expected_type)
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 failure_type?(:exception)
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(arg = nil, attributes = nil, &block)
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 arg
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 !arg && can_yield_self
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 if !is_a_use_case?(arg)
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
- arg.__call_and_set_transition__(self, input)
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
- @__transitions__.clone
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 if !is_a_use_case?(use_case)
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
- __set_transition__ unless @@transition_tracking_disabled
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__(attributes_data)
119
- return attributes_data if @@transition_tracking_disabled
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
- __set_transitions_accessible_attributes__!(attributes_data)
163
+ __update_transitions_accessible_attributes(attributes)
122
164
  end
123
165
 
124
166
  private
125
167
 
126
- def success_type?(expected_type)
127
- success? && (expected_type.nil? || expected_type == type)
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 failure_type?(expected_type)
131
- failure? && (expected_type.nil? || expected_type == type)
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 is_a_use_case?(arg)
135
- (arg.is_a?(Class) && arg < ::Micro::Case) || arg.is_a?(::Micro::Case)
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 __set_transitions_accessible_attributes__!(attributes_data)
139
- attributes = Utils.symbolize_hash_keys(attributes_data)
195
+ def __success_type?(expected_type)
196
+ success? && (expected_type.nil? || expected_type == type)
197
+ end
140
198
 
141
- __update_transitions_accessible_attributes__(attributes)
199
+ def __failure_type?(expected_type)
200
+ failure? && (expected_type.nil? || expected_type == type)
142
201
  end
143
202
 
144
- def __update_transitions_accessible_attributes__(attributes)
145
- @__transitions_accessible_attributes__.merge!(attributes)
146
- @__transitions_accessible_attributes__
203
+ def __update_transitions_accessible_attributes(attributes)
204
+ @__transitions_accessible_attributes.merge!(attributes)
205
+ @__transitions_accessible_attributes
147
206
  end
148
207
 
149
- def __set_transition__
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
- @__transitions__ << {
213
+ @__transitions << {
158
214
  use_case: { class: use_case_class, attributes: use_case_attributes },
159
215
  result => { type: @type, result: data },
160
- accessible_attributes: @__transitions_accessible_attributes__.keys
216
+ accessible_attributes: @__transitions_accessible_attributes.keys
161
217
  }
162
218
  end
163
219
 
@@ -7,8 +7,8 @@ module Micro
7
7
  Cases::Safe::Flow
8
8
  end
9
9
 
10
- def call
11
- __call
10
+ def __call__
11
+ __call!
12
12
  rescue => exception
13
13
  raise exception if Error.by_wrong_usage?(exception)
14
14