u-case 3.1.0 → 4.2.1

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.
@@ -52,7 +52,10 @@ module Micro
52
52
  end
53
53
 
54
54
  def self.by_wrong_usage?(exception)
55
- exception.is_a?(InvalidResult) || exception.is_a?(UnexpectedResult) || exception.is_a?(ArgumentError)
55
+ case exception
56
+ when Kind::Error, ArgumentError, InvalidResult, UnexpectedResult then true
57
+ else false
58
+ end
56
59
  end
57
60
  end
58
61
  end
@@ -5,6 +5,7 @@ require 'set'
5
5
  module Micro
6
6
  class Case
7
7
  class Result
8
+ require 'micro/case/result/wrapper'
8
9
  require 'micro/case/result/transitions'
9
10
 
10
11
  Kind::Types.add(self)
@@ -22,20 +23,35 @@ module Micro
22
23
 
23
24
  alias value data
24
25
 
25
- def initialize(transitions_mapper = nil)
26
+ def initialize(transitions_mapper = Transitions::MapEverything)
27
+ enable_transitions = @@transitions_enabled
28
+
29
+ @__is_unknown = true
26
30
  @__accumulated_data = {}
31
+ @__tracked_use_cases = Set.new
27
32
  @__accessible_attributes = {}
28
33
 
29
- enable_transitions = @@transitions_enabled
30
-
31
34
  @__transitions = enable_transitions ? [] : Kind::Empty::ARRAY
32
- @__transitions_mapper = transitions_mapper || Transitions::MapEverything if enable_transitions
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}>"
33
45
  end
34
46
 
35
47
  def to_ary
36
48
  [data, type]
37
49
  end
38
50
 
51
+ def to_sym
52
+ @__success ? :success : :failure
53
+ end
54
+
39
55
  def [](key)
40
56
  data[key]
41
57
  end
@@ -53,7 +69,7 @@ module Micro
53
69
  end
54
70
 
55
71
  def slice(*keys)
56
- Utils.slice_hash(data, keys)
72
+ Utils::Hashes.slice(data, keys)
57
73
  end
58
74
 
59
75
  def success?
@@ -64,6 +80,10 @@ module Micro
64
80
  !success?
65
81
  end
66
82
 
83
+ def unknown?
84
+ @__is_unknown
85
+ end
86
+
67
87
  def accessible_attributes
68
88
  @__accessible_attributes.keys
69
89
  end
@@ -71,6 +91,7 @@ module Micro
71
91
  def on_success(expected_type = nil)
72
92
  return self unless __success_type?(expected_type)
73
93
 
94
+ @__is_unknown = false
74
95
  hook_data = expected_type.nil? ? self : data
75
96
 
76
97
  yield(hook_data, @use_case)
@@ -81,6 +102,7 @@ module Micro
81
102
  def on_failure(expected_type = nil)
82
103
  return self unless __failure_type?(expected_type)
83
104
 
105
+ @__is_unknown = false
84
106
  hook_data = expected_type.nil? ? self : data
85
107
 
86
108
  yield(hook_data, @use_case)
@@ -98,6 +120,14 @@ module Micro
98
120
  self
99
121
  end
100
122
 
123
+ def on_unknown
124
+ return self unless unknown?
125
+
126
+ yield(self, @use_case)
127
+
128
+ self
129
+ end
130
+
101
131
  def then(use_case = nil, attributes = nil, &block)
102
132
  can_yield_self = respond_to?(:yield_self)
103
133
 
@@ -159,9 +189,13 @@ module Micro
159
189
 
160
190
  @__accumulated_data.merge!(@data)
161
191
 
162
- use_case_attributes = Utils.symbolize_hash_keys(@use_case.attributes)
192
+ use_case_attributes = Utils::Hashes.symbolize_keys(@use_case.attributes)
163
193
 
164
- __update_accessible_attributes(use_case_attributes)
194
+ unless @__tracked_use_cases.member?(use_case_class = @use_case.class)
195
+ @__tracked_use_cases.add(use_case_class)
196
+
197
+ __update_accessible_attributes(use_case_attributes)
198
+ end
165
199
 
166
200
  __set_transition(use_case_attributes) unless @__transitions.frozen?
167
201
 
@@ -171,7 +205,7 @@ module Micro
171
205
  def __set_accessible_attributes__(arg)
172
206
  return arg unless arg.is_a?(Hash)
173
207
 
174
- attributes = Utils.symbolize_hash_keys(arg)
208
+ attributes = Utils::Hashes.symbolize_keys(arg)
175
209
 
176
210
  __update_accessible_attributes(attributes)
177
211
  __fetch_accessible_attributes
@@ -5,11 +5,9 @@ module Micro
5
5
  class Result
6
6
  class Transitions
7
7
  MapEverything = -> (result, use_case_attributes) do
8
- result_track = result.success? ? :success : :failure
9
-
10
8
  {
11
9
  use_case: { class: result.use_case.class, attributes: use_case_attributes },
12
- result_track => { type: result.type, result: result.data },
10
+ result.to_sym => { type: result.type, result: result.data },
13
11
  accessible_attributes: result.accessible_attributes
14
12
  }
15
13
  end
@@ -17,4 +15,3 @@ module Micro
17
15
  end
18
16
  end
19
17
  end
20
-
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro
4
+ class Case
5
+ class Result
6
+ class Wrapper
7
+ def initialize(result)
8
+ @__is_unknown = true
9
+
10
+ @result = result
11
+ end
12
+
13
+ def failure(type = nil)
14
+ return if @result.success?
15
+
16
+ if result_type?(type)
17
+ @__is_unknown = false
18
+
19
+ yield(@result)
20
+ end
21
+ end
22
+
23
+ def success(type = nil)
24
+ return if @result.failure?
25
+
26
+ if result_type?(type)
27
+ @__is_unknown = false
28
+
29
+ yield(@result)
30
+ end
31
+ end
32
+
33
+ def unknown
34
+ return yield(@result) if @__is_unknown
35
+ end
36
+
37
+ private
38
+
39
+ def result_type?(type)
40
+ type.nil? || @result.type == type
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -8,7 +8,7 @@ module Micro
8
8
  end
9
9
 
10
10
  def __call__
11
- call
11
+ __call_the_use_case_or_its_flow
12
12
  rescue => exception
13
13
  raise exception if Error.by_wrong_usage?(exception)
14
14
 
@@ -3,10 +3,10 @@
3
3
  module Micro
4
4
  class Case
5
5
  class Strict < ::Micro::Case
6
- include Micro::Attributes::Features::StrictInitialize
6
+ include Micro::Attributes::Features::Initialize::Strict
7
7
 
8
8
  class Safe < ::Micro::Case::Safe
9
- include Micro::Attributes::Features::StrictInitialize
9
+ include Micro::Attributes::Features::Initialize::Strict
10
10
  end
11
11
  end
12
12
  end
@@ -3,25 +3,34 @@
3
3
  module Micro
4
4
  class Case
5
5
  module Utils
6
- def self.symbolize_hash_keys(hash)
7
- if Kind::Of::Hash(hash).respond_to?(:transform_keys)
8
- hash.transform_keys { |key| key.to_sym rescue key }
9
- else
6
+
7
+ module Hashes
8
+ def self.respond_to?(hash, method)
9
+ Kind.of(Hash, hash).respond_to?(method)
10
+ end
11
+
12
+ def self.symbolize_keys(hash)
13
+ return hash.transform_keys { |key| key.to_sym rescue key } if respond_to?(hash, :transform_keys)
14
+
10
15
  hash.each_with_object({}) do |(k, v), memo|
11
16
  key = k.to_sym rescue k
12
-
13
17
  memo[key] = v
14
18
  end
15
19
  end
16
- end
17
20
 
18
- def self.slice_hash(hash, keys)
19
- if Kind::Of::Hash(hash).respond_to?(:slice)
20
- hash.slice(*keys)
21
- else
21
+ def self.stringify_keys(hash)
22
+ return hash.transform_keys(&:to_s) if respond_to?(hash, :transform_keys)
23
+
24
+ hash.each_with_object({}) { |(k, v), memo| memo[k.to_s] = v }
25
+ end
26
+
27
+ def self.slice(hash, keys)
28
+ return hash.slice(*keys) if respond_to?(hash, :slice)
29
+
22
30
  hash.select { |key, _value| keys.include?(key) }
23
31
  end
24
32
  end
33
+
25
34
  end
26
35
  end
27
36
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  class Case
5
- VERSION = '3.1.0'.freeze
5
+ VERSION = '4.2.1'.freeze
6
6
  end
7
7
  end
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'micro/cases/utils'
4
+ require 'micro/cases/error'
3
5
  require 'micro/cases/flow'
4
6
  require 'micro/cases/safe/flow'
7
+ require 'micro/cases/map'
5
8
 
6
9
  module Micro
7
10
  module Cases
@@ -12,5 +15,9 @@ module Micro
12
15
  def self.safe_flow(args)
13
16
  Safe::Flow.build(args)
14
17
  end
18
+
19
+ def self.map(args)
20
+ Map.build(args)
21
+ end
15
22
  end
16
23
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro
4
+ module Cases
5
+
6
+ module Error
7
+ class InvalidUseCases < ArgumentError
8
+ def initialize; super('argument must be a collection of `Micro::Case` classes'.freeze); end
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -3,20 +3,15 @@
3
3
  module Micro
4
4
  module Cases
5
5
  class Flow
6
- class InvalidUseCases < ArgumentError
7
- def initialize; super('argument must be a collection of `Micro::Case` classes'.freeze); end
8
- end
6
+ IsAUseCaseWithDefaults = -> arg { arg.is_a?(Array) && Micro.case?(arg[0]) && arg[1].is_a?(Hash) }
7
+ IsAValidUseCase = -> use_case { Micro.case?(use_case) || IsAUseCaseWithDefaults[use_case] }
9
8
 
10
9
  attr_reader :use_cases
11
10
 
12
- def self.map_use_cases(arg)
13
- arg.is_a?(Flow) ? arg.use_cases : Array(arg)
14
- end
15
-
16
11
  def self.build(args)
17
- use_cases = Array(args).flat_map { |arg| map_use_cases(arg) }
12
+ use_cases = Utils.map_use_cases(args)
18
13
 
19
- raise InvalidUseCases if use_cases.any? { |klass| !(klass < ::Micro::Case) }
14
+ raise Error::InvalidUseCases if use_cases.none?(&IsAValidUseCase)
20
15
 
21
16
  new(use_cases)
22
17
  end
@@ -27,8 +22,12 @@ module Micro
27
22
  @first = @next_ones.shift
28
23
  end
29
24
 
25
+ def inspect
26
+ '#<(%s) use_cases=%s>' % [self.class, @use_cases]
27
+ end
28
+
30
29
  def call!(input:, result:)
31
- first_result = __case_use_case(@first, result, input)
30
+ first_result = __call_use_case(@first, result, input)
32
31
 
33
32
  return first_result if @next_ones.empty?
34
33
 
@@ -36,7 +35,11 @@ module Micro
36
35
  end
37
36
 
38
37
  def call(input = Kind::Empty::HASH)
39
- call!(input: input, result: Case::Result.new)
38
+ result = call!(input: input, result: Case::Result.new)
39
+
40
+ return result unless block_given?
41
+
42
+ yield ::Micro::Case::Result::Wrapper.new(result)
40
43
  end
41
44
 
42
45
  alias __call__ call
@@ -68,17 +71,23 @@ module Micro
68
71
  raise Case::Error::InvalidInvocationOfTheThenMethod.new("#{self.class.name}#")
69
72
  end
70
73
 
71
- def __case_use_case(use_case, result, input)
72
- use_case.__new__(result, input).__call__
74
+ def __call_use_case(use_case, result, input)
75
+ __build_use_case(use_case, result, input).__call__
73
76
  end
74
77
 
75
78
  def __call_next_use_cases(first_result)
76
79
  @next_ones.reduce(first_result) do |result, use_case|
77
80
  break result if result.failure?
78
81
 
79
- __case_use_case(use_case, result, result.data)
82
+ __call_use_case(use_case, result, result.data)
80
83
  end
81
84
  end
85
+
86
+ def __build_use_case(use_case, result, input)
87
+ return use_case.__new__(result, input) unless use_case.is_a?(Array)
88
+
89
+ use_case[0].__new__(result, input.merge(use_case[1]))
90
+ end
82
91
  end
83
92
  end
84
93
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro
4
+ module Cases
5
+ class Map
6
+ IsAUseCaseOrFlowWithDefaults = -> arg { arg.is_a?(Array) && Micro.case_or_flow?(arg[0]) && arg[1].is_a?(Hash) }
7
+ IsAUseCaseOrFlow = -> arg { Micro.case_or_flow?(arg) || IsAUseCaseOrFlowWithDefaults[arg] }
8
+ HasValidArgs = -> (args) { Kind.of(Array, args).all?(&IsAUseCaseOrFlow) }
9
+
10
+ attr_reader :use_cases
11
+
12
+ def self.build(args)
13
+ raise Error::InvalidUseCases unless HasValidArgs[args]
14
+
15
+ new(args)
16
+ end
17
+
18
+ def initialize(use_cases)
19
+ @use_cases = use_cases
20
+ end
21
+
22
+ GetUseCaseResult = -> (hash) do
23
+ -> (use_case) do
24
+ return use_case.call(hash) unless use_case.is_a?(Array)
25
+
26
+ use_case[0].call(hash.merge(use_case[1]))
27
+ end
28
+ end
29
+
30
+ def call(arg = {})
31
+ hash = Kind.of(Hash, arg)
32
+
33
+ use_cases.map(&GetUseCaseResult[hash])
34
+ end
35
+
36
+ private_constant :HasValidArgs, :IsAUseCaseOrFlow, :IsAUseCaseOrFlowWithDefaults, :GetUseCaseResult
37
+ end
38
+ end
39
+ end
@@ -4,8 +4,8 @@ module Micro
4
4
  module Cases
5
5
  module Safe
6
6
  class Flow < Cases::Flow
7
- private def __case_use_case(use_case, result, input)
8
- instance = use_case.__new__(result, input)
7
+ private def __call_use_case(use_case, result, input)
8
+ instance = __build_use_case(use_case, result, input)
9
9
  instance.__call__
10
10
  rescue => exception
11
11
  raise exception if Case::Error.by_wrong_usage?(exception)
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro
4
+ module Cases
5
+
6
+ module Utils
7
+ def self.map_use_cases(args)
8
+ collection = args.is_a?(Array) && args.size == 1 ? args[0] : args
9
+
10
+ Array(collection).each_with_object([]) do |arg, memo|
11
+ if arg.is_a?(Flow)
12
+ arg.use_cases.each { |use_case| memo << use_case }
13
+ else
14
+ memo << arg
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ end
21
+ end